mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 17:38:00 +00:00
Stop looking for putty.chm alongside the binary.
With this change, we stop expecting to find putty.chm alongside the executable file. That was a security hazard comparable to DLL hijacking, because of the risk that a malicious CHM file could be dropped into the same directory as putty.exe (e.g. if someone ran PuTTY from their browser's download dir).. Instead, the standalone putty.exe (and other binaries needing help) embed the proper CHM file within themselves, as a Windows resource, and if called on to display the help then they write the file out to a temporary location. This has the advantage that if you download and run the standalone putty.exe then you actually _get_ help, which previously didn't happen! The versions of the binaries in the installer don't each contain a copy of the help file; that would be extravagant. Instead, the installer itself writes a registry entry pointing at the proper help file, and the executables will look there. Another effect of this commit is that I've withdrawn support for the older .HLP format completely. It's now entirely outdated, and supporting it through this security fix would have been a huge pain.
This commit is contained in:
parent
63a58759b5
commit
67d3791de8
65
Buildscr
65
Buildscr
@ -168,34 +168,31 @@ in putty/icons do make -j$(nproc)
|
||||
in putty do convert -size 164x312 'gradient:blue-white' -distort SRT -90 -swirl 180 \( -size 329x312 canvas:white \) +append \( icons/putty-48.png -geometry +28+24 \) -composite \( icons/pscp-48.png -geometry +88+96 \) -composite \( icons/puttygen-48.png -geometry +28+168 \) -composite \( icons/pageant-48.png -geometry +88+240 \) -composite windows/msidialog.bmp
|
||||
in putty do convert -size 493x58 canvas:white \( icons/putty-48.png -geometry +440+5 \) -composite windows/msibanner.bmp
|
||||
|
||||
# Build the standard binaries, in both 32- and 64-bit flavours.
|
||||
mkdir putty/windows/build32
|
||||
mkdir putty/windows/build64
|
||||
mkdir putty/windows/buildold
|
||||
mkdir putty/windows/abuild32
|
||||
mkdir putty/windows/abuild64
|
||||
|
||||
# Build the binaries to go in the installer, in both 32- and 64-bit
|
||||
# flavours.
|
||||
#
|
||||
# For the 32-bit ones, we set a subsystem version of 5.01, which
|
||||
# allows the resulting files to still run on Windows XP.
|
||||
in putty/windows with clangcl32 do mkdir build32 && Platform=x86 make -f Makefile.clangcl BUILDDIR=build32/ SUBSYSVER=,5.01 $(Makeargs) all -j$(nproc)
|
||||
in putty/windows with clangcl64 do mkdir build64 && Platform=x64 make -f Makefile.clangcl BUILDDIR=build64/ $(Makeargs) all -j$(nproc)
|
||||
in putty/windows with clangcl32 do Platform=x86 make -f Makefile.clangcl BUILDDIR=build32/ SUBSYSVER=,5.01 $(Makeargs) all -j$(nproc)
|
||||
in putty/windows with clangcl64 do Platform=x64 make -f Makefile.clangcl BUILDDIR=build64/ $(Makeargs) all -j$(nproc)
|
||||
|
||||
# Build experimental Arm Windows binaries.
|
||||
in putty/windows with clangcl_a32 do mkdir abuild32 && Platform=arm make -f Makefile.clangcl BUILDDIR=abuild32/ SUBSYSVER=,5.01 $(Makeargs) all -j$(nproc)
|
||||
in putty/windows with clangcl_a64 do mkdir abuild64 && Platform=arm64 make -f Makefile.clangcl BUILDDIR=abuild64/ $(Makeargs) all -j$(nproc)
|
||||
|
||||
# Build the 'old' binaries, which should still run on all 32-bit
|
||||
# versions of Windows back to Win95 (but not Win32s). These link
|
||||
# against Visual Studio 2003 libraries (the more modern versions
|
||||
# assume excessively modern Win32 API calls to be available), specify
|
||||
# a subsystem version of 4.0, and compile with /arch:IA32 to prevent
|
||||
# the use of modern CPU features like MMX which older machines also
|
||||
# might not have.
|
||||
in putty/windows with clangcl32_2003 do mkdir buildold && Platform=x86 make -f Makefile.clangcl BUILDDIR=buildold/ $(Makeargs) CCTARGET=i386-pc-windows-msvc13.0.0 SUBSYSVER=,4.0 EXTRA_windows=wincrt0.obj EXTRA_console=crt0.obj EXTRA_libs=libcpmt.lib XFLAGS=/arch:IA32 all -j$(nproc)
|
||||
in putty/windows with clangcl_a32 do Platform=arm make -f Makefile.clangcl BUILDDIR=abuild32/ SUBSYSVER=,5.01 $(Makeargs) all -j$(nproc)
|
||||
in putty/windows with clangcl_a64 do Platform=arm64 make -f Makefile.clangcl BUILDDIR=abuild64/ $(Makeargs) all -j$(nproc)
|
||||
|
||||
# Remove Windows binaries for the test programs we don't want to ship,
|
||||
# like testbn.exe. (But we still _built_ them, to ensure the build
|
||||
# like testcrypt.exe. (But we still _built_ them, to ensure the build
|
||||
# worked.)
|
||||
in putty/windows do make -f Makefile.clangcl BUILDDIR=build32/ cleantestprogs
|
||||
in putty/windows do make -f Makefile.clangcl BUILDDIR=build64/ cleantestprogs
|
||||
in putty/windows do make -f Makefile.clangcl BUILDDIR=abuild32/ cleantestprogs
|
||||
in putty/windows do make -f Makefile.clangcl BUILDDIR=abuild64/ cleantestprogs
|
||||
in putty/windows do make -f Makefile.clangcl BUILDDIR=buildold/ cleantestprogs
|
||||
|
||||
# Code-sign the Windows binaries, if the local bob config provides a
|
||||
# script to do so in a cross-compiling way. We assume here that the
|
||||
@ -220,6 +217,42 @@ in putty/windows do ./msiplatform.py installera64.msi Arm64
|
||||
# Sign the Windows installers.
|
||||
ifneq "$(cross_winsigncode)" "" in putty/windows do $(cross_winsigncode) -i https://www.chiark.greenend.org.uk/~sgtatham/putty/ -n "PuTTY Installer" installer32.msi installer64.msi installera32.msi installera64.msi
|
||||
|
||||
# Delete the binaries and resource files from the build directories,
|
||||
# so that we can rebuild them differently.
|
||||
in putty/windows/build32 do rm -f *.exe *.res *.rcpp
|
||||
in putty/windows/build64 do rm -f *.exe *.res *.rcpp
|
||||
in putty/windows/abuild32 do rm -f *.exe *.res *.rcpp
|
||||
in putty/windows/abuild64 do rm -f *.exe *.res *.rcpp
|
||||
|
||||
# Build the standalone binaries, in both 32- and 64-bit flavours.
|
||||
# These differ from the previous set in that they embed the help file.
|
||||
in putty/windows with clangcl32 do Platform=x86 make -f Makefile.clangcl BUILDDIR=build32/ RCFL=-DEMBED_CHM SUBSYSVER=,5.01 $(Makeargs) all -j$(nproc)
|
||||
in putty/windows with clangcl64 do Platform=x64 make -f Makefile.clangcl BUILDDIR=build64/ RCFL=-DEMBED_CHM $(Makeargs) all -j$(nproc)
|
||||
in putty/windows with clangcl_a32 do Platform=arm make -f Makefile.clangcl BUILDDIR=abuild32/ RCFL=-DEMBED_CHM SUBSYSVER=,5.01 $(Makeargs) all -j$(nproc)
|
||||
in putty/windows with clangcl_a64 do Platform=arm64 make -f Makefile.clangcl BUILDDIR=abuild64/ RCFL=-DEMBED_CHM $(Makeargs) all -j$(nproc)
|
||||
|
||||
# Build the 'old' binaries, which should still run on all 32-bit
|
||||
# versions of Windows back to Win95 (but not Win32s). These link
|
||||
# against Visual Studio 2003 libraries (the more modern versions
|
||||
# assume excessively modern Win32 API calls to be available), specify
|
||||
# a subsystem version of 4.0, and compile with /arch:IA32 to prevent
|
||||
# the use of modern CPU features like MMX which older machines also
|
||||
# might not have.
|
||||
#
|
||||
# There's no installer to go with these, so they must also embed the
|
||||
# help file.
|
||||
in putty/windows with clangcl32_2003 do Platform=x86 make -f Makefile.clangcl BUILDDIR=buildold/ RCFL=-DEMBED_CHM $(Makeargs) CCTARGET=i386-pc-windows-msvc13.0.0 SUBSYSVER=,4.0 EXTRA_windows=wincrt0.obj EXTRA_console=crt0.obj EXTRA_libs=libcpmt.lib XFLAGS=/arch:IA32 all -j$(nproc)
|
||||
|
||||
# Remove test programs again.
|
||||
in putty/windows do make -f Makefile.clangcl BUILDDIR=build32/ cleantestprogs
|
||||
in putty/windows do make -f Makefile.clangcl BUILDDIR=build64/ cleantestprogs
|
||||
in putty/windows do make -f Makefile.clangcl BUILDDIR=abuild32/ cleantestprogs
|
||||
in putty/windows do make -f Makefile.clangcl BUILDDIR=abuild64/ cleantestprogs
|
||||
in putty/windows do make -f Makefile.clangcl BUILDDIR=buildold/ cleantestprogs
|
||||
|
||||
# Code-sign the standalone versions of the binaries.
|
||||
ifneq "$(cross_winsigncode)" "" in putty/windows do $(cross_winsigncode) -N -i https://www.chiark.greenend.org.uk/~sgtatham/putty/ build*/*.exe abuild*/*.exe
|
||||
|
||||
in putty/doc do make mostlyclean
|
||||
in putty/doc do make $(Docmakever) -j$(nproc)
|
||||
in putty/windows/buildold do zip -k -j putty.zip `ls *.exe | grep -v puttytel` ../../doc/putty.chm ../../doc/putty.hlp ../../doc/putty.cnt
|
||||
|
10
Recipe
10
Recipe
@ -64,9 +64,7 @@
|
||||
#
|
||||
# - COMPAT=/DNO_HTMLHELP (Windows only)
|
||||
# Disables PuTTY's use of <htmlhelp.h>, which is not available
|
||||
# with some development environments. The resulting binary
|
||||
# will only look for an old-style WinHelp file (.HLP/.CNT), and
|
||||
# will ignore any .CHM file.
|
||||
# with some development environments.
|
||||
#
|
||||
# If you don't have this header, you may be able to use the copy
|
||||
# supplied with HTML Help Workshop.
|
||||
@ -333,11 +331,11 @@ U_BE_NOSSH = be_nos_s uxser nocproxy
|
||||
putty : [G] GUITERM NONSSH WINSSH W_BE_ALL WINMISC winx11 putty.res LIBS
|
||||
puttytel : [G] GUITERM NONSSH W_BE_NOSSH WINMISC puttytel.res nogss LIBS
|
||||
plink : [C] winplink wincons NONSSH WINSSH W_BE_ALL logging WINMISC
|
||||
+ winx11 plink.res winnojmp sessprep noterm LIBS
|
||||
+ winx11 plink.res winnojmp sessprep noterm winnohlp LIBS
|
||||
pscp : [C] pscp winsftp wincons WINSSH BE_SSH SFTP wildcard WINMISC
|
||||
+ pscp.res winnojmp LIBS
|
||||
+ pscp.res winnojmp winnohlp LIBS
|
||||
psftp : [C] psftp winsftp wincons WINSSH BE_SSH SFTP wildcard WINMISC
|
||||
+ psftp.res winnojmp LIBS
|
||||
+ psftp.res winnojmp winnohlp LIBS
|
||||
|
||||
pageant : [G] winpgnt pageant sshrsa sshpubk sshdes ARITH sshmd5 version
|
||||
+ tree234 MISC sshaes sshsha winsecur winpgntc aqsync sshdss sshsh256
|
||||
|
8
misc.c
8
misc.c
@ -272,6 +272,14 @@ char *buildinfo(const char *newline)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if defined _WINDOWS
|
||||
{
|
||||
int echm = has_embedded_chm();
|
||||
if (echm >= 0)
|
||||
strbuf_catf(buf, "%sEmbedded HTML Help file: %s", newline,
|
||||
echm ? "yes" : "no");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined _WINDOWS && defined MINEFIELD
|
||||
strbuf_catf(buf, "%sBuild option: MINEFIELD", newline);
|
||||
|
@ -243,7 +243,11 @@ https://msdn.microsoft.com/en-us/library/windows/desktop/dd391569(v=vs.85).aspx
|
||||
Name="PuTTY Manual"
|
||||
Advertise="no" />
|
||||
</File>
|
||||
<RegistryValue Root="HKLM"
|
||||
Key="$(var.RegKeyPathLocation)\CHMPath"
|
||||
Type="string" Value="[#HelpFile_File]"/>
|
||||
</Component>
|
||||
|
||||
<Component Id="Website_Component"
|
||||
Guid="$(var.Website_Component_GUID)">
|
||||
<File Id="Website_File"
|
||||
|
@ -7,6 +7,8 @@
|
||||
#define APPNAME "Pageant"
|
||||
#define APPDESC "PuTTY SSH authentication agent"
|
||||
|
||||
#include "winhelp.rc2"
|
||||
|
||||
200 ICON "pageant.ico"
|
||||
201 ICON "pageants.ico"
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
#define APPDESC "SSH, Telnet and Rlogin client"
|
||||
|
||||
#include "win_res.rc2"
|
||||
#include "winhelp.rc2"
|
||||
|
||||
#ifndef NO_MANIFESTS
|
||||
1 RT_MANIFEST "putty.mft"
|
||||
|
@ -7,6 +7,8 @@
|
||||
#define APPNAME "PuTTYgen"
|
||||
#define APPDESC "PuTTY SSH key generation utility"
|
||||
|
||||
#include "winhelp.rc2"
|
||||
|
||||
200 ICON "puttygen.ico"
|
||||
|
||||
201 DIALOG DISCARDABLE 0, 0, 318, 270
|
||||
|
@ -4,6 +4,7 @@
|
||||
#define APPDESC "Telnet and Rlogin client"
|
||||
|
||||
#include "win_res.rc2"
|
||||
#include "winhelp.rc2"
|
||||
|
||||
#ifndef NO_MANIFESTS
|
||||
1 RT_MANIFEST "puttytel.mft"
|
||||
|
@ -29,4 +29,7 @@
|
||||
#define IDC_HELPBTN 1005
|
||||
#define IDC_ABOUT 1006
|
||||
|
||||
#define ID_CUSTOM_CHMFILE 2000
|
||||
#define TYPE_CUSTOM_CHMFILE 2000
|
||||
|
||||
#endif
|
||||
|
@ -10,130 +10,246 @@
|
||||
#include <assert.h>
|
||||
|
||||
#include "putty.h"
|
||||
#include "win_res.h"
|
||||
|
||||
#ifdef NO_HTMLHELP
|
||||
|
||||
/* If htmlhelp.h is not available, we can't do any of this at all */
|
||||
bool has_help(void) { return false; }
|
||||
void init_help(void) { }
|
||||
void shutdown_help(void) { }
|
||||
void launch_help(HWND hwnd, const char *topic) { }
|
||||
void quit_help(HWND hwnd) { }
|
||||
|
||||
#else
|
||||
|
||||
#ifndef NO_HTMLHELP
|
||||
#include <htmlhelp.h>
|
||||
#endif /* NO_HTMLHELP */
|
||||
|
||||
static char *chm_path = NULL;
|
||||
static bool chm_created_by_us = false;
|
||||
|
||||
static bool requested_help;
|
||||
static char *help_path;
|
||||
static bool help_has_contents;
|
||||
#ifndef NO_HTMLHELP
|
||||
DECL_WINDOWS_FUNCTION(static, HWND, HtmlHelpA, (HWND, LPCSTR, UINT, DWORD_PTR));
|
||||
static char *chm_path;
|
||||
#endif /* NO_HTMLHELP */
|
||||
|
||||
static HRSRC chm_hrsrc;
|
||||
static DWORD chm_resource_size = 0;
|
||||
static const void *chm_resource = NULL;
|
||||
|
||||
int has_embedded_chm(void)
|
||||
{
|
||||
static bool checked = false;
|
||||
if (!checked) {
|
||||
checked = true;
|
||||
|
||||
chm_hrsrc = FindResource(
|
||||
NULL, MAKEINTRESOURCE(ID_CUSTOM_CHMFILE),
|
||||
MAKEINTRESOURCE(TYPE_CUSTOM_CHMFILE));
|
||||
}
|
||||
return chm_hrsrc != NULL ? 1 : 0;
|
||||
}
|
||||
|
||||
static bool find_chm_resource(void)
|
||||
{
|
||||
static bool checked = false;
|
||||
if (checked) /* we've been here already */
|
||||
goto out;
|
||||
checked = true;
|
||||
|
||||
/*
|
||||
* Look for a CHM file embedded in this executable as a custom
|
||||
* resource.
|
||||
*/
|
||||
if (!has_embedded_chm()) /* set up chm_hrsrc and check if it's NULL */
|
||||
goto out;
|
||||
|
||||
chm_resource_size = SizeofResource(NULL, chm_hrsrc);
|
||||
if (chm_resource_size == 0)
|
||||
goto out;
|
||||
|
||||
HGLOBAL chm_hglobal = LoadResource(NULL, chm_hrsrc);
|
||||
if (chm_hglobal == NULL)
|
||||
goto out;
|
||||
|
||||
chm_resource = (const uint8_t *)LockResource(chm_hglobal);
|
||||
|
||||
out:
|
||||
return chm_resource != NULL;
|
||||
}
|
||||
|
||||
static bool load_chm_resource(void)
|
||||
{
|
||||
bool toret = false;
|
||||
char *filename = NULL;
|
||||
HANDLE filehandle = INVALID_HANDLE_VALUE;
|
||||
bool created = false;
|
||||
|
||||
static bool tried_to_load = false;
|
||||
if (tried_to_load)
|
||||
goto out;
|
||||
tried_to_load = true;
|
||||
|
||||
/*
|
||||
* We've found it! Now write it out into a separate file, so that
|
||||
* htmlhelp.exe can handle it.
|
||||
*/
|
||||
|
||||
/* GetTempPath is documented as returning a size of up to
|
||||
* MAX_PATH+1 which does not count the NUL */
|
||||
char tempdir[MAX_PATH + 2];
|
||||
if (GetTempPath(sizeof(tempdir), tempdir) == 0)
|
||||
goto out;
|
||||
|
||||
unsigned long pid = GetCurrentProcessId();
|
||||
|
||||
for (uint64_t counter = 0;; counter++) {
|
||||
filename = dupprintf(
|
||||
"%s\\putty_%lu_%"PRIu64".chm", tempdir, pid, counter);
|
||||
filehandle = CreateFile(
|
||||
filename, GENERIC_WRITE, FILE_SHARE_READ,
|
||||
NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
if (filehandle != INVALID_HANDLE_VALUE)
|
||||
break; /* success! */
|
||||
|
||||
if (GetLastError() != ERROR_FILE_EXISTS)
|
||||
goto out; /* failed for some other reason! */
|
||||
|
||||
sfree(filename);
|
||||
filename = NULL;
|
||||
}
|
||||
created = true;
|
||||
|
||||
const uint8_t *p = (const uint8_t *)chm_resource;
|
||||
for (DWORD pos = 0; pos < chm_resource_size; pos++) {
|
||||
DWORD to_write = chm_resource_size - pos;
|
||||
DWORD written = 0;
|
||||
|
||||
if (!WriteFile(filehandle, p + pos, to_write, &written, NULL))
|
||||
goto out;
|
||||
pos += written;
|
||||
}
|
||||
|
||||
chm_path = filename;
|
||||
filename = NULL;
|
||||
chm_created_by_us = true;
|
||||
toret = true;
|
||||
|
||||
out:
|
||||
if (created && !toret)
|
||||
DeleteFile(filename);
|
||||
sfree(filename);
|
||||
if (filehandle != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(filehandle);
|
||||
return toret;
|
||||
}
|
||||
|
||||
static bool find_chm_from_installation(void)
|
||||
{
|
||||
static const char *const reg_paths[] = {
|
||||
"Software\\SimonTatham\\PuTTY64\\CHMPath",
|
||||
"Software\\SimonTatham\\PuTTY\\CHMPath",
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < lenof(reg_paths); i++) {
|
||||
char *filename = registry_get_string(
|
||||
HKEY_LOCAL_MACHINE, reg_paths[i], NULL);
|
||||
|
||||
if (filename) {
|
||||
chm_path = filename;
|
||||
chm_created_by_us = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void init_help(void)
|
||||
{
|
||||
char b[2048], *p, *q, *r;
|
||||
FILE *fp;
|
||||
/* Just in case of multiple calls */
|
||||
static bool already_called = false;
|
||||
if (already_called)
|
||||
return;
|
||||
already_called = true;
|
||||
|
||||
GetModuleFileName(NULL, b, sizeof(b) - 1);
|
||||
r = b;
|
||||
p = strrchr(b, '\\');
|
||||
if (p && p >= r) r = p+1;
|
||||
q = strrchr(b, ':');
|
||||
if (q && q >= r) r = q+1;
|
||||
strcpy(r, PUTTY_HELP_FILE);
|
||||
if ( (fp = fopen(b, "r")) != NULL) {
|
||||
help_path = dupstr(b);
|
||||
fclose(fp);
|
||||
} else
|
||||
help_path = NULL;
|
||||
strcpy(r, PUTTY_HELP_CONTENTS);
|
||||
if ( (fp = fopen(b, "r")) != NULL) {
|
||||
help_has_contents = true;
|
||||
fclose(fp);
|
||||
} else
|
||||
help_has_contents = false;
|
||||
|
||||
#ifndef NO_HTMLHELP
|
||||
strcpy(r, PUTTY_CHM_FILE);
|
||||
if ( (fp = fopen(b, "r")) != NULL) {
|
||||
chm_path = dupstr(b);
|
||||
fclose(fp);
|
||||
} else
|
||||
chm_path = NULL;
|
||||
if (chm_path) {
|
||||
HINSTANCE dllHH = load_system32_dll("hhctrl.ocx");
|
||||
GET_WINDOWS_FUNCTION(dllHH, HtmlHelpA);
|
||||
if (!p_HtmlHelpA) {
|
||||
sfree(chm_path);
|
||||
chm_path = NULL;
|
||||
if (dllHH)
|
||||
FreeLibrary(dllHH);
|
||||
}
|
||||
/*
|
||||
* Don't even try looking for the CHM file if we can't even find
|
||||
* the HtmlHelp() API function.
|
||||
*/
|
||||
HINSTANCE dllHH = load_system32_dll("hhctrl.ocx");
|
||||
GET_WINDOWS_FUNCTION(dllHH, HtmlHelpA);
|
||||
if (!p_HtmlHelpA) {
|
||||
FreeLibrary(dllHH);
|
||||
return;
|
||||
}
|
||||
#endif /* NO_HTMLHELP */
|
||||
|
||||
/*
|
||||
* If there's a CHM file embedded in this executable, we should
|
||||
* use that as the first choice.
|
||||
*/
|
||||
if (find_chm_resource())
|
||||
return;
|
||||
|
||||
/*
|
||||
* Otherwise, try looking for the CHM in the location that the
|
||||
* installer marked in the registry.
|
||||
*/
|
||||
if (find_chm_from_installation())
|
||||
return;
|
||||
}
|
||||
|
||||
void shutdown_help(void)
|
||||
{
|
||||
/* Nothing to do currently.
|
||||
* (If we were running HTML Help single-threaded, this is where we'd
|
||||
* call HH_UNINITIALIZE.) */
|
||||
if (chm_path && chm_created_by_us) {
|
||||
p_HtmlHelpA(NULL, NULL, HH_CLOSE_ALL, 0);
|
||||
DeleteFile(chm_path);
|
||||
}
|
||||
sfree(chm_path);
|
||||
chm_path = NULL;
|
||||
chm_created_by_us = false;
|
||||
}
|
||||
|
||||
bool has_help(void)
|
||||
{
|
||||
/*
|
||||
* FIXME: it would be nice here to disregard help_path on
|
||||
* platforms that didn't have WINHLP32. But that's probably
|
||||
* unrealistic, since even Vista will have it if the user
|
||||
* specifically downloads it.
|
||||
*/
|
||||
return (help_path != NULL
|
||||
#ifndef NO_HTMLHELP
|
||||
|| chm_path
|
||||
#endif /* NO_HTMLHELP */
|
||||
);
|
||||
return chm_path != NULL || chm_resource != NULL;
|
||||
}
|
||||
|
||||
void launch_help(HWND hwnd, const char *topic)
|
||||
{
|
||||
if (!chm_path && chm_resource) {
|
||||
/*
|
||||
* If we've been called without already having a file name for
|
||||
* the CHM file, that might be because we've located it in our
|
||||
* resource section but not written it to a temp file yet. Do
|
||||
* so now, on first use.
|
||||
*/
|
||||
load_chm_resource();
|
||||
}
|
||||
|
||||
/* If we _still_ don't have a CHM pathname, we just can't display help. */
|
||||
if (!chm_path)
|
||||
return;
|
||||
|
||||
if (topic) {
|
||||
int colonpos = strcspn(topic, ":");
|
||||
assert(topic[colonpos] != '\0');
|
||||
|
||||
#ifndef NO_HTMLHELP
|
||||
if (chm_path) {
|
||||
char *fname;
|
||||
assert(topic[colonpos] != '\0');
|
||||
fname = dupprintf("%s::/%s.html>main", chm_path,
|
||||
topic + colonpos + 1);
|
||||
p_HtmlHelpA(hwnd, fname, HH_DISPLAY_TOPIC, 0);
|
||||
sfree(fname);
|
||||
} else
|
||||
#endif /* NO_HTMLHELP */
|
||||
if (help_path) {
|
||||
char *cmd = dupprintf("JI(`',`%.*s')", colonpos, topic);
|
||||
WinHelp(hwnd, help_path, HELP_COMMAND, (ULONG_PTR)cmd);
|
||||
sfree(cmd);
|
||||
}
|
||||
char *fname = dupprintf(
|
||||
"%s::/%s.html>main", chm_path, topic + colonpos + 1);
|
||||
p_HtmlHelpA(hwnd, fname, HH_DISPLAY_TOPIC, 0);
|
||||
sfree(fname);
|
||||
} else {
|
||||
#ifndef NO_HTMLHELP
|
||||
if (chm_path) {
|
||||
p_HtmlHelpA(hwnd, chm_path, HH_DISPLAY_TOPIC, 0);
|
||||
} else
|
||||
#endif /* NO_HTMLHELP */
|
||||
if (help_path) {
|
||||
WinHelp(hwnd, help_path,
|
||||
help_has_contents ? HELP_FINDER : HELP_CONTENTS, 0);
|
||||
}
|
||||
p_HtmlHelpA(hwnd, chm_path, HH_DISPLAY_TOPIC, 0);
|
||||
}
|
||||
requested_help = true;
|
||||
}
|
||||
|
||||
void quit_help(HWND hwnd)
|
||||
{
|
||||
if (requested_help) {
|
||||
#ifndef NO_HTMLHELP
|
||||
if (chm_path) {
|
||||
p_HtmlHelpA(NULL, NULL, HH_CLOSE_ALL, 0);
|
||||
} else
|
||||
#endif /* NO_HTMLHELP */
|
||||
if (help_path) {
|
||||
WinHelp(hwnd, help_path, HELP_QUIT, 0);
|
||||
}
|
||||
requested_help = false;
|
||||
}
|
||||
if (requested_help)
|
||||
p_HtmlHelpA(NULL, NULL, HH_CLOSE_ALL, 0);
|
||||
if (chm_path && chm_created_by_us)
|
||||
DeleteFile(chm_path);
|
||||
}
|
||||
|
||||
#endif /* NO_HTMLHELP */
|
||||
|
5
windows/winhelp.rc2
Normal file
5
windows/winhelp.rc2
Normal file
@ -0,0 +1,5 @@
|
||||
#include "win_res.h"
|
||||
|
||||
#ifdef EMBED_CHM
|
||||
ID_CUSTOM_CHMFILE TYPE_CUSTOM_CHMFILE "../doc/putty.chm"
|
||||
#endif
|
@ -430,3 +430,40 @@ void dputs(const char *buf)
|
||||
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;
|
||||
}
|
||||
|
15
windows/winnohlp.c
Normal file
15
windows/winnohlp.c
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* nohelp.c: implement the has_embedded_chm() function for
|
||||
* applications that have no help file at all, so that misc.c's
|
||||
* buildinfo string knows not to talk meaninglessly about whether the
|
||||
* nonexistent help file is present.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "putty.h"
|
||||
|
||||
int has_embedded_chm(void) { return -1; }
|
@ -228,6 +228,7 @@ void shutdown_help(void);
|
||||
bool has_help(void);
|
||||
void launch_help(HWND hwnd, const char *topic);
|
||||
void quit_help(HWND hwnd);
|
||||
int has_embedded_chm(void); /* 1 = yes, 0 = no, -1 = N/A */
|
||||
|
||||
/*
|
||||
* The terminal and logging context are notionally local to the
|
||||
@ -700,4 +701,7 @@ char *get_jumplist_registry_entries(void);
|
||||
#define CLIPUI_DEFAULT_MOUSE CLIPUI_EXPLICIT
|
||||
#define CLIPUI_DEFAULT_INS CLIPUI_EXPLICIT
|
||||
|
||||
/* In winmisc.c */
|
||||
char *registry_get_string(HKEY root, const char *path, const char *leaf);
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user