├── .gitignore ├── Buildscr ├── Buildscr.cv ├── CHECKLST.txt ├── LATEST.VER ├── LICENCE ├── README ├── Recipe ├── agentf.c ├── 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 ├── clicons.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 ├── gdb.py ├── kh2reg.py ├── logparse.pl ├── logrewrap.pl ├── make1305.py ├── nice-ibeam.cur ├── plinkfs └── samplekex.py ├── cproxy.c ├── defs.h ├── dialog.c ├── dialog.h ├── doc ├── Makefile ├── blurb.but ├── chm.css ├── config.but ├── errors.but ├── faq.but ├── feedback.but ├── gs.but ├── index.but ├── intro.but ├── man-pag.but ├── man-pg.but ├── man-pl.but ├── man-pscp.but ├── man-psft.but ├── man-ptel.but ├── man-pter.but ├── man-putt.but ├── mancfg.but ├── manpages.but ├── pageant.but ├── pgpkeys.but ├── plink.but ├── pscp.but ├── psftp.but ├── pubkey.but ├── site.but ├── sshnames.but ├── udp.but ├── using.but └── vids.but ├── ecc.c ├── ecc.h ├── errsock.c ├── fuzzterm.c ├── icons ├── Makefile ├── cicon.pl ├── icon.pl ├── macicon.py └── mkicon.py ├── import.c ├── ldisc.c ├── ldisc.h ├── licence.pl ├── logging.c ├── mainchan.c ├── marshal.c ├── marshal.h ├── memory.c ├── millerrabin.c ├── minibidi.c ├── misc.c ├── misc.h ├── miscucs.c ├── mkauto.sh ├── mkfiles.pl ├── mksrcarc.sh ├── mkunxarc.sh ├── mpint.c ├── mpint.h ├── mpint_i.h ├── mpunsafe.c ├── mpunsafe.h ├── network.h ├── nocmdline.c ├── nocproxy.c ├── nogss.c ├── noprint.c ├── noproxy.c ├── norand.c ├── noshare.c ├── noterm.c ├── notiming.c ├── nullplug.c ├── pageant.c ├── pageant.h ├── pgssapi.c ├── pgssapi.h ├── pinger.c ├── pockle.c ├── portfwd.c ├── pproxy.c ├── primecandidate.c ├── proxy.c ├── proxy.h ├── pscp.c ├── psftp.c ├── psftp.h ├── psftpcommon.c ├── psocks.c ├── psocks.h ├── putty.h ├── puttymem.h ├── puttyps.h ├── raw.c ├── release.pl ├── resource.h ├── rlogin.c ├── scpserver.c ├── sesschan.c ├── sessprep.c ├── settings.c ├── sftp.c ├── sftp.h ├── sftpcommon.c ├── sftpserver.c ├── sign.sh ├── smallprimes.c ├── ssh.c ├── ssh.h ├── ssh1bpp.c ├── ssh1censor.c ├── ssh1connection-client.c ├── ssh1connection-server.c ├── ssh1connection.c ├── ssh1connection.h ├── ssh1login-server.c ├── ssh1login.c ├── ssh2bpp-bare.c ├── ssh2bpp.c ├── ssh2censor.c ├── ssh2connection-client.c ├── ssh2connection-server.c ├── ssh2connection.c ├── ssh2connection.h ├── ssh2kex-client.c ├── ssh2kex-server.c ├── ssh2transhk.c ├── ssh2transport.c ├── ssh2transport.h ├── ssh2userauth-server.c ├── ssh2userauth.c ├── sshaes.c ├── ssharcf.c ├── sshauxcrypt.c ├── sshbcrypt.c ├── sshblowf.c ├── sshblowf.h ├── sshbpp.h ├── sshccp.c ├── sshchan.h ├── sshcommon.c ├── sshcr.h ├── sshcrc.c ├── sshcrcda.c ├── sshdes.c ├── sshdh.c ├── sshdss.c ├── sshdssg.c ├── sshecc.c ├── sshecdsag.c ├── sshgss.h ├── sshgssc.c ├── sshgssc.h ├── sshhmac.c ├── sshkeygen.h ├── sshmac.c ├── sshmd5.c ├── sshnogss.c ├── sshppl.h ├── sshprime.c ├── sshprng.c ├── sshpubk.c ├── sshrand.c ├── sshrsa.c ├── sshrsag.c ├── sshserver.c ├── sshserver.h ├── sshsh256.c ├── sshsh512.c ├── sshsha.c ├── sshsha3.c ├── sshshare.c ├── sshsignals.h ├── sshttymodes.h ├── sshutils.c ├── sshverstring.c ├── sshzlib.c ├── storage.h ├── stripctrl.c ├── supdup.c ├── telnet.c ├── terminal.c ├── terminal.h ├── test ├── agenttest.py ├── agenttestdata.py ├── agenttestgen.py ├── colours.txt ├── cryptsuite.py ├── desref.py ├── display.txt ├── eccref.py ├── lattrs.txt ├── mpu-check.pl ├── numbertheory.py ├── primegen.py ├── sclog │ ├── .gitignore │ ├── CMakeLists.txt │ └── sclog.c ├── scocols.txt ├── ssh.py ├── testcrypt.py ├── utf8.txt └── vt100.txt ├── testback.c ├── testcrypt.c ├── testcrypt.h ├── testsc.c ├── testzlib.c ├── 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 ├── procnet.c ├── pterm.bundle ├── pterm.plist ├── putty.bundle ├── putty.plist ├── unix.h ├── ux_x11.c ├── uxagentc.c ├── uxagentsock.c ├── uxcfg.c ├── uxcliloop.c ├── uxcons.c ├── uxfdsock.c ├── uxgen.c ├── uxgss.c ├── uxmisc.c ├── uxnet.c ├── uxnogtk.c ├── uxnoise.c ├── uxpeer.c ├── uxpgnt.c ├── uxplink.c ├── uxpoll.c ├── uxprint.c ├── uxproxy.c ├── uxpsusan.c ├── uxpterm.c ├── uxpty.c ├── uxputty.c ├── uxsel.c ├── uxser.c ├── uxserver.c ├── uxsftp.c ├── uxsftpserver.c ├── uxshare.c ├── uxsignal.c ├── uxsocks.c ├── uxstore.c ├── uxucs.c ├── uxutils.c ├── x11misc.c ├── x11misc.h ├── xkeysym.c ├── xpmptcfg.c ├── xpmpterm.c ├── xpmpucfg.c └── xpmputty.c ├── utils.c ├── version.c ├── version.h ├── wcwidth.c ├── wildcard.c ├── windows ├── README-msi.txt ├── installer.wxs ├── make_install_images.sh ├── msifixup.py ├── pageant.ico ├── pageant.mft ├── pageant.rc ├── pageants.ico ├── plink.rc ├── pscp.ico ├── pscp.rc ├── psftp.rc ├── putty.ico ├── putty.mft ├── putty.rc ├── puttycfg.ico ├── puttygen.ico ├── puttygen.mft ├── puttygen.rc ├── puttyins.ico ├── puttytel.mft ├── puttytel.rc ├── rcstuff.h ├── sizetip.c ├── version.rc2 ├── website.url ├── win_res.h ├── win_res.rc2 ├── wincapi.c ├── wincapi.h ├── wincfg.c ├── wincliloop.c ├── wincons.c ├── winctrls.c ├── windefs.c ├── windlg.c ├── window.c ├── wingss.c ├── winhandl.c ├── winhelp.c ├── winhelp.h ├── winhelp.rc2 ├── winhsock.c ├── winjump.c ├── winmisc.c ├── winmiscs.c ├── winnet.c ├── winnohlp.c ├── winnoise.c ├── winnojmp.c ├── winnpc.c ├── winnps.c ├── winpgen.c ├── winpgnt.c ├── winpgntc.c ├── winplink.c ├── winprint.c ├── winproxy.c ├── winseat.h ├── winsecur.c ├── winsecur.h ├── winselcli.c ├── winselgui.c ├── winser.c ├── winsftp.c ├── winshare.c ├── winsocks.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.mgw 23 | /Makefile.vc 24 | /Makefile.lcc 25 | /MSVC 26 | /*.log 27 | /*.GID 28 | /local 29 | /Output 30 | /pageant 31 | /plink 32 | /pscp 33 | /psftp 34 | /putty 35 | /puttytel 36 | /puttygen 37 | /pterm 38 | /puttyapp 39 | /ptermapp 40 | /psusan 41 | /osxlaunch 42 | /uppity 43 | /psocks 44 | /unix/PuTTY.app 45 | /unix/Pterm.app 46 | /fuzzterm 47 | /testcrypt 48 | /testsc 49 | /testzlib 50 | /cgtest 51 | /scctest 52 | /*.DSA 53 | /*.RSA 54 | /*.cnt 55 | /*.hlp 56 | /.bmake 57 | /build.log 58 | /build.out 59 | /uxconfig.h 60 | /empty.h 61 | /config.status 62 | /Makefile.am 63 | /Makefile.in 64 | /Makefile 65 | /compile 66 | /config.status 67 | /configure 68 | /stamp-h1 69 | /aclocal.m4 70 | /ar-lib 71 | /autom4te.cache 72 | /depcomp 73 | /install-sh 74 | /local 75 | /missing 76 | /uxconfig.in 77 | /uxconfig.in~ 78 | /uxconfig.h 79 | /licence.h 80 | /*.a 81 | /charset/sbcsdat.c 82 | /contrib/cygtermd/cygtermd.exe 83 | /doc/*.html 84 | /doc/*.txt 85 | /doc/*.cnt 86 | /doc/*.hlp 87 | /doc/*.gid 88 | /doc/*.GID 89 | /doc/*.chm 90 | /doc/*.log 91 | /doc/*.1 92 | /doc/*.info 93 | /doc/vstr.but 94 | /doc/*.hhp 95 | /doc/*.hhc 96 | /doc/*.hhk 97 | /doc/licence.but 98 | /doc/copy.but 99 | /icons/*.pam 100 | /icons/*.png 101 | /icons/*.ico 102 | /icons/*.icns 103 | /icons/*.xpm 104 | /icons/*.c 105 | /unix/Makefile.gtk 106 | /unix/Makefile.ux 107 | /unix/Makefile.local 108 | /unix/empty.h 109 | /unix/plink 110 | /unix/pterm 111 | /unix/putty 112 | /unix/puttytel 113 | /unix/psftp 114 | /unix/pscp 115 | /unix/puttygen 116 | /unix/stamp-h1 117 | /unix/*.log 118 | /unix/.deps 119 | /windows/*.pdb 120 | /windows/*.ilk 121 | /windows/*.res 122 | /windows/*.RES 123 | /windows/*.pch 124 | /windows/*.rsp 125 | /windows/*.obj 126 | /windows/*.exe 127 | /windows/*.ncb 128 | /windows/*.plg 129 | /windows/*.dsw 130 | /windows/*.opt 131 | /windows/*.dsp 132 | /windows/*.tds 133 | /windows/*.td2 134 | /windows/*.map 135 | /windows/*.rcpp 136 | /windows/Makefile.clangcl 137 | /windows/Makefile.mgw 138 | /windows/Makefile.vc 139 | /windows/Makefile.lcc 140 | /windows/MSVC 141 | /windows/DEVCPP 142 | /windows/VS2010 143 | /windows/VS2012 144 | /windows/*.log 145 | /windows/*.GID 146 | /windows/local 147 | /windows/Output 148 | /windows/*.DSA 149 | /windows/*.RSA 150 | /windows/*.cnt 151 | /windows/*.hlp 152 | /windows/.bmake 153 | /windows/*.sln 154 | /windows/*.suo 155 | /windows/*.msi 156 | /windows/*.wixobj 157 | /windows/*.wixpdb 158 | -------------------------------------------------------------------------------- /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 -DNO_SECUREZEROMEMORY -D_FORCE_SOFTWARE_AES" 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.74 2 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | PuTTY is copyright 1997-2020 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, Lorenz Diener, Christian 7 | Brabandt, Jeff Smith, Pavel Kryukov, Maxim Kuznetsov, Svyatoslav 8 | Kuzmich, Nico Williams, Viktor Dukhovni, Josh Dersch, Lars Brinkhoff, 9 | and CORE SDI S.A. 10 | 11 | Permission is hereby granted, free of charge, to any person 12 | obtaining a copy of this software and associated documentation files 13 | (the "Software"), to deal in the Software without restriction, 14 | including without limitation the rights to use, copy, modify, merge, 15 | publish, distribute, sublicense, and/or sell copies of the Software, 16 | and to permit persons to whom the Software is furnished to do so, 17 | subject to the following conditions: 18 | 19 | The above copyright notice and this permission notice shall be 20 | included in all copies or substantial portions of the Software. 21 | 22 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 23 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 24 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 25 | NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE 26 | FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 27 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 28 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 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(strbuf *query, void **out, int *outlen) 15 | { 16 | agent_pending_query *pending; 17 | 18 | pending = agent_query(query, out, outlen, NULL, 0); 19 | assert(!pending); 20 | } 21 | 22 | -------------------------------------------------------------------------------- /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 | const struct BackendVtable *const backends[] = { 26 | &ssh_backend, 27 | &telnet_backend, 28 | &rlogin_backend, 29 | &supdup_backend, 30 | &raw_backend, 31 | &sshconn_backend, 32 | NULL 33 | }; 34 | -------------------------------------------------------------------------------- /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 | const struct BackendVtable *const backends[] = { 26 | &ssh_backend, 27 | &telnet_backend, 28 | &rlogin_backend, 29 | &supdup_backend, 30 | &raw_backend, 31 | &serial_backend, 32 | &sshconn_backend, 33 | NULL 34 | }; 35 | -------------------------------------------------------------------------------- /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 | const int be_default_protocol = -1; 10 | 11 | const struct BackendVtable *const backends[] = { 12 | NULL 13 | }; 14 | -------------------------------------------------------------------------------- /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 | const struct BackendVtable *const backends[] = { 14 | &telnet_backend, 15 | &rlogin_backend, 16 | &supdup_backend, 17 | &raw_backend, 18 | &serial_backend, 19 | NULL 20 | }; 21 | -------------------------------------------------------------------------------- /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 | const struct BackendVtable *const backends[] = { 14 | &telnet_backend, 15 | &rlogin_backend, 16 | &supdup_backend, 17 | &raw_backend, 18 | NULL 19 | }; 20 | -------------------------------------------------------------------------------- /be_ssh.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Linking module for programs that are restricted to only using 3 | * SSH-type protocols (pscp and psftp). These still have a choice of 4 | * two actual backends, because they can also speak PROT_SSHCONN. 5 | */ 6 | 7 | #include 8 | #include "putty.h" 9 | 10 | const int be_default_protocol = PROT_SSH; 11 | 12 | const struct BackendVtable *const backends[] = { 13 | &ssh_backend, 14 | &sshconn_backend, 15 | NULL 16 | }; 17 | -------------------------------------------------------------------------------- /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, int *inlen, 44 | char *output, int outlen, 45 | int charset, charset_state *state, 46 | const char *errstr, int errlen) 47 | { 48 | charset_spec const *spec = charset_find_spec(charset); 49 | charset_state localstate; 50 | struct charset_emit_param param; 51 | 52 | param.output = output; 53 | param.outlen = outlen; 54 | param.stopped = 0; 55 | 56 | /* 57 | * charset_emit will expect a valid errstr. 58 | */ 59 | if (!errstr) { 60 | /* *shrug* this is good enough, and consistent across all SBCS... */ 61 | param.errstr = "."; 62 | param.errlen = 1; 63 | } 64 | param.errstr = errstr; 65 | param.errlen = errlen; 66 | 67 | if (!state) { 68 | localstate.s0 = 0; 69 | } else { 70 | localstate = *state; /* structure copy */ 71 | } 72 | state = &localstate; 73 | 74 | while (*inlen > 0) { 75 | int lenbefore = param.output - output; 76 | spec->write(spec, **input, &localstate, charset_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 | return param.output - output; 92 | } 93 | -------------------------------------------------------------------------------- /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, long int input_chr, 27 | charset_state *state, 28 | void (*emit)(void *ctx, long int output), void *emitctx); 29 | /* 30 | * A function to read Unicode characters and output in this 31 | * character set. The `emit' function expects to get byte 32 | * values passed to it; it should be sent ERROR for any 33 | * non-representable characters on the input. 34 | */ 35 | void (*write)(charset_spec const *charset, long int input_chr, 36 | charset_state *state, 37 | void (*emit)(void *ctx, long int output), void *emitctx); 38 | void const *data; 39 | }; 40 | 41 | /* 42 | * This is the format of `data' used by the SBCS read and write 43 | * functions; so it's the format used in all SBCS definitions. 44 | */ 45 | struct sbcs_data { 46 | /* 47 | * This is a simple mapping table converting each SBCS position 48 | * to a Unicode code point. Some positions may contain ERROR, 49 | * indicating that that byte value is not defined in the SBCS 50 | * in question and its occurrence in input is an error. 51 | */ 52 | unsigned long sbcs2ucs[256]; 53 | 54 | /* 55 | * This lookup table is used to convert Unicode back to the 56 | * SBCS. It consists of the valid byte values in the SBCS, 57 | * sorted in order of their Unicode translation. So given a 58 | * Unicode value U, you can do a binary search on this table 59 | * using the above table as a lookup: when testing the Xth 60 | * position in this table, you branch according to whether 61 | * sbcs2ucs[ucs2sbcs[X]] is less than, greater than, or equal 62 | * to U. 63 | * 64 | * Note that since there may be fewer than 256 valid byte 65 | * values in a particular SBCS, we must supply the length of 66 | * this table as well as the contents. 67 | */ 68 | unsigned char ucs2sbcs[256]; 69 | int nvalid; 70 | }; 71 | 72 | /* 73 | * Prototypes for internal library functions. 74 | */ 75 | charset_spec const *charset_find_spec(int charset); 76 | void read_sbcs(charset_spec const *charset, long int input_chr, 77 | charset_state *state, 78 | void (*emit)(void *ctx, long int output), void *emitctx); 79 | void write_sbcs(charset_spec const *charset, long int input_chr, 80 | charset_state *state, 81 | void (*emit)(void *ctx, long int output), void *emitctx); 82 | 83 | /* 84 | * Placate compiler warning about unused parameters, of which we 85 | * expect to have some in this library. 86 | */ 87 | #define UNUSEDARG(x) ( (x) = (x) ) 88 | 89 | #endif /* charset_internal_h */ 90 | -------------------------------------------------------------------------------- /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, long int input_chr, 16 | charset_state *state, 17 | void (*emit)(void *ctx, long int output), void *emitctx) 18 | { 19 | const struct sbcs_data *sd = charset->data; 20 | 21 | UNUSEDARG(state); 22 | 23 | emit(emitctx, sd->sbcs2ucs[input_chr]); 24 | } 25 | 26 | void write_sbcs(charset_spec const *charset, long int input_chr, 27 | charset_state *state, 28 | void (*emit)(void *ctx, long int output), void *emitctx) 29 | { 30 | const struct sbcs_data *sd = charset->data; 31 | int i, j, k, c; 32 | 33 | UNUSEDARG(state); 34 | 35 | /* 36 | * Binary-search in the ucs2sbcs table. 37 | */ 38 | i = -1; 39 | j = sd->nvalid; 40 | while (i+1 < j) { 41 | k = (i+j)/2; 42 | c = sd->ucs2sbcs[k]; 43 | if (input_chr < sd->sbcs2ucs[c]) 44 | j = k; 45 | else if (input_chr > sd->sbcs2ucs[c]) 46 | i = k; 47 | else { 48 | emit(emitctx, c); 49 | return; 50 | } 51 | } 52 | emit(emitctx, ERROR); 53 | } 54 | -------------------------------------------------------------------------------- /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, int *inlen, 50 | wchar_t *output, int outlen, 51 | int charset, charset_state *state, 52 | const wchar_t *errstr, int errlen) 53 | { 54 | charset_spec const *spec = charset_find_spec(charset); 55 | charset_state localstate; 56 | struct unicode_emit_param param; 57 | 58 | param.output = output; 59 | param.outlen = outlen; 60 | param.errstr = errstr; 61 | param.errlen = errlen; 62 | param.stopped = 0; 63 | 64 | if (!state) { 65 | localstate.s0 = 0; 66 | } else { 67 | localstate = *state; /* structure copy */ 68 | } 69 | 70 | while (*inlen > 0) { 71 | int lenbefore = param.output - output; 72 | spec->read(spec, (unsigned char)**input, &localstate, 73 | unicode_emit, ¶m); 74 | if (param.stopped) { 75 | /* 76 | * The emit function has _tried_ to output some 77 | * characters, but ran up against the end of the 78 | * buffer. Leave immediately, and return what happened 79 | * _before_ attempting to process this character. 80 | */ 81 | return lenbefore; 82 | } 83 | if (state) 84 | *state = localstate; /* structure copy */ 85 | (*input)++; 86 | (*inlen)--; 87 | } 88 | 89 | return param.output - output; 90 | } 91 | -------------------------------------------------------------------------------- /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++; q++; 88 | } 89 | if (!*p && !*q) 90 | return xencs[i].charset; 91 | } 92 | 93 | return CS_NONE; /* not found */ 94 | } 95 | -------------------------------------------------------------------------------- /clicons.c: -------------------------------------------------------------------------------- 1 | /* 2 | * clicons.c: definitions limited to tools that link against both 3 | * console.c and cmdline.c. 4 | */ 5 | 6 | #include "putty.h" 7 | 8 | static const LogPolicyVtable console_cli_logpolicy_vt = { 9 | .eventlog = console_eventlog, 10 | .askappend = console_askappend, 11 | .logging_error = console_logging_error, 12 | .verbose = cmdline_lp_verbose, 13 | }; 14 | LogPolicy console_cli_logpolicy[1] = {{ &console_cli_logpolicy_vt }}; 15 | -------------------------------------------------------------------------------- /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/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 | void *p; 14 | p = malloc(size); 15 | if (!p) { 16 | fatal("out of memory"); 17 | } 18 | return p; 19 | } 20 | 21 | void sfree(void *p) { 22 | if (p) { 23 | free(p); 24 | } 25 | } 26 | 27 | void *srealloc(void *p, size_t size) { 28 | void *q; 29 | if (p) { 30 | q = realloc(p, size); 31 | } else { 32 | q = malloc(size); 33 | } 34 | if (!q) 35 | fatal("out of memory"); 36 | return q; 37 | } 38 | 39 | char *dupstr(const char *s) { 40 | char *r = smalloc(1+strlen(s)); 41 | strcpy(r,s); 42 | return r; 43 | } 44 | -------------------------------------------------------------------------------- /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) \ 39 | ( (type *) smalloc (sizeof (type)) ) 40 | 41 | /* 42 | * snewn allocates n instances of a given type, for arrays. 43 | */ 44 | #define snewn(number, type) \ 45 | ( (type *) smalloc ((number) * sizeof (type)) ) 46 | 47 | /* 48 | * sresize wraps realloc so that you specify the new number of 49 | * elements and the type of the element, with the same type- 50 | * checking advantages. Also type-checks the input pointer. 51 | */ 52 | #define sresize(array, number, type) \ 53 | ( (void)sizeof((array)-(type *)0), \ 54 | (type *) srealloc ((array), (number) * sizeof (type)) ) 55 | 56 | #endif /* UMLWRAP_MALLOC_H */ 57 | -------------------------------------------------------------------------------- /contrib/cygtermd/pty.h: -------------------------------------------------------------------------------- 1 | /* 2 | * pty.h - declare functions for pty setup 3 | */ 4 | 5 | #ifndef CYGTERMD_PTY_H 6 | #define CYGTERMD_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, char **program_args); 27 | 28 | #endif /* CYGTERMD_PTY_H */ 29 | -------------------------------------------------------------------------------- /contrib/cygtermd/telnet.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Header declaring Telnet-handling functions. 3 | */ 4 | 5 | #ifndef CYGTERMD_TELNET_H 6 | #define CYGTERMD_TELNET_H 7 | 8 | #include "sel.h" 9 | 10 | typedef struct Telnet 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 /* CYGTERMD_TELNET_H */ 42 | -------------------------------------------------------------------------------- /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/github/putty/7003b43963aef6cdf2841c2a882a684025f1d806/contrib/nice-ibeam.cur -------------------------------------------------------------------------------- /contrib/plinkfs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Wrapper around the FUSE 'sshfs' client, which arranges to use Plink 4 | # as the SSH transport subcommand. 5 | # 6 | # This is not totally trivial because sshfs assumes slightly more of 7 | # OpenSSH's command-line syntax than Plink supports. So we actually 8 | # give sshfs a subcommand which is this script itself, re-invoked with 9 | # the --helper option. 10 | 11 | import sys 12 | import os 13 | import shlex 14 | 15 | if sys.argv[1:2] == ["--helper"]: 16 | # Helper mode. Strip OpenSSH-specific '-o' options from the 17 | # command line, and invoke Plink. 18 | plink_command = ["plink"] 19 | 20 | it = iter(sys.argv) 21 | next(it) # discard command name 22 | next(it) # discard --helper 23 | 24 | for arg in it: 25 | if arg == "-o": 26 | next(it) # discard -o option 27 | elif arg.startswith("-o"): 28 | pass 29 | else: 30 | plink_command.append(arg) 31 | 32 | os.execvp(plink_command[0], plink_command) 33 | 34 | else: 35 | # Normal mode, invoked by the user. 36 | sshfs_command = [ 37 | "sshfs", "-o", "ssh_command={} --helper".format( 38 | os.path.realpath(__file__)) 39 | ] + sys.argv[1:] 40 | 41 | os.execvp(sshfs_command[0], sshfs_command) 42 | -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | all: man index.html 2 | 3 | # Decide on the versionid policy. 4 | # 5 | # If the user has passed in $(VERSION) on the command line (`make 6 | # VERSION="Release 0.56"'), we use that as an explicit version string. 7 | # Otherwise, we use `svnversion' to examine the checked-out 8 | # documentation source, and if that returns a single revision number 9 | # then we invent a version string reflecting just that number. Failing 10 | # _that_, we resort to versionids.but which gives 'version 11 | # unavailable'. 12 | # 13 | # So here, we define VERSION using svnversion if it isn't already 14 | # defined ... 15 | ifndef VERSION 16 | SVNVERSION=$(shell test -d .svn && svnversion .) 17 | BADCHARS=$(findstring :,$(SVNVERSION))$(findstring S,$(SVNVERSION)) 18 | ifeq ($(BADCHARS),) 19 | ifneq ($(SVNVERSION),) 20 | ifneq ($(SVNVERSION),exported) 21 | VERSION=Built from revision $(patsubst M,,$(SVNVERSION)) 22 | endif 23 | endif 24 | endif 25 | endif 26 | # ... and now, we condition our build behaviour on whether or not 27 | # VERSION _is_ defined. 28 | ifdef VERSION 29 | VERSIONIDS=vstr 30 | vstr.but: FORCE 31 | printf '\\versionid $(VERSION)\n' > vstr.but 32 | FORCE:; 33 | else 34 | VERSIONIDS=vids 35 | endif 36 | 37 | CHAPTERS := $(SITE) copy blurb intro gs using config pscp psftp plink 38 | CHAPTERS += pubkey pageant errors faq feedback licence udp pgpkeys sshnames 39 | CHAPTERS += index $(VERSIONIDS) 40 | 41 | INPUTS = $(patsubst %,%.but,$(CHAPTERS)) 42 | 43 | # This is temporary. Hack it locally or something. 44 | HALIBUT = halibut 45 | 46 | index.html: $(INPUTS) 47 | $(HALIBUT) --text --html --chm $(INPUTS) 48 | 49 | # During formal builds it's useful to be able to build this one alone. 50 | putty.chm: $(INPUTS) 51 | $(HALIBUT) --chm $(INPUTS) 52 | 53 | # We don't ship this any more. 54 | putty.hlp: $(INPUTS) 55 | $(HALIBUT) --winhelp $(INPUTS) 56 | 57 | putty.info: $(INPUTS) 58 | $(HALIBUT) --info $(INPUTS) 59 | 60 | MKMAN = $(HALIBUT) --man=$@ mancfg.but $< 61 | MANPAGES = putty.1 puttygen.1 plink.1 pscp.1 psftp.1 puttytel.1 pterm.1 \ 62 | pageant.1 63 | man: $(MANPAGES) 64 | 65 | putty.1: man-putt.but mancfg.but; $(MKMAN) 66 | puttygen.1: man-pg.but mancfg.but; $(MKMAN) 67 | plink.1: man-pl.but mancfg.but; $(MKMAN) 68 | pscp.1: man-pscp.but mancfg.but; $(MKMAN) 69 | psftp.1: man-psft.but mancfg.but; $(MKMAN) 70 | puttytel.1: man-ptel.but mancfg.but; $(MKMAN) 71 | pterm.1: man-pter.but mancfg.but; $(MKMAN) 72 | pageant.1: man-pag.but mancfg.but; $(MKMAN) 73 | 74 | mostlyclean: 75 | rm -f *.html *.txt *.hlp *.cnt *.1 *.info vstr.but *.hh[pck] 76 | clean: mostlyclean 77 | rm -f *.chm 78 | -------------------------------------------------------------------------------- /doc/blurb.but: -------------------------------------------------------------------------------- 1 | \define{dash} \u2013{-} 2 | 3 | \title PuTTY User Manual 4 | 5 | \cfg{xhtml-leaf-level}{1} 6 | \cfg{xhtml-leaf-smallest-contents}{2} 7 | \cfg{xhtml-leaf-contains-contents}{true} 8 | \cfg{xhtml-body-end}{

If you want to provide feedback on this manual 9 | or on the PuTTY tools themselves, see the 10 | Feedback 11 | page.

} 12 | 13 | \cfg{html-template-fragment}{%k}{%b} 14 | 15 | \cfg{info-max-file-size}{0} 16 | 17 | \cfg{chm-contents-filename}{index.html} 18 | \cfg{chm-template-filename}{%k.html} 19 | \cfg{chm-head-end}{} 20 | \cfg{chm-extra-file}{chm.css} 21 | 22 | \cfg{xhtml-contents-filename}{index.html} 23 | \cfg{text-filename}{puttydoc.txt} 24 | \cfg{winhelp-filename}{putty.hlp} 25 | \cfg{info-filename}{putty.info} 26 | \cfg{chm-filename}{putty.chm} 27 | 28 | PuTTY is a free (MIT-licensed) Windows Telnet and SSH client. This 29 | manual documents PuTTY, and its companion utilities PSCP, PSFTP, 30 | Plink, Pageant and PuTTYgen. 31 | 32 | \e{Note to Unix users:} this manual currently primarily documents the 33 | Windows versions of the PuTTY utilities. Some options are therefore 34 | mentioned that are absent from the \i{Unix version}; the Unix version has 35 | features not described here; and the \i\cw{pterm} and command-line 36 | \cw{puttygen} and \cw{pageant} utilities are not described at all. The 37 | only Unix-specific documentation that currently exists is the 38 | \I{man pages for PuTTY tools}man pages. 39 | 40 | \copyright This manual is copyright \shortcopyrightdetails. All 41 | rights reserved. You may distribute this documentation under the MIT 42 | licence. See \k{licence} for the licence text in full. 43 | -------------------------------------------------------------------------------- /doc/chm.css: -------------------------------------------------------------------------------- 1 | /* Stylesheet for a Windows .CHM help file */ 2 | 3 | body { font-size: 75%; font-family: Verdana, Arial, Helvetica, Sans-Serif; } 4 | 5 | h1 { font-weight: bold; font-size: 150%; } 6 | h2 { font-weight: bold; font-size: 130%; } 7 | h3 { font-weight: bold; font-size: 120%; } 8 | -------------------------------------------------------------------------------- /doc/mancfg.but: -------------------------------------------------------------------------------- 1 | \cfg{man-mindepth}{2} 2 | 3 | \C{not-shown} Chapter title which is not shown 4 | -------------------------------------------------------------------------------- /doc/manpages.but: -------------------------------------------------------------------------------- 1 | \A{man-pages} Man pages for Unix PuTTY 2 | 3 | This appendix contains all the man pages for Unix PuTTY. 4 | -------------------------------------------------------------------------------- /doc/site.but: -------------------------------------------------------------------------------- 1 | \# Additional configuration for the version of the PuTTY docs 2 | \# actually published as HTML on the website. 3 | 4 | \cfg{xhtml-head-end}{} 5 | -------------------------------------------------------------------------------- /doc/sshnames.but: -------------------------------------------------------------------------------- 1 | \A{sshnames} SSH-2 names specified for PuTTY 2 | 3 | There are various parts of the SSH-2 protocol where things are specified 4 | using a textual name. Names ending in \cw{@putty.projects.tartarus.org} 5 | are reserved for allocation by the PuTTY team. Allocated names are 6 | documented here. 7 | 8 | \H{sshnames-channel} Connection protocol channel request names 9 | 10 | These names can be sent in a \cw{SSH_MSG_CHANNEL_REQUEST} message. 11 | 12 | \dt \cw{simple@putty.projects.tartarus.org} 13 | 14 | \dd This is sent by a client to announce that it will not have more than 15 | one channel open at a time in the current connection (that one being 16 | the one the request is sent on). The intention is that the server, 17 | knowing this, can set the window on that one channel to something very 18 | large, and leave flow control to TCP. There is no message-specific data. 19 | 20 | \dt \cw{winadj@putty.projects.tartarus.org} 21 | 22 | \dd PuTTY sends this request along with some 23 | \cw{SSH_MSG_CHANNEL_WINDOW_ADJUST} messages as part of its window-size 24 | tuning. It can be sent on any type of channel. There is no 25 | message-specific data. Servers MUST treat it as an unrecognised request 26 | and respond with \cw{SSH_MSG_CHANNEL_FAILURE}. 27 | 28 | \lcont{ 29 | (Some SSH servers get confused by this message, so there is a 30 | bug-compatibility mode for disabling it. See \k{config-ssh-bug-winadj}.) 31 | } 32 | 33 | \H{sshnames-kex} Key exchange method names 34 | 35 | \dt \cw{rsa-sha1-draft-00@putty.projects.tartarus.org} 36 | 37 | \dt \cw{rsa-sha256-draft-00@putty.projects.tartarus.org} 38 | 39 | \dt \cw{rsa1024-sha1-draft-01@putty.projects.tartarus.org} 40 | 41 | \dt \cw{rsa1024-sha256-draft-01@putty.projects.tartarus.org} 42 | 43 | \dt \cw{rsa2048-sha256-draft-01@putty.projects.tartarus.org} 44 | 45 | \dt \cw{rsa1024-sha1-draft-02@putty.projects.tartarus.org} 46 | 47 | \dt \cw{rsa2048-sha512-draft-02@putty.projects.tartarus.org} 48 | 49 | \dt \cw{rsa1024-sha1-draft-03@putty.projects.tartarus.org} 50 | 51 | \dt \cw{rsa2048-sha256-draft-03@putty.projects.tartarus.org} 52 | 53 | \dt \cw{rsa1024-sha1-draft-04@putty.projects.tartarus.org} 54 | 55 | \dt \cw{rsa2048-sha256-draft-04@putty.projects.tartarus.org} 56 | 57 | \dd These appeared in various drafts of what eventually became RFC\_4432. 58 | They have been superseded by \cw{rsa1024-sha1} and \cw{rsa2048-sha256}. 59 | 60 | \H{sshnames-encrypt} Encryption algorithm names 61 | 62 | \dt \cw{arcfour128-draft-00@putty.projects.tartarus.org} 63 | 64 | \dt \cw{arcfour256-draft-00@putty.projects.tartarus.org} 65 | 66 | \dd These were used in drafts of what eventually became RFC\_4345. 67 | They have been superseded by \cw{arcfour128} and \cw{arcfour256}. 68 | -------------------------------------------------------------------------------- /doc/vids.but: -------------------------------------------------------------------------------- 1 | \# Fallback versionid for use when the build system hasn't provided a 2 | better one. 3 | 4 | \versionid no version information available 5 | -------------------------------------------------------------------------------- /errsock.c: -------------------------------------------------------------------------------- 1 | /* 2 | * A dummy Socket implementation which just holds an error message. 3 | */ 4 | 5 | #include 6 | #include 7 | 8 | #include "tree234.h" 9 | #include "putty.h" 10 | #include "network.h" 11 | 12 | typedef struct { 13 | char *error; 14 | Plug *plug; 15 | 16 | Socket sock; 17 | } ErrorSocket; 18 | 19 | static Plug *sk_error_plug(Socket *s, Plug *p) 20 | { 21 | ErrorSocket *es = container_of(s, ErrorSocket, sock); 22 | Plug *ret = es->plug; 23 | if (p) 24 | es->plug = p; 25 | return ret; 26 | } 27 | 28 | static void sk_error_close(Socket *s) 29 | { 30 | ErrorSocket *es = container_of(s, ErrorSocket, sock); 31 | 32 | sfree(es->error); 33 | sfree(es); 34 | } 35 | 36 | static const char *sk_error_socket_error(Socket *s) 37 | { 38 | ErrorSocket *es = container_of(s, ErrorSocket, sock); 39 | return es->error; 40 | } 41 | 42 | static SocketPeerInfo *sk_error_peer_info(Socket *s) 43 | { 44 | return NULL; 45 | } 46 | 47 | static const SocketVtable ErrorSocket_sockvt = { 48 | .plug = sk_error_plug, 49 | .close = sk_error_close, 50 | .socket_error = sk_error_socket_error, 51 | .peer_info = sk_error_peer_info, 52 | /* other methods are NULL */ 53 | }; 54 | 55 | Socket *new_error_socket_consume_string(Plug *plug, char *errmsg) 56 | { 57 | ErrorSocket *es = snew(ErrorSocket); 58 | es->sock.vt = &ErrorSocket_sockvt; 59 | es->plug = plug; 60 | es->error = errmsg; 61 | return &es->sock; 62 | } 63 | 64 | Socket *new_error_socket_fmt(Plug *plug, const char *fmt, ...) 65 | { 66 | va_list ap; 67 | char *msg; 68 | 69 | va_start(ap, fmt); 70 | msg = dupvprintf(fmt, ap); 71 | va_end(ap); 72 | 73 | return new_error_socket_consume_string(plug, msg); 74 | } 75 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | struct Ldisc_tag { 12 | Terminal *term; 13 | Backend *backend; 14 | Seat *seat; 15 | 16 | /* 17 | * Values cached out of conf. 18 | */ 19 | bool telnet_keyboard, telnet_newline; 20 | int protocol, localecho, localedit; 21 | 22 | char *buf; 23 | size_t buflen, bufsiz; 24 | bool quotenext; 25 | }; 26 | 27 | #endif /* PUTTY_LDISC_H */ 28 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /memory.c: -------------------------------------------------------------------------------- 1 | /* 2 | * PuTTY's memory allocation wrappers. 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "defs.h" 10 | #include "puttymem.h" 11 | #include "misc.h" 12 | 13 | void *safemalloc(size_t factor1, size_t factor2, size_t addend) 14 | { 15 | if (factor1 > SIZE_MAX / factor2) 16 | goto fail; 17 | size_t product = factor1 * factor2; 18 | 19 | if (addend > SIZE_MAX) 20 | goto fail; 21 | if (product > SIZE_MAX - addend) 22 | goto fail; 23 | size_t size = product + addend; 24 | 25 | if (size == 0) 26 | size = 1; 27 | 28 | void *p; 29 | #ifdef MINEFIELD 30 | p = minefield_c_malloc(size); 31 | #else 32 | p = malloc(size); 33 | #endif 34 | 35 | if (!p) 36 | goto fail; 37 | 38 | return p; 39 | 40 | fail: 41 | out_of_memory(); 42 | } 43 | 44 | void *saferealloc(void *ptr, size_t n, size_t size) 45 | { 46 | void *p; 47 | 48 | if (n > INT_MAX / size) { 49 | p = NULL; 50 | } else { 51 | size *= n; 52 | if (!ptr) { 53 | #ifdef MINEFIELD 54 | p = minefield_c_malloc(size); 55 | #else 56 | p = malloc(size); 57 | #endif 58 | } else { 59 | #ifdef MINEFIELD 60 | p = minefield_c_realloc(ptr, size); 61 | #else 62 | p = realloc(ptr, size); 63 | #endif 64 | } 65 | } 66 | 67 | if (!p) 68 | out_of_memory(); 69 | 70 | return p; 71 | } 72 | 73 | void safefree(void *ptr) 74 | { 75 | if (ptr) { 76 | #ifdef MINEFIELD 77 | minefield_c_free(ptr); 78 | #else 79 | free(ptr); 80 | #endif 81 | } 82 | } 83 | 84 | void *safegrowarray(void *ptr, size_t *allocated, size_t eltsize, 85 | size_t oldlen, size_t extralen, bool secret) 86 | { 87 | /* The largest value we can safely multiply by eltsize */ 88 | assert(eltsize > 0); 89 | size_t maxsize = (~(size_t)0) / eltsize; 90 | 91 | size_t oldsize = *allocated; 92 | 93 | /* Range-check the input values */ 94 | assert(oldsize <= maxsize); 95 | assert(oldlen <= maxsize); 96 | assert(extralen <= maxsize - oldlen); 97 | 98 | /* If the size is already enough, don't bother doing anything! */ 99 | if (oldsize > oldlen + extralen) 100 | return ptr; 101 | 102 | /* Find out how much we need to grow the array by. */ 103 | size_t increment = (oldlen + extralen) - oldsize; 104 | 105 | /* Invent a new size. We want to grow the array by at least 106 | * 'increment' elements; by at least a fixed number of bytes (to 107 | * get things started when sizes are small); and by some constant 108 | * factor of its old size (to avoid repeated calls to this 109 | * function taking quadratic time overall). */ 110 | if (increment < 256 / eltsize) 111 | increment = 256 / eltsize; 112 | if (increment < oldsize / 16) 113 | increment = oldsize / 16; 114 | 115 | /* But we also can't grow beyond maxsize. */ 116 | size_t maxincr = maxsize - oldsize; 117 | if (increment > maxincr) 118 | increment = maxincr; 119 | 120 | size_t newsize = oldsize + increment; 121 | void *toret; 122 | if (secret) { 123 | toret = safemalloc(newsize, eltsize, 0); 124 | if (oldsize) { 125 | memcpy(toret, ptr, oldsize * eltsize); 126 | smemclr(ptr, oldsize * eltsize); 127 | sfree(ptr); 128 | } 129 | } else { 130 | toret = saferealloc(ptr, newsize, eltsize); 131 | } 132 | *allocated = newsize; 133 | return toret; 134 | } 135 | -------------------------------------------------------------------------------- /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 'test/.*\.txt|MODULE|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=test/*.txt 22 | # These are actual binary files which we don't want transforming. 23 | bin=`{ ls -1 windows/*.ico 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 | -------------------------------------------------------------------------------- /mpunsafe.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "defs.h" 6 | #include "misc.h" 7 | #include "puttymem.h" 8 | 9 | #include "mpint.h" 10 | #include "mpint_i.h" 11 | 12 | /* 13 | * This global symbol is also defined in ssh2kex-client.c, to ensure 14 | * that these unsafe non-constant-time mp_int functions can't end up 15 | * accidentally linked in to any PuTTY tool that actually makes an SSH 16 | * client connection. 17 | * 18 | * (Only _client_ connections, however. Uppity, being a test server 19 | * only, is exempt.) 20 | */ 21 | const int deliberate_symbol_clash = 12345; 22 | 23 | static size_t mp_unsafe_words_needed(mp_int *x) 24 | { 25 | size_t words = x->nw; 26 | while (words > 1 && !x->w[words-1]) 27 | words--; 28 | return words; 29 | } 30 | 31 | mp_int *mp_unsafe_shrink(mp_int *x) 32 | { 33 | x->nw = mp_unsafe_words_needed(x); 34 | /* This potentially leaves some allocated words between the new 35 | * and old values of x->nw, which won't be wiped by mp_free now 36 | * that x->nw doesn't mention that they exist. But we've just 37 | * checked they're all zero, so we don't need to wipe them now 38 | * either. */ 39 | return x; 40 | } 41 | 42 | mp_int *mp_unsafe_copy(mp_int *x) 43 | { 44 | mp_int *copy = mp_make_sized(mp_unsafe_words_needed(x)); 45 | mp_copy_into(copy, x); 46 | return copy; 47 | } 48 | 49 | uint32_t mp_unsafe_mod_integer(mp_int *x, uint32_t modulus) 50 | { 51 | uint64_t accumulator = 0; 52 | for (size_t i = mp_max_bytes(x); i-- > 0 ;) { 53 | accumulator = 0x100 * accumulator + mp_get_byte(x, i); 54 | accumulator %= modulus; 55 | } 56 | return accumulator; 57 | } 58 | -------------------------------------------------------------------------------- /mpunsafe.h: -------------------------------------------------------------------------------- 1 | /* 2 | * mpunsafe.h: functions that deal with mp_ints in ways that are *not* 3 | * expected to be constant-time. Used during key generation, in which 4 | * constant run time is a lost cause anyway. 5 | * 6 | * These functions are in a separate header, so that you can easily 7 | * check that you're not calling them in the wrong context. They're 8 | * also defined in a separate source file, which is only linked in to 9 | * the key generation tools. Furthermore, that source file also 10 | * defines a global symbol that intentionally conflicts with one 11 | * defined in the SSH client code, so that any attempt to put these 12 | * functions into the same binary as the live SSH client 13 | * implementation will cause a link-time failure. They should only be 14 | * linked into PuTTYgen and auxiliary test programs. 15 | * 16 | * Also, just in case those precautions aren't enough, all the unsafe 17 | * functions have 'unsafe' in the name. 18 | */ 19 | 20 | #ifndef PUTTY_MPINT_UNSAFE_H 21 | #define PUTTY_MPINT_UNSAFE_H 22 | 23 | /* 24 | * The most obvious unsafe thing you want to do with an mp_int is to 25 | * get rid of leading zero words in its representation, so that its 26 | * nominal size is as close as possible to its true size, and you 27 | * don't waste any time processing it. 28 | * 29 | * mp_unsafe_shrink performs this operation in place, mutating the 30 | * size field of the mp_int it's given. It returns the same pointer it 31 | * was given. 32 | * 33 | * mp_unsafe_copy leaves the original mp_int alone and makes a new one 34 | * with the minimal size. 35 | */ 36 | mp_int *mp_unsafe_shrink(mp_int *m); 37 | mp_int *mp_unsafe_copy(mp_int *m); 38 | 39 | /* 40 | * Compute the residue of x mod m. This is implemented in the most 41 | * obvious way using the C % operator, which won't be constant-time on 42 | * many C implementations. 43 | */ 44 | uint32_t mp_unsafe_mod_integer(mp_int *x, uint32_t m); 45 | 46 | #endif /* PUTTY_MPINT_UNSAFE_H */ 47 | -------------------------------------------------------------------------------- /nocmdline.c: -------------------------------------------------------------------------------- 1 | /* 2 | * nocmdline.c - stubs in applications which don't do the 3 | * standard(ish) PuTTY tools' command-line parsing 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include "putty.h" 10 | 11 | /* 12 | * Stub version of the function in cmdline.c which provides the 13 | * password to SSH authentication by remembering it having been passed 14 | * as a command-line option. If we're not doing normal command-line 15 | * handling, then there is no such option, so that function always 16 | * returns failure. 17 | */ 18 | int cmdline_get_passwd_input(prompts_t *p) 19 | { 20 | return -1; 21 | } 22 | 23 | /* 24 | * The main cmdline_process_param function is normally called from 25 | * applications' main(). An application linking against this stub 26 | * module shouldn't have a main() that calls it in the first place :-) 27 | * but it is just occasionally called by other supporting functions, 28 | * such as one in uxputty.c which sometimes handles a non-option 29 | * argument by making up equivalent options and passing them back to 30 | * this function. So we have to provide a link-time stub of this 31 | * function, but it had better not end up being called at run time. 32 | */ 33 | int cmdline_process_param(const char *p, char *value, 34 | int need_save, Conf *conf) 35 | { 36 | unreachable("cmdline_process_param should never be called"); 37 | } 38 | -------------------------------------------------------------------------------- /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 | #include "putty.h" 12 | #include "network.h" 13 | #include "proxy.h" 14 | 15 | void proxy_socks5_offerencryptedauth(BinarySink *bs) 16 | { 17 | /* For telnet, don't add any new encrypted authentication routines */ 18 | } 19 | 20 | int proxy_socks5_handlechap (ProxySocket *p) 21 | { 22 | 23 | plug_closing(p->plug, "Proxy error: Trying to handle a SOCKS5 CHAP request" 24 | " in telnet-only build", 25 | PROXY_ERROR_GENERAL, 0); 26 | return 1; 27 | } 28 | 29 | int proxy_socks5_selectchap(ProxySocket *p) 30 | { 31 | plug_closing(p->plug, "Proxy error: Trying to handle a SOCKS5 CHAP request" 32 | " in telnet-only build", 33 | PROXY_ERROR_GENERAL, 0); 34 | return 1; 35 | } 36 | -------------------------------------------------------------------------------- /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, size_t 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 | -------------------------------------------------------------------------------- /noproxy.c: -------------------------------------------------------------------------------- 1 | /* 2 | * noproxy.c: an alternative to proxy.c, for use by auxiliary programs 3 | * that need to make network connections but don't want to include all 4 | * the full-on support for endless network proxies (and its 5 | * configuration requirements). Implements the primary APIs of 6 | * proxy.c, but maps them straight to the underlying network layer. 7 | */ 8 | 9 | #include "putty.h" 10 | #include "network.h" 11 | #include "proxy.h" 12 | 13 | SockAddr *name_lookup(const char *host, int port, char **canonicalname, 14 | Conf *conf, int addressfamily, LogContext *logctx, 15 | const char *reason) 16 | { 17 | return sk_namelookup(host, canonicalname, addressfamily); 18 | } 19 | 20 | Socket *new_connection(SockAddr *addr, const char *hostname, 21 | int port, bool privport, 22 | bool oobinline, bool nodelay, bool keepalive, 23 | Plug *plug, Conf *conf) 24 | { 25 | return sk_new(addr, port, privport, oobinline, nodelay, keepalive, plug); 26 | } 27 | 28 | Socket *new_listener(const char *srcaddr, int port, Plug *plug, 29 | bool local_host_only, Conf *conf, int addressfamily) 30 | { 31 | return sk_newlistener(srcaddr, port, plug, local_host_only, addressfamily); 32 | } 33 | -------------------------------------------------------------------------------- /norand.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Stub implementations of RNG functions for applications without an RNG. 3 | */ 4 | 5 | #include "putty.h" 6 | 7 | void random_read(void *out, size_t size) 8 | { 9 | unreachable("Random numbers are not available in this application"); 10 | } 11 | 12 | void random_save_seed(void) 13 | { 14 | } 15 | 16 | void random_destroy_seed(void) 17 | { 18 | } 19 | 20 | void noise_ultralight(NoiseSourceId id, unsigned long data) 21 | { 22 | } 23 | -------------------------------------------------------------------------------- /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, Conf *conf, 16 | Plug *downplug, Plug *upplug, Socket **sock, 17 | char **logtext, char **ds_err, char **us_err, 18 | int can_upstream, int can_downstream) 19 | { 20 | return SHARE_NONE; 21 | } 22 | 23 | void platform_ssh_share_cleanup(const char *name) 24 | { 25 | } 26 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /nullplug.c: -------------------------------------------------------------------------------- 1 | /* 2 | * nullplug.c: provide a null implementation of the Plug vtable which 3 | * ignores all calls. Occasionally useful in cases where we want to 4 | * make a network connection just to see if it works, but not do 5 | * anything with it afterwards except close it again. 6 | */ 7 | 8 | #include "putty.h" 9 | 10 | static void nullplug_socket_log(Plug *plug, PlugLogType type, SockAddr *addr, 11 | int port, const char *err_msg, int err_code) 12 | { 13 | } 14 | 15 | static void nullplug_closing(Plug *plug, const char *error_msg, int error_code, 16 | bool calling_back) 17 | { 18 | } 19 | 20 | static void nullplug_receive( 21 | Plug *plug, int urgent, const char *data, size_t len) 22 | { 23 | } 24 | 25 | static void nullplug_sent(Plug *plug, size_t bufsize) 26 | { 27 | } 28 | 29 | static const PlugVtable nullplug_plugvt = { 30 | .log = nullplug_socket_log, 31 | .closing = nullplug_closing, 32 | .receive = nullplug_receive, 33 | .sent = nullplug_sent, 34 | }; 35 | 36 | static Plug nullplug_plug = { &nullplug_plugvt }; 37 | 38 | /* 39 | * There's a singleton instance of nullplug, because it's not 40 | * interesting enough to worry about making more than one of them. 41 | */ 42 | Plug *const nullplug = &nullplug_plug; 43 | -------------------------------------------------------------------------------- /pinger.c: -------------------------------------------------------------------------------- 1 | /* 2 | * pinger.c: centralised module that deals with sending SS_PING 3 | * keepalives, to avoid replicating this code in multiple backends. 4 | */ 5 | 6 | #include "putty.h" 7 | 8 | struct Pinger { 9 | int interval; 10 | bool pending; 11 | unsigned long when_set, next; 12 | Backend *backend; 13 | }; 14 | 15 | static void pinger_schedule(Pinger *pinger); 16 | 17 | static void pinger_timer(void *ctx, unsigned long now) 18 | { 19 | Pinger *pinger = (Pinger *)ctx; 20 | 21 | if (pinger->pending && now == pinger->next) { 22 | backend_special(pinger->backend, SS_PING, 0); 23 | pinger->pending = false; 24 | pinger_schedule(pinger); 25 | } 26 | } 27 | 28 | static void pinger_schedule(Pinger *pinger) 29 | { 30 | unsigned long next; 31 | 32 | if (!pinger->interval) { 33 | pinger->pending = false; /* cancel any pending ping */ 34 | return; 35 | } 36 | 37 | next = schedule_timer(pinger->interval * TICKSPERSEC, 38 | 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 *backend) 48 | { 49 | Pinger *pinger = snew(Pinger); 50 | 51 | pinger->interval = conf_get_int(conf, CONF_ping_interval); 52 | pinger->pending = false; 53 | pinger->backend = backend; 54 | pinger_schedule(pinger); 55 | 56 | return pinger; 57 | } 58 | 59 | void pinger_reconfig(Pinger *pinger, Conf *oldconf, Conf *newconf) 60 | { 61 | int newinterval = conf_get_int(newconf, CONF_ping_interval); 62 | if (conf_get_int(oldconf, CONF_ping_interval) != newinterval) { 63 | pinger->interval = newinterval; 64 | pinger_schedule(pinger); 65 | } 66 | } 67 | 68 | void pinger_free(Pinger *pinger) 69 | { 70 | expire_timer_context(pinger); 71 | sfree(pinger); 72 | } 73 | -------------------------------------------------------------------------------- /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, const char *hostname, 12 | int port, int privport, 13 | int oobinline, int nodelay, int keepalive, 14 | Plug *plug, Conf *conf) 15 | { 16 | return NULL; 17 | } 18 | -------------------------------------------------------------------------------- /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 ProxySocket ProxySocket; 17 | 18 | struct ProxySocket { 19 | const char *error; 20 | 21 | Socket *sub_socket; 22 | Plug *plug; 23 | SockAddr *remote_addr; 24 | int remote_port; 25 | 26 | bufchain pending_output_data; 27 | bufchain pending_oob_output_data; 28 | bufchain pending_input_data; 29 | bool pending_eof; 30 | 31 | #define PROXY_STATE_NEW -1 32 | #define PROXY_STATE_ACTIVE 0 33 | 34 | int state; /* proxy states greater than 0 are implementation 35 | * dependent, but represent various stages/states 36 | * of the initialization/setup/negotiation with the 37 | * proxy server. 38 | */ 39 | bool freeze; /* should we freeze the underlying socket when 40 | * we are done with the proxy negotiation? this 41 | * simply caches the value of sk_set_frozen calls. 42 | */ 43 | 44 | #define PROXY_CHANGE_NEW -1 45 | #define PROXY_CHANGE_CLOSING 0 46 | #define PROXY_CHANGE_SENT 1 47 | #define PROXY_CHANGE_RECEIVE 2 48 | #define PROXY_CHANGE_ACCEPTING 3 49 | 50 | /* something has changed (a call from the sub socket 51 | * layer into our Proxy Plug layer, or we were just 52 | * created, etc), so the proxy layer needs to handle 53 | * this change (the type of which is the second argument) 54 | * and further the proxy negotiation process. 55 | */ 56 | 57 | int (*negotiate) (ProxySocket * /* this */, int /* change type */); 58 | 59 | /* current arguments of plug handlers 60 | * (for use by proxy's negotiate function) 61 | */ 62 | 63 | /* closing */ 64 | const char *closing_error_msg; 65 | int closing_error_code; 66 | bool closing_calling_back; 67 | 68 | /* receive */ 69 | bool receive_urgent; 70 | const char *receive_data; 71 | int receive_len; 72 | 73 | /* accepting */ 74 | accept_fn_t accepting_constructor; 75 | accept_ctx_t accepting_ctx; 76 | 77 | /* configuration, used to look up proxy settings */ 78 | Conf *conf; 79 | 80 | /* CHAP transient data */ 81 | int chap_num_attributes; 82 | int chap_num_attributes_processed; 83 | int chap_current_attribute; 84 | int chap_current_datalen; 85 | 86 | Socket sock; 87 | Plug plugimpl; 88 | }; 89 | 90 | extern void proxy_activate (ProxySocket *); 91 | 92 | extern int proxy_http_negotiate (ProxySocket *, int); 93 | extern int proxy_telnet_negotiate (ProxySocket *, int); 94 | extern int proxy_socks4_negotiate (ProxySocket *, int); 95 | extern int proxy_socks5_negotiate (ProxySocket *, int); 96 | 97 | /* 98 | * This may be reused by local-command proxies on individual 99 | * platforms. 100 | */ 101 | char *format_telnet_command(SockAddr *addr, int port, Conf *conf); 102 | 103 | /* 104 | * These are implemented in cproxy.c or nocproxy.c, depending on 105 | * whether encrypted proxy authentication is available. 106 | */ 107 | extern void proxy_socks5_offerencryptedauth(BinarySink *); 108 | extern int proxy_socks5_handlechap (ProxySocket *); 109 | extern int proxy_socks5_selectchap(ProxySocket *); 110 | 111 | #endif 112 | -------------------------------------------------------------------------------- /psftpcommon.c: -------------------------------------------------------------------------------- 1 | /* 2 | * psftpcommon.c: front-end functionality shared between both file 3 | * transfer tools across platforms. (As opposed to sftpcommon.c, which 4 | * has *protocol*-level common code.) 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #include "putty.h" 11 | #include "sftp.h" 12 | #include "psftp.h" 13 | 14 | #define MAX_NAMES_MEMORY ((size_t)8 << 20) 15 | 16 | /* 17 | * qsort comparison routine for fxp_name structures. Sorts by real 18 | * file name. 19 | */ 20 | int sftp_name_compare(const void *av, const void *bv) 21 | { 22 | const struct fxp_name *const *a = (const struct fxp_name *const *) av; 23 | const struct fxp_name *const *b = (const struct fxp_name *const *) bv; 24 | return strcmp((*a)->filename, (*b)->filename); 25 | } 26 | 27 | struct list_directory_from_sftp_ctx { 28 | size_t nnames, namesize, total_memory; 29 | struct fxp_name **names; 30 | bool sorting; 31 | }; 32 | 33 | struct list_directory_from_sftp_ctx *list_directory_from_sftp_new(void) 34 | { 35 | struct list_directory_from_sftp_ctx *ctx = 36 | snew(struct list_directory_from_sftp_ctx); 37 | memset(ctx, 0, sizeof(*ctx)); 38 | ctx->sorting = true; 39 | return ctx; 40 | } 41 | 42 | void list_directory_from_sftp_free(struct list_directory_from_sftp_ctx *ctx) 43 | { 44 | for (size_t i = 0; i < ctx->nnames; i++) 45 | fxp_free_name(ctx->names[i]); 46 | sfree(ctx->names); 47 | sfree(ctx); 48 | } 49 | 50 | void list_directory_from_sftp_feed(struct list_directory_from_sftp_ctx *ctx, 51 | struct fxp_name *name) 52 | { 53 | if (ctx->sorting) { 54 | /* 55 | * Accumulate these filenames into an array that we'll sort - 56 | * unless the array gets _really_ big, in which case, to avoid 57 | * consuming all the client's memory, we fall back to 58 | * outputting the directory listing unsorted. 59 | */ 60 | size_t this_name_memory = 61 | sizeof(*ctx->names) + sizeof(**ctx->names) + 62 | strlen(name->filename) + 63 | strlen(name->longname); 64 | 65 | if (MAX_NAMES_MEMORY - ctx->total_memory < this_name_memory) { 66 | list_directory_from_sftp_warn_unsorted(); 67 | 68 | /* Output all the previously stored names. */ 69 | for (size_t i = 0; i < ctx->nnames; i++) { 70 | list_directory_from_sftp_print(ctx->names[i]); 71 | fxp_free_name(ctx->names[i]); 72 | } 73 | 74 | /* Don't store further names in that array. */ 75 | sfree(ctx->names); 76 | ctx->names = NULL; 77 | ctx->nnames = 0; 78 | ctx->namesize = 0; 79 | ctx->sorting = false; 80 | 81 | /* And don't forget to output the name passed in this 82 | * actual function call. */ 83 | list_directory_from_sftp_print(name); 84 | } else { 85 | sgrowarray(ctx->names, ctx->namesize, ctx->nnames); 86 | ctx->names[ctx->nnames++] = fxp_dup_name(name); 87 | ctx->total_memory += this_name_memory; 88 | } 89 | } else { 90 | list_directory_from_sftp_print(name); 91 | } 92 | } 93 | 94 | void list_directory_from_sftp_finish(struct list_directory_from_sftp_ctx *ctx) 95 | { 96 | if (ctx->nnames > 0) { 97 | assert(ctx->sorting); 98 | qsort(ctx->names, ctx->nnames, sizeof(*ctx->names), sftp_name_compare); 99 | for (size_t i = 0; i < ctx->nnames; i++) 100 | list_directory_from_sftp_print(ctx->names[i]); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /psocks.h: -------------------------------------------------------------------------------- 1 | typedef struct psocks_state psocks_state; 2 | 3 | typedef struct PsocksPlatform PsocksPlatform; 4 | typedef struct PsocksDataSink PsocksDataSink; 5 | 6 | /* indices into PsocksDataSink arrays */ 7 | typedef enum PsocksDirection { UP, DN } PsocksDirection; 8 | 9 | typedef struct PsocksDataSink { 10 | void (*free)(PsocksDataSink *); 11 | BinarySink *s[2]; 12 | } PsocksDataSink; 13 | static inline void pds_free(PsocksDataSink *pds) 14 | { pds->free(pds); } 15 | 16 | PsocksDataSink *pds_stdio(FILE *fp[2]); 17 | 18 | struct PsocksPlatform { 19 | PsocksDataSink *(*open_pipes)( 20 | const char *cmd, const char *const *direction_args, 21 | const char *index_arg, char **err); 22 | void (*start_subcommand)(strbuf *args); 23 | }; 24 | 25 | psocks_state *psocks_new(const PsocksPlatform *); 26 | void psocks_free(psocks_state *ps); 27 | void psocks_cmdline(psocks_state *ps, int argc, char **argv); 28 | void psocks_start(psocks_state *ps); 29 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /sessprep.c: -------------------------------------------------------------------------------- 1 | /* 2 | * sessprep.c: centralise some preprocessing done on Conf objects 3 | * before launching them. 4 | */ 5 | 6 | #include "putty.h" 7 | 8 | void prepare_session(Conf *conf) 9 | { 10 | char *hostbuf = dupstr(conf_get_str(conf, CONF_host)); 11 | char *host = hostbuf; 12 | char *p, *q; 13 | 14 | /* 15 | * Trim leading whitespace from the hostname. 16 | */ 17 | host += strspn(host, " \t"); 18 | 19 | /* 20 | * See if host is of the form user@host, and separate out the 21 | * username if so. 22 | */ 23 | if (host[0] != '\0') { 24 | /* 25 | * Use strrchr, in case the _username_ in turn is of the form 26 | * user@host, which has been known. 27 | */ 28 | char *atsign = strrchr(host, '@'); 29 | if (atsign) { 30 | *atsign = '\0'; 31 | conf_set_str(conf, CONF_username, host); 32 | host = atsign + 1; 33 | } 34 | } 35 | 36 | /* 37 | * Trim a colon suffix off the hostname if it's there, and discard 38 | * the text after it. 39 | * 40 | * The exact reason why we _ignore_ this text, rather than 41 | * treating it as a port number, is unfortunately lost in the 42 | * mists of history: the commit which originally introduced this 43 | * change on 2001-05-06 was clear on _what_ it was doing but 44 | * didn't bother to explain _why_. But I [SGT, 2017-12-03] suspect 45 | * it has to do with priority order: what should a saved session 46 | * do if its CONF_host contains 'server.example.com:123' and its 47 | * CONF_port contains 456? If CONF_port contained the _default_ 48 | * port number then it might be a good guess that the colon suffix 49 | * on the host name was intended to override that, but you don't 50 | * really want to get into making heuristic judgments on that 51 | * basis. 52 | * 53 | * (Then again, you could just as easily make the same argument 54 | * about whether a 'user@' prefix on the host name should override 55 | * CONF_username, which this code _does_ do. I don't have a good 56 | * answer, sadly. Both these pieces of behaviour have been around 57 | * for years and it would probably cause subtle breakage in all 58 | * sorts of long-forgotten scripting to go changing things around 59 | * now.) 60 | * 61 | * In order to protect unbracketed IPv6 address literals against 62 | * this treatment, we do not make this change at all if there's 63 | * _more_ than one (un-IPv6-bracketed) colon. 64 | */ 65 | p = host_strchr(host, ':'); 66 | if (p && p == host_strrchr(host, ':')) { 67 | *p = '\0'; 68 | } 69 | 70 | /* 71 | * Remove any remaining whitespace. 72 | */ 73 | p = hostbuf; 74 | q = host; 75 | while (*q) { 76 | if (*q != ' ' && *q != '\t') 77 | *p++ = *q; 78 | q++; 79 | } 80 | *p = '\0'; 81 | 82 | conf_set_str(conf, CONF_host, hostbuf); 83 | sfree(hostbuf); 84 | } 85 | -------------------------------------------------------------------------------- /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=38BA7229B7588FD1 13 | preliminary=false 14 | 15 | while :; do 16 | case "$1" in 17 | -r) 18 | shift 19 | keyname=6289A25F4AE8DA82 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 | wa32/*.exe wa32/*.zip wa32/*.msi \ 53 | wa64/*.exe wa64/*.zip wa64/*.msi \ 54 | w32old/*.exe w32old/*.zip; do 55 | sign --detach-sign "$i" "$i.gpg" 56 | done 57 | for i in md5sums sha1sums sha256sums sha512sums; do 58 | sign --clearsign "$i" "$i.gpg" 59 | done 60 | fi 61 | -------------------------------------------------------------------------------- /smallprimes.c: -------------------------------------------------------------------------------- 1 | /* 2 | * smallprimes.c: implementation of the array of small primes defined 3 | * in sshkeygen.h. 4 | */ 5 | 6 | #include 7 | #include "ssh.h" 8 | #include "sshkeygen.h" 9 | 10 | /* The real array that stores the primes. It has to be writable in 11 | * this module, but outside this module, we only expose the 12 | * const-qualified pointer 'smallprimes' so that nobody else can 13 | * accidentally overwrite it. */ 14 | static unsigned short smallprimes_array[NSMALLPRIMES]; 15 | 16 | const unsigned short *const smallprimes = smallprimes_array; 17 | 18 | void init_smallprimes(void) 19 | { 20 | if (smallprimes_array[0]) 21 | return; /* already done */ 22 | 23 | bool A[65536]; 24 | 25 | for (size_t i = 2; i < lenof(A); i++) 26 | A[i] = true; 27 | 28 | for (size_t i = 2; i < lenof(A); i++) { 29 | if (!A[i]) 30 | continue; 31 | for (size_t j = 2*i; j < lenof(A); j += i) 32 | A[j] = false; 33 | } 34 | 35 | size_t pos = 0; 36 | for (size_t i = 2; i < lenof(A); i++) { 37 | if (A[i]) { 38 | assert(pos < NSMALLPRIMES); 39 | smallprimes_array[pos++] = i; 40 | } 41 | } 42 | 43 | assert(pos == NSMALLPRIMES); 44 | } 45 | -------------------------------------------------------------------------------- /ssh1censor.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Packet-censoring code for SSH-1, used to identify sensitive fields 3 | * like passwords so that the logging system can avoid writing them 4 | * into log files. 5 | */ 6 | 7 | #include 8 | 9 | #include "putty.h" 10 | #include "ssh.h" 11 | 12 | int ssh1_censor_packet( 13 | const PacketLogSettings *pls, int type, bool sender_is_client, 14 | ptrlen pkt, logblank_t *blanks) 15 | { 16 | int nblanks = 0; 17 | ptrlen str; 18 | BinarySource src[1]; 19 | 20 | BinarySource_BARE_INIT_PL(src, pkt); 21 | 22 | if (pls->omit_data && 23 | (type == SSH1_SMSG_STDOUT_DATA || 24 | type == SSH1_SMSG_STDERR_DATA || 25 | type == SSH1_CMSG_STDIN_DATA || 26 | type == SSH1_MSG_CHANNEL_DATA)) { 27 | /* "Session data" packets - omit the data string. */ 28 | if (type == SSH1_MSG_CHANNEL_DATA) 29 | get_uint32(src); /* skip channel id */ 30 | str = get_string(src); 31 | if (!get_err(src)) { 32 | assert(nblanks < MAX_BLANKS); 33 | blanks[nblanks].offset = src->pos - str.len; 34 | blanks[nblanks].type = PKTLOG_OMIT; 35 | blanks[nblanks].len = str.len; 36 | nblanks++; 37 | } 38 | } 39 | 40 | if (sender_is_client && pls->omit_passwords) { 41 | if (type == SSH1_CMSG_AUTH_PASSWORD || 42 | type == SSH1_CMSG_AUTH_TIS_RESPONSE || 43 | type == SSH1_CMSG_AUTH_CCARD_RESPONSE) { 44 | /* If this is a password or similar packet, blank the 45 | * password(s). */ 46 | assert(nblanks < MAX_BLANKS); 47 | blanks[nblanks].offset = 0; 48 | blanks[nblanks].len = pkt.len; 49 | blanks[nblanks].type = PKTLOG_BLANK; 50 | nblanks++; 51 | } else if (type == SSH1_CMSG_X11_REQUEST_FORWARDING) { 52 | /* 53 | * If this is an X forwarding request packet, blank the 54 | * fake auth data. 55 | * 56 | * Note that while we blank the X authentication data 57 | * here, we don't take any special action to blank the 58 | * start of an X11 channel, so using MIT-MAGIC-COOKIE-1 59 | * and actually opening an X connection without having 60 | * session blanking enabled is likely to leak your cookie 61 | * into the log. 62 | */ 63 | get_string(src); /* skip protocol name */ 64 | str = get_string(src); 65 | if (!get_err(src)) { 66 | assert(nblanks < MAX_BLANKS); 67 | blanks[nblanks].offset = src->pos - str.len; 68 | blanks[nblanks].type = PKTLOG_BLANK; 69 | blanks[nblanks].len = str.len; 70 | nblanks++; 71 | } 72 | } 73 | } 74 | 75 | return nblanks; 76 | } 77 | -------------------------------------------------------------------------------- /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 | BlowfishContext *blowfish_make_context(void); 9 | void blowfish_free_context(BlowfishContext *ctx); 10 | void blowfish_initkey(BlowfishContext *ctx); 11 | void blowfish_expandkey(BlowfishContext *ctx, 12 | const void *key, short keybytes, 13 | const void *salt, short saltbytes); 14 | void blowfish_lsb_encrypt_ecb(void *blk, int len, BlowfishContext *ctx); 15 | -------------------------------------------------------------------------------- /sshcr.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Coroutine mechanics used in PuTTY's SSH code. 3 | */ 4 | 5 | #ifndef PUTTY_SSHCR_H 6 | #define PUTTY_SSHCR_H 7 | 8 | /* 9 | * If these macros look impenetrable to you, you might find it helpful 10 | * to read 11 | * 12 | * https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html 13 | * 14 | * which explains the theory behind these macros. 15 | * 16 | * In particular, if you are getting `case expression not constant' 17 | * errors when building with MS Visual Studio, this is because MS's 18 | * Edit and Continue debugging feature causes their compiler to 19 | * violate ANSI C. To disable Edit and Continue debugging: 20 | * 21 | * - right-click ssh.c in the FileView 22 | * - click Settings 23 | * - select the C/C++ tab and the General category 24 | * - under `Debug info:', select anything _other_ than `Program 25 | * Database for Edit and Continue'. 26 | */ 27 | 28 | #define crBegin(v) do { int *crLine = &v; switch(v) { case 0: 29 | #define crBeginState crBegin(s->crLine) 30 | #define crStateP(t, v) \ 31 | struct t *s; \ 32 | if (!(v)) { s = (v) = snew(struct t); s->crLine = 0; } \ 33 | s = (v); 34 | #define crState(t) crStateP(t, ssh->t) 35 | #define crFinish(z) } *crLine = 0; return (z); } while (0) 36 | #define crFinishV } *crLine = 0; return; } while (0) 37 | #define crFinishFreed(z) } return (z); } while (0) 38 | #define crFinishFreedV } return; } while (0) 39 | #define crFinishFree(z) } sfree(s); return (z); } while (0) 40 | #define crFinishFreeV } sfree(s); return; } while (0) 41 | #define crReturn(z) \ 42 | do {\ 43 | *crLine =__LINE__; return (z); case __LINE__:;\ 44 | } while (0) 45 | #define crReturnV \ 46 | do {\ 47 | *crLine=__LINE__; return; case __LINE__:;\ 48 | } while (0) 49 | #define crStop(z) do{ *crLine = 0; return (z); }while(0) 50 | #define crStopV do{ *crLine = 0; return; }while(0) 51 | 52 | /* 53 | * The crMaybeWaitUntil macros could have been more easily written in 54 | * terms of the simple crReturn above, by writing things like 55 | * 56 | * while (!condition) { crReturn(whatever); } 57 | * 58 | * (or do-while in the case of crWaitUntil). But it's better to do it 59 | * directly by writing _once_ to crLine before first testing the 60 | * condition, because this way it's robust against the condition check 61 | * potentially freeing the entire coroutine state structure as a side 62 | * effect (as long as it also evaluates false if it does that), 63 | * because we don't write into crLine between the condition evaluating 64 | * to false and the 'return' statement. 65 | */ 66 | #define crMaybeWaitUntil(c) \ 67 | do { \ 68 | *crLine =__LINE__; \ 69 | case __LINE__: if (!(c)) return 0; \ 70 | } while (0) 71 | #define crMaybeWaitUntilV(c) \ 72 | do { \ 73 | *crLine =__LINE__; \ 74 | case __LINE__: if (!(c)) return; \ 75 | } while (0) 76 | #define crWaitUntil(c) \ 77 | do { \ 78 | *crLine =__LINE__; return; \ 79 | case __LINE__: if (!(c)) return 0; \ 80 | } while (0) 81 | #define crWaitUntilV(c) \ 82 | do { \ 83 | *crLine =__LINE__; return; \ 84 | case __LINE__: if (!(c)) return; \ 85 | } while (0) 86 | 87 | #endif /* PUTTY_SSHCR_H */ 88 | -------------------------------------------------------------------------------- /sshdssg.c: -------------------------------------------------------------------------------- 1 | /* 2 | * DSS key generation. 3 | */ 4 | 5 | #include "misc.h" 6 | #include "ssh.h" 7 | #include "sshkeygen.h" 8 | #include "mpint.h" 9 | 10 | int dsa_generate(struct dss_key *key, int bits, PrimeGenerationContext *pgc, 11 | ProgressReceiver *prog) 12 | { 13 | /* 14 | * Progress-reporting setup. 15 | * 16 | * DSA generation involves three potentially long jobs: inventing 17 | * the small prime q, the large prime p, and finding an order-q 18 | * element of the multiplicative group of p. 19 | * 20 | * The latter is done by finding an element whose order is 21 | * _divisible_ by q and raising it to the power of (p-1)/q. Every 22 | * element whose order is not divisible by q is a qth power of q 23 | * distinct elements whose order _is_ divisible by q, so the 24 | * probability of not finding a suitable element on the first try 25 | * is in the region of 1/q, i.e. at most 2^-159. 26 | * 27 | * (So the probability of success will end up indistinguishable 28 | * from 1 in IEEE standard floating point! But what can you do.) 29 | */ 30 | ProgressPhase phase_q = primegen_add_progress_phase(pgc, prog, 160); 31 | ProgressPhase phase_p = primegen_add_progress_phase(pgc, prog, bits); 32 | double g_failure_probability = 1.0 33 | / (double)(1ULL << 53) 34 | / (double)(1ULL << 53) 35 | / (double)(1ULL << 53); 36 | ProgressPhase phase_g = progress_add_probabilistic( 37 | prog, estimate_modexp_cost(bits), 1.0 - g_failure_probability); 38 | progress_ready(prog); 39 | 40 | PrimeCandidateSource *pcs; 41 | 42 | /* 43 | * Generate q: a prime of length 160. 44 | */ 45 | progress_start_phase(prog, phase_q); 46 | pcs = pcs_new(160); 47 | mp_int *q = primegen_generate(pgc, pcs, prog); 48 | progress_report_phase_complete(prog); 49 | 50 | /* 51 | * Now generate p: a prime of length `bits', such that p-1 is 52 | * divisible by q. 53 | */ 54 | progress_start_phase(prog, phase_p); 55 | pcs = pcs_new(bits); 56 | pcs_require_residue_1_mod_prime(pcs, q); 57 | mp_int *p = primegen_generate(pgc, pcs, prog); 58 | progress_report_phase_complete(prog); 59 | 60 | /* 61 | * Next we need g. Raise 2 to the power (p-1)/q modulo p, and 62 | * if that comes out to one then try 3, then 4 and so on. As 63 | * soon as we hit a non-unit (and non-zero!) one, that'll do 64 | * for g. 65 | */ 66 | progress_start_phase(prog, phase_g); 67 | mp_int *power = mp_div(p, q); /* this is floor(p/q) == (p-1)/q */ 68 | mp_int *h = mp_from_integer(2); 69 | mp_int *g; 70 | while (1) { 71 | progress_report_attempt(prog); 72 | g = mp_modpow(h, power, p); 73 | if (mp_hs_integer(g, 2)) 74 | break; /* got one */ 75 | mp_free(g); 76 | mp_add_integer_into(h, h, 1); 77 | } 78 | mp_free(h); 79 | mp_free(power); 80 | progress_report_phase_complete(prog); 81 | 82 | /* 83 | * Now we're nearly done. All we need now is our private key x, 84 | * which should be a number between 1 and q-1 exclusive, and 85 | * our public key y = g^x mod p. 86 | */ 87 | mp_int *two = mp_from_integer(2); 88 | mp_int *qm1 = mp_copy(q); 89 | mp_sub_integer_into(qm1, qm1, 1); 90 | mp_int *x = mp_random_in_range(two, qm1); 91 | mp_free(two); 92 | mp_free(qm1); 93 | 94 | key->sshk.vt = &ssh_dss; 95 | 96 | key->p = p; 97 | key->q = q; 98 | key->g = g; 99 | key->x = x; 100 | key->y = mp_modpow(key->g, key->x, key->p); 101 | 102 | return 1; 103 | } 104 | -------------------------------------------------------------------------------- /sshecdsag.c: -------------------------------------------------------------------------------- 1 | /* 2 | * EC key generation. 3 | */ 4 | 5 | #include "ssh.h" 6 | #include "sshkeygen.h" 7 | #include "mpint.h" 8 | 9 | int ecdsa_generate(struct ecdsa_key *ek, int bits) 10 | { 11 | if (!ec_nist_alg_and_curve_by_bits(bits, &ek->curve, &ek->sshk.vt)) 12 | return 0; 13 | 14 | mp_int *one = mp_from_integer(1); 15 | ek->privateKey = mp_random_in_range(one, ek->curve->w.G_order); 16 | mp_free(one); 17 | 18 | ek->publicKey = ecdsa_public(ek->privateKey, ek->sshk.vt); 19 | 20 | return 1; 21 | } 22 | 23 | int eddsa_generate(struct eddsa_key *ek, int bits) 24 | { 25 | if (!ec_ed_alg_and_curve_by_bits(bits, &ek->curve, &ek->sshk.vt)) 26 | return 0; 27 | 28 | /* EdDSA secret keys are just 32 bytes of hash preimage; the 29 | * 64-byte SHA-512 hash of that key will be used when signing, 30 | * but the form of the key stored on disk is the preimage 31 | * only. */ 32 | ek->privateKey = mp_random_bits(bits); 33 | 34 | ek->publicKey = eddsa_public(ek->privateKey, ek->sshk.vt); 35 | 36 | return 1; 37 | } 38 | -------------------------------------------------------------------------------- /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 | time_t expiry; 14 | } gssapi_ssh_gss_ctx; 15 | 16 | void ssh_gssapi_bind_fns(struct ssh_gss_library *lib); 17 | 18 | #else 19 | 20 | int ssh_gssapi_init(void); 21 | 22 | #endif /*NO_GSSAPI*/ 23 | 24 | #endif /*PUTTY_SSHGSSC_H*/ 25 | -------------------------------------------------------------------------------- /sshmac.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Centralised parts of the SSH-2 MAC API, which don't need to vary 3 | * with the MAC implementation. 4 | */ 5 | 6 | #include 7 | 8 | #include "ssh.h" 9 | 10 | bool ssh2_mac_verresult(ssh2_mac *mac, const void *candidate) 11 | { 12 | unsigned char correct[64]; /* at least as big as all known MACs */ 13 | bool toret; 14 | 15 | assert(mac->vt->len <= sizeof(correct)); 16 | ssh2_mac_genresult(mac, correct); 17 | toret = smemeq(correct, candidate, mac->vt->len); 18 | 19 | smemclr(correct, sizeof(correct)); 20 | 21 | return toret; 22 | } 23 | 24 | static void ssh2_mac_prepare(ssh2_mac *mac, const void *blk, int len, 25 | unsigned long seq) 26 | { 27 | ssh2_mac_start(mac); 28 | put_uint32(mac, seq); 29 | put_data(mac, blk, len); 30 | } 31 | 32 | void ssh2_mac_generate(ssh2_mac *mac, void *blk, int len, unsigned long seq) 33 | { 34 | ssh2_mac_prepare(mac, blk, len, seq); 35 | ssh2_mac_genresult(mac, (unsigned char *)blk + len); 36 | } 37 | 38 | bool ssh2_mac_verify( 39 | ssh2_mac *mac, const void *blk, int len, unsigned long seq) 40 | { 41 | ssh2_mac_prepare(mac, blk, len, seq); 42 | return ssh2_mac_verresult(mac, (const unsigned char *)blk + len); 43 | } 44 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /sshsignals.h: -------------------------------------------------------------------------------- 1 | /* 2 | * List of signal names known to SSH, indicating whether PuTTY's UI 3 | * for special session commands likes to put them in the main specials 4 | * menu or in a submenu (and if the former, what title they have). 5 | * 6 | * This is a separate header file rather than my usual style of a 7 | * parametric list macro, because in this case I need to be able to 8 | * #ifdef out each mode in case it's not defined on a particular 9 | * target system. 10 | * 11 | * If you want only the locally defined signals, #define 12 | * SIGNALS_LOCAL_ONLY before including this header. 13 | */ 14 | 15 | #if !defined SIGNALS_LOCAL_ONLY || defined SIGINT 16 | SIGNAL_MAIN(INT, "Interrupt") 17 | #endif 18 | #if !defined SIGNALS_LOCAL_ONLY || defined SIGTERM 19 | SIGNAL_MAIN(TERM, "Terminate") 20 | #endif 21 | #if !defined SIGNALS_LOCAL_ONLY || defined SIGKILL 22 | SIGNAL_MAIN(KILL, "Kill") 23 | #endif 24 | #if !defined SIGNALS_LOCAL_ONLY || defined SIGQUIT 25 | SIGNAL_MAIN(QUIT, "Quit") 26 | #endif 27 | #if !defined SIGNALS_LOCAL_ONLY || defined SIGHUP 28 | SIGNAL_MAIN(HUP, "Hangup") 29 | #endif 30 | #if !defined SIGNALS_LOCAL_ONLY || defined SIGABRT 31 | SIGNAL_SUB(ABRT) 32 | #endif 33 | #if !defined SIGNALS_LOCAL_ONLY || defined SIGALRM 34 | SIGNAL_SUB(ALRM) 35 | #endif 36 | #if !defined SIGNALS_LOCAL_ONLY || defined SIGFPE 37 | SIGNAL_SUB(FPE) 38 | #endif 39 | #if !defined SIGNALS_LOCAL_ONLY || defined SIGILL 40 | SIGNAL_SUB(ILL) 41 | #endif 42 | #if !defined SIGNALS_LOCAL_ONLY || defined SIGPIPE 43 | SIGNAL_SUB(PIPE) 44 | #endif 45 | #if !defined SIGNALS_LOCAL_ONLY || defined SIGSEGV 46 | SIGNAL_SUB(SEGV) 47 | #endif 48 | #if !defined SIGNALS_LOCAL_ONLY || defined SIGUSR1 49 | SIGNAL_SUB(USR1) 50 | #endif 51 | #if !defined SIGNALS_LOCAL_ONLY || defined SIGUSR2 52 | SIGNAL_SUB(USR2) 53 | #endif 54 | -------------------------------------------------------------------------------- /sshutils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Supporting routines used in common by all the various components of 3 | * the SSH system. 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | #include "putty.h" 10 | #include "ssh.h" 11 | #include "sshchan.h" 12 | 13 | /* ---------------------------------------------------------------------- 14 | * Centralised standard methods for other channel implementations to 15 | * borrow. 16 | */ 17 | 18 | void chan_remotely_opened_confirmation(Channel *chan) 19 | { 20 | unreachable("this channel type should never receive OPEN_CONFIRMATION"); 21 | } 22 | 23 | void chan_remotely_opened_failure(Channel *chan, const char *errtext) 24 | { 25 | unreachable("this channel type should never receive OPEN_FAILURE"); 26 | } 27 | 28 | bool chan_default_want_close( 29 | Channel *chan, bool sent_local_eof, bool rcvd_remote_eof) 30 | { 31 | /* 32 | * Default close policy: we start initiating the CHANNEL_CLOSE 33 | * procedure as soon as both sides of the channel have seen EOF. 34 | */ 35 | return sent_local_eof && rcvd_remote_eof; 36 | } 37 | 38 | bool chan_no_exit_status(Channel *chan, int status) 39 | { 40 | return false; 41 | } 42 | 43 | bool chan_no_exit_signal( 44 | Channel *chan, ptrlen signame, bool core_dumped, ptrlen msg) 45 | { 46 | return false; 47 | } 48 | 49 | bool chan_no_exit_signal_numeric( 50 | Channel *chan, int signum, bool core_dumped, ptrlen msg) 51 | { 52 | return false; 53 | } 54 | 55 | bool chan_no_run_shell(Channel *chan) 56 | { 57 | return false; 58 | } 59 | 60 | bool chan_no_run_command(Channel *chan, ptrlen command) 61 | { 62 | return false; 63 | } 64 | 65 | bool chan_no_run_subsystem(Channel *chan, ptrlen subsys) 66 | { 67 | return false; 68 | } 69 | 70 | bool chan_no_enable_x11_forwarding( 71 | Channel *chan, bool oneshot, ptrlen authproto, ptrlen authdata, 72 | unsigned screen_number) 73 | { 74 | return false; 75 | } 76 | 77 | bool chan_no_enable_agent_forwarding(Channel *chan) 78 | { 79 | return false; 80 | } 81 | 82 | bool chan_no_allocate_pty( 83 | Channel *chan, ptrlen termtype, unsigned width, unsigned height, 84 | unsigned pixwidth, unsigned pixheight, struct ssh_ttymodes modes) 85 | { 86 | return false; 87 | } 88 | 89 | bool chan_no_set_env(Channel *chan, ptrlen var, ptrlen value) 90 | { 91 | return false; 92 | } 93 | 94 | bool chan_no_send_break(Channel *chan, unsigned length) 95 | { 96 | return false; 97 | } 98 | 99 | bool chan_no_send_signal(Channel *chan, ptrlen signame) 100 | { 101 | return false; 102 | } 103 | 104 | bool chan_no_change_window_size( 105 | Channel *chan, unsigned width, unsigned height, 106 | unsigned pixwidth, unsigned pixheight) 107 | { 108 | return false; 109 | } 110 | 111 | void chan_no_request_response(Channel *chan, bool success) 112 | { 113 | unreachable("this channel type should never send a want-reply request"); 114 | } 115 | 116 | /* ---------------------------------------------------------------------- 117 | * Other miscellaneous utility functions. 118 | */ 119 | 120 | void free_rportfwd(struct ssh_rportfwd *rpf) 121 | { 122 | if (rpf) { 123 | sfree(rpf->log_description); 124 | sfree(rpf->shost); 125 | sfree(rpf->dhost); 126 | sfree(rpf); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /test/agenttestgen.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import sys 4 | 5 | assert sys.version_info[:2] >= (3,0), "This is Python 3 code" 6 | 7 | def generate(): 8 | import hashlib 9 | 10 | print("""\ 11 | # DO NOT EDIT DIRECTLY! Autogenerated by agenttestgen.py 12 | # 13 | # To regenerate, run 14 | # python3 agenttestgen.py > agenttestdata.py 15 | # 16 | # agenttestgen.py depends on the testcrypt system, so you must also 17 | # have built testcrypt in the parent directory, or else set 18 | # PUTTY_TESTCRYPT to point at a working implementation of it. 19 | 20 | """) 21 | 22 | from testcrypt import (rsa_generate, dsa_generate, ecdsa_generate, 23 | eddsa_generate, random_clear, random_queue, 24 | ssh_key_public_blob, ssh_key_openssh_blob, 25 | ssh_key_sign, rsa1_generate, rsa_ssh1_encrypt, 26 | rsa_ssh1_public_blob, rsa_ssh1_private_blob_agent, 27 | mp_from_bytes_be) 28 | from agenttest import (Key2, TestSig2, test_message_to_sign, 29 | Key1, test_session_id) 30 | import ssh 31 | 32 | keygen2 = [ 33 | ('RSA-1024', lambda: rsa_generate(1024, False), 34 | (ssh.SSH_AGENT_RSA_SHA2_256, ssh.SSH_AGENT_RSA_SHA2_512)), 35 | ('DSA-1024', lambda: dsa_generate(1024)), 36 | ('ECDSA-p256', lambda: ecdsa_generate(256)), 37 | ('Ed25519', lambda: eddsa_generate(256)), 38 | ] 39 | 40 | keys2 = [] 41 | 42 | for record in keygen2: 43 | if len(record) == 2: 44 | record += ((),) 45 | comment, genfn, flaglist = record 46 | flaglist = (0,) + flaglist 47 | 48 | random_clear() 49 | random_queue(b''.join(hashlib.sha512('{}{:d}'.format(comment, j) 50 | .encode('ASCII')).digest() 51 | for j in range(1000))) 52 | key = genfn() 53 | sigs = [TestSig2(flags, ssh_key_sign(key, test_message_to_sign, flags)) 54 | for flags in flaglist] 55 | 56 | keys2.append(Key2(comment.encode("ASCII"), 57 | ssh_key_public_blob(key), 58 | sigs, 59 | ssh_key_openssh_blob(key))) 60 | 61 | print("def key2examples(Key2, TestSig2):\n return {!r}".format(keys2)) 62 | 63 | keygen1 = [ 64 | ('RSA-1024a', 1024), 65 | ('RSA-1024b', 1024), 66 | ('RSA-768c', 768), 67 | ('RSA-768d', 768), 68 | ] 69 | 70 | keys1 = [] 71 | 72 | for comment, bits in keygen1: 73 | random_clear() 74 | random_queue(b''.join(hashlib.sha512('{}{:d}'.format(comment, j) 75 | .encode('ASCII')).digest() 76 | for j in range(1000))) 77 | key = rsa1_generate(bits) 78 | preimage = b'Test128BitRSA1ChallengeCleartext' 79 | assert len(preimage) == 32 80 | challenge_bytes = rsa_ssh1_encrypt(preimage, key) 81 | assert len(challenge_bytes) > 0 82 | challenge = int(mp_from_bytes_be(challenge_bytes)) 83 | response = hashlib.md5(preimage + test_session_id).digest() 84 | 85 | keys1.append(Key1(comment.encode("ASCII"), 86 | rsa_ssh1_public_blob(key, 'exponent_first'), 87 | challenge, response, 88 | rsa_ssh1_private_blob_agent(key))) 89 | 90 | print("def key1examples(Key1):\n return {!r}".format(keys1)) 91 | 92 | if __name__ == "__main__": 93 | generate() 94 | -------------------------------------------------------------------------------- /test/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 under strike [Λ̊][チ][text] 8 | Wide char should be off by 1 narrow char: Bold blink under strike [Λ̊][チ][text] 9 | 10 | Double width, double height. Should be red top, magenta bottom, blue DW only: 11 | #3Bold blink under strike [Λ̊][チ][text] 12 | #4Bold blink under strike [Λ̊][チ][text] 13 | #6Bold blink under strike [Λ̊][チ][text] 14 | 15 | -------------------------------------------------------------------------------- /test/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 | -------------------------------------------------------------------------------- /test/mpu-check.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # Trivial command-line client for the function 4 | # Math::Prime::Util::verify_prime, which checks a certificate of 5 | # primality in MPU format. 6 | 7 | use strict; 8 | use warnings; 9 | use Math::Prime::Util; 10 | 11 | Math::Prime::Util::prime_set_config(verbose => 1); 12 | 13 | my $cert = ""; 14 | $cert .= $_ while <<>>; 15 | 16 | my $success = Math::Prime::Util::verify_prime($cert); 17 | 18 | die "verification failed\n" unless $success; 19 | warn "verification succeeded\n"; 20 | -------------------------------------------------------------------------------- /test/primegen.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from testcrypt import * 4 | import base64 5 | import argparse 6 | import itertools 7 | 8 | assert sys.version_info[:2] >= (3,0), "This is Python 3 code" 9 | 10 | def main(): 11 | opener = lambda mode: lambda fname: lambda: argparse.FileType(mode)(fname) 12 | parser = argparse.ArgumentParser(description='') 13 | IntArg = lambda x: int(x, 0) 14 | parser.add_argument("bits", type=IntArg, nargs="?", default=1024) 15 | parser.add_argument("-s", "--seed") 16 | parser.add_argument("-f", "--firstbits", type=IntArg, default=1) 17 | parser.add_argument("--fast", action='store_const', 18 | dest='policy', const='provable_fast') 19 | parser.add_argument("--complex", action='store_const', 20 | dest='policy', const='provable_maurer_complex') 21 | parser.add_argument("-q", "--quiet", action='store_true') 22 | parser.add_argument("-b", "--binary", action='store_const', 23 | dest='fmt', const='{:b}') 24 | parser.add_argument("-x", "--hex", action='store_const', 25 | dest='fmt', const='{:x}') 26 | parser.add_argument("-o", "--output", type=opener("w"), 27 | default=opener("w")("-"), 28 | help="file to write the prime to") 29 | parser.add_argument("--mpu", type=opener("w"), 30 | help="MPU certificate output file") 31 | parser.add_argument("--safe", action='store_true') 32 | parser.set_defaults(fmt='{:d}', policy='provable_maurer_simple') 33 | args = parser.parse_args() 34 | 35 | seed = args.seed 36 | if seed is None: 37 | with open("/dev/urandom", "rb") as f: 38 | seed = base64.b64encode(f.read(32)).decode("ASCII") 39 | 40 | if not args.quiet: 41 | print("seed =", seed) 42 | random_make_prng('sha256', seed) 43 | assert args.firstbits > 0 44 | nfirst = next(i for i in itertools.count() if (args.firstbits >> i) == 0) 45 | pgc = primegen_new_context(args.policy) 46 | if args.safe: 47 | while True: 48 | pcs_q = pcs_new_with_firstbits(args.bits - 1, 49 | args.firstbits, nfirst) 50 | pcs_try_sophie_germain(pcs_q) 51 | q = primegen_generate(pgc, pcs_q) 52 | pcs = pcs_new(args.bits) 53 | pcs_require_residue_1_mod_prime(pcs, q) 54 | pcs_set_oneshot(pcs) 55 | p = primegen_generate(pgc, pcs) 56 | if p is not None: 57 | break 58 | else: 59 | pcs = pcs_new_with_firstbits(args.bits, args.firstbits, nfirst) 60 | p = primegen_generate(pgc, pcs) 61 | 62 | with args.output() as f: 63 | print(args.fmt.format(int(p)), file=f) 64 | 65 | if args.mpu is not None: 66 | s = primegen_mpu_certificate(pgc, p) 67 | with args.mpu() as f: 68 | f.write(s.decode("ASCII")) 69 | 70 | if __name__ == '__main__': 71 | main() 72 | -------------------------------------------------------------------------------- /test/sclog/.gitignore: -------------------------------------------------------------------------------- 1 | /.ninja_* 2 | /CMakeFiles 3 | /CMakeCache.txt 4 | /cmake_install.cmake 5 | /*.ninja 6 | /*.ldscript 7 | /libsclog.so 8 | -------------------------------------------------------------------------------- /test/sclog/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CMake script for the 'sclog' DynamoRIO instrumentation system that 2 | # goes with the PuTTY test binary 'testsc'. For build instructions see 3 | # the comment at the top of testsc.c. 4 | 5 | cmake_minimum_required(VERSION 3.5) 6 | 7 | find_package(DynamoRIO) 8 | if (NOT DynamoRIO_FOUND) 9 | message(FATAL_ERROR "DynamoRIO not found") 10 | endif() 11 | 12 | add_library(sclog SHARED sclog.c) 13 | configure_DynamoRIO_client(sclog) 14 | foreach(extension drmgr drsyms drreg drutil drwrap) 15 | use_DynamoRIO_extension(sclog ${extension}) 16 | endforeach() 17 | -------------------------------------------------------------------------------- /test/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 | -------------------------------------------------------------------------------- /test/ssh.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import struct 3 | import itertools 4 | 5 | assert sys.version_info[:2] >= (3,0), "This is Python 3 code" 6 | 7 | def nbits(n): 8 | # Mimic mp_get_nbits for ordinary Python integers. 9 | assert 0 <= n 10 | smax = next(s for s in itertools.count() if (n >> (1 << s)) == 0) 11 | toret = 0 12 | for shift in reversed([1 << s for s in range(smax)]): 13 | if n >> shift != 0: 14 | n >>= shift 15 | toret += shift 16 | assert n <= 1 17 | if n == 1: 18 | toret += 1 19 | return toret 20 | 21 | def ssh_byte(n): 22 | return struct.pack("B", n) 23 | 24 | def ssh_uint32(n): 25 | return struct.pack(">L", n) 26 | 27 | def ssh_string(s): 28 | return ssh_uint32(len(s)) + s 29 | 30 | def ssh1_mpint(x): 31 | bits = nbits(x) 32 | bytevals = [0xFF & (x >> (8*n)) for n in range((bits-1)//8, -1, -1)] 33 | return struct.pack(">H" + "B" * len(bytevals), bits, *bytevals) 34 | 35 | def ssh2_mpint(x): 36 | bytevals = [0xFF & (x >> (8*n)) for n in range(nbits(x)//8, -1, -1)] 37 | return struct.pack(">L" + "B" * len(bytevals), len(bytevals), *bytevals) 38 | 39 | def decoder(fn): 40 | def decode(s, return_rest = False): 41 | item, length_consumed = fn(s) 42 | if return_rest: 43 | return item, s[length_consumed:] 44 | else: 45 | return item 46 | return decode 47 | 48 | @decoder 49 | def ssh_decode_byte(s): 50 | return struct.unpack_from("B", s, 0)[0], 1 51 | 52 | @decoder 53 | def ssh_decode_uint32(s): 54 | return struct.unpack_from(">L", s, 0)[0], 4 55 | 56 | @decoder 57 | def ssh_decode_string(s): 58 | length = ssh_decode_uint32(s) 59 | assert length + 4 <= len(s) 60 | return s[4:length+4], length+4 61 | 62 | @decoder 63 | def ssh1_get_mpint(s): # returns it unconsumed, still in wire encoding 64 | nbits = struct.unpack_from(">H", s, 0)[0] 65 | nbytes = (nbits + 7) // 8 66 | assert nbytes + 2 <= len(s) 67 | return s[:nbytes+2], nbytes+2 68 | 69 | @decoder 70 | def ssh1_decode_mpint(s): 71 | nbits = struct.unpack_from(">H", s, 0)[0] 72 | nbytes = (nbits + 7) // 8 73 | assert nbytes + 2 <= len(s) 74 | data = s[2:nbytes+2] 75 | v = 0 76 | for b in struct.unpack("B" * len(data), data): 77 | v = (v << 8) | b 78 | return v, nbytes+2 79 | 80 | AGENT_MAX_MSGLEN = 262144 81 | 82 | SSH1_AGENTC_REQUEST_RSA_IDENTITIES = 1 83 | SSH1_AGENT_RSA_IDENTITIES_ANSWER = 2 84 | SSH1_AGENTC_RSA_CHALLENGE = 3 85 | SSH1_AGENT_RSA_RESPONSE = 4 86 | SSH1_AGENTC_ADD_RSA_IDENTITY = 7 87 | SSH1_AGENTC_REMOVE_RSA_IDENTITY = 8 88 | SSH1_AGENTC_REMOVE_ALL_RSA_IDENTITIES = 9 89 | SSH_AGENT_FAILURE = 5 90 | SSH_AGENT_SUCCESS = 6 91 | SSH2_AGENTC_REQUEST_IDENTITIES = 11 92 | SSH2_AGENT_IDENTITIES_ANSWER = 12 93 | SSH2_AGENTC_SIGN_REQUEST = 13 94 | SSH2_AGENT_SIGN_RESPONSE = 14 95 | SSH2_AGENTC_ADD_IDENTITY = 17 96 | SSH2_AGENTC_REMOVE_IDENTITY = 18 97 | SSH2_AGENTC_REMOVE_ALL_IDENTITIES = 19 98 | SSH2_AGENTC_EXTENSION = 27 99 | 100 | SSH_AGENT_RSA_SHA2_256 = 2 101 | SSH_AGENT_RSA_SHA2_512 = 4 102 | -------------------------------------------------------------------------------- /test/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 | -------------------------------------------------------------------------------- /test/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 | -------------------------------------------------------------------------------- /testzlib.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Main program to compile sshzlib.c into a zlib decoding tool. 3 | * 4 | * This is potentially a handy tool in its own right for picking apart 5 | * Zip files or PDFs or PNGs, because it accepts the bare Deflate 6 | * format and the zlib wrapper format, unlike 'zcat' which accepts 7 | * only the gzip wrapper format. 8 | * 9 | * It's also useful as a means for a fuzzer to get reasonably direct 10 | * access to PuTTY's zlib decompressor. 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "defs.h" 19 | #include "ssh.h" 20 | 21 | void out_of_memory(void) 22 | { 23 | fprintf(stderr, "Out of memory!\n"); 24 | exit(1); 25 | } 26 | 27 | int main(int argc, char **argv) 28 | { 29 | unsigned char buf[16], *outbuf; 30 | int ret, outlen; 31 | ssh_decompressor *handle; 32 | int noheader = false, opts = true; 33 | char *filename = NULL; 34 | FILE *fp; 35 | 36 | while (--argc) { 37 | char *p = *++argv; 38 | 39 | if (p[0] == '-' && opts) { 40 | if (!strcmp(p, "-d")) { 41 | noheader = true; 42 | } else if (!strcmp(p, "--")) { 43 | opts = false; /* next thing is filename */ 44 | } else if (!strcmp(p, "--help")) { 45 | printf("usage: testzlib decode zlib (RFC1950) data" 46 | " from standard input\n"); 47 | printf(" testzlib -d decode Deflate (RFC1951) data" 48 | " from standard input\n"); 49 | printf(" testzlib --help display this text\n"); 50 | return 0; 51 | } else { 52 | fprintf(stderr, "unknown command line option '%s'\n", p); 53 | return 1; 54 | } 55 | } else if (!filename) { 56 | filename = p; 57 | } else { 58 | fprintf(stderr, "can only handle one filename\n"); 59 | return 1; 60 | } 61 | } 62 | 63 | handle = ssh_decompressor_new(&ssh_zlib); 64 | 65 | if (noheader) { 66 | /* 67 | * Provide missing zlib header if -d was specified. 68 | */ 69 | static const unsigned char ersatz_zlib_header[] = { 0x78, 0x9C }; 70 | ssh_decompressor_decompress( 71 | handle, ersatz_zlib_header, sizeof(ersatz_zlib_header), 72 | &outbuf, &outlen); 73 | assert(outlen == 0); 74 | } 75 | 76 | if (filename) 77 | fp = fopen(filename, "rb"); 78 | else 79 | fp = stdin; 80 | 81 | if (!fp) { 82 | assert(filename); 83 | fprintf(stderr, "unable to open '%s'\n", filename); 84 | return 1; 85 | } 86 | 87 | while (1) { 88 | ret = fread(buf, 1, sizeof(buf), fp); 89 | if (ret <= 0) 90 | break; 91 | ssh_decompressor_decompress(handle, buf, ret, &outbuf, &outlen); 92 | if (outbuf) { 93 | if (outlen) 94 | fwrite(outbuf, 1, outlen, stdout); 95 | sfree(outbuf); 96 | } else { 97 | fprintf(stderr, "decoding error\n"); 98 | fclose(fp); 99 | return 1; 100 | } 101 | } 102 | 103 | ssh_decompressor_free(handle); 104 | 105 | if (filename) 106 | fclose(fp); 107 | 108 | return 0; 109 | } 110 | -------------------------------------------------------------------------------- /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 | bool 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, 56 | gint colstart, gint colspan); 57 | void columns_taborder_last(Columns *cols, GtkWidget *child); 58 | void columns_force_left_align(Columns *cols, GtkWidget *child); 59 | void columns_force_same_height(Columns *cols, GtkWidget *ch1, GtkWidget *ch2); 60 | 61 | #ifdef __cplusplus 62 | } 63 | #endif /* __cplusplus */ 64 | 65 | #endif /* COLUMNS_H */ 66 | -------------------------------------------------------------------------------- /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, GtkWidget *w, 15 | bool expand, bool fill, guint padding); 16 | void our_dialog_set_action_area(GtkWindow *dlg, GtkWidget *w); 17 | GtkBox *our_dialog_make_action_hbox(GtkWindow *dlg); 18 | 19 | #endif /* PUTTY_GTKMISC_H */ 20 | -------------------------------------------------------------------------------- /unix/pterm.bundle: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | ${env:PUTTY_GTK_PREFIX_FROM_MAKEFILE} 9 | 10 | 11 | gtk+-3.0 12 | 18 | ${project}/../osxlaunch 19 | 20 | 21 | ${project}/pterm.plist 22 | 23 | 24 | ${project}/../ptermapp 25 | 26 | 27 | 28 | ${prefix}/lib/${gtkdir}/${pkg:${gtk}:gtk_binary_version}/immodules/*.so 29 | 30 | 31 | 32 | ${prefix}/lib/${gtkdir}/${pkg:${gtk}:gtk_binary_version}/printbackends/*.so 33 | 34 | 35 | 36 | ${prefix}/share/themes/Adwaita 37 | 38 | 39 | 40 | ${project}/../icons/Pterm.icns 41 | 42 | 43 | 44 | Adwaita 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /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 | 38 | ${env:PUTTY_GTK_PREFIX_FROM_MAKEFILE} 39 | 40 | 41 | gtk+-3.0 42 | 48 | ${project}/../osxlaunch 49 | 50 | 51 | ${project}/putty.plist 52 | 53 | 54 | ${project}/../puttyapp 55 | 56 | 57 | 58 | ${prefix}/lib/${gtkdir}/${pkg:${gtk}:gtk_binary_version}/immodules/*.so 59 | 60 | 61 | 62 | ${prefix}/lib/${gtkdir}/${pkg:${gtk}:gtk_binary_version}/printbackends/*.so 63 | 64 | 65 | 66 | ${prefix}/share/themes/Adwaita 67 | 68 | 69 | 70 | ${project}/../icons/PuTTY.icns 71 | 72 | 73 | 74 | Adwaita 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /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/uxagentsock.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include "putty.h" 11 | #include "ssh.h" 12 | #include "misc.h" 13 | #include "pageant.h" 14 | 15 | Socket *platform_make_agent_socket( 16 | Plug *plug, const char *dirprefix, char **error, char **name) 17 | { 18 | char *username, *socketdir, *socketname, *errw; 19 | const char *errr; 20 | Socket *sock; 21 | 22 | *name = NULL; 23 | 24 | username = get_username(); 25 | socketdir = dupprintf("%s.%s", dirprefix, username); 26 | sfree(username); 27 | 28 | assert(*socketdir == '/'); 29 | if ((errw = make_dir_and_check_ours(socketdir)) != NULL) { 30 | *error = dupprintf("%s: %s\n", socketdir, errw); 31 | sfree(errw); 32 | sfree(socketdir); 33 | return NULL; 34 | } 35 | 36 | socketname = dupprintf("%s/pageant.%d", socketdir, (int)getpid()); 37 | sock = new_unix_listener(unix_sock_addr(socketname), plug); 38 | if ((errr = sk_socket_error(sock)) != NULL) { 39 | *error = dupprintf("%s: %s\n", socketname, errr); 40 | sk_close(sock); 41 | sfree(socketname); 42 | rmdir(socketdir); 43 | sfree(socketdir); 44 | return NULL; 45 | } 46 | 47 | /* 48 | * Spawn a subprocess which will try to reliably delete our socket 49 | * and its containing directory when we terminate, in case we die 50 | * unexpectedly. 51 | */ 52 | { 53 | int cleanup_pipe[2]; 54 | pid_t pid; 55 | 56 | /* Don't worry if pipe or fork fails; it's not _that_ critical. */ 57 | if (!pipe(cleanup_pipe)) { 58 | if ((pid = fork()) == 0) { 59 | int buf[1024]; 60 | /* 61 | * Our parent process holds the writing end of 62 | * this pipe, and writes nothing to it. Hence, 63 | * we expect read() to return EOF as soon as 64 | * that process terminates. 65 | */ 66 | 67 | close(0); 68 | close(1); 69 | close(2); 70 | 71 | setpgid(0, 0); 72 | close(cleanup_pipe[1]); 73 | while (read(cleanup_pipe[0], buf, sizeof(buf)) > 0); 74 | unlink(socketname); 75 | rmdir(socketdir); 76 | _exit(0); 77 | } else if (pid < 0) { 78 | close(cleanup_pipe[0]); 79 | close(cleanup_pipe[1]); 80 | } else { 81 | close(cleanup_pipe[0]); 82 | cloexec(cleanup_pipe[1]); 83 | } 84 | } 85 | } 86 | 87 | *name = socketname; 88 | *error = NULL; 89 | sfree(socketdir); 90 | return sock; 91 | } 92 | -------------------------------------------------------------------------------- /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, bool 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 = false; 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 = 48 | sresize(c->radio.buttons, c->radio.nbuttons, char *); 49 | c->radio.buttons[c->radio.nbuttons-1] = 50 | dupstr("Local"); 51 | c->radio.buttondata = 52 | sresize(c->radio.buttondata, c->radio.nbuttons, intorptr); 53 | c->radio.buttondata[c->radio.nbuttons-1] = I(PROXY_CMD); 54 | break; 55 | } 56 | } 57 | 58 | for (i = 0; i < s->ncontrols; i++) { 59 | c = s->ctrls[i]; 60 | if (c->generic.type == CTRL_EDITBOX && 61 | c->generic.context.i == CONF_proxy_telnet_command) { 62 | assert(c->generic.handler == conf_editbox_handler); 63 | sfree(c->generic.label); 64 | c->generic.label = dupstr("Telnet command, or local" 65 | " proxy command"); 66 | break; 67 | } 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /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 | static const char *const default_devices[] = { 21 | "/dev/urandom", "/dev/random" 22 | }; 23 | size_t i; 24 | 25 | for (i = 0; i < lenof(default_devices); i++) { 26 | if (access(default_devices[i], R_OK) == 0) { 27 | device = default_devices[i]; 28 | break; 29 | } 30 | } 31 | 32 | if (!device) { 33 | sfree(buf); 34 | fprintf(stderr, "puttygen: cannot find a readable " 35 | "random number source; use --random-device\n"); 36 | return NULL; 37 | } 38 | } 39 | 40 | fd = open(device, O_RDONLY); 41 | if (fd < 0) { 42 | sfree(buf); 43 | fprintf(stderr, "puttygen: %s: open: %s\n", 44 | device, strerror(errno)); 45 | return NULL; 46 | } 47 | 48 | ngot = 0; 49 | while (ngot < len) { 50 | ret = read(fd, buf+ngot, len-ngot); 51 | if (ret < 0) { 52 | close(fd); 53 | sfree(buf); 54 | fprintf(stderr, "puttygen: %s: read: %s\n", 55 | device, strerror(errno)); 56 | return NULL; 57 | } 58 | ngot += ret; 59 | } 60 | 61 | close(fd); 62 | 63 | return buf; 64 | } 65 | -------------------------------------------------------------------------------- /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 bool 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 false; 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 false; 34 | } 35 | ngot += ret; 36 | } 37 | 38 | close(fd); 39 | 40 | return true; 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 | bool got_dev_urandom = false; 56 | 57 | if (read_dev_urandom(buf, 32)) { 58 | got_dev_urandom = true; 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, "popen: %s\n" 69 | "Unable to access fallback entropy source\n", strerror(errno)); 70 | exit(1); 71 | } 72 | 73 | fp = popen("ls -al /tmp 2>/dev/null", "r"); 74 | if (fp) { 75 | while ( (ret = fread(buf, 1, sizeof(buf), fp)) > 0) 76 | func(buf, ret); 77 | pclose(fp); 78 | } else if (!got_dev_urandom) { 79 | fprintf(stderr, "popen: %s\n" 80 | "Unable to access fallback entropy source\n", strerror(errno)); 81 | exit(1); 82 | } 83 | 84 | read_random_seed(func); 85 | } 86 | 87 | /* 88 | * This function is called on a timer, and grabs as much changeable 89 | * system data as it can quickly get its hands on. 90 | */ 91 | void noise_regular(void) 92 | { 93 | int fd; 94 | int ret; 95 | char buf[512]; 96 | struct rusage rusage; 97 | 98 | if ((fd = open("/proc/meminfo", O_RDONLY)) >= 0) { 99 | while ( (ret = read(fd, buf, sizeof(buf))) > 0) 100 | random_add_noise(NOISE_SOURCE_MEMINFO, buf, ret); 101 | close(fd); 102 | } 103 | if ((fd = open("/proc/stat", O_RDONLY)) >= 0) { 104 | while ( (ret = read(fd, buf, sizeof(buf))) > 0) 105 | random_add_noise(NOISE_SOURCE_STAT, buf, ret); 106 | close(fd); 107 | } 108 | getrusage(RUSAGE_SELF, &rusage); 109 | random_add_noise(NOISE_SOURCE_RUSAGE, &rusage, sizeof(rusage)); 110 | } 111 | 112 | /* 113 | * This function is called on every keypress or mouse move, and 114 | * will add the current time to the noise pool. It gets the scan 115 | * code or mouse position passed in, and adds that too. 116 | */ 117 | void noise_ultralight(NoiseSourceId id, unsigned long data) 118 | { 119 | struct timeval tv; 120 | gettimeofday(&tv, NULL); 121 | random_add_noise(NOISE_SOURCE_TIME, &tv, sizeof(tv)); 122 | random_add_noise(id, &data, sizeof(data)); 123 | } 124 | 125 | uint64_t prng_reseed_time_ms(void) 126 | { 127 | struct timeval tv; 128 | gettimeofday(&tv, NULL); 129 | return tv.tv_sec * 1000 + tv.tv_usec / 1000; 130 | } 131 | -------------------------------------------------------------------------------- /unix/uxpeer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Unix: wrapper for getsockopt(SO_PEERCRED), conditionalised on 3 | * appropriate autoconfery. 4 | */ 5 | 6 | #ifdef HAVE_CONFIG_H 7 | # include "uxconfig.h" /* leading space prevents mkfiles.pl trying to follow */ 8 | #endif 9 | 10 | #ifdef HAVE_SO_PEERCRED 11 | #define _GNU_SOURCE 12 | #include 13 | #endif 14 | 15 | #include 16 | 17 | #include "putty.h" 18 | 19 | bool so_peercred(int fd, int *pid, int *uid, int *gid) 20 | { 21 | #ifdef HAVE_SO_PEERCRED 22 | struct ucred cr; 23 | socklen_t crlen = sizeof(cr); 24 | if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &crlen) == 0) { 25 | *pid = cr.pid; 26 | *uid = cr.uid; 27 | *gid = cr.gid; 28 | return true; 29 | } 30 | #endif 31 | return false; 32 | } 33 | -------------------------------------------------------------------------------- /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, const void *data, size_t 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 | *nprinters_ptr = 0; 54 | return NULL; 55 | } 56 | char *printer_get_name(printer_enum *pe, int i) { return NULL; 57 | } 58 | void printer_finish_enum(printer_enum *pe) { } 59 | -------------------------------------------------------------------------------- /unix/uxproxy.c: -------------------------------------------------------------------------------- 1 | /* 2 | * uxproxy.c: Unix implementation of platform_new_connection(), 3 | * supporting an OpenSSH-like proxy command. 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "tree234.h" 13 | #include "putty.h" 14 | #include "network.h" 15 | #include "proxy.h" 16 | 17 | Socket *platform_new_connection(SockAddr *addr, const char *hostname, 18 | int port, bool privport, 19 | bool oobinline, bool nodelay, bool keepalive, 20 | Plug *plug, Conf *conf) 21 | { 22 | char *cmd; 23 | 24 | int to_cmd_pipe[2], from_cmd_pipe[2], cmd_err_pipe[2], pid, proxytype; 25 | int infd, outfd, inerrfd; 26 | 27 | proxytype = conf_get_int(conf, CONF_proxy_type); 28 | if (proxytype != PROXY_CMD && proxytype != PROXY_FUZZ) 29 | return NULL; 30 | 31 | if (proxytype == PROXY_CMD) { 32 | cmd = format_telnet_command(addr, port, conf); 33 | 34 | { 35 | char *logmsg = dupprintf("Starting local proxy command: %s", cmd); 36 | plug_log(plug, PLUGLOG_PROXY_MSG, NULL, 0, logmsg, 0); 37 | sfree(logmsg); 38 | } 39 | 40 | /* 41 | * Create the pipes to the proxy command, and spawn the proxy 42 | * command process. 43 | */ 44 | if (pipe(to_cmd_pipe) < 0 || 45 | pipe(from_cmd_pipe) < 0 || 46 | pipe(cmd_err_pipe) < 0) { 47 | sfree(cmd); 48 | return new_error_socket_fmt(plug, "pipe: %s", strerror(errno)); 49 | } 50 | cloexec(to_cmd_pipe[1]); 51 | cloexec(from_cmd_pipe[0]); 52 | cloexec(cmd_err_pipe[0]); 53 | 54 | pid = fork(); 55 | if (pid == 0) { 56 | close(0); 57 | close(1); 58 | dup2(to_cmd_pipe[0], 0); 59 | dup2(from_cmd_pipe[1], 1); 60 | close(to_cmd_pipe[0]); 61 | close(from_cmd_pipe[1]); 62 | dup2(cmd_err_pipe[1], 2); 63 | noncloexec(0); 64 | noncloexec(1); 65 | execl("/bin/sh", "sh", "-c", cmd, (void *)NULL); 66 | _exit(255); 67 | } 68 | 69 | sfree(cmd); 70 | 71 | if (pid < 0) 72 | return new_error_socket_fmt(plug, "fork: %s", strerror(errno)); 73 | 74 | close(to_cmd_pipe[0]); 75 | close(from_cmd_pipe[1]); 76 | close(cmd_err_pipe[1]); 77 | 78 | outfd = to_cmd_pipe[1]; 79 | infd = from_cmd_pipe[0]; 80 | inerrfd = cmd_err_pipe[0]; 81 | } else { 82 | cmd = format_telnet_command(addr, port, conf); 83 | outfd = open("/dev/null", O_WRONLY); 84 | if (outfd == -1) { 85 | sfree(cmd); 86 | return new_error_socket_fmt( 87 | plug, "/dev/null: %s", strerror(errno)); 88 | } 89 | infd = open(cmd, O_RDONLY); 90 | if (infd == -1) { 91 | Socket *toret = new_error_socket_fmt( 92 | plug, "%s: %s", cmd, strerror(errno)); 93 | sfree(cmd); 94 | close(outfd); 95 | return toret; 96 | } 97 | sfree(cmd); 98 | inerrfd = -1; 99 | } 100 | 101 | /* We are responsible for this and don't need it any more */ 102 | sk_addr_free(addr); 103 | 104 | return make_fd_socket(infd, outfd, inerrfd, plug); 105 | } 106 | -------------------------------------------------------------------------------- /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 bool use_event_log = false; /* pterm doesn't need it */ 12 | const bool new_session = false, saved_sessions = false; /* or these */ 13 | const bool dup_check_launchable = false; /* no need to check host name 14 | * in conf */ 15 | const bool use_pty_argv = true; 16 | 17 | const unsigned cmdline_tooltype = TOOLTYPE_NONNETWORK; 18 | 19 | /* gtkwin.c will call this, and in pterm it's not needed */ 20 | void noise_ultralight(NoiseSourceId id, unsigned long data) { } 21 | 22 | const struct BackendVtable *select_backend(Conf *conf) 23 | { 24 | return &pty_backend; 25 | } 26 | 27 | void initial_config_box(Conf *conf, post_dialog_fn_t after, void *afterctx) 28 | { 29 | /* 30 | * This is a no-op in pterm, except that we'll ensure the protocol 31 | * is set to -1 to inhibit the useless Connection panel in the 32 | * config box. So we do that and then just immediately call the 33 | * post-dialog function with a positive result. 34 | */ 35 | conf_set_int(conf, CONF_protocol, -1); 36 | after(afterctx, 1); 37 | } 38 | 39 | void cleanup_exit(int code) 40 | { 41 | exit(code); 42 | } 43 | 44 | char *make_default_wintitle(char *hostname) 45 | { 46 | return dupstr("pterm"); 47 | } 48 | 49 | void setup(bool single) 50 | { 51 | settings_set_default_protocol(-1); 52 | 53 | if (single) 54 | pty_pre_init(); 55 | } 56 | -------------------------------------------------------------------------------- /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 | #define MAY_REFER_TO_GTK_IN_HEADERS 14 | 15 | #include "putty.h" 16 | #include "ssh.h" 17 | #include "storage.h" 18 | 19 | #include "gtkcompat.h" 20 | 21 | /* 22 | * Stubs to avoid uxpty.c needing to be linked in. 23 | */ 24 | const bool use_pty_argv = false; 25 | char **pty_argv; /* never used */ 26 | char *pty_osx_envrestore_prefix; 27 | 28 | /* 29 | * Clean up and exit. 30 | */ 31 | void cleanup_exit(int code) 32 | { 33 | /* 34 | * Clean up. 35 | */ 36 | sk_cleanup(); 37 | random_save_seed(); 38 | exit(code); 39 | } 40 | 41 | const struct BackendVtable *select_backend(Conf *conf) 42 | { 43 | const struct BackendVtable *vt = 44 | backend_vt_from_proto(conf_get_int(conf, CONF_protocol)); 45 | assert(vt != NULL); 46 | return vt; 47 | } 48 | 49 | void initial_config_box(Conf *conf, post_dialog_fn_t after, void *afterctx) 50 | { 51 | char *title = dupcat(appname, " Configuration"); 52 | create_config_box(title, conf, false, 0, after, afterctx); 53 | sfree(title); 54 | } 55 | 56 | const bool use_event_log = true, new_session = true, saved_sessions = true; 57 | const bool dup_check_launchable = true; 58 | 59 | char *make_default_wintitle(char *hostname) 60 | { 61 | return dupcat(hostname, " - ", appname); 62 | } 63 | 64 | /* 65 | * X11-forwarding-related things suitable for Gtk app. 66 | */ 67 | 68 | char *platform_get_x_display(void) { 69 | const char *display; 70 | /* Try to take account of --display and what have you. */ 71 | if (!(display = gdk_get_display())) 72 | /* fall back to traditional method */ 73 | display = getenv("DISPLAY"); 74 | return dupstr(display); 75 | } 76 | 77 | const bool share_can_be_downstream = true; 78 | const bool share_can_be_upstream = true; 79 | 80 | const unsigned cmdline_tooltype = 81 | TOOLTYPE_HOST_ARG | 82 | TOOLTYPE_PORT_ARG | 83 | TOOLTYPE_NO_VERBOSE_OPTION; 84 | 85 | void setup(bool single) 86 | { 87 | sk_init(); 88 | settings_set_default_protocol(be_default_protocol); 89 | /* Find the appropriate default port. */ 90 | { 91 | const struct BackendVtable *vt = 92 | backend_vt_from_proto(be_default_protocol); 93 | settings_set_default_port(0); /* illegal */ 94 | if (vt) 95 | settings_set_default_port(vt->default_port); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /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() or poll()-type things doing to them during an extended 8 | * program 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 | noise_ultralight(NOISE_SOURCE_IOID, fd); 119 | 120 | /* 121 | * Apparently this can sometimes be NULL. Can't see how, but I 122 | * assume it means I need to ignore the event since it's on an 123 | * fd I've stopped being interested in. Sigh. 124 | */ 125 | if (fdstruct) 126 | fdstruct->callback(fd, event); 127 | } 128 | -------------------------------------------------------------------------------- /unix/uxsignal.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "defs.h" 6 | 7 | /* 8 | * Calling signal() is non-portable, as it varies in meaning 9 | * between platforms and depending on feature macros, and has 10 | * stupid semantics at least some of the time. 11 | * 12 | * This function provides the same interface as the libc function, 13 | * but provides consistent semantics. It assumes POSIX semantics 14 | * for sigaction() (so you might need to do some more work if you 15 | * port to something ancient like SunOS 4) 16 | */ 17 | void (*putty_signal(int sig, void (*func)(int)))(int) { 18 | struct sigaction sa; 19 | struct sigaction old; 20 | 21 | sa.sa_handler = func; 22 | if(sigemptyset(&sa.sa_mask) < 0) 23 | return SIG_ERR; 24 | sa.sa_flags = SA_RESTART; 25 | if(sigaction(sig, &sa, &old) < 0) 26 | return SIG_ERR; 27 | return old.sa_handler; 28 | } 29 | 30 | void block_signal(int sig, bool block_it) 31 | { 32 | sigset_t ss; 33 | 34 | sigemptyset(&ss); 35 | sigaddset(&ss, sig); 36 | if(sigprocmask(block_it ? SIG_BLOCK : SIG_UNBLOCK, &ss, 0) < 0) { 37 | perror("sigprocmask"); 38 | exit(1); 39 | } 40 | } 41 | 42 | /* 43 | Local Variables: 44 | c-basic-offset:4 45 | comment-column:40 46 | End: 47 | */ 48 | -------------------------------------------------------------------------------- /unix/uxutils.c: -------------------------------------------------------------------------------- 1 | #include "putty.h" 2 | #include "ssh.h" 3 | 4 | #if defined __linux__ && (defined __arm__ || defined __aarch64__) && \ 5 | HAVE_SYS_AUXV_H && HAVE_ASM_HWCAP_H 6 | 7 | #include 8 | #include 9 | 10 | bool platform_aes_hw_available(void) 11 | { 12 | #if defined HWCAP_AES 13 | return getauxval(AT_HWCAP) & HWCAP_AES; 14 | #elif defined HWCAP2_AES 15 | return getauxval(AT_HWCAP2) & HWCAP2_AES; 16 | #else 17 | return false; 18 | #endif 19 | } 20 | 21 | bool platform_sha256_hw_available(void) 22 | { 23 | #if defined HWCAP_SHA2 24 | return getauxval(AT_HWCAP) & HWCAP_SHA2; 25 | #elif defined HWCAP2_SHA2 26 | return getauxval(AT_HWCAP2) & HWCAP2_SHA2; 27 | #else 28 | return false; 29 | #endif 30 | } 31 | 32 | bool platform_sha1_hw_available(void) 33 | { 34 | #if defined HWCAP_SHA1 35 | return getauxval(AT_HWCAP) & HWCAP_SHA1; 36 | #elif defined HWCAP2_SHA1 37 | return getauxval(AT_HWCAP2) & HWCAP2_SHA1; 38 | #else 39 | return false; 40 | #endif 41 | } 42 | 43 | #else 44 | 45 | bool platform_aes_hw_available(void) 46 | { 47 | return false; 48 | } 49 | 50 | bool platform_sha256_hw_available(void) 51 | { 52 | return false; 53 | } 54 | 55 | bool platform_sha1_hw_available(void) 56 | { 57 | return false; 58 | } 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /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 | static struct x11_err_to_ignore *errs; 36 | static size_t nerrs, errsize; 37 | 38 | static int x11_error_handler(Display *thisdisp, XErrorEvent *err) 39 | { 40 | for (size_t i = 0; i < nerrs; i++) { 41 | if (thisdisp == errs[i].display && 42 | err->serial == errs[i].serial && 43 | err->error_code == errs[i].error_code) { 44 | /* Ok, this is an error we're happy to ignore */ 45 | return 0; 46 | } 47 | } 48 | 49 | return (*orig_x11_error_handler)(thisdisp, err); 50 | } 51 | 52 | void x11_ignore_error(Display *disp, unsigned char errcode) 53 | { 54 | /* 55 | * Install our error handler, if we haven't already. 56 | */ 57 | if (!orig_x11_error_handler) 58 | orig_x11_error_handler = XSetErrorHandler(x11_error_handler); 59 | 60 | /* 61 | * This is as good a moment as any to winnow the ignore list based 62 | * on requests we know to have been processed. 63 | */ 64 | { 65 | unsigned long last = LastKnownRequestProcessed(disp); 66 | size_t i, j; 67 | for (i = j = 0; i < nerrs; i++) { 68 | if (errs[i].display == disp && errs[i].serial <= last) 69 | continue; 70 | errs[j++] = errs[i]; 71 | } 72 | nerrs = j; 73 | } 74 | 75 | sgrowarray(errs, errsize, nerrs); 76 | errs[nerrs].display = disp; 77 | errs[nerrs].error_code = errcode; 78 | errs[nerrs].serial = NextRequest(disp); 79 | nerrs++; 80 | } 81 | 82 | #endif 83 | 84 | -------------------------------------------------------------------------------- /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 | /* 16 | * gtkmisc.c 17 | */ 18 | Display *get_x11_display(void); 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /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 | #include "putty.h" 12 | #include "ssh.h" 13 | 14 | #ifdef SOURCE_COMMIT 15 | #include "empty.h" 16 | #endif 17 | 18 | #include "version.h" 19 | 20 | const char ver[] = TEXTVER; 21 | const char sshver[] = SSHVER; 22 | const char commitid[] = SOURCE_COMMIT; 23 | 24 | /* 25 | * SSH local version string MUST be under 40 characters. Here's a 26 | * compile time assertion to verify this. 27 | */ 28 | enum { vorpal_sword = 1 / (sizeof(sshver) <= 40) }; 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 "-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 | 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/make_install_images.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Script to make the bitmap files that go into the PuTTY MSI installer. 4 | 5 | set -e 6 | 7 | # For convenience, allow this script to be run from the Windows 8 | # subdirectory as well as the top level of the source tree. 9 | if test -f installer.wxs -a ! -f putty.h -a -f ../putty.h; then 10 | cd .. 11 | fi 12 | 13 | convert -size 164x312 'gradient:blue-white' -distort SRT -90 -swirl 180 \ 14 | \( icons/putty-48.png -geometry +28+24 \) -composite \ 15 | \( icons/pscp-48.png -geometry +88+96 \) -composite \ 16 | \( icons/puttygen-48.png -geometry +28+168 \) -composite \ 17 | \( icons/pageant-48.png -geometry +88+240 \) -composite \ 18 | windows/msidialog.bmp 19 | 20 | convert -size 493x58 canvas:white \ 21 | \( icons/putty-48.png -geometry +440+5 \) -composite \ 22 | windows/msibanner.bmp 23 | -------------------------------------------------------------------------------- /windows/msifixup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import argparse 4 | import os 5 | import tempfile 6 | import shutil 7 | import subprocess 8 | import pipes 9 | 10 | def run(command, verbose): 11 | if verbose: 12 | sys.stdout.write("$ {}\n".format(" ".join( 13 | pipes.quote(word) for word in command))) 14 | out = subprocess.check_output(command) 15 | if verbose: 16 | sys.stdout.write("".join( 17 | "> {}\n".format(line) for line in out.splitlines())) 18 | 19 | def make_changes(msi, args): 20 | run(["msidump", "-t", msi], args.verbose) 21 | build_cmd = ["msibuild", msi] 22 | 23 | def change_table(filename): 24 | with open(filename) as fh: 25 | lines = [line.rstrip("\r\n").split("\t") 26 | for line in iter(fh.readline, "")] 27 | 28 | for line in lines[3:]: 29 | yield line 30 | 31 | with open(filename, "w") as fh: 32 | for line in lines: 33 | fh.write("\t".join(line) + "\r\n") 34 | 35 | build_cmd.extend(["-i", filename]) 36 | 37 | if args.platform is not None: 38 | for line in change_table("_SummaryInformation.idt"): 39 | if line[0] == "7": 40 | line[1] = ";".join([args.platform] + line[1].split(";", 1)[1:]) 41 | 42 | if args.dialog_bmp_width is not None: 43 | for line in change_table("Control.idt"): 44 | if line[9] == "WixUI_Bmp_Dialog": 45 | line[5] = args.dialog_bmp_width 46 | 47 | run(build_cmd, args.verbose) 48 | 49 | def main(): 50 | parser = argparse.ArgumentParser( 51 | description='Change the platform field of an MSI installer package.') 52 | parser.add_argument("msi", help="MSI installer file.") 53 | parser.add_argument("--platform", help="Change the platform field.") 54 | parser.add_argument("--dialog-bmp-width", help="Change the width field" 55 | " in all uses of WixUI_Bmp_Dialog.") 56 | parser.add_argument("-v", "--verbose", action="store_true", 57 | help="Log what this script is doing.") 58 | parser.add_argument("-k", "--keep", action="store_true", 59 | help="Don't delete the temporary working directory.") 60 | args = parser.parse_args() 61 | 62 | msi = os.path.abspath(args.msi) 63 | msidir = os.path.dirname(msi) 64 | try: 65 | tempdir = tempfile.mkdtemp(dir=msidir) 66 | os.chdir(tempdir) 67 | make_changes(msi, args) 68 | finally: 69 | if args.keep: 70 | sys.stdout.write( 71 | "Retained temporary directory {}\n".format(tempdir)) 72 | else: 73 | shutil.rmtree(tempdir) 74 | 75 | if __name__ == '__main__': 76 | main() 77 | -------------------------------------------------------------------------------- /windows/pageant.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/github/putty/7003b43963aef6cdf2841c2a882a684025f1d806/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 | #define APPNAME "Pageant" 8 | #define APPDESC "PuTTY SSH authentication agent" 9 | 10 | #include "winhelp.rc2" 11 | 12 | 200 ICON "pageant.ico" 13 | 201 ICON "pageants.ico" 14 | 15 | 210 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 | 211 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 | 213 DIALOG DISCARDABLE 140, 40, 270, 136 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, 118, 48, 14 47 | PUSHBUTTON "View &Licence", 101, 6, 118, 70, 14 48 | PUSHBUTTON "Visit &Web Site", 102, 140, 118, 70, 14 49 | EDITTEXT 1000, 10, 6, 250, 110, ES_READONLY | ES_MULTILINE | ES_CENTER, WS_EX_STATICEDGE 50 | END 51 | 52 | /* No accelerators used */ 53 | 214 DIALOG DISCARDABLE 50, 50, 326, 239 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, 219, 44, 14 59 | 60 | EDITTEXT 1000, 10, 10, 306, 200, ES_READONLY | ES_MULTILINE | ES_LEFT, WS_EX_STATICEDGE 61 | END 62 | 63 | #include "version.rc2" 64 | 65 | #ifndef NO_MANIFESTS 66 | 1 RT_MANIFEST "pageant.mft" 67 | #endif /* NO_MANIFESTS */ 68 | -------------------------------------------------------------------------------- /windows/pageants.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/github/putty/7003b43963aef6cdf2841c2a882a684025f1d806/windows/pageants.ico -------------------------------------------------------------------------------- /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/github/putty/7003b43963aef6cdf2841c2a882a684025f1d806/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/github/putty/7003b43963aef6cdf2841c2a882a684025f1d806/windows/putty.ico -------------------------------------------------------------------------------- /windows/putty.mft: -------------------------------------------------------------------------------- 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, Rlogin and SUPDUDP client" 5 | 6 | #include "winhelp.rc2" 7 | #include "win_res.rc2" 8 | 9 | #ifndef NO_MANIFESTS 10 | 1 RT_MANIFEST "putty.mft" 11 | #endif /* NO_MANIFESTS */ 12 | -------------------------------------------------------------------------------- /windows/puttycfg.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/github/putty/7003b43963aef6cdf2841c2a882a684025f1d806/windows/puttycfg.ico -------------------------------------------------------------------------------- /windows/puttygen.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/github/putty/7003b43963aef6cdf2841c2a882a684025f1d806/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 | #define APPNAME "PuTTYgen" 8 | #define APPDESC "PuTTY SSH key generation utility" 9 | 10 | #include "winhelp.rc2" 11 | 12 | 200 ICON "puttygen.ico" 13 | 14 | 201 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 | 210 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 | 213 DIALOG DISCARDABLE 140, 40, 270, 136 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, 118, 48, 14 40 | PUSHBUTTON "View &Licence", 101, 6, 118, 70, 14 41 | PUSHBUTTON "Visit &Web Site", 102, 140, 118, 70, 14 42 | EDITTEXT 1000, 10, 6, 250, 110, ES_READONLY | ES_MULTILINE | ES_CENTER, WS_EX_STATICEDGE 43 | END 44 | 45 | /* No accelerators used */ 46 | 214 DIALOG DISCARDABLE 50, 50, 326, 239 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, 219, 44, 14 52 | 53 | EDITTEXT 1000, 10, 10, 306, 200, ES_READONLY | ES_MULTILINE | ES_LEFT, WS_EX_STATICEDGE 54 | END 55 | 56 | #include "version.rc2" 57 | 58 | #ifndef NO_MANIFESTS 59 | 1 RT_MANIFEST "puttygen.mft" 60 | #endif /* NO_MANIFESTS */ 61 | -------------------------------------------------------------------------------- /windows/puttyins.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/github/putty/7003b43963aef6cdf2841c2a882a684025f1d806/windows/puttyins.ico -------------------------------------------------------------------------------- /windows/puttytel.mft: -------------------------------------------------------------------------------- 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/puttytel.rc: -------------------------------------------------------------------------------- 1 | #include "rcstuff.h" 2 | 3 | #define APPNAME "PuTTYtel" 4 | #define APPDESC "Telnet and Rlogin client" 5 | 6 | #include "winhelp.rc2" 7 | #include "win_res.rc2" 8 | 9 | #ifndef NO_MANIFESTS 10 | 1 RT_MANIFEST "puttytel.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 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/version.rc2: -------------------------------------------------------------------------------- 1 | /* 2 | * Standard Windows version information. 3 | * (For inclusion in other .rc files with appropriate macro definitions.) 4 | * 5 | * This file has the more or less arbitrary extension '.rc2' to avoid 6 | * IDEs taking it to be a top-level resource script in its own right 7 | * (which has been known to happen if the extension was '.rc'), and 8 | * also to avoid the resource compiler ignoring everything included 9 | * from it (which happens if the extension is '.h'). 10 | */ 11 | 12 | #include "version.h" 13 | #include "licence.h" 14 | 15 | /* 16 | * The actual VERSIONINFO resource. 17 | */ 18 | VS_VERSION_INFO VERSIONINFO 19 | /* (None of this "fixed" info appears to be trivially user-visible on 20 | * Win98SE. The binary version does show up on Win2K.) */ 21 | FILEVERSION BINARY_VERSION 22 | PRODUCTVERSION BINARY_VERSION /* version of whole suite */ 23 | FILEFLAGSMASK VS_FF_DEBUG | VS_FF_PRERELEASE | VS_FF_PRIVATEBUILD 24 | FILEFLAGS 0x0L 25 | #if defined DEBUG 26 | | VS_FF_DEBUG 27 | #endif 28 | #if defined SNAPSHOT || defined PRERELEASE 29 | | VS_FF_PRERELEASE 30 | #elif !defined RELEASE 31 | | VS_FF_PRIVATEBUILD 32 | #endif 33 | FILEOS VOS__WINDOWS32 34 | FILETYPE VFT_APP 35 | FILESUBTYPE 0x0L /* n/a for VFT_APP */ 36 | BEGIN 37 | /* (On Win98SE and Win2K, we can see most of this on the Version tab 38 | * in the file properties in Explorer.) */ 39 | BLOCK "StringFileInfo" 40 | BEGIN 41 | /* "lang-charset" LLLLCCCC = (UK English, Unicode) */ 42 | BLOCK "080904B0" 43 | BEGIN 44 | VALUE "CompanyName", "Simon Tatham" /* required :/ */ 45 | VALUE "ProductName", "PuTTY suite" 46 | VALUE "FileDescription", APPDESC 47 | VALUE "InternalName", APPNAME 48 | VALUE "OriginalFilename", APPNAME 49 | #if (defined HELPVER) 50 | /* FIXME: this doesn't seem to be visible in Win7/Win10's UI. 51 | * Oh well. */ 52 | VALUE "FileVersion", TEXTVER HELPVER 53 | #else 54 | VALUE "FileVersion", TEXTVER 55 | #endif 56 | VALUE "ProductVersion", TEXTVER 57 | VALUE "LegalCopyright", "Copyright \251 " SHORT_COPYRIGHT_DETAILS "." 58 | #if (!defined SNAPSHOT) && (!defined RELEASE) && (!defined PRERELEASE) 59 | /* Only if VS_FF_PRIVATEBUILD. */ 60 | VALUE "PrivateBuild", TEXTVER /* NBI */ 61 | #endif 62 | END 63 | END 64 | BLOCK "VarFileInfo" 65 | BEGIN 66 | /* Once again -- same meanings -- apparently necessary */ 67 | VALUE "Translation", 0x809, 1200 68 | END 69 | END 70 | -------------------------------------------------------------------------------- /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 | #define ID_CUSTOM_CHMFILE 2000 33 | #define TYPE_CUSTOM_CHMFILE 2000 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /windows/win_res.rc2: -------------------------------------------------------------------------------- 1 | /* 2 | * Windows resources shared between PuTTY and PuTTYtel, to be #include'd 3 | * after defining appropriate macros. 4 | * 5 | * Note that many of these strings mention PuTTY. Due to restrictions in 6 | * VC's handling of string concatenation, this can't easily be fixed. 7 | * It's fixed up at runtime. 8 | * 9 | * This file has the more or less arbitrary extension '.rc2' to avoid 10 | * IDEs taking it to be a top-level resource script in its own right 11 | * (which has been known to happen if the extension was '.rc'), and 12 | * also to avoid the resource compiler ignoring everything included 13 | * from it (which happens if the extension is '.h'). 14 | */ 15 | 16 | #include "win_res.h" 17 | 18 | IDI_MAINICON ICON "putty.ico" 19 | 20 | IDI_CFGICON ICON "puttycfg.ico" 21 | 22 | /* Accelerators used: clw */ 23 | IDD_ABOUTBOX DIALOG DISCARDABLE 140, 40, 270, 136 24 | STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU 25 | CAPTION "About PuTTY" 26 | FONT 8, "MS Shell Dlg" 27 | BEGIN 28 | DEFPUSHBUTTON "&Close", IDOK, 216, 118, 48, 14 29 | PUSHBUTTON "View &Licence", IDA_LICENCE, 6, 118, 70, 14 30 | PUSHBUTTON "Visit &Web Site", IDA_WEB, 140, 118, 70, 14 31 | EDITTEXT IDA_TEXT, 10, 6, 250, 110, ES_READONLY | ES_MULTILINE | ES_CENTER, WS_EX_STATICEDGE 32 | END 33 | 34 | /* Accelerators used: aco */ 35 | IDD_MAINBOX DIALOG DISCARDABLE 0, 0, 300, 252 36 | STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU 37 | CAPTION "PuTTY Configuration" 38 | FONT 8, "MS Shell Dlg" 39 | CLASS "PuTTYConfigBox" 40 | BEGIN 41 | END 42 | 43 | /* Accelerators used: co */ 44 | IDD_LOGBOX DIALOG DISCARDABLE 100, 20, 300, 119 45 | STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU 46 | CAPTION "PuTTY Event Log" 47 | FONT 8, "MS Shell Dlg" 48 | BEGIN 49 | DEFPUSHBUTTON "&Close", IDOK, 135, 102, 44, 14 50 | PUSHBUTTON "C&opy", IDN_COPY, 81, 102, 44, 14 51 | LISTBOX IDN_LIST, 3, 3, 294, 95, LBS_HASSTRINGS | LBS_USETABSTOPS | WS_VSCROLL | LBS_EXTENDEDSEL 52 | END 53 | 54 | /* No accelerators used */ 55 | IDD_LICENCEBOX DIALOG DISCARDABLE 50, 50, 326, 239 56 | STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU 57 | CAPTION "PuTTY Licence" 58 | FONT 8, "MS Shell Dlg" 59 | BEGIN 60 | DEFPUSHBUTTON "OK", IDOK, 148, 219, 44, 14 61 | 62 | EDITTEXT IDA_TEXT, 10, 10, 306, 200, ES_READONLY | ES_MULTILINE | ES_LEFT, WS_EX_STATICEDGE 63 | END 64 | 65 | #include "version.rc2" 66 | -------------------------------------------------------------------------------- /windows/wincapi.h: -------------------------------------------------------------------------------- 1 | /* 2 | * wincapi.h: Windows Crypto API functions defined in wincapi.c that 3 | * use the crypt32 library. Also centralises the machinery for 4 | * dynamically loading that library, and our own functions using that 5 | * in turn. 6 | */ 7 | 8 | #if !defined NO_SECURITY 9 | 10 | DECL_WINDOWS_FUNCTION(extern, BOOL, CryptProtectMemory, (LPVOID,DWORD,DWORD)); 11 | 12 | bool got_crypt(void); 13 | 14 | /* 15 | * Function to obfuscate an input string into something usable as a 16 | * pathname for a Windows named pipe. Uses CryptProtectMemory to make 17 | * the obfuscation depend on a key Windows stores for the owning user, 18 | * and then hashes the string as well to make it have a manageable 19 | * length and be composed of filename-legal characters. 20 | * 21 | * Rationale: Windows's named pipes all live in the same namespace, so 22 | * one user can see what pipes another user has open. This is an 23 | * undesirable privacy leak: in particular, if we used unobfuscated 24 | * names for the connection-sharing pipe names, it would permit one 25 | * user to know what username@host another user is SSHing to. 26 | * 27 | * The returned string is dynamically allocated. 28 | */ 29 | char *capi_obfuscate_string(const char *realname); 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /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", false, 10, ANSI_CHARSET); 13 | else 14 | return fontspec_new("", false, 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 | bool platform_default_b(const char *name, bool def) 33 | { 34 | return def; 35 | } 36 | 37 | int platform_default_i(const char *name, int def) 38 | { 39 | return def; 40 | } 41 | -------------------------------------------------------------------------------- /windows/winhelp.rc2: -------------------------------------------------------------------------------- 1 | #include "win_res.h" 2 | 3 | #ifdef EMBED_CHM 4 | ID_CUSTOM_CHMFILE TYPE_CUSTOM_CHMFILE "../doc/putty.chm" 5 | #define HELPVER " (with embedded help)" 6 | #else 7 | #define HELPVER " (without embedded help)" 8 | #endif 9 | -------------------------------------------------------------------------------- /windows/winnohlp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * nohelp.c: implement the has_embedded_chm() function for 3 | * applications that have no help file at all, so that misc.c's 4 | * buildinfo string knows not to talk meaninglessly about whether the 5 | * nonexistent help file is present. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "putty.h" 14 | 15 | int has_embedded_chm(void) { return -1; } 16 | -------------------------------------------------------------------------------- /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 | void remove_session_from_jumplist(const char * const sessionname) {} 8 | void clear_jumplist(void) {} 9 | -------------------------------------------------------------------------------- /windows/winnpc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Windows support module which deals with being a named-pipe client. 3 | */ 4 | 5 | #include 6 | #include 7 | 8 | #include "tree234.h" 9 | #include "putty.h" 10 | #include "network.h" 11 | #include "proxy.h" 12 | #include "ssh.h" 13 | 14 | #if !defined NO_SECURITY 15 | 16 | #include "winsecur.h" 17 | 18 | HANDLE connect_to_named_pipe(const char *pipename, char **err) 19 | { 20 | HANDLE pipehandle; 21 | PSID usersid, pipeowner; 22 | PSECURITY_DESCRIPTOR psd; 23 | 24 | assert(strncmp(pipename, "\\\\.\\pipe\\", 9) == 0); 25 | assert(strchr(pipename + 9, '\\') == NULL); 26 | 27 | while (1) { 28 | pipehandle = CreateFile(pipename, GENERIC_READ | GENERIC_WRITE, 29 | 0, NULL, OPEN_EXISTING, 30 | FILE_FLAG_OVERLAPPED, NULL); 31 | 32 | if (pipehandle != INVALID_HANDLE_VALUE) 33 | break; 34 | 35 | if (GetLastError() != ERROR_PIPE_BUSY) { 36 | *err = dupprintf( 37 | "Unable to open named pipe '%s': %s", 38 | pipename, win_strerror(GetLastError())); 39 | return INVALID_HANDLE_VALUE; 40 | } 41 | 42 | /* 43 | * If we got ERROR_PIPE_BUSY, wait for the server to 44 | * create a new pipe instance. (Since the server is 45 | * expected to be winnps.c, which will do that immediately 46 | * after a previous connection is accepted, that shouldn't 47 | * take excessively long.) 48 | */ 49 | if (!WaitNamedPipe(pipename, NMPWAIT_USE_DEFAULT_WAIT)) { 50 | *err = dupprintf( 51 | "Error waiting for named pipe '%s': %s", 52 | pipename, win_strerror(GetLastError())); 53 | return INVALID_HANDLE_VALUE; 54 | } 55 | } 56 | 57 | if ((usersid = get_user_sid()) == NULL) { 58 | CloseHandle(pipehandle); 59 | *err = dupprintf( 60 | "Unable to get user SID: %s", win_strerror(GetLastError())); 61 | return INVALID_HANDLE_VALUE; 62 | } 63 | 64 | if (p_GetSecurityInfo(pipehandle, SE_KERNEL_OBJECT, 65 | OWNER_SECURITY_INFORMATION, 66 | &pipeowner, NULL, NULL, NULL, 67 | &psd) != ERROR_SUCCESS) { 68 | CloseHandle(pipehandle); 69 | *err = dupprintf( 70 | "Unable to get named pipe security information: %s", 71 | win_strerror(GetLastError())); 72 | return INVALID_HANDLE_VALUE; 73 | } 74 | 75 | if (!EqualSid(pipeowner, usersid)) { 76 | CloseHandle(pipehandle); 77 | LocalFree(psd); 78 | *err = dupprintf( 79 | "Owner of named pipe '%s' is not us", pipename); 80 | return INVALID_HANDLE_VALUE; 81 | } 82 | 83 | LocalFree(psd); 84 | 85 | return pipehandle; 86 | } 87 | 88 | Socket *new_named_pipe_client(const char *pipename, Plug *plug) 89 | { 90 | char *err = NULL; 91 | HANDLE pipehandle = connect_to_named_pipe(pipename, &err); 92 | if (pipehandle == INVALID_HANDLE_VALUE) 93 | return new_error_socket_consume_string(plug, err); 94 | else 95 | return make_handle_socket(pipehandle, pipehandle, NULL, plug, true); 96 | } 97 | 98 | #endif /* !defined NO_SECURITY */ 99 | -------------------------------------------------------------------------------- /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 | #include "tree234.h" 11 | #include "putty.h" 12 | #include "network.h" 13 | #include "proxy.h" 14 | 15 | Socket *platform_new_connection(SockAddr *addr, const char *hostname, 16 | int port, bool privport, 17 | bool oobinline, bool nodelay, bool keepalive, 18 | Plug *plug, Conf *conf) 19 | { 20 | char *cmd; 21 | HANDLE us_to_cmd, cmd_from_us; 22 | HANDLE us_from_cmd, cmd_to_us; 23 | HANDLE us_from_cmd_err, cmd_err_to_us; 24 | SECURITY_ATTRIBUTES sa; 25 | STARTUPINFO si; 26 | PROCESS_INFORMATION pi; 27 | 28 | if (conf_get_int(conf, CONF_proxy_type) != PROXY_CMD) 29 | return NULL; 30 | 31 | cmd = format_telnet_command(addr, port, conf); 32 | 33 | /* We are responsible for this and don't need it any more */ 34 | sk_addr_free(addr); 35 | 36 | { 37 | char *msg = dupprintf("Starting local proxy command: %s", cmd); 38 | plug_log(plug, PLUGLOG_PROXY_MSG, NULL, 0, msg, 0); 39 | sfree(msg); 40 | } 41 | 42 | /* 43 | * Create the pipes to the proxy command, and spawn the proxy 44 | * command process. 45 | */ 46 | sa.nLength = sizeof(sa); 47 | sa.lpSecurityDescriptor = NULL; /* default */ 48 | sa.bInheritHandle = true; 49 | if (!CreatePipe(&us_from_cmd, &cmd_to_us, &sa, 0)) { 50 | sfree(cmd); 51 | return new_error_socket_fmt( 52 | plug, "Unable to create pipes for proxy command: %s", 53 | win_strerror(GetLastError())); 54 | } 55 | 56 | if (!CreatePipe(&cmd_from_us, &us_to_cmd, &sa, 0)) { 57 | sfree(cmd); 58 | CloseHandle(us_from_cmd); 59 | CloseHandle(cmd_to_us); 60 | return new_error_socket_fmt( 61 | plug, "Unable to create pipes for proxy command: %s", 62 | win_strerror(GetLastError())); 63 | } 64 | 65 | if (!CreatePipe(&us_from_cmd_err, &cmd_err_to_us, &sa, 0)) { 66 | sfree(cmd); 67 | CloseHandle(us_from_cmd); 68 | CloseHandle(cmd_to_us); 69 | CloseHandle(us_to_cmd); 70 | CloseHandle(cmd_from_us); 71 | return new_error_socket_fmt( 72 | plug, "Unable to create pipes for proxy command: %s", 73 | win_strerror(GetLastError())); 74 | } 75 | 76 | SetHandleInformation(us_to_cmd, HANDLE_FLAG_INHERIT, 0); 77 | SetHandleInformation(us_from_cmd, HANDLE_FLAG_INHERIT, 0); 78 | if (us_from_cmd_err != NULL) 79 | SetHandleInformation(us_from_cmd_err, HANDLE_FLAG_INHERIT, 0); 80 | 81 | si.cb = sizeof(si); 82 | si.lpReserved = NULL; 83 | si.lpDesktop = NULL; 84 | si.lpTitle = NULL; 85 | si.dwFlags = STARTF_USESTDHANDLES; 86 | si.cbReserved2 = 0; 87 | si.lpReserved2 = NULL; 88 | si.hStdInput = cmd_from_us; 89 | si.hStdOutput = cmd_to_us; 90 | si.hStdError = cmd_err_to_us; 91 | CreateProcess(NULL, cmd, NULL, NULL, true, 92 | CREATE_NO_WINDOW | NORMAL_PRIORITY_CLASS, 93 | NULL, NULL, &si, &pi); 94 | CloseHandle(pi.hProcess); 95 | CloseHandle(pi.hThread); 96 | 97 | sfree(cmd); 98 | 99 | CloseHandle(cmd_from_us); 100 | CloseHandle(cmd_to_us); 101 | 102 | if (cmd_err_to_us != NULL) 103 | CloseHandle(cmd_err_to_us); 104 | 105 | return make_handle_socket(us_to_cmd, us_from_cmd, us_from_cmd_err, 106 | plug, false); 107 | } 108 | -------------------------------------------------------------------------------- /windows/winseat.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Small implementation of Seat and LogPolicy shared between window.c 3 | * and windlg.c. 4 | */ 5 | 6 | typedef struct WinGuiSeat WinGuiSeat; 7 | 8 | struct WinGuiSeat { 9 | HWND term_hwnd; 10 | Seat seat; 11 | LogPolicy logpolicy; 12 | }; 13 | 14 | extern const LogPolicyVtable win_gui_logpolicy_vt; /* in windlg.c */ 15 | -------------------------------------------------------------------------------- /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 | /* 12 | * Functions loaded from advapi32.dll. 13 | */ 14 | DECL_WINDOWS_FUNCTION(extern, BOOL, OpenProcessToken, 15 | (HANDLE, DWORD, PHANDLE)); 16 | DECL_WINDOWS_FUNCTION(extern, BOOL, GetTokenInformation, 17 | (HANDLE, TOKEN_INFORMATION_CLASS, 18 | LPVOID, DWORD, PDWORD)); 19 | DECL_WINDOWS_FUNCTION(extern, BOOL, InitializeSecurityDescriptor, 20 | (PSECURITY_DESCRIPTOR, DWORD)); 21 | DECL_WINDOWS_FUNCTION(extern, BOOL, SetSecurityDescriptorOwner, 22 | (PSECURITY_DESCRIPTOR, PSID, BOOL)); 23 | DECL_WINDOWS_FUNCTION(extern, DWORD, GetSecurityInfo, 24 | (HANDLE, SE_OBJECT_TYPE, SECURITY_INFORMATION, 25 | PSID *, PSID *, PACL *, PACL *, 26 | PSECURITY_DESCRIPTOR *)); 27 | DECL_WINDOWS_FUNCTION(extern, DWORD, SetSecurityInfo, 28 | (HANDLE, SE_OBJECT_TYPE, SECURITY_INFORMATION, 29 | PSID, PSID, PACL, PACL)); 30 | DECL_WINDOWS_FUNCTION(extern, DWORD, SetEntriesInAclA, 31 | (ULONG, PEXPLICIT_ACCESS, PACL, PACL *)); 32 | bool got_advapi(void); 33 | 34 | /* 35 | * Find the SID describing the current user. The return value (if not 36 | * NULL for some error-related reason) is smalloced. 37 | */ 38 | PSID get_user_sid(void); 39 | 40 | /* 41 | * Construct a PSECURITY_DESCRIPTOR of the type used for named pipe 42 | * servers, i.e. allowing access only to the current user id and also 43 | * only local (i.e. not over SMB) connections. 44 | * 45 | * If this function returns true, then 'psd' and 'acl' will have been 46 | * filled in with memory allocated using LocalAlloc (and hence must be 47 | * freed later using LocalFree). If it returns false, then instead 48 | * 'error' has been filled with a dynamically allocated error message. 49 | */ 50 | bool make_private_security_descriptor( 51 | DWORD permissions, PSECURITY_DESCRIPTOR *psd, PACL *acl, char **error); 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /windows/winselcli.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Implementation of do_select() for winnet.c to use, suitable for use 3 | * when there's no GUI window to have network activity reported to. 4 | * 5 | * It uses WSAEventSelect, where available, to convert network 6 | * activity into activity on an event object, for integration into an 7 | * event loop that includes WaitForMultipleObjects. 8 | * 9 | * It also maintains a list of currently active sockets, which can be 10 | * retrieved by a front end that wants to use WinSock's synchronous 11 | * select() function. 12 | */ 13 | 14 | #include "putty.h" 15 | 16 | static tree234 *winselcli_sockets; 17 | 18 | static int socket_cmp(void *av, void *bv) 19 | { 20 | return memcmp(av, bv, sizeof(SOCKET)); 21 | } 22 | 23 | HANDLE winselcli_event = INVALID_HANDLE_VALUE; 24 | 25 | void winselcli_setup(void) 26 | { 27 | if (!winselcli_sockets) 28 | winselcli_sockets = newtree234(socket_cmp); 29 | 30 | if (p_WSAEventSelect && winselcli_event == INVALID_HANDLE_VALUE) 31 | winselcli_event = CreateEvent(NULL, false, false, NULL); 32 | } 33 | 34 | SOCKET winselcli_unique_socket(void) 35 | { 36 | if (!winselcli_sockets) 37 | return INVALID_SOCKET; 38 | 39 | assert(count234(winselcli_sockets) <= 1); 40 | 41 | SOCKET *p = index234(winselcli_sockets, 0); 42 | if (!p) 43 | return INVALID_SOCKET; 44 | 45 | return *p; 46 | } 47 | 48 | const char *do_select(SOCKET skt, bool enable) 49 | { 50 | /* Check everything's been set up, for convenience of callers. */ 51 | winselcli_setup(); 52 | 53 | if (enable) { 54 | SOCKET *ptr = snew(SOCKET); 55 | *ptr = skt; 56 | if (add234(winselcli_sockets, ptr) != ptr) 57 | sfree(ptr); /* already there */ 58 | } else { 59 | SOCKET *ptr = del234(winselcli_sockets, &skt); 60 | if (ptr) 61 | sfree(ptr); 62 | } 63 | 64 | if (p_WSAEventSelect) { 65 | int events; 66 | if (enable) { 67 | events = (FD_CONNECT | FD_READ | FD_WRITE | 68 | FD_OOB | FD_CLOSE | FD_ACCEPT); 69 | } else { 70 | events = 0; 71 | } 72 | 73 | if (p_WSAEventSelect(skt, winselcli_event, events) == SOCKET_ERROR) 74 | return winsock_error_string(p_WSAGetLastError()); 75 | } 76 | 77 | return NULL; 78 | } 79 | -------------------------------------------------------------------------------- /windows/winselgui.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Implementation of do_select() for winnet.c to use, that uses 3 | * WSAAsyncSelect to convert network activity into window messages, 4 | * for integration into a GUI event loop. 5 | */ 6 | 7 | #include "putty.h" 8 | 9 | static HWND winsel_hwnd = NULL; 10 | 11 | void winselgui_set_hwnd(HWND hwnd) 12 | { 13 | winsel_hwnd = hwnd; 14 | } 15 | 16 | void winselgui_clear_hwnd(void) 17 | { 18 | winsel_hwnd = NULL; 19 | } 20 | 21 | const char *do_select(SOCKET skt, bool enable) 22 | { 23 | int msg, events; 24 | if (enable) { 25 | msg = WM_NETEVENT; 26 | events = (FD_CONNECT | FD_READ | FD_WRITE | 27 | FD_OOB | FD_CLOSE | FD_ACCEPT); 28 | } else { 29 | msg = events = 0; 30 | } 31 | 32 | assert(winsel_hwnd); 33 | 34 | if (p_WSAAsyncSelect(skt, winsel_hwnd, msg, events) == SOCKET_ERROR) 35 | return winsock_error_string(p_WSAGetLastError()); 36 | 37 | return NULL; 38 | } 39 | -------------------------------------------------------------------------------- /windows/winsocks.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Main program for Windows psocks. 3 | */ 4 | 5 | #include "putty.h" 6 | #include "ssh.h" 7 | #include "psocks.h" 8 | 9 | static const PsocksPlatform platform = { 10 | NULL /* open_pipes */, 11 | NULL /* start_subcommand */, 12 | }; 13 | 14 | int main(int argc, char **argv) 15 | { 16 | psocks_state *ps = psocks_new(&platform); 17 | psocks_cmdline(ps, argc, argv); 18 | 19 | sk_init(); 20 | winselcli_setup(); 21 | psocks_start(ps); 22 | 23 | cli_main_loop(cliloop_null_pre, cliloop_null_post, NULL); 24 | } 25 | -------------------------------------------------------------------------------- /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 bool platform_uses_x11_unix_by_default = false; 20 | --------------------------------------------------------------------------------