├── .editorconfig ├── .gitignore ├── Buildscr ├── Buildscr.cv ├── CHECKLST.txt ├── CMakeLists.txt ├── LATEST.VER ├── LICENCE ├── README ├── README.md ├── aqsync.c ├── b64 ├── cdecode.c ├── cdecode.h ├── cencode.c └── cencode.h ├── be_list.c ├── build └── putty.exe ├── callback.c ├── cgtest.c ├── charset ├── CMakeLists.txt ├── 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 ├── cmake ├── cmake.h.in ├── gitcommit.cmake ├── gtk.cmake ├── licence.cmake ├── platforms │ ├── unix.cmake │ └── windows.cmake ├── setup.cmake ├── toolchain-mingw.cmake ├── toolchain-winegcc.cmake └── winegcc ├── cmdgen.c ├── cmdline.c ├── config.c ├── console.c ├── console.h ├── contrib ├── authplugin-example.py ├── 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 ├── proveprime.py └── samplekex.py ├── crypto ├── CMakeLists.txt ├── aes-common.c ├── aes-neon.c ├── aes-ni.c ├── aes-select.c ├── aes-sw.c ├── aes.h ├── aesgcm-clmul.c ├── aesgcm-common.c ├── aesgcm-footer.h ├── aesgcm-neon.c ├── aesgcm-ref-poly.c ├── aesgcm-select.c ├── aesgcm-sw.c ├── aesgcm.h ├── arcfour.c ├── argon2.c ├── bcrypt.c ├── blake2.c ├── blowfish.c ├── blowfish.h ├── chacha20-poly1305.c ├── crc32.c ├── des.c ├── diffie-hellman.c ├── dsa.c ├── ecc-arithmetic.c ├── ecc-ssh.c ├── ecc.h ├── hash_simple.c ├── hmac.c ├── mac.c ├── mac_simple.c ├── md5.c ├── mpint.c ├── mpint_i.h ├── ntru.c ├── ntru.h ├── openssh-certs.c ├── prng.c ├── pubkey-pem.c ├── pubkey-ppk.c ├── pubkey-ssh1.c ├── rsa.c ├── sha1-common.c ├── sha1-neon.c ├── sha1-ni.c ├── sha1-select.c ├── sha1-sw.c ├── sha1.h ├── sha256-common.c ├── sha256-neon.c ├── sha256-ni.c ├── sha256-select.c ├── sha256-sw.c ├── sha256.h ├── sha3.c ├── sha512-common.c ├── sha512-neon.c ├── sha512-select.c ├── sha512-sw.c ├── sha512.h └── xdmauth.c ├── defs.h ├── dialog.c ├── dialog.h ├── doc ├── CMakeLists.txt ├── authplugin.but ├── blurb.but ├── chm.css ├── chmextra.but ├── config.but ├── errors.but ├── faq.but ├── feedback.but ├── gs.but ├── index.but ├── intro.but ├── man-pageant.but ├── man-plink.but ├── man-pscp.but ├── man-psftp.but ├── man-psocks.but ├── man-psusan.but ├── man-pterm.but ├── man-putty.but ├── man-puttygen.but ├── man-puttytel.but ├── mancfg.but ├── manpages.but ├── pageant.but ├── pgpkeys.but ├── plink.but ├── pscp.but ├── psftp.but ├── pubkey.but ├── pubkeyfmt.but ├── site.but ├── sshnames.but ├── udp.but ├── using.but └── vids.but ├── errsock.c ├── icons ├── Makefile ├── cicon.pl ├── icon.pl ├── macicon.py ├── mkicon.py └── mksvg.py ├── import.c ├── keygen ├── CMakeLists.txt ├── dsa.c ├── ecdsa.c ├── millerrabin.c ├── mpunsafe.c ├── mpunsafe.h ├── pockle.c ├── prime.c ├── primecandidate.c ├── rsa.c └── smallprimes.c ├── ldisc.c ├── licence.pl ├── logging.c ├── make_with_mingw.sh ├── marshal.h ├── misc.h ├── mksrcarc.sh ├── mkunxarc.sh ├── mpint.h ├── network.h ├── otherbackends ├── CMakeLists.txt ├── raw.c ├── rlogin.c ├── supdup.c ├── telnet.c └── testback.c ├── pageant.c ├── pageant.h ├── pinger.c ├── proxy ├── cproxy.c ├── cproxy.h ├── http.c ├── interactor.c ├── local.c ├── nocproxy.c ├── noproxy.c ├── nosshproxy.c ├── pproxy.c ├── proxy.c ├── proxy.h ├── socks.h ├── socks4.c ├── socks5.c ├── sshproxy.c └── telnet.c ├── pscp.c ├── psftp.c ├── psftp.h ├── psftpcommon.c ├── psocks.c ├── psocks.h ├── putty.h ├── puttymem.h ├── release.pl ├── settings.c ├── sign.sh ├── specials.h ├── ssh.h ├── ssh ├── CMakeLists.txt ├── agentf.c ├── bpp-bare.c ├── bpp.h ├── bpp1.c ├── bpp2.c ├── ca-config.c ├── censor1.c ├── censor2.c ├── channel.h ├── common.c ├── connection1-client.c ├── connection1-server.c ├── connection1.c ├── connection1.h ├── connection2-client.c ├── connection2-server.c ├── connection2.c ├── connection2.h ├── crc-attack-detector.c ├── gss.h ├── gssc.c ├── gssc.h ├── kex2-client.c ├── kex2-server.c ├── login1-server.c ├── login1.c ├── mainchan.c ├── nogss.c ├── nosharing.c ├── pgssapi.c ├── pgssapi.h ├── portfwd.c ├── ppl.h ├── scpserver.c ├── server.c ├── server.h ├── sesschan.c ├── sftp.c ├── sftp.h ├── sftpcommon.c ├── sftpserver.c ├── sharing.c ├── signal-list.h ├── ssh.c ├── transient-hostkey-cache.c ├── transport2.c ├── transport2.h ├── ttymode-list.h ├── userauth2-client.c ├── userauth2-server.c ├── verstring.c ├── x11fwd.c └── zlib.c ├── sshcr.h ├── sshkeygen.h ├── sshpubk.c ├── sshrand.c ├── storage.h ├── stubs ├── CMakeLists.txt ├── no-agent.c ├── no-ca-config.c ├── no-callback.c ├── no-cmdline.c ├── no-console.c ├── no-gss.c ├── no-ldisc.c ├── no-lineedit.c ├── no-logging.c ├── no-network.c ├── no-print.c ├── no-printing.c ├── no-rand.c ├── no-storage.c ├── no-term.c ├── no-timing.c ├── null-cipher.c ├── null-key.c ├── null-lp.c ├── null-mac.c ├── null-opener.c ├── null-plug.c └── null-seat.c ├── terminal ├── bidi.c ├── bidi.h ├── bidi_gettype.c ├── bidi_test.c ├── lineedit.c ├── terminal.c └── terminal.h ├── test ├── agentmulti.py ├── agenttest.py ├── agenttestdata.py ├── agenttestgen.py ├── ca.py ├── colours.txt ├── cryptsuite.py ├── desref.py ├── display.txt ├── eccref.py ├── fuzzterm.c ├── lattrs.txt ├── list-accel.py ├── mpu-check.pl ├── numbertheory.py ├── primegen.py ├── sclog │ ├── .gitignore │ ├── CMakeLists.txt │ └── sclog.c ├── scocols.txt ├── ssh.py ├── test_lineedit.c ├── test_terminal.c ├── testcrypt-enum.h ├── testcrypt-func.h ├── testcrypt.c ├── testcrypt.py ├── testsc.c ├── testzlib.c ├── utf8.txt ├── vt100.txt └── windowchange.py ├── timing.c ├── tree234.h ├── unicode ├── ambiguous_wide_chars.h ├── bidi_brackets.h ├── bidi_mirror.h ├── bidi_type.h ├── canonical_comp.h ├── canonical_decomp.h ├── combining_classes.h ├── known_chars.h ├── nonspacing_chars.h ├── read_ucd.py ├── version.h └── wide_chars.h ├── unix ├── CMakeLists.txt ├── agent-client.c ├── agent-socket.c ├── askpass.c ├── cliloop.c ├── columns.c ├── columns.h ├── config-gtk.c ├── config-unix.c ├── console.c ├── dialog.c ├── fd-socket.c ├── gss.c ├── gtk-common.c ├── gtkcompat.h ├── gtkmisc.h ├── keygen-noise.c ├── local-proxy.c ├── main-gtk-application.c ├── main-gtk-simple.c ├── network.c ├── no-gtk.c ├── noaskpass.c ├── noise.c ├── osxlaunch.c ├── pageant.c ├── peerinfo.c ├── platform.h ├── plink.c ├── printing.c ├── procnet.c ├── psocks.c ├── psusan.c ├── pterm-config-xpm.c ├── pterm-xpm.c ├── pterm.bundle ├── pterm.c ├── pterm.plist ├── pty.c ├── putty-config-xpm.c ├── putty-xpm.c ├── putty.bundle ├── putty.c ├── putty.plist ├── serial.c ├── sftp.c ├── sftpserver.c ├── sharing.c ├── storage.c ├── stubs │ └── no-uxsel.c ├── unicode.c ├── unifont.c ├── unifont.h ├── uppity.c ├── utils │ ├── align_label_left.c │ ├── arm_arch_queries.c │ ├── arm_arch_queries.h │ ├── block_signal.c │ ├── buildinfo_gtk_version.c │ ├── cloexec.c │ ├── dputs.c │ ├── filename.c │ ├── fontspec.c │ ├── get_label_text_dimensions.c │ ├── get_username.c │ ├── get_x11_display.c │ ├── getticks.c │ ├── keysym_to_unicode.c │ ├── make_dir_and_check_ours.c │ ├── make_dir_path.c │ ├── make_spr_sw_abort_errno.c │ ├── nonblock.c │ ├── open_for_write_would_lose_data.c │ ├── our_dialog.c │ ├── pgp_fingerprints.c │ ├── pollwrap.c │ ├── signal.c │ ├── string_width.c │ └── x11_ignore_error.c ├── uxsel.c ├── window.c ├── x11.c └── x11misc.h ├── utils ├── CMakeLists.txt ├── antispoof.c ├── backend_socket_log.c ├── base64_decode.c ├── base64_decode_atom.c ├── base64_encode.c ├── base64_encode_atom.c ├── base64_valid.c ├── bufchain.c ├── buildinfo.c ├── burnstr.c ├── burnwcs.c ├── cert-expr.c ├── chomp.c ├── cmdline_get_passwd_input_state_new.c ├── conf.c ├── conf_dest.c ├── conf_launchable.c ├── ctrlparse.c ├── ctrlset_normalise.c ├── debug.c ├── decode_utf8.c ├── decode_utf8_to_wchar.c ├── decode_utf8_to_wide_string.c ├── default_description.c ├── dup_mb_to_wc.c ├── dup_wc_to_mb.c ├── dupcat.c ├── dupprintf.c ├── dupstr.c ├── dupwcs.c ├── encode_utf8.c ├── encode_wide_string_as_utf8.c ├── fgetline.c ├── host_ca_new_free.c ├── host_strchr.c ├── host_strchr_internal.c ├── host_strcspn.c ├── host_strduptrim.c ├── host_strrchr.c ├── key_components.c ├── log_proxy_stderr.c ├── logeventf.c ├── ltime.c ├── make_spr_sw_abort_static.c ├── marshal.c ├── memory.c ├── memxor.c ├── nullstrcmp.c ├── out_of_memory.c ├── parse_blocksize.c ├── percent_decode.c ├── percent_encode.c ├── prompts.c ├── ptrlen.c ├── read_file_into.c ├── seat_connection_fatal.c ├── seat_dialog_text.c ├── seat_nonfatal.c ├── sessprep.c ├── sk_free_peer_info.c ├── smemclr.c ├── smemeq.c ├── spr_get_error_message.c ├── ssh2_pick_fingerprint.c ├── ssh_key_clone.c ├── sshutils.c ├── strbuf.c ├── string_length_for_printf.c ├── stripctrl.c ├── tempseat.c ├── tree234.c ├── unicode-known.c ├── unicode-norm.c ├── utils.h ├── validate_manual_hostkey.c ├── version.c ├── wcwidth.c ├── wildcard.c ├── wordwrap.c ├── write_c_string_literal.c ├── x11_dehexify.c ├── x11_identify_auth_proto.c ├── x11_make_greeting.c ├── x11_parse_ip.c ├── x11authfile.c └── x11authnames.c ├── version.h ├── windows ├── CMakeLists.txt ├── README-msi.txt ├── agent-client.c ├── cliloop.c ├── config.c ├── conpty.c ├── console.c ├── controls.c ├── cryptoapi.h ├── dialog.c ├── gss.c ├── handle-io.c ├── handle-socket.c ├── handle-wait.c ├── help.c ├── help.h ├── help.rc2 ├── installer.wxs ├── jump-list.c ├── local-proxy.c ├── make_install_images.sh ├── msifixup.py ├── named-pipe-client.c ├── named-pipe-server.c ├── network.c ├── no-jump-list.c ├── nohelp.c ├── noise.c ├── pageant-rc.h ├── pageant.c ├── pageant.ico ├── pageant.mft ├── pageant.rc ├── pageants.ico ├── platform.h ├── plink.c ├── plink.rc ├── printing.c ├── pscp.ico ├── pscp.rc ├── psftp.rc ├── psocks.c ├── pterm.c ├── pterm.ico ├── pterm.rc ├── ptermcfg.ico ├── putty-common.rc2 ├── putty-rc.h ├── putty.c ├── putty.ico ├── putty.mft ├── putty.rc ├── puttycfg.ico ├── puttygen-rc.h ├── puttygen.c ├── puttygen.ico ├── puttygen.mft ├── puttygen.rc ├── puttyins.ico ├── puttytel.mft ├── puttytel.rc ├── rcstuff.h ├── security-api.h ├── select-cli.c ├── select-gui.c ├── serial.c ├── sftp.c ├── sharing.c ├── sizetip.c ├── storage.c ├── test │ ├── test_screenshot.c │ └── test_split_into_argv.c ├── unicode.c ├── utils │ ├── agent_mutex_name.c │ ├── agent_named_pipe_name.c │ ├── arm_arch_queries.c │ ├── aux_match_opt.c │ ├── centre_window.c │ ├── cryptoapi.c │ ├── defaults.c │ ├── dll_hijacking_protection.c │ ├── dputs.c │ ├── escape_registry_key.c │ ├── filename.c │ ├── fontspec.c │ ├── get_system_dir.c │ ├── get_username.c │ ├── getdlgitemtext_alloc.c │ ├── gui-timing.c │ ├── interprocess_mutex.c │ ├── is_console_handle.c │ ├── load_system32_dll.c │ ├── ltime.c │ ├── make_spr_sw_abort_winerror.c │ ├── makedlgitemborderless.c │ ├── message_box.c │ ├── minefield.c │ ├── open_for_write_would_lose_data.c │ ├── pgp_fingerprints_msgbox.c │ ├── platform_get_x_display.c │ ├── registry.c │ ├── request_file.c │ ├── screenshot.c │ ├── security.c │ ├── shinydialogbox.c │ ├── split_into_argv.c │ ├── split_into_argv_w.c │ ├── strtoumax.c │ ├── version.c │ └── win_strerror.c ├── version.rc2 ├── website.url ├── win-gui-seat.h ├── window.c └── x11.c └── x11disp.c /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 4 6 | 7 | [Makefile*] 8 | indent_style = tab 9 | 10 | [cencode*] 11 | indent_style = tab 12 | 13 | [cdecode*] 14 | indent_style = tab 15 | 16 | [install-sh] 17 | indent_size = 2 18 | 19 | [depcomp] 20 | indent_size = 2 21 | 22 | [configure] 23 | indent_size = 2 24 | 25 | [ar-lib] 26 | indent_size = 2 27 | -------------------------------------------------------------------------------- /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 | # Scan the Unix build, on a 64-bit system to differentiate as much as 10 | # possible from the other scan of the cross-platform files. 11 | delegate covscan64 12 | in putty do mkdir linbuild 13 | in putty/linbuild do cmake .. 14 | in putty/linbuild do cov-build --dir ../cov-int make -j$(nproc) VERBOSE=1 15 | in putty do tar czvf cov-int.tar.gz cov-int 16 | return putty/cov-int.tar.gz 17 | enddelegate 18 | 19 | # Scan the Windows build, by means of building with Winelib (since as 20 | # of 2013-07-22, the Coverity Scan website doesn't offer a 32-bit 21 | # Windows scanner for download). 22 | delegate covscan32wine 23 | in putty do tar xzvf cov-int.tar.gz 24 | in putty do mkdir winbuild 25 | in putty/winbuild do cmake .. -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchain-winegcc.cmake 26 | in putty/winbuild do cov-build --dir ../cov-int make -j$(nproc) VERBOSE=1 27 | in putty do tar czvf cov-int.tar.gz cov-int 28 | return putty/cov-int.tar.gz 29 | enddelegate 30 | 31 | # Provide the revision number as one of the build outputs, to make it 32 | # easy to construct a curl upload command which will annotate it 33 | # appropriately when uploaded. 34 | in putty do echo $(vcsfullid) > revision.txt 35 | 36 | deliver putty/revision.txt $@ 37 | deliver putty/cov-int.tar.gz $@ 38 | -------------------------------------------------------------------------------- /LATEST.VER: -------------------------------------------------------------------------------- 1 | 0.78 2 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | PuTTY is copyright 1997-2023 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 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | This is the README for PuTTY, a free Windows and Unix Telnet and SSH 2 | client. 3 | 4 | PuTTY is built using CMake . To compile in the 5 | simplest way (on any of Linux, Windows or Mac), run these commands in 6 | the source directory: 7 | 8 | cmake . 9 | cmake --build . 10 | 11 | Then, to install in the simplest way on Linux or Mac: 12 | 13 | cmake --build . --target install 14 | 15 | On Unix, pterm would like to be setuid or setgid, as appropriate, to 16 | permit it to write records of user logins to /var/run/utmp and 17 | /var/log/wtmp. (Of course it will not use this privilege for 18 | anything else, and in particular it will drop all privileges before 19 | starting up complex subsystems like GTK.) The cmake install step 20 | doesn't attempt to add these privileges, so if you want user login 21 | recording to work, you should manually ch{own,grp} and chmod the 22 | pterm binary yourself after installation. If you don't do this, 23 | pterm will still work, but not update the user login databases. 24 | 25 | Documentation (in various formats including Windows Help and Unix 26 | `man' pages) is built from the Halibut (`.but') files in the `doc' 27 | subdirectory. If you aren't using one of our source snapshots, 28 | you'll need to do this yourself. Halibut can be found at 29 | . 30 | 31 | The PuTTY home web site is 32 | 33 | https://www.chiark.greenend.org.uk/~sgtatham/putty/ 34 | 35 | If you want to send bug reports or feature requests, please read the 36 | Feedback section of the web site before doing so. Sending one-line 37 | reports saying `it doesn't work' will waste your time as much as 38 | ours. 39 | 40 | See the file LICENCE for the licence conditions. 41 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /b64/cdecode.h: -------------------------------------------------------------------------------- 1 | /* 2 | cdecode.h - c header for a base64 decoding algorithm 3 | 4 | This is part of the libb64 project, and has been placed in the public domain. 5 | For details, see http://sourceforge.net/projects/libb64 6 | */ 7 | 8 | #ifndef BASE64_CDECODE_H 9 | #define BASE64_CDECODE_H 10 | 11 | typedef enum 12 | { 13 | step_a, step_b, step_c, step_d 14 | } base64_decodestep; 15 | 16 | typedef struct 17 | { 18 | base64_decodestep step; 19 | char plainchar; 20 | } base64_decodestate; 21 | 22 | void base64_init_decodestate(base64_decodestate* state_in); 23 | 24 | int base64_decode_value(char value_in); 25 | 26 | int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in); 27 | 28 | #endif /* BASE64_CDECODE_H */ 29 | 30 | -------------------------------------------------------------------------------- /b64/cencode.h: -------------------------------------------------------------------------------- 1 | /* 2 | cencode.h - c header for a base64 encoding algorithm 3 | 4 | This is part of the libb64 project, and has been placed in the public domain. 5 | For details, see http://sourceforge.net/projects/libb64 6 | */ 7 | 8 | #ifndef BASE64_CENCODE_H 9 | #define BASE64_CENCODE_H 10 | 11 | typedef enum 12 | { 13 | step_A, step_B, step_C 14 | } base64_encodestep; 15 | 16 | typedef struct 17 | { 18 | base64_encodestep step; 19 | char result; 20 | int stepcount; 21 | } base64_encodestate; 22 | 23 | void base64_init_encodestate(base64_encodestate* state_in); 24 | 25 | char base64_encode_value(char value_in); 26 | 27 | int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in); 28 | 29 | int base64_encode_blockend(char* code_out, base64_encodestate* state_in); 30 | 31 | #endif /* BASE64_CENCODE_H */ 32 | 33 | -------------------------------------------------------------------------------- /build/putty.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unxed/putty4far2l/1816bdba0554f9f4465b92bc0df95fb845ff4170/build/putty.exe -------------------------------------------------------------------------------- /charset/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include(FindPerl) 2 | if(NOT PERL_EXECUTABLE) 3 | message(FATAL_ERROR "Perl is required to autogenerate sbcsdat.c") 4 | endif() 5 | 6 | set(GENERATED_SBCSDAT_C ${GENERATED_SOURCES_DIR}/sbcsdat.c) 7 | add_custom_command(OUTPUT ${GENERATED_SBCSDAT_C}.tmp 8 | COMMAND ${PERL_EXECUTABLE} ${CMAKE_SOURCE_DIR}/charset/sbcsgen.pl 9 | -o ${GENERATED_SBCSDAT_C}.tmp 10 | DEPENDS ${CMAKE_SOURCE_DIR}/charset/sbcsgen.pl 11 | ${CMAKE_SOURCE_DIR}/charset/sbcs.dat) 12 | add_custom_target(generated_sbcsdat_c 13 | BYPRODUCTS ${GENERATED_SBCSDAT_C} 14 | COMMAND ${CMAKE_COMMAND} -E copy_if_different 15 | ${GENERATED_SBCSDAT_C}.tmp ${GENERATED_SBCSDAT_C} 16 | DEPENDS ${GENERATED_SBCSDAT_C}.tmp 17 | COMMENT "Updating sbcsdat.c") 18 | 19 | add_library(charset STATIC 20 | fromucs.c 21 | localenc.c 22 | macenc.c 23 | mimeenc.c 24 | sbcs.c 25 | ${GENERATED_SBCSDAT_C} 26 | slookup.c 27 | toucs.c 28 | utf8.c 29 | xenc.c) 30 | add_dependencies(charset generated_sbcsdat_c) 31 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /cmake/licence.cmake: -------------------------------------------------------------------------------- 1 | # Pure cmake script to generate licence.h from LICENCE 2 | 3 | file(READ "${LICENCE_FILE}" LICENCE_TEXT) 4 | 5 | function(c_string_escape outvar value) 6 | string(REPLACE "\\" "\\\\" value "${value}") 7 | string(REPLACE "\"" "\\\"" value "${value}") 8 | set("${outvar}" "${value}" PARENT_SCOPE) 9 | endfunction() 10 | 11 | set(copyright_regex "PuTTY is copyright ([0-9]+-[0-9]+ [^\n]*[^\n.])\\.?\n") 12 | string(REGEX MATCH "${copyright_regex}" COPYRIGHT_NOTICE "${LICENCE_TEXT}") 13 | string(REGEX REPLACE "${copyright_regex}" "\\1" 14 | COPYRIGHT_NOTICE "${COPYRIGHT_NOTICE}") 15 | c_string_escape(COPYRIGHT_NOTICE "${COPYRIGHT_NOTICE}") 16 | 17 | string(REGEX REPLACE "\n$" "" LICENCE_TEXT "${LICENCE_TEXT}") 18 | string(REPLACE "\r" "" LICENCE_TEXT "${LICENCE_TEXT}") 19 | string(REPLACE "\n\n" "\r" LICENCE_TEXT "${LICENCE_TEXT}") 20 | string(REPLACE "\n" " " LICENCE_TEXT "${LICENCE_TEXT}") 21 | string(REPLACE "\r" "\n" LICENCE_TEXT "${LICENCE_TEXT}") 22 | 23 | c_string_escape(LICENCE_TEXT "${LICENCE_TEXT}") 24 | string(REPLACE "\n" "\" \\\n parsep \\\n \"" 25 | LICENCE_TEXT "${LICENCE_TEXT}") 26 | 27 | file(WRITE "${OUTPUT_FILE}" "\ 28 | /* 29 | * licence.h - macro definitions for the PuTTY licence. 30 | * 31 | * Generated by cmake/licence.cmake from ./LICENCE. 32 | * You should edit those files rather than editing this one. 33 | */ 34 | 35 | #define LICENCE_TEXT(parsep) \\ 36 | \"${LICENCE_TEXT}\" 37 | 38 | #define SHORT_COPYRIGHT_DETAILS \"${COPYRIGHT_NOTICE}\" 39 | ") 40 | -------------------------------------------------------------------------------- /cmake/toolchain-mingw.cmake: -------------------------------------------------------------------------------- 1 | # Simple toolchain file for cross-building Windows PuTTY on Linux 2 | # using MinGW (tested on Ubuntu). 3 | 4 | set(CMAKE_SYSTEM_NAME Windows) 5 | set(CMAKE_SYSTEM_PROCESSOR x86_64) 6 | 7 | set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc) 8 | set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres) 9 | set(CMAKE_AR x86_64-w64-mingw32-ar) 10 | set(CMAKE_RANLIB x86_64-w64-mingw32-ranlib) 11 | 12 | add_compile_definitions(__USE_MINGW_ANSI_STDIO) 13 | -------------------------------------------------------------------------------- /cmake/toolchain-winegcc.cmake: -------------------------------------------------------------------------------- 1 | # Toolchain file for cross-building a Winelib version of Windows PuTTY 2 | # on Linux, using winegcc (tested on Ubuntu). 3 | 4 | # Winelib is weird because it's basically compiling ordinary Linux 5 | # objects and executables, but we want to pretend to be Windows for 6 | # purposes of (a) having resource files, and (b) selecting the Windows 7 | # platform subdirectory. 8 | # 9 | # So, do we tag this as a weird kind of Windows build, or a weird kind 10 | # of Linux build? Either way we have to do _something_ out of the 11 | # ordinary. 12 | # 13 | # After some experimentation, it seems to make more sense to treat 14 | # Winelib builds as basically Linux, and set a flag WINELIB that 15 | # PuTTY's main build scripts will detect and handle specially. 16 | # Specifically, that flag will cause cmake/setup.cmake to select the 17 | # Windows platform (overriding the usual check of CMAKE_SYSTEM_NAME), 18 | # and also trigger a call to enable_language(RC), which for some kind 19 | # of cmake re-entrancy reason we can't do in this toolchain file 20 | # itself. 21 | set(CMAKE_SYSTEM_NAME Linux) 22 | set(WINELIB ON) 23 | 24 | # We need a wrapper script around winegcc proper, because cmake's link 25 | # command lines will refer to system libraries as "-lkernel32.lib" 26 | # rather than the required "-lkernel32". The winegcc script alongside 27 | # this toolchain file bodges that command-line translation. 28 | set(CMAKE_C_COMPILER ${CMAKE_SOURCE_DIR}/cmake/winegcc) 29 | 30 | set(CMAKE_RC_COMPILER wrc) 31 | set(CMAKE_RC_OUTPUT_EXTENSION .res.o) 32 | set(CMAKE_RC_COMPILE_OBJECT 33 | " -o ") 34 | -------------------------------------------------------------------------------- /cmake/winegcc: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Wrapper for winegcc that allows it to be used in a build generated 4 | # from PuTTY's CMakeLists.txt, by bodging around the command-line 5 | # options that CMake gets wrong. 6 | 7 | init=true 8 | for arg in init "$@"; do 9 | if $init; then 10 | set -- 11 | init=false 12 | continue 13 | fi 14 | 15 | case "$arg" in 16 | # The Windows build definition for PuTTY specifies all the 17 | # system API libraries by names like kernel32.lib. When CMake 18 | # reads that file and thinks it's compiling for Linux, it will 19 | # generate link options such as -lkernel32.lib. But in fact 20 | # winegcc expects -lkernel32, so we need to strip the ".lib" 21 | # suffix. 22 | -l*.lib) set -- "$@" "${arg%.lib}";; 23 | 24 | # Anything else, we leave unchanged. 25 | *) set -- "$@" "$arg";; 26 | esac 27 | done 28 | 29 | exec winegcc "$@" 30 | -------------------------------------------------------------------------------- /console.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Common pieces between the platform console frontend modules. 3 | */ 4 | 5 | char *hk_absentmsg_common(const char *host, int port, 6 | const char *keytype, const char *fingerprint); 7 | extern const char hk_absentmsg_interactive_intro[]; 8 | extern const char hk_absentmsg_interactive_prompt[]; 9 | 10 | char *hk_wrongmsg_common(const char *host, int port, 11 | const char *keytype, const char *fingerprint); 12 | extern const char hk_wrongmsg_interactive_intro[]; 13 | extern const char hk_wrongmsg_interactive_prompt[]; 14 | 15 | extern const char weakcrypto_msg_common_fmt[]; 16 | 17 | extern const char weakhk_msg_common_fmt[]; 18 | 19 | extern const char console_continue_prompt[]; 20 | extern const char console_abandoned_msg[]; 21 | -------------------------------------------------------------------------------- /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/nice-ibeam.cur: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unxed/putty4far2l/1816bdba0554f9f4465b92bc0df95fb845ff4170/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 | -------------------------------------------------------------------------------- /crypto/aes-common.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Common variable definitions across all the AES implementations. 3 | */ 4 | 5 | #include "ssh.h" 6 | #include "aes.h" 7 | 8 | const uint8_t aes_key_setup_round_constants[10] = { 9 | /* The first few powers of X in GF(2^8), used during key setup. 10 | * This can safely be a lookup table without side channel risks, 11 | * because key setup iterates through it once in a standard way 12 | * regardless of the key. */ 13 | 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 14 | }; 15 | 16 | void aesgcm_cipher_crypt_length( 17 | ssh_cipher *cipher, void *blk, int len, unsigned long seq) 18 | { 19 | /* Do nothing: lengths are sent in clear for this cipher. */ 20 | } 21 | -------------------------------------------------------------------------------- /crypto/aesgcm-common.c: -------------------------------------------------------------------------------- 1 | #include "ssh.h" 2 | #include "aesgcm.h" 3 | 4 | void aesgcm_set_prefix_lengths(ssh2_mac *mac, size_t skip, size_t aad) 5 | { 6 | const struct aesgcm_extra *extra = mac->vt->extra; 7 | extra->set_prefix_lengths(mac, skip, aad); 8 | } 9 | -------------------------------------------------------------------------------- /crypto/aesgcm-select.c: -------------------------------------------------------------------------------- 1 | #include "ssh.h" 2 | #include "aesgcm.h" 3 | 4 | static ssh2_mac *aesgcm_mac_selector_new(const ssh2_macalg *alg, 5 | ssh_cipher *cipher) 6 | { 7 | static const ssh2_macalg *const real_algs[] = { 8 | #if HAVE_CLMUL 9 | &ssh2_aesgcm_mac_clmul, 10 | #endif 11 | #if HAVE_NEON_PMULL 12 | &ssh2_aesgcm_mac_neon, 13 | #endif 14 | &ssh2_aesgcm_mac_sw, 15 | NULL, 16 | }; 17 | 18 | for (size_t i = 0; real_algs[i]; i++) { 19 | const ssh2_macalg *alg = real_algs[i]; 20 | const struct aesgcm_extra *alg_extra = 21 | (const struct aesgcm_extra *)alg->extra; 22 | if (check_aesgcm_availability(alg_extra)) 23 | return ssh2_mac_new(alg, cipher); 24 | } 25 | 26 | /* We should never reach the NULL at the end of the list, because 27 | * the last non-NULL entry should be software-only GCM, which is 28 | * always available. */ 29 | unreachable("aesgcm_select ran off the end of its list"); 30 | } 31 | 32 | const ssh2_macalg ssh2_aesgcm_mac = { 33 | .new = aesgcm_mac_selector_new, 34 | .name = "", 35 | .etm_name = "", /* Not selectable independently */ 36 | .len = 16, 37 | .keylen = 0, 38 | }; 39 | -------------------------------------------------------------------------------- /crypto/aesgcm.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Common parts of the state structure for AESGCM MAC implementations. 3 | */ 4 | #define AESGCM_COMMON_FIELDS \ 5 | ssh_cipher *cipher; \ 6 | unsigned char partblk[16]; \ 7 | size_t skiplen, aadlen, ciphertextlen; \ 8 | size_t skipgot, aadgot, partlen; \ 9 | BinarySink_IMPLEMENTATION; \ 10 | ssh2_mac mac 11 | 12 | /* 13 | * The 'extra' structure is used to include information about how to 14 | * check if a given implementation is available at run time, and 15 | * whether we've already checked. 16 | */ 17 | struct aesgcm_extra_mutable; 18 | struct aesgcm_extra { 19 | /* Function to check availability. Might be expensive, so we don't 20 | * want to call it more than once. */ 21 | bool (*check_available)(void); 22 | 23 | /* Point to a writable substructure. */ 24 | struct aesgcm_extra_mutable *mut; 25 | 26 | /* 27 | * Extra API function specific to this MAC type that allows 28 | * testcrypt to set more general lengths for skiplen and aadlen. 29 | */ 30 | void (*set_prefix_lengths)(ssh2_mac *mac, size_t skip, size_t aad); 31 | }; 32 | struct aesgcm_extra_mutable { 33 | bool checked_availability; 34 | bool is_available; 35 | }; 36 | static inline bool check_aesgcm_availability(const struct aesgcm_extra *extra) 37 | { 38 | if (!extra->mut->checked_availability) { 39 | extra->mut->is_available = extra->check_available(); 40 | extra->mut->checked_availability = true; 41 | } 42 | 43 | return extra->mut->is_available; 44 | } 45 | -------------------------------------------------------------------------------- /crypto/blowfish.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Header file shared between blowfish.c and bcrypt.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 | -------------------------------------------------------------------------------- /crypto/hash_simple.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Convenience function to hash a single piece of data, wrapping up 3 | * the faff of making and freeing an ssh_hash. 4 | */ 5 | 6 | #include "ssh.h" 7 | 8 | void hash_simple(const ssh_hashalg *alg, ptrlen data, void *output) 9 | { 10 | ssh_hash *hash = ssh_hash_new(alg); 11 | put_datapl(hash, data); 12 | ssh_hash_final(hash, output); 13 | } 14 | -------------------------------------------------------------------------------- /crypto/mac.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 | -------------------------------------------------------------------------------- /crypto/mac_simple.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Convenience function to MAC a single piece of data, wrapping up 3 | * the faff of making and freeing an ssh_mac. 4 | */ 5 | 6 | #include "ssh.h" 7 | 8 | void mac_simple(const ssh2_macalg *alg, ptrlen key, ptrlen data, void *output) 9 | { 10 | ssh2_mac *mac = ssh2_mac_new(alg, NULL); 11 | ssh2_mac_setkey(mac, key); 12 | ssh2_mac_start(mac); 13 | put_datapl(mac, data); 14 | ssh2_mac_genresult(mac, output); 15 | ssh2_mac_free(mac); 16 | } 17 | -------------------------------------------------------------------------------- /crypto/pubkey-pem.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Convenience functions to encrypt and decrypt OpenSSH PEM format for 3 | * SSH-2 private key files. This uses triple-DES in SSH-2 style (one 4 | * CBC layer), with three distinct keys, and an IV also generated from 5 | * the passphrase. 6 | */ 7 | 8 | #include "ssh.h" 9 | 10 | static ssh_cipher *des3_pubkey_ossh_cipher(const void *vkey, const void *viv) 11 | { 12 | ssh_cipher *c = ssh_cipher_new(&ssh_3des_ssh2); 13 | ssh_cipher_setkey(c, vkey); 14 | ssh_cipher_setiv(c, viv); 15 | return c; 16 | } 17 | 18 | void des3_decrypt_pubkey_ossh(const void *vkey, const void *viv, 19 | void *vblk, int len) 20 | { 21 | ssh_cipher *c = des3_pubkey_ossh_cipher(vkey, viv); 22 | ssh_cipher_decrypt(c, vblk, len); 23 | ssh_cipher_free(c); 24 | } 25 | 26 | void des3_encrypt_pubkey_ossh(const void *vkey, const void *viv, 27 | void *vblk, int len) 28 | { 29 | ssh_cipher *c = des3_pubkey_ossh_cipher(vkey, viv); 30 | ssh_cipher_encrypt(c, vblk, len); 31 | ssh_cipher_free(c); 32 | } 33 | -------------------------------------------------------------------------------- /crypto/pubkey-ppk.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Convenience functions to encrypt and decrypt PuTTY's own .PPK 3 | * format for SSH-2 private key files, which uses 256-bit AES in CBC 4 | * mode. 5 | */ 6 | 7 | #include "ssh.h" 8 | 9 | static ssh_cipher *aes256_pubkey_cipher(const void *key, const void *iv) 10 | { 11 | ssh_cipher *cipher = ssh_cipher_new(&ssh_aes256_cbc); 12 | ssh_cipher_setkey(cipher, key); 13 | ssh_cipher_setiv(cipher, iv); 14 | return cipher; 15 | } 16 | 17 | void aes256_encrypt_pubkey(const void *key, const void *iv, void *blk, int len) 18 | { 19 | ssh_cipher *c = aes256_pubkey_cipher(key, iv); 20 | ssh_cipher_encrypt(c, blk, len); 21 | ssh_cipher_free(c); 22 | } 23 | 24 | void aes256_decrypt_pubkey(const void *key, const void *iv, void *blk, int len) 25 | { 26 | ssh_cipher *c = aes256_pubkey_cipher(key, iv); 27 | ssh_cipher_decrypt(c, blk, len); 28 | ssh_cipher_free(c); 29 | } 30 | -------------------------------------------------------------------------------- /crypto/pubkey-ssh1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Convenience functions to encrypt and decrypt the standard format 3 | * for SSH-1 private key files. This uses triple-DES in SSH-1 style 4 | * (three separate CBC layers), but the same key is used for the first 5 | * and third layers.CBC mode. 6 | */ 7 | 8 | #include "ssh.h" 9 | 10 | static ssh_cipher *des3_pubkey_cipher(const void *vkey) 11 | { 12 | ssh_cipher *c = ssh_cipher_new(&ssh_3des_ssh1); 13 | uint8_t keys3[24], iv[8]; 14 | 15 | memcpy(keys3, vkey, 16); 16 | memcpy(keys3 + 16, vkey, 8); 17 | ssh_cipher_setkey(c, keys3); 18 | smemclr(keys3, sizeof(keys3)); 19 | 20 | memset(iv, 0, 8); 21 | ssh_cipher_setiv(c, iv); 22 | 23 | return c; 24 | } 25 | 26 | void des3_decrypt_pubkey(const void *vkey, void *vblk, int len) 27 | { 28 | ssh_cipher *c = des3_pubkey_cipher(vkey); 29 | ssh_cipher_decrypt(c, vblk, len); 30 | ssh_cipher_free(c); 31 | } 32 | 33 | void des3_encrypt_pubkey(const void *vkey, void *vblk, int len) 34 | { 35 | ssh_cipher *c = des3_pubkey_cipher(vkey); 36 | ssh_cipher_encrypt(c, vblk, len); 37 | ssh_cipher_free(c); 38 | } 39 | -------------------------------------------------------------------------------- /crypto/sha1-common.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Common variable definitions across all the SHA-1 implementations. 3 | */ 4 | 5 | #include "ssh.h" 6 | #include "sha1.h" 7 | 8 | const uint32_t sha1_initial_state[5] = { 9 | 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0, 10 | }; 11 | -------------------------------------------------------------------------------- /crypto/sha1-select.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Top-level vtables to select a SHA-1 implementation. 3 | */ 4 | 5 | #include 6 | #include 7 | 8 | #include "putty.h" 9 | #include "ssh.h" 10 | #include "sha1.h" 11 | 12 | static ssh_hash *sha1_select(const ssh_hashalg *alg) 13 | { 14 | static const ssh_hashalg *const real_algs[] = { 15 | #if HAVE_SHA_NI 16 | &ssh_sha1_ni, 17 | #endif 18 | #if HAVE_NEON_CRYPTO 19 | &ssh_sha1_neon, 20 | #endif 21 | &ssh_sha1_sw, 22 | NULL, 23 | }; 24 | 25 | for (size_t i = 0; real_algs[i]; i++) { 26 | const ssh_hashalg *alg = real_algs[i]; 27 | const struct sha1_extra *alg_extra = 28 | (const struct sha1_extra *)alg->extra; 29 | if (check_availability(alg_extra)) 30 | return ssh_hash_new(alg); 31 | } 32 | 33 | /* We should never reach the NULL at the end of the list, because 34 | * the last non-NULL entry should be software-only SHA-1, which 35 | * is always available. */ 36 | unreachable("sha1_select ran off the end of its list"); 37 | } 38 | 39 | const ssh_hashalg ssh_sha1 = { 40 | .new = sha1_select, 41 | .hlen = 20, 42 | .blocklen = 64, 43 | HASHALG_NAMES_ANNOTATED("SHA-1", "dummy selector vtable"), 44 | }; 45 | -------------------------------------------------------------------------------- /crypto/sha256-common.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Common variable definitions across all the SHA-256 implementations. 3 | */ 4 | 5 | #include "ssh.h" 6 | #include "sha256.h" 7 | 8 | const uint32_t sha256_initial_state[8] = { 9 | 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 10 | 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, 11 | }; 12 | 13 | const uint32_t sha256_round_constants[64] = { 14 | 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 15 | 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 16 | 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 17 | 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 18 | 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 19 | 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 20 | 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 21 | 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 22 | 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 23 | 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 24 | 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 25 | 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 26 | 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 27 | 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 28 | 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 29 | 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, 30 | }; 31 | -------------------------------------------------------------------------------- /crypto/sha256-select.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Top-level vtables to select a SHA-256 implementation. 3 | */ 4 | 5 | #include 6 | #include 7 | 8 | #include "putty.h" 9 | #include "ssh.h" 10 | #include "sha256.h" 11 | 12 | static ssh_hash *sha256_select(const ssh_hashalg *alg) 13 | { 14 | static const ssh_hashalg *const real_algs[] = { 15 | #if HAVE_SHA_NI 16 | &ssh_sha256_ni, 17 | #endif 18 | #if HAVE_NEON_CRYPTO 19 | &ssh_sha256_neon, 20 | #endif 21 | &ssh_sha256_sw, 22 | NULL, 23 | }; 24 | 25 | for (size_t i = 0; real_algs[i]; i++) { 26 | const ssh_hashalg *alg = real_algs[i]; 27 | const struct sha256_extra *alg_extra = 28 | (const struct sha256_extra *)alg->extra; 29 | if (check_availability(alg_extra)) 30 | return ssh_hash_new(alg); 31 | } 32 | 33 | /* We should never reach the NULL at the end of the list, because 34 | * the last non-NULL entry should be software-only SHA-256, which 35 | * is always available. */ 36 | unreachable("sha256_select ran off the end of its list"); 37 | } 38 | 39 | const ssh_hashalg ssh_sha256 = { 40 | .new = sha256_select, 41 | .hlen = 32, 42 | .blocklen = 64, 43 | HASHALG_NAMES_ANNOTATED("SHA-256", "dummy selector vtable"), 44 | }; 45 | -------------------------------------------------------------------------------- /crypto/sha512-select.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Top-level vtables to select a SHA-512 implementation. 3 | */ 4 | 5 | #include 6 | #include 7 | 8 | #include "putty.h" 9 | #include "ssh.h" 10 | #include "sha512.h" 11 | 12 | static const ssh_hashalg *const real_sha512_algs[] = { 13 | #if HAVE_NEON_SHA512 14 | &ssh_sha512_neon, 15 | #endif 16 | &ssh_sha512_sw, 17 | NULL, 18 | }; 19 | 20 | static const ssh_hashalg *const real_sha384_algs[] = { 21 | #if HAVE_NEON_SHA512 22 | &ssh_sha384_neon, 23 | #endif 24 | &ssh_sha384_sw, 25 | NULL, 26 | }; 27 | 28 | static ssh_hash *sha512_select(const ssh_hashalg *alg) 29 | { 30 | const ssh_hashalg *const *real_algs = 31 | (const ssh_hashalg *const *)alg->extra; 32 | 33 | for (size_t i = 0; real_algs[i]; i++) { 34 | const ssh_hashalg *alg = real_algs[i]; 35 | const struct sha512_extra *alg_extra = 36 | (const struct sha512_extra *)alg->extra; 37 | if (check_availability(alg_extra)) 38 | return ssh_hash_new(alg); 39 | } 40 | 41 | /* We should never reach the NULL at the end of the list, because 42 | * the last non-NULL entry should be software-only SHA-512, which 43 | * is always available. */ 44 | unreachable("sha512_select ran off the end of its list"); 45 | } 46 | 47 | const ssh_hashalg ssh_sha512 = { 48 | .new = sha512_select, 49 | .hlen = 64, 50 | .blocklen = 128, 51 | HASHALG_NAMES_ANNOTATED("SHA-512", "dummy selector vtable"), 52 | .extra = real_sha512_algs, 53 | }; 54 | 55 | const ssh_hashalg ssh_sha384 = { 56 | .new = sha512_select, 57 | .hlen = 48, 58 | .blocklen = 128, 59 | HASHALG_NAMES_ANNOTATED("SHA-384", "dummy selector vtable"), 60 | .extra = real_sha384_algs, 61 | }; 62 | -------------------------------------------------------------------------------- /crypto/xdmauth.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Convenience functions to encrypt and decrypt the cookies used in 3 | * XDM-AUTHORIZATION-1. 4 | */ 5 | 6 | #include "ssh.h" 7 | 8 | static ssh_cipher *des_xdmauth_cipher(const void *vkeydata) 9 | { 10 | /* 11 | * XDM-AUTHORIZATION-1 uses single-DES, but packs the key into 7 12 | * bytes, so here we have to repack it manually into the canonical 13 | * form where it occupies 8 bytes each with the low bit unused. 14 | */ 15 | const unsigned char *keydata = (const unsigned char *)vkeydata; 16 | unsigned char key[8]; 17 | int i, nbits, j; 18 | unsigned int bits; 19 | 20 | bits = 0; 21 | nbits = 0; 22 | j = 0; 23 | for (i = 0; i < 8; i++) { 24 | if (nbits < 7) { 25 | bits = (bits << 8) | keydata[j]; 26 | nbits += 8; 27 | j++; 28 | } 29 | key[i] = (bits >> (nbits - 7)) << 1; 30 | bits &= ~(0x7F << (nbits - 7)); 31 | nbits -= 7; 32 | } 33 | 34 | ssh_cipher *c = ssh_cipher_new(&ssh_des); 35 | ssh_cipher_setkey(c, key); 36 | smemclr(key, sizeof(key)); 37 | ssh_cipher_setiv(c, key); 38 | return c; 39 | } 40 | 41 | void des_encrypt_xdmauth(const void *keydata, void *blk, int len) 42 | { 43 | ssh_cipher *c = des_xdmauth_cipher(keydata); 44 | ssh_cipher_encrypt(c, blk, len); 45 | ssh_cipher_free(c); 46 | } 47 | 48 | void des_decrypt_xdmauth(const void *keydata, void *blk, int len) 49 | { 50 | ssh_cipher *c = des_xdmauth_cipher(keydata); 51 | ssh_cipher_decrypt(c, blk, len); 52 | ssh_cipher_free(c); 53 | } 54 | -------------------------------------------------------------------------------- /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 | 21 | \cfg{xhtml-contents-filename}{index.html} 22 | \cfg{text-filename}{puttydoc.txt} 23 | \cfg{winhelp-filename}{putty.hlp} 24 | \cfg{info-filename}{putty.info} 25 | \cfg{chm-filename}{putty.chm} 26 | \cfg{pdf-filename}{putty.pdf} 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/chmextra.but: -------------------------------------------------------------------------------- 1 | \# If you want to do a Halibut build of the CHM file by hand, without 2 | \# the help of the CMake edifice, then include this file which will 3 | \# refer to chm.css. The CMake edifice builds its own with a different 4 | \# pathname in it, for the sake of out-of-tree builds. 5 | 6 | \cfg{chm-extra-file}{chm.css} 7 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /keygen/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_sources_from_current_dir(keygen 2 | dsa.c 3 | ecdsa.c 4 | millerrabin.c 5 | mpunsafe.c 6 | pockle.c 7 | prime.c 8 | primecandidate.c 9 | rsa.c 10 | smallprimes.c) 11 | -------------------------------------------------------------------------------- /keygen/ecdsa.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 | -------------------------------------------------------------------------------- /keygen/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 "mpunsafe.h" 11 | #include "crypto/mpint_i.h" 12 | 13 | /* 14 | * This global symbol is also defined in ssh/kex2-client.c, to ensure 15 | * that these unsafe non-constant-time mp_int functions can't end up 16 | * accidentally linked in to any PuTTY tool that actually makes an SSH 17 | * client connection. 18 | * 19 | * (Only _client_ connections, however. Uppity, being a test server 20 | * only, is exempt.) 21 | */ 22 | const int deliberate_symbol_clash = 12345; 23 | 24 | static size_t mp_unsafe_words_needed(mp_int *x) 25 | { 26 | size_t words = x->nw; 27 | while (words > 1 && !x->w[words-1]) 28 | words--; 29 | return words; 30 | } 31 | 32 | mp_int *mp_unsafe_shrink(mp_int *x) 33 | { 34 | x->nw = mp_unsafe_words_needed(x); 35 | /* This potentially leaves some allocated words between the new 36 | * and old values of x->nw, which won't be wiped by mp_free now 37 | * that x->nw doesn't mention that they exist. But we've just 38 | * checked they're all zero, so we don't need to wipe them now 39 | * either. */ 40 | return x; 41 | } 42 | 43 | mp_int *mp_unsafe_copy(mp_int *x) 44 | { 45 | mp_int *copy = mp_make_sized(mp_unsafe_words_needed(x)); 46 | mp_copy_into(copy, x); 47 | return copy; 48 | } 49 | -------------------------------------------------------------------------------- /keygen/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 | #endif /* PUTTY_MPINT_UNSAFE_H */ 40 | -------------------------------------------------------------------------------- /keygen/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 | -------------------------------------------------------------------------------- /make_with_mingw.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # install compiler first: 4 | # sudo apt install mingw-w64 5 | # 6 | # i686 (32 bit) version is built by default. 7 | # 8 | # For x86_64 (64 bit) build, replace 9 | # i686-w64-mingw32 10 | # with 11 | # x86_64-w64-mingw32 12 | # 13 | cmake -DCMAKE_SYSTEM_NAME=Windows \ 14 | -DCMAKE_SYSTEM_PROCESSOR=x86 \ 15 | -DCMAKE_C_COMPILER=i686-w64-mingw32-gcc \ 16 | -DCMAKE_CXX_COMPILER=i686-w64-mingw32-g++ \ 17 | -DCMAKE_RC_COMPILER=i686-w64-mingw32-windres \ 18 | -B build -S . 19 | cd build 20 | make -j$(nproc --all) 21 | -------------------------------------------------------------------------------- /mksrcarc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | # These are text files. 6 | text=`{ find . -name CVS -prune -o \ 7 | -name .cvsignore -prune -o \ 8 | -name .svn -prune -o \ 9 | -name .git -prune -o \ 10 | -name LATEST.VER -prune -o \ 11 | -name CHECKLST.txt -prune -o \ 12 | -name mksrcarc.sh -prune -o \ 13 | -name '*.chm' -prune -o \ 14 | -name '*.cur' -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 '*.chm' -print -o -name '*.cur' -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 suffix to put on the Unix source tarball 7 | # - the options to put on the 'make' command line for the docs 8 | 9 | arcsuffix="$1" 10 | 11 | relver=`cat LATEST.VER` 12 | arcname="putty$arcsuffix" 13 | mkdir uxarc 14 | mkdir uxarc/$arcname 15 | find . -name uxarc -prune -o \ 16 | -name CVS -prune -o \ 17 | -name .svn -prune -o \ 18 | -name . -o \ 19 | -type d -exec mkdir uxarc/$arcname/{} \; 20 | find . -name uxarc -prune -o \ 21 | -name CVS -prune -o \ 22 | -name .cvsignore -prune -o \ 23 | -name .svn -prune -o \ 24 | -name '*.zip' -prune -o \ 25 | -name '*.tar.gz' -prune -o \ 26 | -type f -exec ln -s $PWD/{} uxarc/$arcname/{} \; 27 | 28 | tar -C uxarc -chzof $arcname.tar.gz $arcname 29 | rm -rf uxarc 30 | -------------------------------------------------------------------------------- /otherbackends/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_sources_from_current_dir(otherbackends 2 | raw.c 3 | rlogin.c 4 | supdup.c 5 | telnet.c 6 | testback.c) 7 | -------------------------------------------------------------------------------- /proxy/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 | const bool socks5_chap_available = false; 16 | const bool http_digest_available = false; 17 | 18 | strbuf *chap_response(ptrlen challenge, ptrlen password) 19 | { 20 | unreachable("CHAP is not built into this binary"); 21 | } 22 | 23 | /* dummy arrays to prevent link error */ 24 | const char *const httphashnames[] = { NULL }; 25 | const bool httphashaccepted[] = { false }; 26 | 27 | void http_digest_response(BinarySink *bs, ptrlen username, ptrlen password, 28 | ptrlen realm, ptrlen method, ptrlen uri, ptrlen qop, 29 | ptrlen nonce, ptrlen opaque, uint32_t nonce_count, 30 | HttpDigestHash hash, bool hash_username) 31 | { 32 | unreachable("HTTP DIGEST is not built into this binary"); 33 | } 34 | -------------------------------------------------------------------------------- /proxy/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, Interactor *itr) 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 | -------------------------------------------------------------------------------- /proxy/nosshproxy.c: -------------------------------------------------------------------------------- 1 | /* 2 | * nosshproxy.c: stub implementation of sshproxy_new_connection(). 3 | */ 4 | 5 | #include "putty.h" 6 | #include "network.h" 7 | 8 | const bool ssh_proxy_supported = false; 9 | 10 | Socket *sshproxy_new_connection(SockAddr *addr, const char *hostname, 11 | int port, bool privport, 12 | bool oobinline, bool nodelay, bool keepalive, 13 | Plug *plug, Conf *conf, Interactor *itr) 14 | { 15 | return NULL; 16 | } 17 | -------------------------------------------------------------------------------- /proxy/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, Interactor *itr) 15 | { 16 | return NULL; 17 | } 18 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /ssh/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(sshcommon OBJECT 2 | bpp1.c 3 | bpp2.c 4 | bpp-bare.c 5 | ca-config.c 6 | censor1.c 7 | censor2.c 8 | common.c 9 | connection1.c 10 | connection2.c 11 | crc-attack-detector.c 12 | gssc.c 13 | login1.c 14 | pgssapi.c 15 | portfwd.c 16 | ../sshpubk.c 17 | ../sshrand.c 18 | transient-hostkey-cache.c 19 | transport2.c 20 | verstring.c 21 | x11fwd.c 22 | zlib.c) 23 | 24 | add_library(sftpcommon OBJECT sftpcommon.c) 25 | 26 | add_library(sshclient STATIC 27 | agentf.c 28 | connection1-client.c 29 | connection2-client.c 30 | kex2-client.c 31 | mainchan.c 32 | sharing.c 33 | ssh.c 34 | userauth2-client.c 35 | $ 36 | $ 37 | $) 38 | 39 | add_library(sshserver STATIC 40 | connection1-server.c 41 | connection2-server.c 42 | kex2-server.c 43 | login1-server.c 44 | server.c 45 | sesschan.c 46 | sftpserver.c 47 | userauth2-server.c 48 | $ 49 | $) 50 | 51 | add_sources_from_current_dir(sftpclient sftp.c) 52 | target_sources(sftpclient PRIVATE $) 53 | -------------------------------------------------------------------------------- /ssh/gssc.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 "gss.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 | -------------------------------------------------------------------------------- /ssh/nogss.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 | -------------------------------------------------------------------------------- /ssh/nosharing.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 | bool can_upstream, bool can_downstream) 19 | { 20 | return SHARE_NONE; 21 | } 22 | 23 | void platform_ssh_share_cleanup(const char *name) 24 | { 25 | } 26 | -------------------------------------------------------------------------------- /stubs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # This subdirectory is generally full of 'stubs' in the sense of 2 | # functions and types that don't do anything interesting, and are 3 | # substituted in some contexts for ones that do. 4 | # 5 | # Some of the files here, with names beginning 'no-', are substituted 6 | # at link time, conditional on the application. For example, a program 7 | # that doesn't use the timing subsystem but still includes a module 8 | # that makes a passing reference to it (say, in a context that never 9 | # turns out to be called) can link against no-timing.c in place of the 10 | # real timing.c. 11 | # 12 | # Other files, with names beginning 'null-', provide non-functional 13 | # implementations of a particular internal API, or a selection of 14 | # non-functional methods for that API that real implementations can 15 | # selectively use. Those are linked in to a program _alongside_ real 16 | # implementations of the same API. 17 | # 18 | # So the cmake setup for this directory puts all the 'null-' files 19 | # into the utils library (at the end of the link, where they'll be 20 | # available everywhere), but doesn't mention the 'no-' files, because 21 | # those will be selected manually by add_executable() commands 22 | # elsewhere. 23 | 24 | add_sources_from_current_dir(utils 25 | null-lp.c 26 | null-cipher.c 27 | null-key.c 28 | null-mac.c 29 | null-opener.c 30 | null-plug.c 31 | null-seat.c) 32 | -------------------------------------------------------------------------------- /stubs/no-agent.c: -------------------------------------------------------------------------------- 1 | #include "putty.h" 2 | 3 | bool agent_exists(void) { return false; } 4 | Socket *agent_connect(Plug *plug) { 5 | return new_error_socket_fmt( 6 | plug, "no actual networking in this application"); 7 | } 8 | void agent_cancel_query(agent_pending_query *pq) {} 9 | agent_pending_query *agent_query( 10 | strbuf *query, void **out, int *outlen, 11 | void (*callback)(void *, void *, int), void *callback_ctx) {return NULL;} 12 | -------------------------------------------------------------------------------- /stubs/no-ca-config.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Stub version of setup_ca_config_box, for tools that don't have SSH 3 | * code linked in. 4 | */ 5 | 6 | #include "putty.h" 7 | #include "dialog.h" 8 | 9 | const bool has_ca_config_box = false; 10 | 11 | void setup_ca_config_box(struct controlbox *b) 12 | { 13 | unreachable("should never call setup_ca_config_box in this application"); 14 | } 15 | -------------------------------------------------------------------------------- /stubs/no-callback.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Stub version of the callback.c functions. Doesn't let anyone 3 | * _schedule_ a callback (because that would lead them into the false 4 | * assumption that it would actually happen later on), but permits the 5 | * other functions without error, on the grounds that it's well 6 | * defined what they would do if nobody had scheduled any callbacks. 7 | */ 8 | 9 | #include "putty.h" 10 | 11 | void queue_idempotent_callback(struct IdempotentCallback *ic) 12 | { 13 | unreachable("callbacks are not supported in this application"); 14 | } 15 | 16 | void delete_callbacks_for_context(void *ctx) 17 | { 18 | } 19 | 20 | void queue_toplevel_callback(toplevel_callback_fn_t fn, void *ctx) 21 | { 22 | unreachable("callbacks are not supported in this application"); 23 | } 24 | 25 | bool run_toplevel_callbacks(void) 26 | { 27 | return false; 28 | } 29 | 30 | bool toplevel_callback_pending(void) 31 | { 32 | return false; 33 | } 34 | -------------------------------------------------------------------------------- /stubs/no-cmdline.c: -------------------------------------------------------------------------------- 1 | /* 2 | * no-cmdline.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 | SeatPromptResult cmdline_get_passwd_input( 19 | prompts_t *p, cmdline_get_passwd_input_state *state, bool restartable) 20 | { 21 | return SPR_INCOMPLETE; 22 | } 23 | -------------------------------------------------------------------------------- /stubs/no-console.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Stub functions for when console.c is not linked into a program. 3 | */ 4 | 5 | #include "putty.h" 6 | 7 | bool console_set_batch_mode(bool newvalue) 8 | { 9 | return false; 10 | } 11 | 12 | bool console_set_stdio_prompts(bool newvalue) 13 | { 14 | return false; 15 | } 16 | -------------------------------------------------------------------------------- /stubs/no-gss.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 | #include "ssh/pgssapi.h" 10 | #include "ssh/gss.h" 11 | #include "ssh/gssc.h" 12 | 13 | const int ngsslibs = 0; 14 | const char *const gsslibnames[1] = { "dummy" }; 15 | const struct keyvalwhere gsslibkeywords[1] = { { "dummy", 0, -1, -1 } }; 16 | 17 | struct ssh_gss_liblist *ssh_gss_setup(Conf *conf) 18 | { 19 | struct ssh_gss_liblist *list = snew(struct ssh_gss_liblist); 20 | 21 | list->libraries = NULL; 22 | list->nlibraries = 0; 23 | return list; 24 | } 25 | 26 | void ssh_gss_cleanup(struct ssh_gss_liblist *list) 27 | { 28 | sfree(list->libraries); /* I know it's always NULL, but stay consistent */ 29 | sfree(list); 30 | } 31 | -------------------------------------------------------------------------------- /stubs/no-ldisc.c: -------------------------------------------------------------------------------- 1 | #include "putty.h" 2 | 3 | struct Ldisc_tag { 4 | int dummy; 5 | }; 6 | 7 | Ldisc *ldisc_create(Conf *conf, Terminal *term, Backend *backend, Seat *seat) 8 | { 9 | Ldisc *ldisc = snew(Ldisc); 10 | memset(ldisc, 0, sizeof(Ldisc)); 11 | return ldisc; 12 | } 13 | 14 | void ldisc_configure(Ldisc *ldisc, Conf *conf) 15 | { 16 | } 17 | 18 | void ldisc_free(Ldisc *ldisc) 19 | { 20 | sfree(ldisc); 21 | } 22 | 23 | void ldisc_echoedit_update(Ldisc *ldisc) 24 | { 25 | } 26 | 27 | void ldisc_provide_userpass_le(Ldisc *ldisc, TermLineEditor *le) 28 | { 29 | } 30 | 31 | void ldisc_check_sendok(Ldisc *ldisc) 32 | { 33 | } 34 | 35 | void ldisc_send(Ldisc *ldisc, const void *vbuf, int len, bool interactive) 36 | { 37 | } 38 | -------------------------------------------------------------------------------- /stubs/no-lineedit.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Stubs of functions in lineedit.c, for use in programs that don't 3 | * have any use for line editing (e.g. because they don't have a 4 | * terminal either). 5 | */ 6 | 7 | #include "putty.h" 8 | #include "terminal.h" 9 | 10 | TermLineEditor *lineedit_new(Terminal *term, unsigned flags, 11 | TermLineEditorCallbackReceiver *receiver) 12 | { 13 | return NULL; 14 | } 15 | void lineedit_free(TermLineEditor *le) {} 16 | void lineedit_input(TermLineEditor *le, char ch, bool dedicated) {} 17 | void lineedit_modify_flags(TermLineEditor *le, unsigned clr, unsigned flip) {} 18 | void lineedit_send_line(TermLineEditor *le) {} 19 | -------------------------------------------------------------------------------- /stubs/no-logging.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Stub module implementing the logging API for tools that don't do 3 | * session logging. 4 | */ 5 | 6 | #include "putty.h" 7 | 8 | void logtraffic(LogContext *ctx, unsigned char c, int logmode) {} 9 | void logflush(LogContext *ctx) {} 10 | void logevent(LogContext *ctx, const char *event) {} 11 | void log_free(LogContext *ctx) {} 12 | void log_reconfig(LogContext *ctx, Conf *conf) {} 13 | void log_packet(LogContext *ctx, int direction, int type, 14 | const char *texttype, const void *data, size_t len, 15 | int n_blanks, const struct logblank_t *blanks, 16 | const unsigned long *seq, 17 | unsigned downstream_id, const char *additional_log_text) {} 18 | 19 | LogContext *log_init(LogPolicy *lp, Conf *conf) 20 | { return NULL; } 21 | -------------------------------------------------------------------------------- /stubs/no-print.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, const 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 | -------------------------------------------------------------------------------- /stubs/no-printing.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Stub module implementing the printing API for tools that don't 3 | * print. 4 | */ 5 | 6 | #include "putty.h" 7 | 8 | printer_job *printer_start_job(char *printer) { return NULL; } 9 | void printer_job_data(printer_job *pj, const void *data, size_t len) {} 10 | void printer_finish_job(printer_job *pj) {} 11 | 12 | printer_enum *printer_start_enum(int *nprinters_ptr) 13 | { 14 | *nprinters_ptr = 0; 15 | return NULL; 16 | } 17 | char *printer_get_name(printer_enum *pe, int i) { return NULL; } 18 | void printer_finish_enum(printer_enum *pe) {} 19 | -------------------------------------------------------------------------------- /stubs/no-rand.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 | -------------------------------------------------------------------------------- /stubs/no-term.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 | 13 | SeatPromptResult term_get_userpass_input(Terminal *term, prompts_t *p) 14 | { 15 | return SPR_SW_ABORT("No terminal to send interactive prompts to"); 16 | } 17 | -------------------------------------------------------------------------------- /stubs/no-timing.c: -------------------------------------------------------------------------------- 1 | /* 2 | * no-timing.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 | 23 | unsigned long timing_last_clock(void) 24 | { 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /stubs/null-cipher.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Implementation of shared trivial routines that ssh_cipher 3 | * implementations might use. 4 | */ 5 | 6 | #include "ssh.h" 7 | 8 | void nullcipher_next_message(ssh_cipher *cipher) 9 | { 10 | /* Most ciphers don't do anything at all with this */ 11 | } 12 | -------------------------------------------------------------------------------- /stubs/null-key.c: -------------------------------------------------------------------------------- 1 | #include "misc.h" 2 | #include "ssh.h" 3 | 4 | unsigned nullkey_supported_flags(const ssh_keyalg *self) 5 | { 6 | return 0; 7 | } 8 | 9 | const char *nullkey_alternate_ssh_id(const ssh_keyalg *self, unsigned flags) 10 | { 11 | /* There are no alternate ids */ 12 | return self->ssh_id; 13 | } 14 | 15 | ssh_key *nullkey_base_key(ssh_key *key) 16 | { 17 | /* When a key is not certified, it is its own base */ 18 | return key; 19 | } 20 | 21 | bool nullkey_variable_size_no(const ssh_keyalg *self) { return false; } 22 | bool nullkey_variable_size_yes(const ssh_keyalg *self) { return true; } 23 | -------------------------------------------------------------------------------- /stubs/null-lp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Stub methods usable by LogPolicy implementations. 3 | */ 4 | 5 | #include "putty.h" 6 | 7 | bool null_lp_verbose_no(LogPolicy *lp) { return false; } 8 | bool null_lp_verbose_yes(LogPolicy *lp) { return true; } 9 | -------------------------------------------------------------------------------- /stubs/null-mac.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Implementation of shared trivial routines that ssh2_mac 3 | * implementations might use. 4 | */ 5 | 6 | #include "ssh.h" 7 | 8 | void nullmac_next_message(ssh2_mac *m) 9 | { 10 | /* Most MACs don't do anything at all with this */ 11 | } 12 | -------------------------------------------------------------------------------- /stubs/null-opener.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Null implementation of DeferredSocketOpener. Doesn't even bother to 3 | * allocate and free itself: there's just one static implementation 4 | * which we hand out to any caller. 5 | */ 6 | 7 | #include "putty.h" 8 | 9 | static void null_opener_free(DeferredSocketOpener *opener) {} 10 | 11 | static const DeferredSocketOpenerVtable NullOpener_vt = { 12 | .free = null_opener_free, 13 | }; 14 | 15 | static DeferredSocketOpener null_opener = { .vt = &NullOpener_vt }; 16 | 17 | DeferredSocketOpener *null_deferred_socket_opener(void) 18 | { 19 | return &null_opener; 20 | } 21 | -------------------------------------------------------------------------------- /stubs/null-plug.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 | void nullplug_log(Plug *plug, PlugLogType type, SockAddr *addr, 11 | int port, const char *err_msg, int err_code) 12 | { 13 | } 14 | 15 | void nullplug_closing(Plug *plug, PlugCloseType type, const char *error_msg) 16 | { 17 | } 18 | 19 | void nullplug_receive(Plug *plug, int urgent, const char *data, size_t len) 20 | { 21 | } 22 | 23 | void nullplug_sent(Plug *plug, size_t bufsize) 24 | { 25 | } 26 | 27 | static const PlugVtable nullplug_plugvt = { 28 | .log = nullplug_log, 29 | .closing = nullplug_closing, 30 | .receive = nullplug_receive, 31 | .sent = nullplug_sent, 32 | }; 33 | 34 | static Plug nullplug_plug = { &nullplug_plugvt }; 35 | 36 | /* 37 | * There's a singleton instance of nullplug, because it's not 38 | * interesting enough to worry about making more than one of them. 39 | */ 40 | Plug *const nullplug = &nullplug_plug; 41 | -------------------------------------------------------------------------------- /terminal/bidi_gettype.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Standalone test program that exposes the minibidi getType function. 3 | */ 4 | 5 | #include 6 | #include 7 | 8 | #include "putty.h" 9 | #include "misc.h" 10 | #include "bidi.h" 11 | 12 | void out_of_memory(void) 13 | { 14 | fprintf(stderr, "out of memory!\n"); 15 | exit(2); 16 | } 17 | 18 | #define TYPETONAME(X) #X, 19 | static const char *const typenames[] = { BIDI_CHAR_TYPE_LIST(TYPETONAME) }; 20 | #undef TYPETONAME 21 | 22 | int main(int argc, char **argv) 23 | { 24 | int i; 25 | 26 | for (i = 1; i < argc; i++) { 27 | unsigned long chr = strtoul(argv[i], NULL, 0); 28 | int type = bidi_getType(chr); 29 | printf("U+%04x: %s\n", (unsigned)chr, typenames[type]); 30 | } 31 | 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /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/list-accel.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Simple client of the testcrypt system that reports the available 4 | # variants of each of the crypto primitives that have hardware- 5 | # accelerated implementations. 6 | # 7 | # It will report the set of primitives compiled in to testcrypt, and 8 | # also report whether each one can be instantiated at run time. 9 | 10 | from testcrypt import * 11 | 12 | def get_implementations(alg): 13 | return get_implementations_commasep(alg).decode("ASCII").split(",") 14 | 15 | def list_implementations(alg, checkfn): 16 | print(f"Implementations of {alg}:") 17 | for impl in get_implementations(alg): 18 | if impl == alg: 19 | continue 20 | if checkfn(impl): 21 | print(f" {impl:<32s} available") 22 | else: 23 | print(f" {impl:<32s} compiled in, but unavailable at run time") 24 | 25 | def list_cipher_implementations(alg): 26 | list_implementations(alg, lambda impl: ssh_cipher_new(impl) is not None) 27 | 28 | def list_mac_implementations(alg): 29 | list_implementations(alg, lambda impl: ssh2_mac_new(impl, None) is not None) 30 | 31 | def list_hash_implementations(alg): 32 | list_implementations(alg, lambda impl: ssh_hash_new(impl) is not None) 33 | 34 | list_cipher_implementations("aes256_cbc") 35 | list_mac_implementations("aesgcm") 36 | list_hash_implementations("sha1") 37 | list_hash_implementations("sha256") 38 | list_hash_implementations("sha512") 39 | -------------------------------------------------------------------------------- /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/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 | project(sclog LANGUAGES C) 8 | 9 | find_package(DynamoRIO) 10 | if (NOT DynamoRIO_FOUND) 11 | message(FATAL_ERROR "DynamoRIO not found") 12 | endif() 13 | 14 | add_library(sclog SHARED sclog.c) 15 | configure_DynamoRIO_client(sclog) 16 | foreach(extension drmgr drsyms drreg drutil drwrap) 17 | use_DynamoRIO_extension(sclog ${extension}) 18 | endforeach() 19 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /unicode/version.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Autogenerated by read_ucd.py from The Unicode Standard 15.0.0 3 | * 4 | * String literals giving the currently supported version of Unicode. 5 | * Useful for error messages and 'about' boxes. 6 | */ 7 | 8 | #define UNICODE_VERSION_FULL "The Unicode Standard 15.0.0" 9 | #define UNICODE_VERSION_SHORT "15.0.0" 10 | -------------------------------------------------------------------------------- /unix/config-unix.c: -------------------------------------------------------------------------------- 1 | /* 2 | * config-unix.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 | dlgcontrol *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]->type == CTRL_EDITBOX); 32 | s->ctrls[0]->editbox.has_list = false; 33 | 34 | /* 35 | * Unix supports a local-command proxy. 36 | */ 37 | if (!midsession) { 38 | int i; 39 | s = ctrl_getset(b, "Connection/Proxy", "basics", NULL); 40 | for (i = 0; i < s->ncontrols; i++) { 41 | c = s->ctrls[i]; 42 | if (c->type == CTRL_LISTBOX && 43 | c->handler == proxy_type_handler) { 44 | c->context.i |= PROXY_UI_FLAG_LOCAL; 45 | break; 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /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/keygen-noise.c: -------------------------------------------------------------------------------- 1 | /* 2 | * keygen-noise.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/no-gtk.c: -------------------------------------------------------------------------------- 1 | /* 2 | * no-gtk.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/noaskpass.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Dummy (lack-of-)implementation of a GUI password/passphrase prompt. 3 | */ 4 | 5 | #include "putty.h" 6 | 7 | void random_add_noise(NoiseSourceId source, const void *noise, int length) 8 | { 9 | /* We have no keypress_prng here, so no need to implement this */ 10 | } 11 | 12 | const bool buildinfo_gtk_relevant = false; 13 | 14 | char *gtk_askpass_main(const char *display, const char *wintitle, 15 | const char *prompt, bool *success) 16 | { 17 | *success = false; 18 | return dupstr("this Pageant was built without GTK"); 19 | } 20 | -------------------------------------------------------------------------------- /unix/peerinfo.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Unix: wrapper for getsockopt(SO_PEERCRED), conditionalised on 3 | * appropriate autoconfery. 4 | */ 5 | 6 | #if HAVE_CMAKE_H 7 | #include "cmake.h" 8 | #endif 9 | 10 | #if 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 | #if 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/printing.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 *pj = 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 | pj->fp = popen(printer, "w"); 21 | if (!pj->fp) { 22 | sfree(pj); 23 | pj = NULL; 24 | } 25 | return pj; 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 config-unix.c will disable 50 | * the 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/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.c: -------------------------------------------------------------------------------- 1 | /* 2 | * pterm main program. 3 | */ 4 | 5 | #include 6 | #include 7 | 8 | #include "putty.h" 9 | 10 | const bool use_event_log = false; /* pterm doesn't need it */ 11 | const bool new_session = false, saved_sessions = false; /* or these */ 12 | const bool dup_check_launchable = false; /* no need to check host name 13 | * in conf */ 14 | const bool use_pty_argv = true; 15 | 16 | const unsigned cmdline_tooltype = TOOLTYPE_NONNETWORK; 17 | 18 | /* window.c will call this, and in pterm it's not needed */ 19 | void noise_ultralight(NoiseSourceId id, unsigned long data) { } 20 | 21 | const struct BackendVtable *select_backend(Conf *conf) 22 | { 23 | return &pty_backend; 24 | } 25 | 26 | void initial_config_box(Conf *conf, post_dialog_fn_t after, void *afterctx) 27 | { 28 | /* 29 | * This is a no-op in pterm, except that we'll ensure the protocol 30 | * is set to -1 to inhibit the useless Connection panel in the 31 | * config box. So we do that and then just immediately call the 32 | * post-dialog function with a positive result. 33 | */ 34 | conf_set_int(conf, CONF_protocol, -1); 35 | after(afterctx, 1); 36 | } 37 | 38 | void cleanup_exit(int code) 39 | { 40 | exit(code); 41 | } 42 | 43 | void setup(bool single) 44 | { 45 | settings_set_default_protocol(-1); 46 | 47 | if (single) 48 | pty_pre_init(); 49 | } 50 | -------------------------------------------------------------------------------- /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.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/stubs/no-uxsel.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Stub version of uxsel.c, for test programs. 3 | */ 4 | 5 | #include "putty.h" 6 | 7 | void uxsel_init(void) 8 | { 9 | } 10 | 11 | void uxsel_set(int fd, int rwx, uxsel_callback_fn callback) 12 | { 13 | } 14 | 15 | void uxsel_del(int fd) 16 | { 17 | } 18 | 19 | int next_fd(int *state, int *rwx) 20 | { 21 | return -1; 22 | } 23 | 24 | int first_fd(int *state, int *rwx) 25 | { 26 | return -1; 27 | } 28 | 29 | void select_result(int fd, int event) 30 | { 31 | } 32 | -------------------------------------------------------------------------------- /unix/utils/align_label_left.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Helper function to align the text in a GtkLabel to the left, which 3 | * has to be done in several different ways depending on GTK version. 4 | */ 5 | 6 | #include 7 | #include "putty.h" 8 | #include "gtkcompat.h" 9 | #include "gtkmisc.h" 10 | 11 | void align_label_left(GtkLabel *label) 12 | { 13 | #if GTK_CHECK_VERSION(3,16,0) 14 | gtk_label_set_xalign(label, 0.0); 15 | #elif GTK_CHECK_VERSION(3,14,0) 16 | gtk_widget_set_halign(GTK_WIDGET(label), GTK_ALIGN_START); 17 | #else 18 | gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); 19 | #endif 20 | } 21 | -------------------------------------------------------------------------------- /unix/utils/block_signal.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Handy function to block or unblock a signal, which does all the 3 | * messing about with sigset_t for you. 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | #include "defs.h" 10 | 11 | void block_signal(int sig, bool block_it) 12 | { 13 | sigset_t ss; 14 | 15 | sigemptyset(&ss); 16 | sigaddset(&ss, sig); 17 | if (sigprocmask(block_it ? SIG_BLOCK : SIG_UNBLOCK, &ss, 0) < 0) { 18 | perror("sigprocmask"); 19 | exit(1); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /unix/utils/buildinfo_gtk_version.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Return the version of GTK we were compiled against, for buildinfo. 3 | */ 4 | 5 | #include 6 | #include "putty.h" 7 | #include "gtkcompat.h" 8 | #include "gtkmisc.h" 9 | 10 | char *buildinfo_gtk_version(void) 11 | { 12 | return dupprintf("%d.%d.%d", 13 | GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION); 14 | } 15 | -------------------------------------------------------------------------------- /unix/utils/cloexec.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Set and clear the FD_CLOEXEC fcntl option on a file descriptor. 3 | * 4 | * We don't realistically expect these operations to fail (the most 5 | * plausible error condition is EBADF, but we always believe ourselves 6 | * to be passing a valid fd so even that's an assertion-fail sort of 7 | * response), so we don't make any effort to return sensible error 8 | * codes to the caller - we just log to standard error and die 9 | * unceremoniously. 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | 19 | #include "putty.h" 20 | 21 | void cloexec(int fd) 22 | { 23 | int fdflags; 24 | 25 | fdflags = fcntl(fd, F_GETFD); 26 | if (fdflags < 0) { 27 | fprintf(stderr, "%d: fcntl(F_GETFD): %s\n", fd, strerror(errno)); 28 | exit(1); 29 | } 30 | if (fcntl(fd, F_SETFD, fdflags | FD_CLOEXEC) < 0) { 31 | fprintf(stderr, "%d: fcntl(F_SETFD): %s\n", fd, strerror(errno)); 32 | exit(1); 33 | } 34 | } 35 | 36 | void noncloexec(int fd) 37 | { 38 | int fdflags; 39 | 40 | fdflags = fcntl(fd, F_GETFD); 41 | if (fdflags < 0) { 42 | fprintf(stderr, "%d: fcntl(F_GETFD): %s\n", fd, strerror(errno)); 43 | exit(1); 44 | } 45 | if (fcntl(fd, F_SETFD, fdflags & ~FD_CLOEXEC) < 0) { 46 | fprintf(stderr, "%d: fcntl(F_SETFD): %s\n", fd, strerror(errno)); 47 | exit(1); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /unix/utils/dputs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Implementation of dputs() for Unix. 3 | * 4 | * The debug messages are written to standard output, and also into a 5 | * file called debug.log. 6 | */ 7 | 8 | #include 9 | 10 | #include "putty.h" 11 | 12 | static FILE *debug_fp = NULL; 13 | 14 | void dputs(const char *buf) 15 | { 16 | if (!debug_fp) { 17 | debug_fp = fopen("debug.log", "w"); 18 | } 19 | 20 | if (write(1, buf, strlen(buf)) < 0) {} /* 'error check' to placate gcc */ 21 | 22 | fputs(buf, debug_fp); 23 | fflush(debug_fp); 24 | } 25 | -------------------------------------------------------------------------------- /unix/utils/filename.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Implementation of Filename for Unix, including f_open(). 3 | */ 4 | 5 | #include 6 | #include 7 | 8 | #include "putty.h" 9 | 10 | Filename *filename_from_str(const char *str) 11 | { 12 | Filename *fn = snew(Filename); 13 | fn->path = dupstr(str); 14 | return fn; 15 | } 16 | 17 | Filename *filename_copy(const Filename *fn) 18 | { 19 | return filename_from_str(fn->path); 20 | } 21 | 22 | const char *filename_to_str(const Filename *fn) 23 | { 24 | return fn->path; 25 | } 26 | 27 | bool filename_equal(const Filename *f1, const Filename *f2) 28 | { 29 | return !strcmp(f1->path, f2->path); 30 | } 31 | 32 | bool filename_is_null(const Filename *fn) 33 | { 34 | return !fn->path[0]; 35 | } 36 | 37 | void filename_free(Filename *fn) 38 | { 39 | sfree(fn->path); 40 | sfree(fn); 41 | } 42 | 43 | void filename_serialise(BinarySink *bs, const Filename *f) 44 | { 45 | put_asciz(bs, f->path); 46 | } 47 | Filename *filename_deserialise(BinarySource *src) 48 | { 49 | return filename_from_str(get_asciz(src)); 50 | } 51 | 52 | char filename_char_sanitise(char c) 53 | { 54 | if (c == '/') 55 | return '.'; 56 | return c; 57 | } 58 | 59 | FILE *f_open(const Filename *filename, char const *mode, bool is_private) 60 | { 61 | if (!is_private) { 62 | return fopen(filename->path, mode); 63 | } else { 64 | int fd; 65 | assert(mode[0] == 'w'); /* is_private is meaningless for read, 66 | and tricky for append */ 67 | fd = open(filename->path, O_WRONLY | O_CREAT | O_TRUNC, 0600); 68 | if (fd < 0) 69 | return NULL; 70 | return fdopen(fd, mode); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /unix/utils/fontspec.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Implementation of FontSpec for Unix. This is more or less 3 | * degenerate - on this platform a font specification is just a 4 | * string. 5 | */ 6 | 7 | #include "putty.h" 8 | 9 | FontSpec *fontspec_new(const char *name) 10 | { 11 | FontSpec *f = snew(FontSpec); 12 | f->name = dupstr(name); 13 | return f; 14 | } 15 | 16 | FontSpec *fontspec_new_default(void) 17 | { 18 | return fontspec_new(""); 19 | } 20 | 21 | FontSpec *fontspec_copy(const FontSpec *f) 22 | { 23 | return fontspec_new(f->name); 24 | } 25 | 26 | void fontspec_free(FontSpec *f) 27 | { 28 | sfree(f->name); 29 | sfree(f); 30 | } 31 | 32 | void fontspec_serialise(BinarySink *bs, FontSpec *f) 33 | { 34 | put_asciz(bs, f->name); 35 | } 36 | 37 | FontSpec *fontspec_deserialise(BinarySource *src) 38 | { 39 | return fontspec_new(get_asciz(src)); 40 | } 41 | -------------------------------------------------------------------------------- /unix/utils/get_label_text_dimensions.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Determine the dimensions of a piece of text in the standard 3 | * font used in GTK interface elements like labels. We do this by 4 | * instantiating an actual GtkLabel, and then querying its size. 5 | */ 6 | 7 | #include 8 | #include "putty.h" 9 | #include "gtkcompat.h" 10 | #include "gtkmisc.h" 11 | 12 | void get_label_text_dimensions(const char *text, int *width, int *height) 13 | { 14 | GtkWidget *label = gtk_label_new(text); 15 | 16 | /* 17 | * GTK2 and GTK3 require us to query the size completely 18 | * differently. I'm sure there ought to be an easier approach than 19 | * the way I'm doing this in GTK3, too! 20 | */ 21 | #if GTK_CHECK_VERSION(3,0,0) 22 | PangoLayout *layout = gtk_label_get_layout(GTK_LABEL(label)); 23 | PangoRectangle logrect; 24 | pango_layout_get_extents(layout, NULL, &logrect); 25 | if (width) 26 | *width = logrect.width / PANGO_SCALE; 27 | if (height) 28 | *height = logrect.height / PANGO_SCALE; 29 | #else 30 | GtkRequisition req; 31 | gtk_widget_size_request(label, &req); 32 | if (width) 33 | *width = req.width; 34 | if (height) 35 | *height = req.height; 36 | #endif 37 | 38 | g_object_ref_sink(G_OBJECT(label)); 39 | #if GTK_CHECK_VERSION(2,10,0) 40 | g_object_unref(label); 41 | #endif 42 | } 43 | -------------------------------------------------------------------------------- /unix/utils/get_username.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Implementation of get_username() for Unix. 3 | */ 4 | 5 | #include 6 | #include 7 | 8 | #include "putty.h" 9 | 10 | char *get_username(void) 11 | { 12 | struct passwd *p; 13 | uid_t uid = getuid(); 14 | char *user, *ret = NULL; 15 | 16 | /* 17 | * First, find who we think we are using getlogin. If this 18 | * agrees with our uid, we'll go along with it. This should 19 | * allow sharing of uids between several login names whilst 20 | * coping correctly with people who have su'ed. 21 | */ 22 | user = getlogin(); 23 | #if HAVE_SETPWENT 24 | setpwent(); 25 | #endif 26 | if (user) 27 | p = getpwnam(user); 28 | else 29 | p = NULL; 30 | if (p && p->pw_uid == uid) { 31 | /* 32 | * The result of getlogin() really does correspond to 33 | * our uid. Fine. 34 | */ 35 | ret = user; 36 | } else { 37 | /* 38 | * If that didn't work, for whatever reason, we'll do 39 | * the simpler version: look up our uid in the password 40 | * file and map it straight to a name. 41 | */ 42 | p = getpwuid(uid); 43 | if (!p) 44 | return NULL; 45 | ret = p->pw_name; 46 | } 47 | #if HAVE_ENDPWENT 48 | endpwent(); 49 | #endif 50 | 51 | return dupstr(ret); 52 | } 53 | -------------------------------------------------------------------------------- /unix/utils/get_x11_display.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Return the Xlib 'Display *' underlying our GTK environment, if any. 3 | */ 4 | 5 | #include 6 | #include "putty.h" 7 | #include "gtkcompat.h" 8 | #include "gtkmisc.h" 9 | 10 | #ifndef NOT_X_WINDOWS 11 | 12 | #include 13 | #include 14 | 15 | Display *get_x11_display(void) 16 | { 17 | #if GTK_CHECK_VERSION(3,0,0) 18 | if (!GDK_IS_X11_DISPLAY(gdk_display_get_default())) 19 | return NULL; 20 | #endif 21 | return GDK_DISPLAY_XDISPLAY(gdk_display_get_default()); 22 | } 23 | 24 | #else 25 | 26 | /* 27 | * Include _something_ in this file to prevent an annoying compiler 28 | * warning, and to avoid having to condition out this file in 29 | * CMakeLists. It's in a library, so this variable shouldn't end up in 30 | * any actual program, because nothing will refer to it. 31 | */ 32 | const int get_x11_display_dummy_variable = 0; 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /unix/utils/getticks.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Implement getticks() for Unix. 3 | */ 4 | 5 | #include 6 | #include 7 | 8 | #include "putty.h" 9 | 10 | unsigned long getticks(void) 11 | { 12 | /* 13 | * We want to use milliseconds rather than the microseconds or 14 | * nanoseconds given by the underlying clock functions, because we 15 | * need a decent number of them to fit into a 32-bit word so it 16 | * can be used for keepalives. 17 | */ 18 | #if HAVE_CLOCK_GETTIME && HAVE_CLOCK_MONOTONIC 19 | { 20 | /* Use CLOCK_MONOTONIC if available, so as to be unconfused if 21 | * the system clock changes. */ 22 | struct timespec ts; 23 | if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) 24 | return ts.tv_sec * TICKSPERSEC + 25 | ts.tv_nsec / (1000000000 / TICKSPERSEC); 26 | } 27 | #endif 28 | { 29 | struct timeval tv; 30 | gettimeofday(&tv, NULL); 31 | return tv.tv_sec * TICKSPERSEC + tv.tv_usec / (1000000 / TICKSPERSEC); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /unix/utils/make_dir_path.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Make a path of subdirectories, tolerating EEXIST at every step. 3 | */ 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "putty.h" 13 | 14 | char *make_dir_path(const char *path, mode_t mode) 15 | { 16 | int pos = 0; 17 | char *prefix; 18 | 19 | while (1) { 20 | pos += strcspn(path + pos, "/"); 21 | 22 | if (pos > 0) { 23 | prefix = dupprintf("%.*s", pos, path); 24 | 25 | if (mkdir(prefix, mode) < 0 && errno != EEXIST) { 26 | char *ret = dupprintf("%s: mkdir: %s", 27 | prefix, strerror(errno)); 28 | sfree(prefix); 29 | return ret; 30 | } 31 | 32 | sfree(prefix); 33 | } 34 | 35 | if (!path[pos]) 36 | return NULL; 37 | pos += strspn(path + pos, "/"); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /unix/utils/make_spr_sw_abort_errno.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Constructor function for a SeatPromptResult of the 'software abort' 3 | * category, whose error message includes the translation of an OS 4 | * error code. 5 | */ 6 | 7 | #include "putty.h" 8 | 9 | static void spr_errno_errfn(SeatPromptResult spr, BinarySink *bs) 10 | { 11 | put_fmt(bs, "%s: %s", spr.errdata_lit, strerror(spr.errdata_u)); 12 | } 13 | 14 | SeatPromptResult make_spr_sw_abort_errno(const char *prefix, int errno_value) 15 | { 16 | SeatPromptResult spr; 17 | spr.kind = SPRK_SW_ABORT; 18 | spr.errfn = spr_errno_errfn; 19 | spr.errdata_lit = prefix; 20 | spr.errdata_u = errno_value; 21 | return spr; 22 | } 23 | -------------------------------------------------------------------------------- /unix/utils/nonblock.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Set and clear the O_NONBLOCK fcntl option on an open file. 3 | * 4 | * We don't realistically expect these operations to fail (the most 5 | * plausible error condition is EBADF, but we always believe ourselves 6 | * to be passing a valid fd so even that's an assertion-fail sort of 7 | * response), so we don't make any effort to return sensible error 8 | * codes to the caller - we just log to standard error and die 9 | * unceremoniously. 10 | * 11 | * Returns the previous state of O_NONBLOCK. 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | 21 | #include "putty.h" 22 | 23 | bool nonblock(int fd) 24 | { 25 | int fdflags; 26 | 27 | fdflags = fcntl(fd, F_GETFL); 28 | if (fdflags < 0) { 29 | fprintf(stderr, "%d: fcntl(F_GETFL): %s\n", fd, strerror(errno)); 30 | exit(1); 31 | } 32 | if (fcntl(fd, F_SETFL, fdflags | O_NONBLOCK) < 0) { 33 | fprintf(stderr, "%d: fcntl(F_SETFL): %s\n", fd, strerror(errno)); 34 | exit(1); 35 | } 36 | 37 | return fdflags & O_NONBLOCK; 38 | } 39 | 40 | bool no_nonblock(int fd) 41 | { 42 | int fdflags; 43 | 44 | fdflags = fcntl(fd, F_GETFL); 45 | if (fdflags < 0) { 46 | fprintf(stderr, "%d: fcntl(F_GETFL): %s\n", fd, strerror(errno)); 47 | exit(1); 48 | } 49 | if (fcntl(fd, F_SETFL, fdflags & ~O_NONBLOCK) < 0) { 50 | fprintf(stderr, "%d: fcntl(F_SETFL): %s\n", fd, strerror(errno)); 51 | exit(1); 52 | } 53 | 54 | return fdflags & O_NONBLOCK; 55 | } 56 | -------------------------------------------------------------------------------- /unix/utils/open_for_write_would_lose_data.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Unix implementation of open_for_write_would_lose_data(). 3 | */ 4 | 5 | #include 6 | #include 7 | 8 | #include "putty.h" 9 | 10 | bool open_for_write_would_lose_data(const Filename *fn) 11 | { 12 | struct stat st; 13 | 14 | if (stat(fn->path, &st) < 0) { 15 | /* 16 | * If the file doesn't even exist, we obviously want to return 17 | * false. If we failed to stat it for any other reason, 18 | * ignoring the precise error code and returning false still 19 | * doesn't seem too unreasonable, because then we'll try to 20 | * open the file for writing and report _that_ error, which is 21 | * likely to be more to the point. 22 | */ 23 | return false; 24 | } 25 | 26 | /* 27 | * OK, something exists at this pathname and we've found out 28 | * something about it. But an open-for-write will only 29 | * destructively truncate it if it's a regular file with nonzero 30 | * size. If it's empty, or some other kind of special thing like a 31 | * character device (e.g. /dev/tty) or a named pipe, then opening 32 | * it for write is already non-destructive and it's pointless and 33 | * annoying to warn about it just because the same file can be 34 | * opened for reading. (Indeed, if it's a named pipe, opening it 35 | * for reading actually _causes inconvenience_ in its own right, 36 | * even before the question of whether it gives misleading 37 | * information.) 38 | */ 39 | if (S_ISREG(st.st_mode) && st.st_size > 0) { 40 | return true; 41 | } 42 | 43 | return false; 44 | } 45 | -------------------------------------------------------------------------------- /unix/utils/pgp_fingerprints.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Display the fingerprints of the PGP Master Keys to the user. 3 | * 4 | * (This is in its own file rather than in console.c, because it's 5 | * appropriate even for Unix GUI apps.) 6 | */ 7 | 8 | #include "putty.h" 9 | 10 | void pgp_fingerprints(void) 11 | { 12 | fputs("These are the fingerprints of the PuTTY PGP Master Keys. They can\n" 13 | "be used to establish a trust path from this executable to another\n" 14 | "one. See the manual for more information.\n" 15 | "(Note: these fingerprints have nothing to do with SSH!)\n" 16 | "\n" 17 | "PuTTY Master Key as of " PGP_MASTER_KEY_YEAR 18 | " (" PGP_MASTER_KEY_DETAILS "):\n" 19 | " " PGP_MASTER_KEY_FP "\n\n" 20 | "Previous Master Key (" PGP_PREV_MASTER_KEY_YEAR 21 | ", " PGP_PREV_MASTER_KEY_DETAILS "):\n" 22 | " " PGP_PREV_MASTER_KEY_FP "\n", stdout); 23 | } 24 | -------------------------------------------------------------------------------- /unix/utils/signal.c: -------------------------------------------------------------------------------- 1 | /* 2 | * PuTTY's wrapper on signal(2). 3 | * 4 | * Calling signal() is non-portable, as it varies in meaning between 5 | * platforms and depending on feature macros, and has stupid semantics 6 | * at least some of the time. 7 | * 8 | * This function provides the same interface as the libc function, but 9 | * provides consistent semantics. It assumes POSIX semantics for 10 | * sigaction() (so you might need to do some more work if you port to 11 | * something ancient like SunOS 4). 12 | */ 13 | 14 | #include 15 | 16 | #include "defs.h" 17 | 18 | void (*putty_signal(int sig, void (*func)(int)))(int) 19 | { 20 | struct sigaction sa; 21 | struct sigaction old; 22 | 23 | sa.sa_handler = func; 24 | if (sigemptyset(&sa.sa_mask) < 0) 25 | return SIG_ERR; 26 | sa.sa_flags = SA_RESTART; 27 | if (sigaction(sig, &sa, &old) < 0) 28 | return SIG_ERR; 29 | return old.sa_handler; 30 | } 31 | -------------------------------------------------------------------------------- /unix/utils/string_width.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Return the width of a string in the font used in GTK controls. Used 3 | * as a means of picking a sensible size for dialog boxes and pieces 4 | * of them, in a way that should adapt sensibly to changes in font and 5 | * resolution. 6 | */ 7 | 8 | #include 9 | #include "putty.h" 10 | #include "gtkcompat.h" 11 | #include "gtkmisc.h" 12 | 13 | int string_width(const char *text) 14 | { 15 | int ret; 16 | get_label_text_dimensions(text, &ret, NULL); 17 | return ret; 18 | } 19 | -------------------------------------------------------------------------------- /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 | /* Defined in unix/utils */ 11 | void x11_ignore_error(Display *disp, unsigned char errcode); 12 | Display *get_x11_display(void); 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /utils/antispoof.c: -------------------------------------------------------------------------------- 1 | #include "putty.h" 2 | #include "misc.h" 3 | 4 | void seat_antispoof_msg(InteractionReadySeat iseat, const char *msg) 5 | { 6 | strbuf *sb = strbuf_new(); 7 | seat_set_trust_status(iseat.seat, true); 8 | if (seat_can_set_trust_status(iseat.seat)) { 9 | /* 10 | * If the seat can directly indicate that this message is 11 | * generated by the client, then we can just use the message 12 | * unmodified as an unspoofable header. 13 | */ 14 | put_dataz(sb, msg); 15 | } else if (*msg) { 16 | /* 17 | * Otherwise, add enough padding around it that the server 18 | * wouldn't be able to mimic it within our line-length 19 | * constraint. 20 | */ 21 | put_fmt(sb, "-- %s ", msg); 22 | while (sb->len < 78) 23 | put_byte(sb, '-'); 24 | } 25 | put_datapl(sb, PTRLEN_LITERAL("\r\n")); 26 | seat_banner_pl(iseat, ptrlen_from_strbuf(sb)); 27 | strbuf_free(sb); 28 | } 29 | -------------------------------------------------------------------------------- /utils/base64_decode.c: -------------------------------------------------------------------------------- 1 | #include "misc.h" 2 | 3 | void base64_decode_bs(BinarySink *bs, ptrlen input) 4 | { 5 | BinarySource src[1]; 6 | BinarySource_BARE_INIT_PL(src, input); 7 | 8 | while (get_avail(src)) { 9 | char b64atom[4]; 10 | unsigned char binatom[3]; 11 | 12 | for (size_t i = 0; i < 4 ;) { 13 | char c = get_byte(src); 14 | if (get_err(src)) 15 | c = '='; 16 | if (c == '\n' || c == '\r') 17 | continue; 18 | b64atom[i++] = c; 19 | } 20 | 21 | put_data(bs, binatom, base64_decode_atom(b64atom, binatom)); 22 | } 23 | } 24 | 25 | void base64_decode_fp(FILE *fp, ptrlen input) 26 | { 27 | stdio_sink ss; 28 | stdio_sink_init(&ss, fp); 29 | base64_decode_bs(BinarySink_UPCAST(&ss), input); 30 | } 31 | 32 | strbuf *base64_decode_sb(ptrlen input) 33 | { 34 | strbuf *sb = strbuf_new_nm(); 35 | base64_decode_bs(BinarySink_UPCAST(sb), input); 36 | return sb; 37 | } 38 | -------------------------------------------------------------------------------- /utils/base64_decode_atom.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Core routine to decode a single atomic base64 chunk. 3 | */ 4 | 5 | #include "defs.h" 6 | #include "misc.h" 7 | 8 | int base64_decode_atom(const char *atom, unsigned char *out) 9 | { 10 | int vals[4]; 11 | int i, v, len; 12 | unsigned word; 13 | char c; 14 | 15 | for (i = 0; i < 4; i++) { 16 | c = atom[i]; 17 | if (c >= 'A' && c <= 'Z') 18 | v = c - 'A'; 19 | else if (c >= 'a' && c <= 'z') 20 | v = c - 'a' + 26; 21 | else if (c >= '0' && c <= '9') 22 | v = c - '0' + 52; 23 | else if (c == '+') 24 | v = 62; 25 | else if (c == '/') 26 | v = 63; 27 | else if (c == '=') 28 | v = -1; 29 | else 30 | return 0; /* invalid atom */ 31 | vals[i] = v; 32 | } 33 | 34 | if (vals[0] == -1 || vals[1] == -1) 35 | return 0; 36 | if (vals[2] == -1 && vals[3] != -1) 37 | return 0; 38 | 39 | if (vals[3] != -1) 40 | len = 3; 41 | else if (vals[2] != -1) 42 | len = 2; 43 | else 44 | len = 1; 45 | 46 | word = ((vals[0] << 18) | 47 | (vals[1] << 12) | ((vals[2] & 0x3F) << 6) | (vals[3] & 0x3F)); 48 | out[0] = (word >> 16) & 0xFF; 49 | if (len > 1) 50 | out[1] = (word >> 8) & 0xFF; 51 | if (len > 2) 52 | out[2] = word & 0xFF; 53 | return len; 54 | } 55 | -------------------------------------------------------------------------------- /utils/base64_encode.c: -------------------------------------------------------------------------------- 1 | #include "misc.h" 2 | 3 | void base64_encode_bs(BinarySink *bs, ptrlen input, int cpl) 4 | { 5 | BinarySource src[1]; 6 | BinarySource_BARE_INIT_PL(src, input); 7 | int linelen = 0; 8 | 9 | while (get_avail(src)) { 10 | size_t n = get_avail(src) < 3 ? get_avail(src) : 3; 11 | ptrlen binatom = get_data(src, n); 12 | 13 | char b64atom[4]; 14 | base64_encode_atom(binatom.ptr, binatom.len, b64atom); 15 | for (size_t i = 0; i < 4; i++) { 16 | if (cpl > 0 && linelen >= cpl) { 17 | linelen = 0; 18 | put_byte(bs, '\n'); 19 | } 20 | put_byte(bs, b64atom[i]); 21 | linelen++; 22 | } 23 | } 24 | if (cpl > 0) 25 | put_byte(bs, '\n'); 26 | } 27 | 28 | void base64_encode_fp(FILE *fp, ptrlen input, int cpl) 29 | { 30 | stdio_sink ss; 31 | stdio_sink_init(&ss, fp); 32 | base64_encode_bs(BinarySink_UPCAST(&ss), input, cpl); 33 | } 34 | 35 | strbuf *base64_encode_sb(ptrlen input, int cpl) 36 | { 37 | strbuf *sb = strbuf_new_nm(); 38 | base64_encode_bs(BinarySink_UPCAST(sb), input, cpl); 39 | return sb; 40 | } 41 | -------------------------------------------------------------------------------- /utils/base64_encode_atom.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Core routine to encode a single atomic base64 chunk. 3 | */ 4 | 5 | #include "defs.h" 6 | #include "misc.h" 7 | 8 | void base64_encode_atom(const unsigned char *data, int n, char *out) 9 | { 10 | static const char base64_chars[] = 11 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 12 | 13 | unsigned word; 14 | 15 | word = data[0] << 16; 16 | if (n > 1) 17 | word |= data[1] << 8; 18 | if (n > 2) 19 | word |= data[2]; 20 | out[0] = base64_chars[(word >> 18) & 0x3F]; 21 | out[1] = base64_chars[(word >> 12) & 0x3F]; 22 | if (n > 1) 23 | out[2] = base64_chars[(word >> 6) & 0x3F]; 24 | else 25 | out[2] = '='; 26 | if (n > 2) 27 | out[3] = base64_chars[word & 0x3F]; 28 | else 29 | out[3] = '='; 30 | } 31 | -------------------------------------------------------------------------------- /utils/base64_valid.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Determine whether a string looks like valid base64-encoded data. 3 | */ 4 | 5 | #include "misc.h" 6 | 7 | static inline bool valid_char_main(char c) 8 | { 9 | return ((c >= 'A' && c <= 'Z') || 10 | (c >= 'a' && c <= 'z') || 11 | (c >= '0' && c <= '9') || 12 | c == '+' || c == '/'); 13 | } 14 | 15 | bool base64_valid(ptrlen data) 16 | { 17 | size_t blocklen = 0, nequals = 0; 18 | 19 | for (size_t i = 0; i < data.len; i++) { 20 | char c = ((const char *)data.ptr)[i]; 21 | 22 | if (c == '\n' || c == '\r') 23 | continue; 24 | 25 | if (valid_char_main(c)) { 26 | if (nequals) /* can't go back to data after = */ 27 | return false; 28 | blocklen++; 29 | if (blocklen == 4) 30 | blocklen = 0; 31 | continue; 32 | } 33 | 34 | if (c == '=') { 35 | if (blocklen == 0 && nequals) /* started a fresh block */ 36 | return false; 37 | 38 | nequals++; 39 | blocklen++; 40 | if (blocklen == 4) { 41 | if (nequals > 2) 42 | return false; /* nonsensical final block */ 43 | blocklen = 0; 44 | } 45 | continue; 46 | } 47 | 48 | return false; /* bad character */ 49 | } 50 | 51 | if (blocklen == 0 || blocklen == 2 || blocklen == 3) 52 | return true; /* permit eliding the trailing = */ 53 | return false; 54 | } 55 | -------------------------------------------------------------------------------- /utils/burnstr.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 'Burn' a dynamically allocated string, in the sense of destroying 3 | * it beyond recovery: overwrite it with zeroes and then free it. 4 | */ 5 | 6 | #include "defs.h" 7 | #include "misc.h" 8 | 9 | void burnstr(char *string) 10 | { 11 | if (string) { 12 | smemclr(string, strlen(string)); 13 | sfree(string); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /utils/burnwcs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 'Burn' a dynamically allocated wide string, in the sense of 3 | * destroying it beyond recovery: overwrite it with zeroes and then 4 | * free it. 5 | */ 6 | 7 | #include 8 | 9 | #include "defs.h" 10 | #include "misc.h" 11 | 12 | void burnwcs(wchar_t *string) 13 | { 14 | if (string) { 15 | smemclr(string, sizeof(*string) * wcslen(string)); 16 | sfree(string); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /utils/chomp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Perl-style 'chomp', for a line we just read with fgetline. 3 | * 4 | * Unlike Perl chomp, however, we're deliberately forgiving of strange 5 | * line-ending conventions. 6 | * 7 | * Also we forgive NULL on input, so you can just write 'line = 8 | * chomp(fgetline(fp));' and not bother checking for NULL until 9 | * afterwards. 10 | */ 11 | 12 | #include 13 | 14 | #include "defs.h" 15 | #include "misc.h" 16 | 17 | char *chomp(char *str) 18 | { 19 | if (str) { 20 | int len = strlen(str); 21 | while (len > 0 && (str[len-1] == '\r' || str[len-1] == '\n')) 22 | len--; 23 | str[len] = '\0'; 24 | } 25 | return str; 26 | } 27 | -------------------------------------------------------------------------------- /utils/cmdline_get_passwd_input_state_new.c: -------------------------------------------------------------------------------- 1 | /* 2 | * A preinitialised cmdline_get_passwd_input_state which makes it easy 3 | * to assign by structure copy. 4 | */ 5 | 6 | #include "putty.h" 7 | 8 | const cmdline_get_passwd_input_state cmdline_get_passwd_input_state_new = 9 | CMDLINE_GET_PASSWD_INPUT_STATE_INIT; 10 | -------------------------------------------------------------------------------- /utils/conf_dest.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Decide whether the 'host name' or 'serial line' field of a Conf is 3 | * important, based on which protocol it has selected. 4 | */ 5 | 6 | #include "putty.h" 7 | 8 | char const *conf_dest(Conf *conf) 9 | { 10 | if (conf_get_int(conf, CONF_protocol) == PROT_SERIAL) 11 | return conf_get_str(conf, CONF_serline); 12 | else 13 | return conf_get_str(conf, CONF_host); 14 | } 15 | 16 | -------------------------------------------------------------------------------- /utils/conf_launchable.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Determine whether or not a Conf represents a session which can 3 | * sensibly be launched right now. 4 | */ 5 | 6 | #include "putty.h" 7 | 8 | bool conf_launchable(Conf *conf) 9 | { 10 | if (conf_get_int(conf, CONF_protocol) == PROT_SERIAL) 11 | return conf_get_str(conf, CONF_serline)[0] != 0; 12 | else 13 | return conf_get_str(conf, CONF_host)[0] != 0; 14 | } 15 | -------------------------------------------------------------------------------- /utils/ctrlparse.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Parse a ^C style character specification. 3 | * Returns NULL in `next' if we didn't recognise it as a control character, 4 | * in which case `c' should be ignored. 5 | * The precise current parsing is an oddity inherited from the terminal 6 | * answerback-string parsing code. All sequences start with ^; all except 7 | * ^<123> are two characters. The ones that are worth keeping are probably: 8 | * ^? 127 9 | * ^@A-Z[\]^_ 0-31 10 | * a-z 1-26 11 | * specified by number (decimal, 0octal, 0xHEX) 12 | * ~ ^ escape 13 | */ 14 | 15 | #include 16 | 17 | #include "defs.h" 18 | #include "misc.h" 19 | 20 | char ctrlparse(char *s, char **next) 21 | { 22 | char c = 0; 23 | if (*s != '^') { 24 | *next = NULL; 25 | } else { 26 | s++; 27 | if (*s == '\0') { 28 | *next = NULL; 29 | } else if (*s == '<') { 30 | s++; 31 | c = (char)strtol(s, next, 0); 32 | if ((*next == s) || (**next != '>')) { 33 | c = 0; 34 | *next = NULL; 35 | } else 36 | (*next)++; 37 | } else if (*s >= 'a' && *s <= 'z') { 38 | c = (*s - ('a' - 1)); 39 | *next = s+1; 40 | } else if ((*s >= '@' && *s <= '_') || *s == '?' || (*s & 0x80)) { 41 | c = ('@' ^ *s); 42 | *next = s+1; 43 | } else if (*s == '~') { 44 | c = '^'; 45 | *next = s+1; 46 | } 47 | } 48 | return c; 49 | } 50 | -------------------------------------------------------------------------------- /utils/debug.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Debugging routines used by the debug() macros, at least if you 3 | * compiled with -DDEBUG (aka the PUTTY_DEBUG cmake option) so that 4 | * those macros don't optimise down to nothing. 5 | */ 6 | 7 | #include "defs.h" 8 | #include "misc.h" 9 | #include "utils/utils.h" 10 | 11 | void debug_printf(const char *fmt, ...) 12 | { 13 | char *buf; 14 | va_list ap; 15 | 16 | va_start(ap, fmt); 17 | buf = dupvprintf(fmt, ap); 18 | dputs(buf); 19 | sfree(buf); 20 | va_end(ap); 21 | } 22 | 23 | void debug_memdump(const void *buf, int len, bool L) 24 | { 25 | int i; 26 | const unsigned char *p = buf; 27 | char foo[17]; 28 | if (L) { 29 | int delta; 30 | debug_printf("\t%d (0x%x) bytes:\n", len, len); 31 | delta = 15 & (uintptr_t)p; 32 | p -= delta; 33 | len += delta; 34 | } 35 | for (; 0 < len; p += 16, len -= 16) { 36 | dputs(" "); 37 | if (L) 38 | debug_printf("%p: ", p); 39 | strcpy(foo, "................"); /* sixteen dots */ 40 | for (i = 0; i < 16 && i < len; ++i) { 41 | if (&p[i] < (unsigned char *) buf) { 42 | dputs(" "); /* 3 spaces */ 43 | foo[i] = ' '; 44 | } else { 45 | debug_printf("%c%2.2x", 46 | &p[i] != (unsigned char *) buf 47 | && i % 4 ? '.' : ' ', p[i] 48 | ); 49 | if (p[i] >= ' ' && p[i] <= '~') 50 | foo[i] = (char) p[i]; 51 | } 52 | } 53 | foo[i] = '\0'; 54 | debug_printf("%*s%s\n", (16 - i) * 3 + 2, "", foo); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /utils/decode_utf8_to_wchar.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Decode a single UTF-8 character to the platform's local wchar_t. 3 | */ 4 | 5 | #include "putty.h" 6 | #include "misc.h" 7 | 8 | size_t decode_utf8_to_wchar(BinarySource *src, wchar_t *out, 9 | DecodeUTF8Failure *err) 10 | { 11 | size_t outlen = 0; 12 | unsigned wc = decode_utf8(src, err); 13 | if (sizeof(wchar_t) > 2 || wc < 0x10000) { 14 | out[outlen++] = wc; 15 | } else { 16 | unsigned wcoff = wc - 0x10000; 17 | out[outlen++] = 0xD800 | (0x3FF & (wcoff >> 10)); 18 | out[outlen++] = 0xDC00 | (0x3FF & wcoff); 19 | } 20 | return outlen; 21 | } 22 | -------------------------------------------------------------------------------- /utils/decode_utf8_to_wide_string.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Decode a string of UTF-8 to a wchar_t string. 3 | */ 4 | 5 | #include "misc.h" 6 | 7 | wchar_t *decode_utf8_to_wide_string(const char *s) 8 | { 9 | wchar_t *ws = NULL; 10 | size_t wlen = 0, wsize = 0; 11 | 12 | BinarySource src[1]; 13 | BinarySource_BARE_INIT_PL(src, ptrlen_from_asciz(s)); 14 | 15 | while (get_avail(src) > 0) { 16 | /* 17 | * decode_utf8_to_wchar might emit up to 2 wchar_t if wchar_t 18 | * is 16 bits (because of UTF-16 surrogates), but will emit at 19 | * most one if wchar_t is 32-bit 20 | */ 21 | sgrowarrayn(ws, wsize, wlen, 1 + (sizeof(wchar_t) < 4)); 22 | 23 | /* We ignore 'err': if it is set, then the character decode 24 | * function will have emitted U+FFFD REPLACEMENT CHARACTER, 25 | * which is what we'd have done in response anyway. */ 26 | DecodeUTF8Failure err; 27 | wlen += decode_utf8_to_wchar(src, ws + wlen, &err); 28 | } 29 | 30 | /* Reallocate to the final size and append the trailing NUL */ 31 | ws = sresize(ws, wlen + 1, wchar_t); 32 | ws[wlen] = L'\0'; 33 | 34 | return ws; 35 | } 36 | -------------------------------------------------------------------------------- /utils/default_description.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Construct a description string for a backend to use as 3 | * backend_description(), or a plug as plug_description(). 4 | * 5 | * For some backends this will be overridden: e.g. SSH prefers to 6 | * think in terms of _logical_ host names (i.e. the one associated 7 | * with the host key) rather than the physical details of where you're 8 | * connecting to. But this default is good for simpler backends. 9 | */ 10 | 11 | #include "putty.h" 12 | 13 | char *default_description(const BackendVtable *backvt, 14 | const char *host, int port) 15 | { 16 | const char *be_name = backvt->displayname_lc; 17 | 18 | if (backvt->default_port && port == backvt->default_port) 19 | return dupprintf("%s connection to %s", be_name, host); 20 | else 21 | return dupprintf("%s connection to %s port %d", be_name, host, port); 22 | } 23 | -------------------------------------------------------------------------------- /utils/dup_mb_to_wc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * dup_mb_to_wc: memory-allocating wrapper on mb_to_wc. 3 | * 4 | * Also dup_mb_to_wc_c: same but you already know the length of the 5 | * string, and you get told the length of the returned wide string. 6 | * (But it's still NUL-terminated, for convenience.) 7 | */ 8 | 9 | #include "putty.h" 10 | #include "misc.h" 11 | 12 | wchar_t *dup_mb_to_wc_c(int codepage, int flags, const char *string, 13 | size_t inlen, size_t *outlen_p) 14 | { 15 | assert(inlen <= INT_MAX); 16 | size_t mult; 17 | for (mult = 1 ;; mult++) { 18 | wchar_t *ret = snewn(mult*inlen + 2, wchar_t); 19 | size_t outlen = mb_to_wc(codepage, flags, string, inlen, ret, 20 | mult*inlen + 1); 21 | if (outlen < mult*inlen+1) { 22 | if (outlen_p) 23 | *outlen_p = outlen; 24 | ret[outlen] = L'\0'; 25 | return ret; 26 | } 27 | sfree(ret); 28 | } 29 | } 30 | 31 | wchar_t *dup_mb_to_wc(int codepage, int flags, const char *string) 32 | { 33 | return dup_mb_to_wc_c(codepage, flags, string, strlen(string), NULL); 34 | } 35 | -------------------------------------------------------------------------------- /utils/dup_wc_to_mb.c: -------------------------------------------------------------------------------- 1 | /* 2 | * dup_wc_to_mb: memory-allocating wrapper on wc_to_mb. 3 | * 4 | * Also dup_wc_to_mb_c: same but you already know the length of the 5 | * wide string, and you get told the length of the returned string. 6 | * (But it's still NUL-terminated, for convenience.). 7 | */ 8 | 9 | #include 10 | 11 | #include "putty.h" 12 | #include "misc.h" 13 | 14 | char *dup_wc_to_mb_c(int codepage, int flags, const wchar_t *string, 15 | size_t inlen, const char *defchr, size_t *outlen_p) 16 | { 17 | assert(inlen <= INT_MAX); 18 | 19 | size_t outsize = inlen+1; 20 | char *out = snewn(outsize, char); 21 | 22 | while (true) { 23 | size_t outlen = wc_to_mb(codepage, flags, string, inlen, out, outsize, 24 | defchr); 25 | /* We can only be sure we've consumed the whole input if the 26 | * output is not within a multibyte-character-length of the 27 | * end of the buffer! */ 28 | if (outlen < outsize && outsize - outlen > MB_LEN_MAX) { 29 | if (outlen_p) 30 | *outlen_p = outlen; 31 | out[outlen] = '\0'; 32 | return out; 33 | } 34 | 35 | sgrowarray(out, outsize, outsize); 36 | } 37 | } 38 | 39 | char *dup_wc_to_mb(int codepage, int flags, const wchar_t *string, 40 | const char *defchr) 41 | { 42 | return dup_wc_to_mb_c(codepage, flags, string, wcslen(string), 43 | defchr, NULL); 44 | } 45 | -------------------------------------------------------------------------------- /utils/dupcat.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Implementation function behind dupcat() in misc.h. 3 | * 4 | * This function is called with an arbitrary number of 'const char *' 5 | * parameters, of which the last one is a null pointer. The wrapper 6 | * macro puts on the null pointer itself, so normally callers don't 7 | * have to. 8 | */ 9 | 10 | #include 11 | #include 12 | 13 | #include "defs.h" 14 | #include "misc.h" 15 | 16 | char *dupcat_fn(const char *s1, ...) 17 | { 18 | int len; 19 | char *p, *q, *sn; 20 | va_list ap; 21 | 22 | len = strlen(s1); 23 | va_start(ap, s1); 24 | while (1) { 25 | sn = va_arg(ap, char *); 26 | if (!sn) 27 | break; 28 | len += strlen(sn); 29 | } 30 | va_end(ap); 31 | 32 | p = snewn(len + 1, char); 33 | strcpy(p, s1); 34 | q = p + strlen(p); 35 | 36 | va_start(ap, s1); 37 | while (1) { 38 | sn = va_arg(ap, char *); 39 | if (!sn) 40 | break; 41 | strcpy(q, sn); 42 | q += strlen(q); 43 | } 44 | va_end(ap); 45 | 46 | return p; 47 | } 48 | 49 | -------------------------------------------------------------------------------- /utils/dupstr.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Allocate a duplicate of an ordinary C NUL-terminated string. 3 | */ 4 | 5 | #include 6 | 7 | #include "defs.h" 8 | #include "misc.h" 9 | 10 | char *dupstr(const char *s) 11 | { 12 | char *p = NULL; 13 | if (s) { 14 | int len = strlen(s); 15 | p = snewn(len + 1, char); 16 | strcpy(p, s); 17 | } 18 | return p; 19 | } 20 | -------------------------------------------------------------------------------- /utils/dupwcs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Allocate a duplicate of a NUL-terminated wchar_t string. 3 | */ 4 | 5 | #include 6 | 7 | #include "defs.h" 8 | #include "misc.h" 9 | 10 | wchar_t *dupwcs(const wchar_t *s) 11 | { 12 | wchar_t *p = NULL; 13 | if (s) { 14 | int len = wcslen(s); 15 | p = snewn(len + 1, wchar_t); 16 | wcscpy(p, s); 17 | } 18 | return p; 19 | } 20 | -------------------------------------------------------------------------------- /utils/encode_utf8.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Encode a single code point as UTF-8. 3 | */ 4 | 5 | #include "defs.h" 6 | #include "misc.h" 7 | 8 | void BinarySink_put_utf8_char(BinarySink *output, unsigned ch) 9 | { 10 | if (ch < 0x80) { 11 | put_byte(output, ch); 12 | } else if (ch < 0x800) { 13 | put_byte(output, 0xC0 | (ch >> 6)); 14 | put_byte(output, 0x80 | (ch & 0x3F)); 15 | } else if (ch < 0x10000) { 16 | put_byte(output, 0xE0 | (ch >> 12)); 17 | put_byte(output, 0x80 | ((ch >> 6) & 0x3F)); 18 | put_byte(output, 0x80 | (ch & 0x3F)); 19 | } else { 20 | assert(ch <= 0x10FFFF); 21 | put_byte(output, 0xF0 | (ch >> 18)); 22 | put_byte(output, 0x80 | ((ch >> 12) & 0x3F)); 23 | put_byte(output, 0x80 | ((ch >> 6) & 0x3F)); 24 | put_byte(output, 0x80 | (ch & 0x3F)); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /utils/encode_wide_string_as_utf8.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Encode a string of wchar_t as UTF-8. 3 | */ 4 | 5 | #include "putty.h" 6 | #include "misc.h" 7 | 8 | char *encode_wide_string_as_utf8(const wchar_t *ws) 9 | { 10 | strbuf *sb = strbuf_new(); 11 | while (*ws) { 12 | unsigned long ch = *ws++; 13 | if (sizeof(wchar_t) == 2 && IS_HIGH_SURROGATE(ch) && 14 | IS_LOW_SURROGATE(*ws)) { 15 | ch = FROM_SURROGATES(ch, *ws); 16 | ws++; 17 | } else if (IS_SURROGATE(ch)) { 18 | ch = 0xfffd; /* illegal UTF-16 -> REPLACEMENT CHARACTER */ 19 | } 20 | put_utf8_char(sb, ch); 21 | } 22 | return strbuf_to_str(sb); 23 | } 24 | -------------------------------------------------------------------------------- /utils/fgetline.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Read an entire line of text from a file. Return a buffer 3 | * malloced to be as big as necessary (caller must free). 4 | */ 5 | 6 | #include "defs.h" 7 | #include "misc.h" 8 | 9 | char *fgetline(FILE *fp) 10 | { 11 | char *ret = snewn(512, char); 12 | size_t size = 512, len = 0; 13 | while (fgets(ret + len, size - len, fp)) { 14 | len += strlen(ret + len); 15 | if (len > 0 && ret[len-1] == '\n') 16 | break; /* got a newline, we're done */ 17 | sgrowarrayn_nm(ret, size, len, 512); 18 | } 19 | if (len == 0) { /* first fgets returned NULL */ 20 | sfree(ret); 21 | return NULL; 22 | } 23 | ret[len] = '\0'; 24 | return ret; 25 | } 26 | -------------------------------------------------------------------------------- /utils/host_ca_new_free.c: -------------------------------------------------------------------------------- 1 | #include "defs.h" 2 | #include "misc.h" 3 | #include "storage.h" 4 | 5 | host_ca *host_ca_new(void) 6 | { 7 | host_ca *hca = snew(host_ca); 8 | memset(hca, 0, sizeof(*hca)); 9 | hca->opts.permit_rsa_sha1 = false; 10 | hca->opts.permit_rsa_sha256 = true; 11 | hca->opts.permit_rsa_sha512 = true; 12 | return hca; 13 | } 14 | 15 | void host_ca_free(host_ca *hca) 16 | { 17 | sfree(hca->name); 18 | sfree(hca->validity_expression); 19 | if (hca->ca_public_key) 20 | strbuf_free(hca->ca_public_key); 21 | sfree(hca); 22 | } 23 | -------------------------------------------------------------------------------- /utils/host_strchr.c: -------------------------------------------------------------------------------- 1 | /* 2 | * strchr-like wrapper around host_strchr_internal. 3 | */ 4 | 5 | #include 6 | #include 7 | 8 | #include "defs.h" 9 | #include "misc.h" 10 | #include "utils/utils.h" 11 | 12 | char *host_strchr(const char *s, int c) 13 | { 14 | char set[2]; 15 | set[0] = c; 16 | set[1] = '\0'; 17 | return (char *) host_strchr_internal(s, set, true); 18 | } 19 | -------------------------------------------------------------------------------- /utils/host_strcspn.c: -------------------------------------------------------------------------------- 1 | /* 2 | * strcspn-like wrapper around host_strchr_internal. 3 | */ 4 | 5 | #include 6 | #include 7 | 8 | #include "defs.h" 9 | #include "misc.h" 10 | #include "utils/utils.h" 11 | 12 | size_t host_strcspn(const char *s, const char *set) 13 | { 14 | const char *answer = host_strchr_internal(s, set, true); 15 | if (answer) 16 | return answer - s; 17 | else 18 | return strlen(s); 19 | } 20 | -------------------------------------------------------------------------------- /utils/host_strduptrim.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Trim square brackets off the outside of an IPv6 address literal. 3 | * Leave all other strings unchanged. Returns a fresh dynamically 4 | * allocated string. 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #include "defs.h" 11 | #include "misc.h" 12 | 13 | char *host_strduptrim(const char *s) 14 | { 15 | if (s[0] == '[') { 16 | const char *p = s+1; 17 | int colons = 0; 18 | while (*p && *p != ']') { 19 | if (isxdigit((unsigned char)*p)) 20 | /* OK */; 21 | else if (*p == ':') 22 | colons++; 23 | else 24 | break; 25 | p++; 26 | } 27 | if (*p == '%') { 28 | /* 29 | * This delimiter character introduces an RFC 4007 scope 30 | * id suffix (e.g. suffixing the address literal with 31 | * %eth1 or %2 or some such). There's no syntax 32 | * specification for the scope id, so just accept anything 33 | * except the closing ]. 34 | */ 35 | p += strcspn(p, "]"); 36 | } 37 | if (*p == ']' && !p[1] && colons > 1) { 38 | /* 39 | * This looks like an IPv6 address literal (hex digits and 40 | * at least two colons, plus optional scope id, contained 41 | * in square brackets). Trim off the brackets. 42 | */ 43 | return dupprintf("%.*s", (int)(p - (s+1)), s+1); 44 | } 45 | } 46 | 47 | /* 48 | * Any other shape of string is simply duplicated. 49 | */ 50 | return dupstr(s); 51 | } 52 | -------------------------------------------------------------------------------- /utils/host_strrchr.c: -------------------------------------------------------------------------------- 1 | /* 2 | * strchr-like wrapper around host_strchr_internal. 3 | */ 4 | 5 | #include 6 | #include 7 | 8 | #include "defs.h" 9 | #include "misc.h" 10 | #include "utils/utils.h" 11 | 12 | char *host_strrchr(const char *s, int c) 13 | { 14 | char set[2]; 15 | set[0] = c; 16 | set[1] = '\0'; 17 | return (char *) host_strchr_internal(s, set, false); 18 | } 19 | -------------------------------------------------------------------------------- /utils/logeventf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Helpful wrapper functions around the raw logevent(). 3 | * 4 | * This source file lives in 'utils' because it's conceptually a 5 | * convenience utility rather than core functionality. But it can't 6 | * live in the utils _library_, because then it might refer to 7 | * logevent() in an earlier library after Unix ld had already finished 8 | * searching that library, and cause a link failure. So it must live 9 | * alongside logging.c. 10 | */ 11 | 12 | #include "putty.h" 13 | 14 | void logevent_and_free(LogContext *ctx, char *event) 15 | { 16 | logevent(ctx, event); 17 | sfree(event); 18 | } 19 | 20 | void logeventvf(LogContext *ctx, const char *fmt, va_list ap) 21 | { 22 | logevent_and_free(ctx, dupvprintf(fmt, ap)); 23 | } 24 | 25 | void logeventf(LogContext *ctx, const char *fmt, ...) 26 | { 27 | va_list ap; 28 | 29 | va_start(ap, fmt); 30 | logeventvf(ctx, fmt, ap); 31 | va_end(ap); 32 | } 33 | -------------------------------------------------------------------------------- /utils/ltime.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 | -------------------------------------------------------------------------------- /utils/make_spr_sw_abort_static.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Constructor function for a SeatPromptResult of the 'software abort' 3 | * category, whose error message is in the simplest possible form of a 4 | * static string constant. 5 | */ 6 | 7 | #include "putty.h" 8 | 9 | static void spr_static_errfn(SeatPromptResult spr, BinarySink *bs) 10 | { 11 | put_dataz(bs, spr.errdata_lit); 12 | } 13 | 14 | SeatPromptResult make_spr_sw_abort_static(const char *str) 15 | { 16 | SeatPromptResult spr; 17 | spr.kind = SPRK_SW_ABORT; 18 | spr.errfn = spr_static_errfn; 19 | spr.errdata_lit = str; 20 | return spr; 21 | } 22 | -------------------------------------------------------------------------------- /utils/memxor.c: -------------------------------------------------------------------------------- 1 | /* 2 | * XOR two pieces of memory, copying the result into a third, which 3 | * may precisely alias one of the input pair (but no guarantees if it 4 | * partially overlaps). 5 | */ 6 | 7 | #include "defs.h" 8 | #include "misc.h" 9 | 10 | void memxor(uint8_t *out, const uint8_t *in1, const uint8_t *in2, size_t size) 11 | { 12 | switch (size & 15) { 13 | case 0: 14 | while (size >= 16) { 15 | size -= 16; 16 | *out++ = *in1++ ^ *in2++; 17 | case 15: *out++ = *in1++ ^ *in2++; 18 | case 14: *out++ = *in1++ ^ *in2++; 19 | case 13: *out++ = *in1++ ^ *in2++; 20 | case 12: *out++ = *in1++ ^ *in2++; 21 | case 11: *out++ = *in1++ ^ *in2++; 22 | case 10: *out++ = *in1++ ^ *in2++; 23 | case 9: *out++ = *in1++ ^ *in2++; 24 | case 8: *out++ = *in1++ ^ *in2++; 25 | case 7: *out++ = *in1++ ^ *in2++; 26 | case 6: *out++ = *in1++ ^ *in2++; 27 | case 5: *out++ = *in1++ ^ *in2++; 28 | case 4: *out++ = *in1++ ^ *in2++; 29 | case 3: *out++ = *in1++ ^ *in2++; 30 | case 2: *out++ = *in1++ ^ *in2++; 31 | case 1: *out++ = *in1++ ^ *in2++; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /utils/nullstrcmp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Compare two strings, just like strcmp, except that we tolerate null 3 | * pointers as a legal input, and define them to compare before any 4 | * non-null string (even the empty string). 5 | */ 6 | 7 | #include 8 | 9 | #include "defs.h" 10 | #include "misc.h" 11 | 12 | int nullstrcmp(const char *a, const char *b) 13 | { 14 | if (a == NULL && b == NULL) 15 | return 0; 16 | if (a == NULL) 17 | return -1; 18 | if (b == NULL) 19 | return +1; 20 | return strcmp(a, b); 21 | } 22 | -------------------------------------------------------------------------------- /utils/out_of_memory.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Standard implementation of the out_of_memory function called by our 3 | * malloc wrappers. 4 | */ 5 | 6 | #include "putty.h" 7 | 8 | void out_of_memory(void) 9 | { 10 | modalfatalbox("Out of memory"); 11 | } 12 | -------------------------------------------------------------------------------- /utils/parse_blocksize.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Parse a string block size specification. This is approximately a 3 | * subset of the block size specs supported by GNU fileutils: 4 | * "nk" = n kilobytes 5 | * "nM" = n megabytes 6 | * "nG" = n gigabytes 7 | * All numbers are decimal, and suffixes refer to powers of two. 8 | * Case-insensitive. 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include "defs.h" 16 | #include "misc.h" 17 | 18 | unsigned long parse_blocksize(const char *bs) 19 | { 20 | char *suf; 21 | unsigned long r = strtoul(bs, &suf, 10); 22 | if (*suf != '\0') { 23 | while (*suf && isspace((unsigned char)*suf)) suf++; 24 | switch (*suf) { 25 | case 'k': case 'K': 26 | r *= 1024ul; 27 | break; 28 | case 'm': case 'M': 29 | r *= 1024ul * 1024ul; 30 | break; 31 | case 'g': case 'G': 32 | r *= 1024ul * 1024ul * 1024ul; 33 | break; 34 | case '\0': 35 | default: 36 | break; 37 | } 38 | } 39 | return r; 40 | } 41 | -------------------------------------------------------------------------------- /utils/percent_decode.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Decode %-encoding in URL style. 3 | */ 4 | 5 | #include 6 | 7 | #include "misc.h" 8 | 9 | void percent_decode_bs(BinarySink *bs, ptrlen data) 10 | { 11 | for (const char *p = data.ptr, *e = ptrlen_end(data); p < e; p++) { 12 | char c = *p; 13 | if (c == '%' && e-p >= 3 && 14 | isxdigit((unsigned char)p[1]) && 15 | isxdigit((unsigned char)p[2])) { 16 | char hex[3]; 17 | hex[0] = p[1]; 18 | hex[1] = p[2]; 19 | hex[2] = '\0'; 20 | put_byte(bs, strtoul(hex, NULL, 16)); 21 | p += 2; 22 | } else { 23 | put_byte(bs, c); 24 | } 25 | } 26 | 27 | } 28 | 29 | void percent_decode_fp(FILE *fp, ptrlen data) 30 | { 31 | stdio_sink ss; 32 | stdio_sink_init(&ss, fp); 33 | percent_decode_bs(BinarySink_UPCAST(&ss), data); 34 | } 35 | 36 | strbuf *percent_decode_sb(ptrlen data) 37 | { 38 | strbuf *sb = strbuf_new(); 39 | percent_decode_bs(BinarySink_UPCAST(sb), data); 40 | return sb; 41 | } 42 | -------------------------------------------------------------------------------- /utils/percent_encode.c: -------------------------------------------------------------------------------- 1 | /* 2 | * %-encoding in URL style. 3 | * 4 | * Defaults to escaping % itself (necessary for decoding to even 5 | * work), and any C0 escape character. Further bad characters can be 6 | * provided in 'badchars'. 7 | */ 8 | 9 | #include "misc.h" 10 | 11 | void percent_encode_bs(BinarySink *bs, ptrlen data, const char *badchars) 12 | { 13 | for (const char *p = data.ptr, *e = ptrlen_end(data); p < e; p++) { 14 | char c = *p; 15 | if (c == '%' || c < ' ' || (badchars && strchr(badchars, c))) 16 | put_fmt(bs, "%%%02X", (unsigned char)c); 17 | else 18 | put_byte(bs, c); 19 | } 20 | } 21 | 22 | void percent_encode_fp(FILE *fp, ptrlen data, const char *badchars) 23 | { 24 | stdio_sink ss; 25 | stdio_sink_init(&ss, fp); 26 | percent_encode_bs(BinarySink_UPCAST(&ss), data, badchars); 27 | } 28 | 29 | strbuf *percent_encode_sb(ptrlen data, const char *badchars) 30 | { 31 | strbuf *sb = strbuf_new(); 32 | percent_encode_bs(BinarySink_UPCAST(sb), data, badchars); 33 | return sb; 34 | } 35 | -------------------------------------------------------------------------------- /utils/read_file_into.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Read an entire file into a BinarySink. 3 | */ 4 | 5 | #include 6 | 7 | #include "defs.h" 8 | #include "misc.h" 9 | 10 | bool read_file_into(BinarySink *bs, FILE *fp) 11 | { 12 | char buf[4096]; 13 | while (1) { 14 | size_t retd = fread(buf, 1, sizeof(buf), fp); 15 | if (retd == 0) 16 | return !ferror(fp); 17 | put_data(bs, buf, retd); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /utils/seat_connection_fatal.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Wrapper function for the connection_fatal() method of a Seat, 3 | * providing printf-style formatting. 4 | */ 5 | 6 | #include "putty.h" 7 | 8 | void seat_connection_fatal(Seat *seat, const char *fmt, ...) 9 | { 10 | va_list ap; 11 | char *msg; 12 | 13 | va_start(ap, fmt); 14 | msg = dupvprintf(fmt, ap); 15 | va_end(ap); 16 | 17 | seat->vt->connection_fatal(seat, msg); 18 | sfree(msg); /* if we return */ 19 | } 20 | 21 | -------------------------------------------------------------------------------- /utils/seat_dialog_text.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Helper routines for dealing with SeatDialogText structures. 3 | */ 4 | 5 | #include 6 | 7 | #include "putty.h" 8 | 9 | SeatDialogText *seat_dialog_text_new(void) 10 | { 11 | SeatDialogText *sdt = snew(SeatDialogText); 12 | sdt->nitems = sdt->itemsize = 0; 13 | sdt->items = NULL; 14 | return sdt; 15 | } 16 | 17 | void seat_dialog_text_free(SeatDialogText *sdt) 18 | { 19 | for (size_t i = 0; i < sdt->nitems; i++) 20 | sfree(sdt->items[i].text); 21 | sfree(sdt->items); 22 | sfree(sdt); 23 | } 24 | 25 | static void seat_dialog_text_append_v( 26 | SeatDialogText *sdt, SeatDialogTextType type, const char *fmt, va_list ap) 27 | { 28 | sgrowarray(sdt->items, sdt->itemsize, sdt->nitems); 29 | SeatDialogTextItem *item = &sdt->items[sdt->nitems++]; 30 | item->type = type; 31 | item->text = dupvprintf(fmt, ap); 32 | } 33 | 34 | void seat_dialog_text_append(SeatDialogText *sdt, SeatDialogTextType type, 35 | const char *fmt, ...) 36 | { 37 | va_list ap; 38 | va_start(ap, fmt); 39 | seat_dialog_text_append_v(sdt, type, fmt, ap); 40 | va_end(ap); 41 | } 42 | -------------------------------------------------------------------------------- /utils/seat_nonfatal.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Wrapper function for the nonfatal() method of a Seat, 3 | * providing printf-style formatting. 4 | */ 5 | 6 | #include "putty.h" 7 | 8 | void seat_nonfatal(Seat *seat, const char *fmt, ...) 9 | { 10 | va_list ap; 11 | char *msg; 12 | 13 | va_start(ap, fmt); 14 | msg = dupvprintf(fmt, ap); 15 | va_end(ap); 16 | 17 | seat->vt->nonfatal(seat, msg); 18 | sfree(msg); 19 | } 20 | -------------------------------------------------------------------------------- /utils/sk_free_peer_info.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Free a SocketPeerInfo, and everything that dangles off it. 3 | */ 4 | 5 | #include "putty.h" 6 | 7 | void sk_free_peer_info(SocketPeerInfo *pi) 8 | { 9 | if (pi) { 10 | sfree((char *)pi->addr_text); 11 | sfree((char *)pi->log_text); 12 | sfree(pi); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /utils/smemeq.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Compare two fixed-size regions of memory, in a crypto-safe way, 3 | * i.e. without timing or cache side channels indicating anything 4 | * about what the answer was or where the first difference (if any) 5 | * might have been. 6 | */ 7 | 8 | #include "defs.h" 9 | #include "misc.h" 10 | 11 | unsigned smemeq(const void *av, const void *bv, size_t len) 12 | { 13 | const unsigned char *a = (const unsigned char *)av; 14 | const unsigned char *b = (const unsigned char *)bv; 15 | unsigned val = 0; 16 | 17 | while (len-- > 0) { 18 | val |= *a++ ^ *b++; 19 | } 20 | /* Now val is 0 iff we want to return 1, and in the range 21 | * 0x01..0xFF iff we want to return 0. So subtracting from 0x100 22 | * will clear bit 8 iff we want to return 0, and leave it set iff 23 | * we want to return 1, so then we can just shift down. */ 24 | return (0x100 - val) >> 8; 25 | } 26 | -------------------------------------------------------------------------------- /utils/spr_get_error_message.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Construct the error message from a SeatPromptResult, and return it 3 | * in a dynamically allocated string. 4 | */ 5 | 6 | #include "putty.h" 7 | 8 | char *spr_get_error_message(SeatPromptResult spr) 9 | { 10 | strbuf *sb = strbuf_new(); 11 | spr.errfn(spr, BinarySink_UPCAST(sb)); 12 | return strbuf_to_str(sb); 13 | } 14 | -------------------------------------------------------------------------------- /utils/ssh2_pick_fingerprint.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Choose an SSH-2 fingerprint type, out of an array of possible ones. 3 | */ 4 | 5 | #include "defs.h" 6 | #include "misc.h" 7 | #include "ssh.h" 8 | 9 | FingerprintType ssh2_pick_fingerprint( 10 | char **fingerprints, FingerprintType preferred_type) 11 | { 12 | /* 13 | * Keys are either SSH-2, in which case we have all fingerprint 14 | * types, or SSH-1, in which case we have only MD5. So we return 15 | * the default type if we can, or MD5 if that's all we have; no 16 | * need for a fully general preference-list system. 17 | */ 18 | FingerprintType fptype = fingerprints[preferred_type] ? 19 | preferred_type : SSH_FPTYPE_MD5; 20 | assert(fingerprints[fptype]); 21 | return fptype; 22 | } 23 | 24 | FingerprintType ssh2_pick_default_fingerprint(char **fingerprints) 25 | { 26 | return ssh2_pick_fingerprint(fingerprints, SSH_FPTYPE_DEFAULT); 27 | } 28 | -------------------------------------------------------------------------------- /utils/ssh_key_clone.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Make a copy of an existing ssh_key object, e.g. to survive after 3 | * the original is freed. 4 | */ 5 | 6 | #include "misc.h" 7 | #include "ssh.h" 8 | 9 | ssh_key *ssh_key_clone(ssh_key *key) 10 | { 11 | /* 12 | * To avoid having to add a special method in the vtable API, we 13 | * clone by round-tripping through public and private blobs. 14 | */ 15 | strbuf *pub = strbuf_new_nm(); 16 | ssh_key_public_blob(key, BinarySink_UPCAST(pub)); 17 | 18 | ssh_key *copy; 19 | 20 | if (ssh_key_has_private(key)) { 21 | strbuf *priv = strbuf_new_nm(); 22 | ssh_key_private_blob(key, BinarySink_UPCAST(priv)); 23 | copy = ssh_key_new_priv(ssh_key_alg(key), ptrlen_from_strbuf(pub), 24 | ptrlen_from_strbuf(priv)); 25 | strbuf_free(priv); 26 | } else { 27 | copy = ssh_key_new_pub(ssh_key_alg(key), ptrlen_from_strbuf(pub)); 28 | } 29 | 30 | strbuf_free(pub); 31 | return copy; 32 | } 33 | -------------------------------------------------------------------------------- /utils/string_length_for_printf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Convert a size_t value to int, by saturating it at INT_MAX. Useful 3 | * if you want to use the printf idiom "%.*s", where the '*' precision 4 | * specifier expects an int in the variadic argument list, but what 5 | * you have is not an int but a size_t. This method of converting to 6 | * int will at least do something _safe_ with overlong values, even if 7 | * (due to the limitation of printf itself) the whole string still 8 | * won't be printed. 9 | */ 10 | 11 | #include 12 | 13 | #include "defs.h" 14 | #include "misc.h" 15 | 16 | int string_length_for_printf(size_t s) 17 | { 18 | if (s > INT_MAX) 19 | return INT_MAX; 20 | return s; 21 | } 22 | -------------------------------------------------------------------------------- /utils/utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Internal header to the utils subdirectory, for definitions shared 3 | * between the library implementations but not intended to be exposed 4 | * further than that. 5 | */ 6 | 7 | void dputs(const char *); 8 | 9 | char *dupvprintf_inner(char *buf, size_t oldlen, size_t *sizeptr, 10 | const char *fmt, va_list ap); 11 | 12 | const char *host_strchr_internal(const char *s, const char *set, bool first); 13 | -------------------------------------------------------------------------------- /utils/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 | #include "version.h" 15 | 16 | const char ver[] = TEXTVER; 17 | const char sshver[] = SSHVER; 18 | 19 | /* 20 | * SSH local version string MUST be under 40 characters. Here's a 21 | * compile time assertion to verify this. 22 | */ 23 | enum { vorpal_sword = 1 / (sizeof(sshver) <= 40) }; 24 | -------------------------------------------------------------------------------- /utils/wordwrap.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Function to wrap text to a fixed number of columns. 3 | * 4 | * Currently, assumes the text is in a single-byte character set, 5 | * because it's only used to display host key prompt messages. 6 | * Extending to Unicode and using wcwidth() could be an extension. 7 | */ 8 | 9 | #include "misc.h" 10 | 11 | void wordwrap(BinarySink *bs, ptrlen input, size_t maxwid) 12 | { 13 | size_t col = 0; 14 | while (true) { 15 | ptrlen word = ptrlen_get_word(&input, " "); 16 | if (!word.len) 17 | break; 18 | 19 | /* At the start of a line, any word is legal, even if it's 20 | * overlong, because we have to display it _somehow_ and 21 | * wrapping to the next line won't make it any better. */ 22 | if (col > 0) { 23 | size_t newcol = col + 1 + word.len; 24 | if (newcol <= maxwid) { 25 | put_byte(bs, ' '); 26 | col++; 27 | } else { 28 | put_byte(bs, '\n'); 29 | col = 0; 30 | } 31 | } 32 | 33 | put_datapl(bs, word); 34 | col += word.len; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /utils/write_c_string_literal.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Write data to a file or BinarySink in the form of a C string 3 | * literal, with any non-printable-ASCII character escaped 4 | * appropriately. 5 | */ 6 | 7 | #include "defs.h" 8 | #include "misc.h" 9 | 10 | void BinarySink_put_c_string_literal(BinarySink *bs, ptrlen str) 11 | { 12 | for (const char *p = str.ptr; p < (const char *)str.ptr + str.len; p++) { 13 | char c = *p; 14 | 15 | if (c == '\n') 16 | put_datalit(bs, "\\n"); 17 | else if (c == '\r') 18 | put_datalit(bs, "\\r"); 19 | else if (c == '\t') 20 | put_datalit(bs, "\\t"); 21 | else if (c == '\b') 22 | put_datalit(bs, "\\b"); 23 | else if (c == '\\') 24 | put_datalit(bs, "\\\\"); 25 | else if (c == '"') 26 | put_datalit(bs, "\\\""); 27 | else if (c >= 32 && c <= 126) 28 | put_byte(bs, c); 29 | else 30 | put_fmt(bs, "\\%03o", (unsigned)c & 0xFFU); 31 | } 32 | } 33 | 34 | void write_c_string_literal(FILE *fp, ptrlen str) 35 | { 36 | stdio_sink s; 37 | stdio_sink_init(&s, fp); 38 | put_c_string_literal(&s, str); 39 | } 40 | -------------------------------------------------------------------------------- /utils/x11_dehexify.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Utility function to convert a textual representation of an X11 3 | * auth hex cookie into binary auth data. 4 | */ 5 | 6 | #include "putty.h" 7 | #include "ssh.h" 8 | 9 | void *x11_dehexify(ptrlen hexpl, int *outlen) 10 | { 11 | int len, i; 12 | unsigned char *ret; 13 | 14 | len = hexpl.len / 2; 15 | ret = snewn(len, unsigned char); 16 | 17 | for (i = 0; i < len; i++) { 18 | char bytestr[3]; 19 | unsigned val = 0; 20 | bytestr[0] = ((const char *)hexpl.ptr)[2*i]; 21 | bytestr[1] = ((const char *)hexpl.ptr)[2*i+1]; 22 | bytestr[2] = '\0'; 23 | sscanf(bytestr, "%x", &val); 24 | ret[i] = val; 25 | } 26 | 27 | *outlen = len; 28 | return ret; 29 | } 30 | -------------------------------------------------------------------------------- /utils/x11_identify_auth_proto.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Utility function to convert a textual representation of an X11 3 | * auth protocol name into our integer protocol ids. 4 | */ 5 | 6 | #include "putty.h" 7 | #include "ssh.h" 8 | 9 | int x11_identify_auth_proto(ptrlen protoname) 10 | { 11 | int protocol; 12 | 13 | for (protocol = 1; protocol < lenof(x11_authnames); protocol++) 14 | if (ptrlen_eq_string(protoname, x11_authnames[protocol])) 15 | return protocol; 16 | return -1; 17 | } 18 | -------------------------------------------------------------------------------- /utils/x11_parse_ip.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Try to make sense of a string as an IPv4 address, for 3 | * XDM-AUTHORIZATION-1 purposes. 4 | */ 5 | 6 | #include 7 | 8 | #include "putty.h" 9 | #include "ssh.h" 10 | 11 | bool x11_parse_ip(const char *addr_string, unsigned long *ip) 12 | { 13 | int i[4]; 14 | if (addr_string && 15 | 4 == sscanf(addr_string, "%d.%d.%d.%d", i+0, i+1, i+2, i+3)) { 16 | *ip = (i[0] << 24) | (i[1] << 16) | (i[2] << 8) | i[3]; 17 | return true; 18 | } else { 19 | return false; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /utils/x11authnames.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Definition of the array of X11 authorisation method names. 3 | */ 4 | 5 | #include "putty.h" 6 | 7 | const char *const x11_authnames[X11_NAUTHS] = { 8 | "", "MIT-MAGIC-COOKIE-1", "XDM-AUTHORIZATION-1" 9 | }; 10 | -------------------------------------------------------------------------------- /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 with far2l extensions support" 12 | #define SSHVER "-Unidentified-Local-Build" 13 | #define BINARY_VERSION 0,0,0,0 14 | -------------------------------------------------------------------------------- /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/cryptoapi.h: -------------------------------------------------------------------------------- 1 | /* 2 | * cryptoapi.h: Windows Crypto API functions defined in PuTTY 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 | DECL_WINDOWS_FUNCTION(extern, BOOL, CryptProtectMemory, (LPVOID,DWORD,DWORD)); 9 | 10 | bool got_crypt(void); 11 | 12 | /* 13 | * Function to obfuscate an input string into something usable as a 14 | * pathname for a Windows named pipe. Uses CryptProtectMemory to make 15 | * the obfuscation depend on a key Windows stores for the owning user, 16 | * and then hashes the string as well to make it have a manageable 17 | * length and be composed of filename-legal characters. 18 | * 19 | * Rationale: Windows's named pipes all live in the same namespace, so 20 | * one user can see what pipes another user has open. This is an 21 | * undesirable privacy leak: in particular, if we used unobfuscated 22 | * names for the connection-sharing pipe names, it would permit one 23 | * user to know what username@host another user is SSHing to. 24 | * 25 | * The returned string is dynamically allocated. 26 | */ 27 | char *capi_obfuscate_string(const char *realname); 28 | -------------------------------------------------------------------------------- /windows/help.rc2: -------------------------------------------------------------------------------- 1 | #include "putty-rc.h" 2 | 3 | #ifdef EMBEDDED_CHM_FILE 4 | ID_CUSTOM_CHMFILE TYPE_CUSTOM_CHMFILE EMBEDDED_CHM_FILE 5 | #define HELPVER " (with embedded help)" 6 | #else 7 | #define HELPVER " (without embedded help)" 8 | #endif 9 | -------------------------------------------------------------------------------- /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/no-jump-list.c: -------------------------------------------------------------------------------- 1 | /* 2 | * no-jump-list.c: stub jump list functions for Windows executables 3 | * that don't update the jump list. 4 | */ 5 | 6 | #include "putty.h" 7 | 8 | void add_session_to_jumplist(const char * const sessionname) {} 9 | void remove_session_from_jumplist(const char * const sessionname) {} 10 | void clear_jumplist(void) {} 11 | -------------------------------------------------------------------------------- /windows/nohelp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * nohelp.c: implement the has_embedded_chm() function for 3 | * applications that have no help file at all, so that buildinfo.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/pageant-rc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Constant definitions for the Pageant resource file. 3 | */ 4 | 5 | #define IDI_MAINICON 200 6 | #define IDI_TRAYICON 201 7 | 8 | #define IDD_KEYLIST 211 9 | #define IDD_LOAD_PASSPHRASE 210 10 | #define IDD_ONDEMAND_PASSPHRASE 212 11 | #define IDD_ABOUT 213 12 | #define IDD_LICENCE 214 13 | 14 | #define IDC_PASSPHRASE_STATIC1 100 15 | #define IDC_PASSPHRASE_FINGERPRINT 101 16 | #define IDC_PASSPHRASE_STATIC2 102 17 | #define IDC_PASSPHRASE_STATIC3 103 18 | #define IDC_PASSPHRASE_EDITBOX 104 19 | 20 | #define IDC_KEYLIST_LISTBOX 100 21 | #define IDC_KEYLIST_ADDKEY 101 22 | #define IDC_KEYLIST_ADDKEY_ENC 110 23 | #define IDC_KEYLIST_REENCRYPT 106 24 | #define IDC_KEYLIST_REMOVE 102 25 | #define IDC_KEYLIST_HELP 103 26 | #define IDC_KEYLIST_FPTYPE_STATIC 104 27 | #define IDC_KEYLIST_FPTYPE 105 28 | 29 | #define IDC_ABOUT_LICENCE 101 30 | #define IDC_ABOUT_WEBSITE 102 31 | #define IDC_ABOUT_TEXTBOX 1000 32 | 33 | #define IDC_LICENCE_TEXTBOX 1000 34 | -------------------------------------------------------------------------------- /windows/pageant.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unxed/putty4far2l/1816bdba0554f9f4465b92bc0df95fb845ff4170/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/pageants.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unxed/putty4far2l/1816bdba0554f9f4465b92bc0df95fb845ff4170/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/unxed/putty4far2l/1816bdba0554f9f4465b92bc0df95fb845ff4170/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/psocks.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/pterm.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unxed/putty4far2l/1816bdba0554f9f4465b92bc0df95fb845ff4170/windows/pterm.ico -------------------------------------------------------------------------------- /windows/pterm.rc: -------------------------------------------------------------------------------- 1 | #include "rcstuff.h" 2 | #include "putty-rc.h" 3 | 4 | #define APPNAME "pterm" 5 | #define APPDESC "PuTTY-style wrapper for Windows command prompts" 6 | 7 | IDI_MAINICON ICON "pterm.ico" 8 | IDI_CFGICON ICON "ptermcfg.ico" 9 | 10 | #include "help.rc2" 11 | #include "putty-common.rc2" 12 | 13 | #ifndef NO_MANIFESTS 14 | 1 RT_MANIFEST "putty.mft" 15 | #endif /* NO_MANIFESTS */ 16 | -------------------------------------------------------------------------------- /windows/ptermcfg.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unxed/putty4far2l/1816bdba0554f9f4465b92bc0df95fb845ff4170/windows/ptermcfg.ico -------------------------------------------------------------------------------- /windows/putty-rc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * putty-rc.h - constants shared between putty-common.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 | #define IDD_HOSTKEY 114 17 | #define IDD_HK_MOREINFO 116 18 | #define IDD_CA_CONFIG 117 19 | 20 | #define IDN_LIST 1001 21 | #define IDN_COPY 1002 22 | 23 | #define IDA_ICON 1001 24 | #define IDA_TEXT 1002 25 | #define IDA_LICENCE 1003 26 | #define IDA_WEB 1004 27 | 28 | #define IDC_TAB 1001 29 | #define IDC_TABSTATIC1 1002 30 | #define IDC_TABSTATIC2 1003 31 | #define IDC_TABLIST 1004 32 | #define IDC_HELPBTN 1005 33 | #define IDC_ABOUT 1006 34 | 35 | #define IDC_HK_ICON 98 36 | #define IDC_HK_TITLE 99 37 | #define IDC_HK_TEXT 100 38 | #define IDC_HK_ACCEPT 1001 39 | #define IDC_HK_ONCE 1000 40 | #define IDC_HK_HOST 1002 41 | #define IDC_HK_FINGERPRINT 1003 42 | #define IDC_HK_MOREINFO 1004 43 | 44 | #define IDC_HKI_SHA256 1000 45 | #define IDC_HKI_MD5 1001 46 | #define IDC_HKI_PUBKEY 1002 47 | 48 | #define ID_CUSTOM_CHMFILE 2000 49 | #define TYPE_CUSTOM_CHMFILE 2000 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /windows/putty.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unxed/putty4far2l/1816bdba0554f9f4465b92bc0df95fb845ff4170/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 | 31 | PerMonitorV2 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /windows/putty.rc: -------------------------------------------------------------------------------- 1 | #include "rcstuff.h" 2 | #include "putty-rc.h" 3 | 4 | #define APPNAME "PuTTY" 5 | #define APPDESC "SSH, Telnet, Rlogin, and SUPDUP client" 6 | 7 | IDI_MAINICON ICON "putty.ico" 8 | IDI_CFGICON ICON "puttycfg.ico" 9 | 10 | #include "help.rc2" 11 | #include "putty-common.rc2" 12 | 13 | #ifndef NO_MANIFESTS 14 | 1 RT_MANIFEST "putty.mft" 15 | #endif /* NO_MANIFESTS */ 16 | -------------------------------------------------------------------------------- /windows/puttycfg.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unxed/putty4far2l/1816bdba0554f9f4465b92bc0df95fb845ff4170/windows/puttycfg.ico -------------------------------------------------------------------------------- /windows/puttygen-rc.h: -------------------------------------------------------------------------------- 1 | #define IDC_PPKVER_STATIC 100 2 | #define IDC_PPKVER_2 101 3 | #define IDC_PPKVER_3 102 4 | #define IDC_KDF_STATIC 103 5 | #define IDC_KDF_ARGON2ID 104 6 | #define IDC_KDF_ARGON2I 105 7 | #define IDC_KDF_ARGON2D 106 8 | #define IDC_ARGON2_MEM_STATIC 107 9 | #define IDC_ARGON2_MEM 108 10 | #define IDC_ARGON2_MEM_STATIC2 109 11 | #define IDC_PPK_AUTO_STATIC 110 12 | #define IDC_PPK_AUTO_YES 111 13 | #define IDC_PPK_AUTO_NO 112 14 | #define IDC_ARGON2_TIME_STATIC 113 15 | #define IDC_ARGON2_TIME 114 16 | #define IDC_ARGON2_PARALLEL_STATIC 115 17 | #define IDC_ARGON2_PARALLEL 116 18 | -------------------------------------------------------------------------------- /windows/puttygen.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unxed/putty4far2l/1816bdba0554f9f4465b92bc0df95fb845ff4170/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/puttyins.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unxed/putty4far2l/1816bdba0554f9f4465b92bc0df95fb845ff4170/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 | 31 | PerMonitorV2 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /windows/puttytel.rc: -------------------------------------------------------------------------------- 1 | #include "rcstuff.h" 2 | #include "putty-rc.h" 3 | 4 | #define APPNAME "PuTTYtel" 5 | #define APPDESC "Telnet and Rlogin client" 6 | 7 | IDI_MAINICON ICON "putty.ico" 8 | IDI_CFGICON ICON "puttycfg.ico" 9 | 10 | #include "help.rc2" 11 | #include "putty-common.rc2" 12 | 13 | #ifndef NO_MANIFESTS 14 | 1 RT_MANIFEST "puttytel.mft" 15 | #endif /* NO_MANIFESTS */ 16 | -------------------------------------------------------------------------------- /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 HAVE_CMAKE_H 9 | #include "cmake.h" 10 | #endif 11 | 12 | #if HAVE_WINRESRC_H 13 | #include 14 | #elif HAVE_WINRES_H 15 | #include 16 | #endif 17 | 18 | /* Some systems don't define this, so I do it myself if necessary */ 19 | #ifndef TCS_MULTILINE 20 | #define TCS_MULTILINE 0x0200 21 | #endif 22 | 23 | /* Likewise */ 24 | #ifndef RT_MANIFEST 25 | #define RT_MANIFEST 24 26 | #endif 27 | 28 | /* LCC is the offender here. */ 29 | #ifndef VS_FF_DEBUG 30 | #define VS_FF_DEBUG 1 31 | #endif 32 | #ifndef VS_FF_PRERELEASE 33 | #define VS_FF_PRERELEASE 2 34 | #endif 35 | #ifndef VS_FF_PRIVATEBUILD 36 | #define VS_FF_PRIVATEBUILD 8 37 | #endif 38 | #ifndef VOS__WINDOWS32 39 | #define VOS__WINDOWS32 4 40 | #endif 41 | #ifndef VFT_APP 42 | #define VFT_APP 1 43 | #endif 44 | 45 | #endif /* PUTTY_RCSTUFF_H */ 46 | -------------------------------------------------------------------------------- /windows/test/test_screenshot.c: -------------------------------------------------------------------------------- 1 | #include "putty.h" 2 | 3 | static NORETURN PRINTF_LIKE(1, 2) void fatal_error(const char *p, ...) 4 | { 5 | va_list ap; 6 | fprintf(stderr, "screenshot: "); 7 | va_start(ap, p); 8 | vfprintf(stderr, p, ap); 9 | va_end(ap); 10 | fputc('\n', stderr); 11 | exit(1); 12 | } 13 | 14 | void out_of_memory(void) { fatal_error("out of memory"); } 15 | 16 | int main(int argc, char **argv) 17 | { 18 | const char *outfile = NULL; 19 | 20 | AuxMatchOpt amo = aux_match_opt_init(argc-1, argv+1, 0, fatal_error); 21 | while (!aux_match_done(&amo)) { 22 | char *val; 23 | #define match_opt(...) aux_match_opt( \ 24 | &amo, NULL, __VA_ARGS__, (const char *)NULL) 25 | #define match_optval(...) aux_match_opt( \ 26 | &amo, &val, __VA_ARGS__, (const char *)NULL) 27 | 28 | if (aux_match_arg(&amo, &val)) { 29 | fatal_error("unexpected argument '%s'", val); 30 | } else if (match_optval("-o", "--output")) { 31 | outfile = val; 32 | } else { 33 | fatal_error("unrecognised option '%s'\n", amo.argv[amo.index]); 34 | } 35 | } 36 | 37 | if (!outfile) 38 | fatal_error("expected an output file name"); 39 | 40 | char *err = save_screenshot(NULL, outfile); 41 | if (err) 42 | fatal_error("%s", err); 43 | 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /windows/utils/agent_mutex_name.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Return the full pathname of the global mutex that Pageant uses at 3 | * startup to atomically decide whether to be a server or a client. 4 | */ 5 | 6 | #include "putty.h" 7 | 8 | char *agent_mutex_name(void) 9 | { 10 | char *username = get_username(); 11 | char *mutexname = dupprintf("Local\\pageant-mutex.%s", username); 12 | sfree(username); 13 | return mutexname; 14 | } 15 | -------------------------------------------------------------------------------- /windows/utils/agent_named_pipe_name.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Return the full pathname of the named pipe Pageant will listen on. 3 | * Used by both the Pageant server code and client code. 4 | */ 5 | 6 | #include "putty.h" 7 | #include "cryptoapi.h" 8 | 9 | char *agent_named_pipe_name(void) 10 | { 11 | char *username = get_username(); 12 | char *suffix = capi_obfuscate_string("Pageant"); 13 | char *pipename = dupprintf("\\\\.\\pipe\\pageant.%s.%s", username, suffix); 14 | sfree(username); 15 | sfree(suffix); 16 | return pipename; 17 | } 18 | -------------------------------------------------------------------------------- /windows/utils/arm_arch_queries.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Windows implementation of the OS query functions that detect Arm 3 | * architecture extensions. 4 | */ 5 | 6 | #include "putty.h" 7 | #include "ssh.h" 8 | 9 | #if !(defined _M_ARM || defined _M_ARM64) 10 | /* 11 | * For non-Arm, stub out these functions. This module shouldn't be 12 | * _called_ in that situation anyway, but it will still be compiled 13 | * (because that's easier than getting CMake to identify the 14 | * architecture in all cases). 15 | */ 16 | #define IsProcessorFeaturePresent(...) false 17 | #endif 18 | 19 | bool platform_aes_neon_available(void) 20 | { 21 | return IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE); 22 | } 23 | 24 | bool platform_pmull_neon_available(void) 25 | { 26 | return IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE); 27 | } 28 | 29 | bool platform_sha256_neon_available(void) 30 | { 31 | return IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE); 32 | } 33 | 34 | bool platform_sha1_neon_available(void) 35 | { 36 | return IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE); 37 | } 38 | 39 | bool platform_sha512_neon_available(void) 40 | { 41 | /* As of 2020-12-24, as far as I can tell from docs.microsoft.com, 42 | * Windows on Arm does not yet provide a PF_ARM_V8_* flag for the 43 | * SHA-512 architecture extension. */ 44 | return false; 45 | } 46 | -------------------------------------------------------------------------------- /windows/utils/centre_window.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Centre a window on the screen. Used to position the main config box. 3 | */ 4 | 5 | #include "putty.h" 6 | 7 | void centre_window(HWND win) 8 | { 9 | RECT rd, rw; 10 | 11 | if (!GetWindowRect(GetDesktopWindow(), &rd)) 12 | return; 13 | if (!GetWindowRect(win, &rw)) 14 | return; 15 | 16 | MoveWindow(win, 17 | (rd.right + rd.left + rw.left - rw.right) / 2, 18 | (rd.bottom + rd.top + rw.top - rw.bottom) / 2, 19 | rw.right - rw.left, rw.bottom - rw.top, true); 20 | } 21 | -------------------------------------------------------------------------------- /windows/utils/defaults.c: -------------------------------------------------------------------------------- 1 | /* 2 | * windows/utils/defaults.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_default(); 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/utils/dputs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Implementation of dputs() for Windows. 3 | * 4 | * The debug messages are written to STD_OUTPUT_HANDLE, except that 5 | * first it has to make sure that handle _exists_, by calling 6 | * AllocConsole first if necessary. 7 | * 8 | * They also go into a file called debug.log. 9 | */ 10 | 11 | #include "putty.h" 12 | #include "utils/utils.h" 13 | 14 | static HANDLE debug_fp = INVALID_HANDLE_VALUE; 15 | static HANDLE debug_hdl = INVALID_HANDLE_VALUE; 16 | static int debug_got_console = 0; 17 | 18 | void dputs(const char *buf) 19 | { 20 | DWORD dw; 21 | 22 | if (!debug_got_console) { 23 | if (AllocConsole()) { 24 | debug_got_console = 1; 25 | debug_hdl = GetStdHandle(STD_OUTPUT_HANDLE); 26 | } 27 | } 28 | if (debug_fp == INVALID_HANDLE_VALUE) { 29 | debug_fp = CreateFile("debug.log", GENERIC_WRITE, FILE_SHARE_READ, 30 | NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 31 | } 32 | 33 | if (debug_fp != INVALID_HANDLE_VALUE) { 34 | WriteFile(debug_fp, buf, strlen(buf), &dw, NULL); 35 | } 36 | if (debug_hdl != INVALID_HANDLE_VALUE) { 37 | WriteFile(debug_hdl, buf, strlen(buf), &dw, NULL); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /windows/utils/escape_registry_key.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Escaping/unescaping functions to translate between a saved session 3 | * name, and the key name used to represent it in the Registry area 4 | * where we store saved sessions. 5 | * 6 | * The basic technique is to %-escape characters we can't use in 7 | * Registry keys. 8 | */ 9 | 10 | #include "putty.h" 11 | 12 | void escape_registry_key(const char *in, strbuf *out) 13 | { 14 | bool candot = false; 15 | static const char hex[16] = "0123456789ABCDEF"; 16 | 17 | while (*in) { 18 | if (*in == ' ' || *in == '\\' || *in == '*' || *in == '?' || 19 | *in == '%' || *in < ' ' || *in > '~' || (*in == '.' 20 | && !candot)) { 21 | put_byte(out, '%'); 22 | put_byte(out, hex[((unsigned char) *in) >> 4]); 23 | put_byte(out, hex[((unsigned char) *in) & 15]); 24 | } else 25 | put_byte(out, *in); 26 | in++; 27 | candot = true; 28 | } 29 | } 30 | 31 | void unescape_registry_key(const char *in, strbuf *out) 32 | { 33 | while (*in) { 34 | if (*in == '%' && in[1] && in[2]) { 35 | int i, j; 36 | 37 | i = in[1] - '0'; 38 | i -= (i > 9 ? 7 : 0); 39 | j = in[2] - '0'; 40 | j -= (j > 9 ? 7 : 0); 41 | 42 | put_byte(out, (i << 4) + j); 43 | in += 3; 44 | } else { 45 | put_byte(out, *in++); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /windows/utils/fontspec.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Implementation of FontSpec for Windows. 3 | */ 4 | 5 | #include "putty.h" 6 | 7 | FontSpec *fontspec_new(const char *name, bool bold, int height, int charset) 8 | { 9 | FontSpec *f = snew(FontSpec); 10 | f->name = dupstr(name); 11 | f->isbold = bold; 12 | f->height = height; 13 | f->charset = charset; 14 | return f; 15 | } 16 | 17 | FontSpec *fontspec_new_default(void) 18 | { 19 | return fontspec_new("", false, 0, 0); 20 | } 21 | 22 | FontSpec *fontspec_copy(const FontSpec *f) 23 | { 24 | return fontspec_new(f->name, f->isbold, f->height, f->charset); 25 | } 26 | 27 | void fontspec_free(FontSpec *f) 28 | { 29 | sfree(f->name); 30 | sfree(f); 31 | } 32 | 33 | void fontspec_serialise(BinarySink *bs, FontSpec *f) 34 | { 35 | put_asciz(bs, f->name); 36 | put_uint32(bs, f->isbold); 37 | put_uint32(bs, f->height); 38 | put_uint32(bs, f->charset); 39 | } 40 | 41 | FontSpec *fontspec_deserialise(BinarySource *src) 42 | { 43 | const char *name = get_asciz(src); 44 | unsigned isbold = get_uint32(src); 45 | unsigned height = get_uint32(src); 46 | unsigned charset = get_uint32(src); 47 | return fontspec_new(name, isbold, height, charset); 48 | } 49 | -------------------------------------------------------------------------------- /windows/utils/get_system_dir.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Wrapper function around GetSystemDirectory that deals with 3 | * allocating the output buffer, and also caches the result for future 4 | * calls. 5 | */ 6 | 7 | #include "putty.h" 8 | 9 | const char *get_system_dir(void) 10 | { 11 | static char *sysdir = NULL; 12 | static size_t sysdirsize = 0; 13 | 14 | if (!sysdir) { 15 | size_t len; 16 | while ((len = GetSystemDirectory(sysdir, sysdirsize)) >= sysdirsize) 17 | sgrowarray(sysdir, sysdirsize, len); 18 | } 19 | 20 | return sysdir; 21 | } 22 | -------------------------------------------------------------------------------- /windows/utils/getdlgitemtext_alloc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Handy wrappers around GetDlgItemText (A and W) which don't make you 3 | * invent an arbitrary length limit on the output string. Returned 4 | * string is dynamically allocated; caller must free. 5 | */ 6 | 7 | #include "putty.h" 8 | 9 | char *GetDlgItemText_alloc(HWND hwnd, int id) 10 | { 11 | char *ret = NULL; 12 | size_t size = 0; 13 | 14 | do { 15 | sgrowarray_nm(ret, size, size); 16 | GetDlgItemText(hwnd, id, ret, size); 17 | } while (!memchr(ret, '\0', size-1)); 18 | 19 | return ret; 20 | } 21 | 22 | wchar_t *GetDlgItemTextW_alloc(HWND hwnd, int id) 23 | { 24 | wchar_t *ret = NULL; 25 | size_t size = 0; 26 | 27 | do { 28 | sgrowarray_nm(ret, size, size); 29 | GetDlgItemTextW(hwnd, id, ret, size); 30 | } while (!memchr(ret, '\0', size-1)); 31 | 32 | return ret; 33 | } 34 | -------------------------------------------------------------------------------- /windows/utils/gui-timing.c: -------------------------------------------------------------------------------- 1 | #include "putty.h" 2 | 3 | #define TIMING_CLASS_NAME "PuTTYTimerWindow" 4 | #define TIMING_TIMER_ID 1234 5 | static long timing_next_time; 6 | static HWND timing_hwnd; 7 | 8 | static LRESULT CALLBACK TimingWndProc(HWND hwnd, UINT message, 9 | WPARAM wParam, LPARAM lParam) 10 | { 11 | switch (message) { 12 | case WM_TIMER: 13 | if ((UINT_PTR)wParam == TIMING_TIMER_ID) { 14 | unsigned long next; 15 | 16 | KillTimer(hwnd, TIMING_TIMER_ID); 17 | if (run_timers(timing_next_time, &next)) { 18 | timer_change_notify(next); 19 | } else { 20 | } 21 | } 22 | return 0; 23 | } 24 | return DefWindowProc(hwnd, message, wParam, lParam); 25 | } 26 | 27 | void setup_gui_timing(void) 28 | { 29 | WNDCLASS wndclass; 30 | 31 | memset(&wndclass, 0, sizeof(wndclass)); 32 | wndclass.lpfnWndProc = TimingWndProc; 33 | wndclass.hInstance = hinst; 34 | wndclass.lpszClassName = TIMING_CLASS_NAME; 35 | 36 | RegisterClass(&wndclass); 37 | 38 | timing_hwnd = CreateWindow( 39 | TIMING_CLASS_NAME, "PuTTY: hidden timing window", 40 | WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 41 | 100, 100, NULL, NULL, hinst, NULL); 42 | ShowWindow(timing_hwnd, SW_HIDE); 43 | } 44 | 45 | void timer_change_notify(unsigned long next) 46 | { 47 | unsigned long now = GETTICKCOUNT(); 48 | long ticks; 49 | if (now - next < INT_MAX) 50 | ticks = 0; 51 | else 52 | ticks = next - now; 53 | KillTimer(timing_hwnd, TIMING_TIMER_ID); 54 | SetTimer(timing_hwnd, TIMING_TIMER_ID, ticks, NULL); 55 | timing_next_time = next; 56 | } 57 | -------------------------------------------------------------------------------- /windows/utils/interprocess_mutex.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Lock and unlock a mutex with a globally visible name. Used to 3 | * synchronise between unrelated processes, such as two 4 | * connection-sharing PuTTYs deciding which will be the upstream. 5 | */ 6 | 7 | #include "putty.h" 8 | #include "security-api.h" 9 | 10 | HANDLE lock_interprocess_mutex(const char *mutexname, char **error) 11 | { 12 | PSECURITY_DESCRIPTOR psd = NULL; 13 | PACL acl = NULL; 14 | HANDLE mutex = NULL; 15 | 16 | if (should_have_security() && !make_private_security_descriptor( 17 | MUTEX_ALL_ACCESS, &psd, &acl, error)) 18 | goto out; 19 | 20 | SECURITY_ATTRIBUTES sa; 21 | memset(&sa, 0, sizeof(sa)); 22 | sa.nLength = sizeof(sa); 23 | sa.lpSecurityDescriptor = psd; 24 | sa.bInheritHandle = false; 25 | 26 | mutex = CreateMutex(&sa, false, mutexname); 27 | if (!mutex) { 28 | *error = dupprintf("CreateMutex(\"%s\") failed: %s", 29 | mutexname, win_strerror(GetLastError())); 30 | goto out; 31 | } 32 | 33 | WaitForSingleObject(mutex, INFINITE); 34 | 35 | out: 36 | if (psd) 37 | LocalFree(psd); 38 | if (acl) 39 | LocalFree(acl); 40 | 41 | return mutex; 42 | } 43 | 44 | void unlock_interprocess_mutex(HANDLE mutex) 45 | { 46 | ReleaseMutex(mutex); 47 | CloseHandle(mutex); 48 | } 49 | -------------------------------------------------------------------------------- /windows/utils/is_console_handle.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Determine whether a Windows HANDLE points at a console device. 3 | */ 4 | 5 | #include "putty.h" 6 | 7 | bool is_console_handle(HANDLE handle) 8 | { 9 | DWORD ignored_output; 10 | if (GetConsoleMode(handle, &ignored_output)) 11 | return true; 12 | return false; 13 | } 14 | -------------------------------------------------------------------------------- /windows/utils/load_system32_dll.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Wrapper function to load a DLL out of c:\windows\system32 without 3 | * going through the full DLL search path. (Hence no attack is 4 | * possible by placing a substitute DLL earlier on that path.) 5 | */ 6 | 7 | #include "putty.h" 8 | 9 | HMODULE load_system32_dll(const char *libname) 10 | { 11 | char *fullpath; 12 | HMODULE ret; 13 | 14 | fullpath = dupcat(get_system_dir(), "\\", libname); 15 | ret = LoadLibrary(fullpath); 16 | sfree(fullpath); 17 | return ret; 18 | } 19 | -------------------------------------------------------------------------------- /windows/utils/ltime.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Implementation of ltime() that avoids trouble with time() returning 3 | * (time_t)-1 on Windows. 4 | */ 5 | 6 | #include "putty.h" 7 | #include 8 | 9 | struct tm ltime(void) 10 | { 11 | SYSTEMTIME st; 12 | struct tm tm; 13 | 14 | memset(&tm, 0, sizeof(tm)); /* in case there are any other fields */ 15 | 16 | GetLocalTime(&st); 17 | tm.tm_sec=st.wSecond; 18 | tm.tm_min=st.wMinute; 19 | tm.tm_hour=st.wHour; 20 | tm.tm_mday=st.wDay; 21 | tm.tm_mon=st.wMonth-1; 22 | tm.tm_year=(st.wYear>=1900?st.wYear-1900:0); 23 | tm.tm_wday=st.wDayOfWeek; 24 | tm.tm_yday=-1; /* GetLocalTime doesn't tell us */ 25 | tm.tm_isdst=0; /* GetLocalTime doesn't tell us */ 26 | return tm; 27 | } 28 | -------------------------------------------------------------------------------- /windows/utils/make_spr_sw_abort_winerror.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Constructor function for a SeatPromptResult of the 'software abort' 3 | * category, whose error message includes the translation of an OS 4 | * error code. 5 | */ 6 | 7 | #include "putty.h" 8 | 9 | static void spr_winerror_errfn(SeatPromptResult spr, BinarySink *bs) 10 | { 11 | put_fmt(bs, "%s: %s", spr.errdata_lit, win_strerror(spr.errdata_u)); 12 | } 13 | 14 | SeatPromptResult make_spr_sw_abort_winerror(const char *prefix, DWORD error) 15 | { 16 | SeatPromptResult spr; 17 | spr.kind = SPRK_SW_ABORT; 18 | spr.errfn = spr_winerror_errfn; 19 | spr.errdata_lit = prefix; 20 | spr.errdata_u = error; 21 | return spr; 22 | } 23 | -------------------------------------------------------------------------------- /windows/utils/makedlgitemborderless.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Helper function to remove the border around a dialog item such as 3 | * a read-only edit control. 4 | */ 5 | 6 | #include "putty.h" 7 | 8 | void MakeDlgItemBorderless(HWND parent, int id) 9 | { 10 | HWND child = GetDlgItem(parent, id); 11 | LONG_PTR style = GetWindowLongPtr(child, GWL_STYLE); 12 | LONG_PTR exstyle = GetWindowLongPtr(child, GWL_EXSTYLE); 13 | style &= ~WS_BORDER; 14 | exstyle &= ~(WS_EX_CLIENTEDGE | WS_EX_STATICEDGE | WS_EX_WINDOWEDGE); 15 | SetWindowLongPtr(child, GWL_STYLE, style); 16 | SetWindowLongPtr(child, GWL_EXSTYLE, exstyle); 17 | SetWindowPos(child, NULL, 0, 0, 0, 0, 18 | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); 19 | } 20 | -------------------------------------------------------------------------------- /windows/utils/pgp_fingerprints_msgbox.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Display the fingerprints of the PGP Master Keys to the user as a 3 | * GUI message box. 4 | */ 5 | 6 | #include "putty.h" 7 | 8 | void pgp_fingerprints_msgbox(HWND owner) 9 | { 10 | message_box( 11 | owner, 12 | "These are the fingerprints of the PuTTY PGP Master Keys. They can\n" 13 | "be used to establish a trust path from this executable to another\n" 14 | "one. See the manual for more information.\n" 15 | "(Note: these fingerprints have nothing to do with SSH!)\n" 16 | "\n" 17 | "PuTTY Master Key as of " PGP_MASTER_KEY_YEAR 18 | " (" PGP_MASTER_KEY_DETAILS "):\n" 19 | " " PGP_MASTER_KEY_FP "\n\n" 20 | "Previous Master Key (" PGP_PREV_MASTER_KEY_YEAR 21 | ", " PGP_PREV_MASTER_KEY_DETAILS "):\n" 22 | " " PGP_PREV_MASTER_KEY_FP, 23 | "PGP fingerprints", MB_ICONINFORMATION | MB_OK, 24 | false, HELPCTXID(pgp_fingerprints)); 25 | } 26 | -------------------------------------------------------------------------------- /windows/utils/platform_get_x_display.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Implementation of platform_get_x_display for Windows, common to all 3 | * tools. 4 | */ 5 | 6 | #include "putty.h" 7 | #include "ssh.h" 8 | 9 | char *platform_get_x_display(void) 10 | { 11 | /* We may as well check for DISPLAY in case it's useful. */ 12 | return dupstr(getenv("DISPLAY")); 13 | } 14 | -------------------------------------------------------------------------------- /windows/utils/split_into_argv_w.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Unicode version of split_into_argv. 3 | */ 4 | 5 | #define SPLIT_INTO_ARGV_W 6 | #include "split_into_argv.c" 7 | -------------------------------------------------------------------------------- /windows/utils/strtoumax.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Work around lack of strtoumax in older MSVC libraries. 3 | */ 4 | 5 | #include 6 | 7 | #include "defs.h" 8 | 9 | uintmax_t strtoumax(const char *nptr, char **endptr, int base) 10 | { 11 | return _strtoui64(nptr, endptr, base); 12 | } 13 | -------------------------------------------------------------------------------- /windows/website.url: -------------------------------------------------------------------------------- 1 | [InternetShortcut] 2 | URL=https://www.chiark.greenend.org.uk/~sgtatham/putty/ 3 | -------------------------------------------------------------------------------- /windows/x11.c: -------------------------------------------------------------------------------- 1 | /* 2 | * x11.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 | Filename *xauthfn = conf_get_filename(conf, CONF_xauthfile); 15 | if (!filename_is_null(xauthfn)) 16 | x11_get_auth_from_authfile(disp, xauthfn); 17 | } 18 | 19 | const bool platform_uses_x11_unix_by_default = false; 20 | --------------------------------------------------------------------------------