From aeca9fa80cbdf6e85f15e0c676b70f76c7ae6037 Mon Sep 17 00:00:00 2001 From: marha Date: Thu, 27 Jan 2011 15:37:48 +0000 Subject: plink: updated to putty revision 9080 --- tools/plink/cmdline.c | 1 + tools/plink/putty.h | 17 +++++ tools/plink/settings.c | 7 ++ tools/plink/ssh.c | 8 ++- tools/plink/version.c | 2 +- tools/plink/winhelp.h | 1 + tools/plink/winpgntc.c | 91 +++++++++++++++++++++++++- tools/plink/winstore.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++++ tools/plink/winstuff.h | 48 +++++++++++++- 9 files changed, 342 insertions(+), 6 deletions(-) (limited to 'tools/plink') diff --git a/tools/plink/cmdline.c b/tools/plink/cmdline.c index 6492132f1..aa376a053 100644 --- a/tools/plink/cmdline.c +++ b/tools/plink/cmdline.c @@ -172,6 +172,7 @@ int cmdline_process_param(char *p, char *value, int need_save, Config *cfg) * saved. */ do_defaults(value, cfg); loaded_session = TRUE; + cmdline_session_name = dupstr(value); return 2; } if (!strcmp(p, "-ssh")) { diff --git a/tools/plink/putty.h b/tools/plink/putty.h index ac2701133..c72d8eb76 100644 --- a/tools/plink/putty.h +++ b/tools/plink/putty.h @@ -470,6 +470,7 @@ struct config_tag { int sshprot; /* use v1 or v2 when both available */ int ssh2_des_cbc; /* "des-cbc" unrecommended SSH-2 cipher */ int ssh_no_userauth; /* bypass "ssh-userauth" (SSH-2 only) */ + int ssh_show_banner; /* show USERAUTH_BANNERs (SSH-2 only) */ int try_tis_auth; int try_ki_auth; int try_gssapi_auth; /* attempt gssapi auth */ @@ -625,6 +626,7 @@ struct config_tag { FontSpec wideboldfont; int shadowboldoffset; int crhaslf; + char winclass[256]; }; /* @@ -666,6 +668,10 @@ GLOBAL int default_port; * This is set TRUE by cmdline.c iff a session is loaded with "-load". */ GLOBAL int loaded_session; +/* + * This is set to the name of the loaded session. + */ +GLOBAL char *cmdline_session_name; struct RSAKey; /* be a little careful of scope */ @@ -1246,4 +1252,15 @@ void expire_timer_context(void *ctx); int run_timers(long now, long *next); void timer_change_notify(long next); +/* + * Define no-op macros for the jump list functions, on platforms that + * don't support them. (This is a bit of a hack, and it'd be nicer to + * localise even the calls to those functions into the Windows front + * end, but it'll do for the moment.) + */ +#ifndef JUMPLIST_SUPPORTED +#define add_session_to_jumplist(x) ((void)0) +#define remove_session_from_jumplist(x) ((void)0) +#endif + #endif diff --git a/tools/plink/settings.c b/tools/plink/settings.c index bd6b97495..46e19f49c 100644 --- a/tools/plink/settings.c +++ b/tools/plink/settings.c @@ -348,6 +348,7 @@ void save_open_settings(void *sesskey, Config *cfg) write_setting_i(sesskey, "RekeyTime", cfg->ssh_rekey_time); write_setting_s(sesskey, "RekeyBytes", cfg->ssh_rekey_data); write_setting_i(sesskey, "SshNoAuth", cfg->ssh_no_userauth); + write_setting_i(sesskey, "SshBanner", cfg->ssh_show_banner); write_setting_i(sesskey, "AuthTIS", cfg->try_tis_auth); write_setting_i(sesskey, "AuthKI", cfg->try_ki_auth); write_setting_i(sesskey, "AuthGSSAPI", cfg->try_gssapi_auth); @@ -498,6 +499,7 @@ void save_open_settings(void *sesskey, Config *cfg) write_setting_i(sesskey, "SerialStopHalfbits", cfg->serstopbits); write_setting_i(sesskey, "SerialParity", cfg->serparity); write_setting_i(sesskey, "SerialFlowControl", cfg->serflow); + write_setting_s(sesskey, "WindowClass", cfg->winclass); } void load_settings(char *section, Config * cfg) @@ -507,6 +509,9 @@ void load_settings(char *section, Config * cfg) sesskey = open_settings_r(section); load_open_settings(sesskey, cfg); close_settings_r(sesskey); + + if (cfg_launchable(cfg)) + add_session_to_jumplist(section); } void load_open_settings(void *sesskey, Config *cfg) @@ -642,6 +647,7 @@ void load_open_settings(void *sesskey, Config *cfg) gpps(sesskey, "LogHost", "", cfg->loghost, sizeof(cfg->loghost)); gppi(sesskey, "SSH2DES", 0, &cfg->ssh2_des_cbc); gppi(sesskey, "SshNoAuth", 0, &cfg->ssh_no_userauth); + gppi(sesskey, "SshBanner", 1, &cfg->ssh_show_banner); gppi(sesskey, "AuthTIS", 0, &cfg->try_tis_auth); gppi(sesskey, "AuthKI", 1, &cfg->try_ki_auth); gppi(sesskey, "AuthGSSAPI", 1, &cfg->try_gssapi_auth); @@ -853,6 +859,7 @@ void load_open_settings(void *sesskey, Config *cfg) gppi(sesskey, "SerialStopHalfbits", 2, &cfg->serstopbits); gppi(sesskey, "SerialParity", SER_PAR_NONE, &cfg->serparity); gppi(sesskey, "SerialFlowControl", SER_FLOW_XONXOFF, &cfg->serflow); + gpps(sesskey, "WindowClass", "", cfg->winclass, sizeof(cfg->winclass)); } void do_defaults(char *session, Config * cfg) diff --git a/tools/plink/ssh.c b/tools/plink/ssh.c index 7c9b929de..0982f84a4 100644 --- a/tools/plink/ssh.c +++ b/tools/plink/ssh.c @@ -2862,6 +2862,7 @@ static int ssh_do_close(Ssh ssh, int notify_exit) x11_close(c->u.x11.s); break; case CHAN_SOCKDATA: + case CHAN_SOCKDATA_DORMANT: pfd_close(c->u.pfd.s); break; } @@ -7194,12 +7195,14 @@ static void ssh2_msg_channel_open(Ssh ssh, struct Packet *pktin) } /* - * Buffer banner messages for later display at some convenient point. + * Buffer banner messages for later display at some convenient point, + * if we're going to display them. */ static void ssh2_msg_userauth_banner(Ssh ssh, struct Packet *pktin) { /* Arbitrary limit to prevent unbounded inflation of buffer */ - if (bufchain_size(&ssh->banner) <= 131072) { + if (ssh->cfg.ssh_show_banner && + bufchain_size(&ssh->banner) <= 131072) { char *banner = NULL; int size = 0; ssh_pkt_getstring(pktin, &banner, &size); @@ -9355,6 +9358,7 @@ static void ssh_free(void *handle) x11_close(c->u.x11.s); break; case CHAN_SOCKDATA: + case CHAN_SOCKDATA_DORMANT: if (c->u.pfd.s != NULL) pfd_close(c->u.pfd.s); break; diff --git a/tools/plink/version.c b/tools/plink/version.c index 483495771..bcb233272 100644 --- a/tools/plink/version.c +++ b/tools/plink/version.c @@ -5,7 +5,7 @@ #define STR1(x) #x #define STR(x) STR1(x) -#define SVN_REV 9025 +#define SVN_REV 9080 #if defined SNAPSHOT diff --git a/tools/plink/winhelp.h b/tools/plink/winhelp.h index 9ee140fef..d670c0cb8 100644 --- a/tools/plink/winhelp.h +++ b/tools/plink/winhelp.h @@ -102,6 +102,7 @@ #define WINHELP_CTX_ssh_kexlist "ssh.kex.order:config-ssh-kex-order" #define WINHELP_CTX_ssh_kex_repeat "ssh.kex.repeat:config-ssh-kex-rekey" #define WINHELP_CTX_ssh_auth_bypass "ssh.auth.bypass:config-ssh-noauth" +#define WINHELP_CTX_ssh_auth_banner "ssh.auth.banner:config-ssh-banner" #define WINHELP_CTX_ssh_auth_privkey "ssh.auth.privkey:config-ssh-privkey" #define WINHELP_CTX_ssh_auth_agentfwd "ssh.auth.agentfwd:config-ssh-agentfwd" #define WINHELP_CTX_ssh_auth_changeuser "ssh.auth.changeuser:config-ssh-changeuser" diff --git a/tools/plink/winpgntc.c b/tools/plink/winpgntc.c index 3bfafc972..2a5aa734f 100644 --- a/tools/plink/winpgntc.c +++ b/tools/plink/winpgntc.c @@ -7,6 +7,10 @@ #include "putty.h" +#ifndef NO_SECURITY +#include +#endif + #define AGENT_COPYDATA_ID 0x804e50ba /* random goop */ #define AGENT_MAX_MSGLEN 8192 @@ -66,6 +70,33 @@ DWORD WINAPI agent_query_thread(LPVOID param) #endif +/* + * Dynamically load advapi32.dll for SID manipulation. In its absence, + * we degrade gracefully. + */ +#ifndef NO_SECURITY +int advapi_initialised = FALSE; +static HMODULE advapi; +DECL_WINDOWS_FUNCTION(static, BOOL, OpenProcessToken, + (HANDLE, DWORD, PHANDLE)); +DECL_WINDOWS_FUNCTION(static, BOOL, GetTokenInformation, + (HANDLE, TOKEN_INFORMATION_CLASS, + LPVOID, DWORD, PDWORD)); +DECL_WINDOWS_FUNCTION(static, BOOL, InitializeSecurityDescriptor, + (PSECURITY_DESCRIPTOR, DWORD)); +DECL_WINDOWS_FUNCTION(static, BOOL, SetSecurityDescriptorOwner, + (PSECURITY_DESCRIPTOR, PSID, BOOL)); +static int init_advapi(void) +{ + advapi = load_system32_dll("advapi32.dll"); + return advapi && + GET_WINDOWS_FUNCTION(advapi, OpenProcessToken) && + GET_WINDOWS_FUNCTION(advapi, GetTokenInformation) && + GET_WINDOWS_FUNCTION(advapi, InitializeSecurityDescriptor) && + GET_WINDOWS_FUNCTION(advapi, SetSecurityDescriptorOwner); +} +#endif + int agent_query(void *in, int inlen, void **out, int *outlen, void (*callback)(void *, void *, int), void *callback_ctx) { @@ -75,6 +106,10 @@ int agent_query(void *in, int inlen, void **out, int *outlen, unsigned char *p, *ret; int id, retlen; COPYDATASTRUCT cds; + SECURITY_ATTRIBUTES sa, *psa; + PSECURITY_DESCRIPTOR psd = NULL; + HANDLE proc, tok; + TOKEN_USER *user = NULL; *out = NULL; *outlen = 0; @@ -83,7 +118,57 @@ int agent_query(void *in, int inlen, void **out, int *outlen, if (!hwnd) return 1; /* *out == NULL, so failure */ mapname = dupprintf("PageantRequest%08x", (unsigned)GetCurrentThreadId()); - filemap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, + +#ifndef NO_SECURITY + if (advapi_initialised || init_advapi()) { + /* + * Make the file mapping we create for communication with + * Pageant owned by the user SID rather than the default. This + * should make communication between processes with slightly + * different contexts more reliable: in particular, command + * prompts launched as administrator should still be able to + * run PSFTPs which refer back to the owning user's + * unprivileged Pageant. + */ + + if ((proc = OpenProcess(MAXIMUM_ALLOWED, FALSE, + GetCurrentProcessId())) != NULL) { + if (p_OpenProcessToken(proc, TOKEN_QUERY, &tok)) { + DWORD retlen; + p_GetTokenInformation(tok, TokenUser, NULL, 0, &retlen); + user = (TOKEN_USER *)LocalAlloc(LPTR, retlen); + if (!p_GetTokenInformation(tok, TokenUser, + user, retlen, &retlen)) { + LocalFree(user); + user = NULL; + } + CloseHandle(tok); + } + CloseHandle(proc); + } + + psa = NULL; + if (user) { + psd = (PSECURITY_DESCRIPTOR) + LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH); + if (psd) { + if (p_InitializeSecurityDescriptor + (psd, SECURITY_DESCRIPTOR_REVISION) && + p_SetSecurityDescriptorOwner(psd, user->User.Sid, FALSE)) { + sa.nLength = sizeof(sa); + sa.bInheritHandle = TRUE; + sa.lpSecurityDescriptor = psd; + psa = &sa; + } else { + LocalFree(psd); + psd = NULL; + } + } + } + } +#endif /* NO_SECURITY */ + + filemap = CreateFileMapping(INVALID_HANDLE_VALUE, psa, PAGE_READWRITE, 0, AGENT_MAX_MSGLEN, mapname); if (filemap == NULL || filemap == INVALID_HANDLE_VALUE) return 1; /* *out == NULL, so failure */ @@ -134,5 +219,9 @@ int agent_query(void *in, int inlen, void **out, int *outlen, } UnmapViewOfFile(p); CloseHandle(filemap); + if (psd) + LocalFree(psd); + if (user) + LocalFree(user); return 1; } diff --git a/tools/plink/winstore.c b/tools/plink/winstore.c index f7dd98965..13ee184a5 100644 --- a/tools/plink/winstore.c +++ b/tools/plink/winstore.c @@ -17,6 +17,8 @@ #define CSIDL_LOCAL_APPDATA 0x001c #endif +static const char *const reg_jumplist_key = PUTTY_REG_POS "\\Jumplist"; +static const char *const reg_jumplist_value = "Recent sessions"; static const char *const puttystr = PUTTY_REG_POS "\\Sessions"; static const char hex[16] = "0123456789ABCDEF"; @@ -243,6 +245,8 @@ void del_settings(const char *sessionname) sfree(p); RegCloseKey(subkey1); + + remove_session_from_jumplist(sessionname); } struct enumsettings { @@ -581,6 +585,169 @@ void write_random_seed(void *data, int len) } } +/* + * Internal function supporting the jump list registry code. All the + * functions to add, remove and read the list have substantially + * similar content, so this is a generalisation of all of them which + * transforms the list in the registry by prepending 'add' (if + * non-null), removing 'rem' from what's left (if non-null), and + * returning the resulting concatenated list of strings in 'out' (if + * non-null). + */ +static int transform_jumplist_registry + (const char *add, const char *rem, char **out) +{ + int ret; + HKEY pjumplist_key, psettings_tmp; + DWORD type; + int value_length; + char *old_value, *new_value; + char *piterator_old, *piterator_new, *piterator_tmp; + + ret = RegCreateKeyEx(HKEY_CURRENT_USER, reg_jumplist_key, 0, NULL, + REG_OPTION_NON_VOLATILE, (KEY_READ | KEY_WRITE), NULL, + &pjumplist_key, NULL); + if (ret != ERROR_SUCCESS) { + return JUMPLISTREG_ERROR_KEYOPENCREATE_FAILURE; + } + + /* Get current list of saved sessions in the registry. */ + value_length = 200; + old_value = snewn(value_length, char); + ret = RegQueryValueEx(pjumplist_key, reg_jumplist_value, NULL, &type, + old_value, &value_length); + /* When the passed buffer is too small, ERROR_MORE_DATA is + * returned and the required size is returned in the length + * argument. */ + if (ret == ERROR_MORE_DATA) { + sfree(old_value); + old_value = snewn(value_length, char); + ret = RegQueryValueEx(pjumplist_key, reg_jumplist_value, NULL, &type, + old_value, &value_length); + } + + if (ret == ERROR_FILE_NOT_FOUND) { + /* Value doesn't exist yet. Start from an empty value. */ + *old_value = '\0'; + *(old_value + 1) = '\0'; + } else if (ret != ERROR_SUCCESS) { + /* Some non-recoverable error occurred. */ + sfree(old_value); + RegCloseKey(pjumplist_key); + return JUMPLISTREG_ERROR_VALUEREAD_FAILURE; + } else if (type != REG_MULTI_SZ) { + /* The value present in the registry has the wrong type: we + * try to delete it and start from an empty value. */ + ret = RegDeleteValue(pjumplist_key, reg_jumplist_value); + if (ret != ERROR_SUCCESS) { + sfree(old_value); + RegCloseKey(pjumplist_key); + return JUMPLISTREG_ERROR_VALUEREAD_FAILURE; + } + + *old_value = '\0'; + *(old_value + 1) = '\0'; + } + + /* Check validity of registry data: REG_MULTI_SZ value must end + * with \0\0. */ + piterator_tmp = old_value; + while (((piterator_tmp - old_value) < (value_length - 1)) && + !(*piterator_tmp == '\0' && *(piterator_tmp+1) == '\0')) { + ++piterator_tmp; + } + + if ((piterator_tmp - old_value) >= (value_length-1)) { + /* Invalid value. Start from an empty value. */ + *old_value = '\0'; + *(old_value + 1) = '\0'; + } + + /* + * Modify the list, if we're modifying. + */ + if (add || rem) { + /* Walk through the existing list and construct the new list of + * saved sessions. */ + new_value = snewn(value_length + (add ? strlen(add) + 1 : 0), char); + piterator_new = new_value; + piterator_old = old_value; + + /* First add the new item to the beginning of the list. */ + if (add) { + strcpy(piterator_new, add); + piterator_new += strlen(piterator_new) + 1; + } + /* Now add the existing list, taking care to leave out the removed + * item, if it was already in the existing list. */ + while (*piterator_old != '\0') { + if (!rem || strcmp(piterator_old, rem) != 0) { + /* Check if this is a valid session, otherwise don't add. */ + psettings_tmp = open_settings_r(piterator_old); + if (psettings_tmp != NULL) { + close_settings_r(psettings_tmp); + strcpy(piterator_new, piterator_old); + piterator_new += strlen(piterator_new) + 1; + } + } + piterator_old += strlen(piterator_old) + 1; + } + *piterator_new = '\0'; + ++piterator_new; + + /* Save the new list to the registry. */ + ret = RegSetValueEx(pjumplist_key, reg_jumplist_value, 0, REG_MULTI_SZ, + new_value, piterator_new - new_value); + + sfree(old_value); + old_value = new_value; + } else + ret = ERROR_SUCCESS; + + /* + * Either return or free the result. + */ + if (out) + *out = old_value; + else + sfree(old_value); + + /* Clean up and return. */ + RegCloseKey(pjumplist_key); + + if (ret != ERROR_SUCCESS) { + return JUMPLISTREG_ERROR_VALUEWRITE_FAILURE; + } else { + return JUMPLISTREG_OK; + } +} + +/* Adds a new entry to the jumplist entries in the registry. */ +int add_to_jumplist_registry(const char *item) +{ + return transform_jumplist_registry(item, item, NULL); +} + +/* Removes an item from the jumplist entries in the registry. */ +int remove_from_jumplist_registry(const char *item) +{ + return transform_jumplist_registry(NULL, item, NULL); +} + +/* Returns the jumplist entries from the registry. Caller must free + * the returned pointer. */ +char *get_jumplist_registry_entries (void) +{ + char *list_value; + + if (transform_jumplist_registry(NULL,NULL,&list_value) != ERROR_SUCCESS) { + list_value = snewn(2, char); + *list_value = '\0'; + *(list_value + 1) = '\0'; + } + return list_value; +} + /* * Recursively delete a registry key and everything under it. */ @@ -612,6 +779,12 @@ void cleanup_all(void) */ access_random_seed(DEL); + /* ------------------------------------------------------------ + * Ask Windows to delete any jump list information associated + * with this installation of PuTTY. + */ + clear_jumplist(); + /* ------------------------------------------------------------ * Destroy all registry information associated with PuTTY. */ diff --git a/tools/plink/winstuff.h b/tools/plink/winstuff.h index eeceea17a..1cc48348e 100644 --- a/tools/plink/winstuff.h +++ b/tools/plink/winstuff.h @@ -96,9 +96,9 @@ struct FontSpec { #define STR1(x) #x #define STR(x) STR1(x) #define GET_WINDOWS_FUNCTION_PP(module, name) \ - p_##name = module ? (t_##name) GetProcAddress(module, STR(name)) : NULL + (p_##name = module ? (t_##name) GetProcAddress(module, STR(name)) : NULL) #define GET_WINDOWS_FUNCTION(module, name) \ - p_##name = module ? (t_##name) GetProcAddress(module, #name) : NULL + (p_##name = module ? (t_##name) GetProcAddress(module, #name) : NULL) /* * Global variables. Most modules declare these `extern', but @@ -126,6 +126,14 @@ typedef struct terminal_tag Terminal; #define PUTTY_REG_GPARENT "Software" #define PUTTY_REG_GPARENT_CHILD "SimonTatham" +/* Result values for the jumplist registry functions. */ +#define JUMPLISTREG_OK 0 +#define JUMPLISTREG_ERROR_INVALID_PARAMETER 1 +#define JUMPLISTREG_ERROR_KEYOPENCREATE_FAILURE 2 +#define JUMPLISTREG_ERROR_VALUEREAD_FAILURE 3 +#define JUMPLISTREG_ERROR_VALUEWRITE_FAILURE 4 +#define JUMPLISTREG_ERROR_INVALID_VALUE 5 + #define PUTTY_HELP_FILE "putty.hlp" #define PUTTY_CHM_FILE "putty.chm" #define PUTTY_HELP_CONTENTS "putty.cnt" @@ -308,6 +316,7 @@ struct dlgparam { struct { unsigned char r, g, b, ok; } coloursel_result; /* 0-255 */ tree234 *privdata; /* stores per-control private data */ int ended, endresult; /* has the dialog been ended? */ + int fixed_pitch_fonts; /* are we constrained to fixed fonts? */ }; /* @@ -366,6 +375,10 @@ void fwdsetter(struct ctlpos *cp, int listid, char *stext, int sid, char *btext, int bid, char *r1text, int r1id, char *r2text, int r2id); +void dlg_auto_set_fixed_pitch_flag(void *dlg); +int dlg_get_fixed_pitch_flag(void *dlg); +void dlg_set_fixed_pitch_flag(void *dlg, int flag); + #define MAX_SHORTCUTS_PER_CTRL 16 /* @@ -500,4 +513,35 @@ void agent_schedule_callback(void (*callback)(void *, void *, int), */ extern Backend serial_backend; +/* + * Exports from winjump.c. + */ +#define JUMPLIST_SUPPORTED /* suppress #defines in putty.h */ +void add_session_to_jumplist(const char * const sessionname); +void remove_session_from_jumplist(const char * const sessionname); +void clear_jumplist(void); + +/* + * Extra functions in winstore.c over and above the interface in + * storage.h. + * + * These functions manipulate the Registry section which mirrors the + * current Windows 7 jump list. (Because the real jump list storage is + * write-only, we need to keep another copy of whatever we put in it, + * so that we can put in a slightly modified version the next time.) + */ + +/* Adds a saved session to the registry jump list mirror. 'item' is a + * string naming a saved session. */ +int add_to_jumplist_registry(const char *item); + +/* Removes an item from the registry jump list mirror. */ +int remove_from_jumplist_registry(const char *item); + +/* Returns the current jump list entries from the registry. Caller + * must free the returned pointer, which points to a contiguous + * sequence of NUL-terminated strings in memory, terminated with an + * empty one. */ +char *get_jumplist_registry_entries(void); + #endif -- cgit v1.2.3 From 987904f9692c374b81547ebe0bd3bad5a279db48 Mon Sep 17 00:00:00 2001 From: marha Date: Thu, 27 Jan 2011 15:48:10 +0000 Subject: Added missing file winnojmp.c --- tools/plink/winnojmp.c | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 tools/plink/winnojmp.c (limited to 'tools/plink') diff --git a/tools/plink/winnojmp.c b/tools/plink/winnojmp.c new file mode 100644 index 000000000..27d969a3b --- /dev/null +++ b/tools/plink/winnojmp.c @@ -0,0 +1,8 @@ +/* + * winnojmp.c: stub jump list functions for Windows executables that + * don't update the jump list. + */ + +void add_session_to_jumplist(const char * const sessionname) {} +void remove_session_from_jumplist(const char * const sessionname) {} +void clear_jumplist(void) {} -- cgit v1.2.3