├── .gitignore ├── Buildscr ├── Buildscr.cv ├── LATEST.VER ├── LICENCE ├── README.md ├── Recipe ├── appveyor.yml ├── aqsync.c ├── be_all.c ├── be_all_s.c ├── be_misc.c ├── be_none.c ├── be_nos_s.c ├── be_nossh.c ├── be_ssh.c ├── callback.c ├── cgtest.c ├── charset ├── README ├── charset.h ├── enum.c ├── fromucs.c ├── internal.h ├── localenc.c ├── macenc.c ├── mimeenc.c ├── sbcs.c ├── sbcs.dat ├── sbcsgen.pl ├── slookup.c ├── toucs.c ├── utf8.c └── xenc.c ├── cmdgen.c ├── cmdline.c ├── conf.c ├── config.c ├── configure.ac ├── contrib ├── cygtermd │ ├── Makefile │ ├── README │ ├── main.c │ ├── malloc.c │ ├── malloc.h │ ├── pty.c │ ├── pty.h │ ├── sel.c │ ├── sel.h │ ├── telnet.c │ └── telnet.h ├── encodelib.py ├── kh2reg.py ├── logparse.pl ├── logrewrap.pl ├── make1305.py ├── nice-ibeam.cur └── samplekex.py ├── cproxy.c ├── dialog.c ├── dialog.h ├── errsock.c ├── fatty.c ├── fuzzterm.c ├── icons ├── Makefile ├── cicon.pl ├── icon.pl ├── macicon.py └── mkicon.py ├── import.c ├── int64.c ├── int64.h ├── ldisc.c ├── ldisc.h ├── ldiscucs.c ├── licence.pl ├── logging.c ├── mingw-w64-x86_64.cmake ├── minibidi.c ├── misc.c ├── misc.h ├── miscucs.c ├── mkauto.sh ├── mkcmake.py ├── mkfiles.pl ├── mksrcarc.sh ├── mkunxarc.sh ├── network.h ├── nocproxy.c ├── nogss.c ├── noprint.c ├── noshare.c ├── noterm.c ├── notiming.c ├── pageant.c ├── pageant.h ├── pgssapi.c ├── pgssapi.h ├── pinger.c ├── portfwd.c ├── pproxy.c ├── proxy.c ├── proxy.h ├── pscp.c ├── psftp.c ├── psftp.h ├── putty.h ├── puttymem.h ├── puttyps.h ├── raw.c ├── release.pl ├── resource.h ├── rlogin.c ├── sercfg.c ├── settings.c ├── sftp.c ├── sftp.h ├── sign.sh ├── ssh.c ├── ssh.h ├── sshaes.c ├── ssharcf.c ├── sshbcrypt.c ├── sshblowf.c ├── sshblowf.h ├── sshbn.c ├── sshbn.h ├── sshccp.c ├── sshcrc.c ├── sshcrcda.c ├── sshdes.c ├── sshdh.c ├── sshdss.c ├── sshdssg.c ├── sshecc.c ├── sshecdsag.c ├── sshgss.h ├── sshgssc.c ├── sshgssc.h ├── sshmd5.c ├── sshnogss.c ├── sshprime.c ├── sshpubk.c ├── sshrand.c ├── sshrsa.c ├── sshrsag.c ├── sshsh256.c ├── sshsh512.c ├── sshsha.c ├── sshshare.c ├── sshzlib.c ├── storage.h ├── telnet.c ├── terminal.c ├── terminal.h ├── testback.c ├── testbn.c ├── testdata ├── bignum.py ├── bignumtests.txt ├── colours.txt ├── display.txt ├── lattrs.txt ├── scocols.txt ├── utf8.txt └── vt100.txt ├── time.c ├── timing.c ├── tree234.c ├── tree234.h ├── unix ├── configure ├── gtkapp.c ├── gtkask.c ├── gtkcfg.c ├── gtkcols.c ├── gtkcols.h ├── gtkcomm.c ├── gtkcompat.h ├── gtkdlg.c ├── gtkfont.c ├── gtkfont.h ├── gtkmain.c ├── gtkmisc.c ├── gtkmisc.h ├── gtkwin.c ├── osxlaunch.c ├── pterm.bundle ├── pterm.plist ├── putty.bundle ├── putty.plist ├── unix.h ├── urlhack_unix.c ├── ux_x11.c ├── uxagentc.c ├── uxcfg.c ├── uxcons.c ├── uxgen.c ├── uxgss.c ├── uxmisc.c ├── uxnet.c ├── uxnogtk.c ├── uxnoise.c ├── uxpeer.c ├── uxpgnt.c ├── uxplink.c ├── uxprint.c ├── uxproxy.c ├── uxpterm.c ├── uxpty.c ├── uxputty.c ├── uxsel.c ├── uxser.c ├── uxsftp.c ├── uxshare.c ├── uxsignal.c ├── uxstore.c ├── uxucs.c ├── x11misc.c ├── x11misc.h ├── xkeysym.c ├── xpmptcfg.c ├── xpmpterm.c ├── xpmpucfg.c └── xpmputty.c ├── urlhack.cpp ├── urlhack.h ├── version.c ├── version.h ├── wcwidth.c ├── wildcard.c ├── windows ├── README-msi.txt ├── README.txt ├── installer.wxs ├── pageant.ico ├── pageant.mft ├── pageant.rc ├── pageants.ico ├── pickicondialog.c ├── pickicondialog.h ├── plink.rc ├── pscp.ico ├── pscp.rc ├── psftp.rc ├── putty.ico ├── putty.iss ├── putty.manifest ├── putty.rc ├── puttycfg.ico ├── puttygen.ico ├── puttygen.mft ├── puttygen.rc ├── puttyins.ico ├── puttytel.rc ├── rcstuff.h ├── sizetip.c ├── urlhack_win.c ├── version.rc2 ├── website.url ├── win_res.h ├── win_res.rc2 ├── wincapi.c ├── wincapi.h ├── wincfg.c ├── wincons.c ├── winctrls.c ├── windefs.c ├── windlg.c ├── window.c ├── wingss.c ├── winhandl.c ├── winhelp.c ├── winhelp.h ├── winhsock.c ├── winjump.c ├── winmisc.c ├── winnet.c ├── winnoise.c ├── winnojmp.c ├── winnpc.c ├── winnps.c ├── winpgen.c ├── winpgnt.c ├── winpgntc.c ├── winplink.c ├── winprint.c ├── winproxy.c ├── winsecur.c ├── winsecur.h ├── winser.c ├── winsftp.c ├── winshare.c ├── winstore.c ├── winstuff.h ├── wintime.c ├── winucs.c ├── winutils.c └── winx11.c └── x11fwd.c /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.pyc 3 | .dirstamp 4 | .deps 5 | .DS_Store 6 | /*.pdb 7 | /*.ilk 8 | /*.res 9 | /*.RES 10 | /*.pch 11 | /*.rsp 12 | /*.obj 13 | /*.exe 14 | /*.ncb 15 | /*.plg 16 | /*.dsw 17 | /*.opt 18 | /*.dsp 19 | /*.tds 20 | /*.td2 21 | /*.map 22 | /Makefile.bor 23 | /Makefile.mgw 24 | /Makefile.vc 25 | /Makefile.lcc 26 | /MSVC 27 | /*.log 28 | /*.GID 29 | /local 30 | /Output 31 | /pageant 32 | /plink 33 | /pscp 34 | /psftp 35 | /putty 36 | /puttytel 37 | /puttygen 38 | /pterm 39 | /puttyapp 40 | /ptermapp 41 | /osxlaunch 42 | /unix/PuTTY.app 43 | /unix/Pterm.app 44 | /fuzzterm 45 | /testbn 46 | /cgtest 47 | /*.DSA 48 | /*.RSA 49 | /*.cnt 50 | /*.hlp 51 | /.bmake 52 | /build.log 53 | /build.out 54 | /uxconfig.h 55 | /empty.h 56 | /config.status 57 | /Makefile.am 58 | /Makefile.in 59 | /Makefile 60 | /compile 61 | /config.status 62 | /configure 63 | /stamp-h1 64 | /aclocal.m4 65 | /ar-lib 66 | /autom4te.cache 67 | /depcomp 68 | /install-sh 69 | /local 70 | /missing 71 | /uxconfig.in 72 | /uxconfig.h 73 | /licence.h 74 | /*.a 75 | /charset/sbcsdat.c 76 | /contrib/cygtermd/cygtermd.exe 77 | /doc/*.html 78 | /doc/*.txt 79 | /doc/*.cnt 80 | /doc/*.hlp 81 | /doc/*.gid 82 | /doc/*.GID 83 | /doc/*.chm 84 | /doc/*.log 85 | /doc/*.1 86 | /doc/*.info 87 | /doc/vstr.but 88 | /doc/*.hhp 89 | /doc/*.hhc 90 | /doc/*.hhk 91 | /doc/licence.but 92 | /doc/copy.but 93 | /icons/*.pam 94 | /icons/*.png 95 | /icons/*.ico 96 | /icons/*.icns 97 | /icons/*.xpm 98 | /icons/*.c 99 | /testdata/bignum.txt 100 | /unix/Makefile.gtk 101 | /unix/Makefile.ux 102 | /unix/Makefile.local 103 | /unix/empty.h 104 | /unix/plink 105 | /unix/pterm 106 | /unix/putty 107 | /unix/puttytel 108 | /unix/psftp 109 | /unix/pscp 110 | /unix/puttygen 111 | /unix/stamp-h1 112 | /unix/*.log 113 | /unix/.deps 114 | /windows/*.aps 115 | /windows/*.pdb 116 | /windows/*.ilk 117 | /windows/*.res 118 | /windows/*.RES 119 | /windows/*.pch 120 | /windows/*.rsp 121 | /windows/*.obj 122 | /windows/*.exe 123 | /windows/*.ncb 124 | /windows/*.plg 125 | /windows/*.dsw 126 | /windows/*.opt 127 | /windows/*.dsp 128 | /windows/*.tds 129 | /windows/*.td2 130 | /windows/*.map 131 | /windows/Makefile.clangcl 132 | /windows/Makefile.bor 133 | /windows/Makefile.mgw 134 | /windows/Makefile.vc 135 | /windows/Makefile.lcc 136 | /windows/MSVC 137 | /windows/DEVCPP 138 | /windows/VS2010 139 | /windows/VS2012 140 | /windows/*.log 141 | /windows/*.GID 142 | /windows/local 143 | /windows/Output 144 | /windows/*.DSA 145 | /windows/*.RSA 146 | /windows/*.cnt 147 | /windows/*.hlp 148 | /windows/.bmake 149 | /windows/*.sln 150 | /windows/*.suo 151 | /windows/*.msi 152 | /windows/*.wixobj 153 | /windows/*.wixpdb 154 | .clang-format 155 | doc/ 156 | build/ 157 | CMakeLists.txt 158 | .idea/ 159 | cmake-*/ 160 | crossbuild/ 161 | -------------------------------------------------------------------------------- /Buildscr.cv: -------------------------------------------------------------------------------- 1 | # -*- sh -*- 2 | 3 | # Build script to scan PuTTY with the downloadable Coverity scanner 4 | # and generate a tar file to upload to their open-source scanning 5 | # service. 6 | 7 | module putty 8 | 9 | # Preparations. 10 | in putty do ./mkfiles.pl 11 | in putty do ./mkauto.sh 12 | in putty/doc do make 13 | 14 | # Scan the Unix build, on a 64-bit system to differentiate as much as 15 | # possible from the other scan of the cross-platform files. 16 | delegate covscan64 17 | in putty do ./configure 18 | in putty do cov-build --dir cov-int make 19 | in putty do tar czvf cov-int.tar.gz cov-int 20 | return putty/cov-int.tar.gz 21 | enddelegate 22 | 23 | # Scan the Windows build, by means of building with Winelib (since as 24 | # of 2013-07-22, the Coverity Scan website doesn't offer a 32-bit 25 | # Windows scanner for download). 26 | delegate covscan32wine 27 | in putty do tar xzvf cov-int.tar.gz 28 | in putty/windows do cov-build --dir ../cov-int make -f Makefile.mgw CC=winegcc RC=wrc XFLAGS=-DCOVERITY 29 | in putty do tar czvf cov-int.tar.gz cov-int 30 | return putty/cov-int.tar.gz 31 | enddelegate 32 | 33 | # Provide the revision number as one of the build outputs, to make it 34 | # easy to construct a curl upload command which will annotate it 35 | # appropriately when uploaded. 36 | in putty do echo $(vcsfullid) > revision.txt 37 | 38 | deliver putty/revision.txt $@ 39 | deliver putty/cov-int.tar.gz $@ 40 | -------------------------------------------------------------------------------- /LATEST.VER: -------------------------------------------------------------------------------- 1 | 0.70 2 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | PuTTY is copyright 1997-2017 Simon Tatham. 2 | 3 | Portions copyright Robert de Bath, Joris van Rantwijk, Delian 4 | Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry, 5 | Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, Markus 6 | Kuhn, Colin Watson, Christopher Staite, and CORE SDI S.A. 7 | 8 | Permission is hereby granted, free of charge, to any person 9 | obtaining a copy of this software and associated documentation files 10 | (the "Software"), to deal in the Software without restriction, 11 | including without limitation the rights to use, copy, modify, merge, 12 | publish, distribute, sublicense, and/or sell copies of the Software, 13 | and to permit persons to whom the Software is furnished to do so, 14 | subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be 17 | included in all copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE 23 | FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 24 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PuTTYTray 2 | 3 | This branch contains an attempt to re-ignite PuTTYTray on PuTTY 0.68 or higher. 4 | 5 | ### Project status 6 | 7 | The project has fallen behind PuTTY upstream, and shouldn't be used for now. 8 | **Please use [upstream PuTTY](https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html)**. 9 | 10 | There is discussion of the [project status on github issues](https://github.com/FauxFaux/PuTTYTray/issues/278). 11 | 12 | The previously released binaries are built from the [latest PuTTYTray tag](https://github.com/FauxFaux/PuTTYTray/tree/p0.67-t029). 13 | 14 | ### Branches: 15 | 16 | * `upstream`: the actual upstream branch we're tracking (master) 17 | * `upclean`: an automatically cleaned-up variant of the branch 18 | * `scripts`: orphan branch carrying the scripts to generate upclean 19 | * `master`: third attempt to reignite the project 20 | * `t67-failed-merge`: a failed attempt to merge `0.68` and `p0.67-t029` 21 | * `t67-failed-patches`: a failed attempt to make patches from `p0.67-t029` 22 | 23 | I will rebase all branches. Please work from tags. 24 | 25 | **All branches are a mess**. Do not use them. Do not look at them. 26 | Do not raise issues or pull requests about them. 27 | 28 | 29 | ### Projects: 30 | 31 | * `proj`: miscellaneous changes necessary to run a project (e.g. README) 32 | * `cmake`: build system extensions to use cmake, could be merged 33 | * `url`: support for clickable urls, url menu, etc. 34 | * `backport`: pulling changes back from the next release 35 | * `zoom`: increase font size with the mousewheel 36 | * `fatty`: bundle `agent` and `gen` into `putty.exe` 37 | * `icon`: tray icon and extra menu / actions 38 | * `import`: transparent support for openssh key formats 39 | 40 | 41 | ### cmake 42 | 43 | ```bash 44 | mkdir -p doc && \ 45 | perl licence.pl && \ 46 | (cd charset && perl sbcsgen.pl) && \ 47 | ./mkcmake.py > CMakeLists.txt 48 | ``` 49 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 1.0.{build} 2 | image: Visual Studio 2017 3 | install: 4 | - cmd: >- 5 | mkdir doc 6 | 7 | perl licence.pl 8 | 9 | cd charset & perl sbcsgen.pl & cd .. 10 | 11 | C:\Python36-x64\python mkcmake.py > CMakeLists.txt 12 | 13 | mkdir cmake-build 14 | 15 | cd cmake-build 16 | 17 | cmake .. 18 | build: 19 | verbosity: normal 20 | test: off 21 | branches: 22 | only: 23 | - master 24 | artifacts: 25 | - path: cmake-build/RelWithDebInfo/putty.pdb 26 | - path: cmake-build/RelWithDebInfo/putty.exe 27 | configuration: 28 | - RelWithDebInfo 29 | -------------------------------------------------------------------------------- /aqsync.c: -------------------------------------------------------------------------------- 1 | /* 2 | * aqsync.c: the agent_query_synchronous() wrapper function. 3 | * 4 | * This is a very small thing to have to put in its own module, but it 5 | * wants to be shared between back ends, and exist in any SSH client 6 | * program and also Pageant, and _nowhere else_ (because it pulls in 7 | * the main agent_query). 8 | */ 9 | 10 | #include 11 | 12 | #include "putty.h" 13 | 14 | void agent_query_synchronous(void *in, int inlen, void **out, int *outlen) 15 | { 16 | agent_pending_query *pending; 17 | 18 | pending = agent_query(in, inlen, out, outlen, NULL, 0); 19 | assert(!pending); 20 | } 21 | -------------------------------------------------------------------------------- /be_all.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Linking module for PuTTY proper: list the available backends 3 | * including ssh. 4 | */ 5 | 6 | #include 7 | #include "putty.h" 8 | 9 | /* 10 | * This appname is not strictly in the right place, since Plink 11 | * also uses this module. However, Plink doesn't currently use any 12 | * of the dialog-box sorts of things that make use of appname, so 13 | * it shouldn't do any harm here. I'm trying to avoid having to 14 | * have tiny little source modules containing nothing but 15 | * declarations of appname, for as long as I can... 16 | */ 17 | const char *const appname = "PuTTY"; 18 | 19 | #ifdef TELNET_DEFAULT 20 | const int be_default_protocol = PROT_TELNET; 21 | #else 22 | const int be_default_protocol = PROT_SSH; 23 | #endif 24 | 25 | Backend *backends[] = { 26 | &ssh_backend, &telnet_backend, &rlogin_backend, &raw_backend, NULL}; 27 | -------------------------------------------------------------------------------- /be_all_s.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Linking module for PuTTY proper: list the available backends 3 | * including ssh, plus the serial backend. 4 | */ 5 | 6 | #include 7 | #include "putty.h" 8 | 9 | /* 10 | * This appname is not strictly in the right place, since Plink 11 | * also uses this module. However, Plink doesn't currently use any 12 | * of the dialog-box sorts of things that make use of appname, so 13 | * it shouldn't do any harm here. I'm trying to avoid having to 14 | * have tiny little source modules containing nothing but 15 | * declarations of appname, for as long as I can... 16 | */ 17 | const char *const appname = "PuTTY"; 18 | 19 | #ifdef TELNET_DEFAULT 20 | const int be_default_protocol = PROT_TELNET; 21 | #else 22 | const int be_default_protocol = PROT_SSH; 23 | #endif 24 | 25 | Backend *backends[] = {&ssh_backend, 26 | &telnet_backend, 27 | &rlogin_backend, 28 | &raw_backend, 29 | &serial_backend, 30 | NULL}; 31 | -------------------------------------------------------------------------------- /be_misc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * be_misc.c: helper functions shared between main network backends. 3 | */ 4 | 5 | #include 6 | #include 7 | 8 | #define DEFINE_PLUG_METHOD_MACROS 9 | #include "putty.h" 10 | #include "network.h" 11 | 12 | void backend_socket_log(void *frontend, 13 | int type, 14 | SockAddr addr, 15 | int port, 16 | const char *error_msg, 17 | int error_code, 18 | Conf *conf, 19 | int session_started) 20 | { 21 | char addrbuf[256], *msg; 22 | 23 | switch (type) { 24 | case 0: 25 | sk_getaddr(addr, addrbuf, lenof(addrbuf)); 26 | if (sk_addr_needs_port(addr)) { 27 | msg = dupprintf("Connecting to %s port %d", addrbuf, port); 28 | } else { 29 | msg = dupprintf("Connecting to %s", addrbuf); 30 | } 31 | break; 32 | case 1: 33 | sk_getaddr(addr, addrbuf, lenof(addrbuf)); 34 | msg = dupprintf("Failed to connect to %s: %s", addrbuf, error_msg); 35 | break; 36 | case 2: 37 | /* Proxy-related log messages have their own identifying 38 | * prefix already, put on by our caller. */ 39 | { 40 | int len, log_to_term; 41 | 42 | /* Suffix \r\n temporarily, so we can log to the terminal. */ 43 | msg = dupprintf("%s\r\n", error_msg); 44 | len = strlen(msg); 45 | assert(len >= 2); 46 | 47 | log_to_term = conf_get_int(conf, CONF_proxy_log_to_term); 48 | if (log_to_term == AUTO) 49 | log_to_term = session_started ? FORCE_OFF : FORCE_ON; 50 | if (log_to_term == FORCE_ON) 51 | from_backend(frontend, TRUE, msg, len); 52 | 53 | msg[len - 2] = '\0'; /* remove the \r\n again */ 54 | } 55 | break; 56 | default: 57 | msg = NULL; /* shouldn't happen, but placate optimiser */ 58 | break; 59 | } 60 | 61 | if (msg) { 62 | logevent(frontend, msg); 63 | sfree(msg); 64 | } 65 | } 66 | 67 | void log_proxy_stderr(Plug plug, bufchain *buf, const void *vdata, int len) 68 | { 69 | const char *data = (const char *)vdata; 70 | int pos = 0; 71 | int msglen; 72 | char *nlpos, *msg, *fullmsg; 73 | 74 | /* 75 | * This helper function allows us to collect the data written to a 76 | * local proxy command's standard error in whatever size chunks we 77 | * happen to get from its pipe, and whenever we have a complete 78 | * line, we pass it to plug_log. 79 | * 80 | * Prerequisites: a plug to log to, and a bufchain stored 81 | * somewhere to collect the data in. 82 | */ 83 | 84 | while (pos < len && (nlpos = memchr(data + pos, '\n', len - pos)) != NULL) { 85 | /* 86 | * Found a newline in the current input buffer. Append it to 87 | * the bufchain (which may contain a partial line from last 88 | * time). 89 | */ 90 | bufchain_add(buf, data + pos, nlpos - (data + pos)); 91 | 92 | /* 93 | * Collect the resulting line of data and pass it to plug_log. 94 | */ 95 | msglen = bufchain_size(buf); 96 | msg = snewn(msglen + 1, char); 97 | bufchain_fetch(buf, msg, msglen); 98 | bufchain_consume(buf, msglen); 99 | msg[msglen] = '\0'; 100 | fullmsg = dupprintf("proxy: %s", msg); 101 | plug_log(plug, 2, NULL, 0, fullmsg, 0); 102 | sfree(fullmsg); 103 | sfree(msg); 104 | 105 | /* 106 | * Advance past the newline. 107 | */ 108 | pos += nlpos + 1 - (data + pos); 109 | } 110 | 111 | /* 112 | * Now any remaining data is a partial line, which we save for 113 | * next time. 114 | */ 115 | bufchain_add(buf, data + pos, len - pos); 116 | } 117 | -------------------------------------------------------------------------------- /be_none.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Linking module for programs that do not support selection of backend 3 | * (such as pterm). 4 | */ 5 | 6 | #include 7 | #include "putty.h" 8 | 9 | Backend *backends[] = {NULL}; 10 | -------------------------------------------------------------------------------- /be_nos_s.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Linking module for PuTTYtel: list the available backends not 3 | * including ssh. 4 | */ 5 | 6 | #include 7 | #include "putty.h" 8 | 9 | const int be_default_protocol = PROT_TELNET; 10 | 11 | const char *const appname = "PuTTYtel"; 12 | 13 | Backend *backends[] = { 14 | &telnet_backend, &rlogin_backend, &raw_backend, &serial_backend, NULL}; 15 | 16 | /* 17 | * Stub implementations of functions not used in non-ssh versions. 18 | */ 19 | void random_save_seed(void) 20 | { 21 | } 22 | 23 | void random_destroy_seed(void) 24 | { 25 | } 26 | 27 | void noise_ultralight(unsigned long data) 28 | { 29 | } 30 | -------------------------------------------------------------------------------- /be_nossh.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Linking module for PuTTYtel: list the available backends not 3 | * including ssh. 4 | */ 5 | 6 | #include 7 | #include "putty.h" 8 | 9 | const int be_default_protocol = PROT_TELNET; 10 | 11 | const char *const appname = "PuTTYtel"; 12 | 13 | Backend *backends[] = {&telnet_backend, &rlogin_backend, &raw_backend, NULL}; 14 | 15 | /* 16 | * Stub implementations of functions not used in non-ssh versions. 17 | */ 18 | void random_save_seed(void) 19 | { 20 | } 21 | 22 | void random_destroy_seed(void) 23 | { 24 | } 25 | 26 | void noise_ultralight(unsigned long data) 27 | { 28 | } 29 | -------------------------------------------------------------------------------- /be_ssh.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Linking module for programs that are restricted to only using SSH 3 | * (pscp and psftp). These do not support selection of backend, but 4 | * must still have a backends[] array mentioning SSH because 5 | * settings.c will want to consult it during session load. 6 | */ 7 | 8 | #include 9 | #include "putty.h" 10 | 11 | const int be_default_protocol = PROT_SSH; 12 | 13 | Backend *backends[] = {&ssh_backend, NULL}; 14 | -------------------------------------------------------------------------------- /callback.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Facility for queueing callback functions to be run from the 3 | * top-level event loop after the current top-level activity finishes. 4 | */ 5 | 6 | #include 7 | 8 | #include "putty.h" 9 | 10 | struct callback { 11 | struct callback *next; 12 | 13 | toplevel_callback_fn_t fn; 14 | void *ctx; 15 | }; 16 | 17 | struct callback *cbhead = NULL, *cbtail = NULL; 18 | 19 | toplevel_callback_notify_fn_t notify_frontend = NULL; 20 | void *frontend = NULL; 21 | 22 | void request_callback_notifications(toplevel_callback_notify_fn_t fn, void *fr) 23 | { 24 | notify_frontend = fn; 25 | frontend = fr; 26 | } 27 | 28 | void queue_toplevel_callback(toplevel_callback_fn_t fn, void *ctx) 29 | { 30 | struct callback *cb; 31 | 32 | cb = snew(struct callback); 33 | cb->fn = fn; 34 | cb->ctx = ctx; 35 | 36 | /* If the front end has requested notification of pending 37 | * callbacks, and we didn't already have one queued, let it know 38 | * we do have one now. */ 39 | if (notify_frontend && !cbhead) 40 | notify_frontend(frontend); 41 | 42 | if (cbtail) 43 | cbtail->next = cb; 44 | else 45 | cbhead = cb; 46 | cbtail = cb; 47 | cb->next = NULL; 48 | } 49 | 50 | void run_toplevel_callbacks(void) 51 | { 52 | if (cbhead) { 53 | struct callback *cb = cbhead; 54 | /* 55 | * Careful ordering here. We call the function _before_ 56 | * advancing cbhead (though, of course, we must free cb 57 | * _after_ advancing it). This means that if the very last 58 | * callback schedules another callback, cbhead does not become 59 | * NULL at any point, and so the frontend notification 60 | * function won't be needlessly pestered. 61 | */ 62 | cb->fn(cb->ctx); 63 | cbhead = cb->next; 64 | sfree(cb); 65 | if (!cbhead) 66 | cbtail = NULL; 67 | } 68 | } 69 | 70 | int toplevel_callback_pending(void) 71 | { 72 | return cbhead != NULL; 73 | } 74 | -------------------------------------------------------------------------------- /cgtest.c: -------------------------------------------------------------------------------- 1 | /* 2 | * cgtest.c: stub file to compile cmdgen.c in self-test mode 3 | */ 4 | 5 | #define TEST_CMDGEN 6 | #include "cmdgen.c" 7 | -------------------------------------------------------------------------------- /charset/README: -------------------------------------------------------------------------------- 1 | This subdirectory contains a general character-set conversion 2 | library, used in the Unix port of PuTTY, and available for use in 3 | other ports if it should happen to be useful. 4 | 5 | This is a variant of a library that's currently used in some other 6 | programs such as Timber and Halibut. At some future date, we would 7 | like to merge the two libraries, so that all programs use the same 8 | libcharset. 9 | 10 | It is therefore a _strong_ design goal that this library should remain 11 | perfectly general, and not tied to particulars of PuTTY. It must not 12 | reference any code outside its own subdirectory; it should not have 13 | PuTTY-specific helper routines added to it unless they can be 14 | documented in a general manner which might make them useful in other 15 | circumstances as well. 16 | -------------------------------------------------------------------------------- /charset/enum.c: -------------------------------------------------------------------------------- 1 | /* 2 | * enum.c - enumerate all charsets defined by the library. 3 | * 4 | * This file maintains a list of every other source file which 5 | * contains ENUM_CHARSET definitions. It #includes each one with 6 | * ENUM_CHARSETS defined, which causes those source files to do 7 | * nothing at all except call the ENUM_CHARSET macro on each 8 | * charset they define. 9 | * 10 | * This file in turn is included from various other places, with 11 | * the ENUM_CHARSET macro defined to various different things. This 12 | * allows us to have multiple implementations of the master charset 13 | * lookup table (a static one and a dynamic one). 14 | */ 15 | 16 | #define ENUM_CHARSETS 17 | #include "sbcsdat.c" 18 | #include "utf8.c" 19 | #undef ENUM_CHARSETS 20 | -------------------------------------------------------------------------------- /charset/fromucs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * fromucs.c - convert Unicode to other character sets. 3 | */ 4 | 5 | #include "charset.h" 6 | #include "internal.h" 7 | 8 | struct charset_emit_param { 9 | char *output; 10 | int outlen; 11 | const char *errstr; 12 | int errlen; 13 | int stopped; 14 | }; 15 | 16 | static void charset_emit(void *ctx, long int output) 17 | { 18 | struct charset_emit_param *param = (struct charset_emit_param *)ctx; 19 | char outval; 20 | char const *p; 21 | int outlen; 22 | 23 | if (output == ERROR) { 24 | p = param->errstr; 25 | outlen = param->errlen; 26 | } else { 27 | outval = output; 28 | p = &outval; 29 | outlen = 1; 30 | } 31 | 32 | if (param->outlen >= outlen) { 33 | while (outlen > 0) { 34 | *param->output++ = *p++; 35 | param->outlen--; 36 | outlen--; 37 | } 38 | } else { 39 | param->stopped = 1; 40 | } 41 | } 42 | 43 | int charset_from_unicode(const wchar_t **input, 44 | int *inlen, 45 | char *output, 46 | int outlen, 47 | int charset, 48 | charset_state *state, 49 | const char *errstr, 50 | int errlen) 51 | { 52 | charset_spec const *spec = charset_find_spec(charset); 53 | charset_state localstate; 54 | struct charset_emit_param param; 55 | 56 | param.output = output; 57 | param.outlen = outlen; 58 | param.stopped = 0; 59 | 60 | /* 61 | * charset_emit will expect a valid errstr. 62 | */ 63 | if (!errstr) { 64 | /* *shrug* this is good enough, and consistent across all SBCS... */ 65 | param.errstr = "."; 66 | param.errlen = 1; 67 | } 68 | param.errstr = errstr; 69 | param.errlen = errlen; 70 | 71 | if (!state) { 72 | localstate.s0 = 0; 73 | } else { 74 | localstate = *state; /* structure copy */ 75 | } 76 | state = &localstate; 77 | 78 | while (*inlen > 0) { 79 | int lenbefore = param.output - output; 80 | spec->write(spec, **input, &localstate, charset_emit, ¶m); 81 | if (param.stopped) { 82 | /* 83 | * The emit function has _tried_ to output some 84 | * characters, but ran up against the end of the 85 | * buffer. Leave immediately, and return what happened 86 | * _before_ attempting to process this character. 87 | */ 88 | return lenbefore; 89 | } 90 | if (state) 91 | *state = localstate; /* structure copy */ 92 | (*input)++; 93 | (*inlen)--; 94 | } 95 | return param.output - output; 96 | } 97 | -------------------------------------------------------------------------------- /charset/internal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * internal.h - internal header stuff for the charset library. 3 | */ 4 | 5 | #ifndef charset_internal_h 6 | #define charset_internal_h 7 | 8 | /* This invariably comes in handy */ 9 | #define lenof(x) (sizeof((x)) / sizeof(*(x))) 10 | 11 | /* This is an invalid Unicode value used to indicate an error. */ 12 | #define ERROR 0xFFFFL /* Unicode value representing error */ 13 | 14 | typedef struct charset_spec charset_spec; 15 | typedef struct sbcs_data sbcs_data; 16 | 17 | struct charset_spec { 18 | int charset; /* numeric identifier */ 19 | 20 | /* 21 | * A function to read the character set and output Unicode 22 | * characters. The `emit' function expects to get Unicode chars 23 | * passed to it; it should be sent ERROR for any encoding error 24 | * on the input. 25 | */ 26 | void (*read)(charset_spec const *charset, 27 | long int input_chr, 28 | charset_state *state, 29 | void (*emit)(void *ctx, long int output), 30 | void *emitctx); 31 | /* 32 | * A function to read Unicode characters and output in this 33 | * character set. The `emit' function expects to get byte 34 | * values passed to it; it should be sent ERROR for any 35 | * non-representable characters on the input. 36 | */ 37 | void (*write)(charset_spec const *charset, 38 | long int input_chr, 39 | charset_state *state, 40 | void (*emit)(void *ctx, long int output), 41 | void *emitctx); 42 | void const *data; 43 | }; 44 | 45 | /* 46 | * This is the format of `data' used by the SBCS read and write 47 | * functions; so it's the format used in all SBCS definitions. 48 | */ 49 | struct sbcs_data { 50 | /* 51 | * This is a simple mapping table converting each SBCS position 52 | * to a Unicode code point. Some positions may contain ERROR, 53 | * indicating that that byte value is not defined in the SBCS 54 | * in question and its occurrence in input is an error. 55 | */ 56 | unsigned long sbcs2ucs[256]; 57 | 58 | /* 59 | * This lookup table is used to convert Unicode back to the 60 | * SBCS. It consists of the valid byte values in the SBCS, 61 | * sorted in order of their Unicode translation. So given a 62 | * Unicode value U, you can do a binary search on this table 63 | * using the above table as a lookup: when testing the Xth 64 | * position in this table, you branch according to whether 65 | * sbcs2ucs[ucs2sbcs[X]] is less than, greater than, or equal 66 | * to U. 67 | * 68 | * Note that since there may be fewer than 256 valid byte 69 | * values in a particular SBCS, we must supply the length of 70 | * this table as well as the contents. 71 | */ 72 | unsigned char ucs2sbcs[256]; 73 | int nvalid; 74 | }; 75 | 76 | /* 77 | * Prototypes for internal library functions. 78 | */ 79 | charset_spec const *charset_find_spec(int charset); 80 | void read_sbcs(charset_spec const *charset, 81 | long int input_chr, 82 | charset_state *state, 83 | void (*emit)(void *ctx, long int output), 84 | void *emitctx); 85 | void write_sbcs(charset_spec const *charset, 86 | long int input_chr, 87 | charset_state *state, 88 | void (*emit)(void *ctx, long int output), 89 | void *emitctx); 90 | 91 | /* 92 | * Placate compiler warning about unused parameters, of which we 93 | * expect to have some in this library. 94 | */ 95 | #define UNUSEDARG(x) ((x) = (x)) 96 | 97 | #endif /* charset_internal_h */ 98 | -------------------------------------------------------------------------------- /charset/localenc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * local.c - translate our internal character set codes to and from 3 | * our own set of plausibly legible character-set names. Also 4 | * provides a canonical name for each encoding (useful for software 5 | * announcing what character set it will be using), and a set of 6 | * enumeration functions which return a list of supported 7 | * encodings one by one. 8 | * 9 | * charset_from_localenc will attempt all other text translations 10 | * as well as this table, to maximise the number of different ways 11 | * you can select a supported charset. 12 | */ 13 | 14 | #include 15 | #include "charset.h" 16 | #include "internal.h" 17 | 18 | static const struct { 19 | const char *name; 20 | int charset; 21 | int return_in_enum; /* enumeration misses some charsets */ 22 | } localencs[] = { 23 | {"", CS_NONE, 0}, 24 | {"UTF-8", CS_UTF8, 1}, 25 | {"ISO-8859-1", CS_ISO8859_1, 1}, 26 | {"ISO-8859-1 with X11 line drawing", CS_ISO8859_1_X11, 0}, 27 | {"ISO-8859-2", CS_ISO8859_2, 1}, 28 | {"ISO-8859-3", CS_ISO8859_3, 1}, 29 | {"ISO-8859-4", CS_ISO8859_4, 1}, 30 | {"ISO-8859-5", CS_ISO8859_5, 1}, 31 | {"ISO-8859-6", CS_ISO8859_6, 1}, 32 | {"ISO-8859-7", CS_ISO8859_7, 1}, 33 | {"ISO-8859-8", CS_ISO8859_8, 1}, 34 | {"ISO-8859-9", CS_ISO8859_9, 1}, 35 | {"ISO-8859-10", CS_ISO8859_10, 1}, 36 | {"ISO-8859-11", CS_ISO8859_11, 1}, 37 | {"ISO-8859-13", CS_ISO8859_13, 1}, 38 | {"ISO-8859-14", CS_ISO8859_14, 1}, 39 | {"ISO-8859-15", CS_ISO8859_15, 1}, 40 | {"ISO-8859-16", CS_ISO8859_16, 1}, 41 | {"CP437", CS_CP437, 1}, 42 | {"CP850", CS_CP850, 1}, 43 | {"CP852", CS_CP852, 1}, 44 | {"CP866", CS_CP866, 1}, 45 | {"CP1250", CS_CP1250, 1}, 46 | {"CP1251", CS_CP1251, 1}, 47 | {"CP1252", CS_CP1252, 1}, 48 | {"CP1253", CS_CP1253, 1}, 49 | {"CP1254", CS_CP1254, 1}, 50 | {"CP1255", CS_CP1255, 1}, 51 | {"CP1256", CS_CP1256, 1}, 52 | {"CP1257", CS_CP1257, 1}, 53 | {"CP1258", CS_CP1258, 1}, 54 | {"KOI8-R", CS_KOI8_R, 1}, 55 | {"KOI8-U", CS_KOI8_U, 1}, 56 | {"Mac Roman", CS_MAC_ROMAN, 1}, 57 | {"Mac Turkish", CS_MAC_TURKISH, 1}, 58 | {"Mac Croatian", CS_MAC_CROATIAN, 1}, 59 | {"Mac Iceland", CS_MAC_ICELAND, 1}, 60 | {"Mac Romanian", CS_MAC_ROMANIAN, 1}, 61 | {"Mac Greek", CS_MAC_GREEK, 1}, 62 | {"Mac Cyrillic", CS_MAC_CYRILLIC, 1}, 63 | {"Mac Thai", CS_MAC_THAI, 1}, 64 | {"Mac Centeuro", CS_MAC_CENTEURO, 1}, 65 | {"Mac Symbol", CS_MAC_SYMBOL, 1}, 66 | {"Mac Dingbats", CS_MAC_DINGBATS, 1}, 67 | {"Mac Roman (old)", CS_MAC_ROMAN_OLD, 0}, 68 | {"Mac Croatian (old)", CS_MAC_CROATIAN_OLD, 0}, 69 | {"Mac Iceland (old)", CS_MAC_ICELAND_OLD, 0}, 70 | {"Mac Romanian (old)", CS_MAC_ROMANIAN_OLD, 0}, 71 | {"Mac Greek (old)", CS_MAC_GREEK_OLD, 0}, 72 | {"Mac Cyrillic (old)", CS_MAC_CYRILLIC_OLD, 0}, 73 | {"Mac Ukraine", CS_MAC_UKRAINE, 1}, 74 | {"Mac VT100", CS_MAC_VT100, 1}, 75 | {"Mac VT100 (old)", CS_MAC_VT100_OLD, 0}, 76 | {"VISCII", CS_VISCII, 1}, 77 | {"HP ROMAN8", CS_HP_ROMAN8, 1}, 78 | {"DEC MCS", CS_DEC_MCS, 1}, 79 | }; 80 | 81 | const char *charset_to_localenc(int charset) 82 | { 83 | int i; 84 | 85 | for (i = 0; i < (int)lenof(localencs); i++) 86 | if (charset == localencs[i].charset) 87 | return localencs[i].name; 88 | 89 | return NULL; /* not found */ 90 | } 91 | 92 | int charset_from_localenc(const char *name) 93 | { 94 | int i; 95 | 96 | if ((i = charset_from_mimeenc(name)) != CS_NONE) 97 | return i; 98 | if ((i = charset_from_xenc(name)) != CS_NONE) 99 | return i; 100 | 101 | for (i = 0; i < (int)lenof(localencs); i++) { 102 | const char *p, *q; 103 | p = name; 104 | q = localencs[i].name; 105 | while (*p || *q) { 106 | if (tolower((unsigned char)*p) != tolower((unsigned char)*q)) 107 | break; 108 | p++; 109 | q++; 110 | } 111 | if (!*p && !*q) 112 | return localencs[i].charset; 113 | } 114 | 115 | return CS_NONE; /* not found */ 116 | } 117 | 118 | int charset_localenc_nth(int n) 119 | { 120 | int i; 121 | 122 | for (i = 0; i < (int)lenof(localencs); i++) 123 | if (localencs[i].return_in_enum && !n--) 124 | return localencs[i].charset; 125 | 126 | return CS_NONE; /* end of list */ 127 | } 128 | -------------------------------------------------------------------------------- /charset/sbcs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * sbcs.c - routines to handle single-byte character sets. 3 | */ 4 | 5 | #include "charset.h" 6 | #include "internal.h" 7 | 8 | /* 9 | * The charset_spec for any single-byte character set should 10 | * provide read_sbcs() as its read function, and its `data' field 11 | * should be a wchar_t string constant containing the 256 entries 12 | * of the translation table. 13 | */ 14 | 15 | void read_sbcs(charset_spec const *charset, 16 | long int input_chr, 17 | charset_state *state, 18 | void (*emit)(void *ctx, long int output), 19 | void *emitctx) 20 | { 21 | const struct sbcs_data *sd = charset->data; 22 | 23 | UNUSEDARG(state); 24 | 25 | emit(emitctx, sd->sbcs2ucs[input_chr]); 26 | } 27 | 28 | void write_sbcs(charset_spec const *charset, 29 | long int input_chr, 30 | charset_state *state, 31 | void (*emit)(void *ctx, long int output), 32 | void *emitctx) 33 | { 34 | const struct sbcs_data *sd = charset->data; 35 | int i, j, k, c; 36 | 37 | UNUSEDARG(state); 38 | 39 | /* 40 | * Binary-search in the ucs2sbcs table. 41 | */ 42 | i = -1; 43 | j = sd->nvalid; 44 | while (i + 1 < j) { 45 | k = (i + j) / 2; 46 | c = sd->ucs2sbcs[k]; 47 | if (input_chr < sd->sbcs2ucs[c]) 48 | j = k; 49 | else if (input_chr > sd->sbcs2ucs[c]) 50 | i = k; 51 | else { 52 | emit(emitctx, c); 53 | return; 54 | } 55 | } 56 | emit(emitctx, ERROR); 57 | } 58 | -------------------------------------------------------------------------------- /charset/sbcsgen.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl -w 2 | 3 | # This script generates sbcsdat.c (the data for all the SBCSes) from its 4 | # source form sbcs.dat. 5 | 6 | $infile = "sbcs.dat"; 7 | $outfile = "sbcsdat.c"; 8 | 9 | open FOO, $infile; 10 | open BAR, ">$outfile"; 11 | select BAR; 12 | 13 | print "/*\n"; 14 | print " * sbcsdat.c - data definitions for single-byte character sets.\n"; 15 | print " *\n"; 16 | print " * Generated by sbcsgen.pl from sbcs.dat.\n"; 17 | print " * You should edit those files rather than editing this one.\n"; 18 | print " */\n"; 19 | print "\n"; 20 | print "#ifndef ENUM_CHARSETS\n"; 21 | print "\n"; 22 | print "#include \"charset.h\"\n"; 23 | print "#include \"internal.h\"\n"; 24 | print "\n"; 25 | 26 | my $charsetname = undef; 27 | my @vals = (); 28 | 29 | my @charsetnames = (); 30 | my @sortpriority = (); 31 | 32 | while () { 33 | chomp; 34 | if (/^charset (.*)$/) { 35 | $charsetname = $1; 36 | @vals = (); 37 | @sortpriority = map { 0 } 0..255; 38 | } elsif (/^sortpriority ([^-]*)-([^-]*) (.*)$/) { 39 | for ($i = hex $1; $i <= hex $2; $i++) { 40 | $sortpriority[$i] += $3; 41 | } 42 | } elsif (/^[0-9a-fA-FX]/) { 43 | push @vals, map { $_ eq "XXXX" ? -1 : hex $_ } split / +/, $_; 44 | if (scalar @vals > 256) { 45 | die "$infile:$.: charset $charsetname has more than 256 values\n"; 46 | } elsif (scalar @vals == 256) { 47 | &outcharset($charsetname, \@vals, \@sortpriority); 48 | push @charsetnames, $charsetname; 49 | $charsetname = undef; 50 | @vals = (); 51 | @sortpriority = map { 0 } 0..255; 52 | } 53 | } 54 | } 55 | 56 | print "#else /* ENUM_CHARSETS */\n"; 57 | print "\n"; 58 | 59 | foreach $i (@charsetnames) { 60 | print "ENUM_CHARSET($i)\n"; 61 | } 62 | 63 | print "\n"; 64 | print "#endif /* ENUM_CHARSETS */\n"; 65 | 66 | sub outcharset($$$) { 67 | my ($name, $vals, $sortpriority) = @_; 68 | my ($prefix, $i, @sorted); 69 | 70 | print "static const sbcs_data data_$name = {\n"; 71 | print " {\n"; 72 | $prefix = " "; 73 | @sorted = (); 74 | for ($i = 0; $i < 256; $i++) { 75 | if ($vals->[$i] < 0) { 76 | printf "%sERROR ", $prefix; 77 | } else { 78 | printf "%s0x%04x", $prefix, $vals->[$i]; 79 | die "ooh? $i\n" unless defined $sortpriority->[$i]; 80 | push @sorted, [$i, $vals->[$i], 0+$sortpriority->[$i]]; 81 | } 82 | if ($i % 8 == 7) { 83 | $prefix = ",\n "; 84 | } else { 85 | $prefix = ", "; 86 | } 87 | } 88 | print "\n },\n {\n"; 89 | @sorted = sort { ($a->[1] == $b->[1] ? 90 | $b->[2] <=> $a->[2] : 91 | $a->[1] <=> $b->[1]) || 92 | $a->[0] <=> $b->[0] } @sorted; 93 | $prefix = " "; 94 | $uval = -1; 95 | for ($i = $j = 0; $i < scalar @sorted; $i++) { 96 | next if ($uval == $sorted[$i]->[1]); # low-priority alternative 97 | $uval = $sorted[$i]->[1]; 98 | printf "%s0x%02x", $prefix, $sorted[$i]->[0]; 99 | if ($j % 8 == 7) { 100 | $prefix = ",\n "; 101 | } else { 102 | $prefix = ", "; 103 | } 104 | $j++; 105 | } 106 | printf "\n },\n %d\n", $j; 107 | print "};\n"; 108 | print "const charset_spec charset_$name = {\n" . 109 | " $name, read_sbcs, write_sbcs, &data_$name\n};\n\n"; 110 | } 111 | -------------------------------------------------------------------------------- /charset/slookup.c: -------------------------------------------------------------------------------- 1 | /* 2 | * slookup.c - static lookup of character sets. 3 | */ 4 | 5 | #include "charset.h" 6 | #include "internal.h" 7 | 8 | #define ENUM_CHARSET(x) extern charset_spec const charset_##x; 9 | #include "enum.c" 10 | #undef ENUM_CHARSET 11 | 12 | static charset_spec const *const cs_table[] = { 13 | 14 | #define ENUM_CHARSET(x) &charset_##x, 15 | #include "enum.c" 16 | #undef ENUM_CHARSET 17 | 18 | }; 19 | 20 | charset_spec const *charset_find_spec(int charset) 21 | { 22 | int i; 23 | 24 | for (i = 0; i < (int)lenof(cs_table); i++) 25 | if (cs_table[i]->charset == charset) 26 | return cs_table[i]; 27 | 28 | return NULL; 29 | } 30 | -------------------------------------------------------------------------------- /charset/toucs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * toucs.c - convert charsets to Unicode. 3 | */ 4 | 5 | #include "charset.h" 6 | #include "internal.h" 7 | 8 | struct unicode_emit_param { 9 | wchar_t *output; 10 | int outlen; 11 | const wchar_t *errstr; 12 | int errlen; 13 | int stopped; 14 | }; 15 | 16 | static void unicode_emit(void *ctx, long int output) 17 | { 18 | struct unicode_emit_param *param = (struct unicode_emit_param *)ctx; 19 | wchar_t outval; 20 | wchar_t const *p; 21 | int outlen; 22 | 23 | if (output == ERROR) { 24 | if (param->errstr) { 25 | p = param->errstr; 26 | outlen = param->errlen; 27 | } else { 28 | outval = 0xFFFD; /* U+FFFD REPLACEMENT CHARACTER */ 29 | p = &outval; 30 | outlen = 1; 31 | } 32 | } else { 33 | outval = output; 34 | p = &outval; 35 | outlen = 1; 36 | } 37 | 38 | if (param->outlen >= outlen) { 39 | while (outlen > 0) { 40 | *param->output++ = *p++; 41 | param->outlen--; 42 | outlen--; 43 | } 44 | } else { 45 | param->stopped = 1; 46 | } 47 | } 48 | 49 | int charset_to_unicode(const char **input, 50 | int *inlen, 51 | wchar_t *output, 52 | int outlen, 53 | int charset, 54 | charset_state *state, 55 | const wchar_t *errstr, 56 | int errlen) 57 | { 58 | charset_spec const *spec = charset_find_spec(charset); 59 | charset_state localstate; 60 | struct unicode_emit_param param; 61 | 62 | param.output = output; 63 | param.outlen = outlen; 64 | param.errstr = errstr; 65 | param.errlen = errlen; 66 | param.stopped = 0; 67 | 68 | if (!state) { 69 | localstate.s0 = 0; 70 | } else { 71 | localstate = *state; /* structure copy */ 72 | } 73 | 74 | while (*inlen > 0) { 75 | int lenbefore = param.output - output; 76 | spec->read(spec, (unsigned char)**input, &localstate, unicode_emit, ¶m); 77 | if (param.stopped) { 78 | /* 79 | * The emit function has _tried_ to output some 80 | * characters, but ran up against the end of the 81 | * buffer. Leave immediately, and return what happened 82 | * _before_ attempting to process this character. 83 | */ 84 | return lenbefore; 85 | } 86 | if (state) 87 | *state = localstate; /* structure copy */ 88 | (*input)++; 89 | (*inlen)--; 90 | } 91 | 92 | return param.output - output; 93 | } 94 | -------------------------------------------------------------------------------- /charset/xenc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * xenc.c - translate our internal character set codes to and from 3 | * X11 character encoding names. 4 | * 5 | */ 6 | 7 | #include 8 | #include "charset.h" 9 | #include "internal.h" 10 | 11 | static const struct { 12 | const char *name; 13 | int charset; 14 | } xencs[] = { 15 | /* 16 | * Officially registered encoding names. This list is derived 17 | * from the font encodings section of 18 | * 19 | * http://ftp.x.org/pub/DOCS/registry 20 | * 21 | * Where multiple encoding names map to the same encoding id 22 | * (such as iso8859-15 and fcd8859-15), the first is considered 23 | * canonical and will be returned when translating the id to a 24 | * string. 25 | */ 26 | {"iso8859-1", CS_ISO8859_1}, 27 | {"iso8859-2", CS_ISO8859_2}, 28 | {"iso8859-3", CS_ISO8859_3}, 29 | {"iso8859-4", CS_ISO8859_4}, 30 | {"iso8859-5", CS_ISO8859_5}, 31 | {"iso8859-6", CS_ISO8859_6}, 32 | {"iso8859-7", CS_ISO8859_7}, 33 | {"iso8859-8", CS_ISO8859_8}, 34 | {"iso8859-9", CS_ISO8859_9}, 35 | {"iso8859-10", CS_ISO8859_10}, 36 | {"iso8859-13", CS_ISO8859_13}, 37 | {"iso8859-14", CS_ISO8859_14}, 38 | {"iso8859-15", CS_ISO8859_15}, 39 | {"fcd8859-15", CS_ISO8859_15}, 40 | {"hp-roman8", CS_HP_ROMAN8}, 41 | {"koi8-r", CS_KOI8_R}, 42 | /* 43 | * Unofficial encoding names found in the wild. 44 | */ 45 | {"iso8859-16", CS_ISO8859_16}, 46 | {"koi8-u", CS_KOI8_U}, 47 | {"ibm-cp437", CS_CP437}, 48 | {"ibm-cp850", CS_CP850}, 49 | {"ibm-cp852", CS_CP852}, 50 | {"ibm-cp866", CS_CP866}, 51 | {"microsoft-cp1250", CS_CP1250}, 52 | {"microsoft-cp1251", CS_CP1251}, 53 | {"microsoft-cp1252", CS_CP1252}, 54 | {"microsoft-cp1253", CS_CP1253}, 55 | {"microsoft-cp1254", CS_CP1254}, 56 | {"microsoft-cp1255", CS_CP1255}, 57 | {"microsoft-cp1256", CS_CP1256}, 58 | {"microsoft-cp1257", CS_CP1257}, 59 | {"microsoft-cp1258", CS_CP1258}, 60 | {"mac-roman", CS_MAC_ROMAN}, 61 | {"viscii1.1-1", CS_VISCII}, 62 | {"viscii1-1", CS_VISCII}, 63 | }; 64 | 65 | const char *charset_to_xenc(int charset) 66 | { 67 | int i; 68 | 69 | for (i = 0; i < (int)lenof(xencs); i++) 70 | if (charset == xencs[i].charset) 71 | return xencs[i].name; 72 | 73 | return NULL; /* not found */ 74 | } 75 | 76 | int charset_from_xenc(const char *name) 77 | { 78 | int i; 79 | 80 | for (i = 0; i < (int)lenof(xencs); i++) { 81 | const char *p, *q; 82 | p = name; 83 | q = xencs[i].name; 84 | while (*p || *q) { 85 | if (tolower((unsigned char)*p) != tolower((unsigned char)*q)) 86 | break; 87 | p++; 88 | q++; 89 | } 90 | if (!*p && !*q) 91 | return xencs[i].charset; 92 | } 93 | 94 | return CS_NONE; /* not found */ 95 | } 96 | -------------------------------------------------------------------------------- /contrib/cygtermd/Makefile: -------------------------------------------------------------------------------- 1 | cygtermd.exe: main.c sel.c telnet.c pty.c malloc.c 2 | gcc -o cygtermd.exe main.c sel.c telnet.c pty.c malloc.c 3 | -------------------------------------------------------------------------------- /contrib/cygtermd/README: -------------------------------------------------------------------------------- 1 | This directory contains 'cygtermd', a small and specialist Telnet 2 | server designed to act as middleware between PuTTY and a Cygwin shell 3 | session running on the same machine, so that PuTTY can act as an 4 | xterm-alike for Cygwin. 5 | 6 | To install it, you must compile it from source using Cygwin gcc, 7 | install it in Cygwin's /bin, and configure PuTTY to use it as a local 8 | proxy process. For detailed instructions, see the PuTTY Wishlist page 9 | at 10 | 11 | https://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/cygwin-terminal-window.html 12 | -------------------------------------------------------------------------------- /contrib/cygtermd/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Main program. 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #include "sel.h" 18 | #include "pty.h" 19 | #include "telnet.h" 20 | 21 | int signalpipe[2]; 22 | 23 | sel *asel; 24 | sel_rfd *netr, *ptyr, *sigr; 25 | int ptyfd; 26 | sel_wfd *netw, *ptyw; 27 | Telnet telnet; 28 | 29 | #define BUF 65536 30 | 31 | void sigchld(int signum) 32 | { 33 | write(signalpipe[1], "C", 1); 34 | } 35 | 36 | void fatal(const char *fmt, ...) 37 | { 38 | va_list ap; 39 | fprintf(stderr, "FIXME: "); 40 | va_start(ap, fmt); 41 | vfprintf(stderr, fmt, ap); 42 | va_end(ap); 43 | fprintf(stderr, "\n"); 44 | exit(1); 45 | } 46 | 47 | void net_readdata(sel_rfd *rfd, void *data, size_t len) 48 | { 49 | if (len == 0) 50 | exit(0); /* EOF on network - client went away */ 51 | telnet_from_net(telnet, data, len); 52 | if (sel_write(netw, NULL, 0) > BUF) 53 | sel_rfd_freeze(ptyr); 54 | if (sel_write(ptyw, NULL, 0) > BUF) 55 | sel_rfd_freeze(netr); 56 | } 57 | 58 | void net_readerr(sel_rfd *rfd, int error) 59 | { 60 | fprintf(stderr, "standard input: read: %s\n", strerror(errno)); 61 | exit(1); 62 | } 63 | 64 | void net_written(sel_wfd *wfd, size_t bufsize) 65 | { 66 | if (bufsize < BUF) 67 | sel_rfd_unfreeze(ptyr); 68 | } 69 | 70 | void net_writeerr(sel_wfd *wfd, int error) 71 | { 72 | fprintf(stderr, "standard input: write: %s\n", strerror(errno)); 73 | exit(1); 74 | } 75 | 76 | void pty_readdata(sel_rfd *rfd, void *data, size_t len) 77 | { 78 | if (len == 0) 79 | exit(0); /* EOF on pty */ 80 | telnet_from_pty(telnet, data, len); 81 | if (sel_write(netw, NULL, 0) > BUF) 82 | sel_rfd_freeze(ptyr); 83 | if (sel_write(ptyw, NULL, 0) > BUF) 84 | sel_rfd_freeze(netr); 85 | } 86 | 87 | void pty_readerr(sel_rfd *rfd, int error) 88 | { 89 | if (error == EIO) /* means EOF, on a pty */ 90 | exit(0); 91 | fprintf(stderr, "pty: read: %s\n", strerror(errno)); 92 | exit(1); 93 | } 94 | 95 | void pty_written(sel_wfd *wfd, size_t bufsize) 96 | { 97 | if (bufsize < BUF) 98 | sel_rfd_unfreeze(netr); 99 | } 100 | 101 | void pty_writeerr(sel_wfd *wfd, int error) 102 | { 103 | fprintf(stderr, "pty: write: %s\n", strerror(errno)); 104 | exit(1); 105 | } 106 | 107 | void sig_readdata(sel_rfd *rfd, void *data, size_t len) 108 | { 109 | char *p = data; 110 | 111 | while (len > 0) { 112 | if (*p == 'C') { 113 | int status; 114 | waitpid(-1, &status, WNOHANG); 115 | if (WIFEXITED(status) || WIFSIGNALED(status)) 116 | exit(0); /* child process vanished */ 117 | } 118 | } 119 | } 120 | 121 | void sig_readerr(sel_rfd *rfd, int error) 122 | { 123 | fprintf(stderr, "signal pipe: read: %s\n", strerror(errno)); 124 | exit(1); 125 | } 126 | 127 | int main(int argc, char **argv) 128 | { 129 | int ret; 130 | int shell_started = 0; 131 | char *directory = NULL; 132 | char **program_args = NULL; 133 | 134 | if (argc > 1 && argv[1][0]) { 135 | directory = argv[1]; 136 | argc--, argv++; 137 | } 138 | if (argc > 1) { 139 | program_args = argv + 1; 140 | } 141 | 142 | pty_preinit(); 143 | 144 | asel = sel_new(NULL); 145 | netr = sel_rfd_add(asel, 0, net_readdata, net_readerr, NULL); 146 | netw = sel_wfd_add(asel, 1, net_written, net_writeerr, NULL); 147 | ptyr = sel_rfd_add(asel, -1, pty_readdata, pty_readerr, NULL); 148 | ptyw = sel_wfd_add(asel, -1, pty_written, pty_writeerr, NULL); 149 | 150 | telnet = telnet_new(netw, ptyw); 151 | 152 | if (pipe(signalpipe) < 0) { 153 | perror("pipe"); 154 | return 1; 155 | } 156 | sigr = sel_rfd_add(asel, signalpipe[0], sig_readdata, sig_readerr, NULL); 157 | 158 | signal(SIGCHLD, sigchld); 159 | 160 | do { 161 | struct shell_data shdata; 162 | 163 | ret = sel_iterate(asel, -1); 164 | if (!shell_started && telnet_shell_ok(telnet, &shdata)) { 165 | ptyfd = run_program_in_pty(&shdata, directory, program_args); 166 | sel_rfd_setfd(ptyr, ptyfd); 167 | sel_wfd_setfd(ptyw, ptyfd); 168 | shell_started = 1; 169 | } 170 | } while (ret == 0); 171 | 172 | return 0; 173 | } 174 | -------------------------------------------------------------------------------- /contrib/cygtermd/malloc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * malloc.c: implementation of malloc.h 3 | */ 4 | 5 | #include 6 | #include 7 | 8 | #include "malloc.h" 9 | 10 | extern void fatal(const char *, ...); 11 | 12 | void *smalloc(size_t size) 13 | { 14 | void *p; 15 | p = malloc(size); 16 | if (!p) { 17 | fatal("out of memory"); 18 | } 19 | return p; 20 | } 21 | 22 | void sfree(void *p) 23 | { 24 | if (p) { 25 | free(p); 26 | } 27 | } 28 | 29 | void *srealloc(void *p, size_t size) 30 | { 31 | void *q; 32 | if (p) { 33 | q = realloc(p, size); 34 | } else { 35 | q = malloc(size); 36 | } 37 | if (!q) 38 | fatal("out of memory"); 39 | return q; 40 | } 41 | 42 | char *dupstr(const char *s) 43 | { 44 | char *r = smalloc(1 + strlen(s)); 45 | strcpy(r, s); 46 | return r; 47 | } 48 | -------------------------------------------------------------------------------- /contrib/cygtermd/malloc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * malloc.h: safe wrappers around malloc, realloc, free, strdup 3 | */ 4 | 5 | #ifndef UMLWRAP_MALLOC_H 6 | #define UMLWRAP_MALLOC_H 7 | 8 | #include 9 | 10 | /* 11 | * smalloc should guarantee to return a useful pointer - Halibut 12 | * can do nothing except die when it's out of memory anyway. 13 | */ 14 | void *smalloc(size_t size); 15 | 16 | /* 17 | * srealloc should guaranteeably be able to realloc NULL 18 | */ 19 | void *srealloc(void *p, size_t size); 20 | 21 | /* 22 | * sfree should guaranteeably deal gracefully with freeing NULL 23 | */ 24 | void sfree(void *p); 25 | 26 | /* 27 | * dupstr is like strdup, but with the never-return-NULL property 28 | * of smalloc (and also reliably defined in all environments :-) 29 | */ 30 | char *dupstr(const char *s); 31 | 32 | /* 33 | * snew allocates one instance of a given type, and casts the 34 | * result so as to type-check that you're assigning it to the 35 | * right kind of pointer. Protects against allocation bugs 36 | * involving allocating the wrong size of thing. 37 | */ 38 | #define snew(type) ((type *)smalloc(sizeof(type))) 39 | 40 | /* 41 | * snewn allocates n instances of a given type, for arrays. 42 | */ 43 | #define snewn(number, type) ((type *)smalloc((number) * sizeof(type))) 44 | 45 | /* 46 | * sresize wraps realloc so that you specify the new number of 47 | * elements and the type of the element, with the same type- 48 | * checking advantages. Also type-checks the input pointer. 49 | */ 50 | #define sresize(array, number, type) \ 51 | ((void)sizeof((array) - (type *)0), \ 52 | (type *)srealloc((array), (number) * sizeof(type))) 53 | 54 | #endif /* UMLWRAP_MALLOC_H */ 55 | -------------------------------------------------------------------------------- /contrib/cygtermd/pty.h: -------------------------------------------------------------------------------- 1 | /* 2 | * pty.h - FIXME 3 | */ 4 | 5 | #ifndef FIXME_PTY_H 6 | #define FIXME_PTY_H 7 | 8 | #include "telnet.h" /* for struct shdata */ 9 | 10 | /* 11 | * Called at program startup to actually allocate a pty, so that 12 | * we can start passing in resize events as soon as they arrive. 13 | */ 14 | void pty_preinit(void); 15 | 16 | /* 17 | * Set the terminal size for the pty. 18 | */ 19 | void pty_resize(int w, int h); 20 | 21 | /* 22 | * Start a program in a subprocess running in the pty we allocated. 23 | * Returns the fd of the pty master. 24 | */ 25 | int run_program_in_pty(const struct shell_data *shdata, 26 | char *directory, 27 | char **program_args); 28 | 29 | #endif /* FIXME_PTY_H */ 30 | -------------------------------------------------------------------------------- /contrib/cygtermd/telnet.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Header declaring Telnet-handling functions. 3 | */ 4 | 5 | #ifndef FIXME_TELNET_H 6 | #define FIXME_TELNET_H 7 | 8 | #include "sel.h" 9 | 10 | typedef struct telnet_tag *Telnet; 11 | 12 | struct shell_data { 13 | char **envvars; /* array of "VAR=value" terms */ 14 | int nenvvars; 15 | char *termtype; 16 | }; 17 | 18 | /* 19 | * Create and destroy a Telnet structure. 20 | */ 21 | Telnet telnet_new(sel_wfd *net, sel_wfd *pty); 22 | void telnet_free(Telnet telnet); 23 | 24 | /* 25 | * Process data read from the pty. 26 | */ 27 | void telnet_from_pty(Telnet telnet, char *buf, int len); 28 | 29 | /* 30 | * Process Telnet protocol data received from the network. 31 | */ 32 | void telnet_from_net(Telnet telnet, char *buf, int len); 33 | 34 | /* 35 | * Return true if pre-shell-startup negotiations are complete and 36 | * it's safe to start the shell subprocess now. On a true return, 37 | * also fills in the shell_data structure. 38 | */ 39 | int telnet_shell_ok(Telnet telnet, struct shell_data *shdata); 40 | 41 | #endif /* FIXME_TELNET_H */ 42 | -------------------------------------------------------------------------------- /contrib/encodelib.py: -------------------------------------------------------------------------------- 1 | # Python module to make it easy to manually encode SSH packets, by 2 | # supporting the various uint32, string, mpint primitives. 3 | # 4 | # The idea of this is that you can use it to manually construct key 5 | # exchange sequences of interesting kinds, for testing purposes. 6 | 7 | import struct, random 8 | 9 | def boolean(b): 10 | return "\1" if b else "\0" 11 | 12 | def byte(b): 13 | assert 0 <= b < 0x100 14 | return chr(b) 15 | 16 | def uint32(u): 17 | assert 0 <= u < 0x100000000 18 | return struct.pack(">I", u) 19 | 20 | def uint64(u): 21 | assert 0 <= u < 0x10000000000000000 22 | return struct.pack(">L", u) 23 | 24 | def string(s): 25 | return uint32(len(s)) + s 26 | 27 | def mpint(m): 28 | s = "" 29 | lastbyte = 0 30 | while m > 0: 31 | lastbyte = m & 0xFF 32 | s = chr(lastbyte) + s 33 | m >>= 8 34 | if lastbyte & 0x80: 35 | s = "\0" + s 36 | return string(s) 37 | 38 | def name_list(ns): 39 | s = "" 40 | for n in ns: 41 | assert "," not in n 42 | if s != "": 43 | s += "," 44 | s += n 45 | return string(s) 46 | 47 | def ssh_rsa_key_blob(modulus, exponent): 48 | return string(string("ssh-rsa") + mpint(modulus) + mpint(exponent)) 49 | 50 | def ssh_rsa_signature_blob(signature): 51 | return string(string("ssh-rsa") + mpint(signature)) 52 | 53 | def greeting(string): 54 | # Greeting at the start of an SSH connection. 55 | return string + "\r\n" 56 | 57 | # Packet types. 58 | SSH2_MSG_DISCONNECT = 1 59 | SSH2_MSG_IGNORE = 2 60 | SSH2_MSG_UNIMPLEMENTED = 3 61 | SSH2_MSG_DEBUG = 4 62 | SSH2_MSG_SERVICE_REQUEST = 5 63 | SSH2_MSG_SERVICE_ACCEPT = 6 64 | SSH2_MSG_KEXINIT = 20 65 | SSH2_MSG_NEWKEYS = 21 66 | SSH2_MSG_KEXDH_INIT = 30 67 | SSH2_MSG_KEXDH_REPLY = 31 68 | SSH2_MSG_KEX_DH_GEX_REQUEST_OLD = 30 69 | SSH2_MSG_KEX_DH_GEX_GROUP = 31 70 | SSH2_MSG_KEX_DH_GEX_INIT = 32 71 | SSH2_MSG_KEX_DH_GEX_REPLY = 33 72 | SSH2_MSG_KEX_DH_GEX_REQUEST = 34 73 | SSH2_MSG_KEXRSA_PUBKEY = 30 74 | SSH2_MSG_KEXRSA_SECRET = 31 75 | SSH2_MSG_KEXRSA_DONE = 32 76 | SSH2_MSG_USERAUTH_REQUEST = 50 77 | SSH2_MSG_USERAUTH_FAILURE = 51 78 | SSH2_MSG_USERAUTH_SUCCESS = 52 79 | SSH2_MSG_USERAUTH_BANNER = 53 80 | SSH2_MSG_USERAUTH_PK_OK = 60 81 | SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ = 60 82 | SSH2_MSG_USERAUTH_INFO_REQUEST = 60 83 | SSH2_MSG_USERAUTH_INFO_RESPONSE = 61 84 | SSH2_MSG_GLOBAL_REQUEST = 80 85 | SSH2_MSG_REQUEST_SUCCESS = 81 86 | SSH2_MSG_REQUEST_FAILURE = 82 87 | SSH2_MSG_CHANNEL_OPEN = 90 88 | SSH2_MSG_CHANNEL_OPEN_CONFIRMATION = 91 89 | SSH2_MSG_CHANNEL_OPEN_FAILURE = 92 90 | SSH2_MSG_CHANNEL_WINDOW_ADJUST = 93 91 | SSH2_MSG_CHANNEL_DATA = 94 92 | SSH2_MSG_CHANNEL_EXTENDED_DATA = 95 93 | SSH2_MSG_CHANNEL_EOF = 96 94 | SSH2_MSG_CHANNEL_CLOSE = 97 95 | SSH2_MSG_CHANNEL_REQUEST = 98 96 | SSH2_MSG_CHANNEL_SUCCESS = 99 97 | SSH2_MSG_CHANNEL_FAILURE = 100 98 | SSH2_MSG_USERAUTH_GSSAPI_RESPONSE = 60 99 | SSH2_MSG_USERAUTH_GSSAPI_TOKEN = 61 100 | SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE = 63 101 | SSH2_MSG_USERAUTH_GSSAPI_ERROR = 64 102 | SSH2_MSG_USERAUTH_GSSAPI_ERRTOK = 65 103 | SSH2_MSG_USERAUTH_GSSAPI_MIC = 66 104 | 105 | def clearpkt(msgtype, *stuff): 106 | # SSH-2 binary packet, in the cleartext format used for initial 107 | # setup and kex. 108 | s = byte(msgtype) 109 | for thing in stuff: 110 | s += thing 111 | padlen = 0 112 | while padlen < 4 or len(s) % 8 != 3: 113 | padlen += 1 114 | s += byte(random.randint(0,255)) 115 | s = byte(padlen) + s 116 | return string(s) 117 | 118 | def decode_uint32(s): 119 | assert len(s) == 4 120 | return struct.unpack(">I", s)[0] 121 | 122 | def read_clearpkt(fh): 123 | length_field = fh.read(4) 124 | s = fh.read(decode_uint32(length_field)) 125 | import sys 126 | padlen = ord(s[0]) 127 | s = s[1:-padlen] 128 | msgtype = ord(s[0]) 129 | return msgtype, s[1:] 130 | -------------------------------------------------------------------------------- /contrib/logrewrap.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # Process a PuTTY SSH packet log that has gone through inappropriate 4 | # line wrapping, and try to make it legible again. 5 | # 6 | # Motivation: people often include PuTTY packet logs in email 7 | # messages, and if they're not careful, the sending MUA 'helpfully' 8 | # wraps the lines at 72 characters, corrupting all the hex dumps into 9 | # total unreadability. 10 | # 11 | # But as long as it's only the ASCII part of the dump at the end of 12 | # the line that gets wrapped, and the hex part is untouched, this is a 13 | # mechanically recoverable kind of corruption, because the ASCII is 14 | # redundant and can be reconstructed from the hex. Better still, you 15 | # can spot lines in which this has happened (because the ASCII at the 16 | # end of the line is a truncated version of what we think it should 17 | # say), and use that as a cue to remove the following line. 18 | 19 | use strict; 20 | use warnings; 21 | 22 | while (<>) { 23 | if (/^ ([0-9a-f]{8}) ((?:[0-9a-f]{2} ){0,15}(?:[0-9a-f]{2}))/) { 24 | my $addr = $1; 25 | my $hex = $2; 26 | my $ascii = ""; 27 | for (my $i = 0; $i < length($2); $i += 3) { 28 | my $byte = hex(substr($hex, $i, 2)); 29 | my $char = ($byte >= 32 && $byte < 127 ? chr($byte) : "."); 30 | $ascii .= $char; 31 | } 32 | $hex = substr($hex . (" " x 48), 0, 47); 33 | my $old_line = $_; 34 | chomp($old_line); 35 | my $new_line = " $addr $hex $ascii"; 36 | if ($old_line ne $new_line and 37 | $old_line eq substr($new_line, 0, length($old_line))) { 38 | print "$new_line\n"; 39 | <>; # eat the subsequent wrapped line 40 | next; 41 | } 42 | } 43 | print $_; 44 | } 45 | -------------------------------------------------------------------------------- /contrib/nice-ibeam.cur: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FauxFaux/PuTTYTray/4db528dd8477b7dbb40976fd0f1d4ff34d8bb101/contrib/nice-ibeam.cur -------------------------------------------------------------------------------- /errsock.c: -------------------------------------------------------------------------------- 1 | /* 2 | * A dummy Socket implementation which just holds an error message. 3 | */ 4 | 5 | #include 6 | #include 7 | 8 | #define DEFINE_PLUG_METHOD_MACROS 9 | #include "tree234.h" 10 | #include "putty.h" 11 | #include "network.h" 12 | 13 | typedef struct Socket_error_tag *Error_Socket; 14 | 15 | struct Socket_error_tag { 16 | const struct socket_function_table *fn; 17 | /* the above variable absolutely *must* be the first in this structure */ 18 | 19 | char *error; 20 | Plug plug; 21 | }; 22 | 23 | static Plug sk_error_plug(Socket s, Plug p) 24 | { 25 | Error_Socket ps = (Error_Socket)s; 26 | Plug ret = ps->plug; 27 | if (p) 28 | ps->plug = p; 29 | return ret; 30 | } 31 | 32 | static void sk_error_close(Socket s) 33 | { 34 | Error_Socket ps = (Error_Socket)s; 35 | 36 | sfree(ps->error); 37 | sfree(ps); 38 | } 39 | 40 | static const char *sk_error_socket_error(Socket s) 41 | { 42 | Error_Socket ps = (Error_Socket)s; 43 | return ps->error; 44 | } 45 | 46 | static char *sk_error_peer_info(Socket s) 47 | { 48 | return NULL; 49 | } 50 | 51 | Socket new_error_socket(const char *errmsg, Plug plug) 52 | { 53 | static const struct socket_function_table socket_fn_table = { 54 | sk_error_plug, 55 | sk_error_close, 56 | NULL /* write */, 57 | NULL /* write_oob */, 58 | NULL /* write_eof */, 59 | NULL /* flush */, 60 | NULL /* set_frozen */, 61 | sk_error_socket_error, 62 | sk_error_peer_info, 63 | }; 64 | 65 | Error_Socket ret; 66 | 67 | ret = snew(struct Socket_error_tag); 68 | ret->fn = &socket_fn_table; 69 | ret->plug = plug; 70 | ret->error = dupstr(errmsg); 71 | 72 | return (Socket)ret; 73 | } 74 | -------------------------------------------------------------------------------- /fatty.c: -------------------------------------------------------------------------------- 1 | #include "putty.h" 2 | 3 | int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) 4 | { 5 | char us[MAX_PATH]; 6 | 7 | while (*cmdline && isspace(*cmdline)) 8 | ++cmdline; 9 | 10 | #define ARG_RUN(arg, method) \ 11 | if (!strncmp(cmdline, arg, strlen(arg))) { \ 12 | return method(inst, prev, cmdline + strlen(arg), show); \ 13 | } 14 | 15 | ARG_RUN("--as-gen", puttygen_main); 16 | ARG_RUN("--as-agent", pageant_main); 17 | ARG_RUN("--as-putty", putty_main); 18 | #undef ARG_RUN 19 | 20 | if (GetModuleFileName(NULL, us, MAX_PATH)) { 21 | char *fn = strrchr(us, '\\'); 22 | if (!fn) 23 | fn = us; 24 | else 25 | ++fn; 26 | 27 | if (!strncmp(fn, "puttygen", strlen("puttygen"))) { 28 | return puttygen_main(inst, prev, cmdline, show); 29 | } 30 | if (!strncmp(fn, "pageant", strlen("pageant"))) { 31 | return pageant_main(inst, prev, cmdline, show); 32 | } 33 | } 34 | 35 | return putty_main(inst, prev, cmdline, show); 36 | } 37 | -------------------------------------------------------------------------------- /icons/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for the PuTTY icon suite. 2 | 3 | ICONS = putty puttycfg puttygen pscp pageant pterm ptermcfg puttyins 4 | SIZES = 16 32 48 128 5 | 6 | MODE = # override to -it on command line for opaque testing 7 | 8 | PAMS = $(foreach I,$(ICONS),$(foreach S,$(SIZES),$(I)-$(S).pam)) 9 | MONOPAMS = $(foreach I,$(ICONS),$(foreach S,$(SIZES),$(I)-$(S)-mono.pam)) 10 | TRUEPAMS = $(foreach I,$(ICONS),$(foreach S,$(SIZES),$(I)-$(S)-true.pam)) 11 | 12 | PNGS = $(patsubst %.pam,%.png,$(PAMS)) 13 | MONOPNGS = $(patsubst %.pam,%.png,$(MONOPAMS)) 14 | TRUEPNGS = $(patsubst %.pam,%.png,$(TRUEPAMS)) 15 | 16 | ICOS = putty.ico puttygen.ico pscp.ico pageant.ico pageants.ico puttycfg.ico \ 17 | puttyins.ico 18 | ICNS = PuTTY.icns Pterm.icns 19 | CICONS = xpmputty.c xpmpucfg.c xpmpterm.c xpmptcfg.c 20 | 21 | base: icos cicons 22 | 23 | all: pngs monopngs base icns # truepngs currently disabled by default 24 | 25 | pngs: $(PNGS) 26 | monopngs: $(MONOPNGS) 27 | truepngs: $(TRUEPNGS) 28 | 29 | icos: $(ICOS) 30 | icns: $(ICNS) 31 | cicons: $(CICONS) 32 | 33 | install: icos cicons 34 | cp $(ICOS) ../windows 35 | cp $(CICONS) ../unix 36 | 37 | $(PAMS): %.pam: mkicon.py 38 | ./mkicon.py $(MODE) $(join $(subst -, ,$(basename $@)),_icon) $@ 39 | 40 | $(PNGS) $(MONOPNGS) $(TRUEPNGS): %.png: %.pam 41 | convert $< $@ 42 | 43 | $(MONOPAMS): %.pam: mkicon.py 44 | ./mkicon.py -2 $(MODE) $(join $(subst -, ,$(subst -mono,,$(basename $@))),_icon) $@ 45 | 46 | $(TRUEPAMS): %.pam: mkicon.py 47 | ./mkicon.py -T $(MODE) $(join $(subst -, ,$(subst -true,,$(basename $@))),_icon) $@ 48 | 49 | putty.ico: putty-16.png putty-32.png putty-48.png \ 50 | putty-16-mono.png putty-32-mono.png putty-48-mono.png 51 | ./icon.pl -4 $(filter-out %-mono.png, $^) -1 $(filter %-mono.png, $^) > $@ 52 | 53 | puttycfg.ico: puttycfg-16.png puttycfg-32.png puttycfg-48.png \ 54 | puttycfg-16-mono.png puttycfg-32-mono.png puttycfg-48-mono.png 55 | ./icon.pl -4 $(filter-out %-mono.png, $^) -1 $(filter %-mono.png, $^) > $@ 56 | 57 | puttygen.ico: puttygen-16.png puttygen-32.png puttygen-48.png \ 58 | puttygen-16-mono.png puttygen-32-mono.png puttygen-48-mono.png 59 | ./icon.pl -4 $(filter-out %-mono.png, $^) -1 $(filter %-mono.png, $^) > $@ 60 | 61 | pageant.ico: pageant-16.png pageant-32.png pageant-48.png \ 62 | pageant-16-mono.png pageant-32-mono.png pageant-48-mono.png 63 | ./icon.pl -4 $(filter-out %-mono.png, $^) -1 $(filter %-mono.png, $^) > $@ 64 | 65 | pageants.ico: pageant-16.png pageant-16-mono.png 66 | ./icon.pl -4 $(filter-out %-mono.png, $^) -1 $(filter %-mono.png, $^) > $@ 67 | 68 | pscp.ico: pscp-16.png pscp-32.png pscp-48.png \ 69 | pscp-16-mono.png pscp-32-mono.png pscp-48-mono.png 70 | ./icon.pl -4 $(filter-out %-mono.png, $^) -1 $(filter %-mono.png, $^) > $@ 71 | 72 | # Because the installer icon makes heavy use of brown when drawing 73 | # the cardboard box, it's worth having 8-bit versions of it in 74 | # addition to the 4- and 1-bit ones. 75 | puttyins.ico: puttyins-16.png puttyins-32.png puttyins-48.png \ 76 | puttyins-16-mono.png puttyins-32-mono.png \ 77 | puttyins-48-mono.png \ 78 | puttyins-16-true.png puttyins-32-true.png \ 79 | puttyins-48-true.png 80 | ./icon.pl -8 $(filter %-true.png, $^) \ 81 | -4 $(filter-out %-true.png, $(filter-out %-mono.png, $^)) \ 82 | -1 $(filter %-mono.png, $^) > $@ 83 | 84 | # Icon for the website. (This isn't linked into "make all".) 85 | website.ico: putty-16.png 86 | ./icon.pl -4 $^ >$@ 87 | 88 | xpmputty.c: putty-16.png putty-32.png putty-48.png 89 | ./cicon.pl main_icon $^ > $@ 90 | 91 | xpmpucfg.c: puttycfg-16.png puttycfg-32.png puttycfg-48.png 92 | ./cicon.pl cfg_icon $^ > $@ 93 | 94 | xpmpterm.c: pterm-16.png pterm-32.png pterm-48.png 95 | ./cicon.pl main_icon $^ > $@ 96 | 97 | xpmptcfg.c: ptermcfg-16.png ptermcfg-32.png ptermcfg-48.png 98 | ./cicon.pl cfg_icon $^ > $@ 99 | 100 | PuTTY.icns: putty-16-mono.pam putty-16.pam \ 101 | putty-32-mono.pam putty-32.pam \ 102 | putty-48-mono.pam putty-48.pam \ 103 | putty-128.pam 104 | ./macicon.py mono:putty-16-mono.pam colour:putty-16.pam \ 105 | mono:putty-32-mono.pam colour:putty-32.pam \ 106 | mono:putty-48-mono.pam colour:putty-48.pam \ 107 | colour:putty-128.pam \ 108 | output:$@ 109 | 110 | Pterm.icns: pterm-16-mono.pam pterm-16.pam \ 111 | pterm-32-mono.pam pterm-32.pam \ 112 | pterm-48-mono.pam pterm-48.pam \ 113 | pterm-128.pam 114 | ./macicon.py mono:pterm-16-mono.pam colour:pterm-16.pam \ 115 | mono:pterm-32-mono.pam colour:pterm-32.pam \ 116 | mono:pterm-48-mono.pam colour:pterm-48.pam \ 117 | colour:pterm-128.pam \ 118 | output:$@ 119 | 120 | clean: 121 | rm -f *.pam *.png *.ico *.icns *.c 122 | -------------------------------------------------------------------------------- /icons/cicon.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # Given a list of input PNGs, create a C source file containing a 4 | # const array of XPMs, named by a given C identifier. 5 | 6 | $id = shift @ARGV; 7 | $k = 0; 8 | @xpms = (); 9 | foreach $f (@ARGV) { 10 | # XPM format is generated directly by ImageMagick, so that's easy 11 | # enough. We just have to adjust the declaration line so that it 12 | # has the right name, linkage and storage class. 13 | @lines = (); 14 | open XPM, "convert $f xpm:- |"; 15 | push @lines, $_ while ; 16 | close XPM; 17 | die "XPM from $f in unexpected format\n" unless $lines[1] =~ /^static.*\{$/; 18 | $lines[1] = "static const char *const ${id}_$k"."[] = {\n"; 19 | $k++; 20 | push @xpms, @lines, "\n"; 21 | } 22 | 23 | # Now output. 24 | foreach $line (@xpms) { print $line; } 25 | print "const char *const *const ${id}[] = {\n"; 26 | for ($i = 0; $i < $k; $i++) { print " ${id}_$i,\n"; } 27 | print "};\n"; 28 | print "const int n_${id} = $k;\n"; 29 | -------------------------------------------------------------------------------- /int64.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Handling of the int64 and uint64 types. Done in 32-bit integers, 3 | * for (pre-C99) portability. Hopefully once C99 becomes widespread 4 | * we can kiss this lot goodbye... 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #include "int64.h" 11 | 12 | uint64 uint64_div10(uint64 x, int *remainder) 13 | { 14 | uint64 y; 15 | unsigned int rem, r2; 16 | y.hi = x.hi / 10; 17 | y.lo = x.lo / 10; 18 | rem = x.lo % 10; 19 | /* 20 | * Now we have to add in the remainder left over from x.hi. 21 | */ 22 | r2 = x.hi % 10; 23 | y.lo += r2 * 429496729; 24 | rem += r2 * 6; 25 | y.lo += rem / 10; 26 | rem %= 10; 27 | 28 | if (remainder) 29 | *remainder = rem; 30 | return y; 31 | } 32 | 33 | void uint64_decimal(uint64 x, char *buffer) 34 | { 35 | char buf[20]; 36 | int start = 20; 37 | int d; 38 | 39 | do { 40 | x = uint64_div10(x, &d); 41 | assert(start > 0); 42 | buf[--start] = d + '0'; 43 | } while (x.hi || x.lo); 44 | 45 | memcpy(buffer, buf + start, sizeof(buf) - start); 46 | buffer[sizeof(buf) - start] = '\0'; 47 | } 48 | 49 | uint64 uint64_make(unsigned long hi, unsigned long lo) 50 | { 51 | uint64 y; 52 | y.hi = hi & 0xFFFFFFFFU; 53 | y.lo = lo & 0xFFFFFFFFU; 54 | return y; 55 | } 56 | 57 | uint64 uint64_add(uint64 x, uint64 y) 58 | { 59 | x.lo = (x.lo + y.lo) & 0xFFFFFFFFU; 60 | x.hi += y.hi + (x.lo < y.lo ? 1 : 0); 61 | return x; 62 | } 63 | 64 | uint64 uint64_add32(uint64 x, unsigned long y) 65 | { 66 | uint64 yy; 67 | yy.hi = 0; 68 | yy.lo = y; 69 | return uint64_add(x, yy); 70 | } 71 | 72 | int uint64_compare(uint64 x, uint64 y) 73 | { 74 | if (x.hi != y.hi) 75 | return x.hi < y.hi ? -1 : +1; 76 | if (x.lo != y.lo) 77 | return x.lo < y.lo ? -1 : +1; 78 | return 0; 79 | } 80 | 81 | uint64 uint64_subtract(uint64 x, uint64 y) 82 | { 83 | x.lo = (x.lo - y.lo) & 0xFFFFFFFFU; 84 | x.hi = (x.hi - y.hi - (x.lo > (y.lo ^ 0xFFFFFFFFU) ? 1 : 0)) & 0xFFFFFFFFU; 85 | return x; 86 | } 87 | 88 | double uint64_to_double(uint64 x) 89 | { 90 | return (4294967296.0 * x.hi) + (double)x.lo; 91 | } 92 | 93 | uint64 uint64_shift_right(uint64 x, int shift) 94 | { 95 | if (shift < 32) { 96 | x.lo >>= shift; 97 | x.lo |= (x.hi << (32 - shift)) & 0xFFFFFFFFU; 98 | x.hi >>= shift; 99 | } else { 100 | x.lo = x.hi >> (shift - 32); 101 | x.hi = 0; 102 | } 103 | return x; 104 | } 105 | 106 | uint64 uint64_shift_left(uint64 x, int shift) 107 | { 108 | if (shift < 32) { 109 | x.hi = (x.hi << shift) & 0xFFFFFFFFU; 110 | x.hi |= (x.lo >> (32 - shift)); 111 | x.lo = (x.lo << shift) & 0xFFFFFFFFU; 112 | } else { 113 | x.hi = (x.lo << (shift - 32)) & 0xFFFFFFFFU; 114 | x.lo = 0; 115 | } 116 | return x; 117 | } 118 | 119 | uint64 uint64_from_decimal(char *str) 120 | { 121 | uint64 ret; 122 | ret.hi = ret.lo = 0; 123 | while (*str >= '0' && *str <= '9') { 124 | ret = uint64_add(uint64_shift_left(ret, 3), uint64_shift_left(ret, 1)); 125 | ret = uint64_add32(ret, *str - '0'); 126 | str++; 127 | } 128 | return ret; 129 | } 130 | 131 | #ifdef TESTMODE 132 | 133 | #include 134 | 135 | int main(void) 136 | { 137 | uint64 x, y, z; 138 | char buf[80]; 139 | 140 | x = uint64_make(0x3456789AUL, 0xDEF01234UL); 141 | printf("%08lx.%08lx\n", x.hi, x.lo); 142 | uint64_decimal(x, buf); 143 | printf("%s\n", buf); 144 | 145 | y = uint64_add32(x, 0xFFFFFFFFU); 146 | printf("%08lx.%08lx\n", y.hi, y.lo); 147 | uint64_decimal(y, buf); 148 | printf("%s\n", buf); 149 | 150 | z = uint64_subtract(y, x); 151 | printf("%08lx.%08lx\n", z.hi, z.lo); 152 | uint64_decimal(z, buf); 153 | printf("%s\n", buf); 154 | 155 | z = uint64_subtract(x, y); 156 | printf("%08lx.%08lx\n", z.hi, z.lo); 157 | uint64_decimal(z, buf); 158 | printf("%s\n", buf); 159 | 160 | y = uint64_shift_right(x, 4); 161 | printf("%08lx.%08lx\n", y.hi, y.lo); 162 | 163 | y = uint64_shift_right(x, 36); 164 | printf("%08lx.%08lx\n", y.hi, y.lo); 165 | 166 | y = uint64_shift_left(x, 4); 167 | printf("%08lx.%08lx\n", x.hi, x.lo); 168 | 169 | y = uint64_shift_left(x, 36); 170 | printf("%08lx.%08lx\n", x.hi, x.lo); 171 | 172 | return 0; 173 | } 174 | #endif 175 | -------------------------------------------------------------------------------- /int64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Header for int64.c. 3 | */ 4 | 5 | #ifndef PUTTY_INT64_H 6 | #define PUTTY_INT64_H 7 | 8 | typedef struct { 9 | unsigned long hi, lo; 10 | } uint64; 11 | 12 | uint64 uint64_div10(uint64 x, int *remainder); 13 | void uint64_decimal(uint64 x, char *buffer); 14 | uint64 uint64_make(unsigned long hi, unsigned long lo); 15 | uint64 uint64_add(uint64 x, uint64 y); 16 | uint64 uint64_add32(uint64 x, unsigned long y); 17 | int uint64_compare(uint64 x, uint64 y); 18 | uint64 uint64_subtract(uint64 x, uint64 y); 19 | double uint64_to_double(uint64 x); 20 | uint64 uint64_shift_right(uint64 x, int shift); 21 | uint64 uint64_shift_left(uint64 x, int shift); 22 | uint64 uint64_from_decimal(char *str); 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /ldisc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ldisc.h: defines the Ldisc data structure used by ldisc.c and 3 | * ldiscucs.c. (Unfortunately it was necessary to split the ldisc 4 | * module in two, to avoid unnecessarily linking in the Unicode 5 | * stuff in tools that don't require it.) 6 | */ 7 | 8 | #ifndef PUTTY_LDISC_H 9 | #define PUTTY_LDISC_H 10 | 11 | typedef struct ldisc_tag { 12 | Terminal *term; 13 | Backend *back; 14 | void *backhandle; 15 | void *frontend; 16 | 17 | /* 18 | * Values cached out of conf. 19 | */ 20 | int telnet_keyboard, telnet_newline, protocol, localecho, localedit; 21 | 22 | char *buf; 23 | int buflen, bufsiz, quotenext; 24 | } * Ldisc; 25 | 26 | #endif /* PUTTY_LDISC_H */ 27 | -------------------------------------------------------------------------------- /ldiscucs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ldisc.c: PuTTY line discipline. Sits between the input coming 3 | * from keypresses in the window, and the output channel leading to 4 | * the back end. Implements echo and/or local line editing, 5 | * depending on what's currently configured. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | #include "putty.h" 12 | #include "terminal.h" 13 | #include "ldisc.h" 14 | 15 | void lpage_send( 16 | void *handle, int codepage, const char *buf, int len, int interactive) 17 | { 18 | Ldisc ldisc = (Ldisc)handle; 19 | wchar_t *widebuffer = 0; 20 | int widesize = 0; 21 | int wclen; 22 | 23 | if (codepage < 0) { 24 | ldisc_send(ldisc, buf, len, interactive); 25 | return; 26 | } 27 | 28 | widesize = len * 2; 29 | widebuffer = snewn(widesize, wchar_t); 30 | 31 | wclen = mb_to_wc(codepage, 0, buf, len, widebuffer, widesize); 32 | luni_send(ldisc, widebuffer, wclen, interactive); 33 | 34 | sfree(widebuffer); 35 | } 36 | 37 | void luni_send(void *handle, const wchar_t *widebuf, int len, int interactive) 38 | { 39 | Ldisc ldisc = (Ldisc)handle; 40 | int ratio = (in_utf(ldisc->term)) ? 3 : 1; 41 | char *linebuffer; 42 | int linesize; 43 | int i; 44 | char *p; 45 | 46 | linesize = len * ratio * 2; 47 | linebuffer = snewn(linesize, char); 48 | 49 | if (in_utf(ldisc->term)) { 50 | /* UTF is a simple algorithm */ 51 | for (p = linebuffer, i = 0; i < len; i++) { 52 | unsigned long ch = widebuf[i]; 53 | 54 | if (IS_SURROGATE(ch)) { 55 | #ifdef PLATFORM_IS_UTF16 56 | if (i + 1 < len) { 57 | unsigned long ch2 = widebuf[i + 1]; 58 | if (IS_SURROGATE_PAIR(ch, ch2)) { 59 | ch = FROM_SURROGATES(ch, ch2); 60 | i++; 61 | } 62 | } else 63 | #endif 64 | { 65 | /* Unrecognised UTF-16 sequence */ 66 | ch = '.'; 67 | } 68 | } 69 | 70 | if (ch < 0x80) { 71 | *p++ = (char)(ch); 72 | } else if (ch < 0x800) { 73 | *p++ = (char)(0xC0 | (ch >> 6)); 74 | *p++ = (char)(0x80 | (ch & 0x3F)); 75 | } else if (ch < 0x10000) { 76 | *p++ = (char)(0xE0 | (ch >> 12)); 77 | *p++ = (char)(0x80 | ((ch >> 6) & 0x3F)); 78 | *p++ = (char)(0x80 | (ch & 0x3F)); 79 | } else { 80 | *p++ = (char)(0xF0 | (ch >> 18)); 81 | *p++ = (char)(0x80 | ((ch >> 12) & 0x3F)); 82 | *p++ = (char)(0x80 | ((ch >> 6) & 0x3F)); 83 | *p++ = (char)(0x80 | (ch & 0x3F)); 84 | } 85 | } 86 | } else { 87 | int rv; 88 | rv = wc_to_mb(ldisc->term->ucsdata->line_codepage, 89 | 0, 90 | widebuf, 91 | len, 92 | linebuffer, 93 | linesize, 94 | NULL, 95 | NULL, 96 | ldisc->term->ucsdata); 97 | if (rv >= 0) 98 | p = linebuffer + rv; 99 | else 100 | p = linebuffer; 101 | } 102 | if (p > linebuffer) 103 | ldisc_send(ldisc, linebuffer, p - linebuffer, interactive); 104 | 105 | sfree(linebuffer); 106 | } 107 | -------------------------------------------------------------------------------- /licence.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl -w 2 | 3 | # This script generates licence.h (containing the PuTTY licence in the 4 | # form of macros expanding to C string literals) from the LICENCE 5 | # master file. It also regenerates the licence-related Halibut input 6 | # files. 7 | 8 | use File::Basename; 9 | 10 | # Read the input file. 11 | $infile = "LICENCE"; 12 | open my $in, $infile or die "$infile: open: $!\n"; 13 | my @lines = (); 14 | while (<$in>) { 15 | chomp; 16 | push @lines, $_; 17 | } 18 | close $in; 19 | 20 | # Format into paragraphs. 21 | my @paras = (); 22 | my $para = undef; 23 | for my $line (@lines) { 24 | if ($line eq "") { 25 | $para = undef; 26 | } elsif (!defined $para) { 27 | push @paras, $line; 28 | $para = \$paras[$#paras]; 29 | } else { 30 | $$para .= " " . $line; 31 | } 32 | } 33 | 34 | # Get the copyright years and short form of copyright holder. 35 | die "bad format of first paragraph\n" 36 | unless $paras[0] =~ m!copyright ([^\.]*)\.!i; 37 | $shortdetails = $1; 38 | 39 | # Write out licence.h. 40 | 41 | $outfile = "licence.h"; 42 | open my $out, ">", $outfile or die "$outfile: open: $!\n"; 43 | select $out; 44 | 45 | print "/*\n"; 46 | print " * $outfile - macro definitions for the PuTTY licence.\n"; 47 | print " *\n"; 48 | print " * Generated by @{[basename __FILE__]} from $infile.\n"; 49 | print " * You should edit those files rather than editing this one.\n"; 50 | print " */\n"; 51 | print "\n"; 52 | 53 | print "#define LICENCE_TEXT(parsep) \\\n"; 54 | for my $i (0..$#paras) { 55 | my $lit = &stringlit($paras[$i]); 56 | print " parsep \\\n" if $i > 0; 57 | print " \"$lit\""; 58 | print " \\" if $i < $#paras; 59 | print "\n"; 60 | } 61 | print "\n"; 62 | 63 | printf "#define SHORT_COPYRIGHT_DETAILS \"%s\"\n", &stringlit($shortdetails); 64 | 65 | sub stringlit { 66 | my ($lit) = @_; 67 | $lit =~ s!\\!\\\\!g; 68 | $lit =~ s!"!\\"!g; 69 | return $lit; 70 | } 71 | 72 | close $out; 73 | 74 | # Write out doc/licence.but. 75 | 76 | $outfile = "doc/licence.but"; 77 | open $out, ">", $outfile or die "$outfile: open: $!\n"; 78 | select $out; 79 | 80 | print "\\# Generated by @{[basename __FILE__]} from $infile.\n"; 81 | print "\\# You should edit those files rather than editing this one.\n\n"; 82 | 83 | print "\\A{licence} PuTTY \\ii{Licence}\n\n"; 84 | 85 | for my $i (0..$#paras) { 86 | my $para = &halibutescape($paras[$i]); 87 | if ($i == 0) { 88 | $para =~ s!copyright!\\i{copyright}!; # index term in paragraph 1 89 | } 90 | print "$para\n\n"; 91 | } 92 | 93 | close $out; 94 | 95 | # And write out doc/copy.but, which defines a macro used in the manual 96 | # preamble blurb. 97 | 98 | $outfile = "doc/copy.but"; 99 | open $out, ">", $outfile or die "$outfile: open: $!\n"; 100 | select $out; 101 | 102 | print "\\# Generated by @{[basename __FILE__]} from $infile.\n"; 103 | print "\\# You should edit those files rather than editing this one.\n\n"; 104 | 105 | printf "\\define{shortcopyrightdetails} %s\n\n", 106 | &halibutescape($shortdetails); 107 | 108 | close $out; 109 | 110 | sub halibutescape { 111 | my ($text) = @_; 112 | $text =~ s![\\{}]!\\$&!g; # Halibut escaping 113 | $text =~ s!"([^"]*)"!\\q{$1}!g; # convert quoted strings to \q{} 114 | return $text; 115 | } 116 | -------------------------------------------------------------------------------- /mingw-w64-x86_64.cmake: -------------------------------------------------------------------------------- 1 | # Sample toolchain file for building for Windows from an Ubuntu Linux system. 2 | # 3 | # Typical usage: 4 | # *) install cross compiler: `sudo apt-get install mingw-w64` 5 | # *) cd build 6 | # *) cmake -DCMAKE_TOOLCHAIN_FILE=../mingw-w64-x86_64.cmake .. 7 | 8 | set(CMAKE_SYSTEM_NAME Windows) 9 | set(UNIX false) 10 | set(WIN32 true) 11 | set(TOOLCHAIN_PREFIX x86_64-w64-mingw32) 12 | 13 | # cross compilers to use for C, C++ and Fortran 14 | set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc) 15 | set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++) 16 | set(CMAKE_Fortran_COMPILER ${TOOLCHAIN_PREFIX}-gfortran) 17 | set(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres) 18 | 19 | # target environment on the build host system 20 | set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX}) 21 | 22 | # modify default behavior of FIND_XXX() commands 23 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 24 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 25 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) -------------------------------------------------------------------------------- /miscucs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Centralised Unicode-related helper functions, separate from misc.c 3 | * so that they can be omitted from tools that aren't including 4 | * Unicode handling. 5 | */ 6 | 7 | #include "putty.h" 8 | #include "misc.h" 9 | 10 | wchar_t *dup_mb_to_wc_c(int codepage, int flags, const char *string, int len) 11 | { 12 | int mult; 13 | for (mult = 1;; mult++) { 14 | wchar_t *ret = snewn(mult * len + 2, wchar_t); 15 | int outlen; 16 | outlen = mb_to_wc(codepage, flags, string, len, ret, mult * len + 1); 17 | if (outlen < mult * len + 1) { 18 | ret[outlen] = L'\0'; 19 | return ret; 20 | } 21 | sfree(ret); 22 | } 23 | } 24 | 25 | wchar_t *dup_mb_to_wc(int codepage, int flags, const char *string) 26 | { 27 | return dup_mb_to_wc_c(codepage, flags, string, strlen(string)); 28 | } 29 | -------------------------------------------------------------------------------- /mkauto.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # This script makes the autoconf mechanism for the Unix port work. 3 | # It's separate from mkfiles.pl because it won't work (and isn't needed) 4 | # on a non-Unix system. 5 | 6 | # It's nice to be able to run this from inside the unix subdir as 7 | # well as from outside. 8 | test -f unix.h && cd .. 9 | 10 | # Run autoconf on our real configure.in. 11 | autoreconf -i && rm -rf autom4te.cache 12 | -------------------------------------------------------------------------------- /mksrcarc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | perl mkfiles.pl 6 | # These are text files. 7 | text=`{ find . -name CVS -prune -o \ 8 | -name .cvsignore -prune -o \ 9 | -name .svn -prune -o \ 10 | -name LATEST.VER -prune -o \ 11 | -name CHECKLST.txt -prune -o \ 12 | -name mksrcarc.sh -prune -o \ 13 | -name '*.dsp' -prune -o \ 14 | -name '*.dsw' -prune -o \ 15 | -type f -print | sed 's/^\.\///'; } | \ 16 | grep -ivE 'testdata/.*\.txt|MODULE|putty.iss|website.url' | grep -vF .ico | grep -vF .icns` 17 | # These are files which I'm _sure_ should be treated as text, but 18 | # which zip might complain about, so we direct its moans to 19 | # /dev/null! Apparently its heuristics are doubtful of UTF-8 text 20 | # files. 21 | bintext=testdata/*.txt 22 | # These are actual binary files which we don't want transforming. 23 | bin=`{ ls -1 windows/*.ico windows/putty.iss windows/website.url; \ 24 | find . -name '*.dsp' -print -o -name '*.dsw' -print; }` 25 | 26 | verbosely() { 27 | echo "$@" 28 | "$@" 29 | } 30 | 31 | verbosely zip -l putty-src.zip $text 32 | verbosely zip -l putty-src.zip $bintext 33 | verbosely zip putty-src.zip $bin 34 | -------------------------------------------------------------------------------- /mkunxarc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Build a Unix source distribution from the PuTTY CVS area. 4 | # 5 | # Expects the following arguments: 6 | # - the version number to write into configure.ac 7 | # - the suffix to put on the Unix source tarball 8 | # - the options to put on the 'make' command line for the docs 9 | 10 | autoconfver="$1" 11 | arcsuffix="$2" 12 | docver="$3" 13 | 14 | perl mkfiles.pl 15 | (cd doc && make -s ${docver:+"$docver"}) 16 | 17 | relver=`cat LATEST.VER` 18 | arcname="putty$arcsuffix" 19 | mkdir uxarc 20 | mkdir uxarc/$arcname 21 | find . -name uxarc -prune -o \ 22 | -name CVS -prune -o \ 23 | -name .svn -prune -o \ 24 | -name . -o \ 25 | -type d -exec mkdir uxarc/$arcname/{} \; 26 | find . -name uxarc -prune -o \ 27 | -name CVS -prune -o \ 28 | -name .cvsignore -prune -o \ 29 | -name .svn -prune -o \ 30 | -name configure.ac -prune -o \ 31 | -name '*.zip' -prune -o \ 32 | -name '*.tar.gz' -prune -o \ 33 | -type f -exec ln -s $PWD/{} uxarc/$arcname/{} \; 34 | sed "s/^AC_INIT(putty,.*/AC_INIT(putty, $autoconfver)/" configure.ac > uxarc/$arcname/configure.ac 35 | (cd uxarc/$arcname && sh mkauto.sh) 2>errors || { cat errors >&2; exit 1; } 36 | 37 | tar -C uxarc -chzof $arcname.tar.gz $arcname 38 | rm -rf uxarc 39 | -------------------------------------------------------------------------------- /nocproxy.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Routines to refuse to do cryptographic interaction with proxies 3 | * in PuTTY. This is a stub implementation of the same interfaces 4 | * provided by cproxy.c, for use in PuTTYtel. 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #define DEFINE_PLUG_METHOD_MACROS 12 | #include "putty.h" 13 | #include "network.h" 14 | #include "proxy.h" 15 | 16 | void proxy_socks5_offerencryptedauth(char *command, int *len) 17 | { 18 | /* For telnet, don't add any new encrypted authentication routines */ 19 | } 20 | 21 | int proxy_socks5_handlechap(Proxy_Socket p) 22 | { 23 | 24 | plug_closing(p->plug, 25 | "Proxy error: Trying to handle a SOCKS5 CHAP request" 26 | " in telnet-only build", 27 | PROXY_ERROR_GENERAL, 28 | 0); 29 | return 1; 30 | } 31 | 32 | int proxy_socks5_selectchap(Proxy_Socket p) 33 | { 34 | plug_closing(p->plug, 35 | "Proxy error: Trying to handle a SOCKS5 CHAP request" 36 | " in telnet-only build", 37 | PROXY_ERROR_GENERAL, 38 | 0); 39 | return 1; 40 | } 41 | -------------------------------------------------------------------------------- /nogss.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Stub definitions of the GSSAPI library list, for Unix pterm and 3 | * any other application that needs the symbols defined but has no 4 | * use for them. 5 | */ 6 | 7 | #include "putty.h" 8 | 9 | const int ngsslibs = 0; 10 | const char *const gsslibnames[1] = {"dummy"}; 11 | const struct keyvalwhere gsslibkeywords[1] = {{"dummy", 0, -1, -1}}; 12 | -------------------------------------------------------------------------------- /noprint.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Stub implementation of the printing interface for PuTTY, for the 3 | * benefit of non-printing terminal applications. 4 | */ 5 | 6 | #include 7 | #include 8 | #include "putty.h" 9 | 10 | struct printer_job_tag { 11 | int dummy; 12 | }; 13 | 14 | printer_job *printer_start_job(char *printer) 15 | { 16 | return NULL; 17 | } 18 | 19 | void printer_job_data(printer_job *pj, void *data, int len) 20 | { 21 | } 22 | 23 | void printer_finish_job(printer_job *pj) 24 | { 25 | } 26 | 27 | printer_enum *printer_start_enum(int *nprinters_ptr) 28 | { 29 | *nprinters_ptr = 0; 30 | return NULL; 31 | } 32 | char *printer_get_name(printer_enum *pe, int i) 33 | { 34 | return NULL; 35 | } 36 | void printer_finish_enum(printer_enum *pe) 37 | { 38 | } 39 | -------------------------------------------------------------------------------- /noshare.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Stub implementation of SSH connection-sharing IPC, for any 3 | * platform which can't support it at all. 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include "tree234.h" 11 | #include "putty.h" 12 | #include "ssh.h" 13 | #include "network.h" 14 | 15 | int platform_ssh_share(const char *name, 16 | Conf *conf, 17 | Plug downplug, 18 | Plug upplug, 19 | Socket *sock, 20 | char **logtext, 21 | char **ds_err, 22 | char **us_err, 23 | int can_upstream, 24 | int can_downstream) 25 | { 26 | return SHARE_NONE; 27 | } 28 | 29 | void platform_ssh_share_cleanup(const char *name) 30 | { 31 | } 32 | -------------------------------------------------------------------------------- /noterm.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Stubs of functions in terminal.c, for use in programs that don't 3 | * have a terminal. 4 | */ 5 | 6 | #include "putty.h" 7 | #include "terminal.h" 8 | 9 | void term_nopaste(Terminal *term) 10 | { 11 | } 12 | -------------------------------------------------------------------------------- /notiming.c: -------------------------------------------------------------------------------- 1 | /* 2 | * notiming.c: stub version of timing API. 3 | * 4 | * Used in any tool which needs a subsystem linked against the 5 | * timing API but doesn't want to actually provide timing. For 6 | * example, key generation tools need the random number generator, 7 | * but they don't want the hassle of calling noise_regular() at 8 | * regular intervals - and they don't _need_ it either, since they 9 | * have their own rigorous and different means of noise collection. 10 | */ 11 | 12 | #include "putty.h" 13 | 14 | unsigned long schedule_timer(int ticks, timer_fn_t fn, void *ctx) 15 | { 16 | return 0; 17 | } 18 | 19 | void expire_timer_context(void *ctx) 20 | { 21 | } 22 | -------------------------------------------------------------------------------- /pinger.c: -------------------------------------------------------------------------------- 1 | /* 2 | * pinger.c: centralised module that deals with sending TS_PING 3 | * keepalives, to avoid replicating this code in multiple backends. 4 | */ 5 | 6 | #include "putty.h" 7 | 8 | struct pinger_tag { 9 | int interval; 10 | int pending; 11 | unsigned long when_set, next; 12 | Backend *back; 13 | void *backhandle; 14 | }; 15 | 16 | static void pinger_schedule(Pinger pinger); 17 | 18 | static void pinger_timer(void *ctx, unsigned long now) 19 | { 20 | Pinger pinger = (Pinger)ctx; 21 | 22 | if (pinger->pending && now == pinger->next) { 23 | pinger->back->special(pinger->backhandle, TS_PING); 24 | pinger->pending = FALSE; 25 | pinger_schedule(pinger); 26 | } 27 | } 28 | 29 | static void pinger_schedule(Pinger pinger) 30 | { 31 | unsigned long next; 32 | 33 | if (!pinger->interval) { 34 | pinger->pending = FALSE; /* cancel any pending ping */ 35 | return; 36 | } 37 | 38 | next = schedule_timer(pinger->interval * TICKSPERSEC, pinger_timer, pinger); 39 | if (!pinger->pending || 40 | (next - pinger->when_set) < (pinger->next - pinger->when_set)) { 41 | pinger->next = next; 42 | pinger->when_set = timing_last_clock(); 43 | pinger->pending = TRUE; 44 | } 45 | } 46 | 47 | Pinger pinger_new(Conf *conf, Backend *back, void *backhandle) 48 | { 49 | Pinger pinger = snew(struct pinger_tag); 50 | 51 | pinger->interval = conf_get_int(conf, CONF_ping_interval); 52 | pinger->pending = FALSE; 53 | pinger->back = back; 54 | pinger->backhandle = backhandle; 55 | pinger_schedule(pinger); 56 | 57 | return pinger; 58 | } 59 | 60 | void pinger_reconfig(Pinger pinger, Conf *oldconf, Conf *newconf) 61 | { 62 | int newinterval = conf_get_int(newconf, CONF_ping_interval); 63 | if (conf_get_int(oldconf, CONF_ping_interval) != newinterval) { 64 | pinger->interval = newinterval; 65 | pinger_schedule(pinger); 66 | } 67 | } 68 | 69 | void pinger_free(Pinger pinger) 70 | { 71 | expire_timer_context(pinger); 72 | sfree(pinger); 73 | } 74 | -------------------------------------------------------------------------------- /pproxy.c: -------------------------------------------------------------------------------- 1 | /* 2 | * pproxy.c: dummy implementation of platform_new_connection(), to 3 | * be supplanted on any platform which has its own local proxy 4 | * method. 5 | */ 6 | 7 | #include "putty.h" 8 | #include "network.h" 9 | #include "proxy.h" 10 | 11 | Socket platform_new_connection(SockAddr addr, 12 | const char *hostname, 13 | int port, 14 | int privport, 15 | int oobinline, 16 | int nodelay, 17 | int keepalive, 18 | Plug plug, 19 | Conf *conf) 20 | { 21 | return NULL; 22 | } 23 | -------------------------------------------------------------------------------- /proxy.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Network proxy abstraction in PuTTY 3 | * 4 | * A proxy layer, if necessary, wedges itself between the 5 | * network code and the higher level backend. 6 | * 7 | * Supported proxies: HTTP CONNECT, generic telnet, SOCKS 4 & 5 8 | */ 9 | 10 | #ifndef PUTTY_PROXY_H 11 | #define PUTTY_PROXY_H 12 | 13 | #define PROXY_ERROR_GENERAL 8000 14 | #define PROXY_ERROR_UNEXPECTED 8001 15 | 16 | typedef struct Socket_proxy_tag *Proxy_Socket; 17 | 18 | struct Socket_proxy_tag { 19 | const struct socket_function_table *fn; 20 | /* the above variable absolutely *must* be the first in this structure */ 21 | 22 | const char *error; 23 | 24 | Socket sub_socket; 25 | Plug plug; 26 | SockAddr remote_addr; 27 | int remote_port; 28 | 29 | bufchain pending_output_data; 30 | bufchain pending_oob_output_data; 31 | int pending_flush; 32 | bufchain pending_input_data; 33 | int pending_eof; 34 | 35 | #define PROXY_STATE_NEW -1 36 | #define PROXY_STATE_ACTIVE 0 37 | 38 | int state; /* proxy states greater than 0 are implementation 39 | * dependent, but represent various stages/states 40 | * of the initialization/setup/negotiation with the 41 | * proxy server. 42 | */ 43 | int freeze; /* should we freeze the underlying socket when 44 | * we are done with the proxy negotiation? this 45 | * simply caches the value of sk_set_frozen calls. 46 | */ 47 | 48 | #define PROXY_CHANGE_NEW -1 49 | #define PROXY_CHANGE_CLOSING 0 50 | #define PROXY_CHANGE_SENT 1 51 | #define PROXY_CHANGE_RECEIVE 2 52 | #define PROXY_CHANGE_ACCEPTING 3 53 | 54 | /* something has changed (a call from the sub socket 55 | * layer into our Proxy Plug layer, or we were just 56 | * created, etc), so the proxy layer needs to handle 57 | * this change (the type of which is the second argument) 58 | * and further the proxy negotiation process. 59 | */ 60 | 61 | int (*negotiate)(Proxy_Socket /* this */, int /* change type */); 62 | 63 | /* current arguments of plug handlers 64 | * (for use by proxy's negotiate function) 65 | */ 66 | 67 | /* closing */ 68 | const char *closing_error_msg; 69 | int closing_error_code; 70 | int closing_calling_back; 71 | 72 | /* receive */ 73 | int receive_urgent; 74 | char *receive_data; 75 | int receive_len; 76 | 77 | /* sent */ 78 | int sent_bufsize; 79 | 80 | /* accepting */ 81 | accept_fn_t accepting_constructor; 82 | accept_ctx_t accepting_ctx; 83 | 84 | /* configuration, used to look up proxy settings */ 85 | Conf *conf; 86 | 87 | /* CHAP transient data */ 88 | int chap_num_attributes; 89 | int chap_num_attributes_processed; 90 | int chap_current_attribute; 91 | int chap_current_datalen; 92 | }; 93 | 94 | typedef struct Plug_proxy_tag *Proxy_Plug; 95 | 96 | struct Plug_proxy_tag { 97 | const struct plug_function_table *fn; 98 | /* the above variable absolutely *must* be the first in this structure */ 99 | 100 | Proxy_Socket proxy_socket; 101 | }; 102 | 103 | extern void proxy_activate(Proxy_Socket); 104 | 105 | extern int proxy_http_negotiate(Proxy_Socket, int); 106 | extern int proxy_telnet_negotiate(Proxy_Socket, int); 107 | extern int proxy_socks4_negotiate(Proxy_Socket, int); 108 | extern int proxy_socks5_negotiate(Proxy_Socket, int); 109 | 110 | /* 111 | * This may be reused by local-command proxies on individual 112 | * platforms. 113 | */ 114 | char *format_telnet_command(SockAddr addr, int port, Conf *conf); 115 | 116 | /* 117 | * These are implemented in cproxy.c or nocproxy.c, depending on 118 | * whether encrypted proxy authentication is available. 119 | */ 120 | extern void proxy_socks5_offerencryptedauth(char *command, int *len); 121 | extern int proxy_socks5_handlechap(Proxy_Socket p); 122 | extern int proxy_socks5_selectchap(Proxy_Socket p); 123 | 124 | #endif 125 | -------------------------------------------------------------------------------- /puttymem.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PuTTY memory-handling header. 3 | */ 4 | 5 | #ifndef PUTTY_PUTTYMEM_H 6 | #define PUTTY_PUTTYMEM_H 7 | 8 | #include /* for size_t */ 9 | #include /* for memcpy() */ 10 | 11 | /* #define MALLOC_LOG do this if you suspect putty of leaking memory */ 12 | #ifdef MALLOC_LOG 13 | #define smalloc(z) (mlog(__FILE__, __LINE__), safemalloc(z, 1)) 14 | #define snmalloc(z, s) (mlog(__FILE__, __LINE__), safemalloc(z, s)) 15 | #define srealloc(y, z) (mlog(__FILE__, __LINE__), saferealloc(y, z, 1)) 16 | #define snrealloc(y, z, s) (mlog(__FILE__, __LINE__), saferealloc(y, z, s)) 17 | #define sfree(z) (mlog(__FILE__, __LINE__), safefree(z)) 18 | void mlog(char *, int); 19 | #else 20 | #define smalloc(z) safemalloc(z, 1) 21 | #define snmalloc safemalloc 22 | #define srealloc(y, z) saferealloc(y, z, 1) 23 | #define snrealloc saferealloc 24 | #define sfree safefree 25 | #endif 26 | 27 | void *safemalloc(size_t, size_t); 28 | void *saferealloc(void *, size_t, size_t); 29 | void safefree(void *); 30 | 31 | /* 32 | * Direct use of smalloc within the code should be avoided where 33 | * possible, in favour of these type-casting macros which ensure 34 | * you don't mistakenly allocate enough space for one sort of 35 | * structure and assign it to a different sort of pointer. 36 | * 37 | * The nasty trick in sresize with sizeof arranges for the compiler, 38 | * in passing, to type-check the expression ((type *)0 == (ptr)), i.e. 39 | * to type-check that the input pointer is a pointer to the correct 40 | * type. The construction sizeof(stuff) ? (b) : (b) looks like a 41 | * violation of the first principle of safe macros, but in fact it's 42 | * OK - although it _expands_ the macro parameter more than once, it 43 | * only _evaluates_ it once, so it's still side-effect safe. 44 | */ 45 | #define snew(type) ((type *)snmalloc(1, sizeof(type))) 46 | #define snewn(n, type) ((type *)snmalloc((n), sizeof(type))) 47 | #define sresize(ptr, n, type) \ 48 | ((type *)snrealloc( \ 49 | sizeof((type *)0 == (ptr)) ? (ptr) : (ptr), (n), sizeof(type))) 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /puttyps.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Find the platform-specific header for this platform. 3 | */ 4 | 5 | #ifndef PUTTY_PUTTYPS_H 6 | #define PUTTY_PUTTYPS_H 7 | 8 | #ifdef _WINDOWS 9 | 10 | #include "winstuff.h" 11 | 12 | #else 13 | 14 | #include "unix.h" 15 | 16 | #endif 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Developer Studio generated include file. 3 | // Used by win_res.rc 4 | // 5 | 6 | // Next default values for new objects 7 | // 8 | #ifdef APSTUDIO_INVOKED 9 | #ifndef APSTUDIO_READONLY_SYMBOLS 10 | #define _APS_NEXT_RESOURCE_VALUE 101 11 | #define _APS_NEXT_COMMAND_VALUE 40001 12 | #define _APS_NEXT_CONTROL_VALUE 1000 13 | #define _APS_NEXT_SYMED_VALUE 101 14 | #endif 15 | #endif 16 | -------------------------------------------------------------------------------- /sign.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Generate GPG signatures on a PuTTY release/snapshot directory as 4 | # delivered by Buildscr. 5 | 6 | # Usage: sh sign.sh [-r] 7 | # e.g. sh sign.sh putty (probably in the build.out directory) 8 | # or sh sign.sh -r 0.60 (-r means use the release keys) 9 | 10 | set -e 11 | 12 | keyname=EEF20295D15F7E8A 13 | preliminary=false 14 | 15 | while :; do 16 | case "$1" in 17 | -r) 18 | shift 19 | keyname=9DFE2648B43434E4 20 | ;; 21 | -p) 22 | shift 23 | preliminary=true 24 | ;; 25 | -*) 26 | echo "Unknown option '$1'" >&2 27 | exit 1 28 | ;; 29 | *) 30 | break 31 | ;; 32 | esac 33 | done 34 | 35 | sign() { 36 | # Check for the prior existence of the signature, so we can 37 | # re-run this script if it encounters an error part way 38 | # through. 39 | echo "----- Signing $2 with key '$keyname'" 40 | test -f "$3" || \ 41 | gpg --load-extension=idea "$1" -u "$keyname" -o "$3" "$2" 42 | } 43 | 44 | cd "$1" 45 | echo "===== Signing with key '$keyname'" 46 | if $preliminary; then 47 | sign --clearsign sha512sums ../sha512sums-preliminary.gpg 48 | else 49 | for i in putty*src.zip putty*.tar.gz \ 50 | w32/*.exe w32/*.zip w32/*.msi \ 51 | w64/*.exe w64/*.zip w64/*.msi \ 52 | w32old/*.exe w32old/*.zip; do 53 | sign --detach-sign "$i" "$i.gpg" 54 | done 55 | for i in md5sums sha1sums sha256sums sha512sums; do 56 | sign --clearsign "$i" "$i.gpg" 57 | done 58 | fi 59 | -------------------------------------------------------------------------------- /ssharcf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Arcfour (RC4) implementation for PuTTY. 3 | * 4 | * Coded from Schneier. 5 | */ 6 | 7 | #include 8 | #include "ssh.h" 9 | 10 | typedef struct { 11 | unsigned char i, j, s[256]; 12 | } ArcfourContext; 13 | 14 | static void arcfour_block(void *handle, unsigned char *blk, int len) 15 | { 16 | ArcfourContext *ctx = (ArcfourContext *)handle; 17 | unsigned k; 18 | unsigned char tmp, i, j, *s; 19 | 20 | s = ctx->s; 21 | i = ctx->i; 22 | j = ctx->j; 23 | for (k = 0; (int)k < len; k++) { 24 | i = (i + 1) & 0xff; 25 | j = (j + s[i]) & 0xff; 26 | tmp = s[i]; 27 | s[i] = s[j]; 28 | s[j] = tmp; 29 | blk[k] ^= s[(s[i] + s[j]) & 0xff]; 30 | } 31 | ctx->i = i; 32 | ctx->j = j; 33 | } 34 | 35 | static void arcfour_setkey(ArcfourContext *ctx, 36 | unsigned char const *key, 37 | unsigned keybytes) 38 | { 39 | unsigned char tmp, k[256], *s; 40 | unsigned i, j; 41 | 42 | s = ctx->s; 43 | assert(keybytes <= 256); 44 | ctx->i = ctx->j = 0; 45 | for (i = 0; i < 256; i++) { 46 | s[i] = i; 47 | k[i] = key[i % keybytes]; 48 | } 49 | j = 0; 50 | for (i = 0; i < 256; i++) { 51 | j = (j + s[i] + k[i]) & 0xff; 52 | tmp = s[i]; 53 | s[i] = s[j]; 54 | s[j] = tmp; 55 | } 56 | } 57 | 58 | /* -- Interface with PuTTY -- */ 59 | 60 | /* 61 | * We don't implement Arcfour in SSH-1 because it's utterly insecure in 62 | * several ways. See CERT Vulnerability Notes VU#25309, VU#665372, 63 | * and VU#565052. 64 | * 65 | * We don't implement the "arcfour" algorithm in SSH-2 because it doesn't 66 | * stir the cipher state before emitting keystream, and hence is likely 67 | * to leak data about the key. 68 | */ 69 | 70 | static void *arcfour_make_context(void) 71 | { 72 | return snew(ArcfourContext); 73 | } 74 | 75 | static void arcfour_free_context(void *handle) 76 | { 77 | sfree(handle); 78 | } 79 | 80 | static void arcfour_stir(ArcfourContext *ctx) 81 | { 82 | unsigned char *junk = snewn(1536, unsigned char); 83 | memset(junk, 0, 1536); 84 | arcfour_block(ctx, junk, 1536); 85 | smemclr(junk, 1536); 86 | sfree(junk); 87 | } 88 | 89 | static void arcfour128_key(void *handle, unsigned char *key) 90 | { 91 | ArcfourContext *ctx = (ArcfourContext *)handle; 92 | arcfour_setkey(ctx, key, 16); 93 | arcfour_stir(ctx); 94 | } 95 | 96 | static void arcfour256_key(void *handle, unsigned char *key) 97 | { 98 | ArcfourContext *ctx = (ArcfourContext *)handle; 99 | arcfour_setkey(ctx, key, 32); 100 | arcfour_stir(ctx); 101 | } 102 | 103 | static void arcfour_iv(void *handle, unsigned char *key) 104 | { 105 | } 106 | 107 | const struct ssh2_cipher ssh_arcfour128_ssh2 = {arcfour_make_context, 108 | arcfour_free_context, 109 | arcfour_iv, 110 | arcfour128_key, 111 | arcfour_block, 112 | arcfour_block, 113 | NULL, 114 | NULL, 115 | "arcfour128", 116 | 1, 117 | 128, 118 | 16, 119 | 0, 120 | "Arcfour-128", 121 | NULL}; 122 | 123 | const struct ssh2_cipher ssh_arcfour256_ssh2 = {arcfour_make_context, 124 | arcfour_free_context, 125 | arcfour_iv, 126 | arcfour256_key, 127 | arcfour_block, 128 | arcfour_block, 129 | NULL, 130 | NULL, 131 | "arcfour256", 132 | 1, 133 | 256, 134 | 32, 135 | 0, 136 | "Arcfour-256", 137 | NULL}; 138 | 139 | static const struct ssh2_cipher *const arcfour_list[] = { 140 | &ssh_arcfour256_ssh2, 141 | &ssh_arcfour128_ssh2, 142 | }; 143 | 144 | const struct ssh2_ciphers ssh2_arcfour = { 145 | sizeof(arcfour_list) / sizeof(*arcfour_list), arcfour_list}; 146 | -------------------------------------------------------------------------------- /sshbcrypt.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 'bcrypt' password hash function, for PuTTY's import/export of 3 | * OpenSSH encrypted private key files. 4 | * 5 | * This is not really the same as the original bcrypt; OpenSSH has 6 | * modified it in various ways, and of course we have to do the same. 7 | */ 8 | 9 | #include 10 | #include 11 | #include "ssh.h" 12 | #include "sshblowf.h" 13 | 14 | BlowfishContext *bcrypt_setup(const unsigned char *key, 15 | int keybytes, 16 | const unsigned char *salt, 17 | int saltbytes) 18 | { 19 | int i; 20 | BlowfishContext *ctx; 21 | 22 | ctx = blowfish_make_context(); 23 | blowfish_initkey(ctx); 24 | blowfish_expandkey(ctx, key, keybytes, salt, saltbytes); 25 | 26 | /* Original bcrypt replaces this fixed loop count with the 27 | * variable cost. OpenSSH instead iterates the whole thing more 28 | * than once if it wants extra rounds. */ 29 | for (i = 0; i < 64; i++) { 30 | blowfish_expandkey(ctx, salt, saltbytes, NULL, 0); 31 | blowfish_expandkey(ctx, key, keybytes, NULL, 0); 32 | } 33 | 34 | return ctx; 35 | } 36 | 37 | void bcrypt_hash(const unsigned char *key, 38 | int keybytes, 39 | const unsigned char *salt, 40 | int saltbytes, 41 | unsigned char output[32]) 42 | { 43 | BlowfishContext *ctx; 44 | int i; 45 | 46 | ctx = bcrypt_setup(key, keybytes, salt, saltbytes); 47 | /* This was quite a nice starting string until it ran into 48 | * little-endian Blowfish :-/ */ 49 | memcpy(output, "cyxOmorhcitawolBhsiftawSanyDetim", 32); 50 | for (i = 0; i < 64; i++) { 51 | blowfish_lsb_encrypt_ecb(output, 32, ctx); 52 | } 53 | blowfish_free_context(ctx); 54 | } 55 | 56 | void bcrypt_genblock(int counter, 57 | const unsigned char hashed_passphrase[64], 58 | const unsigned char *salt, 59 | int saltbytes, 60 | unsigned char output[32]) 61 | { 62 | SHA512_State shastate; 63 | unsigned char hashed_salt[64]; 64 | unsigned char countbuf[4]; 65 | 66 | /* Hash the input salt with the counter value optionally suffixed 67 | * to get our real 32-byte salt */ 68 | SHA512_Init(&shastate); 69 | SHA512_Bytes(&shastate, salt, saltbytes); 70 | if (counter) { 71 | PUT_32BIT_MSB_FIRST(countbuf, counter); 72 | SHA512_Bytes(&shastate, countbuf, 4); 73 | } 74 | SHA512_Final(&shastate, hashed_salt); 75 | 76 | bcrypt_hash(hashed_passphrase, 64, hashed_salt, 64, output); 77 | 78 | smemclr(&shastate, sizeof(shastate)); 79 | smemclr(&hashed_salt, sizeof(hashed_salt)); 80 | } 81 | 82 | void openssh_bcrypt(const char *passphrase, 83 | const unsigned char *salt, 84 | int saltbytes, 85 | int rounds, 86 | unsigned char *out, 87 | int outbytes) 88 | { 89 | unsigned char hashed_passphrase[64]; 90 | unsigned char block[32], outblock[32]; 91 | const unsigned char *thissalt; 92 | int thissaltbytes; 93 | int modulus, residue, i, j, round; 94 | 95 | /* Hash the passphrase to get the bcrypt key material */ 96 | SHA512_Simple(passphrase, strlen(passphrase), hashed_passphrase); 97 | 98 | /* We output key bytes in a scattered fashion to meld all output 99 | * key blocks into all parts of the output. To do this, we pick a 100 | * modulus, and we output the key bytes to indices of out[] in the 101 | * following order: first the indices that are multiples of the 102 | * modulus, then the ones congruent to 1 mod modulus, etc. Each of 103 | * those passes consumes exactly one block output from 104 | * bcrypt_genblock, so we must pick a modulus large enough that at 105 | * most 32 bytes are used in the pass. */ 106 | modulus = (outbytes + 31) / 32; 107 | 108 | for (residue = 0; residue < modulus; residue++) { 109 | /* Our output block of data is the XOR of all blocks generated 110 | * by bcrypt in the following loop */ 111 | memset(outblock, 0, sizeof(outblock)); 112 | 113 | thissalt = salt; 114 | thissaltbytes = saltbytes; 115 | for (round = 0; round < rounds; round++) { 116 | bcrypt_genblock(round == 0 ? residue + 1 : 0, 117 | hashed_passphrase, 118 | thissalt, 119 | thissaltbytes, 120 | block); 121 | /* Each subsequent bcrypt call reuses the previous one's 122 | * output as its salt */ 123 | thissalt = block; 124 | thissaltbytes = 32; 125 | 126 | for (i = 0; i < 32; i++) 127 | outblock[i] ^= block[i]; 128 | } 129 | 130 | for (i = residue, j = 0; i < outbytes; i += modulus, j++) 131 | out[i] = outblock[j]; 132 | } 133 | smemclr(&hashed_passphrase, sizeof(hashed_passphrase)); 134 | } 135 | -------------------------------------------------------------------------------- /sshblowf.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Header file shared between sshblowf.c and sshbcrypt.c. Exposes the 3 | * internal Blowfish routines needed by bcrypt. 4 | */ 5 | 6 | typedef struct BlowfishContext BlowfishContext; 7 | 8 | void *blowfish_make_context(void); 9 | void blowfish_free_context(void *handle); 10 | void blowfish_initkey(BlowfishContext *ctx); 11 | void blowfish_expandkey(BlowfishContext *ctx, 12 | const unsigned char *key, 13 | short keybytes, 14 | const unsigned char *salt, 15 | short saltbytes); 16 | void blowfish_lsb_encrypt_ecb(unsigned char *blk, 17 | int len, 18 | BlowfishContext *ctx); 19 | -------------------------------------------------------------------------------- /sshecdsag.c: -------------------------------------------------------------------------------- 1 | /* 2 | * EC key generation. 3 | */ 4 | 5 | #include "ssh.h" 6 | 7 | /* Forward reference from sshecc.c */ 8 | struct ec_point *ecp_mul(const struct ec_point *a, const Bignum b); 9 | 10 | int ec_generate(struct ec_key *key, int bits, progfn_t pfn, void *pfnparam) 11 | { 12 | struct ec_point *publicKey; 13 | 14 | if (!ec_nist_alg_and_curve_by_bits( 15 | bits, &key->publicKey.curve, &key->signalg)) 16 | return 0; 17 | 18 | key->privateKey = bignum_random_in_range(One, key->publicKey.curve->w.n); 19 | if (!key->privateKey) 20 | return 0; 21 | 22 | publicKey = ec_public(key->privateKey, key->publicKey.curve); 23 | if (!publicKey) { 24 | freebn(key->privateKey); 25 | key->privateKey = NULL; 26 | return 0; 27 | } 28 | 29 | key->publicKey.x = publicKey->x; 30 | key->publicKey.y = publicKey->y; 31 | key->publicKey.z = NULL; 32 | sfree(publicKey); 33 | 34 | return 1; 35 | } 36 | 37 | int ec_edgenerate(struct ec_key *key, int bits, progfn_t pfn, void *pfnparam) 38 | { 39 | struct ec_point *publicKey; 40 | 41 | if (!ec_ed_alg_and_curve_by_bits(bits, &key->publicKey.curve, &key->signalg)) 42 | return 0; 43 | 44 | { 45 | /* EdDSA secret keys are just 32 bytes of hash preimage; the 46 | * 64-byte SHA-512 hash of that key will be used when signing, 47 | * but the form of the key stored on disk is the preimage 48 | * only. */ 49 | Bignum privMax = bn_power_2(bits); 50 | if (!privMax) 51 | return 0; 52 | key->privateKey = bignum_random_in_range(Zero, privMax); 53 | freebn(privMax); 54 | if (!key->privateKey) 55 | return 0; 56 | } 57 | 58 | publicKey = ec_public(key->privateKey, key->publicKey.curve); 59 | if (!publicKey) { 60 | freebn(key->privateKey); 61 | key->privateKey = NULL; 62 | return 0; 63 | } 64 | 65 | key->publicKey.x = publicKey->x; 66 | key->publicKey.y = publicKey->y; 67 | key->publicKey.z = NULL; 68 | sfree(publicKey); 69 | 70 | return 1; 71 | } 72 | -------------------------------------------------------------------------------- /sshgssc.h: -------------------------------------------------------------------------------- 1 | #ifndef PUTTY_SSHGSSC_H 2 | #define PUTTY_SSHGSSC_H 3 | #include "putty.h" 4 | #ifndef NO_GSSAPI 5 | 6 | #include "pgssapi.h" 7 | #include "sshgss.h" 8 | 9 | typedef struct gssapi_ssh_gss_ctx { 10 | OM_uint32 maj_stat; 11 | OM_uint32 min_stat; 12 | gss_ctx_id_t ctx; 13 | } gssapi_ssh_gss_ctx; 14 | 15 | void ssh_gssapi_bind_fns(struct ssh_gss_library *lib); 16 | 17 | #else 18 | 19 | int ssh_gssapi_init(void); 20 | 21 | #endif /*NO_GSSAPI*/ 22 | 23 | #endif /*PUTTY_SSHGSSC_H*/ 24 | -------------------------------------------------------------------------------- /sshnogss.c: -------------------------------------------------------------------------------- 1 | #include "putty.h" 2 | #ifndef NO_GSSAPI 3 | 4 | /* For platforms not supporting GSSAPI */ 5 | 6 | struct ssh_gss_liblist *ssh_gss_setup(Conf *conf) 7 | { 8 | struct ssh_gss_liblist *list = snew(struct ssh_gss_liblist *); 9 | list->libraries = NULL; 10 | list->nlibraries = 0; 11 | return list; 12 | } 13 | 14 | void ssh_gss_cleanup(struct ssh_gss_liblist *list) 15 | { 16 | sfree(list); 17 | } 18 | 19 | #endif /* NO_GSSAPI */ 20 | -------------------------------------------------------------------------------- /sshrsag.c: -------------------------------------------------------------------------------- 1 | /* 2 | * RSA key generation. 3 | */ 4 | 5 | #include 6 | 7 | #include "ssh.h" 8 | 9 | #define RSA_EXPONENT 37 /* we like this prime */ 10 | 11 | int rsa_generate(struct RSAKey *key, int bits, progfn_t pfn, void *pfnparam) 12 | { 13 | Bignum pm1, qm1, phi_n; 14 | unsigned pfirst, qfirst; 15 | 16 | /* 17 | * Set up the phase limits for the progress report. We do this 18 | * by passing minus the phase number. 19 | * 20 | * For prime generation: our initial filter finds things 21 | * coprime to everything below 2^16. Computing the product of 22 | * (p-1)/p for all prime p below 2^16 gives about 20.33; so 23 | * among B-bit integers, one in every 20.33 will get through 24 | * the initial filter to be a candidate prime. 25 | * 26 | * Meanwhile, we are searching for primes in the region of 2^B; 27 | * since pi(x) ~ x/log(x), when x is in the region of 2^B, the 28 | * prime density will be d/dx pi(x) ~ 1/log(B), i.e. about 29 | * 1/0.6931B. So the chance of any given candidate being prime 30 | * is 20.33/0.6931B, which is roughly 29.34 divided by B. 31 | * 32 | * So now we have this probability P, we're looking at an 33 | * exponential distribution with parameter P: we will manage in 34 | * one attempt with probability P, in two with probability 35 | * P(1-P), in three with probability P(1-P)^2, etc. The 36 | * probability that we have still not managed to find a prime 37 | * after N attempts is (1-P)^N. 38 | * 39 | * We therefore inform the progress indicator of the number B 40 | * (29.34/B), so that it knows how much to increment by each 41 | * time. We do this in 16-bit fixed point, so 29.34 becomes 42 | * 0x1D.57C4. 43 | */ 44 | pfn(pfnparam, PROGFN_PHASE_EXTENT, 1, 0x10000); 45 | pfn(pfnparam, PROGFN_EXP_PHASE, 1, -0x1D57C4 / (bits / 2)); 46 | pfn(pfnparam, PROGFN_PHASE_EXTENT, 2, 0x10000); 47 | pfn(pfnparam, PROGFN_EXP_PHASE, 2, -0x1D57C4 / (bits - bits / 2)); 48 | pfn(pfnparam, PROGFN_PHASE_EXTENT, 3, 0x4000); 49 | pfn(pfnparam, PROGFN_LIN_PHASE, 3, 5); 50 | pfn(pfnparam, PROGFN_READY, 0, 0); 51 | 52 | /* 53 | * We don't generate e; we just use a standard one always. 54 | */ 55 | key->exponent = bignum_from_long(RSA_EXPONENT); 56 | 57 | /* 58 | * Generate p and q: primes with combined length `bits', not 59 | * congruent to 1 modulo e. (Strictly speaking, we wanted (p-1) 60 | * and e to be coprime, and (q-1) and e to be coprime, but in 61 | * general that's slightly more fiddly to arrange. By choosing 62 | * a prime e, we can simplify the criterion.) 63 | */ 64 | invent_firstbits(&pfirst, &qfirst); 65 | key->p = primegen(bits / 2, RSA_EXPONENT, 1, NULL, 1, pfn, pfnparam, pfirst); 66 | key->q = primegen( 67 | bits - bits / 2, RSA_EXPONENT, 1, NULL, 2, pfn, pfnparam, qfirst); 68 | 69 | /* 70 | * Ensure p > q, by swapping them if not. 71 | */ 72 | if (bignum_cmp(key->p, key->q) < 0) { 73 | Bignum t = key->p; 74 | key->p = key->q; 75 | key->q = t; 76 | } 77 | 78 | /* 79 | * Now we have p, q and e. All we need to do now is work out 80 | * the other helpful quantities: n=pq, d=e^-1 mod (p-1)(q-1), 81 | * and (q^-1 mod p). 82 | */ 83 | pfn(pfnparam, PROGFN_PROGRESS, 3, 1); 84 | key->modulus = bigmul(key->p, key->q); 85 | pfn(pfnparam, PROGFN_PROGRESS, 3, 2); 86 | pm1 = copybn(key->p); 87 | decbn(pm1); 88 | qm1 = copybn(key->q); 89 | decbn(qm1); 90 | phi_n = bigmul(pm1, qm1); 91 | pfn(pfnparam, PROGFN_PROGRESS, 3, 3); 92 | freebn(pm1); 93 | freebn(qm1); 94 | key->private_exponent = modinv(key->exponent, phi_n); 95 | assert(key->private_exponent); 96 | pfn(pfnparam, PROGFN_PROGRESS, 3, 4); 97 | key->iqmp = modinv(key->q, key->p); 98 | assert(key->iqmp); 99 | pfn(pfnparam, PROGFN_PROGRESS, 3, 5); 100 | 101 | /* 102 | * Clean up temporary numbers. 103 | */ 104 | freebn(phi_n); 105 | 106 | return 1; 107 | } 108 | -------------------------------------------------------------------------------- /storage.h: -------------------------------------------------------------------------------- 1 | /* 2 | * storage.h: interface defining functions for storage and recovery 3 | * of PuTTY's persistent data. 4 | */ 5 | 6 | #ifndef PUTTY_STORAGE_H 7 | #define PUTTY_STORAGE_H 8 | 9 | /* ---------------------------------------------------------------------- 10 | * Functions to save and restore PuTTY sessions. Note that this is 11 | * only the low-level code to do the reading and writing. The 12 | * higher-level code that translates an internal Conf structure into 13 | * a set of (key,value) pairs in their external storage format is 14 | * elsewhere, since it doesn't (mostly) change between platforms. 15 | */ 16 | 17 | /* 18 | * Write a saved session. The caller is expected to call 19 | * open_setting_w() to get a `void *' handle, then pass that to a 20 | * number of calls to write_setting_s() and write_setting_i(), and 21 | * then close it using close_settings_w(). At the end of this call 22 | * sequence the settings should have been written to the PuTTY 23 | * persistent storage area. 24 | * 25 | * A given key will be written at most once while saving a session. 26 | * Keys may be up to 255 characters long. String values have no length 27 | * limit. 28 | * 29 | * Any returned error message must be freed after use. 30 | */ 31 | void *open_settings_w(const char *sessionname, char **errmsg); 32 | void write_setting_s(void *handle, const char *key, const char *value); 33 | void write_setting_i(void *handle, const char *key, int value); 34 | void write_setting_filename(void *handle, const char *key, Filename *value); 35 | void write_setting_fontspec(void *handle, const char *key, FontSpec *font); 36 | void close_settings_w(void *handle); 37 | 38 | /* 39 | * Read a saved session. The caller is expected to call 40 | * open_setting_r() to get a `void *' handle, then pass that to a 41 | * number of calls to read_setting_s() and read_setting_i(), and 42 | * then close it using close_settings_r(). 43 | * 44 | * read_setting_s() returns a dynamically allocated string which the 45 | * caller must free. read_setting_filename() and 46 | * read_setting_fontspec() likewise return dynamically allocated 47 | * structures. 48 | * 49 | * If a particular string setting is not present in the session, 50 | * read_setting_s() can return NULL, in which case the caller 51 | * should invent a sensible default. If an integer setting is not 52 | * present, read_setting_i() returns its provided default. 53 | */ 54 | void *open_settings_r(const char *sessionname); 55 | char *read_setting_s(void *handle, const char *key); 56 | int read_setting_i(void *handle, const char *key, int defvalue); 57 | Filename *read_setting_filename(void *handle, const char *key); 58 | FontSpec *read_setting_fontspec(void *handle, const char *key); 59 | void close_settings_r(void *handle); 60 | 61 | /* 62 | * Delete a whole saved session. 63 | */ 64 | void del_settings(const char *sessionname); 65 | 66 | /* 67 | * Enumerate all saved sessions. 68 | */ 69 | void *enum_settings_start(void); 70 | char *enum_settings_next(void *handle, char *buffer, int buflen); 71 | void enum_settings_finish(void *handle); 72 | 73 | /* ---------------------------------------------------------------------- 74 | * Functions to access PuTTY's host key database. 75 | */ 76 | 77 | /* 78 | * See if a host key matches the database entry. Return values can 79 | * be 0 (entry matches database), 1 (entry is absent in database), 80 | * or 2 (entry exists in database and is different). 81 | */ 82 | int verify_host_key(const char *hostname, 83 | int port, 84 | const char *keytype, 85 | const char *key); 86 | 87 | /* 88 | * Write a host key into the database, overwriting any previous 89 | * entry that might have been there. 90 | */ 91 | void store_host_key(const char *hostname, 92 | int port, 93 | const char *keytype, 94 | const char *key); 95 | 96 | /* ---------------------------------------------------------------------- 97 | * Functions to access PuTTY's random number seed file. 98 | */ 99 | 100 | typedef void (*noise_consumer_t)(void *data, int len); 101 | 102 | /* 103 | * Read PuTTY's random seed file and pass its contents to a noise 104 | * consumer function. 105 | */ 106 | void read_random_seed(noise_consumer_t consumer); 107 | 108 | /* 109 | * Write PuTTY's random seed file from a given chunk of noise. 110 | */ 111 | void write_random_seed(void *data, int len); 112 | 113 | /* ---------------------------------------------------------------------- 114 | * Cleanup function: remove all of PuTTY's persistent state. 115 | */ 116 | void cleanup_all(void); 117 | 118 | #endif 119 | -------------------------------------------------------------------------------- /testdata/display.txt: -------------------------------------------------------------------------------- 1 | Test of all features involved in do_text() 2 | ========================================== 3 | 4 | Reverse video + red on yellow:  bing!  5 | Yellow on red should look the same:  bong!  6 | 7 | Basic attrs, combining chars, both widths: Bold blink underline [Λ̊][チ][text] 8 | Wide char should be off by 1 narrow char: Bold blink underline [Λ̊][チ][text] 9 | 10 | Double width, double height. Should be red top, magenta bottom, blue DW only: 11 | #3Bold blink underline [Λ̊][チ][text] 12 | #4Bold blink underline [Λ̊][チ][text] 13 | #6Bold blink underline [Λ̊][チ][text] 14 | 15 | -------------------------------------------------------------------------------- /testdata/lattrs.txt: -------------------------------------------------------------------------------- 1 | Test of line attributes: 2 | 3 | #3Double-height top 4 | #4Double-height bottom 5 | #5Normal text (#5) 6 | #6Double-width only 7 | -------------------------------------------------------------------------------- /testdata/scocols.txt: -------------------------------------------------------------------------------- 1 | Test of (destructive) SCO colour rendering. 2 | SCO fg: [=0F0[=7F [=1F1[=7F [=2F2[=7F [=3F3[=7F [=4F4[=7F [=5F5[=7F [=6F6[=7F [=7F7[=7F [=8F8[=7F [=9F9[=7F [=10F10[=7F [=11F11[=7F [=12F12[=7F [=13F13[=7F [=14F14[=7F [=15F15[=7F 3 | SCO bg: [=0G0[=0G [=1G1[=0G [=2G2[=0G [=3G3[=0G [=4G4[=0G [=5G5[=0G [=6G6[=0G [=7G7[=0G [=8G8[=0G [=9G9[=0G [=10G10[=0G [=11G11[=0G [=12G12[=0G [=13G13[=0G [=14G14[=0G [=15G15[=0G 4 | -------------------------------------------------------------------------------- /testdata/utf8.txt: -------------------------------------------------------------------------------- 1 | Test of UTF-8 output in a terminal emulator 2 | ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ 3 | 4 | Some basic Unicode: 5 | ∮ E⋅da = Q, n → ∞, ∑ f(i) = ∏ g(i), ∀x∈ℝ: ⌈x⌉ = −⌊−x⌋, α ∧ ¬β = ¬(¬α ∨ β), 6 | ℕ ⊆ ℕ₀ ⊂ ℤ ⊂ ℚ ⊂ ℝ ⊂ ℂ, ⊥ < a ≠ b ≡ c ≤ d ≪ ⊤ ⇒ (A ⇔ B), 7 | 8 | Combining characters: 9 | STARGΛ̊TE SG-1, a = v̇ = r̈, a⃑ ⊥ b⃑ 10 | [----------------------------|------------------------] 11 | ๏ แผ่นดินฮั่นเสื่อมโทรมแสนสังเวช พระปกเกศกองบู๊กู้ขึ้นใหม่ 12 | สิบสองกษัตริย์ก่อนหน้าแลถัดไป สององค์ไซร้โง่เขลาเบาปัญญา 13 | 14 | Wide characters with difficult wrapping: 15 | Here we go then: コンニチハ コンニチハ コンニチハ コンニチハ コンニチハ コンニチハ コンニチハ コンニチハ コンニチハ コンニチハ コンニチハ コンニチハ コンニチハ コンニチハ コンニチハ 16 | 17 | Arabic and bidirectional text: 18 | (من مجمع الزوائد ومنبع الفوائد للهيثمي ، ج 1 ، ص 74-84) 19 | عن جرير رضي الله عنه قال قال رسول الله صلى الله عليه 20 | وسلم: بني الاسلام على خمس شهادة ان لا اله الا الله واقام 21 | Mixed LTR and RTL text: جرير رضي back to LTR. 22 | 23 | East Asian Ambiguous characters: ¼½¾¼½¾¼½¾¼½¾¼½¾¼½¾¼½¾¼½¾¼½¾¼½¾ 24 | -------------------------------------------------------------------------------- /testdata/vt100.txt: -------------------------------------------------------------------------------- 1 | VT100 line drawing characters, actually using the VT100 escapes 2 | (B)0ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo 3 | 4 | lqqqqqqqqqqpoopqrssrqqqqqqqqqqwqqqqqqqqqqpoopqrssrqqqqqqqqqqk 5 | x x x 6 | x ooh, swirly! x top right corner x 7 | x x x 8 | tqqqqqqqqqqpoopqrssrqqqqqqqqqqnqqqqqqqqqqpoopqrssrqqqqqqqqqqu 9 | x x x 10 | x stuff down here x is quite inane x 11 | x x x 12 | mqqqqqqqqqqpoopqrssrqqqqqqqqqqvqqqqqqqqqqpoopqrssrqqqqqqqqqqj 13 | 14 | (This won't do the right thing in PuTTY's default UTF-8 translation; 15 | you'll just see lqqqk letters. It should work with a character set 16 | like ISO8859-1.) 17 | -------------------------------------------------------------------------------- /time.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Portable implementation of ltime() for any ISO-C platform where 3 | * time_t behaves. (In practice, we've found that platforms such as 4 | * Windows and Mac have needed their own specialised implementations.) 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | struct tm ltime(void) 11 | { 12 | time_t t; 13 | time(&t); 14 | assert(t != ((time_t)-1)); 15 | return *localtime(&t); 16 | } 17 | -------------------------------------------------------------------------------- /unix/configure: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | $(echo "$0" | sed '$s!configure$!../configure!') "$@" 4 | -------------------------------------------------------------------------------- /unix/gtkcols.h: -------------------------------------------------------------------------------- 1 | /* 2 | * gtkcols.h - header file for a columns-based widget container 3 | * capable of supporting the PuTTY portable dialog box layout 4 | * mechanism. 5 | */ 6 | 7 | #ifndef COLUMNS_H 8 | #define COLUMNS_H 9 | 10 | #include 11 | #include 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif /* __cplusplus */ 16 | 17 | #define TYPE_COLUMNS (columns_get_type()) 18 | #define COLUMNS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_COLUMNS, Columns)) 19 | #define COLUMNS_CLASS(klass) \ 20 | (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_COLUMNS, ColumnsClass)) 21 | #define IS_COLUMNS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_COLUMNS)) 22 | #define IS_COLUMNS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_COLUMNS)) 23 | 24 | typedef struct Columns_tag Columns; 25 | typedef struct ColumnsClass_tag ColumnsClass; 26 | typedef struct ColumnsChild_tag ColumnsChild; 27 | 28 | struct Columns_tag { 29 | GtkContainer container; 30 | /* private after here */ 31 | GList *children; /* this holds ColumnsChild structures */ 32 | GList *taborder; /* this just holds GtkWidgets */ 33 | gint spacing; 34 | }; 35 | 36 | struct ColumnsClass_tag { 37 | GtkContainerClass parent_class; 38 | }; 39 | 40 | struct ColumnsChild_tag { 41 | /* If `widget' is non-NULL, this entry represents an actual widget. */ 42 | GtkWidget *widget; 43 | gint colstart, colspan; 44 | gboolean force_left; /* for recalcitrant GtkLabels */ 45 | ColumnsChild *same_height_as; 46 | /* Otherwise, this entry represents a change in the column setup. */ 47 | gint ncols; 48 | gint *percentages; 49 | gint x, y, w, h; /* used during an individual size computation */ 50 | }; 51 | 52 | GType columns_get_type(void); 53 | GtkWidget *columns_new(gint spacing); 54 | void columns_set_cols(Columns *cols, gint ncols, const gint *percentages); 55 | void columns_add(Columns *cols, GtkWidget *child, gint colstart, gint colspan); 56 | void columns_taborder_last(Columns *cols, GtkWidget *child); 57 | void columns_force_left_align(Columns *cols, GtkWidget *child); 58 | void columns_force_same_height(Columns *cols, GtkWidget *ch1, GtkWidget *ch2); 59 | 60 | #ifdef __cplusplus 61 | } 62 | #endif /* __cplusplus */ 63 | 64 | #endif /* COLUMNS_H */ 65 | -------------------------------------------------------------------------------- /unix/gtkmisc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Miscellaneous helper functions for GTK. 3 | */ 4 | 5 | #ifndef PUTTY_GTKMISC_H 6 | #define PUTTY_GTKMISC_H 7 | 8 | int string_width(const char *text); 9 | void get_label_text_dimensions(const char *text, int *width, int *height); 10 | 11 | void align_label_left(GtkLabel *label); 12 | 13 | GtkWidget *our_dialog_new(void); 14 | void our_dialog_add_to_content_area(GtkWindow *dlg, 15 | GtkWidget *w, 16 | gboolean expand, 17 | gboolean fill, 18 | guint padding); 19 | void our_dialog_set_action_area(GtkWindow *dlg, GtkWidget *w); 20 | GtkBox *our_dialog_make_action_hbox(GtkWindow *dlg); 21 | 22 | #endif /* PUTTY_GTKMISC_H */ 23 | -------------------------------------------------------------------------------- /unix/pterm.bundle: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ${env:JHBUILD_PREFIX} 6 | 7 | gtk+-3.0 8 | 14 | ${project}/../osxlaunch 15 | 16 | 17 | ${project}/pterm.plist 18 | 19 | 20 | ${project}/../ptermapp 21 | 22 | 23 | 24 | ${prefix}/lib/${gtkdir}/${pkg:${gtk}:gtk_binary_version}/immodules/*.so 25 | 26 | 27 | 28 | ${prefix}/lib/${gtkdir}/${pkg:${gtk}:gtk_binary_version}/printbackends/*.so 29 | 30 | 31 | 32 | ${prefix}/share/themes/Adwaita 33 | 34 | 35 | 36 | ${project}/../icons/Pterm.icns 37 | 38 | 39 | 40 | Adwaita 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /unix/pterm.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleIconFile 6 | Pterm.icns 7 | CFBundleName 8 | Pterm 9 | CFBundleDisplayName 10 | Pterm 11 | CFBundleExecutable 12 | Pterm 13 | CFBundleVersion 14 | Unidentified build 15 | CFBundleShortVersionString 16 | Unidentified build 17 | CFBundleDevelopmentRegion 18 | en 19 | CFBundleIdentifier 20 | org.tartarus.projects.putty.macpterm 21 | CFBundleInfoDictionaryVersion 22 | 6.0 23 | CFBundlePackageType 24 | APPL 25 | CFBundleSignature 26 | ???? 27 | NSHumanReadableCopyright 28 | © 1997-2015 Simon Tatham. All rights reserved. 29 | 30 | 31 | -------------------------------------------------------------------------------- /unix/putty.bundle: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ${env:JHBUILD_PREFIX} 6 | 7 | gtk+-3.0 8 | 14 | ${project}/../osxlaunch 15 | 16 | 17 | ${project}/putty.plist 18 | 19 | 20 | ${project}/../puttyapp 21 | 22 | 23 | 24 | ${prefix}/lib/${gtkdir}/${pkg:${gtk}:gtk_binary_version}/immodules/*.so 25 | 26 | 27 | 28 | ${prefix}/lib/${gtkdir}/${pkg:${gtk}:gtk_binary_version}/printbackends/*.so 29 | 30 | 31 | 32 | ${prefix}/share/themes/Adwaita 33 | 34 | 35 | 36 | ${project}/../icons/PuTTY.icns 37 | 38 | 39 | 40 | Adwaita 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /unix/putty.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleIconFile 6 | PuTTY.icns 7 | CFBundleName 8 | PuTTY 9 | CFBundleDisplayName 10 | PuTTY 11 | CFBundleExecutable 12 | PuTTY 13 | CFBundleVersion 14 | Unidentified build 15 | CFBundleShortVersionString 16 | Unidentified build 17 | CFBundleDevelopmentRegion 18 | en 19 | CFBundleIdentifier 20 | org.tartarus.projects.putty.macputty 21 | CFBundleInfoDictionaryVersion 22 | 6.0 23 | CFBundlePackageType 24 | APPL 25 | CFBundleSignature 26 | ???? 27 | NSHumanReadableCopyright 28 | © 1997-2015 Simon Tatham. All rights reserved. 29 | 30 | 31 | -------------------------------------------------------------------------------- /unix/urlhack_unix.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "urlhack.h" 6 | 7 | enum 8 | { 9 | max = 4000 10 | }; 11 | void urlhack_launch_url(const char *app, const wchar_t *url) 12 | { 13 | char buf[max]; 14 | const char *browser = NULL; 15 | 16 | if (app) 17 | browser = app; 18 | if (NULL == browser || 0 == strlen(browser)) 19 | browser = "xdg-open"; 20 | 21 | strncat(buf, browser, max - 1); 22 | strcat(buf, " "); 23 | wcstombs(buf + strlen(buf), url, max - strlen(buf) - 2); 24 | if (!system(buf)) 25 | printf("couldn't run browser: %s", buf); 26 | } 27 | 28 | int urlhack_is_ctrl_pressed() 29 | { 30 | // TODO 31 | return 1; 32 | } 33 | 34 | void rtfm(const char *error) 35 | { 36 | // TODO 37 | } 38 | -------------------------------------------------------------------------------- /unix/ux_x11.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ux_x11.c: fetch local auth data for X forwarding. 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "putty.h" 12 | #include "ssh.h" 13 | #include "network.h" 14 | 15 | void platform_get_x11_auth(struct X11Display *disp, Conf *conf) 16 | { 17 | char *xauthfile; 18 | int needs_free; 19 | 20 | /* 21 | * Find the .Xauthority file. 22 | */ 23 | needs_free = FALSE; 24 | xauthfile = getenv("XAUTHORITY"); 25 | if (!xauthfile) { 26 | xauthfile = getenv("HOME"); 27 | if (xauthfile) { 28 | xauthfile = dupcat(xauthfile, "/.Xauthority", NULL); 29 | needs_free = TRUE; 30 | } 31 | } 32 | 33 | if (xauthfile) { 34 | x11_get_auth_from_authfile(disp, xauthfile); 35 | if (needs_free) 36 | sfree(xauthfile); 37 | } 38 | } 39 | 40 | const int platform_uses_x11_unix_by_default = TRUE; 41 | -------------------------------------------------------------------------------- /unix/uxcfg.c: -------------------------------------------------------------------------------- 1 | /* 2 | * uxcfg.c - the Unix-specific parts of the PuTTY configuration 3 | * box. 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | #include "putty.h" 10 | #include "dialog.h" 11 | #include "storage.h" 12 | 13 | void unix_setup_config_box(struct controlbox *b, int midsession, int protocol) 14 | { 15 | struct controlset *s; 16 | union control *c; 17 | 18 | /* 19 | * The Conf structure contains two Unix-specific elements which 20 | * are not configured in here: stamp_utmp and login_shell. This 21 | * is because pterm does not put up a configuration box right at 22 | * the start, which is the only time when these elements would 23 | * be useful to configure. 24 | */ 25 | 26 | /* 27 | * On Unix, we don't have a drop-down list for the printer 28 | * control. 29 | */ 30 | s = ctrl_getset(b, "Terminal", "printing", "Remote-controlled printing"); 31 | assert(s->ncontrols == 1 && s->ctrls[0]->generic.type == CTRL_EDITBOX); 32 | s->ctrls[0]->editbox.has_list = 0; 33 | 34 | /* 35 | * Unix supports a local-command proxy. This also means we must 36 | * adjust the text on the `Telnet command' control. 37 | */ 38 | if (!midsession) { 39 | int i; 40 | s = ctrl_getset(b, "Connection/Proxy", "basics", NULL); 41 | for (i = 0; i < s->ncontrols; i++) { 42 | c = s->ctrls[i]; 43 | if (c->generic.type == CTRL_RADIO && 44 | c->generic.context.i == CONF_proxy_type) { 45 | assert(c->generic.handler == conf_radiobutton_handler); 46 | c->radio.nbuttons++; 47 | c->radio.buttons = sresize(c->radio.buttons, c->radio.nbuttons, char *); 48 | c->radio.buttons[c->radio.nbuttons - 1] = dupstr("Local"); 49 | c->radio.buttondata = 50 | sresize(c->radio.buttondata, c->radio.nbuttons, intorptr); 51 | c->radio.buttondata[c->radio.nbuttons - 1] = I(PROXY_CMD); 52 | break; 53 | } 54 | } 55 | 56 | for (i = 0; i < s->ncontrols; i++) { 57 | c = s->ctrls[i]; 58 | if (c->generic.type == CTRL_EDITBOX && 59 | c->generic.context.i == CONF_proxy_telnet_command) { 60 | assert(c->generic.handler == conf_editbox_handler); 61 | sfree(c->generic.label); 62 | c->generic.label = dupstr("Telnet command, or local" 63 | " proxy command"); 64 | break; 65 | } 66 | } 67 | } 68 | 69 | /* 70 | * Serial back end is available on Unix. However, we have to 71 | * mask out a couple of the configuration options: mark and 72 | * space parity are not conveniently supported, and neither is 73 | * DSR/DTR flow control. 74 | */ 75 | if (!midsession || (protocol == PROT_SERIAL)) 76 | ser_setup_config_box(b, midsession, 0x07, 0x07); 77 | } 78 | -------------------------------------------------------------------------------- /unix/uxgen.c: -------------------------------------------------------------------------------- 1 | /* 2 | * uxgen.c: Unix implementation of get_heavy_noise() from cmdgen.c. 3 | */ 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | #include "putty.h" 12 | 13 | char *get_random_data(int len, const char *device) 14 | { 15 | char *buf = snewn(len, char); 16 | int fd; 17 | int ngot, ret; 18 | 19 | if (!device) 20 | device = "/dev/random"; 21 | 22 | fd = open(device, O_RDONLY); 23 | if (fd < 0) { 24 | sfree(buf); 25 | fprintf(stderr, "puttygen: %s: open: %s\n", device, strerror(errno)); 26 | return NULL; 27 | } 28 | 29 | ngot = 0; 30 | while (ngot < len) { 31 | ret = read(fd, buf + ngot, len - ngot); 32 | if (ret < 0) { 33 | close(fd); 34 | sfree(buf); 35 | fprintf(stderr, "puttygen: %s: read: %s\n", device, strerror(errno)); 36 | return NULL; 37 | } 38 | ngot += ret; 39 | } 40 | 41 | close(fd); 42 | 43 | return buf; 44 | } 45 | -------------------------------------------------------------------------------- /unix/uxnogtk.c: -------------------------------------------------------------------------------- 1 | /* 2 | * uxnogtk.c: link into non-GUI Unix programs so that they can tell 3 | * buildinfo about a lack of GTK. 4 | */ 5 | 6 | #include "putty.h" 7 | 8 | char *buildinfo_gtk_version(void) 9 | { 10 | return NULL; 11 | } 12 | -------------------------------------------------------------------------------- /unix/uxnoise.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Noise generation for PuTTY's cryptographic random number 3 | * generator. 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "putty.h" 16 | #include "ssh.h" 17 | #include "storage.h" 18 | 19 | static int read_dev_urandom(char *buf, int len) 20 | { 21 | int fd; 22 | int ngot, ret; 23 | 24 | fd = open("/dev/urandom", O_RDONLY); 25 | if (fd < 0) 26 | return 0; 27 | 28 | ngot = 0; 29 | while (ngot < len) { 30 | ret = read(fd, buf + ngot, len - ngot); 31 | if (ret < 0) { 32 | close(fd); 33 | return 0; 34 | } 35 | ngot += ret; 36 | } 37 | 38 | close(fd); 39 | 40 | return 1; 41 | } 42 | 43 | /* 44 | * This function is called once, at PuTTY startup. It will do some 45 | * slightly silly things such as fetching an entire process listing 46 | * and scanning /tmp, load the saved random seed from disk, and 47 | * also read 32 bytes out of /dev/urandom. 48 | */ 49 | 50 | void noise_get_heavy(void (*func)(void *, int)) 51 | { 52 | char buf[512]; 53 | FILE *fp; 54 | int ret; 55 | int got_dev_urandom = 0; 56 | 57 | if (read_dev_urandom(buf, 32)) { 58 | got_dev_urandom = 1; 59 | func(buf, 32); 60 | } 61 | 62 | fp = popen("ps -axu 2>/dev/null", "r"); 63 | if (fp) { 64 | while ((ret = fread(buf, 1, sizeof(buf), fp)) > 0) 65 | func(buf, ret); 66 | pclose(fp); 67 | } else if (!got_dev_urandom) { 68 | fprintf(stderr, 69 | "popen: %s\n" 70 | "Unable to access fallback entropy source\n", 71 | strerror(errno)); 72 | exit(1); 73 | } 74 | 75 | fp = popen("ls -al /tmp 2>/dev/null", "r"); 76 | if (fp) { 77 | while ((ret = fread(buf, 1, sizeof(buf), fp)) > 0) 78 | func(buf, ret); 79 | pclose(fp); 80 | } else if (!got_dev_urandom) { 81 | fprintf(stderr, 82 | "popen: %s\n" 83 | "Unable to access fallback entropy source\n", 84 | strerror(errno)); 85 | exit(1); 86 | } 87 | 88 | read_random_seed(func); 89 | random_save_seed(); 90 | } 91 | 92 | void random_save_seed(void) 93 | { 94 | int len; 95 | void *data; 96 | 97 | if (random_active) { 98 | random_get_savedata(&data, &len); 99 | write_random_seed(data, len); 100 | sfree(data); 101 | } 102 | } 103 | 104 | /* 105 | * This function is called every time the random pool needs 106 | * stirring, and will acquire the system time. 107 | */ 108 | void noise_get_light(void (*func)(void *, int)) 109 | { 110 | struct timeval tv; 111 | gettimeofday(&tv, NULL); 112 | func(&tv, sizeof(tv)); 113 | } 114 | 115 | /* 116 | * This function is called on a timer, and grabs as much changeable 117 | * system data as it can quickly get its hands on. 118 | */ 119 | void noise_regular(void) 120 | { 121 | int fd; 122 | int ret; 123 | char buf[512]; 124 | struct rusage rusage; 125 | 126 | if ((fd = open("/proc/meminfo", O_RDONLY)) >= 0) { 127 | while ((ret = read(fd, buf, sizeof(buf))) > 0) 128 | random_add_noise(buf, ret); 129 | close(fd); 130 | } 131 | if ((fd = open("/proc/stat", O_RDONLY)) >= 0) { 132 | while ((ret = read(fd, buf, sizeof(buf))) > 0) 133 | random_add_noise(buf, ret); 134 | close(fd); 135 | } 136 | getrusage(RUSAGE_SELF, &rusage); 137 | random_add_noise(&rusage, sizeof(rusage)); 138 | } 139 | 140 | /* 141 | * This function is called on every keypress or mouse move, and 142 | * will add the current time to the noise pool. It gets the scan 143 | * code or mouse position passed in, and adds that too. 144 | */ 145 | void noise_ultralight(unsigned long data) 146 | { 147 | struct timeval tv; 148 | gettimeofday(&tv, NULL); 149 | random_add_noise(&tv, sizeof(tv)); 150 | random_add_noise(&data, sizeof(data)); 151 | } 152 | -------------------------------------------------------------------------------- /unix/uxpeer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Unix: wrapper for getsockopt(SO_PEERCRED), conditionalised on 3 | * appropriate autoconfery. 4 | */ 5 | 6 | #ifdef HAVE_CONFIG_H 7 | // clang-format off 8 | # include "uxconfig.h" /* leading space prevents mkfiles.pl trying to follow */ 9 | // clang-format on 10 | #endif 11 | 12 | #ifdef HAVE_SO_PEERCRED 13 | #define _GNU_SOURCE 14 | #include 15 | #endif 16 | 17 | #include 18 | 19 | #include "putty.h" 20 | 21 | int so_peercred(int fd, int *pid, int *uid, int *gid) 22 | { 23 | #ifdef HAVE_SO_PEERCRED 24 | struct ucred cr; 25 | socklen_t crlen = sizeof(cr); 26 | if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &crlen) == 0) { 27 | *pid = cr.pid; 28 | *uid = cr.uid; 29 | *gid = cr.gid; 30 | return TRUE; 31 | } 32 | #endif 33 | return FALSE; 34 | } 35 | -------------------------------------------------------------------------------- /unix/uxprint.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Printing interface for PuTTY. 3 | */ 4 | 5 | #include 6 | #include 7 | #include "putty.h" 8 | 9 | struct printer_job_tag { 10 | FILE *fp; 11 | }; 12 | 13 | printer_job *printer_start_job(char *printer) 14 | { 15 | printer_job *ret = snew(printer_job); 16 | /* 17 | * On Unix, we treat the printer string as the name of a 18 | * command to pipe to - typically lpr, of course. 19 | */ 20 | ret->fp = popen(printer, "w"); 21 | if (!ret->fp) { 22 | sfree(ret); 23 | ret = NULL; 24 | } 25 | return ret; 26 | } 27 | 28 | void printer_job_data(printer_job *pj, void *data, int len) 29 | { 30 | if (!pj) 31 | return; 32 | 33 | if (fwrite(data, 1, len, pj->fp) < len) 34 | /* ignore */; 35 | } 36 | 37 | void printer_finish_job(printer_job *pj) 38 | { 39 | if (!pj) 40 | return; 41 | 42 | pclose(pj->fp); 43 | sfree(pj); 44 | } 45 | 46 | /* 47 | * There's no sensible way to enumerate printers under Unix, since 48 | * practically any valid Unix command is a valid printer :-) So 49 | * these are useless stub functions, and uxcfg.c will disable the 50 | * drop-down list in the printer configurer. 51 | */ 52 | printer_enum *printer_start_enum(int *nprinters_ptr) 53 | { 54 | *nprinters_ptr = 0; 55 | return NULL; 56 | } 57 | char *printer_get_name(printer_enum *pe, int i) 58 | { 59 | return NULL; 60 | } 61 | void printer_finish_enum(printer_enum *pe) 62 | { 63 | } 64 | -------------------------------------------------------------------------------- /unix/uxpterm.c: -------------------------------------------------------------------------------- 1 | /* 2 | * pterm main program. 3 | */ 4 | 5 | #include 6 | #include 7 | 8 | #include "putty.h" 9 | 10 | const char *const appname = "pterm"; 11 | const int use_event_log = 0; /* pterm doesn't need it */ 12 | const int new_session = 0, saved_sessions = 0; /* or these */ 13 | const int dup_check_launchable = 0; /* no need to check host name in conf */ 14 | const int use_pty_argv = TRUE; 15 | 16 | Backend *select_backend(Conf *conf) 17 | { 18 | return &pty_backend; 19 | } 20 | 21 | int cfgbox(Conf *conf) 22 | { 23 | /* 24 | * This is a no-op in pterm, except that we'll ensure the 25 | * protocol is set to -1 to inhibit the useless Connection 26 | * panel in the config box. 27 | */ 28 | conf_set_int(conf, CONF_protocol, -1); 29 | return 1; 30 | } 31 | 32 | void cleanup_exit(int code) 33 | { 34 | exit(code); 35 | } 36 | 37 | int process_nonoption_arg(const char *arg, Conf *conf, int *allow_launch) 38 | { 39 | return 0; /* pterm doesn't have any. */ 40 | } 41 | 42 | char *make_default_wintitle(char *hostname) 43 | { 44 | return dupstr("pterm"); 45 | } 46 | 47 | void setup(int single) 48 | { 49 | extern void pty_pre_init(void); /* declared in pty.c */ 50 | 51 | cmdline_tooltype = TOOLTYPE_NONNETWORK; 52 | default_protocol = -1; 53 | 54 | if (single) 55 | pty_pre_init(); 56 | } 57 | -------------------------------------------------------------------------------- /unix/uxputty.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Unix PuTTY main program. 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "putty.h" 14 | #include "storage.h" 15 | 16 | #include "gtkcompat.h" 17 | 18 | /* 19 | * Stubs to avoid uxpty.c needing to be linked in. 20 | */ 21 | const int use_pty_argv = FALSE; 22 | char **pty_argv; /* never used */ 23 | char *pty_osx_envrestore_prefix; 24 | 25 | /* 26 | * Clean up and exit. 27 | */ 28 | void cleanup_exit(int code) 29 | { 30 | /* 31 | * Clean up. 32 | */ 33 | sk_cleanup(); 34 | random_save_seed(); 35 | exit(code); 36 | } 37 | 38 | Backend *select_backend(Conf *conf) 39 | { 40 | Backend *back = backend_from_proto(conf_get_int(conf, CONF_protocol)); 41 | assert(back != NULL); 42 | return back; 43 | } 44 | 45 | int cfgbox(Conf *conf) 46 | { 47 | char *title = dupcat(appname, " Configuration", NULL); 48 | int ret = do_config_box(title, conf, 0, 0); 49 | sfree(title); 50 | return ret; 51 | } 52 | 53 | static int got_host = 0; 54 | 55 | const int use_event_log = 1, new_session = 1, saved_sessions = 1; 56 | const int dup_check_launchable = 1; 57 | 58 | int process_nonoption_arg(const char *arg, Conf *conf, int *allow_launch) 59 | { 60 | char *argdup, *p, *q; 61 | argdup = dupstr(arg); 62 | q = argdup; 63 | 64 | if (got_host) { 65 | /* 66 | * If we already have a host name, treat this argument as a 67 | * port number. NB we have to treat this as a saved -P 68 | * argument, so that it will be deferred until it's a good 69 | * moment to run it. 70 | */ 71 | int ret = cmdline_process_param("-P", argdup, 1, conf); 72 | assert(ret == 2); 73 | } else if (!strncmp(q, "telnet:", 7)) { 74 | /* 75 | * If the hostname starts with "telnet:", 76 | * set the protocol to Telnet and process 77 | * the string as a Telnet URL. 78 | */ 79 | char c; 80 | 81 | q += 7; 82 | if (q[0] == '/' && q[1] == '/') 83 | q += 2; 84 | conf_set_int(conf, CONF_protocol, PROT_TELNET); 85 | p = q; 86 | p += host_strcspn(p, ":/"); 87 | c = *p; 88 | if (*p) 89 | *p++ = '\0'; 90 | if (c == ':') 91 | conf_set_int(conf, CONF_port, atoi(p)); 92 | else 93 | conf_set_int(conf, CONF_port, -1); 94 | conf_set_str(conf, CONF_host, q); 95 | got_host = 1; 96 | } else { 97 | /* 98 | * Otherwise, treat this argument as a host name. 99 | */ 100 | p = argdup; 101 | while (*p && !isspace((unsigned char)*p)) 102 | p++; 103 | if (*p) 104 | *p++ = '\0'; 105 | conf_set_str(conf, CONF_host, q); 106 | got_host = 1; 107 | } 108 | if (got_host) 109 | *allow_launch = TRUE; 110 | 111 | sfree(argdup); 112 | 113 | return 1; 114 | } 115 | 116 | char *make_default_wintitle(char *hostname) 117 | { 118 | return dupcat(hostname, " - ", appname, NULL); 119 | } 120 | 121 | /* 122 | * X11-forwarding-related things suitable for Gtk app. 123 | */ 124 | 125 | char *platform_get_x_display(void) 126 | { 127 | const char *display; 128 | /* Try to take account of --display and what have you. */ 129 | if (!(display = gdk_get_display())) 130 | /* fall back to traditional method */ 131 | display = getenv("DISPLAY"); 132 | return dupstr(display); 133 | } 134 | 135 | const int share_can_be_downstream = TRUE; 136 | const int share_can_be_upstream = TRUE; 137 | 138 | void setup(int single) 139 | { 140 | sk_init(); 141 | flags = FLAG_VERBOSE | FLAG_INTERACTIVE; 142 | default_protocol = be_default_protocol; 143 | /* Find the appropriate default port. */ 144 | { 145 | Backend *b = backend_from_proto(default_protocol); 146 | default_port = 0; /* illegal */ 147 | if (b) 148 | default_port = b->default_port; 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /unix/uxsel.c: -------------------------------------------------------------------------------- 1 | /* 2 | * uxsel.c 3 | * 4 | * This module is a sort of all-purpose interchange for file 5 | * descriptors. At one end it talks to uxnet.c and pty.c and 6 | * anything else which might have one or more fds that need 7 | * select()-type things doing to them during an extended program 8 | * run; at the other end it talks to pterm.c or uxplink.c or 9 | * anything else which might have its own means of actually doing 10 | * those select()-type things. 11 | */ 12 | 13 | #include 14 | 15 | #include "putty.h" 16 | #include "tree234.h" 17 | 18 | struct fd { 19 | int fd; 20 | int rwx; /* 4=except 2=write 1=read */ 21 | uxsel_callback_fn callback; 22 | uxsel_id *id; /* for uxsel_input_remove */ 23 | }; 24 | 25 | static tree234 *fds; 26 | 27 | static int uxsel_fd_cmp(void *av, void *bv) 28 | { 29 | struct fd *a = (struct fd *)av; 30 | struct fd *b = (struct fd *)bv; 31 | if (a->fd < b->fd) 32 | return -1; 33 | if (a->fd > b->fd) 34 | return +1; 35 | return 0; 36 | } 37 | static int uxsel_fd_findcmp(void *av, void *bv) 38 | { 39 | int *a = (int *)av; 40 | struct fd *b = (struct fd *)bv; 41 | if (*a < b->fd) 42 | return -1; 43 | if (*a > b->fd) 44 | return +1; 45 | return 0; 46 | } 47 | 48 | void uxsel_init(void) 49 | { 50 | fds = newtree234(uxsel_fd_cmp); 51 | } 52 | 53 | /* 54 | * Here is the interface to fd-supplying modules. They supply an 55 | * fd, a set of read/write/execute states, and a callback function 56 | * for when the fd satisfies one of those states. Repeated calls to 57 | * uxsel_set on the same fd are perfectly legal and serve to change 58 | * the rwx state (typically you only want to select an fd for 59 | * writing when you actually have pending data you want to write to 60 | * it!). 61 | */ 62 | 63 | void uxsel_set(int fd, int rwx, uxsel_callback_fn callback) 64 | { 65 | struct fd *newfd; 66 | 67 | assert(fd >= 0); 68 | 69 | uxsel_del(fd); 70 | 71 | if (rwx) { 72 | newfd = snew(struct fd); 73 | newfd->fd = fd; 74 | newfd->rwx = rwx; 75 | newfd->callback = callback; 76 | newfd->id = uxsel_input_add(fd, rwx); 77 | add234(fds, newfd); 78 | } 79 | } 80 | 81 | void uxsel_del(int fd) 82 | { 83 | struct fd *oldfd = find234(fds, &fd, uxsel_fd_findcmp); 84 | if (oldfd) { 85 | if (oldfd->id) 86 | uxsel_input_remove(oldfd->id); 87 | del234(fds, oldfd); 88 | sfree(oldfd); 89 | } 90 | } 91 | 92 | /* 93 | * And here is the interface to select-functionality-supplying 94 | * modules. 95 | */ 96 | 97 | int next_fd(int *state, int *rwx) 98 | { 99 | struct fd *fd; 100 | fd = index234(fds, (*state)++); 101 | if (fd) { 102 | *rwx = fd->rwx; 103 | return fd->fd; 104 | } else 105 | return -1; 106 | } 107 | 108 | int first_fd(int *state, int *rwx) 109 | { 110 | *state = 0; 111 | return next_fd(state, rwx); 112 | } 113 | 114 | void select_result(int fd, int event) 115 | { 116 | struct fd *fdstruct = find234(fds, &fd, uxsel_fd_findcmp); 117 | /* 118 | * Apparently this can sometimes be NULL. Can't see how, but I 119 | * assume it means I need to ignore the event since it's on an 120 | * fd I've stopped being interested in. Sigh. 121 | */ 122 | if (fdstruct) 123 | fdstruct->callback(fd, event); 124 | } 125 | -------------------------------------------------------------------------------- /unix/uxsignal.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | /* 6 | * Calling signal() is non-portable, as it varies in meaning 7 | * between platforms and depending on feature macros, and has 8 | * stupid semantics at least some of the time. 9 | * 10 | * This function provides the same interface as the libc function, 11 | * but provides consistent semantics. It assumes POSIX semantics 12 | * for sigaction() (so you might need to do some more work if you 13 | * port to something ancient like SunOS 4) 14 | */ 15 | void (*putty_signal(int sig, void (*func)(int)))(int) 16 | { 17 | struct sigaction sa; 18 | struct sigaction old; 19 | 20 | sa.sa_handler = func; 21 | if (sigemptyset(&sa.sa_mask) < 0) 22 | return SIG_ERR; 23 | sa.sa_flags = SA_RESTART; 24 | if (sigaction(sig, &sa, &old) < 0) 25 | return SIG_ERR; 26 | return old.sa_handler; 27 | } 28 | 29 | void block_signal(int sig, int block_it) 30 | { 31 | sigset_t ss; 32 | 33 | sigemptyset(&ss); 34 | sigaddset(&ss, sig); 35 | if (sigprocmask(block_it ? SIG_BLOCK : SIG_UNBLOCK, &ss, 0) < 0) { 36 | perror("sigprocmask"); 37 | exit(1); 38 | } 39 | } 40 | 41 | /* 42 | Local Variables: 43 | c-basic-offset:4 44 | comment-column:40 45 | End: 46 | */ 47 | -------------------------------------------------------------------------------- /unix/x11misc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * x11misc.c: miscellaneous stuff for dealing directly with X servers. 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "putty.h" 12 | 13 | #ifndef NOT_X_WINDOWS 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #include "x11misc.h" 20 | 21 | /* ---------------------------------------------------------------------- 22 | * Error handling mechanism which permits us to ignore specific X11 23 | * errors from particular requests. We maintain a list of upcoming 24 | * potential error events that we want to not treat as fatal errors. 25 | */ 26 | 27 | static int (*orig_x11_error_handler)(Display *thisdisp, XErrorEvent *err); 28 | 29 | struct x11_err_to_ignore { 30 | Display *display; 31 | unsigned char error_code; 32 | unsigned long serial; 33 | }; 34 | 35 | struct x11_err_to_ignore *errs; 36 | 37 | int nerrs, errsize; 38 | 39 | static int x11_error_handler(Display *thisdisp, XErrorEvent *err) 40 | { 41 | int i; 42 | for (i = 0; i < nerrs; i++) { 43 | if (thisdisp == errs[i].display && err->serial == errs[i].serial && 44 | err->error_code == errs[i].error_code) { 45 | /* Ok, this is an error we're happy to ignore */ 46 | return 0; 47 | } 48 | } 49 | 50 | return (*orig_x11_error_handler)(thisdisp, err); 51 | } 52 | 53 | void x11_ignore_error(Display *disp, unsigned char errcode) 54 | { 55 | /* 56 | * Install our error handler, if we haven't already. 57 | */ 58 | if (!orig_x11_error_handler) 59 | orig_x11_error_handler = XSetErrorHandler(x11_error_handler); 60 | 61 | /* 62 | * This is as good a moment as any to winnow the ignore list based 63 | * on requests we know to have been processed. 64 | */ 65 | { 66 | unsigned long last = LastKnownRequestProcessed(disp); 67 | int i, j; 68 | for (i = j = 0; i < nerrs; i++) { 69 | if (errs[i].display == disp && errs[i].serial <= last) 70 | continue; 71 | errs[j++] = errs[i]; 72 | } 73 | nerrs = j; 74 | } 75 | 76 | if (nerrs >= errsize) { 77 | errsize = nerrs * 5 / 4 + 16; 78 | errs = sresize(errs, errsize, struct x11_err_to_ignore); 79 | } 80 | errs[nerrs].display = disp; 81 | errs[nerrs].error_code = errcode; 82 | errs[nerrs].serial = NextRequest(disp); 83 | nerrs++; 84 | } 85 | 86 | #endif 87 | -------------------------------------------------------------------------------- /unix/x11misc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * x11misc.h: header file for functions that need to refer to Xlib 3 | * data types. Has to be separate from unix.h so that we can include 4 | * it only after including the X headers, which in turn has to be done 5 | * after putty.h has told us whether NOT_X_WINDOWS is defined. 6 | */ 7 | 8 | #ifndef NOT_X_WINDOWS 9 | 10 | /* 11 | * x11misc.c. 12 | */ 13 | void x11_ignore_error(Display *disp, unsigned char errcode); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /urlhack.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef _URLHACK_H 3 | #define _URLHACK_H 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | #include 9 | 10 | typedef struct { 11 | int x0, y0, x1, y1; 12 | } text_region; 13 | 14 | extern const char *urlhack_default_regex; 15 | extern const char *urlhack_liberal_regex; 16 | extern int urlhack_mouse_old_x, urlhack_mouse_old_y, urlhack_current_region; 17 | 18 | void urlhack_reset(); 19 | void urlhack_go_find_me_some_hyperlinks(int screen_width); 20 | void urlhack_putchar(char ch); 21 | text_region urlhack_get_link_region(unsigned int index); 22 | 23 | int urlhack_is_in_link_region(int x, int y); 24 | int urlhack_is_in_this_link_region(text_region r, int x, int y); 25 | text_region urlhack_get_link_bounds(int x, int y); 26 | void urlhack_add_link_region(int x0, int y0, int x1, int y1); 27 | void urlhack_launch_url(const char *app, const wchar_t *url); 28 | int urlhack_is_ctrl_pressed(); 29 | void urlhack_set_regular_expression(int mode, const char *expression); 30 | void rtfm(const char *error); 31 | 32 | void urlhack_init(); 33 | void urlhack_cleanup(); 34 | 35 | #ifdef __cplusplus 36 | } 37 | #endif 38 | 39 | #endif // _URLHACK_H 40 | -------------------------------------------------------------------------------- /version.c: -------------------------------------------------------------------------------- 1 | /* 2 | * PuTTY version numbering 3 | */ 4 | 5 | /* 6 | * The difficult part of deciding what goes in these version strings 7 | * is done in Buildscr, and then written into version.h. All we have 8 | * to do here is to drop it into variables of the right names. 9 | */ 10 | 11 | #ifdef SOURCE_COMMIT 12 | #include "empty.h" 13 | #endif 14 | 15 | #include "version.h" 16 | 17 | const char ver[] = TEXTVER; 18 | const char sshver[] = SSHVER; 19 | const char commitid[] = SOURCE_COMMIT; 20 | 21 | /* 22 | * SSH local version string MUST be under 40 characters. Here's a 23 | * compile time assertion to verify this. 24 | */ 25 | enum 26 | { 27 | vorpal_sword = 1 / (sizeof(sshver) <= 40) 28 | }; 29 | -------------------------------------------------------------------------------- /version.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This header file provides the various versioning-related #defines 3 | * for a particular PuTTY build. 4 | * 5 | * When my automated build system does a full build, Buildscr 6 | * completely overwrites this file with information derived from the 7 | * circumstances and type of that build. The information _here_ is 8 | * default stuff used for local development runs of 'make'. 9 | */ 10 | 11 | #define TEXTVER "Unidentified build" 12 | #define SSHVER "PuTTY-Unidentified-Local-Build" 13 | #define BINARY_VERSION 0, 0, 0, 0 14 | 15 | #ifndef SOURCE_COMMIT 16 | /* 17 | * git commit id from which this build was made. This is defined by 18 | * Buildscr for official builds - both source archives and prebuilt 19 | * binaries - in the course of overwriting this file as described 20 | * above. But we put it here under ifdef, so that it can also be 21 | * passed in on the command line for Unix local development builds, 22 | * which I treat specially because Unix developers - e.g. me - are 23 | * quite likely to run 'make install' straight out of their dev 24 | * directory so as to use the bleeding-edge code for day-to-day 25 | * running. 26 | * 27 | * Windows doesn't really need the same treatment, because the easiest 28 | * way to install a build properly on Windows is to run the installer, 29 | * and the easiest way to do that is to run Buildscr, which will 30 | * populate this field its own way. It's only the Unix automake build 31 | * where you might go straight from local 'make' to 'make install' 32 | * without going through Buildscr. 33 | */ 34 | #define SOURCE_COMMIT "unavailable" 35 | #endif 36 | -------------------------------------------------------------------------------- /windows/README-msi.txt: -------------------------------------------------------------------------------- 1 | PuTTY README 2 | ============ 3 | 4 | This is the README file for the PuTTY MSI installer distribution. If 5 | you're reading this, you've probably just run our installer and 6 | installed PuTTY on your system. 7 | 8 | What should I do next? 9 | ---------------------- 10 | 11 | If you want to use PuTTY to connect to other computers, or use PSFTP 12 | to transfer files, you should just be able to run them from the 13 | Start menu. 14 | 15 | If you want to use the command-line file transfer utility PSCP, you 16 | will need to run this from a Command Prompt or equivalent, because it 17 | will not do anything useful without command-line options telling it 18 | what files to copy to and from where. You can do this by just running 19 | the command 'pscp' from a Command Prompt, if you used the installer's 20 | option to put the PuTTY installation directory on your PATH. 21 | Alternatively, you can always run pscp.exe by its full pathname, e.g. 22 | "C:\Program Files\PuTTY\pscp.exe". 23 | 24 | (Note that a Command Prompt that was already open before you ran the 25 | installer will not have inherited the update of PATH.) 26 | 27 | Some versions of Windows will refuse to run HTML Help files (.CHM) 28 | if they are installed on a network drive. If you have installed 29 | PuTTY on a network drive, you might want to check that the help file 30 | works properly. If not, see http://support.microsoft.com/kb/896054 31 | for information on how to solve this problem. 32 | 33 | What do I do if it doesn't work? 34 | -------------------------------- 35 | 36 | The PuTTY home web site is 37 | 38 | https://www.chiark.greenend.org.uk/~sgtatham/putty/ 39 | 40 | Here you will find our list of known bugs and pending feature 41 | requests. If your problem is not listed in there, or in the FAQ, or 42 | in the manuals, read the Feedback page to find out how to report 43 | bugs to us. PLEASE read the Feedback page carefully: it is there to 44 | save you time as well as us. Do not send us one-line bug reports 45 | telling us `it doesn't work'. 46 | -------------------------------------------------------------------------------- /windows/README.txt: -------------------------------------------------------------------------------- 1 | PuTTY README 2 | ============ 3 | 4 | This is the README file for the PuTTY installer distribution. If 5 | you're reading this, you've probably just run our installer and 6 | installed PuTTY on your system. 7 | 8 | What should I do next? 9 | ---------------------- 10 | 11 | If you want to use PuTTY to connect to other computers, or use PSFTP 12 | to transfer files, you should just be able to run them from the 13 | Start menu. 14 | 15 | If you want to use the command-line-only file transfer utility PSCP, 16 | you will probably want to put the PuTTY installation directory on 17 | your PATH. On Windows 7 and similar versions, you can do this at 18 | Control Panel > System and Security > System > Advanced system 19 | settings > Environment Variables. 20 | 21 | Some versions of Windows will refuse to run HTML Help files (.CHM) 22 | if they are installed on a network drive. If you have installed 23 | PuTTY on a network drive, you might want to check that the help file 24 | works properly. If not, see http://support.microsoft.com/kb/896054 25 | for information on how to solve this problem. 26 | 27 | What do I do if it doesn't work? 28 | -------------------------------- 29 | 30 | The PuTTY home web site is 31 | 32 | https://www.chiark.greenend.org.uk/~sgtatham/putty/ 33 | 34 | Here you will find our list of known bugs and pending feature 35 | requests. If your problem is not listed in there, or in the FAQ, or 36 | in the manuals, read the Feedback page to find out how to report 37 | bugs to us. PLEASE read the Feedback page carefully: it is there to 38 | save you time as well as us. Do not send us one-line bug reports 39 | telling us `it doesn't work'. 40 | -------------------------------------------------------------------------------- /windows/pageant.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FauxFaux/PuTTYTray/4db528dd8477b7dbb40976fd0f1d4ff34d8bb101/windows/pageant.ico -------------------------------------------------------------------------------- /windows/pageant.mft: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 11 | PuTTY SSH authentication agent 12 | 13 | 14 | 16 | 22 | 23 | 24 | 25 | 26 | 28 | true 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /windows/pageant.rc: -------------------------------------------------------------------------------- 1 | /* 2 | * Windows resources for Pageant. 3 | */ 4 | 5 | #include "rcstuff.h" 6 | 7 | // region tray-fatty 8 | // * removing duplicated definitions 9 | // * change all the 2-based ids to 9-based 10 | // endregion 11 | 12 | 900 ICON "pageant.ico" 13 | 901 ICON "pageants.ico" 14 | 15 | 910 DIALOG DISCARDABLE 0, 0, 140, 60 16 | STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU 17 | CAPTION "Pageant: Enter Passphrase" 18 | FONT 8, "MS Shell Dlg" 19 | BEGIN 20 | CTEXT "Enter passphrase for key", 100, 10, 6, 120, 8 21 | CTEXT "", 101, 10, 16, 120, 8 22 | EDITTEXT 102, 10, 26, 120, 12, ES_PASSWORD | ES_AUTOHSCROLL 23 | DEFPUSHBUTTON "O&K", IDOK, 20, 42, 40, 14 24 | PUSHBUTTON "&Cancel", IDCANCEL, 80, 42, 40, 14 25 | END 26 | 27 | 911 DIALOG DISCARDABLE 0, 0, 330, 200 28 | STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU 29 | CAPTION "Pageant Key List" 30 | FONT 8, "MS Shell Dlg" 31 | BEGIN 32 | LISTBOX 100, 10, 10, 310, 155, 33 | LBS_EXTENDEDSEL | LBS_HASSTRINGS | LBS_USETABSTOPS | WS_VSCROLL | WS_TABSTOP 34 | PUSHBUTTON "&Add Key", 101, 75, 162, 60, 14 35 | PUSHBUTTON "&Remove Key", 102, 195, 162, 60, 14 36 | PUSHBUTTON "&Help", 103, 10, 182, 50, 14 37 | DEFPUSHBUTTON "&Close", IDOK, 270, 182, 50, 14 38 | END 39 | 40 | /* Accelerators used: cl */ 41 | 913 DIALOG DISCARDABLE 140, 40, 270, 106 42 | STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU 43 | CAPTION "About Pageant" 44 | FONT 8, "MS Shell Dlg" 45 | BEGIN 46 | DEFPUSHBUTTON "&Close", IDOK, 216, 88, 48, 14 47 | PUSHBUTTON "View &Licence", 101, 6, 88, 70, 14 48 | PUSHBUTTON "Visit &Web Site", 102, 140, 88, 70, 14 49 | EDITTEXT 1000, 10, 6, 250, 80, ES_READONLY | ES_MULTILINE | ES_CENTER, WS_EX_STATICEDGE 50 | END 51 | 52 | /* No accelerators used */ 53 | 914 DIALOG DISCARDABLE 50, 50, 326, 231 54 | STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU 55 | CAPTION "PuTTY Licence" 56 | FONT 8, "MS Shell Dlg" 57 | BEGIN 58 | DEFPUSHBUTTON "OK", IDOK, 148, 211, 44, 14 59 | 60 | EDITTEXT 1000, 10, 10, 306, 192, ES_READONLY | ES_MULTILINE | ES_LEFT, WS_EX_STATICEDGE 61 | END 62 | 63 | // region tray-fatty 64 | // removing duplicated definitions 65 | // endregion 66 | -------------------------------------------------------------------------------- /windows/pageants.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FauxFaux/PuTTYTray/4db528dd8477b7dbb40976fd0f1d4ff34d8bb101/windows/pageants.ico -------------------------------------------------------------------------------- /windows/pickicondialog.c: -------------------------------------------------------------------------------- 1 | #include 2 | typedef WINSHELLAPI BOOL(WINAPI *fnPickIconDlg)(HWND hWndParent, 3 | LPTSTR pszFilename, 4 | LPDWORD pdwBufferSize, 5 | LPDWORD pdwIndex); 6 | 7 | BOOL SelectIconA(HWND hWndParent, 8 | LPSTR lpszFilename, 9 | DWORD dwBufferSize, 10 | DWORD *pdwIndex) 11 | { 12 | BOOL result = FALSE; 13 | OSVERSIONINFO versioninfo; 14 | HMODULE hShell32 = LoadLibrary("shell32.dll"); 15 | versioninfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); 16 | GetVersionEx(&versioninfo); 17 | 18 | if (hShell32) { 19 | fnPickIconDlg PickIconDlg = 20 | (fnPickIconDlg)GetProcAddress(hShell32, (LPCSTR)62); 21 | if (PickIconDlg) { 22 | if (versioninfo.dwPlatformId == VER_PLATFORM_WIN32_NT) { 23 | LPWSTR pszWideName = (LPWSTR)malloc(dwBufferSize); 24 | MultiByteToWideChar( 25 | CP_ACP, 0, lpszFilename, -1, pszWideName, dwBufferSize); 26 | result = PickIconDlg( 27 | hWndParent, (LPTSTR)pszWideName, &dwBufferSize, pdwIndex); 28 | WideCharToMultiByte( 29 | CP_ACP, 0, pszWideName, -1, lpszFilename, dwBufferSize, NULL, NULL); 30 | free(pszWideName); 31 | } else { 32 | result = PickIconDlg( 33 | hWndParent, (LPTSTR)lpszFilename, &dwBufferSize, pdwIndex); 34 | } 35 | } 36 | FreeLibrary(hShell32); 37 | } 38 | 39 | return result; 40 | } 41 | 42 | BOOL SelectIconW(HWND hWndParent, 43 | LPWSTR lpszFilename, 44 | DWORD dwBufferSize, 45 | DWORD *pdwIndex) 46 | { 47 | BOOL result = FALSE; 48 | OSVERSIONINFO versioninfo; 49 | HMODULE hShell32 = LoadLibrary("shell32.dll"); 50 | versioninfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); 51 | GetVersionEx(&versioninfo); 52 | 53 | if (hShell32) { 54 | fnPickIconDlg PickIconDlg = 55 | (fnPickIconDlg)GetProcAddress(hShell32, (LPCSTR)62); 56 | if (PickIconDlg) { 57 | if (versioninfo.dwPlatformId != VER_PLATFORM_WIN32_NT) { 58 | LPSTR pszMBName = (LPSTR)malloc(dwBufferSize); 59 | WideCharToMultiByte( 60 | CP_ACP, 0, lpszFilename, -1, pszMBName, dwBufferSize, NULL, NULL); 61 | result = 62 | PickIconDlg(hWndParent, (LPTSTR)pszMBName, &dwBufferSize, pdwIndex); 63 | MultiByteToWideChar( 64 | CP_ACP, 0, pszMBName, -1, lpszFilename, dwBufferSize); 65 | free(pszMBName); 66 | } else { 67 | result = PickIconDlg( 68 | hWndParent, (LPTSTR)lpszFilename, &dwBufferSize, pdwIndex); 69 | } 70 | } 71 | FreeLibrary(hShell32); 72 | } 73 | 74 | return result; 75 | } 76 | -------------------------------------------------------------------------------- /windows/pickicondialog.h: -------------------------------------------------------------------------------- 1 | #ifndef _SELECTICON_H_ 2 | #define _SELECTICON_H_ 3 | 4 | BOOL SelectIconW(HWND hWndParent, 5 | LPWSTR lpszFilename, 6 | DWORD dwBufferSize, 7 | DWORD *pdwIndex); 8 | BOOL SelectIconA(HWND hWndParent, 9 | LPSTR lpszFilename, 10 | DWORD dwBufferSize, 11 | DWORD *pdwIndex); 12 | 13 | #ifdef _UNICODE 14 | #define SelectIcon SelectIconW 15 | #else 16 | #define SelectIcon SelectIconA 17 | #endif 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /windows/plink.rc: -------------------------------------------------------------------------------- 1 | #include "rcstuff.h" 2 | 3 | #define APPNAME "Plink" 4 | #define APPDESC "Command-line SSH, Telnet, and Rlogin client" 5 | 6 | 200 ICON "putty.ico" 7 | 8 | #include "version.rc2" 9 | -------------------------------------------------------------------------------- /windows/pscp.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FauxFaux/PuTTYTray/4db528dd8477b7dbb40976fd0f1d4ff34d8bb101/windows/pscp.ico -------------------------------------------------------------------------------- /windows/pscp.rc: -------------------------------------------------------------------------------- 1 | #include "rcstuff.h" 2 | 3 | #define APPNAME "PSCP" 4 | #define APPDESC "Command-line SCP/SFTP client" 5 | 6 | 200 ICON "pscp.ico" 7 | 8 | #include "version.rc2" 9 | -------------------------------------------------------------------------------- /windows/psftp.rc: -------------------------------------------------------------------------------- 1 | #include "rcstuff.h" 2 | 3 | #define APPNAME "PSFTP" 4 | #define APPDESC "Command-line interactive SFTP client" 5 | 6 | 200 ICON "pscp.ico" 7 | 8 | #include "version.rc2" 9 | -------------------------------------------------------------------------------- /windows/putty.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FauxFaux/PuTTYTray/4db528dd8477b7dbb40976fd0f1d4ff34d8bb101/windows/putty.ico -------------------------------------------------------------------------------- /windows/putty.manifest: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 11 | A network client and terminal emulator 12 | 13 | 14 | 16 | 22 | 23 | 24 | 25 | 26 | 28 | true 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /windows/putty.rc: -------------------------------------------------------------------------------- 1 | #include "rcstuff.h" 2 | 3 | #define APPNAME "PuTTY" 4 | #define APPDESC "SSH, Telnet and Rlogin client" 5 | 6 | #include "win_res.rc2" 7 | 8 | // region tray-fatty 9 | #include "puttygen.rc" 10 | #include "pageant.rc" 11 | // endregion 12 | 13 | #ifndef NO_MANIFESTS 14 | 1 RT_MANIFEST "putty.manifest" 15 | #endif /* NO_MANIFESTS */ 16 | -------------------------------------------------------------------------------- /windows/puttycfg.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FauxFaux/PuTTYTray/4db528dd8477b7dbb40976fd0f1d4ff34d8bb101/windows/puttycfg.ico -------------------------------------------------------------------------------- /windows/puttygen.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FauxFaux/PuTTYTray/4db528dd8477b7dbb40976fd0f1d4ff34d8bb101/windows/puttygen.ico -------------------------------------------------------------------------------- /windows/puttygen.mft: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 11 | SSH key generator for PuTTY 12 | 13 | 14 | 16 | 22 | 23 | 24 | 25 | 26 | 28 | true 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /windows/puttygen.rc: -------------------------------------------------------------------------------- 1 | /* 2 | * Windows resources for PuTTYgen. 3 | */ 4 | 5 | #include "rcstuff.h" 6 | 7 | // region tray-fatty 8 | // * removing duplicated definitions 9 | // * change all the 2-based ids to 8-based 10 | // endregion 11 | 12 | 800 ICON "puttygen.ico" 13 | 14 | 801 DIALOG DISCARDABLE 0, 0, 318, 270 15 | STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU 16 | CAPTION "PuTTY Key Generator" 17 | FONT 8, "MS Shell Dlg" 18 | BEGIN 19 | END 20 | 21 | 810 DIALOG DISCARDABLE 0, 0, 140, 60 22 | STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU 23 | CAPTION "PuTTYgen: Enter Passphrase" 24 | FONT 8, "MS Shell Dlg" 25 | BEGIN 26 | CTEXT "Enter passphrase for key", 100, 10, 6, 120, 8 27 | CTEXT "", 101, 10, 16, 120, 8 28 | EDITTEXT 102, 10, 26, 120, 12, ES_PASSWORD | ES_AUTOHSCROLL 29 | DEFPUSHBUTTON "O&K", IDOK, 20, 42, 40, 14 30 | PUSHBUTTON "&Cancel", IDCANCEL, 80, 42, 40, 14 31 | END 32 | 33 | /* Accelerators used: cl */ 34 | 813 DIALOG DISCARDABLE 140, 40, 270, 106 35 | STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU 36 | CAPTION "About PuTTYgen" 37 | FONT 8, "MS Shell Dlg" 38 | BEGIN 39 | DEFPUSHBUTTON "&Close", IDOK, 216, 88, 48, 14 40 | PUSHBUTTON "View &Licence", 101, 6, 88, 70, 14 41 | PUSHBUTTON "Visit &Web Site", 102, 140, 88, 70, 14 42 | EDITTEXT 1000, 10, 6, 250, 80, ES_READONLY | ES_MULTILINE | ES_CENTER, WS_EX_STATICEDGE 43 | END 44 | 45 | /* No accelerators used */ 46 | 814 DIALOG DISCARDABLE 50, 50, 326, 231 47 | STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU 48 | CAPTION "PuTTY Licence" 49 | FONT 8, "MS Shell Dlg" 50 | BEGIN 51 | DEFPUSHBUTTON "OK", IDOK, 148, 211, 44, 14 52 | 53 | EDITTEXT 1000, 10, 10, 306, 192, ES_READONLY | ES_MULTILINE | ES_LEFT, WS_EX_STATICEDGE 54 | END 55 | 56 | // region tray-fatty 57 | // removing duplicated definitions 58 | // endregion 59 | -------------------------------------------------------------------------------- /windows/puttyins.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FauxFaux/PuTTYTray/4db528dd8477b7dbb40976fd0f1d4ff34d8bb101/windows/puttyins.ico -------------------------------------------------------------------------------- /windows/puttytel.rc: -------------------------------------------------------------------------------- 1 | #include "rcstuff.h" 2 | 3 | #define APPNAME "PuTTYtel" 4 | #define APPDESC "Telnet and Rlogin client" 5 | 6 | #include "win_res.rc2" 7 | 8 | #ifndef NO_MANIFESTS 9 | /* FIXME */ 10 | 1 RT_MANIFEST "putty.mft" 11 | #endif /* NO_MANIFESTS */ 12 | -------------------------------------------------------------------------------- /windows/rcstuff.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Miscellaneous stuff to include in all .rc files. 3 | */ 4 | 5 | #ifndef PUTTY_RCSTUFF_H 6 | #define PUTTY_RCSTUFF_H 7 | 8 | #ifdef __LCC__ 9 | #include 10 | #else 11 | 12 | /* Some compilers, like Borland, don't have winresrc.h */ 13 | #ifndef NO_WINRESRC_H 14 | #ifndef MSVC4 15 | #include 16 | #else 17 | #include 18 | #endif 19 | #endif 20 | 21 | #endif /* end #ifdef __LCC__ */ 22 | 23 | /* Some systems don't define this, so I do it myself if necessary */ 24 | #ifndef TCS_MULTILINE 25 | #define TCS_MULTILINE 0x0200 26 | #endif 27 | 28 | /* Likewise */ 29 | #ifndef RT_MANIFEST 30 | #define RT_MANIFEST 24 31 | #endif 32 | 33 | /* LCC is the offender here. */ 34 | #ifndef VS_FF_DEBUG 35 | #define VS_FF_DEBUG 1 36 | #endif 37 | #ifndef VS_FF_PRERELEASE 38 | #define VS_FF_PRERELEASE 2 39 | #endif 40 | #ifndef VS_FF_PRIVATEBUILD 41 | #define VS_FF_PRIVATEBUILD 8 42 | #endif 43 | #ifndef VOS__WINDOWS32 44 | #define VOS__WINDOWS32 4 45 | #endif 46 | #ifndef VFT_APP 47 | #define VFT_APP 1 48 | #endif 49 | 50 | #endif /* PUTTY_RCSTUFF_H */ 51 | -------------------------------------------------------------------------------- /windows/urlhack_win.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "misc.h" 5 | #include "urlhack.h" 6 | 7 | enum 8 | { 9 | MAX_STR = 4096 10 | }; 11 | 12 | static int starts_with(const wchar_t *thing, const wchar_t *prefix) 13 | { 14 | return 0 == wcsncmp(thing, prefix, wcslen(prefix)); 15 | } 16 | 17 | void urlhack_launch_url(const char *app, const wchar_t *url) 18 | { 19 | wchar_t *u; 20 | if (app) { 21 | wchar_t app_w[MAX_STR]; 22 | size_t newlen; 23 | mbstowcs_s(&newlen, app_w, MAX_STR, app, MAX_STR); 24 | ShellExecuteW(NULL, NULL, app_w, url, NULL, SW_SHOW); 25 | return; 26 | } 27 | 28 | if ((long)ShellExecuteW(NULL, NULL, url, NULL, NULL, SW_SHOWNORMAL) > 32) { 29 | return; 30 | } 31 | 32 | // if the OS couldn't launch it, munge it towards a plausible url, then launch 33 | // that instead: 34 | u = snewn(wcslen(url) + 10, wchar_t); 35 | wcscpy(u, url); 36 | 37 | if (!starts_with(url, L"http://") && !starts_with(url, L"https://") && 38 | !starts_with(url, L"ftp://") && !starts_with(url, L"ftps://")) { 39 | if (wcsstr(url, L"ftp.")) { 40 | wcscpy(u, L"ftp://"); 41 | wcscat(u, url); 42 | } else { 43 | wcscpy(u, L"http://"); 44 | wcscat(u, url); 45 | } 46 | } 47 | 48 | if (!!wcscmp(url, u)) { 49 | ShellExecuteW(NULL, NULL, u, NULL, NULL, SW_SHOWNORMAL); 50 | } 51 | 52 | free(u); 53 | } 54 | 55 | int urlhack_is_ctrl_pressed() 56 | { 57 | return HIWORD(GetAsyncKeyState(VK_CONTROL)); 58 | } 59 | 60 | void rtfm(const char *error) 61 | { 62 | char std_msg[] = 63 | "The following error occurred when compiling the regular expression\n" 64 | "for the hyperlink support. Hyperlink detection is disabled during\n" 65 | "this session (restart PuTTY Tray to try again).\n\n"; 66 | 67 | char *full_msg = dupprintf("%s%s", std_msg, error); 68 | 69 | MessageBox(0, full_msg, "PuTTYTray Error", MB_OK); 70 | free(full_msg); 71 | } 72 | -------------------------------------------------------------------------------- /windows/version.rc2: -------------------------------------------------------------------------------- 1 | /* 2 | * Standard Windows version information. 3 | * (For inclusion in other .rc files with appropriate macro definitions.) 4 | * FIXME: This file is called '.rc2' rather than '.rc' to avoid MSVC trying 5 | * to compile it on its own when using the project files. Nicer solutions 6 | * welcome. 7 | */ 8 | 9 | #include "version.h" 10 | #include "licence.h" 11 | 12 | /* 13 | * The actual VERSIONINFO resource. 14 | */ 15 | VS_VERSION_INFO VERSIONINFO 16 | /* (None of this "fixed" info appears to be trivially user-visible on 17 | * Win98SE. The binary version does show up on Win2K.) */ 18 | FILEVERSION BINARY_VERSION 19 | PRODUCTVERSION BINARY_VERSION /* version of whole suite */ 20 | FILEFLAGSMASK VS_FF_DEBUG | VS_FF_PRERELEASE | VS_FF_PRIVATEBUILD 21 | FILEFLAGS 0x0L 22 | #if defined DEBUG 23 | | VS_FF_DEBUG 24 | #endif 25 | #if defined SNAPSHOT || defined PRERELEASE 26 | | VS_FF_PRERELEASE 27 | #elif !defined RELEASE 28 | | VS_FF_PRIVATEBUILD 29 | #endif 30 | FILEOS VOS__WINDOWS32 31 | FILETYPE VFT_APP 32 | FILESUBTYPE 0x0L /* n/a for VFT_APP */ 33 | BEGIN 34 | /* (On Win98SE and Win2K, we can see most of this on the Version tab 35 | * in the file properties in Explorer.) */ 36 | BLOCK "StringFileInfo" 37 | BEGIN 38 | /* "lang-charset" LLLLCCCC = (UK English, Unicode) */ 39 | BLOCK "080904B0" 40 | BEGIN 41 | VALUE "CompanyName", "Simon Tatham" /* required :/ */ 42 | VALUE "ProductName", "PuTTY suite" 43 | VALUE "FileDescription", APPDESC 44 | VALUE "InternalName", APPNAME 45 | VALUE "OriginalFilename", APPNAME 46 | VALUE "FileVersion", TEXTVER 47 | VALUE "ProductVersion", TEXTVER 48 | VALUE "LegalCopyright", "Copyright \251 " SHORT_COPYRIGHT_DETAILS "." 49 | #if (!defined SNAPSHOT) && (!defined RELEASE) && (!defined PRERELEASE) 50 | /* Only if VS_FF_PRIVATEBUILD. */ 51 | VALUE "PrivateBuild", TEXTVER /* NBI */ 52 | #endif 53 | END 54 | END 55 | BLOCK "VarFileInfo" 56 | BEGIN 57 | /* Once again -- same meanings -- apparently necessary */ 58 | VALUE "Translation", 0x809, 1200 59 | END 60 | END 61 | -------------------------------------------------------------------------------- /windows/website.url: -------------------------------------------------------------------------------- 1 | [InternetShortcut] 2 | URL=https://www.chiark.greenend.org.uk/~sgtatham/putty/ 3 | -------------------------------------------------------------------------------- /windows/win_res.h: -------------------------------------------------------------------------------- 1 | /* 2 | * win_res.h - constants shared between win_res.rc2 and the C code. 3 | */ 4 | 5 | #ifndef PUTTY_WIN_RES_H 6 | #define PUTTY_WIN_RES_H 7 | 8 | #define IDI_MAINICON 200 9 | #define IDI_CFGICON 201 10 | 11 | #define IDD_MAINBOX 102 12 | #define IDD_LOGBOX 110 13 | #define IDD_ABOUTBOX 111 14 | #define IDD_RECONF 112 15 | #define IDD_LICENCEBOX 113 16 | 17 | #define IDN_LIST 1001 18 | #define IDN_COPY 1002 19 | 20 | #define IDA_ICON 1001 21 | #define IDA_TEXT 1002 22 | #define IDA_LICENCE 1003 23 | #define IDA_WEB 1004 24 | 25 | #define IDC_TAB 1001 26 | #define IDC_TABSTATIC1 1002 27 | #define IDC_TABSTATIC2 1003 28 | #define IDC_TABLIST 1004 29 | #define IDC_HELPBTN 1005 30 | #define IDC_ABOUT 1006 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /windows/win_res.rc2: -------------------------------------------------------------------------------- 1 | /* 2 | * Windows resources shared between PuTTY and PuTTYtel, to be #include'd 3 | * after defining appropriate macros. 4 | * Note that many of these strings mention PuTTY. Due to restrictions in 5 | * VC's handling of string concatenation, this can't easily be fixed. 6 | * It's fixed up at runtime. 7 | * FIXME: This file is called '.rc2' rather than '.rc' to avoid MSVC trying 8 | * to compile it on its own when using the project files. Nicer solutions 9 | * welcome. 10 | */ 11 | 12 | #include "win_res.h" 13 | 14 | IDI_MAINICON ICON "putty.ico" 15 | 16 | IDI_CFGICON ICON "puttycfg.ico" 17 | 18 | /* Accelerators used: clw */ 19 | IDD_ABOUTBOX DIALOG DISCARDABLE 140, 40, 270, 136 20 | STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU 21 | CAPTION "About PuTTY" 22 | FONT 8, "MS Shell Dlg" 23 | BEGIN 24 | DEFPUSHBUTTON "&Close", IDOK, 216, 118, 48, 14 25 | PUSHBUTTON "View &Licence", IDA_LICENCE, 6, 118, 70, 14 26 | PUSHBUTTON "Visit &Web Site", IDA_WEB, 140, 118, 70, 14 27 | EDITTEXT IDA_TEXT, 10, 6, 250, 110, ES_READONLY | ES_MULTILINE | ES_CENTER, WS_EX_STATICEDGE 28 | END 29 | 30 | /* Accelerators used: aco */ 31 | IDD_MAINBOX DIALOG DISCARDABLE 0, 0, 300, 252 32 | STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU 33 | CAPTION "PuTTY Configuration" 34 | FONT 8, "MS Shell Dlg" 35 | CLASS "PuTTYConfigBox" 36 | BEGIN 37 | END 38 | 39 | /* Accelerators used: co */ 40 | IDD_LOGBOX DIALOG DISCARDABLE 100, 20, 300, 119 41 | STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU 42 | CAPTION "PuTTY Event Log" 43 | FONT 8, "MS Shell Dlg" 44 | BEGIN 45 | DEFPUSHBUTTON "&Close", IDOK, 135, 102, 44, 14 46 | PUSHBUTTON "C&opy", IDN_COPY, 81, 102, 44, 14 47 | LISTBOX IDN_LIST, 3, 3, 294, 95, LBS_HASSTRINGS | LBS_USETABSTOPS | WS_VSCROLL | LBS_EXTENDEDSEL 48 | END 49 | 50 | /* No accelerators used */ 51 | IDD_LICENCEBOX DIALOG DISCARDABLE 50, 50, 326, 231 52 | STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU 53 | CAPTION "PuTTY Licence" 54 | FONT 8, "MS Shell Dlg" 55 | BEGIN 56 | DEFPUSHBUTTON "OK", IDOK, 148, 211, 44, 14 57 | 58 | EDITTEXT IDA_TEXT, 10, 10, 306, 192, ES_READONLY | ES_MULTILINE | ES_LEFT, WS_EX_STATICEDGE 59 | END 60 | 61 | #include "version.rc2" 62 | -------------------------------------------------------------------------------- /windows/wincapi.c: -------------------------------------------------------------------------------- 1 | /* 2 | * wincapi.c: implementation of wincapi.h. 3 | */ 4 | 5 | #include "putty.h" 6 | 7 | #if !defined NO_SECURITY 8 | 9 | #define WINCAPI_GLOBAL 10 | #include "wincapi.h" 11 | 12 | int got_crypt(void) 13 | { 14 | static int attempted = FALSE; 15 | static int successful; 16 | static HMODULE crypt; 17 | 18 | if (!attempted) { 19 | attempted = TRUE; 20 | crypt = load_system32_dll("crypt32.dll"); 21 | successful = crypt && 22 | #ifdef COVERITY 23 | /* The build toolchain I use with Coverity doesn't know 24 | * about this function, so can't type-check it */ 25 | GET_WINDOWS_FUNCTION_NO_TYPECHECK(crypt, CryptProtectMemory) 26 | #else 27 | GET_WINDOWS_FUNCTION(crypt, CryptProtectMemory) 28 | #endif 29 | ; 30 | } 31 | return successful; 32 | } 33 | 34 | #endif /* !defined NO_SECURITY */ 35 | -------------------------------------------------------------------------------- /windows/wincapi.h: -------------------------------------------------------------------------------- 1 | /* 2 | * wincapi.h: Windows Crypto API functions defined in wincrypt.c 3 | * that use the crypt32 library. Also centralises the machinery 4 | * for dynamically loading that library. 5 | */ 6 | 7 | #if !defined NO_SECURITY 8 | 9 | #ifndef WINCAPI_GLOBAL 10 | #define WINCAPI_GLOBAL extern 11 | #endif 12 | 13 | DECL_WINDOWS_FUNCTION(WINCAPI_GLOBAL, 14 | BOOL, 15 | CryptProtectMemory, 16 | (LPVOID, DWORD, DWORD)); 17 | 18 | int got_crypt(void); 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /windows/windefs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * windefs.c: default settings that are specific to Windows. 3 | */ 4 | 5 | #include "putty.h" 6 | 7 | #include 8 | 9 | FontSpec *platform_default_fontspec(const char *name) 10 | { 11 | if (!strcmp(name, "Font")) 12 | return fontspec_new("Courier New", 0, 10, ANSI_CHARSET); 13 | else 14 | return fontspec_new("", 0, 0, 0); 15 | } 16 | 17 | Filename *platform_default_filename(const char *name) 18 | { 19 | if (!strcmp(name, "LogFileName")) 20 | return filename_from_str("putty.log"); 21 | else 22 | return filename_from_str(""); 23 | } 24 | 25 | char *platform_default_s(const char *name) 26 | { 27 | if (!strcmp(name, "SerialLine")) 28 | return dupstr("COM1"); 29 | return NULL; 30 | } 31 | 32 | int platform_default_i(const char *name, int def) 33 | { 34 | return def; 35 | } 36 | -------------------------------------------------------------------------------- /windows/winhelp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * winhelp.c: centralised functions to launch Windows help files, 3 | * and to decide whether to use .HLP or .CHM help in any given 4 | * situation. 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "putty.h" 13 | 14 | #ifndef NO_HTMLHELP 15 | #include 16 | #endif /* NO_HTMLHELP */ 17 | 18 | static int requested_help; 19 | static char *help_path; 20 | static int help_has_contents; 21 | #ifndef NO_HTMLHELP 22 | DECL_WINDOWS_FUNCTION(static, HWND, HtmlHelpA, (HWND, LPCSTR, UINT, DWORD)); 23 | static char *chm_path; 24 | #endif /* NO_HTMLHELP */ 25 | 26 | void init_help(void) 27 | { 28 | char b[2048], *p, *q, *r; 29 | FILE *fp; 30 | 31 | GetModuleFileName(NULL, b, sizeof(b) - 1); 32 | r = b; 33 | p = strrchr(b, '\\'); 34 | if (p && p >= r) 35 | r = p + 1; 36 | q = strrchr(b, ':'); 37 | if (q && q >= r) 38 | r = q + 1; 39 | strcpy(r, PUTTY_HELP_FILE); 40 | if ((fp = fopen(b, "r")) != NULL) { 41 | help_path = dupstr(b); 42 | fclose(fp); 43 | } else 44 | help_path = NULL; 45 | strcpy(r, PUTTY_HELP_CONTENTS); 46 | if ((fp = fopen(b, "r")) != NULL) { 47 | help_has_contents = TRUE; 48 | fclose(fp); 49 | } else 50 | help_has_contents = FALSE; 51 | 52 | #ifndef NO_HTMLHELP 53 | strcpy(r, PUTTY_CHM_FILE); 54 | if ((fp = fopen(b, "r")) != NULL) { 55 | chm_path = dupstr(b); 56 | fclose(fp); 57 | } else 58 | chm_path = NULL; 59 | if (chm_path) { 60 | HINSTANCE dllHH = load_system32_dll("hhctrl.ocx"); 61 | GET_WINDOWS_FUNCTION(dllHH, HtmlHelpA); 62 | if (!p_HtmlHelpA) { 63 | sfree(chm_path); 64 | chm_path = NULL; 65 | if (dllHH) 66 | FreeLibrary(dllHH); 67 | } 68 | } 69 | #endif /* NO_HTMLHELP */ 70 | } 71 | 72 | void shutdown_help(void) 73 | { 74 | /* Nothing to do currently. 75 | * (If we were running HTML Help single-threaded, this is where we'd 76 | * call HH_UNINITIALIZE.) */ 77 | } 78 | 79 | int has_help(void) 80 | { 81 | /* 82 | * FIXME: it would be nice here to disregard help_path on 83 | * platforms that didn't have WINHLP32. But that's probably 84 | * unrealistic, since even Vista will have it if the user 85 | * specifically downloads it. 86 | */ 87 | return (help_path != NULL 88 | #ifndef NO_HTMLHELP 89 | || chm_path 90 | #endif /* NO_HTMLHELP */ 91 | ); 92 | } 93 | 94 | void launch_help(HWND hwnd, const char *topic) 95 | { 96 | if (topic) { 97 | int colonpos = strcspn(topic, ":"); 98 | 99 | #ifndef NO_HTMLHELP 100 | if (chm_path) { 101 | char *fname; 102 | assert(topic[colonpos] != '\0'); 103 | fname = dupprintf("%s::/%s.html>main", chm_path, topic + colonpos + 1); 104 | p_HtmlHelpA(hwnd, fname, HH_DISPLAY_TOPIC, 0); 105 | sfree(fname); 106 | } else 107 | #endif /* NO_HTMLHELP */ 108 | if (help_path) { 109 | char *cmd = dupprintf("JI(`',`%.*s')", colonpos, topic); 110 | WinHelp(hwnd, help_path, HELP_COMMAND, (ULONG_PTR)cmd); 111 | sfree(cmd); 112 | } 113 | } else { 114 | #ifndef NO_HTMLHELP 115 | if (chm_path) { 116 | p_HtmlHelpA(hwnd, chm_path, HH_DISPLAY_TOPIC, 0); 117 | } else 118 | #endif /* NO_HTMLHELP */ 119 | if (help_path) { 120 | WinHelp( 121 | hwnd, help_path, help_has_contents ? HELP_FINDER : HELP_CONTENTS, 0); 122 | } 123 | } 124 | requested_help = TRUE; 125 | } 126 | 127 | void quit_help(HWND hwnd) 128 | { 129 | if (requested_help) { 130 | #ifndef NO_HTMLHELP 131 | if (chm_path) { 132 | p_HtmlHelpA(NULL, NULL, HH_CLOSE_ALL, 0); 133 | } else 134 | #endif /* NO_HTMLHELP */ 135 | if (help_path) { 136 | WinHelp(hwnd, help_path, HELP_QUIT, 0); 137 | } 138 | requested_help = FALSE; 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /windows/winnoise.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Noise generation for PuTTY's cryptographic random number 3 | * generator. 4 | */ 5 | 6 | #include 7 | 8 | #include "putty.h" 9 | #include "ssh.h" 10 | #include "storage.h" 11 | 12 | #include 13 | 14 | DECL_WINDOWS_FUNCTION(static, 15 | BOOL, 16 | CryptAcquireContextA, 17 | (HCRYPTPROV *, LPCTSTR, LPCTSTR, DWORD, DWORD)); 18 | DECL_WINDOWS_FUNCTION(static, 19 | BOOL, 20 | CryptGenRandom, 21 | (HCRYPTPROV, DWORD, BYTE *)); 22 | DECL_WINDOWS_FUNCTION(static, BOOL, CryptReleaseContext, (HCRYPTPROV, DWORD)); 23 | static HMODULE wincrypt_module = NULL; 24 | 25 | /* 26 | * This function is called once, at PuTTY startup. 27 | */ 28 | 29 | void noise_get_heavy(void (*func)(void *, int)) 30 | { 31 | HANDLE srch; 32 | WIN32_FIND_DATA finddata; 33 | DWORD pid; 34 | HCRYPTPROV crypt_provider; 35 | char winpath[MAX_PATH + 3]; 36 | 37 | GetWindowsDirectory(winpath, sizeof(winpath)); 38 | strcat(winpath, "\\*"); 39 | srch = FindFirstFile(winpath, &finddata); 40 | if (srch != INVALID_HANDLE_VALUE) { 41 | do { 42 | func(&finddata, sizeof(finddata)); 43 | } while (FindNextFile(srch, &finddata)); 44 | FindClose(srch); 45 | } 46 | 47 | pid = GetCurrentProcessId(); 48 | func(&pid, sizeof(pid)); 49 | 50 | if (!wincrypt_module) { 51 | wincrypt_module = load_system32_dll("advapi32.dll"); 52 | GET_WINDOWS_FUNCTION(wincrypt_module, CryptAcquireContextA); 53 | GET_WINDOWS_FUNCTION(wincrypt_module, CryptGenRandom); 54 | GET_WINDOWS_FUNCTION(wincrypt_module, CryptReleaseContext); 55 | } 56 | 57 | if (wincrypt_module && p_CryptAcquireContextA && p_CryptGenRandom && 58 | p_CryptReleaseContext && 59 | p_CryptAcquireContextA( 60 | &crypt_provider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { 61 | BYTE buf[32]; 62 | if (p_CryptGenRandom(crypt_provider, 32, buf)) { 63 | func(buf, sizeof(buf)); 64 | } 65 | p_CryptReleaseContext(crypt_provider, 0); 66 | } 67 | 68 | read_random_seed(func); 69 | /* Update the seed immediately, in case another instance uses it. */ 70 | random_save_seed(); 71 | } 72 | 73 | void random_save_seed(void) 74 | { 75 | int len; 76 | void *data; 77 | 78 | if (random_active) { 79 | random_get_savedata(&data, &len); 80 | write_random_seed(data, len); 81 | sfree(data); 82 | } 83 | } 84 | 85 | /* 86 | * This function is called every time the random pool needs 87 | * stirring, and will acquire the system time in all available 88 | * forms. 89 | */ 90 | void noise_get_light(void (*func)(void *, int)) 91 | { 92 | SYSTEMTIME systime; 93 | DWORD adjust[2]; 94 | BOOL rubbish; 95 | 96 | GetSystemTime(&systime); 97 | func(&systime, sizeof(systime)); 98 | 99 | GetSystemTimeAdjustment(&adjust[0], &adjust[1], &rubbish); 100 | func(&adjust, sizeof(adjust)); 101 | } 102 | 103 | /* 104 | * This function is called on a timer, and it will monitor 105 | * frequently changing quantities such as the state of physical and 106 | * virtual memory, the state of the process's message queue, which 107 | * window is in the foreground, which owns the clipboard, etc. 108 | */ 109 | void noise_regular(void) 110 | { 111 | HWND w; 112 | DWORD z; 113 | POINT pt; 114 | MEMORYSTATUS memstat; 115 | FILETIME times[4]; 116 | 117 | w = GetForegroundWindow(); 118 | random_add_noise(&w, sizeof(w)); 119 | w = GetCapture(); 120 | random_add_noise(&w, sizeof(w)); 121 | w = GetClipboardOwner(); 122 | random_add_noise(&w, sizeof(w)); 123 | z = GetQueueStatus(QS_ALLEVENTS); 124 | random_add_noise(&z, sizeof(z)); 125 | 126 | GetCursorPos(&pt); 127 | random_add_noise(&pt, sizeof(pt)); 128 | 129 | GlobalMemoryStatus(&memstat); 130 | random_add_noise(&memstat, sizeof(memstat)); 131 | 132 | GetThreadTimes(GetCurrentThread(), times, times + 1, times + 2, times + 3); 133 | random_add_noise(×, sizeof(times)); 134 | GetProcessTimes(GetCurrentProcess(), times, times + 1, times + 2, times + 3); 135 | random_add_noise(×, sizeof(times)); 136 | } 137 | 138 | /* 139 | * This function is called on every keypress or mouse move, and 140 | * will add the current Windows time and performance monitor 141 | * counter to the noise pool. It gets the scan code or mouse 142 | * position passed in. 143 | */ 144 | void noise_ultralight(unsigned long data) 145 | { 146 | DWORD wintime; 147 | LARGE_INTEGER perftime; 148 | 149 | random_add_noise(&data, sizeof(DWORD)); 150 | 151 | wintime = GetTickCount(); 152 | random_add_noise(&wintime, sizeof(DWORD)); 153 | 154 | if (QueryPerformanceCounter(&perftime)) 155 | random_add_noise(&perftime, sizeof(perftime)); 156 | } 157 | -------------------------------------------------------------------------------- /windows/winnojmp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * winnojmp.c: stub jump list functions for Windows executables that 3 | * don't update the jump list. 4 | */ 5 | 6 | void add_session_to_jumplist(const char *const sessionname) 7 | { 8 | } 9 | void remove_session_from_jumplist(const char *const sessionname) 10 | { 11 | } 12 | void clear_jumplist(void) 13 | { 14 | } 15 | -------------------------------------------------------------------------------- /windows/winnpc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Windows support module which deals with being a named-pipe client. 3 | */ 4 | 5 | #include 6 | #include 7 | 8 | #define DEFINE_PLUG_METHOD_MACROS 9 | #include "tree234.h" 10 | #include "putty.h" 11 | #include "network.h" 12 | #include "proxy.h" 13 | #include "ssh.h" 14 | 15 | #if !defined NO_SECURITY 16 | 17 | #include "winsecur.h" 18 | 19 | Socket make_handle_socket( 20 | HANDLE send_H, HANDLE recv_H, HANDLE stderr_H, Plug plug, int overlapped); 21 | 22 | Socket new_named_pipe_client(const char *pipename, Plug plug) 23 | { 24 | HANDLE pipehandle; 25 | PSID usersid, pipeowner; 26 | PSECURITY_DESCRIPTOR psd; 27 | char *err; 28 | Socket ret; 29 | 30 | assert(strncmp(pipename, "\\\\.\\pipe\\", 9) == 0); 31 | assert(strchr(pipename + 9, '\\') == NULL); 32 | 33 | while (1) { 34 | pipehandle = CreateFile(pipename, 35 | GENERIC_READ | GENERIC_WRITE, 36 | 0, 37 | NULL, 38 | OPEN_EXISTING, 39 | FILE_FLAG_OVERLAPPED, 40 | NULL); 41 | 42 | if (pipehandle != INVALID_HANDLE_VALUE) 43 | break; 44 | 45 | if (GetLastError() != ERROR_PIPE_BUSY) { 46 | err = dupprintf("Unable to open named pipe '%s': %s", 47 | pipename, 48 | win_strerror(GetLastError())); 49 | ret = new_error_socket(err, plug); 50 | sfree(err); 51 | return ret; 52 | } 53 | 54 | /* 55 | * If we got ERROR_PIPE_BUSY, wait for the server to 56 | * create a new pipe instance. (Since the server is 57 | * expected to be winnps.c, which will do that immediately 58 | * after a previous connection is accepted, that shouldn't 59 | * take excessively long.) 60 | */ 61 | if (!WaitNamedPipe(pipename, NMPWAIT_USE_DEFAULT_WAIT)) { 62 | err = dupprintf("Error waiting for named pipe '%s': %s", 63 | pipename, 64 | win_strerror(GetLastError())); 65 | ret = new_error_socket(err, plug); 66 | sfree(err); 67 | return ret; 68 | } 69 | } 70 | 71 | if ((usersid = get_user_sid()) == NULL) { 72 | CloseHandle(pipehandle); 73 | err = dupprintf("Unable to get user SID"); 74 | ret = new_error_socket(err, plug); 75 | sfree(err); 76 | return ret; 77 | } 78 | 79 | if (p_GetSecurityInfo(pipehandle, 80 | SE_KERNEL_OBJECT, 81 | OWNER_SECURITY_INFORMATION, 82 | &pipeowner, 83 | NULL, 84 | NULL, 85 | NULL, 86 | &psd) != ERROR_SUCCESS) { 87 | err = dupprintf("Unable to get named pipe security information: %s", 88 | win_strerror(GetLastError())); 89 | ret = new_error_socket(err, plug); 90 | sfree(err); 91 | CloseHandle(pipehandle); 92 | return ret; 93 | } 94 | 95 | if (!EqualSid(pipeowner, usersid)) { 96 | err = dupprintf("Owner of named pipe '%s' is not us", pipename); 97 | ret = new_error_socket(err, plug); 98 | sfree(err); 99 | CloseHandle(pipehandle); 100 | LocalFree(psd); 101 | return ret; 102 | } 103 | 104 | LocalFree(psd); 105 | 106 | return make_handle_socket(pipehandle, pipehandle, NULL, plug, TRUE); 107 | } 108 | 109 | #endif /* !defined NO_SECURITY */ 110 | -------------------------------------------------------------------------------- /windows/winpgntc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Pageant client code. 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "putty.h" 10 | #include "pageant.h" /* for AGENT_MAX_MSGLEN */ 11 | 12 | #ifndef NO_SECURITY 13 | #include "winsecur.h" 14 | #endif 15 | 16 | #define AGENT_COPYDATA_ID 0x804e50ba /* random goop */ 17 | 18 | int agent_exists(void) 19 | { 20 | HWND hwnd; 21 | hwnd = FindWindow("Pageant", "Pageant"); 22 | if (!hwnd) 23 | return FALSE; 24 | else 25 | return TRUE; 26 | } 27 | 28 | void agent_cancel_query(agent_pending_query *q) 29 | { 30 | assert(0 && "Windows agent queries are never asynchronous!"); 31 | } 32 | 33 | agent_pending_query *agent_query(void *in, 34 | int inlen, 35 | void **out, 36 | int *outlen, 37 | void (*callback)(void *, void *, int), 38 | void *callback_ctx) 39 | { 40 | HWND hwnd; 41 | char *mapname; 42 | HANDLE filemap; 43 | unsigned char *p, *ret; 44 | int id, retlen; 45 | COPYDATASTRUCT cds; 46 | SECURITY_ATTRIBUTES sa, *psa; 47 | PSECURITY_DESCRIPTOR psd = NULL; 48 | PSID usersid = NULL; 49 | 50 | *out = NULL; 51 | *outlen = 0; 52 | 53 | hwnd = FindWindow("Pageant", "Pageant"); 54 | if (!hwnd) 55 | return NULL; /* *out == NULL, so failure */ 56 | mapname = dupprintf("PageantRequest%08x", (unsigned)GetCurrentThreadId()); 57 | 58 | psa = NULL; 59 | #ifndef NO_SECURITY 60 | if (got_advapi()) { 61 | /* 62 | * Make the file mapping we create for communication with 63 | * Pageant owned by the user SID rather than the default. This 64 | * should make communication between processes with slightly 65 | * different contexts more reliable: in particular, command 66 | * prompts launched as administrator should still be able to 67 | * run PSFTPs which refer back to the owning user's 68 | * unprivileged Pageant. 69 | */ 70 | usersid = get_user_sid(); 71 | 72 | if (usersid) { 73 | psd = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, 74 | SECURITY_DESCRIPTOR_MIN_LENGTH); 75 | if (psd) { 76 | if (p_InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION) && 77 | p_SetSecurityDescriptorOwner(psd, usersid, FALSE)) { 78 | sa.nLength = sizeof(sa); 79 | sa.bInheritHandle = TRUE; 80 | sa.lpSecurityDescriptor = psd; 81 | psa = &sa; 82 | } else { 83 | LocalFree(psd); 84 | psd = NULL; 85 | } 86 | } 87 | } 88 | } 89 | #endif /* NO_SECURITY */ 90 | 91 | filemap = CreateFileMapping( 92 | INVALID_HANDLE_VALUE, psa, PAGE_READWRITE, 0, AGENT_MAX_MSGLEN, mapname); 93 | if (filemap == NULL || filemap == INVALID_HANDLE_VALUE) { 94 | sfree(mapname); 95 | return NULL; /* *out == NULL, so failure */ 96 | } 97 | p = MapViewOfFile(filemap, FILE_MAP_WRITE, 0, 0, 0); 98 | memcpy(p, in, inlen); 99 | cds.dwData = AGENT_COPYDATA_ID; 100 | cds.cbData = 1 + strlen(mapname); 101 | cds.lpData = mapname; 102 | 103 | /* 104 | * The user either passed a null callback (indicating that the 105 | * query is required to be synchronous) or CreateThread failed. 106 | * Either way, we need a synchronous request. 107 | */ 108 | id = SendMessage(hwnd, WM_COPYDATA, (WPARAM)NULL, (LPARAM)&cds); 109 | if (id > 0) { 110 | retlen = 4 + GET_32BIT(p); 111 | ret = snewn(retlen, unsigned char); 112 | if (ret) { 113 | memcpy(ret, p, retlen); 114 | *out = ret; 115 | *outlen = retlen; 116 | } 117 | } 118 | UnmapViewOfFile(p); 119 | CloseHandle(filemap); 120 | sfree(mapname); 121 | if (psd) 122 | LocalFree(psd); 123 | return NULL; 124 | } 125 | -------------------------------------------------------------------------------- /windows/winproxy.c: -------------------------------------------------------------------------------- 1 | /* 2 | * winproxy.c: Windows implementation of platform_new_connection(), 3 | * supporting an OpenSSH-like proxy command via the winhandl.c 4 | * mechanism. 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #define DEFINE_PLUG_METHOD_MACROS 11 | #include "tree234.h" 12 | #include "putty.h" 13 | #include "network.h" 14 | #include "proxy.h" 15 | 16 | Socket make_handle_socket( 17 | HANDLE send_H, HANDLE recv_H, HANDLE stderr_H, Plug plug, int overlapped); 18 | 19 | Socket platform_new_connection(SockAddr addr, 20 | const char *hostname, 21 | int port, 22 | int privport, 23 | int oobinline, 24 | int nodelay, 25 | int keepalive, 26 | Plug plug, 27 | Conf *conf) 28 | { 29 | char *cmd; 30 | HANDLE us_to_cmd, cmd_from_us; 31 | HANDLE us_from_cmd, cmd_to_us; 32 | HANDLE us_from_cmd_err, cmd_err_to_us; 33 | SECURITY_ATTRIBUTES sa; 34 | STARTUPINFO si; 35 | PROCESS_INFORMATION pi; 36 | 37 | if (conf_get_int(conf, CONF_proxy_type) != PROXY_CMD) 38 | return NULL; 39 | 40 | cmd = format_telnet_command(addr, port, conf); 41 | 42 | /* We are responsible for this and don't need it any more */ 43 | sk_addr_free(addr); 44 | 45 | { 46 | char *msg = dupprintf("Starting local proxy command: %s", cmd); 47 | plug_log(plug, 2, NULL, 0, msg, 0); 48 | sfree(msg); 49 | } 50 | 51 | /* 52 | * Create the pipes to the proxy command, and spawn the proxy 53 | * command process. 54 | */ 55 | sa.nLength = sizeof(sa); 56 | sa.lpSecurityDescriptor = NULL; /* default */ 57 | sa.bInheritHandle = TRUE; 58 | if (!CreatePipe(&us_from_cmd, &cmd_to_us, &sa, 0)) { 59 | Socket ret = 60 | new_error_socket("Unable to create pipes for proxy command", plug); 61 | sfree(cmd); 62 | return ret; 63 | } 64 | 65 | if (!CreatePipe(&cmd_from_us, &us_to_cmd, &sa, 0)) { 66 | Socket ret = 67 | new_error_socket("Unable to create pipes for proxy command", plug); 68 | sfree(cmd); 69 | CloseHandle(us_from_cmd); 70 | CloseHandle(cmd_to_us); 71 | return ret; 72 | } 73 | 74 | if (flags & FLAG_STDERR) { 75 | /* If we have a sensible stderr, the proxy command can send 76 | * its own standard error there, so we won't interfere. */ 77 | us_from_cmd_err = cmd_err_to_us = NULL; 78 | } else { 79 | /* If we don't have a sensible stderr, we should catch the 80 | * proxy command's standard error to put in our event log. */ 81 | if (!CreatePipe(&us_from_cmd_err, &cmd_err_to_us, &sa, 0)) { 82 | Socket ret = 83 | new_error_socket("Unable to create pipes for proxy command", plug); 84 | sfree(cmd); 85 | CloseHandle(us_from_cmd); 86 | CloseHandle(cmd_to_us); 87 | CloseHandle(us_to_cmd); 88 | CloseHandle(cmd_from_us); 89 | return ret; 90 | } 91 | } 92 | 93 | SetHandleInformation(us_to_cmd, HANDLE_FLAG_INHERIT, 0); 94 | SetHandleInformation(us_from_cmd, HANDLE_FLAG_INHERIT, 0); 95 | if (us_from_cmd_err != NULL) 96 | SetHandleInformation(us_from_cmd_err, HANDLE_FLAG_INHERIT, 0); 97 | 98 | si.cb = sizeof(si); 99 | si.lpReserved = NULL; 100 | si.lpDesktop = NULL; 101 | si.lpTitle = NULL; 102 | si.dwFlags = STARTF_USESTDHANDLES; 103 | si.cbReserved2 = 0; 104 | si.lpReserved2 = NULL; 105 | si.hStdInput = cmd_from_us; 106 | si.hStdOutput = cmd_to_us; 107 | si.hStdError = cmd_err_to_us; 108 | CreateProcess(NULL, 109 | cmd, 110 | NULL, 111 | NULL, 112 | TRUE, 113 | CREATE_NO_WINDOW | NORMAL_PRIORITY_CLASS, 114 | NULL, 115 | NULL, 116 | &si, 117 | &pi); 118 | CloseHandle(pi.hProcess); 119 | CloseHandle(pi.hThread); 120 | 121 | sfree(cmd); 122 | 123 | CloseHandle(cmd_from_us); 124 | CloseHandle(cmd_to_us); 125 | 126 | if (cmd_err_to_us != NULL) 127 | CloseHandle(cmd_err_to_us); 128 | 129 | return make_handle_socket( 130 | us_to_cmd, us_from_cmd, us_from_cmd_err, plug, FALSE); 131 | } 132 | -------------------------------------------------------------------------------- /windows/winsecur.h: -------------------------------------------------------------------------------- 1 | /* 2 | * winsecur.h: some miscellaneous security-related helper functions, 3 | * defined in winsecur.c, that use the advapi32 library. Also 4 | * centralises the machinery for dynamically loading that library. 5 | */ 6 | 7 | #if !defined NO_SECURITY 8 | 9 | #include 10 | 11 | #ifndef WINSECUR_GLOBAL 12 | #define WINSECUR_GLOBAL extern 13 | #endif 14 | 15 | /* 16 | * Functions loaded from advapi32.dll. 17 | */ 18 | DECL_WINDOWS_FUNCTION(WINSECUR_GLOBAL, 19 | BOOL, 20 | OpenProcessToken, 21 | (HANDLE, DWORD, PHANDLE)); 22 | DECL_WINDOWS_FUNCTION(WINSECUR_GLOBAL, 23 | BOOL, 24 | GetTokenInformation, 25 | (HANDLE, TOKEN_INFORMATION_CLASS, LPVOID, DWORD, PDWORD)); 26 | DECL_WINDOWS_FUNCTION(WINSECUR_GLOBAL, 27 | BOOL, 28 | InitializeSecurityDescriptor, 29 | (PSECURITY_DESCRIPTOR, DWORD)); 30 | DECL_WINDOWS_FUNCTION(WINSECUR_GLOBAL, 31 | BOOL, 32 | SetSecurityDescriptorOwner, 33 | (PSECURITY_DESCRIPTOR, PSID, BOOL)); 34 | DECL_WINDOWS_FUNCTION(WINSECUR_GLOBAL, 35 | DWORD, 36 | GetSecurityInfo, 37 | (HANDLE, 38 | SE_OBJECT_TYPE, 39 | SECURITY_INFORMATION, 40 | PSID *, 41 | PSID *, 42 | PACL *, 43 | PACL *, 44 | PSECURITY_DESCRIPTOR *)); 45 | DECL_WINDOWS_FUNCTION( 46 | WINSECUR_GLOBAL, 47 | DWORD, 48 | SetSecurityInfo, 49 | (HANDLE, SE_OBJECT_TYPE, SECURITY_INFORMATION, PSID, PSID, PACL, PACL)); 50 | DECL_WINDOWS_FUNCTION(WINSECUR_GLOBAL, 51 | DWORD, 52 | SetEntriesInAclA, 53 | (ULONG, PEXPLICIT_ACCESS, PACL, PACL *)); 54 | int got_advapi(void); 55 | 56 | /* 57 | * Find the SID describing the current user. The return value (if not 58 | * NULL for some error-related reason) is smalloced. 59 | */ 60 | PSID get_user_sid(void); 61 | 62 | /* 63 | * Construct a PSECURITY_DESCRIPTOR of the type used for named pipe 64 | * servers, i.e. allowing access only to the current user id and also 65 | * only local (i.e. not over SMB) connections. 66 | * 67 | * If this function returns TRUE, then 'psd' and 'acl' will have been 68 | * filled in with memory allocated using LocalAlloc (and hence must be 69 | * freed later using LocalFree). If it returns FALSE, then instead 70 | * 'error' has been filled with a dynamically allocated error message. 71 | */ 72 | int make_private_security_descriptor(DWORD permissions, 73 | PSECURITY_DESCRIPTOR *psd, 74 | PACL *acl, 75 | char **error); 76 | 77 | #endif 78 | -------------------------------------------------------------------------------- /windows/wintime.c: -------------------------------------------------------------------------------- 1 | /* 2 | * wintime.c - Avoid trouble with time() returning (time_t)-1 on Windows. 3 | */ 4 | 5 | #include "putty.h" 6 | #include 7 | 8 | struct tm ltime(void) 9 | { 10 | SYSTEMTIME st; 11 | struct tm tm; 12 | 13 | memset(&tm, 0, sizeof(tm)); /* in case there are any other fields */ 14 | 15 | GetLocalTime(&st); 16 | tm.tm_sec = st.wSecond; 17 | tm.tm_min = st.wMinute; 18 | tm.tm_hour = st.wHour; 19 | tm.tm_mday = st.wDay; 20 | tm.tm_mon = st.wMonth - 1; 21 | tm.tm_year = (st.wYear >= 1900 ? st.wYear - 1900 : 0); 22 | tm.tm_wday = st.wDayOfWeek; 23 | tm.tm_yday = -1; /* GetLocalTime doesn't tell us */ 24 | tm.tm_isdst = 0; /* GetLocalTime doesn't tell us */ 25 | return tm; 26 | } 27 | -------------------------------------------------------------------------------- /windows/winx11.c: -------------------------------------------------------------------------------- 1 | /* 2 | * winx11.c: fetch local auth data for X forwarding. 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "putty.h" 10 | #include "ssh.h" 11 | 12 | void platform_get_x11_auth(struct X11Display *disp, Conf *conf) 13 | { 14 | char *xauthpath = conf_get_filename(conf, CONF_xauthfile)->path; 15 | if (xauthpath[0]) 16 | x11_get_auth_from_authfile(disp, xauthpath); 17 | } 18 | 19 | const int platform_uses_x11_unix_by_default = FALSE; 20 | --------------------------------------------------------------------------------