Compare commits

...
24 Commits
Author SHA1 Message Date
cyd01 75fa2abcd2 Tagging the 0.76.1.13 release of the KiTTY project. 2023-09-17 19:17:22 +02:00
CydandGitHub 0301dd4a9c Merge pull request #512 from unxed/fix-osc52
fix #495 (OSC52 bugs)
2023-09-17 18:59:18 +02:00
CydandGitHub 8f9747ac7e Merge pull request #492 from unxed/fix-clip
Fix insertion from clipboard
2023-09-17 18:54:10 +02:00
Ivan Sorokin a52ffb145c cosmetic 2023-09-17 10:19:30 +02:00
Ivan Sorokin 34f5cea9b3 fix OSC52 bugs 2023-09-17 10:17:56 +02:00
Ivan Sorokin a7f1e2cd7a Fix insertion from clipboard 2023-05-30 19:15:19 +02:00
cyd01 0e5d8582aa Tagging the 0.76.1.12 release of the KiTTY project. 2023-05-23 19:56:00 +02:00
cyd01 4404c65e46 Tagging the 0.76.1.11 release of the KiTTY project - abandonned 2023-05-23 19:55:50 +02:00
cyd01 3dba318b09 Tagging the 0.76.1.10 release of the KiTTY project. 2023-05-20 23:49:09 +02:00
cyd01 1963f21af2 Tagging the 0.76.1.9 release of the KiTTY project. 2023-05-09 14:50:09 +02:00
CydandGitHub 888e28c4c2 Merge pull request #476 from yndx-melkov/fix-window-update-after-sleep
Resolves #475 Terminal window stops updating after resuming from sleep
2023-05-09 14:41:46 +02:00
CydandGitHub d4ffef0a50 Merge pull request #474 from yndx-melkov/fix-dns-fail-reconnect
resolves #360: window closes if dns resolution fails after manual reconnect
2023-05-09 14:41:36 +02:00
cyd01 904dccaf1d Tagging the 0.76.1.8 release of the KiTTY project. 2023-05-09 14:27:29 +02:00
cyd01 cb54bec9b6 Tagging the 0.76.1.7 release of the KiTTY project. 2023-04-28 19:47:37 +02:00
cyd01 59da291c7c Tagging the 0.76.1.6 release of the KiTTY project. 2023-04-24 16:58:13 +02:00
Alexander Melkov b2b8df282a Resolves #475 Terminal window stops updating after resuming from sleep 2023-03-27 07:18:44 +03:00
Alexander Melkov f25d39782c resolves #360: window closes if dns resolution fails after reconnect 2023-03-26 19:04:23 +03:00
cyd01 333860672b Tagging the 0.76.1.5 release of the KiTTY project. 2023-03-06 19:40:49 +01:00
CydandGitHub 9a636dd32f Merge pull request #449 from unxed/master
Set shift bit also if right or left shift key press detected; added workaround for some buggy clients
2023-03-06 19:06:16 +01:00
cyd01 fc2d3e430a Update pre0.77 2023-03-06 17:42:14 +01:00
CydandGitHub 3830e9261a Update FUNDING.yml 2023-03-06 10:07:42 +01:00
Ivan Sorokin b99479f92e workaround for clients that do not flush clipboard before setting it 2/2 2023-01-06 15:10:54 +03:00
Ivan Sorokin d8706714be workaround for clients that do not flush clipboard before setting it 2023-01-06 15:09:04 +03:00
Ivan Sorokin 1a041028c1 Set shift bit also if right or left shift key press detected 2023-01-06 12:19:20 +03:00
83 changed files with 2494 additions and 2042 deletions
+1 -1
View File
@@ -1,2 +1,2 @@
github: [ "cyd01" ]
custom: [ "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=65VYL8F5AD57G&source=url", "https://9bis.net/kitty/bitcoin.html" ]
custom: [ "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=65VYL8F5AD57G&source=url", "http://www.9bis.net/kitty/donate.html" ]
+1 -1
View File
@@ -3631,6 +3631,7 @@ static void do_osc(Terminal *term)
if (gfmt == CF_TEXT) {
n = wcsnlen((wchar_t *)pClipData, n / sizeof(wchar_t));
ClipTextSize = WideCharToMultiByte(
CP_UTF8,
0,
@@ -3643,7 +3644,6 @@ static void do_osc(Terminal *term)
) + 1;
if (ClipTextSize >= 0) {
n = wcsnlen((wchar_t *)pClipData, n / sizeof(wchar_t));
ClipText = calloc(ClipTextSize + 1, 1);
if (ClipText) {
WideCharToMultiByte(
+1
View File
@@ -1842,6 +1842,7 @@ NORETURN void cleanup_exit(int);
X(BOOL, NONE, no_focus_rep) /* totally disable mouse reporting */ \
X(INT, NONE, scrolllines) /* Options for Scroll Lines per Wheel */ \
X(BOOL, NONE, ssh_tunnel_print_in_title) /* print dynamic port number in window title */ \
X(BOOL, NONE, osc52_warn_before_cliboard_sync) /* Warn before clipboard sync */ \
/* #endif */ \
/* #ifdef MOD_PROXY */ \
X(STR, NONE, proxyselection) /* Options for proxy selection */ \
+1 -1
View File
@@ -7,7 +7,7 @@
#ifdef _WINDOWS
#include "winstuff.h"
#include "platform.h"
#else
+2
View File
@@ -949,6 +949,7 @@ void save_open_settings(settings_w *sesskey, Conf *conf)
write_setting_b(sesskey, "NoFocusReporting", conf_get_bool(conf, CONF_no_focus_rep));
write_setting_i(sesskey, "LinesAtAScroll", conf_get_int(conf, CONF_scrolllines));
write_setting_b(sesskey, "SSHTunnelInTitle", conf_get_bool(conf, CONF_ssh_tunnel_print_in_title));
write_setting_b(sesskey, "OSC52WarnBeforeClipboardSync", conf_get_bool(conf, CONF_osc52_warn_before_cliboard_sync));
#endif
#ifdef MOD_PORTKNOCKING
write_setting_s(sesskey, "PortKnocking", conf_get_str(conf, CONF_portknockingoptions) );
@@ -1640,6 +1641,7 @@ void load_open_settings(settings_r *sesskey, Conf *conf)
gppb(sesskey, "NoFocusReporting", true, conf, CONF_no_focus_rep);
gppi(sesskey, "LinesAtAScroll", -1, conf, CONF_scrolllines);
gppb(sesskey, "SSHTunnelInTitle", false, conf, CONF_ssh_tunnel_print_in_title);
gppb(sesskey, "OSC52WarnBeforeClipboardSync", false, conf, CONF_osc52_warn_before_cliboard_sync);
#endif
#ifdef MOD_PORTKNOCKING
gpps(sesskey, "PortKnocking", "", conf, CONF_portknockingoptions );
+223 -121
View File
@@ -26,6 +26,8 @@ int GetPuttyFlag(void) ;
int GetHyperlinkFlag(void) ;
int GetCursorType() ;
void SetCursorType( const int ct ) ;
extern HWND MainHwnd ;
int ManageLocalCmd( HWND hwnd, const char * cmd ) ;
#endif
#ifdef MOD_HYPERLINK
/*
@@ -1150,33 +1152,34 @@ static termline *lineptr(Terminal *term, int y, int lineno, int screen)
int treeindex;
if (y >= 0) {
whichtree = term->screen;
treeindex = y;
whichtree = term->screen;
treeindex = y;
} else {
int altlines = 0;
int altlines = 0;
#ifndef MOD_PERSO
assert(!screen);
#endif
if (term->erase_to_scrollback &&
term->alt_which && term->alt_screen) {
altlines = term->alt_sblines;
}
if (y < -altlines) {
whichtree = term->scrollback;
treeindex = y + altlines + count234(term->scrollback);
} else {
whichtree = term->alt_screen;
treeindex = y + term->alt_sblines;
/* treeindex = y + count234(term->alt_screen); */
}
if (term->erase_to_scrollback &&
term->alt_which && term->alt_screen) {
altlines = term->alt_sblines;
}
if (y < -altlines) {
whichtree = term->scrollback;
treeindex = y + altlines + count234(term->scrollback);
} else {
whichtree = term->alt_screen;
treeindex = y + term->alt_sblines;
/* treeindex = y + count234(term->alt_screen); */
}
}
if (whichtree == term->scrollback) {
compressed_scrollback_line *cline = index234(whichtree, treeindex);
compressed_scrollback_line *cline = index234(whichtree, treeindex);
if (!cline)
null_line_error(term, y, lineno, whichtree, treeindex, "cline");
line = decompressline(cline);
line = decompressline(cline);
} else {
line = index234(whichtree, treeindex);
line = index234(whichtree, treeindex);
}
/* We assume that we don't screw up and retrieve something out of range. */
@@ -1235,21 +1238,21 @@ static void term_timer(void *ctx, unsigned long now)
Terminal *term = (Terminal *)ctx;
if (term->tblink_pending && now == term->next_tblink) {
term->tblinker = !term->tblinker;
term->tblink_pending = false;
term_schedule_tblink(term);
term->tblinker = !term->tblinker;
term->tblink_pending = false;
term_schedule_tblink(term);
term->window_update_pending = true;
}
if (term->cblink_pending && now == term->next_cblink) {
term->cblinker = !term->cblinker;
term->cblink_pending = false;
term_schedule_cblink(term);
term->cblinker = !term->cblinker;
term->cblink_pending = false;
term_schedule_cblink(term);
term->window_update_pending = true;
}
if (term->in_vbell && now == term->vbell_end) {
term->in_vbell = false;
term->in_vbell = false;
term->window_update_pending = true;
}
@@ -1268,7 +1271,7 @@ static void term_update_callback(void *ctx)
if (!term->window_update_pending)
return;
if (!term->window_update_cooldown) {
term_update(term);
term_update(term);
term->window_update_cooldown = true;
term->window_update_cooldown_end = schedule_timer(
UPDATE_DELAY, term_timer, term);
@@ -1278,7 +1281,7 @@ static void term_update_callback(void *ctx)
static void term_schedule_update(Terminal *term)
{
if (!term->window_update_pending) {
term->window_update_pending = true;
term->window_update_pending = true;
queue_toplevel_callback(term_update_callback, term);
}
}
@@ -3557,6 +3560,10 @@ static void do_osc(Terminal *term)
memcpy(GData,buffer,BufferSize);
GlobalUnlock(hData);
// some clients don't flush the buffer before setting data,
// so we'll do that here just in case
EmptyClipboard();
if (OpenClipboard(NULL)) {
if (!SetClipboardData(fmt, (HANDLE)hData)) {
@@ -3630,6 +3637,7 @@ static void do_osc(Terminal *term)
if (gfmt == CF_TEXT) {
n = wcsnlen((wchar_t *)pClipData, n / sizeof(wchar_t));
ClipTextSize = WideCharToMultiByte(
CP_UTF8,
0,
@@ -3642,7 +3650,6 @@ static void do_osc(Terminal *term)
) + 1;
if (ClipTextSize >= 0) {
n = wcsnlen((wchar_t *)pClipData, n / sizeof(wchar_t));
ClipText = calloc(ClipTextSize + 1, 1);
if (ClipText) {
WideCharToMultiByte(
@@ -3811,32 +3818,130 @@ static void do_osc(Terminal *term)
} else
#endif
if (term->osc_w) {
while (term->osc_strlen--)
term->wordness[(unsigned char)
term->osc_string[term->osc_strlen]] = term->esc_args[0];
while (term->osc_strlen--)
term->wordness[(unsigned char)
term->osc_string[term->osc_strlen]] = term->esc_args[0];
} else {
term->osc_string[term->osc_strlen] = '\0';
switch (term->esc_args[0]) {
case 0:
case 1:
term->osc_string[term->osc_strlen] = '\0';
switch (term->esc_args[0]) {
case 0:
case 1:
if (!term->no_remote_wintitle) {
sfree(term->icon_title);
term->icon_title = dupstr(term->osc_string);
term->win_icon_title_pending = true;
term_schedule_update(term);
}
if (term->esc_args[0] == 1)
break;
/* fall through: parameter 0 means set both */
case 2:
case 21:
if (term->esc_args[0] == 1)
break;
/* fall through: parameter 0 means set both */
case 2:
case 21:
if (!term->no_remote_wintitle) {
#ifdef MOD_PERSO
if( (strlen(term->osc_string)>2) && (term->osc_string[0]=='_') && (term->osc_string[1]=='_') ) {
ManageLocalCmd( MainHwnd, term->osc_string+2 ) ;
} else {
sfree(term->window_title);
term->window_title = dupstr(term->osc_string);
term->win_title_pending = true;
term_schedule_update(term);
}
#else
sfree(term->window_title);
term->window_title = dupstr(term->osc_string);
term->win_title_pending = true;
term_schedule_update(term);
#endif
}
break;
break;
#ifdef MOD_PERSO
case 52:
{
char *env_check = getenv("OSC52ALLOWED");
int status = IDOK; // Default to IDOK
if( conf_get_bool(term->conf, CONF_osc52_warn_before_cliboard_sync) && (!env_check || strlen(env_check) == 0)) {
status = MessageBox(NULL,
"Allow OSC52 clipboard sync?", "PyTTY", MB_OKCANCEL);
}
if (status == IDOK) {
base64_decodestate _d_state;
base64_init_decodestate(&_d_state);
char* d_out = malloc(term->osc_strlen);
if (!d_out) {
// Failed to allocate memory
break;
}
int d_count = base64_decode_block(
term->osc_string+1, term->osc_strlen-1, d_out, &_d_state);
uint32_t fmt;
wchar_t* buffer = NULL; // Changed to wchar_t
int cnt = MultiByteToWideChar(CP_UTF8, 0, (LPCCH)d_out, d_count, NULL, 0);
if (cnt > 0) {
buffer = calloc(cnt + 1, sizeof(wchar_t));
if (!buffer) {
// Failed to allocate memory
free(d_out);
break;
}
MultiByteToWideChar(CP_UTF8, 0, (LPCCH)d_out, d_count, buffer, cnt);
}
fmt = CF_UNICODETEXT;
if (buffer) {
int BufferSize = (wcslen(buffer) + 1) * sizeof(wchar_t);
HGLOBAL hData = GlobalAlloc(GMEM_MOVEABLE, BufferSize);
if (!hData) {
// Failed to allocate global memory
free(buffer);
free(d_out);
break;
}
void *GData = GlobalLock(hData);
if (!GData) {
// Failed to lock global memory
GlobalFree(hData);
free(buffer);
free(d_out);
break;
}
memcpy(GData, buffer, BufferSize);
GlobalUnlock(hData);
if (OpenClipboard(NULL)) {
EmptyClipboard();
if (!SetClipboardData(fmt, (HANDLE)hData)) {
GlobalFree(hData);
}
CloseClipboard();
} else {
GlobalFree(hData);
}
}
free(buffer);
free(d_out);
}
break;
}
#endif
case 4:
if (term->ldisc && !strcmp(term->osc_string, "?")) {
unsigned index = term->esc_args[1];
@@ -3853,63 +3958,60 @@ static void do_osc(Terminal *term)
}
}
break;
}
}
}
}
#ifdef MOD_PRINTCLIP
/*
* Windows clipboard support
* Diomidis Spinellis, June 2003
*/
static char *clip_b, *clip_bp; /* Buffer, pointer to buffer insertion point */
static size_t clip_bsiz, clip_remsiz; /* Buffer, size, remaining size */
static size_t clip_total; /* Total read */
#define CLIP_CHUNK 16384
static void clipboard_init(void)
{
if (clip_b)
sfree(clip_b);
clip_bp = clip_b = smalloc(clip_remsiz = clip_bsiz = CLIP_CHUNK);
clip_total = 0;
}
static void clipboard_data(const void *buff, int len)
{
memcpy(clip_bp, buff, len);
clip_remsiz -= len;
clip_total += len;
clip_bp += len;
if (clip_remsiz < CLIP_CHUNK) {
clip_b = srealloc(clip_b, clip_bsiz *= 2);
clip_remsiz = clip_bsiz - clip_total;
clip_bp = clip_b + clip_total;
}
}
static void clipboard_copy(void)
{
HANDLE hglb;
if (!OpenClipboard(NULL))
return; // error("Unable to open the clipboard");
if (!EmptyClipboard()) {
CloseClipboard();
return; // error("Unable to empty the clipboard");
}
hglb = GlobalAlloc(GMEM_DDESHARE, clip_total + 1);
if (hglb == NULL) {
CloseClipboard();
return; // error("Unable to allocate clipboard memory");
}
memcpy(hglb, clip_b, clip_total);
((char *)hglb)[clip_total] = '\0';
SetClipboardData(CF_TEXT, hglb);
CloseClipboard();
}
/*
* Windows clipboard support
* Diomidis Spinellis, June 2003
*/
static char *clip_b, *clip_bp; /* Buffer, pointer to buffer insertion point */
static size_t clip_bsiz, clip_remsiz; /* Buffer, size, remaining size */
static size_t clip_total; /* Total read */
#define CLIP_CHUNK 16384
static void clipboard_init(void) {
if (clip_b)
sfree(clip_b);
clip_bp = clip_b = smalloc(clip_remsiz = clip_bsiz = CLIP_CHUNK);
clip_total = 0;
}
static void clipboard_data(const void *buff, int len) {
memcpy(clip_bp, buff, len);
clip_remsiz -= len;
clip_total += len;
clip_bp += len;
if (clip_remsiz < CLIP_CHUNK) {
clip_b = srealloc(clip_b, clip_bsiz *= 2);
clip_remsiz = clip_bsiz - clip_total;
clip_bp = clip_b + clip_total;
}
}
static void clipboard_copy(void) {
HANDLE hglb;
if (!OpenClipboard(NULL))
return; // error("Unable to open the clipboard");
if (!EmptyClipboard()) {
CloseClipboard();
return; // error("Unable to empty the clipboard");
}
hglb = GlobalAlloc(GMEM_DDESHARE, clip_total + 1);
if (hglb == NULL) {
CloseClipboard();
return; // error("Unable to allocate clipboard memory");
}
memcpy(hglb, clip_b, clip_total);
((char *)hglb)[clip_total] = '\0';
SetClipboardData(CF_TEXT, hglb);
CloseClipboard();
}
#endif
/*
@@ -3919,9 +4021,9 @@ static void term_print_setup(Terminal *term, char *printer)
{
bufchain_clear(&term->printer_buf);
#ifdef MOD_PRINTCLIP
if ( conf_get_int(term->conf,CONF_printclip) )
clipboard_init();
else
if ( conf_get_int(term->conf,CONF_printclip) )
clipboard_init();
else
#endif
term->print_job = printer_start_job(printer);
}
@@ -3929,16 +4031,16 @@ static void term_print_flush(Terminal *term)
{
size_t size;
while ((size = bufchain_size(&term->printer_buf)) > 5) {
ptrlen data = bufchain_prefix(&term->printer_buf);
if (data.len > size-5)
data.len = size-5;
ptrlen data = bufchain_prefix(&term->printer_buf);
if (data.len > size-5)
data.len = size-5;
#ifdef MOD_PRINTCLIP
if ( conf_get_int(term->conf,CONF_printclip) )
clipboard_data(data.ptr, data.len);
else
if ( conf_get_int(term->conf,CONF_printclip) )
clipboard_data(data.ptr, data.len);
else
#endif
printer_job_data(term->print_job, data.ptr, data.len);
bufchain_consume(&term->printer_buf, data.len);
printer_job_data(term->print_job, data.ptr, data.len);
bufchain_consume(&term->printer_buf, data.len);
}
}
static void term_print_finish(Terminal *term)
@@ -3947,29 +4049,29 @@ static void term_print_finish(Terminal *term)
char c;
if (!term->printing && !term->only_printing)
return; /* we need do nothing */
return; /* we need do nothing */
term_print_flush(term);
while ((size = bufchain_size(&term->printer_buf)) > 0) {
ptrlen data = bufchain_prefix(&term->printer_buf);
c = *(char *)data.ptr;
if (c == '\033' || c == '\233') {
bufchain_consume(&term->printer_buf, size);
break;
} else {
ptrlen data = bufchain_prefix(&term->printer_buf);
c = *(char *)data.ptr;
if (c == '\033' || c == '\233') {
bufchain_consume(&term->printer_buf, size);
break;
} else {
#ifdef MOD_PRINTCLIP
if ( conf_get_int(term->conf,CONF_printclip) )
clipboard_data(&c, 1);
else
if ( conf_get_int(term->conf,CONF_printclip) )
clipboard_data(&c, 1);
else
#endif
printer_job_data(term->print_job, &c, 1);
bufchain_consume(&term->printer_buf, 1);
}
printer_job_data(term->print_job, &c, 1);
bufchain_consume(&term->printer_buf, 1);
}
}
#ifdef MOD_PRINTCLIP
if ( conf_get_int(term->conf,CONF_printclip) )
clipboard_copy();
else
if ( conf_get_int(term->conf,CONF_printclip) )
clipboard_copy();
else
#endif
printer_finish_job(term->print_job);
term->print_job = NULL;
+10
View File
@@ -137,11 +137,21 @@ unsigned long schedule_timer(int ticks, timer_fn_t fn, void *ctx)
}
first = (struct timer *)index234(timers, 0);
#ifdef MOD_PERSO
if (first == t || first != NULL && first->now + 10 * (TICKSPERSEC) < now) {
/*
* This timer is the very first on the list, so we must
* notify the front end.
* Also notify if the first timer has seriously missed its run time,
* most likely due to a system sleep event.
*/
#else
if (first == t) {
/*
* This timer is the very first on the list, so we must
* notify the front end.
*/
#endif
timer_change_notify(first->now);
}
+1 -1
View File
@@ -1,5 +1,5 @@
#define RELEASE 0.76
#define TEXTVER "Release 0.76"
#define SSHVER "-Release-0.76"
#define BINARY_VERSION 0,76,1,4
#define BINARY_VERSION 0,76,1,13
#define SOURCE_COMMIT "unavailable"
File diff suppressed because it is too large Load Diff
@@ -10,7 +10,7 @@
#include "pageant.h" /* for AGENT_MAX_MSGLEN */
#ifndef NO_SECURITY
#include "winsecur.h"
#include "security-api.h"
#include "cryptoapi.h"
#endif
+4
View File
@@ -502,6 +502,10 @@ void win_setup_config_box(struct controlbox *b, HWND *hwndp, bool has_help,
HELPCTX(no_help),
conf_checkbox_handler,
I(CONF_ctrl_tab_switch));
ctrl_checkbox(s, "Warn before OSC52 clipboard sync", NO_SHORTCUT,
HELPCTX(no_help),
conf_checkbox_handler, I(CONF_osc52_warn_before_cliboard_sync));
}
#endif
ctrl_checkbox(s, "Full screen on Alt-Enter", 'f',
+1 -1
View File
@@ -12,7 +12,7 @@
#include "putty.h"
#include "ssh.h"
#include "putty-rc.h"
#include "winseat.h"
#include "win-gui-seat.h"
#include "storage.h"
#include "dialog.h"
#include "licence.h"
@@ -13,7 +13,7 @@
#if !defined NO_SECURITY
#include "winsecur.h"
#include "security-api.h"
HANDLE connect_to_named_pipe(const char *pipename, char **err)
{
@@ -13,7 +13,7 @@
#if !defined NO_SECURITY
#include "winsecur.h"
#include "security-api.h"
typedef struct NamedPipeServerSocket {
/* Parameters for (repeated) creation of named pipe objects */
@@ -130,6 +130,7 @@ static tree234 *sktree;
int get_param( const char * val ) ;
#endif
#ifdef MOD_ZMODEM
int GetPuttyFlag(void) ;
static int curpass;
#endif
@@ -13,7 +13,7 @@
#include "ssh.h"
#include "misc.h"
#include "tree234.h"
#include "winsecur.h"
#include "security-api.h"
#include "cryptoapi.h"
#include "pageant.h"
#include "licence.h"
+1 -1
View File
@@ -14,7 +14,7 @@
#define APPDESC "PuTTY SSH authentication agent"
#endif
#include "winhelp.rc2"
#include "help.rc2"
#ifdef MOD_INTEGRATED_AGENT
900 ICON "pageant.ico"
@@ -31,7 +31,7 @@
#include "tree234.h"
#include "winhelp.h"
#include "help.h"
#if defined _M_IX86 || defined _M_AMD64
#define BUILDINFO_PLATFORM "x86 Windows"
@@ -10,7 +10,7 @@
#include "putty.h"
#include "storage.h"
#include "tree234.h"
#include "winsecur.h"
#include "security-api.h"
#ifdef MOD_PERSO
// Flag pour le fonctionnement en mode "portable" (gestion par fichiers)
+12
View File
@@ -86,9 +86,15 @@ BEGIN
ICON "", IDC_HK_ICON, 10, 18, 0, 0
#ifdef MOD_PERSO
PUSHBUTTON "&Cancel", IDCANCEL, 288, 128, 40, 14
PUSHBUTTON "&Accept", IDC_HK_ACCEPT, 168, 128, 40, 14
PUSHBUTTON "Connect &Once", IDC_HK_ONCE, 216, 128, 64, 14
#else
PUSHBUTTON "Cancel", IDCANCEL, 288, 128, 40, 14
PUSHBUTTON "Accept", IDC_HK_ACCEPT, 168, 128, 40, 14
PUSHBUTTON "Connect Once", IDC_HK_ONCE, 216, 128, 64, 14
#endif
PUSHBUTTON "More info...", IDC_HK_MOREINFO, 60, 128, 64, 14
PUSHBUTTON "Help", IDHELP, 12, 128, 40, 14
@@ -117,9 +123,15 @@ BEGIN
ICON "", IDC_HK_ICON, 10, 16, 0, 0
#ifdef MOD_PERSO
PUSHBUTTON "&Cancel", IDCANCEL, 288, 168, 40, 14
PUSHBUTTON "&Accept", IDC_HK_ACCEPT, 168, 168, 40, 14
PUSHBUTTON "Connect &Once", IDC_HK_ONCE, 216, 168, 64, 14
#else
PUSHBUTTON "Cancel", IDCANCEL, 288, 168, 40, 14
PUSHBUTTON "Accept", IDC_HK_ACCEPT, 168, 168, 40, 14
PUSHBUTTON "Connect Once", IDC_HK_ONCE, 216, 168, 64, 14
#endif
PUSHBUTTON "More info...", IDC_HK_MOREINFO, 60, 168, 64, 14
PUSHBUTTON "Help", IDHELP, 12, 168, 40, 14
+1 -1
View File
@@ -3,7 +3,7 @@
#define APPNAME "PuTTY"
#define APPDESC "SSH, Telnet, Rlogin, and SUPDUP client"
#include "winhelp.rc2"
#include "help.rc2"
IDI_MAINICON ICON "putty.ico"
@@ -11,7 +11,7 @@
#include "ssh.h"
#include "sshkeygen.h"
#include "licence.h"
#include "winsecur.h"
#include "security-api.h"
#include "puttygen-rc.h"
#include <commctrl.h>
+1 -1
View File
@@ -8,7 +8,7 @@
#define APPNAME_KEYGEN "PuTTYgen"
#define APPDESC_KEYGEN "PuTTY SSH key generation utility"
#include "winhelp.rc2"
#include "help.rc2"
#include "puttygen-rc.h"
800 ICON "puttygen.ico"
+1 -1
View File
@@ -3,7 +3,7 @@
#define APPNAME "PuTTYtel"
#define APPDESC "Telnet and Rlogin client"
#include "winhelp.rc2"
#include "help.rc2"
#include "putty-common.rc2"
#ifndef NO_MANIFESTS
@@ -1,5 +1,5 @@
/*
* winsecur.h: some miscellaneous security-related helper functions,
* security-api.h: some miscellaneous security-related helper functions,
* defined in winsecur.c, that use the advapi32 library. Also
* centralises the machinery for dynamically loading that library.
*/
@@ -10,7 +10,7 @@
#include "putty.h"
#include "psftp.h"
#include "ssh.h"
#include "winsecur.h"
#include "security-api.h"
#ifdef MOD_PERSO
#include <winerror.h>
@@ -14,7 +14,7 @@
#include "ssh.h"
#include "cryptoapi.h"
#include "winsecur.h"
#include "security-api.h"
#define CONNSHARE_PIPE_PREFIX "\\\\.\\pipe\\putty-connshare"
#define CONNSHARE_MUTEX_PREFIX "Local\\putty-connshare-mutex"
@@ -0,0 +1,43 @@
/*
* If the OS provides it, call SetDefaultDllDirectories() to prevent
* DLLs from being loaded from the directory containing our own
* binary, and instead only load from system32.
*
* This is a protection against hijacking attacks, if someone runs
* PuTTY directly from their web browser's download directory having
* previously been enticed into clicking on an unwise link that
* downloaded a malicious DLL to the same directory under one of
* various magic names that seem to be things that standard Windows
* DLLs delegate to.
*
* It shouldn't break deliberate loading of user-provided DLLs such as
* GSSAPI providers, because those are specified by their full
* pathname by the user-provided configuration.
*/
#include "putty.h"
void dll_hijacking_protection(void)
{
static HMODULE kernel32_module;
DECL_WINDOWS_FUNCTION(static, BOOL, SetDefaultDllDirectories, (DWORD));
if (!kernel32_module) {
kernel32_module = load_system32_dll("kernel32.dll");
#if !HAVE_SETDEFAULTDLLDIRECTORIES
/* For older Visual Studio, this function isn't available in
* the header files to type-check */
GET_WINDOWS_FUNCTION_NO_TYPECHECK(
kernel32_module, SetDefaultDllDirectories);
#else
GET_WINDOWS_FUNCTION(kernel32_module, SetDefaultDllDirectories);
#endif
}
if (p_SetDefaultDllDirectories) {
/* LOAD_LIBRARY_SEARCH_SYSTEM32 and explicitly specified
* directories only */
p_SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_SYSTEM32 |
LOAD_LIBRARY_SEARCH_USER_DIRS);
}
}
+39
View File
@@ -0,0 +1,39 @@
/*
* Implementation of dputs() for Windows.
*
* The debug messages are written to STD_OUTPUT_HANDLE, except that
* first it has to make sure that handle _exists_, by calling
* AllocConsole first if necessary.
*
* They also go into a file called debug.log.
*/
#include "putty.h"
#include "utils/utils.h"
static HANDLE debug_fp = INVALID_HANDLE_VALUE;
static HANDLE debug_hdl = INVALID_HANDLE_VALUE;
static int debug_got_console = 0;
void dputs(const char *buf)
{
DWORD dw;
if (!debug_got_console) {
if (AllocConsole()) {
debug_got_console = 1;
debug_hdl = GetStdHandle(STD_OUTPUT_HANDLE);
}
}
if (debug_fp == INVALID_HANDLE_VALUE) {
debug_fp = CreateFile("debug.log", GENERIC_WRITE, FILE_SHARE_READ,
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
}
if (debug_fp != INVALID_HANDLE_VALUE) {
WriteFile(debug_fp, buf, strlen(buf), &dw, NULL);
}
if (debug_hdl != INVALID_HANDLE_VALUE) {
WriteFile(debug_hdl, buf, strlen(buf), &dw, NULL);
}
}
@@ -0,0 +1,48 @@
/*
* Escaping/unescaping functions to translate between a saved session
* name, and the key name used to represent it in the Registry area
* where we store saved sessions.
*
* The basic technique is to %-escape characters we can't use in
* Registry keys.
*/
#include "putty.h"
void escape_registry_key(const char *in, strbuf *out)
{
bool candot = false;
static const char hex[16] = "0123456789ABCDEF";
while (*in) {
if (*in == ' ' || *in == '\\' || *in == '*' || *in == '?' ||
*in == '%' || *in < ' ' || *in > '~' || (*in == '.'
&& !candot)) {
put_byte(out, '%');
put_byte(out, hex[((unsigned char) *in) >> 4]);
put_byte(out, hex[((unsigned char) *in) & 15]);
} else
put_byte(out, *in);
in++;
candot = true;
}
}
void unescape_registry_key(const char *in, strbuf *out)
{
while (*in) {
if (*in == '%' && in[1] && in[2]) {
int i, j;
i = in[1] - '0';
i -= (i > 9 ? 7 : 0);
j = in[2] - '0';
j -= (j > 9 ? 7 : 0);
put_byte(out, (i << 4) + j);
in += 3;
} else {
put_byte(out, *in++);
}
}
}
+54
View File
@@ -0,0 +1,54 @@
/*
* Implementation of Filename for Windows.
*/
#include "putty.h"
Filename *filename_from_str(const char *str)
{
Filename *ret = snew(Filename);
ret->path = dupstr(str);
return ret;
}
Filename *filename_copy(const Filename *fn)
{
return filename_from_str(fn->path);
}
const char *filename_to_str(const Filename *fn)
{
return fn->path;
}
bool filename_equal(const Filename *f1, const Filename *f2)
{
return !strcmp(f1->path, f2->path);
}
bool filename_is_null(const Filename *fn)
{
return !*fn->path;
}
void filename_free(Filename *fn)
{
sfree(fn->path);
sfree(fn);
}
void filename_serialise(BinarySink *bs, const Filename *f)
{
put_asciz(bs, f->path);
}
Filename *filename_deserialise(BinarySource *src)
{
return filename_from_str(get_asciz(src));
}
char filename_char_sanitise(char c)
{
if (strchr("<>:\"/\\|?*", c))
return '.';
return c;
}
+39
View File
@@ -0,0 +1,39 @@
/*
* Implementation of FontSpec for Windows.
*/
#include "putty.h"
FontSpec *fontspec_new(const char *name, bool bold, int height, int charset)
{
FontSpec *f = snew(FontSpec);
f->name = dupstr(name);
f->isbold = bold;
f->height = height;
f->charset = charset;
return f;
}
FontSpec *fontspec_copy(const FontSpec *f)
{
return fontspec_new(f->name, f->isbold, f->height, f->charset);
}
void fontspec_free(FontSpec *f)
{
sfree(f->name);
sfree(f);
}
void fontspec_serialise(BinarySink *bs, FontSpec *f)
{
put_asciz(bs, f->name);
put_uint32(bs, f->isbold);
put_uint32(bs, f->height);
put_uint32(bs, f->charset);
}
FontSpec *fontspec_deserialise(BinarySource *src)
{
const char *name = get_asciz(src);
unsigned isbold = get_uint32(src);
unsigned height = get_uint32(src);
unsigned charset = get_uint32(src);
return fontspec_new(name, isbold, height, charset);
}
@@ -0,0 +1,77 @@
/*
* Implementation of get_username() for Windows.
*/
#include "putty.h"
#ifndef SECURITY_WIN32
#define SECURITY_WIN32
#endif
#include <security.h>
char *get_username(void)
{
DWORD namelen;
char *user;
bool got_username = false;
DECL_WINDOWS_FUNCTION(static, BOOLEAN, GetUserNameExA,
(EXTENDED_NAME_FORMAT, LPSTR, PULONG));
{
static bool tried_usernameex = false;
if (!tried_usernameex) {
/* Not available on Win9x, so load dynamically */
HMODULE secur32 = load_system32_dll("secur32.dll");
/* If MIT Kerberos is installed, the following call to
GET_WINDOWS_FUNCTION makes Windows implicitly load
sspicli.dll WITHOUT proper path sanitizing, so better
load it properly before */
HMODULE sspicli = load_system32_dll("sspicli.dll");
(void)sspicli; /* squash compiler warning about unused variable */
GET_WINDOWS_FUNCTION(secur32, GetUserNameExA);
tried_usernameex = true;
}
}
if (p_GetUserNameExA) {
/*
* If available, use the principal -- this avoids the problem
* that the local username is case-insensitive but Kerberos
* usernames are case-sensitive.
*/
/* Get the length */
namelen = 0;
(void) p_GetUserNameExA(NameUserPrincipal, NULL, &namelen);
user = snewn(namelen, char);
got_username = p_GetUserNameExA(NameUserPrincipal, user, &namelen);
if (got_username) {
char *p = strchr(user, '@');
if (p) *p = 0;
} else {
sfree(user);
}
}
if (!got_username) {
/* Fall back to local user name */
namelen = 0;
if (!GetUserName(NULL, &namelen)) {
/*
* Apparently this doesn't work at least on Windows XP SP2.
* Thus assume a maximum of 256. It will fail again if it
* doesn't fit.
*/
namelen = 256;
}
user = snewn(namelen, char);
got_username = GetUserName(user, &namelen);
if (!got_username) {
sfree(user);
}
}
return got_username ? user : NULL;
}
@@ -0,0 +1,20 @@
/*
* Handy wrapper around GetDlgItemText which doesn't make you invent
* an arbitrary length limit on the output string. Returned string is
* dynamically allocated; caller must free.
*/
#include "putty.h"
char *GetDlgItemText_alloc(HWND hwnd, int id)
{
char *ret = NULL;
size_t size = 0;
do {
sgrowarray_nm(ret, size, size);
GetDlgItemText(hwnd, id, ret, size);
} while (!memchr(ret, '\0', size-1));
return ret;
}
@@ -0,0 +1,13 @@
/*
* Determine whether a Windows HANDLE points at a console device.
*/
#include "putty.h"
bool is_console_handle(HANDLE handle)
{
DWORD ignored_output;
if (GetConsoleMode(handle, &ignored_output))
return true;
return false;
}
@@ -0,0 +1,32 @@
/*
* Wrapper function to load a DLL out of c:\windows\system32 without
* going through the full DLL search path. (Hence no attack is
* possible by placing a substitute DLL earlier on that path.)
*/
#include "putty.h"
HMODULE load_system32_dll(const char *libname)
{
/*
* Wrapper function to load a DLL out of c:\windows\system32
* without going through the full DLL search path. (Hence no
* attack is possible by placing a substitute DLL earlier on that
* path.)
*/
static char *sysdir = NULL;
static size_t sysdirsize = 0;
char *fullpath;
HMODULE ret;
if (!sysdir) {
size_t len;
while ((len = GetSystemDirectory(sysdir, sysdirsize)) >= sysdirsize)
sgrowarray(sysdir, sysdirsize, len);
}
fullpath = dupcat(sysdir, "\\", libname);
ret = LoadLibrary(fullpath);
sfree(fullpath);
return ret;
}
@@ -0,0 +1,19 @@
/*
* Helper function to remove the border around a dialog item such as
* a read-only edit control.
*/
#include "putty.h"
void MakeDlgItemBorderless(HWND parent, int id)
{
HWND child = GetDlgItem(parent, id);
LONG_PTR style = GetWindowLongPtr(child, GWL_STYLE);
LONG_PTR exstyle = GetWindowLongPtr(child, GWL_EXSTYLE);
style &= ~WS_BORDER;
exstyle &= ~(WS_EX_CLIENTEDGE | WS_EX_STATICEDGE | WS_EX_WINDOWEDGE);
SetWindowLongPtr(child, GWL_STYLE, style);
SetWindowLongPtr(child, GWL_EXSTYLE, exstyle);
SetWindowPos(child, NULL, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
}
@@ -0,0 +1,49 @@
/*
* Message box with optional context help.
*/
#include "putty.h"
static HWND message_box_owner;
/* Callback function to launch context help. */
static VOID CALLBACK message_box_help_callback(LPHELPINFO lpHelpInfo)
{
const char *context = NULL;
#define CHECK_CTX(name) \
do { \
if (lpHelpInfo->dwContextId == WINHELP_CTXID_ ## name) \
context = WINHELP_CTX_ ## name; \
} while (0)
CHECK_CTX(errors_hostkey_absent);
CHECK_CTX(errors_hostkey_changed);
CHECK_CTX(errors_cantloadkey);
CHECK_CTX(option_cleanup);
CHECK_CTX(pgp_fingerprints);
#undef CHECK_CTX
if (context)
launch_help(message_box_owner, context);
}
int message_box(HWND owner, LPCTSTR text, LPCTSTR caption,
DWORD style, DWORD helpctxid)
{
MSGBOXPARAMS mbox;
/*
* We use MessageBoxIndirect() because it allows us to specify a
* callback function for the Help button.
*/
mbox.cbSize = sizeof(mbox);
/* Assumes the globals `hinst' and `hwnd' have sensible values. */
mbox.hInstance = hinst;
mbox.hwndOwner = message_box_owner = owner;
mbox.lpfnMsgBoxCallback = &message_box_help_callback;
mbox.dwLanguageId = LANG_NEUTRAL;
mbox.lpszText = text;
mbox.lpszCaption = caption;
mbox.dwContextHelpId = helpctxid;
mbox.dwStyle = style;
if (helpctxid != 0 && has_help()) mbox.dwStyle |= MB_HELP;
return MessageBoxIndirect(&mbox);
}
@@ -1,26 +1,17 @@
/*
* winmiscs.c: Windows-specific standalone functions. Has the same
* relationship to winmisc.c that utils.c does to misc.c, but the
* corresponding name 'winutils.c' was already taken.
* 'Minefield' - a crude Windows memory debugger, similar in concept
* to the old Unix 'Electric Fence'. The main difference is that
* Electric Fence can be imposed on a program from outside, via
* LD_PRELOAD, whereas this has to be included in the program at
* compile time with its own cooperation.
*
* This module provides the Minefield allocator. Actually enabling it
* is done by a #define in force when the main utils/memory.c is
* compiled.
*/
#include "putty.h"
#ifndef NO_SECUREZEROMEMORY
/*
* Windows implementation of smemclr (see misc.c) using SecureZeroMemory.
*/
void smemclr(void *b, size_t n) {
if (b && n > 0)
SecureZeroMemory(b, n);
}
#endif
#ifdef MINEFIELD
/*
* Minefield - a Windows equivalent for Electric Fence
*/
#define PAGESIZE 4096
/*
@@ -234,52 +225,3 @@ void *minefield_c_realloc(void *p, size_t size)
minefield_free(p);
return q;
}
#endif /* MINEFIELD */
#if defined _MSC_VER && _MSC_VER < 1800
/*
* Work around lack of strtoumax in older MSVC libraries
*/
uintmax_t strtoumax(const char *nptr, char **endptr, int base)
{
return _strtoui64(nptr, endptr, base);
}
#endif
#if defined _M_ARM || defined _M_ARM64
bool platform_aes_hw_available(void)
{
return IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE);
}
bool platform_sha256_hw_available(void)
{
return IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE);
}
bool platform_sha1_hw_available(void)
{
return IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE);
}
bool platform_sha512_hw_available(void)
{
/* As of 2020-12-24, as far as I can tell from docs.microsoft.com,
* Windows on Arm does not yet provide a PF_ARM_V8_* flag for the
* SHA-512 architecture extension. */
return false;
}
#endif
bool is_console_handle(HANDLE handle)
{
DWORD ignored_output;
if (GetConsoleMode(handle, &ignored_output))
return true;
return false;
}
@@ -0,0 +1,47 @@
/*
* Implementation of open_for_write_would_lose_data for Windows.
*/
#include "putty.h"
/*
* This is slightly fiddly because we want to be backwards-compatible
* with systems too old to have GetFileAttributesEx. The next best
* thing is FindFirstFile, which will return a different data
* structure, but one that also contains the fields we want. (But it
* will behave more unhelpfully - for this application - in the
* presence of wildcards, so we'd prefer to use GFAE if we can.)
*/
bool open_for_write_would_lose_data(const Filename *fn)
{
WIN32_FILE_ATTRIBUTE_DATA attrs;
if (!GetFileAttributesEx(fn->path, GetFileExInfoStandard, &attrs)) {
/*
* Generally, if we don't identify a specific reason why we
* should return true from this function, we return false, and
* let the subsequent attempt to open the file for real give a
* more useful error message.
*/
return false;
}
if (attrs.dwFileAttributes & (FILE_ATTRIBUTE_DEVICE |
FILE_ATTRIBUTE_DIRECTORY)) {
/*
* File is something other than an ordinary disk file, so
* opening it for writing will not cause truncation. (It may
* not _succeed_ either, but that's not our problem here!)
*/
return false;
}
if (attrs.nFileSizeHigh == 0 && attrs.nFileSizeLow == 0) {
/*
* File is zero-length (or may be a named pipe, which
* dwFileAttributes can't tell apart from a regular file), so
* opening it for writing won't truncate any data away because
* there's nothing to truncate anyway.
*/
return false;
}
return true;
}
@@ -0,0 +1,25 @@
/*
* Display the fingerprints of the PGP Master Keys to the user as a
* GUI message box.
*/
#include "putty.h"
void pgp_fingerprints_msgbox(HWND owner)
{
message_box(
owner,
"These are the fingerprints of the PuTTY PGP Master Keys. They can\n"
"be used to establish a trust path from this executable to another\n"
"one. See the manual for more information.\n"
"(Note: these fingerprints have nothing to do with SSH!)\n"
"\n"
"PuTTY Master Key as of " PGP_MASTER_KEY_YEAR
" (" PGP_MASTER_KEY_DETAILS "):\n"
" " PGP_MASTER_KEY_FP "\n\n"
"Previous Master Key (" PGP_PREV_MASTER_KEY_YEAR
", " PGP_PREV_MASTER_KEY_DETAILS "):\n"
" " PGP_PREV_MASTER_KEY_FP,
"PGP fingerprints", MB_ICONINFORMATION | MB_OK,
HELPCTXID(pgp_fingerprints));
}
@@ -0,0 +1,12 @@
/*
* Implementation of platform_get_x_display for Windows, common to all
* tools.
*/
#include "putty.h"
char *platform_get_x_display(void)
{
/* We may as well check for DISPLAY in case it's useful. */
return dupstr(getenv("DISPLAY"));
}
@@ -0,0 +1,43 @@
/*
* Self-contained function to try to fetch a single string value from
* the Registry, and return it as a dynamically allocated C string.
*/
#include "putty.h"
char *registry_get_string(HKEY root, const char *path, const char *leaf)
{
HKEY key = root;
bool need_close_key = false;
char *toret = NULL, *str = NULL;
if (path) {
if (RegCreateKey(key, path, &key) != ERROR_SUCCESS)
goto out;
need_close_key = true;
}
DWORD type, size;
if (RegQueryValueEx(key, leaf, 0, &type, NULL, &size) != ERROR_SUCCESS)
goto out;
if (type != REG_SZ)
goto out;
str = snewn(size + 1, char);
DWORD size_got = size;
if (RegQueryValueEx(key, leaf, 0, &type, (LPBYTE)str,
&size_got) != ERROR_SUCCESS)
goto out;
if (type != REG_SZ || size_got > size)
goto out;
str[size_got] = '\0';
toret = str;
str = NULL;
out:
if (need_close_key)
RegCloseKey(key);
sfree(str);
return toret;
}
@@ -0,0 +1,71 @@
/*
* GetOpenFileName/GetSaveFileName tend to muck around with the process'
* working directory on at least some versions of Windows.
* Here's a wrapper that gives more control over this, and hides a little
* bit of other grottiness.
*/
#include "putty.h"
struct filereq_tag {
TCHAR cwd[MAX_PATH];
};
/*
* `of' is expected to be initialised with most interesting fields, but
* this function does some administrivia. (assume `of' was memset to 0)
* save==1 -> GetSaveFileName; save==0 -> GetOpenFileName
* `state' is optional.
*/
bool request_file(filereq *state, OPENFILENAME *of, bool preserve, bool save)
{
TCHAR cwd[MAX_PATH]; /* process CWD */
bool ret;
/* Get process CWD */
if (preserve) {
DWORD r = GetCurrentDirectory(lenof(cwd), cwd);
if (r == 0 || r >= lenof(cwd))
/* Didn't work, oh well. Stop trying to be clever. */
preserve = false;
}
/* Open the file requester, maybe setting lpstrInitialDir */
{
#ifdef OPENFILENAME_SIZE_VERSION_400
of->lStructSize = OPENFILENAME_SIZE_VERSION_400;
#else
of->lStructSize = sizeof(*of);
#endif
of->lpstrInitialDir = (state && state->cwd[0]) ? state->cwd : NULL;
/* Actually put up the requester. */
ret = save ? GetSaveFileName(of) : GetOpenFileName(of);
}
/* Get CWD left by requester */
if (state) {
DWORD r = GetCurrentDirectory(lenof(state->cwd), state->cwd);
if (r == 0 || r >= lenof(state->cwd))
/* Didn't work, oh well. */
state->cwd[0] = '\0';
}
/* Restore process CWD */
if (preserve)
/* If it fails, there's not much we can do. */
(void) SetCurrentDirectory(cwd);
return ret;
}
filereq *filereq_new(void)
{
filereq *ret = snew(filereq);
ret->cwd[0] = '\0';
return ret;
}
void filereq_free(filereq *state)
{
sfree(state);
}
@@ -1,5 +1,5 @@
/*
* winsecur.c: implementation of winsecur.h.
* winsecur.c: implementation of security-api.h.
*/
#include <stdio.h>
@@ -9,7 +9,7 @@
#if !defined NO_SECURITY
#include "winsecur.h"
#include "security-api.h"
/* Initialised once, then kept around to reuse forever */
static PSID worldsid, networksid, usersid;
+52
View File
@@ -0,0 +1,52 @@
/*
* Securely wipe memory.
*
* The actual wiping is no different from what memset would do: the
* point of 'securely' is to try to be sure over-clever compilers
* won't optimise away memsets on variables that are about to be freed
* or go out of scope. See
* https://buildsecurityin.us-cert.gov/bsi-rules/home/g1/771-BSI.html
*/
#include "defs.h"
#include "misc.h"
/*
* Trivial function that is given a pointer to some memory and ignores
* it.
*/
static void no_op(void *ptr, size_t size) {}
/*
* Function pointer that is given a pointer to some memory, and from
* the compiler's point of view, _might_ read it, or otherwise depend
* on its contents.
*
* In fact, this function pointer always points to no_op() above. But
* because the pointer itself is volatile-qualified, the compiler
* isn't allowed to optimise based on the assumption that that will
* always be the case. So it has to call through the function pointer
* anyway, on the basis that it _might_ have magically changed at run
* time into a pointer to some completely arbitrary function. And
* therefore it must also avoid optimising away any observable effect
* beforehand that a completely arbitrary function might depend on -
* such as the zeroing of our memory region.
*/
static void (*const volatile maybe_read)(void *ptr, size_t size) = no_op;
void smemclr(void *b, size_t n)
{
if (b && n > 0) {
/*
* Zero out the memory.
*/
memset(b, 0, n);
/*
* Call the above function pointer, which (for all the
* compiler knows) might check that we've really zeroed the
* memory.
*/
maybe_read(b, n);
}
}
@@ -1,197 +1,3 @@
/*
* winutils.c: miscellaneous Windows utilities for GUI apps
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "putty.h"
#include "misc.h"
#ifdef TESTMODE
/* Definitions to allow this module to be compiled standalone for testing
* split_into_argv(). */
#define smalloc malloc
#define srealloc realloc
#define sfree free
#endif
/*
* GetOpenFileName/GetSaveFileName tend to muck around with the process'
* working directory on at least some versions of Windows.
* Here's a wrapper that gives more control over this, and hides a little
* bit of other grottiness.
*/
struct filereq_tag {
TCHAR cwd[MAX_PATH];
};
/*
* `of' is expected to be initialised with most interesting fields, but
* this function does some administrivia. (assume `of' was memset to 0)
* save==1 -> GetSaveFileName; save==0 -> GetOpenFileName
* `state' is optional.
*/
bool request_file(filereq *state, OPENFILENAME *of, bool preserve, bool save)
{
TCHAR cwd[MAX_PATH]; /* process CWD */
bool ret;
/* Get process CWD */
if (preserve) {
DWORD r = GetCurrentDirectory(lenof(cwd), cwd);
if (r == 0 || r >= lenof(cwd))
/* Didn't work, oh well. Stop trying to be clever. */
preserve = false;
}
/* Open the file requester, maybe setting lpstrInitialDir */
{
#ifdef OPENFILENAME_SIZE_VERSION_400
of->lStructSize = OPENFILENAME_SIZE_VERSION_400;
#else
of->lStructSize = sizeof(*of);
#endif
of->lpstrInitialDir = (state && state->cwd[0]) ? state->cwd : NULL;
/* Actually put up the requester. */
ret = save ? GetSaveFileName(of) : GetOpenFileName(of);
}
/* Get CWD left by requester */
if (state) {
DWORD r = GetCurrentDirectory(lenof(state->cwd), state->cwd);
if (r == 0 || r >= lenof(state->cwd))
/* Didn't work, oh well. */
state->cwd[0] = '\0';
}
/* Restore process CWD */
if (preserve)
/* If it fails, there's not much we can do. */
(void) SetCurrentDirectory(cwd);
return ret;
}
filereq *filereq_new(void)
{
filereq *ret = snew(filereq);
ret->cwd[0] = '\0';
return ret;
}
void filereq_free(filereq *state)
{
sfree(state);
}
/*
* Message box with optional context help.
*/
static HWND message_box_owner;
/* Callback function to launch context help. */
static VOID CALLBACK message_box_help_callback(LPHELPINFO lpHelpInfo)
{
const char *context = NULL;
#define CHECK_CTX(name) \
do { \
if (lpHelpInfo->dwContextId == WINHELP_CTXID_ ## name) \
context = WINHELP_CTX_ ## name; \
} while (0)
CHECK_CTX(errors_hostkey_absent);
CHECK_CTX(errors_hostkey_changed);
CHECK_CTX(errors_cantloadkey);
CHECK_CTX(option_cleanup);
CHECK_CTX(pgp_fingerprints);
#undef CHECK_CTX
if (context)
launch_help(message_box_owner, context);
}
int message_box(HWND owner, LPCTSTR text, LPCTSTR caption,
DWORD style, DWORD helpctxid)
{
MSGBOXPARAMS mbox;
/*
* We use MessageBoxIndirect() because it allows us to specify a
* callback function for the Help button.
*/
mbox.cbSize = sizeof(mbox);
/* Assumes the globals `hinst' and `hwnd' have sensible values. */
mbox.hInstance = hinst;
mbox.hwndOwner = message_box_owner = owner;
mbox.lpfnMsgBoxCallback = &message_box_help_callback;
mbox.dwLanguageId = LANG_NEUTRAL;
mbox.lpszText = text;
mbox.lpszCaption = caption;
mbox.dwContextHelpId = helpctxid;
mbox.dwStyle = style;
if (helpctxid != 0 && has_help()) mbox.dwStyle |= MB_HELP;
return MessageBoxIndirect(&mbox);
}
/*
* Display the fingerprints of the PGP Master Keys to the user.
*/
void pgp_fingerprints_msgbox(HWND owner)
{
message_box(
owner,
"These are the fingerprints of the PuTTY PGP Master Keys. They can\n"
"be used to establish a trust path from this executable to another\n"
"one. See the manual for more information.\n"
"(Note: these fingerprints have nothing to do with SSH!)\n"
"\n"
"PuTTY Master Key as of " PGP_MASTER_KEY_YEAR
" (" PGP_MASTER_KEY_DETAILS "):\n"
" " PGP_MASTER_KEY_FP "\n\n"
"Previous Master Key (" PGP_PREV_MASTER_KEY_YEAR
", " PGP_PREV_MASTER_KEY_DETAILS "):\n"
" " PGP_PREV_MASTER_KEY_FP,
"PGP fingerprints", MB_ICONINFORMATION | MB_OK,
HELPCTXID(pgp_fingerprints));
}
/*
* Helper function to remove the border around a dialog item such as
* a read-only edit control.
*/
void MakeDlgItemBorderless(HWND parent, int id)
{
HWND child = GetDlgItem(parent, id);
LONG_PTR style = GetWindowLongPtr(child, GWL_STYLE);
LONG_PTR exstyle = GetWindowLongPtr(child, GWL_EXSTYLE);
style &= ~WS_BORDER;
exstyle &= ~(WS_EX_CLIENTEDGE | WS_EX_STATICEDGE | WS_EX_WINDOWEDGE);
SetWindowLongPtr(child, GWL_STYLE, style);
SetWindowLongPtr(child, GWL_EXSTYLE, exstyle);
SetWindowPos(child, NULL, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
}
/*
* Handy wrapper around GetDlgItemText which doesn't make you invent
* an arbitrary length limit on the output string. Returned string is
* dynamically allocated; caller must free.
*/
char *GetDlgItemText_alloc(HWND hwnd, int id)
{
char *ret = NULL;
size_t size = 0;
do {
sgrowarray_nm(ret, size, size);
GetDlgItemText(hwnd, id, ret, size);
} while (!memchr(ret, '\0', size-1));
return ret;
}
/*
* Split a complete command line into argc/argv, attempting to do it
* exactly the same way the Visual Studio C library would do it (so
@@ -211,6 +17,8 @@ char *GetDlgItemText_alloc(HWND hwnd, int id)
* `argstart' can be safely left NULL.
*/
#include "putty.h"
/*
* The precise argument-breaking rules vary with compiler version, or
* rather, with the crt0-type startup code that comes with each
@@ -243,6 +51,9 @@ char *GetDlgItemText_alloc(HWND hwnd, int id)
* or more backslashes precedes two or more double quotes, starting
* inside a double-quoted string.
*
* Modern Visual Studio (as of 2021)
* ---------------------------------
*
* I investigated this in an ordinary CLI program, using the
* toolchain's crt0 to split a command line of the form
*
@@ -279,6 +90,9 @@ char *GetDlgItemText_alloc(HWND hwnd, int id)
* either opens or closes a quoted string, and if it closes one, it
* generates a literal " as a side effect.
*
* Older Visual Studio
* -------------------
*
* But here's the corresponding table from the older Visual Studio 7:
*
* backslashes
@@ -299,48 +113,47 @@ char *GetDlgItemText_alloc(HWND hwnd, int id)
* 10 0,3,n | 0,4,y 1,3,n 1,4,y 2,3,n
* 11 0,4,n | 0,4,n 1,4,n 1,4,n 2,4,n
*
* There is very weird mod-3 behaviour going on here in the
* number of quotes, and it even applies when there aren't any
* backslashes! How ghastly.
* There is very weird mod-3 behaviour going on here in the number of
* quotes, and it even applies when there aren't any backslashes! How
* ghastly.
*
* With a bit of thought, this extremely odd diagram suddenly
* coalesced itself into a coherent, if still ghastly, model of
* how things work:
* coalesced itself into a coherent, if still ghastly, model of how
* things work:
*
* - As before, backslashes are only special when one or more
* of them appear contiguously before at least one double
* quote. In this situation the backslashes do exactly what
* you'd expect: each one quotes the next thing in front of
* it, so you end up with n/2 literal backslashes (if n is
* even) or (n-1)/2 literal backslashes and a literal quote
* (if n is odd). In the latter case the double quote
* character right after the backslashes is used up.
* - As before, backslashes are only special when one or more of them
* appear contiguously before at least one double quote. In this
* situation the backslashes do exactly what you'd expect: each one
* quotes the next thing in front of it, so you end up with n/2
* literal backslashes (if n is even) or (n-1)/2 literal
* backslashes and a literal quote (if n is odd). In the latter
* case the double quote character right after the backslashes is
* used up.
*
* - After that, any remaining double quotes are processed. A
* string of contiguous unescaped double quotes has a mod-3
* behaviour:
* - After that, any remaining double quotes are processed. A string
* of contiguous unescaped double quotes has a mod-3 behaviour:
*
* * inside a quoted segment, a quote ends the segment.
* * _immediately_ after ending a quoted segment, a quote
* simply produces a literal quote.
* * otherwise, outside a quoted segment, a quote begins a
* quoted segment.
* * _immediately_ after ending a quoted segment, a quote simply
* produces a literal quote.
* * otherwise, outside a quoted segment, a quote begins a quoted
* segment.
*
* So, for example, if we started inside a quoted segment
* then two contiguous quotes would close the segment and
* produce a literal quote; three would close the segment,
* produce a literal quote, and open a new segment. If we
* started outside a quoted segment, then two contiguous
* quotes would open and then close a segment, producing no
* output (but potentially creating a zero-length argument);
* but three quotes would open and close a segment and then
* produce a literal quote.
*/
/*
* We select between two behaviours depending on the version of Visual
* Studio (see large comment below). I don't know exactly when the bug
* fix happened, but I know that VS7 had the odd mod-3 behaviour.
* So, for example, if we started inside a quoted segment then two
* contiguous quotes would close the segment and produce a literal
* quote; three would close the segment, produce a literal quote,
* and open a new segment. If we started outside a quoted segment,
* then two contiguous quotes would open and then close a segment,
* producing no output (but potentially creating a zero-length
* argument); but three quotes would open and close a segment and
* then produce a literal quote.
*
* I don't know exactly when the bug fix happened, but I know that VS7
* had the odd mod-3 behaviour. So the #if below will ensure that
* modern (2015 onwards) versions of VS use the new more sensible
* behaviour, and VS7 uses the old one. Things in between may be
* wrong; if anyone cares, patches to change the cutoff version in
* this #if are welcome.
*/
#if _MSC_VER < 1400
#define MOD3 1
@@ -455,7 +268,7 @@ void split_into_argv(char *cmdline, int *argc, char ***argv,
if (argstart) *argstart = outputargstart; else sfree(outputargstart);
}
#ifdef TESTMODE
#ifdef TEST
const struct argv_test {
const char *cmdline;
@@ -652,6 +465,12 @@ const struct argv_test {
#endif /* MOD3 */
};
void out_of_memory(void)
{
fprintf(stderr, "out of memory!\n");
exit(2);
}
int main(int argc, char **argv)
{
int i, j;
@@ -692,27 +511,29 @@ int main(int argc, char **argv)
}
if (!strcmp(argv[1], "-split") && argc > 2) {
char *str = malloc(20 + strlen(argv[0]) + strlen(argv[2]));
char *p, *q;
strbuf *cmdline = strbuf_new();
char *p;
q = str + sprintf(str, "%s -splat ", argv[0]);
put_fmt(cmdline, "%s -splat ", argv[0]);
printf(" {\"");
for (p = argv[2]; *p; p++, q++) {
switch (*p) {
case '/': printf("\\\\"); *q = '\\'; break;
case '\'': printf("\\\""); *q = '"'; break;
case '_': printf(" "); *q = ' '; break;
default: putchar(*p); *q = *p; break;
}
size_t args_start = cmdline->len;
for (p = argv[2]; *p; p++) {
char c = (*p == '/' ? '\\' :
*p == '\'' ? '"' :
*p == '_' ? ' ' :
*p);
put_byte(cmdline, c);
}
*p = '\0';
write_c_string_literal(stdout, ptrlen_from_asciz(
cmdline->s + args_start));
printf("\", {");
fflush(stdout);
system(str);
system(cmdline->s);
printf("}},\n");
strbuf_free(cmdline);
return 0;
}
@@ -745,6 +566,83 @@ int main(int argc, char **argv)
return 0;
}
if (!strcmp(argv[1], "-tabulate")) {
char table[] = "\
* backslashes \n\
* \n\
* 0 1 2 3 4 \n\
* \n\
* 0 | \n\
* --------+----------------------------- \n\
* 1 | \n\
* q 2 | \n\
* u 3 | \n\
* o 4 | \n\
* t 5 | \n\
* e 6 | \n\
* s 7 | \n\
* 8 | \n\
";
char *linestarts[14];
char *p = table;
for (i = 0; i < lenof(linestarts); i++) {
linestarts[i] = p;
p += strcspn(p, "\n");
if (*p) p++;
}
for (i = 0; i < lenof(argv_tests); i++) {
const struct argv_test *test = &argv_tests[i];
const char *q = test->cmdline;
/* Skip tests that aren't telling us something about
* the behaviour _inside_ a quoted string */
if (*q != '"')
continue;
q++;
assert(*q == 'a');
q++;
int backslashes_in = 0, quotes_in = 0;
while (*q == '\\') {
q++;
backslashes_in++;
}
while (*q == '"') {
q++;
quotes_in++;
}
q = test->argv[0];
assert(*q == 'a');
q++;
int backslashes_out = 0, quotes_out = 0;
while (*q == '\\') {
q++;
backslashes_out++;
}
while (*q == '"') {
q++;
quotes_out++;
}
assert(*q == 'b');
q++;
bool in_quoted_string = (*q == ' ');
int x = (backslashes_in == 0 ? 15 : 18 + 7 * backslashes_in);
int y = (quotes_in == 0 ? 4 : 5 + quotes_in);
char *buf = dupprintf("%d,%d,%c",
backslashes_out, quotes_out,
in_quoted_string ? 'y' : 'n');
memcpy(linestarts[y] + x, buf, strlen(buf));
sfree(buf);
}
fputs(table, stdout);
return 0;
}
fprintf(stderr, "unrecognised option: \"%s\"\n", argv[1]);
return 1;
}
@@ -753,18 +651,21 @@ int main(int argc, char **argv)
* If we get here, we were invoked with no arguments, so just
* run the tests.
*/
int passes = 0, fails = 0;
for (i = 0; i < lenof(argv_tests); i++) {
int ac;
char **av;
bool failed = false;
split_into_argv(argv_tests[i].cmdline, &ac, &av);
split_into_argv((char *)argv_tests[i].cmdline, &ac, &av, NULL);
for (j = 0; j < ac && argv_tests[i].argv[j]; j++) {
if (strcmp(av[j], argv_tests[i].argv[j])) {
printf("failed test %d (|%s|) arg %d: |%s| should be |%s|\n",
i, argv_tests[i].cmdline,
j, av[j], argv_tests[i].argv[j]);
failed = true;
}
#ifdef VERBOSE
else {
@@ -774,15 +675,33 @@ int main(int argc, char **argv)
}
#endif
}
if (j < ac)
if (j < ac) {
printf("failed test %d (|%s|): %d args returned, should be %d\n",
i, argv_tests[i].cmdline, ac, j);
if (argv_tests[i].argv[j])
failed = true;
}
if (argv_tests[i].argv[j]) {
printf("failed test %d (|%s|): %d args returned, should be more\n",
i, argv_tests[i].cmdline, ac);
failed = true;
}
if (failed)
fails++;
else
passes++;
}
return 0;
printf("passed %d failed %d (%s mode)\n",
passes, fails,
#if MOD3
"mod 3"
#else
"mod 2"
#endif
);
return fails != 0;
}
#endif
#endif /* TEST */
+12
View File
@@ -0,0 +1,12 @@
/*
* Work around lack of strtoumax in older MSVC libraries.
*/
#include <stdlib.h>
#include "defs.h"
uintmax_t strtoumax(const char *nptr, char **endptr, int base)
{
return _strtoui64(nptr, endptr, base);
}
+45
View File
@@ -0,0 +1,45 @@
#include "putty.h"
DWORD osMajorVersion, osMinorVersion, osPlatformId;
void init_winver(void)
{
static bool initialised = false;
if (initialised)
return;
initialised = true;
OSVERSIONINFO osVersion;
static HMODULE kernel32_module;
DECL_WINDOWS_FUNCTION(static, BOOL, GetVersionExA, (LPOSVERSIONINFO));
if (!kernel32_module) {
kernel32_module = load_system32_dll("kernel32.dll");
/* Deliberately don't type-check this function, because that
* would involve using its declaration in a header file which
* triggers a deprecation warning. I know it's deprecated (see
* below) and don't need telling. */
GET_WINDOWS_FUNCTION_NO_TYPECHECK(kernel32_module, GetVersionExA);
}
ZeroMemory(&osVersion, sizeof(osVersion));
osVersion.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
if (p_GetVersionExA && p_GetVersionExA(&osVersion)) {
osMajorVersion = osVersion.dwMajorVersion;
osMinorVersion = osVersion.dwMinorVersion;
osPlatformId = osVersion.dwPlatformId;
} else {
/*
* GetVersionEx is deprecated, so allow for it perhaps going
* away in future API versions. If it's not there, simply
* assume that's because Windows is too _new_, so fill in the
* variables we care about to a value that will always compare
* higher than any given test threshold.
*
* Normally we should be checking against the presence of a
* specific function if possible in any case.
*/
osMajorVersion = osMinorVersion = UINT_MAX; /* a very high number */
osPlatformId = VER_PLATFORM_WIN32_NT; /* not Win32s or Win95-like */
}
}
@@ -0,0 +1,72 @@
/*
* Wrapper around the Windows FormatMessage system for retrieving the
* text of a system error code, with a simple API similar to strerror.
*
* Works by keeping a tree234 containing mappings from system error
* codes to strings. Entries allocated in this tree are simply never
* freed.
*
* Also, the returned string has its trailing newline removed (so it
* can go in places like the Event Log that never want a newline), and
* is prefixed with the error number (so that if a user sends an error
* report containing a translated error message we can't read, we can
* still find out what the error actually was).
*/
#include "putty.h"
struct errstring {
int error;
char *text;
};
static int errstring_find(void *av, void *bv)
{
int *a = (int *)av;
struct errstring *b = (struct errstring *)bv;
if (*a < b->error)
return -1;
if (*a > b->error)
return +1;
return 0;
}
static int errstring_compare(void *av, void *bv)
{
struct errstring *a = (struct errstring *)av;
return errstring_find(&a->error, bv);
}
static tree234 *errstrings = NULL;
const char *win_strerror(int error)
{
struct errstring *es;
if (!errstrings)
errstrings = newtree234(errstring_compare);
es = find234(errstrings, &error, errstring_find);
if (!es) {
char msgtext[65536]; /* maximum size for FormatMessage is 64K */
es = snew(struct errstring);
es->error = error;
if (!FormatMessage((FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS), NULL, error,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
msgtext, lenof(msgtext)-1, NULL)) {
sprintf(msgtext,
"(unable to format: FormatMessage returned %u)",
(unsigned int)GetLastError());
} else {
int len = strlen(msgtext);
if (len > 0 && msgtext[len-1] == '\n')
msgtext[len-1] = '\0';
}
es->text = dupprintf("Error %d: %s", error, msgtext);
add234(errstrings, es);
}
return es->text;
}
+1 -1
View File
@@ -1 +1 @@
4
13
+143 -138
View File
@@ -28,8 +28,8 @@
#include "terminal.h"
#include "storage.h"
#include "putty-rc.h"
#include "winsecur.h"
#include "winseat.h"
#include "security-api.h"
#include "win-gui-seat.h"
#include "tree234.h"
#ifndef NO_MULTIMON
@@ -685,22 +685,24 @@ static void start_backend(void)
start_backend() ;
return ;
}
} else {
} else if( !is_backend_first_connected ) {
MessageBox(NULL, msg, str, MB_OK);
}
}
sfree(str);
sfree(msg);
SetSSHConnected(0) ;
queue_toplevel_callback(close_session, NULL);
session_closed = true;
if( GetAutoreconnectFlag() && conf_get_int(conf,CONF_failure_reconnect) && is_backend_first_connected ) {
SetConnBreakIcon(wgs.term_hwnd) ;
SetSSHConnected(0) ;
queue_toplevel_callback(close_session, NULL);
session_closed = true;
lp_eventlog(&wgs.logpolicy, "Unable to connect, trying to reconnect...") ;
SetTimer(wgs.term_hwnd, TIMER_RECONNECT, GetReconnectDelay()*1000, NULL) ;
return ;
}
else
if( is_backend_first_connected ) {
return ;
}
#else
char *str = dupprintf("%s Error", appname);
char *msg = dupprintf("Unable to open connection to\n%s\n%s",
@@ -4555,8 +4557,8 @@ free(cmd);
else return DefWindowProc(hwnd, message, wParam, lParam);
break;
case WM_COPYDATA: { // Reception d'un de donnees dans un message
#ifdef MOD_RUTTY
case WM_COPYDATA: { // Receive data in message
#ifdef MOD_RUTTY1
COPYDATASTRUCT *cds;
cds = (COPYDATASTRUCT *) lParam;
if (cds->dwData == ruttyAHK_send)
@@ -4578,15 +4580,15 @@ free(cmd);
return 0; /* not our message */
}
#else
PCOPYDATASTRUCT pMyCDS = (PCOPYDATASTRUCT) lParam;
switch( pMyCDS->dwData ) {
case 1: // Reception d'une chaine de caracteres a envoyer dans le terminal
if( pMyCDS->cbData > 0 ) {
SendKeyboardPlus( hwnd, (char*)pMyCDS->lpData ) ;
}
break ;
}
PCOPYDATASTRUCT pMyCDS = (PCOPYDATASTRUCT) lParam;
switch( pMyCDS->dwData ) {
case 1: // Reception of data string to send in terminal
if( pMyCDS->cbData > 0 ) {
SendKeyboardPlus( hwnd, (char*)pMyCDS->lpData ) ;
}
break ;
}
}
#endif
break ;
@@ -5704,6 +5706,8 @@ if( (GetKeyState(VK_MENU)&0x8000) && (wParam==VK_SPACE) ) {
#define LEFT_SHIFT_PRESSED 0x0200
if (GetAsyncKeyState(VK_LSHIFT)) { ctrl |= RIGHT_SHIFT_PRESSED; }
if (GetAsyncKeyState(VK_RSHIFT)) { ctrl |= LEFT_SHIFT_PRESSED; }
if (GetAsyncKeyState(VK_LSHIFT)) { ctrl |= SHIFT_PRESSED; ctrl |= RIGHT_SHIFT_PRESSED; }
if (GetAsyncKeyState(VK_RSHIFT)) { ctrl |= SHIFT_PRESSED; ctrl |= LEFT_SHIFT_PRESSED; }
// end
if ((lParam & ( 1 << 24 )) >> 24) { ctrl |= ENHANCED_KEY; }
if ((((u_short)GetKeyState(VK_NUMLOCK)) & 0xffff) != 0) { ctrl |= NUMLOCK_ON; }
@@ -7680,123 +7684,124 @@ Ex: %%P://%%u@%%h:%%p
Ex: %%f / %%s
*/
char * make_title( char * fmt, const char * title ) {
int p ;
char * res = NULL ;
res = (char *)malloc( strlen(fmt)+strlen(title)+1 ) ;
sprintf( res, fmt, title ) ;
int p ;
char * res = NULL ;
res = (char *)malloc( strlen(fmt)+strlen(title)+1 ) ;
sprintf( res, fmt, title ) ;
while( (p=poss( "%%s", res)) > 0 ) {
del( res, p, 3 ) ;
res = (char*)realloc( res, strlen(res)+strlen(conf_get_str(conf,CONF_sessionname))+1 ) ;
if( strlen(conf_get_str(conf,CONF_sessionname))>0 ) {
insert( res, conf_get_str(conf,CONF_sessionname), p ) ;
}
}
while( (p=poss( "%%h", res)) > 0 ) {
del( res, p, 3 ) ;
if( conf_get_int(conf,CONF_protocol) == PROT_SERIAL ) {
res = (char*)realloc( res, strlen(res)+strlen(conf_get_str(conf,CONF_serline))+1 ) ;
insert( res, conf_get_str(conf,CONF_serline), p ) ;
} else {
res = (char*)realloc( res, strlen(res)+strlen(conf_get_str(conf,CONF_host))+1 ) ;
insert( res, conf_get_str(conf,CONF_host), p ) ;
}
}
while( (p=poss( "%%u", res)) > 0 ) {
del( res, p ,3 ) ;
res = (char*)realloc( res, strlen(res)+strlen(conf_get_str(conf,CONF_username))+1 ) ;
insert( res, conf_get_str(conf,CONF_username), p ) ;
}
while( (p=poss( "%%f", res)) > 0 ) {
del( res, p , 3 ) ;
res = (char*)realloc( res, strlen(res)+strlen(conf_get_str(conf,CONF_folder))+1 ) ;
if(strlen(conf_get_str(conf,CONF_folder))>0) {
insert(res,conf_get_str(conf,CONF_folder),p);
}
}
char b[256] ;
int port = conf_get_int( conf, CONF_port );
switch(conf_get_int(conf,CONF_protocol)) {
case PROT_RAW: strcpy(b,"raw"); break;
case PROT_TELNET: strcpy(b,"telnet"); if(port==-1) port=23 ; break;
case PROT_RLOGIN: strcpy(b,"rlogin"); break;
case PROT_SSH: strcpy(b,"ssh"); if(port==-1) port=22 ; break;
case PROT_SERIAL: strcpy(b,"serial"); break;
}
while( (p=poss( "%%P", res)) > 0 ) {
del( res, p, 3 ) ;
res = (char*)realloc( res, strlen(res)+strlen(b)+1 ) ;
insert( res, b , p ) ;
}
sprintf( b, "%d", port ) ;
while( (p=poss( "%%p", res)) > 0 ) {
del( res, p, 3 ) ;
res = (char*)realloc( res, strlen(res)+strlen(b)+1 ) ;
insert( res, b, p ) ;
}
sprintf(b,"%ld", GetCurrentProcessId() ) ;
while( (p=poss( "%%i", res)) > 0 ) {
del( res, p, 3 ) ;
res = (char*)realloc( res, strlen(res)+strlen(b)+1 ) ;
insert( res, b, p) ;
}
while( (p=poss( "%%d", res)) > 0 ) { // forward port dynamic
char *key, *val, *k;
int nb=0 ;
del( res, p, 3 ) ;
char *bb = (char*)malloc(1) ;
bb[0] = '\0' ;
for( val = conf_get_str_strs(conf, CONF_portfwd, NULL, &key ) ;
val != NULL;
val = conf_get_str_strs(conf, CONF_portfwd, key, &key)) {
k=key;
if( (k[0]=='4')||(k[0]=='6') ) { k++ ; }
if( (k[0]=='L') && (!strcmp(val,"D")) ) {
bb = (char*)realloc( bb, strlen(bb)+strlen(k)+3 ) ;
if( nb!=0 ) { strcat( bb, "|" ) ; }
strcat( bb, k+1 ) ;
switch( GetPortFwdState( atoi(k+1), GetCurrentProcessId() ) ) {
case -1:
break ;
case 0:
strcat(bb,"+");
break ;
default:
strcat(bb,"~");
}
nb++;
}
}
if( bb!=NULL ) {
insert( res, bb, p ) ;
}
free(bb) ;
}
while( (p=poss( "%%l", res)) > 0 ) { // forward port locaux
char *key, *val, *k;
int nb=0 ;
del( res, p, 3 ) ;
char *bb = (char*)malloc(1) ;
bb[0] = '\0' ;
for (val = conf_get_str_strs(conf, CONF_portfwd, NULL, &key);
val != NULL;
val = conf_get_str_strs(conf, CONF_portfwd, key, &key)) {
k=key;
if( (k[0]=='4')||(k[0]=='6') ) { k++; }
if( (k[0]=='L') && (strcmp(val,"D")) ) {
bb = (char*)realloc( bb, strlen(bb)+strlen(k)+3 ) ;
if( nb!=0 ) { strcat( bb, "|" ) ; }
strcat( bb, k+1 ) ;
nb++;
}
res[1023]='\0';
}
if( bb != NULL ) {
insert( res, bb, p ) ;
}
}
return res ;
while( (p=poss( "%%s", res)) > 0 ) {
del( res, p, 3 ) ;
res = (char*)realloc( res, strlen(res)+strlen(conf_get_str(conf,CONF_sessionname))+1 ) ;
if( strlen(conf_get_str(conf,CONF_sessionname))>0 ) {
insert( res, conf_get_str(conf,CONF_sessionname), p ) ;
}
}
while( (p=poss( "%%h", res)) > 0 ) {
del( res, p, 3 ) ;
if( conf_get_int(conf,CONF_protocol) == PROT_SERIAL ) {
res = (char*)realloc( res, strlen(res)+strlen(conf_get_str(conf,CONF_serline))+1 ) ;
insert( res, conf_get_str(conf,CONF_serline), p ) ;
} else {
res = (char*)realloc( res, strlen(res)+strlen(conf_get_str(conf,CONF_host))+1 ) ;
insert( res, conf_get_str(conf,CONF_host), p ) ;
}
}
while( (p=poss( "%%u", res)) > 0 ) {
del( res, p ,3 ) ;
res = (char*)realloc( res, strlen(res)+strlen(conf_get_str(conf,CONF_username))+1 ) ;
insert( res, conf_get_str(conf,CONF_username), p ) ;
}
while( (p=poss( "%%f", res)) > 0 ) {
del( res, p , 3 ) ;
res = (char*)realloc( res, strlen(res)+strlen(conf_get_str(conf,CONF_folder))+1 ) ;
if(strlen(conf_get_str(conf,CONF_folder))>0) {
insert(res,conf_get_str(conf,CONF_folder),p);
}
}
char b[256] ;
int port = conf_get_int( conf, CONF_port );
switch(conf_get_int(conf,CONF_protocol)) {
case PROT_RAW: strcpy(b,"raw"); break;
case PROT_TELNET: strcpy(b,"telnet"); if(port==-1) port=23 ; break;
case PROT_RLOGIN: strcpy(b,"rlogin"); break;
case PROT_SSH: strcpy(b,"ssh"); if(port==-1) port=22 ; break;
case PROT_SERIAL: strcpy(b,"serial"); break;
}
while( (p=poss( "%%P", res)) > 0 ) {
del( res, p, 3 ) ;
res = (char*)realloc( res, strlen(res)+strlen(b)+1 ) ;
insert( res, b , p ) ;
}
sprintf( b, "%d", port ) ;
while( (p=poss( "%%p", res)) > 0 ) {
del( res, p, 3 ) ;
res = (char*)realloc( res, strlen(res)+strlen(b)+1 ) ;
insert( res, b, p ) ;
}
sprintf(b,"%ld", GetCurrentProcessId() ) ;
while( (p=poss( "%%i", res)) > 0 ) {
del( res, p, 3 ) ;
res = (char*)realloc( res, strlen(res)+strlen(b)+1 ) ;
insert( res, b, p) ;
}
while( (p=poss( "%%d", res)) > 0 ) { // forward port dynamic
char *key, *val, *k;
int nb=0 ;
del( res, p, 3 ) ;
char *bb = (char*)malloc(1) ;
bb[0] = '\0' ;
for( val = conf_get_str_strs(conf, CONF_portfwd, NULL, &key ) ;
val != NULL;
val = conf_get_str_strs(conf, CONF_portfwd, key, &key)) {
k=key;
if( (k[0]=='4')||(k[0]=='6') ) { k++ ; }
if( (k[0]=='L') && (!strcmp(val,"D")) ) {
bb = (char*)realloc( bb, strlen(bb)+strlen(k)+3 ) ;
if( nb!=0 ) { strcat( bb, "|" ) ; }
strcat( bb, k+1 ) ;
switch( GetPortFwdState( atoi(k+1), GetCurrentProcessId() ) ) {
case -1:
break ;
case 0:
strcat(bb,"+");
break ;
default:
strcat(bb,"~");
}
nb++;
}
}
if( bb!=NULL ) {
res = (char*)realloc( res, strlen(res)+strlen(bb)+1 ) ;
insert( res, bb, p ) ;
}
free(bb) ;
}
while( (p=poss( "%%l", res)) > 0 ) { // forward port locaux
char *key, *val, *k;
int nb=0 ;
del( res, p, 3 ) ;
char *bb = (char*)malloc(1) ;
bb[0] = '\0' ;
for (val = conf_get_str_strs(conf, CONF_portfwd, NULL, &key);
val != NULL;
val = conf_get_str_strs(conf, CONF_portfwd, key, &key)) {
k=key;
if( (k[0]=='4')||(k[0]=='6') ) { k++; }
if( (k[0]=='L') && (strcmp(val,"D")) ) {
bb = (char*)realloc( bb, strlen(bb)+strlen(k)+3 ) ;
if( nb!=0 ) { strcat( bb, "|" ) ; }
strcat( bb, k+1 ) ;
nb++;
}
}
if( bb != NULL ) {
res = (char*)realloc( res, strlen(res)+strlen(bb)+1 ) ;
insert( res, bb, p ) ;
}
}
return res ;
}
void set_title_internal(TermWin *tw, const char *title) {
@@ -7811,13 +7816,13 @@ static void wintw_set_title(TermWin *tw, const char *title_in) {
if( title_in==NULL ) { return ; }
title = (char*)malloc( strlen(title_in)+1 ) ; strcpy( title, title_in ) ;
if( (title[0]=='_')&&(title[1]=='_') ) { // Mode commande a distance
if( ManageLocalCmd( MainHwnd, title+2 ) ) { free( title ) ; return ; }
}
//if( (title[0]=='_')&&(title[1]=='_') ) { // Remote command ==> moved in terminal.c
// if( ManageLocalCmd( MainHwnd, title+2 ) ) { free( title ) ; return ; }
//}
if( !GetTitleBarFlag() ) { set_title_internal( tw, title ) ; free( title ) ; return ; }
if( strstr( title, " (PROTECTED)")==( title+strlen(title)-12 ) ) {
title[strlen(title)-12]='\0' ;
}
-467
View File
@@ -1,467 +0,0 @@
/*
* winmisc.c: miscellaneous Windows-specific things
*/
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include "putty.h"
#ifndef SECURITY_WIN32
#define SECURITY_WIN32
#endif
#include <security.h>
DWORD osMajorVersion, osMinorVersion, osPlatformId;
char *platform_get_x_display(void) {
/* We may as well check for DISPLAY in case it's useful. */
return dupstr(getenv("DISPLAY"));
}
Filename *filename_from_str(const char *str)
{
Filename *ret = snew(Filename);
ret->path = dupstr(str);
return ret;
}
Filename *filename_copy(const Filename *fn)
{
return filename_from_str(fn->path);
}
const char *filename_to_str(const Filename *fn)
{
return fn->path;
}
bool filename_equal(const Filename *f1, const Filename *f2)
{
return !strcmp(f1->path, f2->path);
}
bool filename_is_null(const Filename *fn)
{
return !*fn->path;
}
void filename_free(Filename *fn)
{
sfree(fn->path);
sfree(fn);
}
void filename_serialise(BinarySink *bs, const Filename *f)
{
put_asciz(bs, f->path);
}
Filename *filename_deserialise(BinarySource *src)
{
return filename_from_str(get_asciz(src));
}
char filename_char_sanitise(char c)
{
if (strchr("<>:\"/\\|?*", c))
return '.';
return c;
}
char *get_username(void)
{
DWORD namelen;
char *user;
bool got_username = false;
DECL_WINDOWS_FUNCTION(static, BOOLEAN, GetUserNameExA,
(EXTENDED_NAME_FORMAT, LPSTR, PULONG));
{
static bool tried_usernameex = false;
if (!tried_usernameex) {
/* Not available on Win9x, so load dynamically */
HMODULE secur32 = load_system32_dll("secur32.dll");
/* If MIT Kerberos is installed, the following call to
GET_WINDOWS_FUNCTION makes Windows implicitly load
sspicli.dll WITHOUT proper path sanitizing, so better
load it properly before */
HMODULE sspicli = load_system32_dll("sspicli.dll");
(void)sspicli; /* squash compiler warning about unused variable */
GET_WINDOWS_FUNCTION(secur32, GetUserNameExA);
tried_usernameex = true;
}
}
if (p_GetUserNameExA) {
/*
* If available, use the principal -- this avoids the problem
* that the local username is case-insensitive but Kerberos
* usernames are case-sensitive.
*/
/* Get the length */
namelen = 0;
(void) p_GetUserNameExA(NameUserPrincipal, NULL, &namelen);
user = snewn(namelen, char);
got_username = p_GetUserNameExA(NameUserPrincipal, user, &namelen);
if (got_username) {
char *p = strchr(user, '@');
if (p) *p = 0;
} else {
sfree(user);
}
}
if (!got_username) {
/* Fall back to local user name */
namelen = 0;
if (!GetUserName(NULL, &namelen)) {
/*
* Apparently this doesn't work at least on Windows XP SP2.
* Thus assume a maximum of 256. It will fail again if it
* doesn't fit.
*/
namelen = 256;
}
user = snewn(namelen, char);
got_username = GetUserName(user, &namelen);
if (!got_username) {
sfree(user);
}
}
return got_username ? user : NULL;
}
void dll_hijacking_protection(void)
{
/*
* If the OS provides it, call SetDefaultDllDirectories() to
* prevent DLLs from being loaded from the directory containing
* our own binary, and instead only load from system32.
*
* This is a protection against hijacking attacks, if someone runs
* PuTTY directly from their web browser's download directory
* having previously been enticed into clicking on an unwise link
* that downloaded a malicious DLL to the same directory under one
* of various magic names that seem to be things that standard
* Windows DLLs delegate to.
*
* It shouldn't break deliberate loading of user-provided DLLs
* such as GSSAPI providers, because those are specified by their
* full pathname by the user-provided configuration.
*/
static HMODULE kernel32_module;
DECL_WINDOWS_FUNCTION(static, BOOL, SetDefaultDllDirectories, (DWORD));
if (!kernel32_module) {
kernel32_module = load_system32_dll("kernel32.dll");
#if (defined _MSC_VER && _MSC_VER < 1900)
/* For older Visual Studio, this function isn't available in
* the header files to type-check */
GET_WINDOWS_FUNCTION_NO_TYPECHECK(
kernel32_module, SetDefaultDllDirectories);
#else
GET_WINDOWS_FUNCTION(kernel32_module, SetDefaultDllDirectories);
#endif
}
if (p_SetDefaultDllDirectories) {
/* LOAD_LIBRARY_SEARCH_SYSTEM32 and explicitly specified
* directories only */
p_SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_SYSTEM32 |
LOAD_LIBRARY_SEARCH_USER_DIRS);
}
}
void init_winver(void)
{
OSVERSIONINFO osVersion;
static HMODULE kernel32_module;
DECL_WINDOWS_FUNCTION(static, BOOL, GetVersionExA, (LPOSVERSIONINFO));
if (!kernel32_module) {
kernel32_module = load_system32_dll("kernel32.dll");
/* Deliberately don't type-check this function, because that
* would involve using its declaration in a header file which
* triggers a deprecation warning. I know it's deprecated (see
* below) and don't need telling. */
GET_WINDOWS_FUNCTION_NO_TYPECHECK(kernel32_module, GetVersionExA);
}
ZeroMemory(&osVersion, sizeof(osVersion));
osVersion.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
if (p_GetVersionExA && p_GetVersionExA(&osVersion)) {
osMajorVersion = osVersion.dwMajorVersion;
osMinorVersion = osVersion.dwMinorVersion;
osPlatformId = osVersion.dwPlatformId;
} else {
/*
* GetVersionEx is deprecated, so allow for it perhaps going
* away in future API versions. If it's not there, simply
* assume that's because Windows is too _new_, so fill in the
* variables we care about to a value that will always compare
* higher than any given test threshold.
*
* Normally we should be checking against the presence of a
* specific function if possible in any case.
*/
osMajorVersion = osMinorVersion = UINT_MAX; /* a very high number */
osPlatformId = VER_PLATFORM_WIN32_NT; /* not Win32s or Win95-like */
}
}
HMODULE load_system32_dll(const char *libname)
{
/*
* Wrapper function to load a DLL out of c:\windows\system32
* without going through the full DLL search path. (Hence no
* attack is possible by placing a substitute DLL earlier on that
* path.)
*/
static char *sysdir = NULL;
static size_t sysdirsize = 0;
char *fullpath;
HMODULE ret;
if (!sysdir) {
size_t len;
while ((len = GetSystemDirectory(sysdir, sysdirsize)) >= sysdirsize)
sgrowarray(sysdir, sysdirsize, len);
}
fullpath = dupcat(sysdir, "\\", libname);
ret = LoadLibrary(fullpath);
sfree(fullpath);
return ret;
}
/*
* A tree234 containing mappings from system error codes to strings.
*/
struct errstring {
int error;
char *text;
};
static int errstring_find(void *av, void *bv)
{
int *a = (int *)av;
struct errstring *b = (struct errstring *)bv;
if (*a < b->error)
return -1;
if (*a > b->error)
return +1;
return 0;
}
static int errstring_compare(void *av, void *bv)
{
struct errstring *a = (struct errstring *)av;
return errstring_find(&a->error, bv);
}
static tree234 *errstrings = NULL;
const char *win_strerror(int error)
{
struct errstring *es;
if (!errstrings)
errstrings = newtree234(errstring_compare);
es = find234(errstrings, &error, errstring_find);
if (!es) {
char msgtext[65536]; /* maximum size for FormatMessage is 64K */
es = snew(struct errstring);
es->error = error;
if (!FormatMessage((FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS), NULL, error,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
msgtext, lenof(msgtext)-1, NULL)) {
sprintf(msgtext,
"(unable to format: FormatMessage returned %u)",
(unsigned int)GetLastError());
} else {
int len = strlen(msgtext);
if (len > 0 && msgtext[len-1] == '\n')
msgtext[len-1] = '\0';
}
es->text = dupprintf("Error %d: %s", error, msgtext);
add234(errstrings, es);
}
return es->text;
}
FontSpec *fontspec_new(const char *name, bool bold, int height, int charset)
{
FontSpec *f = snew(FontSpec);
f->name = dupstr(name);
f->isbold = bold;
f->height = height;
f->charset = charset;
return f;
}
FontSpec *fontspec_copy(const FontSpec *f)
{
return fontspec_new(f->name, f->isbold, f->height, f->charset);
}
void fontspec_free(FontSpec *f)
{
sfree(f->name);
sfree(f);
}
void fontspec_serialise(BinarySink *bs, FontSpec *f)
{
put_asciz(bs, f->name);
put_uint32(bs, f->isbold);
put_uint32(bs, f->height);
put_uint32(bs, f->charset);
}
FontSpec *fontspec_deserialise(BinarySource *src)
{
const char *name = get_asciz(src);
unsigned isbold = get_uint32(src);
unsigned height = get_uint32(src);
unsigned charset = get_uint32(src);
return fontspec_new(name, isbold, height, charset);
}
bool open_for_write_would_lose_data(const Filename *fn)
{
WIN32_FILE_ATTRIBUTE_DATA attrs;
if (!GetFileAttributesEx(fn->path, GetFileExInfoStandard, &attrs)) {
/*
* Generally, if we don't identify a specific reason why we
* should return true from this function, we return false, and
* let the subsequent attempt to open the file for real give a
* more useful error message.
*/
return false;
}
if (attrs.dwFileAttributes & (FILE_ATTRIBUTE_DEVICE |
FILE_ATTRIBUTE_DIRECTORY)) {
/*
* File is something other than an ordinary disk file, so
* opening it for writing will not cause truncation. (It may
* not _succeed_ either, but that's not our problem here!)
*/
return false;
}
if (attrs.nFileSizeHigh == 0 && attrs.nFileSizeLow == 0) {
/*
* File is zero-length (or may be a named pipe, which
* dwFileAttributes can't tell apart from a regular file), so
* opening it for writing won't truncate any data away because
* there's nothing to truncate anyway.
*/
return false;
}
return true;
}
void escape_registry_key(const char *in, strbuf *out)
{
bool candot = false;
static const char hex[16] = "0123456789ABCDEF";
while (*in) {
if (*in == ' ' || *in == '\\' || *in == '*' || *in == '?' ||
*in == '%' || *in < ' ' || *in > '~' || (*in == '.'
&& !candot)) {
put_byte(out, '%');
put_byte(out, hex[((unsigned char) *in) >> 4]);
put_byte(out, hex[((unsigned char) *in) & 15]);
} else
put_byte(out, *in);
in++;
candot = true;
}
}
void unescape_registry_key(const char *in, strbuf *out)
{
while (*in) {
if (*in == '%' && in[1] && in[2]) {
int i, j;
i = in[1] - '0';
i -= (i > 9 ? 7 : 0);
j = in[2] - '0';
j -= (j > 9 ? 7 : 0);
put_byte(out, (i << 4) + j);
in += 3;
} else {
put_byte(out, *in++);
}
}
}
#ifdef DEBUG
static FILE *debug_fp = NULL;
static HANDLE debug_hdl = INVALID_HANDLE_VALUE;
static int debug_got_console = 0;
void dputs(const char *buf)
{
DWORD dw;
if (!debug_got_console) {
if (AllocConsole()) {
debug_got_console = 1;
debug_hdl = GetStdHandle(STD_OUTPUT_HANDLE);
}
}
if (!debug_fp) {
debug_fp = fopen("debug.log", "w");
}
if (debug_hdl != INVALID_HANDLE_VALUE) {
WriteFile(debug_hdl, buf, strlen(buf), &dw, NULL);
}
fputs(buf, debug_fp);
fflush(debug_fp);
}
#endif
char *registry_get_string(HKEY root, const char *path, const char *leaf)
{
HKEY key = root;
bool need_close_key = false;
char *toret = NULL, *str = NULL;
if (path) {
if (RegCreateKey(key, path, &key) != ERROR_SUCCESS)
goto out;
need_close_key = true;
}
DWORD type, size;
if (RegQueryValueEx(key, leaf, 0, &type, NULL, &size) != ERROR_SUCCESS)
goto out;
if (type != REG_SZ)
goto out;
str = snewn(size + 1, char);
DWORD size_got = size;
if (RegQueryValueEx(key, leaf, 0, &type, (LPBYTE)str,
&size_got) != ERROR_SUCCESS)
goto out;
if (type != REG_SZ || size_got > size)
goto out;
str[size_got] = '\0';
toret = str;
str = NULL;
out:
if (need_close_key)
RegCloseKey(key);
sfree(str);
return toret;
}
Binary file not shown.
+2
View File
@@ -13,3 +13,5 @@ Then load this key into you **Kageant**.
When the session that needs to use this key starts, and connects to **Kageant** a pop-up shows up and ask for usage confirmation:
![](../img/ex_kageant.jpg)
>Thanks to [Patrick Cernko](https://people.mpi-klsb.mpg.de/~pcernko/pageant.html) for this patch.
+1 -1
View File
@@ -1 +1 @@
0.76.1.4
0.76.1.13
+526 -483
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -5,7 +5,7 @@
#include <stdio.h>
#include "putty.h"
#include "winstuff.h"
#include "platform.h"
#include <windows.h>
// Flag permettant d'activer l'acces a du code particulier permettant d'avoir plus d'info dans le kitty.dmp
+9
View File
@@ -125,6 +125,12 @@ icon=yes
; KiClassName: change the internal software name to be the same as PuTTY
;KiClassName=PuTTY
; localcmd: manage local commands (starting with __)
;localcmd=yes
; localunsecurecmd: manage local unsecure commands ( ___pl, __ds, __cm, __ie )
;localunsecurecmd=no
; maxblinkingtime: maximum blinks (in system tray) where receiving bell signal
maxblinkingtime=5
@@ -215,6 +221,9 @@ zmodem=yes
; Clear scrollback
;clearscrollback=
; Clear log file
;clearlogfile=
; Close and restart current session
;closerestart=
+2
View File
@@ -448,6 +448,7 @@ void save_open_settings_forced(char *filename, Conf *conf) {
write_setting_b_forced(sesskey, "NoFocusReporting", conf_get_bool(conf, CONF_no_focus_rep));
write_setting_i_forced(sesskey, "LinesAtAScroll", conf_get_int(conf, CONF_scrolllines));
write_setting_b_forced(sesskey, "SSHTunnelInTitle", conf_get_bool(conf, CONF_ssh_tunnel_print_in_title));
write_setting_b_forced(sesskey, "OSC52WarnBeforeClipboardSync", conf_get_bool(conf, CONF_osc52_warn_before_cliboard_sync));
#endif
#ifdef MOD_PORTKNOCKING
write_setting_s_forced(sesskey, "PortKnocking", conf_get_str(conf, CONF_portknockingoptions) );
@@ -1102,6 +1103,7 @@ void load_open_settings_forced(char *filename, Conf *conf) {
gppb_forced(sesskey, "NoFocusReporting", true, conf, CONF_no_focus_rep);
gppi_forced(sesskey, "LinesAtAScroll", 5, conf, CONF_scrolllines);
gppb_forced(sesskey, "SSHTunnelInTitle", false, conf, CONF_ssh_tunnel_print_in_title);
gppb_forced(sesskey, "OSC52WarnBeforeClipboardSync", false, conf, CONF_osc52_warn_before_cliboard_sync);
#endif
#ifdef MOD_PORTKNOCKING
gpps_forced(sesskey, "PortKnocking", "", conf, CONF_portknockingoptions );
+1 -1
View File
@@ -23,7 +23,7 @@ static unsigned int link_regions_current_pos;
// Regex with http://, https://, ftp://, mailto: and ssh:// links
const char* urlhack_default_regex = "((ht|f)tp(s?):\\/\\/[0-9a-zA-Z]([-\\.\\w]*[0-9a-zA-Z])*([:](0-9)+)*(\\/?)([-a-zA-Z0-9\\.\\?\\,\\'\\/\\\\\\+=&%\\$#_]*)?)|(mailto:[a-zA-Z0-9\\-_\\.]+@[a-zA-Z0-9\\-_\\.]+\\.[a-z]{2,})|(ssh:\\/\\/([-a-zA-Z0-9_]+([:][^@]*)?@)?[-a-zA-Z0-9_\\.]+((:[0-9]{2,5})?(\\/[-a-zA-Z0-9_]+)?)?)" ;
const char* urlhack_default_regex = "((ht|f)tp(s?):\\/\\/[0-9a-zA-Z]([-\\.\\w]*[0-9a-zA-Z])*([:][0-9]+)?\\/?([-a-zA-Z0-9\\.\\?\\,\\'\\/\\\\\\+=&%\\$#_]*))|(mailto:[a-zA-Z0-9\\-_\\.]+@[a-zA-Z0-9\\-_\\.]+\\.[a-z]{2,})|(ssh:\\/\\/([-a-zA-Z0-9_]+([:][^@]*)?@)?[-a-zA-Z0-9_\\.]+((:[0-9]{2,5})?(\\/[-a-zA-Z0-9_]+)?)?)" ;
//const char* urlhack_default_regex = "(((((https?|ftp):\\/\\/)|www\\.)(([0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+)|localhost|([a-zA-Z0-9\\-]+\\.)*[a-zA-Z0-9\\-]+\\.(com|net|org|info|biz|int|gov|name|edu|[a-zA-Z][a-zA-Z]))(:[0-9]+)?((\\/|\\?)[^ \"]*[^ ,;\\.:\">)]?)?)|(mailto:[a-zA-Z0-9\\-_\\.]+@[a-zA-Z0-9\\-_\\.]+\\.[a-z]{2,})|(ssh:\\/\\/([a-zA-Z0-9\\-_]+(:[^@]*)?@)?[a-zA-Z0-9\\-_\\.]+(:[0-9]{2,5})?(\\/[a-zA-Z0-9\\-_]+)?))" ;