Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
75fa2abcd2 | ||
|
|
0301dd4a9c | ||
|
|
8f9747ac7e | ||
|
|
a52ffb145c | ||
|
|
34f5cea9b3 | ||
|
|
a7f1e2cd7a | ||
|
|
0e5d8582aa | ||
|
|
4404c65e46 | ||
|
|
3dba318b09 | ||
|
|
1963f21af2 | ||
|
|
888e28c4c2 | ||
|
|
d4ffef0a50 | ||
|
|
904dccaf1d | ||
|
|
cb54bec9b6 | ||
|
|
59da291c7c | ||
|
|
b2b8df282a | ||
|
|
f25d39782c | ||
|
|
333860672b | ||
|
|
9a636dd32f | ||
|
|
fc2d3e430a | ||
|
|
3830e9261a | ||
|
|
b99479f92e | ||
|
|
d8706714be | ||
|
|
1a041028c1 |
+1
-1
@@ -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" ]
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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 */ \
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#ifdef _WINDOWS
|
||||
|
||||
#include "winstuff.h"
|
||||
#include "platform.h"
|
||||
|
||||
#else
|
||||
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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,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
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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"
|
||||
@@ -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)
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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>
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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++);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
+166
-247
@@ -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 */
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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 @@
|
||||
4
|
||||
13
|
||||
|
||||
+143
-138
@@ -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' ;
|
||||
}
|
||||
|
||||
@@ -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.
@@ -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:
|
||||
|
||||

|
||||
|
||||
>Thanks to [Patrick Cernko](https://people.mpi-klsb.mpg.de/~pcernko/pageant.html) for this patch.
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
0.76.1.4
|
||||
0.76.1.13
|
||||
+1
-1
@@ -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
|
||||
|
||||
@@ -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=
|
||||
|
||||
|
||||
@@ -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
@@ -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\\-_]+)?))" ;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user