From 89fff90de738025d338fa5d06b6ff3b589c33c9c Mon Sep 17 00:00:00 2001 From: klemens Date: Sat, 15 Apr 2017 10:06:22 +0200 Subject: [PATCH 001/166] 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 eb96fc17e..269dbdc1b 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 6c0621162..8d78594d2 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 ae15ac488..a19cec5d0 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 2d9a74023..366717251 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 f810d3f97..00c01c546 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 c79944cda..f47fe1bdb 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 004eb4f82..38c0e3cd7 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 002/166] 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 e5f0fa4fd..c8cb46f68 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 7ceca4863..fc26c3e55 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 003/166] 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 54e006366..e2cce9ae8 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 38c0e3cd7..cb42addf7 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 004/166] 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 e2cce9ae8..0fb7bbb76 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 c190e5fb0..115872739 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 005/166] 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 0fb7bbb76..f54581223 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 a03967e6f..737018e45 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 cb42addf7..e01a3c32d 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 c4f4de45b..2507d37ea 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 007889e4a..f8c4243f9 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 006/166] 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 7ca4eb7f5..086800ac6 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 db1ed30c7..b04c64745 100644 --- a/LATEST.VER +++ b/LATEST.VER @@ -1 +1 @@ -0.68 +0.69 diff --git a/doc/plink.but b/doc/plink.but index 351e13ea7..153982e07 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 27643a468..30a47f83b 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 dda68f63b..b3deb76c2 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 007/166] 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 0499d7802..8d55ac412 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 008/166] 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 e01a3c32d..89ddb8636 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 009/166] 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 269dbdc1b..a7d45689f 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 010/166] 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 a7d45689f..bb18b794b 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 011/166] 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 69e335094..bca6daa43 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 012/166] 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 bca6daa43..67cfcac38 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 013/166] 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 a19cec5d0..8a63c65dc 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 014/166] 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 086800ac6..afcc2766e 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 ef931dd14..4d73a995d 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 ebfdfdd77..a722fe10a 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 227300f46..64e8ab74c 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 42f965b27..80cf9d639 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 e0854fc54..b8428e415 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 a46e6a196..9f4118719 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 05e5a23cb..6c703e138 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 80d86ecf6..51f30d3a0 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 a3b794059..73b85ecce 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 df7b9e1fe..cb7cca470 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 9ec900665..71143af22 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 c50464ee1..9ca8ed3f8 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 693f52d8d..994e93aeb 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 a6c2707d5..14aac092d 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 fa153c624..d929df903 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 b3deb76c2..3fadcb922 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 e29f12914..8bd02d855 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 2507d37ea..7903c1cf2 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 70f3d2ca5..ebb6c6ace 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 015/166] Fix a luking mention of Win32 in README. --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index 4d73a995d..50314ca63 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 016/166] 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 afcc2766e..de7f41b57 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 e7bf287e0..cb079fb5d 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 64e8ab74c..e5e03a600 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 44d1dca3f..000000000 --- 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 017/166] 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 2d4259b91..e891d66a8 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 018/166] 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 7ab2ca24f..68f749acc 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 ef25cdb57..52f346a48 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 019/166] 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 68f749acc..f21d23ffa 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 ffc5879cf..51f9a1ebe 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 79f4fbcee..ddcd92280 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 3df4cebe4..d3a82fa4e 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 39f96f126..618fe9bd7 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 41beaf0e7..e77f797a3 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 020/166] 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 474707777..a1a8dda0d 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 021/166] 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 a1a8dda0d..ea4175012 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 e25d7e064..4558e5a9b 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 022/166] 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 fc26c3e55..0ec64a55e 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 f8c4243f9..dfa032f48 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 023/166] 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 c8cb46f68..799fd28d5 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 024/166] 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 d58635b62..0941f721f 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 366717251..a168e522e 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 8a73a182d..febd8af9b 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 52006794c..68b7e9a06 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 0c5445ad4..fbc9018d8 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 eba468da2..ff2c0a8f4 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 994e93aeb..b6298b039 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 82c4bd31e..59cdad45b 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 c4b041327..8d03cb7b9 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 41efcbc2d..cb85b1606 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 584116aa6..9d0a58de6 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 025/166] 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 0ec64a55e..ea950bba2 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 026/166] 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 67cfcac38..f54289a36 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 027/166] 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 fdbdd861a..8e353fb9b 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 80cf9d639..dbc3fcc96 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 028/166] 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 dbc3fcc96..cd3254a8b 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 1e71234f7..30ebd7845 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 029/166] 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 dfa032f48..10fcdabaf 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 030/166] 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 10fcdabaf..546c273b7 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 031/166] 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 8a63c65dc..1d83912bd 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 032/166] 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 4a720e404..e3ed8c711 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 033/166] 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 de7f41b57..8bd680dfe 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 034/166] 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 8bd680dfe..4cbf6c417 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 035/166] 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 4cbf6c417..ab94ea92f 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 036/166] 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 9aff234b9..734ea8b19 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 037/166] 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 bb18b794b..bd12efb28 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 30ebd7845..0877ee90d 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 038/166] 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 115872739..a17166e69 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 039/166] 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 f54289a36..9e73181e2 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 040/166] 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 b6298b039..1d80e9194 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 041/166] 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 a17166e69..6a1a74c23 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 042/166] 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 2627c642e..285161853 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 043/166] 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 5394c1fbb..aa3971812 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 044/166] 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 285161853..8082f2dee 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 045/166] 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 ea950bba2..e2edc87a7 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 046/166] 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 3c777292d..fe46cf988 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 adf68777d..88589a71d 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 8d78594d2..2bdf4deb3 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 734ea8b19..469e4aeb6 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 454ec084c..210362df9 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 f47fe1bdb..ba9dd6172 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 89ddb8636..966003114 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 047/166] 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 f1c0c2edb..d3c5293d8 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 048/166] 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 2550b6def..2bd03470b 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 799fd28d5..7c8b0ba64 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 85fa3c95d..59d643122 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 e2edc87a7..86f7735fa 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 049/166] 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 220c1aa8f..efe1ff1ec 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 febd8af9b..b68e4bb8f 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 aa3971812..e4e77c3af 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 050/166] 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 ec0fb2ba0..25372a79b 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 051/166] 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 469e4aeb6..fc5b149dd 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 052/166] 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 8d55ac412..f757c5e0f 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 cf73d9eb4..7c76c6ae6 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 053/166] 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 f757c5e0f..21f386562 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 bdf6245ff..8dbdb6135 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 054/166] 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 92d39cd5a..0c486ce51 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 055/166] 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 ab94ea92f..8833a9c49 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 b04c64745..ac37bbeae 100644 --- a/LATEST.VER +++ b/LATEST.VER @@ -1 +1 @@ -0.69 +0.70 diff --git a/doc/plink.but b/doc/plink.but index 153982e07..459ceadf2 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 30a47f83b..7b90810b5 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 3fadcb922..ae926310a 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 056/166] 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 7c76c6ae6..da7d2a887 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 057/166] 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 da7d2a887..b5ad149c3 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 058/166] 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 f288ed629..d2a815928 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 9f4118719..58ca7a289 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 459ceadf2..74da18a1a 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 e891d66a8..2a1926efc 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 ea4175012..84e47d6ec 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 059/166] 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 cd3254a8b..4d9e14a93 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 060/166] 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 1d80e9194..89041f487 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 061/166] 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 89041f487..aa9fd5dd9 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 062/166] 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 ef0561671..54b1e477e 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 063/166] 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 1d83912bd..02421316e 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 064/166] 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 ba9dd6172..f7bcbb957 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 065/166] 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 15c253c24..c04f119b7 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 50314ca63..de6eb9b06 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 f54581223..5715938b0 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 9ca8ed3f8..b71688b7e 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 02421316e..6765f2a86 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 22b220358..ee2c76964 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 066/166] 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 7d184b7c2..f5e3b57bd 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 ebb6c6ace..1919a9b83 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 067/166] 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 33709d238..2311eb83a 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 068/166] 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 7c49ceb3b..30b1fe2b3 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 15b5d6354..480dca379 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 fd2d02506..61d6278da 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 f7bcbb957..e597d472e 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 2ed9e6ef5..21b8774a2 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 2311eb83a..34dff8a5a 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 9e73181e2..f49f92af6 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 966003114..452eb7716 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 069/166] 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 e597d472e..0eb1a9a6c 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 070/166] 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 ddcd92280..f3498527f 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 071/166] 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 0eb1a9a6c..433b3fa52 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 072/166] 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 efe1ff1ec..cc5e726b3 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 bd12efb28..7ad5e2822 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 61d6278da..8a8b54254 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 00c01c546..47e5b9f75 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 433b3fa52..5102db12a 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 21b8774a2..4a205a776 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 761c8c76a..dbe32c919 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 073/166] 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 f49f92af6..94ba4069b 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 452eb7716..79738ff9d 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 074/166] 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 94ba4069b..dcff614ff 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 79738ff9d..97c4d462a 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 075/166] 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 480dca379..c57412c46 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 8a8b54254..f89d07097 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 5102db12a..0fa52e172 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 dcff614ff..969c42ffe 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 97c4d462a..aa96a5789 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 076/166] 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 f89d07097..a9433fa70 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 0fa52e172..de5748e96 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 969c42ffe..5c6295190 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 aa96a5789..be7b4379e 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 077/166] 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 de5748e96..8c44b9062 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 078/166] 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 8c44b9062..7a7207a0d 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 4a205a776..fcb321c41 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 079/166] 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 7a7207a0d..a55b6e6ac 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 080/166] 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 fcb321c41..03659744b 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 5c6295190..3e12a4ba9 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 be7b4379e..73f0751c9 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 081/166] 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 a55b6e6ac..2106d10a3 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 082/166] 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 c57412c46..255fc6fb7 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 a9433fa70..ac35eb73f 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 2106d10a3..d32d4f423 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 3e12a4ba9..3a3c2a546 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 73f0751c9..8faa57e93 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 083/166] 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 8faa57e93..88a29dd40 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 084/166] Add Jeff Smith as a copyright holder. --- LICENCE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENCE b/LICENCE index 30b1fe2b3..05fbb7d39 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 085/166] 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 904cbdb2b..0368d6e9f 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 086/166] 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 0368d6e9f..9be58dabf 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 087/166] 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 9be58dabf..48d0ca16c 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 088/166] 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 48d0ca16c..443031844 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 089/166] 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 443031844..488e32a34 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 090/166] 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 488e32a34..7ebeb5be0 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 091/166] Additional copyright holders, from the AES-NI work. --- LICENCE | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/LICENCE b/LICENCE index 05fbb7d39..c473a6a40 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 092/166] 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 51f9a1ebe..2c7483437 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 093/166] 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 d32d4f423..d5d5314a1 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 094/166] 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 e8223a726..ef060d639 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 095/166] 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 3a3c2a546..a851c2584 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 096/166] 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 a851c2584..1038e7569 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 097/166] 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 618fe9bd7..4387ad8fa 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 098/166] 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 8b2a794fc..b544684ed 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 099/166] 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 5715938b0..33d0f2f7e 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 377fee0dc..0d7012160 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