Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Difference From e00724f199c90822 To 62dff762278fcc2e
2014-01-09
| ||
04:22 | Added putty-cac current state Leaf check-in: 62dff76227 user: rkeene tags: putty-cac | |
2013-11-22
| ||
13:41 | Pass the right number of entries to SetEntriesInAcl! check-in: 074d8b4052 user: simon tags: trunk | |
13:41 | Include the numeric error code in win_strerror's output. This will be useful if someone gets a mysterious Windows error on a system configured into a language we don't speak - if they cut and paste the error message to send to us, then we won't have to try to translate it. check-in: e00724f199 user: simon tags: trunk | |
2013-11-18
| ||
16:34 | Fix up the Windows help context stuff for the new connection sharing controls. check-in: 5d4d60ef11 user: jacob tags: trunk | |
2011-12-10
| ||
12:08 | Tag 0.62 release. Leaf check-in: 9c44b3c894 user: simon tags: putty-0.62, putty-branch-0.61 | |
Changes to .fossil-settings/ignore-glob.
1 2 3 4 5 6 7 8 | *.DSA *.DSA/* *.GID *.GID/* *.RES *.RES/* *.RSA *.RSA/* | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | *.DSA *.DSA/* *.GID *.GID/* *.RES *.RES/* *.RSA *.RSA/* *.cnt *.cnt/* *.dsp *.dsp/* *.dsw *.dsw/* *.exe |
︙ | ︙ | |||
42 43 44 45 46 47 48 | *.rsp/* *.td2 *.td2/* *.tds *.tds/* .bmake .bmake/* | < < < < | 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | *.rsp/* *.td2 *.td2/* *.tds *.tds/* .bmake .bmake/* .svn/*.DSA .svn/*.DSA/* .svn/*.GID .svn/*.GID/* .svn/*.RES .svn/*.RES/* .svn/*.RSA .svn/*.RSA/* .svn/*.cnt .svn/*.cnt/* .svn/*.dsp .svn/*.dsp/* .svn/*.dsw .svn/*.dsw/* .svn/*.exe |
︙ | ︙ | |||
92 93 94 95 96 97 98 | .svn/*.rsp/* .svn/*.td2 .svn/*.td2/* .svn/*.tds .svn/*.tds/* .svn/.bmake .svn/.bmake/* | < < < < < < < < < < < < < < < < < < | 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | .svn/*.rsp/* .svn/*.td2 .svn/*.td2/* .svn/*.tds .svn/*.tds/* .svn/.bmake .svn/.bmake/* .svn/MSVC .svn/MSVC/* .svn/Makefile.bor .svn/Makefile.bor/* .svn/Makefile.cyg .svn/Makefile.cyg/* .svn/Makefile.lcc .svn/Makefile.lcc/* .svn/Makefile.vc .svn/Makefile.vc/* .svn/Output .svn/Output/* .svn/build.log .svn/build.log/* .svn/build.out .svn/build.out/* .svn/local .svn/local/* .svn/pageant .svn/pageant/* .svn/plink .svn/plink/* .svn/pscp .svn/pscp/* .svn/psftp .svn/psftp/* .svn/putty .svn/putty/* .svn/puttygen .svn/puttygen/* .svn/puttytel .svn/puttytel/* MSVC MSVC/* Makefile.bor Makefile.bor/* Makefile.cyg Makefile.cyg/* Makefile.lcc Makefile.lcc/* Makefile.vc Makefile.vc/* Output Output/* build.log build.log/* build.out build.out/* charset/sbcsdat.c charset/sbcsdat.c/* contrib/cygtermd/cygtermd.exe contrib/cygtermd/cygtermd.exe/* doc/*.1 doc/*.1/* doc/*.GID doc/*.GID/* doc/*.chm |
︙ | ︙ | |||
190 191 192 193 194 195 196 | doc/*.info/* doc/*.log doc/*.log/* doc/*.txt doc/*.txt/* doc/vstr.but doc/vstr.but/* | < < | 166 167 168 169 170 171 172 173 174 175 176 177 178 179 | doc/*.info/* doc/*.log doc/*.log/* doc/*.txt doc/*.txt/* doc/vstr.but doc/vstr.but/* icons/*.c icons/*.c/* icons/*.ico icons/*.ico/* icons/*.png icons/*.png/* icons/*.xpm |
︙ | ︙ | |||
222 223 224 225 226 227 228 | pageant/* plink plink/* pscp pscp/* psftp psftp/* | < < < < < < < < < < < < < < < < < < < < | 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 | pageant/* plink plink/* pscp pscp/* psftp psftp/* putty putty/* puttygen puttygen/* puttytel puttytel/* testdata/bignum.txt testdata/bignum.txt/* unix/*.log unix/*.log/* unix/Makefile unix/Makefile.gtk unix/Makefile.gtk/* unix/Makefile.in unix/Makefile.in/* unix/Makefile.local unix/Makefile.local/* unix/Makefile.ux unix/Makefile.ux/* unix/Makefile/* unix/aclocal.m4 unix/aclocal.m4/* unix/autom4te.cache unix/autom4te.cache/* unix/config.status unix/config.status/* unix/configure unix/configure/* unix/install-sh unix/install-sh/* unix/local unix/local/* unix/plink unix/plink/* unix/pscp unix/pscp/* unix/psftp unix/psftp/* unix/pterm unix/pterm/* unix/putty unix/putty/* unix/puttygen unix/puttygen/* unix/puttytel unix/puttytel/* unix/uxconfig.h unix/uxconfig.h/* unix/uxconfig.in unix/uxconfig.in/* windows/*.DSA windows/*.DSA/* windows/*.GID windows/*.GID/* windows/*.RES windows/*.RES/* windows/*.RSA |
︙ | ︙ |
Deleted Buildscr.cv.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to CHECKLST.txt.
︙ | ︙ | |||
173 174 175 176 177 178 179 | is available. - After running webupdate, run update-rsync on chiark and verify that the rsync mirror package (~/ftp/putty-website-mirror) contains a subdirectory for the new version and mentions it in its .htaccess. - Announce the release! | | < < | < | < > | 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 | is available. - After running webupdate, run update-rsync on chiark and verify that the rsync mirror package (~/ftp/putty-website-mirror) contains a subdirectory for the new version and mentions it in its .htaccess. - Announce the release! + Mail the announcement to <putty-announce@lists.tartarus.org>. * Put a 'Reply-To: putty@projects.tartarus.org' header on the mail so that people don't keep replying to my personal address. + Post it to comp.security.ssh. + Mention it in <TDHTT> on mono. - Relax (slightly). After the release ----------------- |
︙ | ︙ |
Changes to LATEST.VER.
|
| | | 1 | 0.62 |
Changes to LICENCE.
|
| > > > > > > > > | > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | PuTTY-CAC is Copyright 2009-2012 Daniel Risacher PuTTY-CAC is available under the GPLv2 license. PuTTY-CAC is a derivative work of PuTTY-SC. PuTTY-SC is Copyright 2005-2008 Pascal Buchbinder. PuTTY-SC is available under the GPLv2 license. PuTTY-SC is a derivative work of PuTTY. PuTTY is copyright 1997-2011 Simon Tatham. Portions copyright Robert de Bath, Joris van Rantwijk, Delian Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry, Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, Markus Kuhn, Colin Watson, and CORE SDI S.A. CAPI support donated by Andrew Prout. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, |
︙ | ︙ |
Changes to README.
︙ | ︙ | |||
36 37 38 39 40 41 42 | MSVC/putty/putty.dsp builds PuTTY itself, MSVC/plink/plink.dsp builds Plink, and so on. - windows/Makefile.bor is for the Borland C compiler. Type `make -f Makefile.bor' while in the `windows' subdirectory to build all the PuTTY binaries. | | | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | MSVC/putty/putty.dsp builds PuTTY itself, MSVC/plink/plink.dsp builds Plink, and so on. - windows/Makefile.bor is for the Borland C compiler. Type `make -f Makefile.bor' while in the `windows' subdirectory to build all the PuTTY binaries. - windows/Makefile.cyg is for Cygwin / mingw32 installations. Type `make -f Makefile.cyg' while in the `windows' subdirectory to build all the PuTTY binaries. You'll probably need quite a recent version of the w32api package. Note that by default the multiple monitor and HTML Help support are excluded from the Cygwin build, since at the time of writing Cygwin doesn't include the necessary headers. |
︙ | ︙ | |||
61 62 63 64 65 66 67 | toolchains fairly quickly. Please report any problems with the other toolchains mentioned above. For building on Unix: - unix/configure is for Unix and GTK. If you don't have GTK, you should still be able to build the command-line utilities (PSCP, | | | < < < < | < < < < < < < < < < < < < < < | | < | < < < < | < < | | | < < | 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | toolchains fairly quickly. Please report any problems with the other toolchains mentioned above. For building on Unix: - unix/configure is for Unix and GTK. If you don't have GTK, you should still be able to build the command-line utilities (PSCP, PSFTP, Plink, PuTTYgen) using this script. To use it, change into the `unix' subdirectory, run `./configure' and then `make'. Note that Unix PuTTY has mostly only been tested on Linux so far; portability problems such as BSD-style ptys or different header file requirements are expected. - unix/Makefile.gtk and unix/Makefile.ux are for non-autoconfigured builds. These makefiles expect you to change into the `unix' subdirectory, then run `make -f Makefile.gtk' or `make -f Makefile.ux' respectively. Makefile.gtk builds all the programs but relies on Gtk, whereas Makefile.ux builds only the command-line utilities and has no Gtk dependence. - For the graphical utilities, Gtk+-1.2 and Gtk+-2.0 should both be supported. - Both Unix Makefiles have an `install' target. Note that by default it tries to install `man' pages, which you may need to have built using Halibut first -- see below. All of the Makefiles are generated automatically from the file `Recipe' by the Perl script `mkfiles.pl'. Additions and corrections to Recipe and the mkfiles.pl are much more useful than additions and corrections to the alternative Makefiles themselves. The Unix `configure' script and its various requirements are generated by the shell script `mkauto.sh', which requires GNU Autoconf, GNU Automake, and Gtk; if you've got the source from Subversion rather than using one of our source snapshots, you'll need to run this yourself. Documentation (in various formats including Windows Help and Unix `man' pages) is built from the Halibut (`.but') files in the `doc' subdirectory using `doc/Makefile'. If you aren't using one of our source snapshots, you'll need to do this yourself. Halibut can be found at <http://www.chiark.greenend.org.uk/~sgtatham/halibut/>. |
︙ | ︙ |
Changes to Recipe.
︙ | ︙ | |||
15 16 17 18 19 20 21 | !makefile vc windows/Makefile.vc !makefile vcproj windows/MSVC !makefile cygwin windows/Makefile.cyg !makefile borland windows/Makefile.bor !makefile lcc windows/Makefile.lcc !makefile gtk unix/Makefile.gtk !makefile unix unix/Makefile.ux | | | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | !makefile vc windows/Makefile.vc !makefile vcproj windows/MSVC !makefile cygwin windows/Makefile.cyg !makefile borland windows/Makefile.bor !makefile lcc windows/Makefile.lcc !makefile gtk unix/Makefile.gtk !makefile unix unix/Makefile.ux !makefile ac unix/Makefile.in !makefile osx macosx/Makefile !makefile devcppproj windows/DEVCPP # Source directories. !srcdir charset/ !srcdir windows/ !srcdir unix/ !srcdir macosx/ |
︙ | ︙ | |||
109 110 111 112 113 114 115 | # # - RCFL=/DASCIICTLS (Windows only) # Uses ASCII rather than Unicode to specify the tab control in # the resource file. Probably most useful when compiling with # Cygnus/mingw32, whose resource compiler may have less of a # problem with it. # | < < < < < | 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | # # - RCFL=/DASCIICTLS (Windows only) # Uses ASCII rather than Unicode to specify the tab control in # the resource file. Probably most useful when compiling with # Cygnus/mingw32, whose resource compiler may have less of a # problem with it. # # - XFLAGS=/DTELNET_DEFAULT # Causes PuTTY to default to the Telnet protocol (in the absence # of Default Settings and so on to the contrary). Normally PuTTY # will default to SSH. # # - XFLAGS=/DDEBUG # Causes PuTTY to enable internal debugging. |
︙ | ︙ | |||
170 171 172 173 174 175 176 | if test -z "$(VER)" && (cd ..; md5sum -c manifest); then \ $(CC) $(COMPAT) $(XFLAGS) $(CFLAGS) `cat ../version.def` -c ../version.c; \ else \ $(CC) $(COMPAT) $(XFLAGS) $(CFLAGS) $(VER) -c ../version.c; \ fi !end !specialobj gtk version | < < < < < < < < < < < < < < < < | 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | if test -z "$(VER)" && (cd ..; md5sum -c manifest); then \ $(CC) $(COMPAT) $(XFLAGS) $(CFLAGS) `cat ../version.def` -c ../version.c; \ else \ $(CC) $(COMPAT) $(XFLAGS) $(CFLAGS) $(VER) -c ../version.c; \ fi !end !specialobj gtk version # Add VER to Windows resource targets, and force them to be rebuilt every # time, on the assumption that they will contain version information. !begin vc vars CFLAGS = $(CFLAGS) /DHAS_GSSAPI /DSECURITY_WIN32 RCFLAGS = $(RCFLAGS) $(VER) !end !begin cygwin vars # XXX GNU-ism, but it's probably all right for a Cygwin/MinGW Makefile. RCFLAGS += $(patsubst -D%,--define %,$(VER)) !end !begin borland vars # Borland doesn't support +=. This probably shouldn't work, but seems to. RCFLAGS = $(RCFLAGS) $(VER) !end |
︙ | ︙ | |||
245 246 247 248 249 250 251 | install-strip: $(MAKE) install INSTALL_PROGRAM="$(INSTALL_PROGRAM) -s" !end !begin osx vars CFLAGS += -DMACOSX !end | < < < < < < < < < < < < < < < | | | | < | | | | 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 | install-strip: $(MAKE) install INSTALL_PROGRAM="$(INSTALL_PROGRAM) -s" !end !begin osx vars CFLAGS += -DMACOSX !end # Random symbols. !begin cygwin vars # _WIN32_IE is required to expose identifiers that only make sense on # systems with IE5+ installed, such as some arguments to SHGetFolderPath(). # WINVER etc perform a similar function for FlashWindowEx(). CFLAGS += -D_WIN32_IE=0x0500 CFLAGS += -DWINVER=0x0500 -D_WIN32_WINDOWS=0x0410 -D_WIN32_WINNT=0x0500 !end # ------------------------------------------------------------ # Definitions of object groups. A group name, followed by an =, # followed by any number of objects or other already-defined group # names. A line beginning `+' is assumed to continue the previous # line. # Terminal emulator and its (platform-independent) dependencies. TERMINAL = terminal wcwidth ldiscucs logging tree234 minibidi + config dialog # GUI front end and terminal emulator (putty, puttytel). GUITERM = TERMINAL window windlg winctrls sizetip winucs winprint + winutils wincfg sercfg winhelp winjump # Same thing on Unix. UXTERM = TERMINAL uxcfg sercfg uxucs uxprint timing GTKTERM = UXTERM gtkwin gtkcfg gtkdlg gtkfont gtkcols xkeysym OSXTERM = UXTERM osxwin osxdlg osxctrls # Non-SSH back ends (putty, puttytel, plink). NONSSH = telnet raw rlogin ldisc pinger # SSH back end (putty, plink, pscp, psftp). SSH = ssh sshcrc sshdes sshmd5 sshrsa sshrand sshsha sshblowf + sshdh sshcrcda sshpubk sshzlib sshdss x11fwd portfwd + sshaes sshsh256 sshsh512 sshbn wildcard pinger ssharcf + sshgssc pgssapi WINSSH = SSH winnoise winpgntc wingss UXSSH = SSH uxnoise uxagentc uxgss # SFTP implementation (pscp, psftp). SFTP = sftp int64 logging # Miscellaneous objects appearing in all the network utilities (not # Pageant or PuTTYgen). MISC = timing misc version settings tree234 proxy WINMISC = MISC winstore winnet winhandl cmdline windefs winmisc winproxy + wintime UXMISC = MISC uxstore uxsel uxnet cmdline uxmisc uxproxy time OSXMISC = MISC uxstore uxsel osxsel uxnet uxmisc uxproxy time # Character set library, for use in pterm. CHARSET = sbcsdat slookup sbcs utf8 toucs fromucs xenc mimeenc macenc localenc # Standard libraries. |
︙ | ︙ | |||
340 341 342 343 344 345 346 | # colon, followed by a list of objects. Also in the list may be the # keywords [G] for Windows GUI app, [C] for Console app, [X] for # X/GTK Unix app, [U] for command-line Unix app. putty : [G] GUITERM NONSSH WINSSH W_BE_ALL WINMISC winx11 putty.res LIBS puttytel : [G] GUITERM NONSSH W_BE_NOSSH WINMISC puttytel.res nogss LIBS plink : [C] winplink wincons NONSSH WINSSH W_BE_ALL logging WINMISC | | | | | | | | 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 | # colon, followed by a list of objects. Also in the list may be the # keywords [G] for Windows GUI app, [C] for Console app, [X] for # X/GTK Unix app, [U] for command-line Unix app. putty : [G] GUITERM NONSSH WINSSH W_BE_ALL WINMISC winx11 putty.res LIBS puttytel : [G] GUITERM NONSSH W_BE_NOSSH WINMISC puttytel.res nogss LIBS plink : [C] winplink wincons NONSSH WINSSH W_BE_ALL logging WINMISC + winx11 plink.res winnojmp LIBS pscp : [C] pscp winsftp wincons WINSSH BE_SSH SFTP wildcard WINMISC + pscp.res winnojmp LIBS psftp : [C] psftp winsftp wincons WINSSH BE_SSH SFTP wildcard WINMISC + psftp.res winnojmp LIBS pageant : [G] winpgnt sshrsa sshpubk sshdes sshbn sshmd5 version tree234 + misc sshaes sshsha winpgntc sshdss sshsh256 sshsh512 winutils + winmisc winhelp pageant.res LIBS puttygen : [G] winpgen sshrsag sshdssg sshprime sshdes sshbn sshmd5 version + sshrand winnoise sshsha winstore misc winctrls sshrsa sshdss winmisc + sshpubk sshaes sshsh256 sshsh512 import winutils puttygen.res + tree234 notiming winhelp winnojmp LIBS wintime pterm : [X] GTKTERM uxmisc misc ldisc settings uxpty uxsel BE_NONE uxstore + uxsignal CHARSET cmdline uxpterm version time xpmpterm xpmptcfg + nogss putty : [X] GTKTERM uxmisc misc ldisc settings uxsel U_BE_ALL uxstore + uxsignal CHARSET uxputty NONSSH UXSSH UXMISC ux_x11 xpmputty + xpmpucfg puttytel : [X] GTKTERM uxmisc misc ldisc settings uxsel U_BE_NOSSH + uxstore uxsignal CHARSET uxputty NONSSH UXMISC xpmputty xpmpucfg + nogss plink : [U] uxplink uxcons NONSSH UXSSH U_BE_ALL logging UXMISC uxsignal + ux_x11 puttygen : [U] cmdgen sshrsag sshdssg sshprime sshdes sshbn sshmd5 version + sshrand uxnoise sshsha misc sshrsa sshdss uxcons uxstore uxmisc + sshpubk sshaes sshsh256 sshsh512 import puttygen.res time tree234 + uxgen notiming pscp : [U] pscp uxsftp uxcons UXSSH BE_SSH SFTP wildcard UXMISC psftp : [U] psftp uxsftp uxcons UXSSH BE_SSH SFTP wildcard UXMISC PuTTY : [MX] osxmain OSXTERM OSXMISC CHARSET U_BE_ALL NONSSH UXSSH + ux_x11 uxpty uxsignal testback putty.icns info.plist |
Deleted callback.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Added capi.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 | /* * CAPI: Windows Crypto API support file. * Andrew Prout, aprout at ll mit edu */ #include <windows.h> #include <Cryptuiapi.h> #include "capi.h" #include "ssh.h" #define SHA1_BYTES 20 typedef unsigned char uint8; typedef signed char sint8; typedef unsigned short uint16; typedef signed short sint16; //typedef unsigned long uint32; typedef signed long sint32; #pragma comment(lib, "Crypt32.lib") #pragma comment(lib, "Cryptui.lib") //#define DebugLog_FileName "c:\\blah\\putty-capi.log" #ifdef DebugLog_FileName void AsciiDumpBuffer(FILE* iStream, uint8* buf, uint32 size) { uint32 x; for (x=0; x<size; x++) { if (x && (x % 8) == 0) fprintf(iStream, " "); if (buf[x] >= 32 && buf[x] <= 126) fprintf(iStream, "%hc", buf[x]); else fprintf(iStream, "."); } } void HexDumpBuffer(FILE* iStream, uint8* buf, uint32 size, char* newlinepad) { uint32 x, tmp; if (newlinepad) fprintf(iStream, "%s", newlinepad); for (x=0; x<size; x++) { if (x && (x % 16) == 0) { fprintf(iStream, " "); AsciiDumpBuffer(iStream, &buf[x-16], 16); fprintf(iStream, "\n"); if (newlinepad) fprintf(iStream, "%s", newlinepad); } else if (x % 16 == 8) fprintf(iStream, "- "); if ((x % 16) == 0) fprintf(iStream, "%4u: ", x); fprintf(iStream, "%02X ", buf[x]); } tmp = 16 - (size%16); if (tmp != 16) { for (x=0; x<tmp; x++) { if (x == 7) fprintf(iStream, " "); fprintf(iStream, " "); } } tmp = size % 16; if (tmp == 0) tmp = 16; fprintf(iStream, " "); AsciiDumpBuffer(iStream, &buf[size - tmp], tmp); fprintf(iStream, "\n"); } void debuglog_buffer(void* buf, uint32 size) { FILE* f = fopen(DebugLog_FileName, "a+"); if (f == NULL) return; HexDumpBuffer(f, (uint8*) buf, size, ""); fclose(f); } void debuglog(char* format, ...) { va_list arg_ptr; DWORD tmpAllocedSize = 16384; DWORD contlen; FILE* f; char* message; va_start(arg_ptr, format); message = (char*) malloc(tmpAllocedSize); if (!message) return; _vsnprintf(message, tmpAllocedSize, format, arg_ptr); message[tmpAllocedSize-1] = 0; contlen = (DWORD) strlen(message); f = fopen(DebugLog_FileName, "a+"); if (f == NULL) return; fprintf(f, "%s", message); fclose(f); free(message); } #else //#ifdef DebugLog_FileName #define debuglog_buffer #define debuglog #endif //#ifdef DebugLog_FileName #define CAPI_PUT_32BIT(cp, value) { \ (cp)[0] = (unsigned char)((value) >> 24); \ (cp)[1] = (unsigned char)((value) >> 16); \ (cp)[2] = (unsigned char)((value) >> 8); \ (cp)[3] = (unsigned char)(value); } #define CAPI_BYTES_USED_IN_INT32(i) \ (i & 0xFF000000 ? 4 : ( \ i & 0x00FF0000 ? 3 : ( \ i & 0x0000FF00 ? 2 : 1 \ ) \ )) uint8 GetCodeFromHex(const char iHex) { if (iHex >= '0' && iHex <= '9') // numbers return iHex - 48; if (iHex >= 'A' && iHex <= 'F') // uppercase A-F return iHex - 55; if (iHex >= 'a' && iHex <= 'f') // lowercase a-f return iHex - 87; return 255; } BOOL hextobytes(const char* iHex, uint8* oBytes) { uint32 x = 0; uint8 val; while (iHex[x]) { val = GetCodeFromHex(iHex[x]); if (val >= 16) return FALSE; if (x % 2) oBytes[x/2] |= val; else oBytes[x/2] = (val << 4); x++; #ifdef _DEBUG if (x > 10000) RaiseException(STATUS_BUFFER_OVERFLOW, EXCEPTION_NONCONTINUABLE, 0, 0); #endif } return TRUE; } struct ssh2_userkey capi_key_ssh2_userkey = { 0, 0, 0 }; struct CAPI_PUBKEY_BIT_BLOB_struct { PUBLICKEYSTRUC publickeystruct; RSAPUBKEY rsapubkey; // BYTE modulus[0]; }; BOOL capi_get_cert_handle(char* certID, PCCERT_CONTEXT* oCertContext) { BOOL retval = FALSE; PCCERT_CONTEXT pCertContext = NULL, pFindCertContext = NULL; HCERTSTORE hStore = NULL; CRYPT_HASH_BLOB chb = { 0, NULL }; DWORD FoundCount = 0, dwStoreType, tmpSize; char *LcertID = NULL, *LcertID_StoreType, *LcertID_StoreName, *LcertID_fingerprint; if (certID == NULL || oCertContext == NULL) { debuglog("capi_get_cert_handle: input parameter is NULL that cannot be\n"); return FALSE; // no goto cleanup, it'll crash } if ((LcertID = malloc(strlen(certID) + 1)) == NULL) { debuglog("capi_get_cert_handle: malloc for LcertID failed\n"); goto cleanup; } strcpy(LcertID, certID); LcertID_StoreType = strtok(LcertID, "\\"); LcertID_StoreName = strtok(NULL, "\\"); LcertID_fingerprint = strtok(NULL, "\\"); if (LcertID_StoreType == NULL || LcertID_StoreName == NULL || LcertID_fingerprint == NULL) { debuglog("capi_get_cert_handle: strtok(LcertID) failed\n"); goto cleanup; } if (strcmp(LcertID_StoreType, "User") == 0) dwStoreType = CERT_SYSTEM_STORE_CURRENT_USER; else if (strcmp(LcertID_StoreType, "System") == 0) dwStoreType = CERT_SYSTEM_STORE_LOCAL_MACHINE; else { debuglog("capi_get_cert_handle: Unknown store type\n"); goto cleanup; } if (strlen(LcertID_fingerprint) != (SHA1_BYTES * 2)) { debuglog("capi_get_cert_handle: strlen(LcertID_fingerprint) != (SHA1_BYTES * 2)\n"); goto cleanup; } chb.cbData = SHA1_BYTES; if ((chb.pbData = (BYTE*) malloc(SHA1_BYTES)) == NULL) { debuglog("capi_get_cert_handle: malloc for chb.pbData failed\n"); goto cleanup; } if (!hextobytes(LcertID_fingerprint, chb.pbData)) { debuglog("capi_get_cert_handle: hextobytes(LcertID_fingerprint) failed\n"); goto cleanup; } if((hStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, 0 /*hCryptProv*/, dwStoreType | CERT_STORE_READONLY_FLAG | CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_ENUM_ARCHIVED_FLAG, LcertID_StoreName)) == NULL) { debuglog("capi_get_cert_handle: CertOpenStore(%d, %s) failed\n", dwStoreType, LcertID_StoreName); goto cleanup; } while (pFindCertContext = CertFindCertificateInStore(hStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_SHA1_HASH, &chb, pFindCertContext)) { debuglog("capi_get_cert_handle: found a cert, checking for private key...\n"); tmpSize = 0; if (CertGetCertificateContextProperty(pFindCertContext, CERT_KEY_PROV_INFO_PROP_ID, NULL, &tmpSize)) { debuglog("capi_get_cert_handle: got a private key duplicating context...\n"); if (pCertContext == NULL) pCertContext = CertDuplicateCertificateContext(pFindCertContext); FoundCount++; debuglog("capi_get_cert_handle: All set\n"); } else { // no private key, ignore the cert } } if (FoundCount != 1) { debuglog("capi_get_cert_handle: FoundCount != 1. FoundCount=%d\n", FoundCount); goto cleanup; } if (strcmp(pCertContext->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId, szOID_RSA_RSA) != 0) { // Not an RSA key? egads, bail out... debuglog("capi_get_cert_handle: Not an RSA key?\n"); debuglog("pCertContext->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId=%s\n", pCertContext->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId); goto cleanup; } *oCertContext = pCertContext; pCertContext = NULL; // to avoid the free in cleanup; retval = TRUE; cleanup: if (chb.pbData) free(chb.pbData); chb.pbData = NULL; if (LcertID) free(LcertID); LcertID = NULL; if (pCertContext) CertFreeCertificateContext(pCertContext); pCertContext = NULL; return retval; } BOOL capi_display_cert_ui(HWND hwnd, char* certID, WCHAR* title) { BOOL retval = FALSE; PCCERT_CONTEXT pCertContext = NULL; if (!capi_get_cert_handle(certID, &pCertContext)) { debuglog("capi_display_cert_ui: capi_get_cert_handle failed\n"); goto cleanup; } if (!CryptUIDlgViewContext(CERT_STORE_CERTIFICATE_CONTEXT, pCertContext, hwnd, title, 0, NULL)) { debuglog("capi_display_cert_ui: CryptUIDlgViewContext failed\n"); goto cleanup; } retval = TRUE; cleanup: if (pCertContext) CertFreeCertificateContext(pCertContext); pCertContext = NULL; return retval; } BOOL capi_get_pubkey_blob(PCCERT_CONTEXT pCertContext, unsigned char** pubkey, int *blob_len) { BOOL retval = FALSE; DWORD tmpSize, mbits, mbytes, ebytes; int i; // signed, for loop goes to -1 unsigned char *p = NULL;//, *modu = NULL; struct CAPI_PUBKEY_BIT_BLOB_struct* capi_pubkey = NULL; Bignum modu = NULL; if (pubkey == NULL || blob_len == NULL) { debuglog("capi_get_pubkey: input parameter is NULL that cannot be\n"); return FALSE; // no goto cleanup, it'll crash } if ((mbits = CertGetPublicKeyLength(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &pCertContext->pCertInfo->SubjectPublicKeyInfo)) == 0) { debuglog("capi_get_pubkey: CertGetPublicKeyLength failed\n"); goto cleanup; } debuglog("capi_get_pubkey: mbits=%d\n", mbits); tmpSize = 0; if (!CryptDecodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB, pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData, pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData, 0, NULL, &tmpSize)) { debuglog("capi_get_pubkey: CryptDecodeObject[1] failed\n"); goto cleanup; } capi_pubkey = malloc(tmpSize); if (!CryptDecodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB, pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData, pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData, 0, capi_pubkey, &tmpSize)) { debuglog("capi_get_pubkey: CryptDecodeObject[2] failed\n"); goto cleanup; } // the below formula for the format is taken from sc.c... I agree with the comments there, it's ugly. // ebytes = (ebits/8) + ((ebits % 8) ? 1 : 0); ebytes = CAPI_BYTES_USED_IN_INT32(capi_pubkey->rsapubkey.pubexp); mbytes = (mbits/8) + ((mbits % 8) ? 1 : 0); // offset by sizeof(*capi_pubkey) bytes to the public key... //modu = ((unsigned char*) capi_pubkey) + sizeof(*capi_pubkey); modu = bignum_from_bytes(((unsigned char*) capi_pubkey) + sizeof(*capi_pubkey), mbytes); debuglog("capi_get_pubkey_int: tmpSize=%d, capi_pubkey=:\n", tmpSize); debuglog_buffer(capi_pubkey, tmpSize); *blob_len = 4+7+4+ebytes+4+(1+mbytes); // mbytes has a leading zero if ((p = *pubkey = (unsigned char*) malloc(*blob_len)) == NULL) { debuglog("capi_get_pubkey: malloc for *pubkey failed\n"); goto cleanup; } CAPI_PUT_32BIT(p, 7); p += 4; memcpy(p, "ssh-rsa", 7); p += 7; CAPI_PUT_32BIT(p, ebytes); p += 4; debuglog("capi_get_pubkey_int: ebytes=%d, capi_pubkey->rsapubkey.pubexp=%d (0x%08x), mbytes=%d, modu=:\n", ebytes, capi_pubkey->rsapubkey.pubexp, capi_pubkey->rsapubkey.pubexp, mbytes); debuglog_buffer(modu, mbytes); for (i=ebytes-1; i>=0; i--) *p++ = (unsigned char) ((capi_pubkey->rsapubkey.pubexp & (0xFF << (i*8))) >> (i*8)); CAPI_PUT_32BIT(p, mbytes + 1); // add room for a leading zero p += 4; *p++ = 0; // leading zero for (i = 0; i < (int) mbytes; i++) *p++ = bignum_byte(modu, i); retval = TRUE; cleanup: if (modu) freebn(modu); if (capi_pubkey) free(capi_pubkey); capi_pubkey = NULL; if (!retval) { if (pubkey) { if (*pubkey) free(*pubkey); *pubkey = NULL; } if (blob_len) *blob_len = 0; } return retval; } BOOL capi_get_pubkey_int(void *f /*frontend*/, char* certID, unsigned char** pubkey, char **algorithm, int *blob_len, PCCERT_CONTEXT* oCertContext) { BOOL retval = FALSE; PCCERT_CONTEXT pCertContext = NULL; if (certID == NULL || pubkey == NULL || algorithm == NULL || blob_len == NULL) { debuglog("capi_get_pubkey: input parameter is NULL that cannot be\n"); return FALSE; // no goto cleanup, it'll crash } *pubkey = NULL; *algorithm = NULL; *blob_len = 0; // goto cleanup now OK if ((*algorithm = calloc(sizeof(char *), strlen("ssh-rsa")+1)) == NULL) { debuglog("capi_get_pubkey: calloc for *algorithm failed\n"); goto cleanup; } strcpy(*algorithm, "ssh-rsa"); if (!capi_get_cert_handle(certID, &pCertContext)) { debuglog("capi_get_pubkey: capi_get_cert_handle failed\n"); goto cleanup; } if (!capi_get_pubkey_blob(pCertContext, pubkey, blob_len)) { debuglog("capi_get_pubkey_int: capi_get_pubkey_blob failed\n"); goto cleanup; } if (oCertContext) { *oCertContext = pCertContext; pCertContext = NULL; // to avoid the free in cleanup; } retval = TRUE; cleanup: if (!retval) { if (pubkey) { if (*pubkey) free(*pubkey); *pubkey = NULL; } if (algorithm) { if (*algorithm) free(*algorithm); *algorithm = NULL; } if (blob_len) *blob_len = 0; } return retval; } BOOL capi_get_pubkey(void *f, char* certID, unsigned char** pubkey, char **algorithm, int *blob_len) { return capi_get_pubkey_int(f, certID, pubkey, algorithm, blob_len, NULL); } char *capi_base64key(char *data, int len) { int bi, bn; char out[4]; int datalen = len; char *buffi = calloc(len + len, sizeof(char *)); int buffi_pos = 0; for(bi=0;bi<(len + len); bi++) buffi[bi] = '\0'; while (datalen > 0) { bn = (datalen < 3 ? datalen : 3); base64_encode_atom(data, bn, out); data += bn; datalen -= bn; for (bi = 0; bi < 4; bi++) { buffi[buffi_pos] = out[bi]; buffi_pos++; } } return buffi; } char* capi_get_key_string(char* certID) { unsigned char *pubkey, *algorithm; int pubkey_len; char *key64 = NULL, *keystring = NULL; if (!capi_get_pubkey(NULL, certID, &pubkey, &algorithm, &pubkey_len)) { debuglog("capi_get_key_string: capi_get_pubkey failed\n"); goto cleanup; } debuglog("capi_get_key_string: Got pubkey. algorithm=%s. pubkey_len=%d. pubkey=:\n", algorithm, pubkey_len); debuglog_buffer(pubkey, pubkey_len); if ((key64 = capi_base64key(pubkey, pubkey_len)) == NULL) { debuglog("capi_get_key_string: capi_get_pubkey failed\n"); goto cleanup; } if ((keystring = calloc(1, strlen("ssh-rsa")+1+strlen(key64)+1+strlen("CAPI:")+strlen(certID) + 1)) == NULL) { debuglog("capi_get_key_string: capi_get_pubkey failed\n"); goto cleanup; } sprintf(keystring, "ssh-rsa %s CAPI:%s", key64, certID); cleanup: return keystring; } BOOL capi_get_key_handle(void *f, char* certID, struct capi_keyhandle_struct** keyhandle) { BOOL retval = FALSE; struct capi_keyhandle_struct* newkeyhandle = NULL; PCCERT_CONTEXT pCertContext = NULL; HCRYPTKEY privkey = 0; DWORD ckpi_size; CRYPT_KEY_PROV_INFO* ckpi = NULL; if (certID == NULL || keyhandle == NULL) { debuglog("capi_get_pubkey: input parameter is NULL that cannot be\n"); return FALSE; // no goto cleanup, it'll crash } *keyhandle = NULL; // goto cleanup now OK if ((newkeyhandle = calloc(1, sizeof(struct capi_keyhandle_struct))) == NULL) goto cleanup; if (!capi_get_pubkey_int(f, certID, &newkeyhandle->pubkey, &newkeyhandle->algorithm, &newkeyhandle->pubkey_len, &pCertContext)) goto cleanup; ckpi_size = 0; if (!CertGetCertificateContextProperty(pCertContext, CERT_KEY_PROV_INFO_PROP_ID, NULL, &ckpi_size)) goto cleanup; if ((ckpi = (CRYPT_KEY_PROV_INFO*) malloc(ckpi_size)) == NULL) goto cleanup; if (!CertGetCertificateContextProperty(pCertContext, CERT_KEY_PROV_INFO_PROP_ID, ckpi, &ckpi_size)) goto cleanup; if (ckpi->dwProvType == 0) { // CNG // eh, later... debuglog("capi_get_key_handle: CNG Key, bailing...\n"); goto cleanup; } else { // CAPI if (!CryptAcquireContextW((HCRYPTPROV*) &newkeyhandle->win_provider, ckpi->pwszContainerName, ckpi->pwszProvName, ckpi->dwProvType, ((ckpi->dwFlags & CRYPT_MACHINE_KEYSET) ? CRYPT_MACHINE_KEYSET : 0) )) { debuglog("capi_get_key_handle: Error calling CryptAcquireContext. GetLastError()=%i (0x%08x)\n", GetLastError(), GetLastError()); goto cleanup; } newkeyhandle->win_keyspec = ckpi->dwKeySpec; } *keyhandle = newkeyhandle; retval = TRUE; cleanup: if (pCertContext) CertFreeCertificateContext(pCertContext); pCertContext = NULL; if (ckpi) free(ckpi); ckpi = NULL; if (!retval) { if (newkeyhandle) { if (newkeyhandle->win_provider) CryptReleaseContext((HCRYPTPROV) newkeyhandle->win_provider, 0); newkeyhandle->win_provider = NULL; if (newkeyhandle->pubkey) free(newkeyhandle->pubkey); newkeyhandle->pubkey = NULL; if (newkeyhandle->algorithm) free(newkeyhandle->algorithm); newkeyhandle->algorithm = NULL; free(newkeyhandle); } newkeyhandle = NULL; } return retval; } unsigned char* capi_sig_certID(char* certID, char *sigdata, int sigdata_len, int *sigblob_len) { BOOL success = FALSE; unsigned char* retval = NULL, *rawsig = NULL, *p; HCRYPTHASH hash = 0; DWORD ckpi_size, tmpSize, tmpHashLen, rawsig_len, x; Bignum bn = NULL; HCRYPTPROV hProv = 0; CRYPT_KEY_PROV_INFO* ckpi = NULL; PCCERT_CONTEXT pCertContext = NULL; debuglog("capi_sig_certID called. sigdata_len=%d\n", sigdata_len); debuglog_buffer(sigdata, sigdata_len); // Find cert context from certID if (!capi_get_cert_handle(certID, &pCertContext)) { debuglog("capi_sig: capi_get_cert_handle failed\n"); goto cleanup; } // find the key info from the cert and get a handle if (!CertGetCertificateContextProperty(pCertContext, CERT_KEY_PROV_INFO_PROP_ID, NULL, &ckpi_size)) goto cleanup; if ((ckpi = (CRYPT_KEY_PROV_INFO*) malloc(ckpi_size)) == NULL) goto cleanup; if (!CertGetCertificateContextProperty(pCertContext, CERT_KEY_PROV_INFO_PROP_ID, ckpi, &ckpi_size)) goto cleanup; if (ckpi->dwProvType == 0) { // CNG // eh, later... debuglog("capi_sig_certID: CNG Key, bailing...\n"); goto cleanup; } else { // CAPI if (!CryptAcquireContextW(&hProv, ckpi->pwszContainerName, ckpi->pwszProvName, ckpi->dwProvType, ((ckpi->dwFlags & CRYPT_MACHINE_KEYSET) ? CRYPT_MACHINE_KEYSET : 0) )) { debuglog("capi_sig_certID: Error calling CryptAcquireContext. GetLastError()=%i (0x%08x)\n", GetLastError(), GetLastError()); goto cleanup; } } // create the hash object, set it to SHA-1 and confirm expectations if (!CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hash)) goto cleanup; tmpSize = sizeof(tmpHashLen); if (!CryptGetHashParam(hash, HP_HASHSIZE, (BYTE *) &tmpHashLen, &tmpSize, 0)) goto cleanup; if (tmpHashLen != SHA1_BYTES) goto cleanup; if (!CryptHashData(hash, sigdata, sigdata_len, 0)) goto cleanup; // hash & sign rawsig_len = 0; if (!CryptSignHash(hash, ckpi->dwKeySpec, NULL, 0, NULL, &rawsig_len)) goto cleanup; rawsig = malloc(rawsig_len); if (!CryptSignHash(hash, ckpi->dwKeySpec, NULL, 0, rawsig, &rawsig_len)) goto cleanup; // convert to SSH-style buffer bn = bignum_from_bytes(rawsig, rawsig_len); tmpSize = (bignum_bitcount(bn) + 7) / 8; *sigblob_len = 4 + 7 + 4 + tmpSize; if ((p = retval = calloc(1, *sigblob_len)) == NULL) goto cleanup; CAPI_PUT_32BIT(p, 7); p += 4; memcpy(p, "ssh-rsa", 7); p += 7; CAPI_PUT_32BIT(p, tmpSize); p += 4; for (x = 0; x < tmpSize; x++) *p++ = bignum_byte(bn, x); success = TRUE; cleanup: if (pCertContext) CertFreeCertificateContext(pCertContext); pCertContext = NULL; if (hProv) CryptReleaseContext(hProv, 0); hProv = 0; if (ckpi) free(ckpi); ckpi = NULL; if (hash) CryptDestroyHash(hash); hash = 0; if (rawsig) free(rawsig); rawsig = NULL; if (bn) freebn(bn); bn = NULL; if (!success) { if (retval) free(retval); retval = NULL; } return retval; } unsigned char* capi_sig(struct capi_keyhandle_struct* keyhandle, char *sigdata, int sigdata_len, int *sigblob_len) { BOOL success = FALSE; unsigned char* retval = NULL, *rawsig = NULL, *p; HCRYPTHASH hash = 0; DWORD tmpSize, tmpHashLen, rawsig_len, x; Bignum bn = NULL; debuglog("capi_sig(keyhandle) called. sigdata_len=%d\n", sigdata_len); debuglog_buffer(sigdata, sigdata_len); if (!CryptCreateHash((HCRYPTPROV) keyhandle->win_provider, CALG_SHA1, 0, 0, &hash)) goto cleanup; tmpSize = sizeof(tmpHashLen); if (!CryptGetHashParam(hash, HP_HASHSIZE, (BYTE *) &tmpHashLen, &tmpSize, 0)) goto cleanup; if (tmpHashLen != SHA1_BYTES) goto cleanup; if (!CryptHashData(hash, sigdata, sigdata_len, 0)) goto cleanup; rawsig_len = 0; if (!CryptSignHash(hash, keyhandle->win_keyspec, NULL, 0, NULL, &rawsig_len)) goto cleanup; rawsig = malloc(rawsig_len); if (!CryptSignHash(hash, keyhandle->win_keyspec, NULL, 0, rawsig, &rawsig_len)) goto cleanup; bn = bignum_from_bytes(rawsig, rawsig_len); tmpSize = (bignum_bitcount(bn) + 7) / 8; *sigblob_len = 4 + 7 + 4 + tmpSize; if ((p = retval = calloc(1, *sigblob_len)) == NULL) goto cleanup; CAPI_PUT_32BIT(p, 7); p += 4; memcpy(p, "ssh-rsa", 7); p += 7; CAPI_PUT_32BIT(p, tmpSize); p += 4; for (x = 0; x < tmpSize; x++) *p++ = bignum_byte(bn, x); success = TRUE; cleanup: if (hash) CryptDestroyHash(hash); hash = 0; if (rawsig) free(rawsig); rawsig = NULL; if (bn) freebn(bn); bn = NULL; if (!success) { if (retval) free(retval); retval = NULL; } return retval; } void capi_release_key(struct capi_keyhandle_struct** keyhandle) { if (keyhandle) { if (*keyhandle) { if ((*keyhandle)->win_provider) CryptReleaseContext((HCRYPTPROV) (*keyhandle)->win_provider, 0); (*keyhandle)->win_provider = NULL; if ((*keyhandle)->pubkey) free((*keyhandle)->pubkey); (*keyhandle)->pubkey = NULL; if ((*keyhandle)->algorithm) free((*keyhandle)->algorithm); (*keyhandle)->algorithm = NULL; free(*keyhandle); } *keyhandle = NULL; } return; } struct CAPI_userkey* Create_CAPI_userkey(const char* certID, PCERT_CONTEXT pCertContext) { BOOL success = FALSE; struct CAPI_userkey* retval = NULL; PCERT_CONTEXT LpCertContext = NULL; if (pCertContext == NULL) { if (!capi_get_cert_handle(certID, &LpCertContext)) { debuglog("Create_CAPI_userkey: capi_get_cert_handle failed\n"); goto cleanup; } pCertContext = LpCertContext; } if ((retval = malloc(sizeof(struct CAPI_userkey))) == NULL) { debuglog("Create_CAPI_userkey: malloc for retval failed\n"); goto cleanup; } retval->certID = NULL; retval->blob = NULL; if ((retval->certID = malloc(strlen(certID) + 1)) == NULL) { debuglog("Create_CAPI_userkey: malloc for certID failed\n"); goto cleanup; } strcpy(retval->certID, certID); if (!capi_get_pubkey_blob(pCertContext, &retval->blob, &retval->bloblen)) { debuglog("Create_CAPI_userkey: capi_get_pubkey_blob failed\n"); goto cleanup; } success = TRUE; cleanup: if (LpCertContext) CertFreeCertificateContext(LpCertContext); LpCertContext = NULL; if (!success) { Free_CAPI_userkey(retval); retval = NULL; } return retval; } void Free_CAPI_userkey(struct CAPI_userkey* ckey) { if (ckey->certID) free(ckey->certID); ckey->certID = NULL; if (ckey->blob) free(ckey->blob); ckey->blob = NULL; free(ckey); } char* CAPI_userkey_GetComment(struct CAPI_userkey* ckey) { char *retval = NULL; debuglog("CAPI_userkey_GetComment: called\n"); if ((retval = malloc(5 + strlen(ckey->certID) + 1)) == NULL) { debuglog("CAPI_userkey_GetComment: malloc failed\n"); return NULL; } sprintf(retval, "CAPI:%s", ckey->certID); return retval; } |
Added capi.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | /* * CAPI: Windows Crypto API header file. * Andrew Prout, aprout at ll mit edu */ #ifndef PUTTY_CAPI_H #define PUTTY_CAPI_H #ifdef _WINDOWS struct capi_keyhandle_struct { void* win_provider; char* algorithm; unsigned char* pubkey; unsigned int pubkey_len; unsigned int win_keyspec; }; struct CAPI_userkey { char *certID; // StoreType\StoreName\HexSHA1 unsigned char *blob; int bloblen; }; #define CAPI_userkey_Comment_Length(x) (strlen(x->certID) + 5 /* "CAPI:" */) extern struct ssh2_userkey capi_key_ssh2_userkey; BOOL capi_get_pubkey(void *f, char* certID, unsigned char** pubkey, char **algorithm, int *blob_len); BOOL capi_get_key_handle(void *f, char* certID, struct capi_keyhandle_struct** keyhandle); BOOL capi_display_cert_ui(HWND hwnd, char* certID, WCHAR* title); //BOOL capi_get_cert_handle(char* certID, PCCERT_CONTEXT* oCertContext); unsigned char* capi_sig(struct capi_keyhandle_struct* keyhandle, char *sigdata, int sigdata_len, int *sigblob_len); unsigned char* capi_sig_certID(char* certID, char *sigdata, int sigdata_len, int *sigblob_len); void capi_release_key(struct capi_keyhandle_struct** keyhandle); char* capi_get_key_string(char* certID); char* CAPI_userkey_GetComment(struct CAPI_userkey* ckey); struct CAPI_userkey* Create_CAPI_userkey(const char* certID, CERT_CONTEXT* pCertContext); void Free_CAPI_userkey(struct CAPI_userkey* ckey); #endif //#ifdef _WINDOWS #endif //#ifndef PUTTY_CAPI_H |
Changes to charset/charset.h.
︙ | ︙ | |||
28 29 30 31 32 33 34 | CS_ISO8859_11, CS_ISO8859_13, CS_ISO8859_14, CS_ISO8859_15, CS_ISO8859_16, CS_CP437, CS_CP850, | < | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | CS_ISO8859_11, CS_ISO8859_13, CS_ISO8859_14, CS_ISO8859_15, CS_ISO8859_16, CS_CP437, CS_CP850, CS_CP866, CS_CP1250, CS_CP1251, CS_CP1252, CS_CP1253, CS_CP1254, CS_CP1255, |
︙ | ︙ | |||
95 96 97 98 99 100 101 | * The sequence of `errlen' wide characters pointed to by `errstr' * will be used to indicate a conversion error. If `errstr' is * NULL, `errlen' will be ignored, and the library will choose * something sensible to do on its own. For Unicode, this will be * U+FFFD (REPLACEMENT CHARACTER). */ | < | | 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | * The sequence of `errlen' wide characters pointed to by `errstr' * will be used to indicate a conversion error. If `errstr' is * NULL, `errlen' will be ignored, and the library will choose * something sensible to do on its own. For Unicode, this will be * U+FFFD (REPLACEMENT CHARACTER). */ int charset_to_unicode(char **input, int *inlen, wchar_t *output, int outlen, int charset, charset_state *state, const wchar_t *errstr, int errlen); /* * Routine to convert Unicode to an MB/SB character set. * * This routine accepts some number of Unicode characters, updates |
︙ | ︙ | |||
119 120 121 122 123 124 125 | * The sequence of `errlen' characters pointed to by `errstr' will * be used to indicate a conversion error. If `errstr' is NULL, * `errlen' will be ignored, and the library will choose something * sensible to do on its own (which will vary depending on the * output charset). */ | | < | 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | * The sequence of `errlen' characters pointed to by `errstr' will * be used to indicate a conversion error. If `errstr' is NULL, * `errlen' will be ignored, and the library will choose something * sensible to do on its own (which will vary depending on the * output charset). */ int charset_from_unicode(wchar_t **input, int *inlen, char *output, int outlen, int charset, charset_state *state, const char *errstr, int errlen); /* * Convert X11 encoding names to and from our charset identifiers. */ const char *charset_to_xenc(int charset); |
︙ | ︙ |
Changes to charset/fromucs.c.
︙ | ︙ | |||
36 37 38 39 40 41 42 | outlen--; } } else { param->stopped = 1; } } | | < | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | outlen--; } } else { param->stopped = 1; } } int charset_from_unicode(wchar_t **input, int *inlen, char *output, int outlen, int charset, charset_state *state, const char *errstr, int errlen) { charset_spec const *spec = charset_find_spec(charset); charset_state localstate; struct charset_emit_param param; |
︙ | ︙ |
Changes to charset/localenc.c.
︙ | ︙ | |||
17 18 19 20 21 22 23 | static const struct { const char *name; int charset; int return_in_enum; /* enumeration misses some charsets */ } localencs[] = { { "<UNKNOWN>", CS_NONE, 0 }, | < < | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | static const struct { const char *name; int charset; int return_in_enum; /* enumeration misses some charsets */ } localencs[] = { { "<UNKNOWN>", CS_NONE, 0 }, { "ISO-8859-1", CS_ISO8859_1, 1 }, { "ISO-8859-1 with X11 line drawing", CS_ISO8859_1_X11, 0 }, { "ISO-8859-2", CS_ISO8859_2, 1 }, { "ISO-8859-3", CS_ISO8859_3, 1 }, { "ISO-8859-4", CS_ISO8859_4, 1 }, { "ISO-8859-5", CS_ISO8859_5, 1 }, { "ISO-8859-6", CS_ISO8859_6, 1 }, { "ISO-8859-7", CS_ISO8859_7, 1 }, { "ISO-8859-8", CS_ISO8859_8, 1 }, { "ISO-8859-9", CS_ISO8859_9, 1 }, { "ISO-8859-10", CS_ISO8859_10, 1 }, { "ISO-8859-11", CS_ISO8859_11, 1 }, { "ISO-8859-13", CS_ISO8859_13, 1 }, { "ISO-8859-14", CS_ISO8859_14, 1 }, { "ISO-8859-15", CS_ISO8859_15, 1 }, { "ISO-8859-16", CS_ISO8859_16, 1 }, { "CP437", CS_CP437, 1 }, { "CP850", CS_CP850, 1 }, { "CP866", CS_CP866, 1 }, { "CP1250", CS_CP1250, 1 }, { "CP1251", CS_CP1251, 1 }, { "CP1252", CS_CP1252, 1 }, { "CP1253", CS_CP1253, 1 }, { "CP1254", CS_CP1254, 1 }, { "CP1255", CS_CP1255, 1 }, |
︙ | ︙ | |||
72 73 74 75 76 77 78 79 80 81 82 83 84 85 | { "Mac Cyrillic (old)", CS_MAC_CYRILLIC_OLD, 0 }, { "Mac Ukraine", CS_MAC_UKRAINE, 1 }, { "Mac VT100", CS_MAC_VT100, 1 }, { "Mac VT100 (old)", CS_MAC_VT100_OLD, 0 }, { "VISCII", CS_VISCII, 1 }, { "HP ROMAN8", CS_HP_ROMAN8, 1 }, { "DEC MCS", CS_DEC_MCS, 1 }, }; const char *charset_to_localenc(int charset) { int i; for (i = 0; i < (int)lenof(localencs); i++) | > | 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | { "Mac Cyrillic (old)", CS_MAC_CYRILLIC_OLD, 0 }, { "Mac Ukraine", CS_MAC_UKRAINE, 1 }, { "Mac VT100", CS_MAC_VT100, 1 }, { "Mac VT100 (old)", CS_MAC_VT100_OLD, 0 }, { "VISCII", CS_VISCII, 1 }, { "HP ROMAN8", CS_HP_ROMAN8, 1 }, { "DEC MCS", CS_DEC_MCS, 1 }, { "UTF-8", CS_UTF8, 1 }, }; const char *charset_to_localenc(int charset) { int i; for (i = 0; i < (int)lenof(localencs); i++) |
︙ | ︙ |
Changes to charset/mimeenc.c.
︙ | ︙ | |||
131 132 133 134 135 136 137 | { "csPC8CodePage437", CS_CP437 }, { "IBM850", CS_CP850 }, { "cp850", CS_CP850 }, { "850", CS_CP850 }, { "csPC850Multilingual", CS_CP850 }, | < < < < < | 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | { "csPC8CodePage437", CS_CP437 }, { "IBM850", CS_CP850 }, { "cp850", CS_CP850 }, { "850", CS_CP850 }, { "csPC850Multilingual", CS_CP850 }, { "IBM866", CS_CP866 }, { "cp866", CS_CP866 }, { "866", CS_CP866 }, { "csIBM866", CS_CP866 }, { "windows-1250", CS_CP1250 }, |
︙ | ︙ |
Changes to charset/sbcs.dat.
︙ | ︙ | |||
390 391 392 393 394 395 396 | 0430 0431 0432 0433 0434 0435 0436 0437 0438 0439 043a 043b 043c 043d 043e 043f 2591 2592 2593 2502 2524 2561 2562 2556 2555 2563 2551 2557 255d 255c 255b 2510 2514 2534 252c 251c 2500 253c 255e 255f 255a 2554 2569 2566 2560 2550 256c 2567 2568 2564 2565 2559 2558 2552 2553 256b 256a 2518 250c 2588 2584 258c 2590 2580 0440 0441 0442 0443 0444 0445 0446 0447 0448 0449 044a 044b 044c 044d 044e 044f 0401 0451 0404 0454 0407 0457 040e 045e 00b0 2219 00b7 221a 2116 00a4 25a0 00a0 | < < < < < < < < < < < < < < < < < < < < < < | 390 391 392 393 394 395 396 397 398 399 400 401 402 403 | 0430 0431 0432 0433 0434 0435 0436 0437 0438 0439 043a 043b 043c 043d 043e 043f 2591 2592 2593 2502 2524 2561 2562 2556 2555 2563 2551 2557 255d 255c 255b 2510 2514 2534 252c 251c 2500 253c 255e 255f 255a 2554 2569 2566 2560 2550 256c 2567 2568 2564 2565 2559 2558 2552 2553 256b 256a 2518 250c 2588 2584 258c 2590 2580 0440 0441 0442 0443 0444 0445 0446 0447 0448 0449 044a 044b 044c 044d 044e 044f 0401 0451 0404 0454 0407 0457 040e 045e 00b0 2219 00b7 221a 2116 00a4 25a0 00a0 Here are some Windows code pages, generated by this piece of Bourne shell: for i in 1250 1251 1252 1253 1254 1255 1256 1257 1258; do echo charset CS_CP$i gensbcs http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP$i.TXT echo |
︙ | ︙ |
Changes to charset/toucs.c.
︙ | ︙ | |||
42 43 44 45 46 47 48 | outlen--; } } else { param->stopped = 1; } } | < | | 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | outlen--; } } else { param->stopped = 1; } } int charset_to_unicode(char **input, int *inlen, wchar_t *output, int outlen, int charset, charset_state *state, const wchar_t *errstr, int errlen) { charset_spec const *spec = charset_find_spec(charset); charset_state localstate; struct unicode_emit_param param; |
︙ | ︙ |
Changes to charset/xenc.c.
︙ | ︙ | |||
42 43 44 45 46 47 48 | /* * Unofficial encoding names found in the wild. */ { "iso8859-16", CS_ISO8859_16 }, { "koi8-u", CS_KOI8_U }, { "ibm-cp437", CS_CP437 }, { "ibm-cp850", CS_CP850 }, | < | 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | /* * Unofficial encoding names found in the wild. */ { "iso8859-16", CS_ISO8859_16 }, { "koi8-u", CS_KOI8_U }, { "ibm-cp437", CS_CP437 }, { "ibm-cp850", CS_CP850 }, { "ibm-cp866", CS_CP866 }, { "microsoft-cp1250", CS_CP1250 }, { "microsoft-cp1251", CS_CP1251 }, { "microsoft-cp1252", CS_CP1252 }, { "microsoft-cp1253", CS_CP1253 }, { "microsoft-cp1254", CS_CP1254 }, { "microsoft-cp1255", CS_CP1255 }, |
︙ | ︙ |
Changes to cmdgen.c.
︙ | ︙ | |||
98 99 100 101 102 103 104 | va_start(ap, p); vfprintf(stderr, p, ap); va_end(ap); fputc('\n', stderr); cleanup_exit(1); } | < < < < < < < < < < > > | > | 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | va_start(ap, p); vfprintf(stderr, p, ap); va_end(ap); fputc('\n', stderr); cleanup_exit(1); } /* * Stubs to let everything else link sensibly. */ void log_eventlog(void *handle, const char *event) { } char *x_get_default(const char *key) { return NULL; } void sk_cleanup(void) { } void showversion(void) { char *verstr = dupstr(ver); verstr[0] = tolower((unsigned char)verstr[0]); printf("PuTTYgen %s\n", verstr); sfree(verstr); } void usage(int standalone) { fprintf(stderr, "Usage: puttygen ( keyfile | -t type [ -b bits ] )\n" " [ -C comment ] [ -P ] [ -q ]\n" |
︙ | ︙ | |||
260 261 262 263 264 265 266 | return dupstr(buffer); } int main(int argc, char **argv) { char *infile = NULL; | | > | | 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 | return dupstr(buffer); } int main(int argc, char **argv) { char *infile = NULL; Filename infilename; enum { NOKEYGEN, RSA1, RSA2, DSA } keytype = NOKEYGEN; char *outfile = NULL, *outfiletmp = NULL; Filename outfilename; enum { PRIVATE, PUBLIC, PUBLICO, FP, OPENSSH, SSHCOM } outtype = PRIVATE; int bits = 1024; char *comment = NULL, *origcomment = NULL; int change_passphrase = FALSE; int errs = FALSE, nogo = FALSE; int intype = SSH_KEYTYPE_UNOPENABLE; int sshver = 0; struct ssh2_userkey *ssh2key = NULL; struct RSAKey *ssh1key = NULL; |
︙ | ︙ | |||
538 539 540 541 542 543 544 | /* * Analyse the type of the input file, in case this affects our * course of action. */ if (infile) { infilename = filename_from_str(infile); | | | 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 | /* * Analyse the type of the input file, in case this affects our * course of action. */ if (infile) { infilename = filename_from_str(infile); intype = key_type(&infilename); switch (intype) { /* * It would be nice here to be able to load _public_ * key files, in any of a number of forms, and (a) * convert them to other public key types, (b) print * out their fingerprints. Or, I suppose, for real |
︙ | ︙ | |||
670 671 672 673 674 675 676 | entropy = get_random_data(bits / 8); if (!entropy) { fprintf(stderr, "puttygen: failed to collect entropy, " "could not generate key\n"); return 1; } random_add_heavynoise(entropy, bits / 8); | | | 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 | entropy = get_random_data(bits / 8); if (!entropy) { fprintf(stderr, "puttygen: failed to collect entropy, " "could not generate key\n"); return 1; } random_add_heavynoise(entropy, bits / 8); memset(entropy, 0, bits/8); sfree(entropy); if (keytype == DSA) { struct dss_key *dsskey = snew(struct dss_key); dsa_generate(dsskey, bits, progressfn, &prog); ssh2key = snew(struct ssh2_userkey); ssh2key->data = dsskey; |
︙ | ︙ | |||
709 710 711 712 713 714 715 | assert(infile != NULL); /* * Find out whether the input key is encrypted. */ if (intype == SSH_KEYTYPE_SSH1) | | | | | | 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 | assert(infile != NULL); /* * Find out whether the input key is encrypted. */ if (intype == SSH_KEYTYPE_SSH1) encrypted = rsakey_encrypted(&infilename, &origcomment); else if (intype == SSH_KEYTYPE_SSH2) encrypted = ssh2_userkey_encrypted(&infilename, &origcomment); else encrypted = import_encrypted(&infilename, intype, &origcomment); /* * If so, ask for a passphrase. */ if (encrypted && load_encrypted) { prompts_t *p = new_prompts(NULL); int ret; p->to_server = FALSE; p->name = dupstr("SSH key passphrase"); add_prompt(p, dupstr("Enter passphrase to load key: "), FALSE, 512); ret = console_get_userpass_input(p, NULL, 0); assert(ret >= 0); if (!ret) { free_prompts(p); perror("puttygen: unable to read passphrase"); return 1; } else { |
︙ | ︙ | |||
748 749 750 751 752 753 754 | case SSH_KEYTYPE_SSH1: ssh1key = snew(struct RSAKey); if (!load_encrypted) { void *vblob; unsigned char *blob; int n, l, bloblen; | | < < < | | < | | | | | < | | | 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 | case SSH_KEYTYPE_SSH1: ssh1key = snew(struct RSAKey); if (!load_encrypted) { void *vblob; unsigned char *blob; int n, l, bloblen; ret = rsakey_pubblob(&infilename, &vblob, &bloblen, &origcomment, &error); blob = (unsigned char *)vblob; n = 4; /* skip modulus bits */ l = ssh1_read_bignum(blob + n, bloblen - n, &ssh1key->exponent); if (l < 0) { error = "SSH-1 public key blob was too short"; } else { n += l; l = ssh1_read_bignum(blob + n, bloblen - n, &ssh1key->modulus); if (l < 0) { error = "SSH-1 public key blob was too short"; } else n += l; } ssh1key->comment = dupstr(origcomment); ssh1key->private_exponent = NULL; } else { ret = loadrsakey(&infilename, ssh1key, passphrase, &error); } if (ret > 0) error = NULL; else if (!error) error = "unknown error"; break; case SSH_KEYTYPE_SSH2: if (!load_encrypted) { ssh2blob = ssh2_userkey_loadpub(&infilename, &ssh2alg, &ssh2bloblen, NULL, &error); ssh2algf = find_pubkey_alg(ssh2alg); if (ssh2algf) bits = ssh2algf->pubkey_bits(ssh2blob, ssh2bloblen); else bits = -1; } else { ssh2key = ssh2_load_userkey(&infilename, passphrase, &error); } if ((ssh2key && ssh2key != SSH2_WRONG_PASSPHRASE) || ssh2blob) error = NULL; else if (!error) { if (ssh2key == SSH2_WRONG_PASSPHRASE) error = "wrong passphrase"; else error = "unknown error"; } break; case SSH_KEYTYPE_OPENSSH: case SSH_KEYTYPE_SSHCOM: ssh2key = import_ssh2(&infilename, intype, passphrase, &error); if (ssh2key) { if (ssh2key != SSH2_WRONG_PASSPHRASE) error = NULL; else error = "wrong passphrase"; } else if (!error) error = "unknown error"; |
︙ | ︙ | |||
853 854 855 856 857 858 859 | */ if (change_passphrase || keytype != NOKEYGEN) { prompts_t *p = new_prompts(NULL); int ret; p->to_server = FALSE; p->name = dupstr("New SSH key passphrase"); | | | | | 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 | */ if (change_passphrase || keytype != NOKEYGEN) { prompts_t *p = new_prompts(NULL); int ret; p->to_server = FALSE; p->name = dupstr("New SSH key passphrase"); add_prompt(p, dupstr("Enter passphrase to save key: "), FALSE, 512); add_prompt(p, dupstr("Re-enter passphrase to verify: "), FALSE, 512); ret = console_get_userpass_input(p, NULL, 0); assert(ret >= 0); if (!ret) { free_prompts(p); perror("puttygen: unable to read new passphrase"); return 1; } else { if (strcmp(p->prompts[0]->result, p->prompts[1]->result)) { free_prompts(p); fprintf(stderr, "puttygen: passphrases do not match\n"); return 1; } if (passphrase) { memset(passphrase, 0, strlen(passphrase)); sfree(passphrase); } passphrase = dupstr(p->prompts[0]->result); free_prompts(p); if (!*passphrase) { sfree(passphrase); passphrase = NULL; |
︙ | ︙ | |||
899 900 901 902 903 904 905 | switch (outtype) { int ret; case PRIVATE: if (sshver == 1) { assert(ssh1key); | | | | 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 | switch (outtype) { int ret; case PRIVATE: if (sshver == 1) { assert(ssh1key); ret = saversakey(&outfilename, ssh1key, passphrase); if (!ret) { fprintf(stderr, "puttygen: unable to save SSH-1 private key\n"); return 1; } } else { assert(ssh2key); ret = ssh2_save_userkey(&outfilename, ssh2key, passphrase); if (!ret) { fprintf(stderr, "puttygen: unable to save SSH-2 private key\n"); return 1; } } if (outfiletmp) { if (!move(outfiletmp, outfile)) |
︙ | ︙ | |||
1030 1031 1032 1033 1034 1035 1036 | } break; case OPENSSH: case SSHCOM: assert(sshver == 2); assert(ssh2key); | | | | 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 | } break; case OPENSSH: case SSHCOM: assert(sshver == 2); assert(ssh2key); ret = export_ssh2(&outfilename, outtype, ssh2key, passphrase); if (!ret) { fprintf(stderr, "puttygen: unable to export key\n"); return 1; } if (outfiletmp) { if (!move(outfiletmp, outfile)) return 1; /* rename failed */ } break; } if (passphrase) { memset(passphrase, 0, strlen(passphrase)); sfree(passphrase); } if (ssh1key) freersakey(ssh1key); if (ssh2key) { ssh2key->alg->freekey(ssh2key->data); |
︙ | ︙ |
Changes to cmdline.c.
︙ | ︙ | |||
59 60 61 62 63 64 65 | static char *cmdline_password = NULL; void cmdline_cleanup(void) { int pri; if (cmdline_password) { | | | 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | static char *cmdline_password = NULL; void cmdline_cleanup(void) { int pri; if (cmdline_password) { memset(cmdline_password, 0, strlen(cmdline_password)); sfree(cmdline_password); cmdline_password = NULL; } for (pri = 0; pri < NPRIORITIES; pri++) { sfree(saves[pri].params); saves[pri].params = NULL; |
︙ | ︙ | |||
101 102 103 104 105 106 107 | /* * If we've tried once, return utter failure (no more passwords left * to try). */ if (tried_once) return 0; | | > > | > | 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | /* * If we've tried once, return utter failure (no more passwords left * to try). */ if (tried_once) return 0; strncpy(p->prompts[0]->result, cmdline_password, p->prompts[0]->result_len); p->prompts[0]->result[p->prompts[0]->result_len-1] = '\0'; memset(cmdline_password, 0, strlen(cmdline_password)); sfree(cmdline_password); cmdline_password = NULL; tried_once = 1; return 1; } /* * Here we have a flags word which describes the capabilities of * the particular tool on whose behalf we're running. We will * refuse certain command-line options if a particular tool * inherently can't do anything sensible. For example, the file |
︙ | ︙ | |||
155 156 157 158 159 160 161 | #define RETURN(x) do { \ if ((x) == 2 && !value) return -2; \ ret = x; \ if (need_save < 0) return x; \ } while (0) | | | | | < < | | < < | | < < | < | < | < | > | > | > | > | > > > > > > > > > > > > > > > > > < < < < < < < < < < | | < < < < | | < < < < < < < < < < < < < < < | < < > | > > | > > > > > > > < < < < < | > < | | | | | | | | | | | | | | | | | | | < | < < | | | > > | > > > > > > > > | | | | | | | | | | | | | | | 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 | #define RETURN(x) do { \ if ((x) == 2 && !value) return -2; \ ret = x; \ if (need_save < 0) return x; \ } while (0) int cmdline_process_param(char *p, char *value, int need_save, Config *cfg) { int ret = 0; if (!strcmp(p, "-load")) { RETURN(2); /* This parameter must be processed immediately rather than being * saved. */ do_defaults(value, cfg); loaded_session = TRUE; cmdline_session_name = dupstr(value); return 2; } if (!strcmp(p, "-ssh")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); SAVEABLE(0); default_protocol = cfg->protocol = PROT_SSH; default_port = cfg->port = 22; return 1; } if (!strcmp(p, "-telnet")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); SAVEABLE(0); default_protocol = cfg->protocol = PROT_TELNET; default_port = cfg->port = 23; return 1; } if (!strcmp(p, "-rlogin")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); SAVEABLE(0); default_protocol = cfg->protocol = PROT_RLOGIN; default_port = cfg->port = 513; return 1; } if (!strcmp(p, "-raw")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); SAVEABLE(0); default_protocol = cfg->protocol = PROT_RAW; } if (!strcmp(p, "-serial")) { RETURN(1); /* Serial is not NONNETWORK in an odd sense of the word */ UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); SAVEABLE(0); default_protocol = cfg->protocol = PROT_SERIAL; /* The host parameter will already be loaded into cfg->host, so copy it across */ strncpy(cfg->serline, cfg->host, sizeof(cfg->serline) - 1); cfg->serline[sizeof(cfg->serline) - 1] = '\0'; } if (!strcmp(p, "-v")) { RETURN(1); flags |= FLAG_VERBOSE; } if (!strcmp(p, "-l")) { RETURN(2); UNAVAILABLE_IN(TOOLTYPE_NONNETWORK); SAVEABLE(0); strncpy(cfg->username, value, sizeof(cfg->username)); cfg->username[sizeof(cfg->username) - 1] = '\0'; } if (!strcmp(p, "-loghost")) { RETURN(2); UNAVAILABLE_IN(TOOLTYPE_NONNETWORK); SAVEABLE(0); strncpy(cfg->loghost, value, sizeof(cfg->loghost)); cfg->loghost[sizeof(cfg->loghost) - 1] = '\0'; } if ((!strcmp(p, "-L") || !strcmp(p, "-R") || !strcmp(p, "-D"))) { char *fwd, *ptr, *q, *qq; int dynamic, i=0; RETURN(2); UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); SAVEABLE(0); dynamic = !strcmp(p, "-D"); fwd = value; ptr = cfg->portfwd; /* if existing forwards, find end of list */ while (*ptr) { while (*ptr) ptr++; ptr++; } i = ptr - cfg->portfwd; ptr[0] = p[1]; /* insert a 'L', 'R' or 'D' at the start */ ptr++; if (1 + strlen(fwd) + 2 > sizeof(cfg->portfwd) - i) { cmdline_error("out of space for port forwardings"); return ret; } strncpy(ptr, fwd, sizeof(cfg->portfwd) - i - 2); if (!dynamic) { /* * We expect _at least_ two colons in this string. The * possible formats are `sourceport:desthost:destport', * or `sourceip:sourceport:desthost:destport' if you're * specifying a particular loopback address. We need to * replace the one between source and dest with a \t; * this means we must find the second-to-last colon in * the string. */ q = qq = strchr(ptr, ':'); while (qq) { char *qqq = strchr(qq+1, ':'); if (qqq) q = qq; qq = qqq; } if (q) *q = '\t'; /* replace second-last colon with \t */ } cfg->portfwd[sizeof(cfg->portfwd) - 1] = '\0'; cfg->portfwd[sizeof(cfg->portfwd) - 2] = '\0'; ptr[strlen(ptr)+1] = '\000'; /* append 2nd '\000' */ } if ((!strcmp(p, "-nc"))) { char *host, *portp; RETURN(2); UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); SAVEABLE(0); host = portp = value; while (*portp && *portp != ':') portp++; if (*portp) { unsigned len = portp - host; if (len >= sizeof(cfg->ssh_nc_host)) len = sizeof(cfg->ssh_nc_host) - 1; memcpy(cfg->ssh_nc_host, value, len); cfg->ssh_nc_host[len] = '\0'; cfg->ssh_nc_port = atoi(portp+1); } else { cmdline_error("-nc expects argument of form 'host:port'"); return ret; } } if (!strcmp(p, "-m")) { char *filename, *command; int cmdlen, cmdsize; FILE *fp; int c, d; RETURN(2); UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); SAVEABLE(0); filename = value; cmdlen = cmdsize = 0; command = NULL; fp = fopen(filename, "r"); if (!fp) { cmdline_error("unable to open command " "file \"%s\"", filename); return ret; } do { c = fgetc(fp); d = c; if (c == EOF) d = 0; if (cmdlen >= cmdsize) { cmdsize = cmdlen + 512; command = sresize(command, cmdsize, char); } command[cmdlen++] = d; } while (c != EOF); cfg->remote_cmd_ptr = command; cfg->remote_cmd_ptr2 = NULL; cfg->nopty = TRUE; /* command => no terminal */ fclose(fp); } if (!strcmp(p, "-P")) { RETURN(2); UNAVAILABLE_IN(TOOLTYPE_NONNETWORK); SAVEABLE(1); /* lower priority than -ssh,-telnet */ cfg->port = atoi(value); } if (!strcmp(p, "-pw")) { RETURN(2); UNAVAILABLE_IN(TOOLTYPE_NONNETWORK); SAVEABLE(1); /* We delay evaluating this until after the protocol is decided, * so that we can warn if it's of no use with the selected protocol */ if (cfg->protocol != PROT_SSH) cmdline_error("the -pw option can only be used with the " "SSH protocol"); else { cmdline_password = dupstr(value); /* Assuming that `value' is directly from argv, make a good faith * attempt to trample it, to stop it showing up in `ps' output * on Unix-like systems. Not guaranteed, of course. */ memset(value, 0, strlen(value)); } } if (!strcmp(p, "-agent") || !strcmp(p, "-pagent") || !strcmp(p, "-pageant")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_NONNETWORK); SAVEABLE(0); cfg->tryagent = TRUE; } if (!strcmp(p, "-noagent") || !strcmp(p, "-nopagent") || !strcmp(p, "-nopageant")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_NONNETWORK); SAVEABLE(0); cfg->tryagent = FALSE; } if (!strcmp(p, "-A")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); SAVEABLE(0); cfg->agentfwd = 1; } if (!strcmp(p, "-a")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); SAVEABLE(0); cfg->agentfwd = 0; } if (!strcmp(p, "-X")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); SAVEABLE(0); cfg->x11_forward = 1; } if (!strcmp(p, "-x")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); SAVEABLE(0); cfg->x11_forward = 0; } if (!strcmp(p, "-t")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); SAVEABLE(1); /* lower priority than -m */ cfg->nopty = 0; } if (!strcmp(p, "-T")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); SAVEABLE(1); cfg->nopty = 1; } if (!strcmp(p, "-N")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); SAVEABLE(0); cfg->ssh_no_shell = 1; } if (!strcmp(p, "-C")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_NONNETWORK); SAVEABLE(0); cfg->compression = 1; } if (!strcmp(p, "-1")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_NONNETWORK); SAVEABLE(0); cfg->sshprot = 0; /* ssh protocol 1 only */ } if (!strcmp(p, "-2")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_NONNETWORK); SAVEABLE(0); cfg->sshprot = 3; /* ssh protocol 2 only */ } if (!strcmp(p, "-i")) { RETURN(2); UNAVAILABLE_IN(TOOLTYPE_NONNETWORK); SAVEABLE(0); cfg->keyfile = filename_from_str(value); } if (!strcmp(p, "-4") || !strcmp(p, "-ipv4")) { RETURN(1); SAVEABLE(1); cfg->addressfamily = ADDRTYPE_IPV4; } if (!strcmp(p, "-6") || !strcmp(p, "-ipv6")) { RETURN(1); SAVEABLE(1); cfg->addressfamily = ADDRTYPE_IPV6; } if (!strcmp(p, "-sercfg")) { char* nextitem; RETURN(2); UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); SAVEABLE(1); if (cfg->protocol != PROT_SERIAL) cmdline_error("the -sercfg option can only be used with the " "serial protocol"); /* Value[0] contains one or more , separated values, like 19200,8,n,1,X */ nextitem = value; while (nextitem[0] != '\0') { int length, skip; char *end = strchr(nextitem, ','); if (!end) { length = strlen(nextitem); skip = 0; } else { length = end - nextitem; nextitem[length] = '\0'; skip = 1; } if (length == 1) { switch (*nextitem) { case '1': cfg->serstopbits = 2; break; case '2': cfg->serstopbits = 4; break; case '5': cfg->serdatabits = 5; break; case '6': cfg->serdatabits = 6; break; case '7': cfg->serdatabits = 7; break; case '8': cfg->serdatabits = 8; break; case '9': cfg->serdatabits = 9; break; case 'n': cfg->serparity = SER_PAR_NONE; break; case 'o': cfg->serparity = SER_PAR_ODD; break; case 'e': cfg->serparity = SER_PAR_EVEN; break; case 'm': cfg->serparity = SER_PAR_MARK; break; case 's': cfg->serparity = SER_PAR_SPACE; break; case 'N': cfg->serflow = SER_FLOW_NONE; break; case 'X': cfg->serflow = SER_FLOW_XONXOFF; break; case 'R': cfg->serflow = SER_FLOW_RTSCTS; break; case 'D': cfg->serflow = SER_FLOW_DSRDTR; break; default: cmdline_error("Unrecognised suboption \"-sercfg %c\"", *nextitem); } } else if (length == 3 && !strncmp(nextitem,"1.5",3)) { /* Messy special case */ cfg->serstopbits = 3; } else { int serspeed = atoi(nextitem); if (serspeed != 0) { cfg->serspeed = serspeed; } else { cmdline_error("Unrecognised suboption \"-sercfg %s\"", nextitem); } } nextitem += length + skip; } } return ret; /* unrecognised */ } void cmdline_run_saved(Config *cfg) { int pri, i; for (pri = 0; pri < NPRIORITIES; pri++) for (i = 0; i < saves[pri].nsaved; i++) cmdline_process_param(saves[pri].params[i].p, saves[pri].params[i].value, 0, cfg); } |
Deleted conf.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to config.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | /* * config.c - the platform-independent parts of the PuTTY * configuration box. */ #include <assert.h> #include <stdlib.h> #include "putty.h" #include "dialog.h" #include "storage.h" #define PRINTER_DISABLED_STRING "None (printing disabled)" #define HOST_BOX_TITLE "Host Name (or IP address)" #define PORT_BOX_TITLE "Port" | > > > > > > > > > > > > > > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | < | | | < | | | | | | < < < | | | | < | | < < | < < | | < | | | < < | | | | | | | | | | | | | | | | | | | < | > | | < | | | < | > | < | | | < | | < < | | | < | | > | | < < < < < < < < < | | > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > | > > > > | > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | > > > > > > > > > > > > > > > | | > > > | > > > | | | > | > > > > > > > > > > > > > > > > > | < | > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 | /* * config.c - the platform-independent parts of the PuTTY * configuration box. */ #include <assert.h> #include <stdlib.h> #include "putty.h" #include "dialog.h" #include "storage.h" /* PuTTY SC start */ #include "pkcs11.h" #include "sc.h" /* PuTTY SC end */ /* PuTTY CAPI start */ #ifdef _WINDOWS #include "capi.h" #include <Specstrings.h> #include <Wincrypt.h> #include <CryptDlg.h> #endif /* PuTTY CAPI end */ #define PRINTER_DISABLED_STRING "None (printing disabled)" #define HOST_BOX_TITLE "Host Name (or IP address)" #define PORT_BOX_TITLE "Port" static void config_host_handler(union control *ctrl, void *dlg, void *data, int event) { Config *cfg = (Config *)data; /* * This function works just like the standard edit box handler, * only it has to choose the control's label and text from two * different places depending on the protocol. */ if (event == EVENT_REFRESH) { if (cfg->protocol == PROT_SERIAL) { /* * This label text is carefully chosen to contain an n, * since that's the shortcut for the host name control. */ dlg_label_change(ctrl, dlg, "Serial line"); dlg_editbox_set(ctrl, dlg, cfg->serline); } else { dlg_label_change(ctrl, dlg, HOST_BOX_TITLE); dlg_editbox_set(ctrl, dlg, cfg->host); } } else if (event == EVENT_VALCHANGE) { if (cfg->protocol == PROT_SERIAL) dlg_editbox_get(ctrl, dlg, cfg->serline, lenof(cfg->serline)); else dlg_editbox_get(ctrl, dlg, cfg->host, lenof(cfg->host)); } } static void config_port_handler(union control *ctrl, void *dlg, void *data, int event) { Config *cfg = (Config *)data; char buf[80]; /* * This function works similarly to the standard edit box handler, * only it has to choose the control's label and text from two * different places depending on the protocol. */ if (event == EVENT_REFRESH) { if (cfg->protocol == PROT_SERIAL) { /* * This label text is carefully chosen to contain a p, * since that's the shortcut for the port control. */ dlg_label_change(ctrl, dlg, "Speed"); sprintf(buf, "%d", cfg->serspeed); } else { dlg_label_change(ctrl, dlg, PORT_BOX_TITLE); if (cfg->port != 0) sprintf(buf, "%d", cfg->port); else /* Display an (invalid) port of 0 as blank */ buf[0] = '\0'; } dlg_editbox_set(ctrl, dlg, buf); } else if (event == EVENT_VALCHANGE) { dlg_editbox_get(ctrl, dlg, buf, lenof(buf)); if (cfg->protocol == PROT_SERIAL) cfg->serspeed = atoi(buf); else cfg->port = atoi(buf); } } struct hostport { union control *host, *port; }; /* * We export this function so that platform-specific config * routines can use it to conveniently identify the protocol radio * buttons in order to add to them. */ void config_protocolbuttons_handler(union control *ctrl, void *dlg, void *data, int event) { int button; Config *cfg = (Config *)data; struct hostport *hp = (struct hostport *)ctrl->radio.context.p; /* * This function works just like the standard radio-button * handler, except that it also has to change the setting of * the port box, and refresh both host and port boxes when. We * expect the context parameter to point at a hostport * structure giving the `union control's for both. */ if (event == EVENT_REFRESH) { for (button = 0; button < ctrl->radio.nbuttons; button++) if (cfg->protocol == ctrl->radio.buttondata[button].i) break; /* We expected that `break' to happen, in all circumstances. */ assert(button < ctrl->radio.nbuttons); dlg_radiobutton_set(ctrl, dlg, button); } else if (event == EVENT_VALCHANGE) { int oldproto = cfg->protocol; button = dlg_radiobutton_get(ctrl, dlg); assert(button >= 0 && button < ctrl->radio.nbuttons); cfg->protocol = ctrl->radio.buttondata[button].i; if (oldproto != cfg->protocol) { Backend *ob = backend_from_proto(oldproto); Backend *nb = backend_from_proto(cfg->protocol); assert(ob); assert(nb); /* Iff the user hasn't changed the port from the old protocol's * default, update it with the new protocol's default. * (This includes a "default" of 0, implying that there is no * sensible default for that protocol; in this case it's * displayed as a blank.) * This helps with the common case of tabbing through the * controls in order and setting a non-default port before * getting to the protocol; we want that non-default port * to be preserved. */ if (cfg->port == ob->default_port) cfg->port = nb->default_port; } dlg_refresh(hp->host, dlg); dlg_refresh(hp->port, dlg); } } static void loggingbuttons_handler(union control *ctrl, void *dlg, void *data, int event) { int button; Config *cfg = (Config *)data; /* This function works just like the standard radio-button handler, * but it has to fall back to "no logging" in situations where the * configured logging type isn't applicable. */ if (event == EVENT_REFRESH) { for (button = 0; button < ctrl->radio.nbuttons; button++) if (cfg->logtype == ctrl->radio.buttondata[button].i) break; /* We fell off the end, so we lack the configured logging type */ if (button == ctrl->radio.nbuttons) { button=0; cfg->logtype=LGTYP_NONE; } dlg_radiobutton_set(ctrl, dlg, button); } else if (event == EVENT_VALCHANGE) { button = dlg_radiobutton_get(ctrl, dlg); assert(button >= 0 && button < ctrl->radio.nbuttons); cfg->logtype = ctrl->radio.buttondata[button].i; } } static void numeric_keypad_handler(union control *ctrl, void *dlg, void *data, int event) { int button; Config *cfg = (Config *)data; /* * This function works much like the standard radio button * handler, but it has to handle two fields in Config. */ if (event == EVENT_REFRESH) { if (cfg->nethack_keypad) button = 2; else if (cfg->app_keypad) button = 1; else button = 0; assert(button < ctrl->radio.nbuttons); dlg_radiobutton_set(ctrl, dlg, button); } else if (event == EVENT_VALCHANGE) { button = dlg_radiobutton_get(ctrl, dlg); assert(button >= 0 && button < ctrl->radio.nbuttons); if (button == 2) { cfg->app_keypad = FALSE; cfg->nethack_keypad = TRUE; } else { cfg->app_keypad = (button != 0); cfg->nethack_keypad = FALSE; } } } static void cipherlist_handler(union control *ctrl, void *dlg, void *data, int event) { Config *cfg = (Config *)data; if (event == EVENT_REFRESH) { int i; static const struct { char *s; int c; } ciphers[] = { { "3DES", CIPHER_3DES }, { "Blowfish", CIPHER_BLOWFISH }, { "DES", CIPHER_DES }, { "AES (SSH-2 only)", CIPHER_AES }, { "Arcfour (SSH-2 only)", CIPHER_ARCFOUR }, { "-- warn below here --", CIPHER_WARN } }; /* Set up the "selected ciphers" box. */ /* (cipherlist assumed to contain all ciphers) */ dlg_update_start(ctrl, dlg); dlg_listbox_clear(ctrl, dlg); for (i = 0; i < CIPHER_MAX; i++) { int c = cfg->ssh_cipherlist[i]; int j; char *cstr = NULL; for (j = 0; j < (sizeof ciphers) / (sizeof ciphers[0]); j++) { if (ciphers[j].c == c) { cstr = ciphers[j].s; break; } } dlg_listbox_addwithid(ctrl, dlg, cstr, c); } dlg_update_done(ctrl, dlg); } else if (event == EVENT_VALCHANGE) { int i; /* Update array to match the list box. */ for (i=0; i < CIPHER_MAX; i++) cfg->ssh_cipherlist[i] = dlg_listbox_getid(ctrl, dlg, i); } } #ifndef NO_GSSAPI static void gsslist_handler(union control *ctrl, void *dlg, void *data, int event) { Config *cfg = (Config *)data; if (event == EVENT_REFRESH) { int i; dlg_update_start(ctrl, dlg); dlg_listbox_clear(ctrl, dlg); for (i = 0; i < ngsslibs; i++) { int id = cfg->ssh_gsslist[i]; assert(id >= 0 && id < ngsslibs); dlg_listbox_addwithid(ctrl, dlg, gsslibnames[id], id); } dlg_update_done(ctrl, dlg); } else if (event == EVENT_VALCHANGE) { int i; /* Update array to match the list box. */ for (i=0; i < ngsslibs; i++) cfg->ssh_gsslist[i] = dlg_listbox_getid(ctrl, dlg, i); } } #endif static void kexlist_handler(union control *ctrl, void *dlg, void *data, int event) { Config *cfg = (Config *)data; if (event == EVENT_REFRESH) { int i; static const struct { char *s; int k; } kexes[] = { { "Diffie-Hellman group 1", KEX_DHGROUP1 }, { "Diffie-Hellman group 14", KEX_DHGROUP14 }, { "Diffie-Hellman group exchange", KEX_DHGEX }, { "RSA-based key exchange", KEX_RSA }, { "-- warn below here --", KEX_WARN } }; /* Set up the "kex preference" box. */ /* (kexlist assumed to contain all algorithms) */ dlg_update_start(ctrl, dlg); dlg_listbox_clear(ctrl, dlg); for (i = 0; i < KEX_MAX; i++) { int k = cfg->ssh_kexlist[i]; int j; char *kstr = NULL; for (j = 0; j < (sizeof kexes) / (sizeof kexes[0]); j++) { if (kexes[j].k == k) { kstr = kexes[j].s; break; } } dlg_listbox_addwithid(ctrl, dlg, kstr, k); } dlg_update_done(ctrl, dlg); } else if (event == EVENT_VALCHANGE) { int i; /* Update array to match the list box. */ for (i=0; i < KEX_MAX; i++) cfg->ssh_kexlist[i] = dlg_listbox_getid(ctrl, dlg, i); } } static void printerbox_handler(union control *ctrl, void *dlg, void *data, int event) { Config *cfg = (Config *)data; if (event == EVENT_REFRESH) { int nprinters, i; printer_enum *pe; dlg_update_start(ctrl, dlg); /* * Some backends may wish to disable the drop-down list on * this edit box. Be prepared for this. */ if (ctrl->editbox.has_list) { dlg_listbox_clear(ctrl, dlg); dlg_listbox_add(ctrl, dlg, PRINTER_DISABLED_STRING); pe = printer_start_enum(&nprinters); for (i = 0; i < nprinters; i++) dlg_listbox_add(ctrl, dlg, printer_get_name(pe, i)); printer_finish_enum(pe); } dlg_editbox_set(ctrl, dlg, (*cfg->printer ? cfg->printer : PRINTER_DISABLED_STRING)); dlg_update_done(ctrl, dlg); } else if (event == EVENT_VALCHANGE) { dlg_editbox_get(ctrl, dlg, cfg->printer, sizeof(cfg->printer)); if (!strcmp(cfg->printer, PRINTER_DISABLED_STRING)) *cfg->printer = '\0'; } } static void codepage_handler(union control *ctrl, void *dlg, void *data, int event) { Config *cfg = (Config *)data; if (event == EVENT_REFRESH) { int i; const char *cp, *thiscp; dlg_update_start(ctrl, dlg); thiscp = cp_name(decode_codepage(cfg->line_codepage)); dlg_listbox_clear(ctrl, dlg); for (i = 0; (cp = cp_enumerate(i)) != NULL; i++) dlg_listbox_add(ctrl, dlg, cp); dlg_editbox_set(ctrl, dlg, thiscp); strcpy(cfg->line_codepage, thiscp); dlg_update_done(ctrl, dlg); } else if (event == EVENT_VALCHANGE) { dlg_editbox_get(ctrl, dlg, cfg->line_codepage, sizeof(cfg->line_codepage)); strcpy(cfg->line_codepage, cp_name(decode_codepage(cfg->line_codepage))); } } static void sshbug_handler(union control *ctrl, void *dlg, void *data, int event) { if (event == EVENT_REFRESH) { dlg_update_start(ctrl, dlg); dlg_listbox_clear(ctrl, dlg); dlg_listbox_addwithid(ctrl, dlg, "Auto", AUTO); dlg_listbox_addwithid(ctrl, dlg, "Off", FORCE_OFF); dlg_listbox_addwithid(ctrl, dlg, "On", FORCE_ON); switch (*(int *)ATOFFSET(data, ctrl->listbox.context.i)) { case AUTO: dlg_listbox_select(ctrl, dlg, 0); break; case FORCE_OFF: dlg_listbox_select(ctrl, dlg, 1); break; case FORCE_ON: dlg_listbox_select(ctrl, dlg, 2); break; } dlg_update_done(ctrl, dlg); } else if (event == EVENT_SELCHANGE) { int i = dlg_listbox_index(ctrl, dlg); if (i < 0) i = AUTO; else i = dlg_listbox_getid(ctrl, dlg, i); *(int *)ATOFFSET(data, ctrl->listbox.context.i) = i; } } #define SAVEDSESSION_LEN 2048 struct sessionsaver_data { union control *editbox, *listbox, *loadbutton, *savebutton, *delbutton; union control *okbutton, *cancelbutton; struct sesslist sesslist; int midsession; }; /* PuTTY SC start */ void *m_label_dlg = NULL; void *m_cert_dlg = NULL; void *m_keystring_dlg = NULL; void *sc_get_label_dialog() { return m_label_dlg; } void *m_label_ctrl = NULL; void *m_cert_ctrl = NULL; void *m_keystring_ctrl = NULL; void *sc_get_label_ctrl() { return m_label_ctrl; } void sc_cert_handler(union control *ctrl, void *dlg, void *data, int event); void sc_tokenlabel_handler(union control *ctrl, void *dlg, void *data, int event ) { Config *cfg = (Config *)data; m_label_dlg = dlg; m_label_ctrl = ctrl; if(event == EVENT_REFRESH) { dlg_update_start(ctrl, dlg); dlg_listbox_clear(ctrl, dlg); if(filename_is_null(cfg->pkcs11_libfile)) { strcpy(cfg->pkcs11_token_label, ""); dlg_listbox_add(ctrl, dlg, "<E: SELECT LIBRARY FIRST!>"); } else { int i; CK_RV rv = 0; HINSTANCE hLib = LoadLibrary((char *)&cfg->pkcs11_libfile); CK_C_GetFunctionList pGFL = (CK_RV (*)(CK_FUNCTION_LIST_PTR_PTR))GetProcAddress(hLib, "C_GetFunctionList"); if (pGFL == NULL) { strcpy(cfg->pkcs11_token_label, ""); dlg_listbox_add(ctrl, dlg, "<E: WRONG LIBRARY!>"); } else { CK_FUNCTION_LIST_PTR fl = 0; rv = pGFL(&fl); if(rv != CKR_OK) { strcpy(cfg->pkcs11_token_label, ""); dlg_listbox_add(ctrl, dlg, "<E: ACCESS TO LIBRARY FAILED!>"); } else { int rv1, rv2; unsigned long slot_count = 16; CK_SLOT_ID slots[16]; rv1 = fl->C_Initialize(0); rv2 = fl->C_GetSlotList(TRUE, slots, &slot_count); if((rv1 != CKR_OK) || (rv2 != CKR_OK)) { strcpy(cfg->pkcs11_token_label, ""); dlg_listbox_add(ctrl, dlg, "<E: NO SLOTS FOUND!>"); } else { if(slot_count == 0) { strcpy(cfg->pkcs11_token_label, ""); dlg_listbox_add(ctrl, dlg, "<E: NO TOKEN FOUND!>"); } for(i=0; i<slot_count; i++) { CK_TOKEN_INFO token_info; CK_SLOT_ID slot = 64; slot = slots[i]; fl->C_GetTokenInfo(slot,&token_info); { char buf[40]; int j; memset(buf, 0, 40); strncpy(buf, token_info.label, 30); for(j=29;j>0;j--) { if(buf[j] == ' ') { buf[j] = '\0'; } else { break; } } dlg_listbox_add(ctrl, dlg, buf); } } } fl->C_Finalize(0); } } FreeLibrary(hLib); } dlg_editbox_set(ctrl, dlg, cfg->pkcs11_token_label); dlg_update_done(ctrl, dlg); } else if (event == EVENT_VALCHANGE) { char buf[70]; dlg_editbox_get(ctrl, dlg, buf, sizeof(buf)); if(strncmp(buf, "<E: ", 4) != 0){ strcpy(cfg->pkcs11_token_label, buf); } } if(m_cert_dlg != NULL) { sc_cert_handler(m_cert_ctrl, m_cert_dlg, data, EVENT_REFRESH); } } void sc_keystring_handler(union control *ctrl, void *dlg, void *data, int event ) { m_keystring_dlg = dlg; m_keystring_ctrl = ctrl; } void sc_cert_handler(union control *ctrl, void *dlg, void *data, int event ) { Config *cfg = (Config *)data; m_cert_dlg = dlg; m_cert_ctrl = ctrl; if(event == EVENT_REFRESH) { dlg_update_start(ctrl, dlg); dlg_listbox_clear(ctrl, dlg); if(cfg->pkcs11_token_label == NULL || strlen(cfg->pkcs11_token_label) == 0) { strcpy(cfg->pkcs11_token_label, ""); dlg_listbox_add(ctrl, dlg, "<E: SELECT TOKEN FIRST!>"); } else { sc_lib *sclib; if (cfg->sclib == NULL) { cfg->sclib = calloc(sizeof(sc_lib), 1); } sclib = cfg->sclib; sc_init_library(NULL, 0, sclib, &cfg->pkcs11_libfile); if(sclib->m_fl) { CK_SESSION_HANDLE session = sc_get_session(NULL, 0, sclib->m_fl, cfg->pkcs11_token_label); if(session) { char msg[1024] = ""; sc_cert_list *pcl; sc_cert_list *cl = sc_get_cert_list(sclib, session, msg); pcl = cl; while(pcl != NULL) { char *p_buf; p_buf = calloc(1,pcl->cert_attr[0].ulValueLen+1); strncpy(p_buf, pcl->cert_attr[0].pValue, pcl->cert_attr[0].ulValueLen); dlg_listbox_add(ctrl, dlg, p_buf); free(p_buf); pcl = pcl->next; } sc_free_cert_list(cl); // sclib->m_fl->C_CloseSession(session); } // sclib->m_fl->C_Finalize(0); } // free(sclib); } dlg_editbox_set(ctrl, dlg, cfg->pkcs11_cert_label); dlg_update_done(ctrl, dlg); } else if (event == EVENT_VALCHANGE) { sc_lib *sclib; char token_label[70]; char cert_label[70]; int blob_len; char *algorithm; /* minor memory leak */ sclib = cfg->sclib; dlg_editbox_get(m_label_ctrl, m_label_dlg, token_label, sizeof(token_label)); dlg_editbox_get(ctrl, dlg, cert_label, sizeof(cert_label)); if(strncmp(cert_label, "<E: ", 4) != 0) { strcpy(cfg->pkcs11_cert_label, cert_label); sc_get_pub(NULL, 0, sclib, token_label, cert_label, &algorithm, &blob_len); if (m_keystring_dlg != NULL && sclib && sclib->keystring != NULL) { dlg_editbox_set(m_keystring_ctrl, m_keystring_dlg, sclib->keystring); } if (sclib == NULL) { dlg_editbox_set(m_keystring_ctrl, m_keystring_dlg, "no sclib"); } else if (sclib->keystring == NULL) { dlg_editbox_set(m_keystring_ctrl, m_keystring_dlg, "no sclib keystring"); } } } } /* PuTTY SC end */ /* PuTTY CAPI begin */ #ifdef _WINDOWS struct capi_data { union control *certstore_droplist, *certID_text, *cert_browse, *keystring_text; }; void capi_certstore_handler(union control *ctrl, void *dlg, void *data, int event ) { Config *cfg = (Config *)data; struct capi_data *capid = (struct capi_data *)ctrl->generic.context.p; if (event == EVENT_REFRESH) { if (ctrl == capid->certstore_droplist) { dlg_update_start(ctrl, dlg); dlg_listbox_clear(ctrl, dlg); dlg_listbox_add(ctrl, dlg, "User\\MY (Personal Certificates)"); dlg_listbox_add(ctrl, dlg, "System\\MY (Personal Certificates)"); if (strncmp(cfg->capi_certID, "System\\MY", 9) == 0) dlg_listbox_select(ctrl, dlg, 1); else dlg_listbox_select(ctrl, dlg, 0); /* *shrug* */ dlg_update_done(ctrl, dlg); } } } void capi_certID_handler(union control *ctrl, void *dlg, void *data, int event ) { Config *cfg = (Config *)data; struct capi_data *capid = (struct capi_data *)ctrl->generic.context.p; char* tmpKeystring = NULL; if (event == EVENT_REFRESH) { dlg_editbox_set(ctrl, dlg, cfg->capi_certID); } else if (event == EVENT_VALCHANGE) { dlg_editbox_get(ctrl, dlg, cfg->capi_certID, sizeof(cfg->capi_certID)); } if (cfg->capi_certID[0]) { if ((tmpKeystring = capi_get_key_string(cfg->capi_certID)) != NULL) { dlg_editbox_set(capid->keystring_text, dlg, tmpKeystring); free(tmpKeystring); tmpKeystring = NULL; } } } typedef BOOL (WINAPI *PCertSelectCertificateA)( __inout PCERT_SELECT_STRUCT_A pCertSelectInfo ); void capi_certstore_browse_handler(union control *ctrl, void *dlg, void *data, int event ) { Config *cfg = (Config *)data; struct capi_data *capid = (struct capi_data *)ctrl->generic.context.p; HCERTSTORE hStore = NULL; CERT_SELECT_STRUCT_A* css = NULL; CERT_CONTEXT** acc = NULL; unsigned int tmpSHA1size = 0, dwCertStoreUser; unsigned char tmpSHA1[20]; char tmpSHA1hex[41] = ""; char tmpCertID[100] = ""; char* tmpKeystring = NULL; HMODULE hCertDlgDLL = NULL; PCertSelectCertificateA f_csca = NULL; int i; if (event == EVENT_ACTION) { i = dlg_listbox_index(capid->certstore_droplist, dlg); if (i < 0) goto cleanup; if ((hCertDlgDLL = LoadLibrary("CryptDlg.dll")) == NULL) goto cleanup; if ((f_csca = (PCertSelectCertificateA) GetProcAddress(hCertDlgDLL, "CertSelectCertificateA")) == NULL) goto cleanup; dwCertStoreUser = CERT_SYSTEM_STORE_CURRENT_USER; if (i == 1) dwCertStoreUser = CERT_SYSTEM_STORE_LOCAL_MACHINE; if ((hStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, 0 /*hCryptProv*/, dwCertStoreUser | CERT_STORE_READONLY_FLAG | CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_ENUM_ARCHIVED_FLAG, "MY")) == NULL) goto cleanup; acc = (CERT_CONTEXT**) malloc(sizeof(CERT_CONTEXT*)); acc[0] = NULL; css = (CERT_SELECT_STRUCT_A*) malloc(sizeof(CERT_SELECT_STRUCT_A)); memset(css, 0, sizeof(CERT_SELECT_STRUCT_A)); css->dwSize = sizeof(CERT_SELECT_STRUCT_A); css->hwndParent = ((struct dlgparam *) dlg)->hwnd; css->hInstance = NULL; css->pTemplateName = NULL; css->dwFlags = 0; css->szTitle = "PuTTY: Select Certificate for CAPI Auth"; css->cCertStore = 1; css->arrayCertStore = &hStore; css->szPurposeOid = szOID_PKIX_KP_CLIENT_AUTH; css->cCertContext = 1; // count of arrayCertContext indexes allocated css->arrayCertContext = acc; if (!f_csca(css)) // GetProcAddress(hCertDlgDLL, "CertSelectCertificateA") goto cleanup; if (css->cCertContext != 1) goto cleanup; if (acc[0] == NULL) goto cleanup; tmpSHA1size = sizeof(tmpSHA1); if (!CertGetCertificateContextProperty(acc[0], CERT_HASH_PROP_ID, tmpSHA1, &tmpSHA1size)) memset(tmpSHA1, 0, sizeof(tmpSHA1)); _snprintf(tmpSHA1hex, sizeof(tmpSHA1hex)-1, "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", tmpSHA1[0], tmpSHA1[1], tmpSHA1[2], tmpSHA1[3], tmpSHA1[4], tmpSHA1[5], tmpSHA1[6], tmpSHA1[7], tmpSHA1[8], tmpSHA1[9], tmpSHA1[10], tmpSHA1[11], tmpSHA1[12], tmpSHA1[13], tmpSHA1[14], tmpSHA1[15], tmpSHA1[16], tmpSHA1[17], tmpSHA1[18], tmpSHA1[19]); tmpSHA1hex[sizeof(tmpSHA1hex)-1] = '\0'; _snprintf(tmpCertID, sizeof(tmpCertID)-1, "%s\\%s", i == 1 ? "Machine\\MY" : "User\\MY", tmpSHA1hex); tmpCertID[sizeof(tmpCertID)-1] = '\0'; dlg_editbox_set(capid->certID_text, dlg, tmpCertID); strncpy(cfg->capi_certID, tmpCertID, sizeof(cfg->capi_certID)); cfg->capi_certID[sizeof(cfg->capi_certID)-1] = '\0'; if ((tmpKeystring = capi_get_key_string(tmpCertID)) != NULL) { dlg_editbox_set(capid->keystring_text, dlg, tmpKeystring); free(tmpKeystring); tmpKeystring = NULL; } } cleanup: if (hCertDlgDLL) { FreeLibrary(hCertDlgDLL); f_csca = NULL; hCertDlgDLL = NULL; } if (acc) { if (acc[0]) CertFreeCertificateContext(acc[0]); acc[0] = NULL; free(acc); acc = NULL; } if (css) free(css); css = NULL; if (hStore) CertCloseStore(hStore, 0); hStore = NULL; return; } #endif /* PuTTY CAPI end */ /* * Helper function to load the session selected in the list box, if * any, as this is done in more than one place below. Returns 0 for * failure. */ static int load_selected_session(struct sessionsaver_data *ssd, char *savedsession, void *dlg, Config *cfg, int *maybe_launch) { int i = dlg_listbox_index(ssd->listbox, dlg); int isdef; if (i < 0) { dlg_beep(dlg); return 0; } isdef = !strcmp(ssd->sesslist.sessions[i], "Default Settings"); load_settings(ssd->sesslist.sessions[i], cfg); if (!isdef) { strncpy(savedsession, ssd->sesslist.sessions[i], SAVEDSESSION_LEN); savedsession[SAVEDSESSION_LEN-1] = '\0'; if (maybe_launch) *maybe_launch = TRUE; } else { savedsession[0] = '\0'; if (maybe_launch) *maybe_launch = FALSE; } dlg_refresh(NULL, dlg); /* Restore the selection, which might have been clobbered by * changing the value of the edit box. */ dlg_listbox_select(ssd->listbox, dlg, i); return 1; } static void sessionsaver_handler(union control *ctrl, void *dlg, void *data, int event) { Config *cfg = (Config *)data; struct sessionsaver_data *ssd = (struct sessionsaver_data *)ctrl->generic.context.p; char *savedsession; /* * The first time we're called in a new dialog, we must * allocate space to store the current contents of the saved * session edit box (since it must persist even when we switch * panels, but is not part of the Config). */ if (!ssd->editbox) { savedsession = NULL; } else if (!dlg_get_privdata(ssd->editbox, dlg)) { savedsession = (char *) dlg_alloc_privdata(ssd->editbox, dlg, SAVEDSESSION_LEN); savedsession[0] = '\0'; } else { savedsession = dlg_get_privdata(ssd->editbox, dlg); } if (event == EVENT_REFRESH) { if (ctrl == ssd->editbox) { dlg_editbox_set(ctrl, dlg, savedsession); } else if (ctrl == ssd->listbox) { int i; dlg_update_start(ctrl, dlg); dlg_listbox_clear(ctrl, dlg); for (i = 0; i < ssd->sesslist.nsessions; i++) dlg_listbox_add(ctrl, dlg, ssd->sesslist.sessions[i]); dlg_update_done(ctrl, dlg); } } else if (event == EVENT_VALCHANGE) { int top, bottom, halfway, i; if (ctrl == ssd->editbox) { dlg_editbox_get(ctrl, dlg, savedsession, SAVEDSESSION_LEN); top = ssd->sesslist.nsessions; bottom = -1; while (top-bottom > 1) { halfway = (top+bottom)/2; i = strcmp(savedsession, ssd->sesslist.sessions[halfway]); if (i <= 0 ) { top = halfway; } else { bottom = halfway; } } if (top == ssd->sesslist.nsessions) { |
︙ | ︙ | |||
646 647 648 649 650 651 652 | /* * The user has double-clicked a session, or hit Load. * We must load the selected session, and then * terminate the configuration dialog _if_ there was a * double-click on the list box _and_ that session * contains a hostname. */ | | | | | > > > | > | < | > | | 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 | /* * The user has double-clicked a session, or hit Load. * We must load the selected session, and then * terminate the configuration dialog _if_ there was a * double-click on the list box _and_ that session * contains a hostname. */ if (load_selected_session(ssd, savedsession, dlg, cfg, &mbl) && (mbl && ctrl == ssd->listbox && cfg_launchable(cfg))) { dlg_end(dlg, 1); /* it's all over, and succeeded */ } } else if (ctrl == ssd->savebutton) { int isdef = !strcmp(savedsession, "Default Settings"); if (!savedsession[0]) { int i = dlg_listbox_index(ssd->listbox, dlg); if (i < 0) { dlg_beep(dlg); return; } isdef = !strcmp(ssd->sesslist.sessions[i], "Default Settings"); if (!isdef) { strncpy(savedsession, ssd->sesslist.sessions[i], SAVEDSESSION_LEN); savedsession[SAVEDSESSION_LEN-1] = '\0'; } else { savedsession[0] = '\0'; } } { char *errmsg = save_settings(savedsession, cfg); if (errmsg) { dlg_error_msg(dlg, errmsg); sfree(errmsg); } } get_sesslist(&ssd->sesslist, FALSE); get_sesslist(&ssd->sesslist, TRUE); |
︙ | ︙ | |||
699 700 701 702 703 704 705 | * Annoying special case. If the `Open' button is * pressed while no host name is currently set, _and_ * the session list previously had the focus, _and_ * there was a session selected in that which had a * valid host name in it, then load it and go. */ if (dlg_last_focused(ctrl, dlg) == ssd->listbox && | | | | > < | | > < < | | | < | | < | | 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 | * Annoying special case. If the `Open' button is * pressed while no host name is currently set, _and_ * the session list previously had the focus, _and_ * there was a session selected in that which had a * valid host name in it, then load it and go. */ if (dlg_last_focused(ctrl, dlg) == ssd->listbox && !cfg_launchable(cfg)) { Config cfg2; int mbl = FALSE; if (!load_selected_session(ssd, savedsession, dlg, &cfg2, &mbl)) { dlg_beep(dlg); return; } /* If at this point we have a valid session, go! */ if (mbl && cfg_launchable(&cfg2)) { *cfg = cfg2; /* structure copy */ cfg->remote_cmd_ptr = NULL; dlg_end(dlg, 1); } else dlg_beep(dlg); return; } /* * Otherwise, do the normal thing: if we have a valid * session, get going. */ if (cfg_launchable(cfg)) { dlg_end(dlg, 1); } else dlg_beep(dlg); } else if (ctrl == ssd->cancelbutton) { dlg_end(dlg, 0); } } } struct charclass_data { union control *listbox, *editbox, *button; }; static void charclass_handler(union control *ctrl, void *dlg, void *data, int event) { Config *cfg = (Config *)data; struct charclass_data *ccd = (struct charclass_data *)ctrl->generic.context.p; if (event == EVENT_REFRESH) { if (ctrl == ccd->listbox) { int i; dlg_update_start(ctrl, dlg); dlg_listbox_clear(ctrl, dlg); for (i = 0; i < 128; i++) { char str[100]; sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i, (i >= 0x21 && i != 0x7F) ? i : ' ', cfg->wordness[i]); dlg_listbox_add(ctrl, dlg, str); } dlg_update_done(ctrl, dlg); } } else if (event == EVENT_ACTION) { if (ctrl == ccd->button) { char str[100]; int i, n; dlg_editbox_get(ccd->editbox, dlg, str, sizeof(str)); n = atoi(str); for (i = 0; i < 128; i++) { if (dlg_listbox_issel(ccd->listbox, dlg, i)) cfg->wordness[i] = n; } dlg_refresh(ccd->listbox, dlg); } } } struct colour_data { |
︙ | ︙ | |||
794 795 796 797 798 799 800 | "ANSI Cyan", "ANSI Cyan Bold", "ANSI White", "ANSI White Bold" }; static void colour_handler(union control *ctrl, void *dlg, void *data, int event) { | | | 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 | "ANSI Cyan", "ANSI Cyan Bold", "ANSI White", "ANSI White Bold" }; static void colour_handler(union control *ctrl, void *dlg, void *data, int event) { Config *cfg = (Config *)data; struct colour_data *cd = (struct colour_data *)ctrl->generic.context.p; int update = FALSE, clear = FALSE, r, g, b; if (event == EVENT_REFRESH) { if (ctrl == cd->listbox) { int i; |
︙ | ︙ | |||
818 819 820 821 822 823 824 | if (ctrl == cd->listbox) { /* The user has selected a colour. Update the RGB text. */ int i = dlg_listbox_index(ctrl, dlg); if (i < 0) { clear = TRUE; } else { clear = FALSE; | | | | | | | < | | | | | | | | | | 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 | if (ctrl == cd->listbox) { /* The user has selected a colour. Update the RGB text. */ int i = dlg_listbox_index(ctrl, dlg); if (i < 0) { clear = TRUE; } else { clear = FALSE; r = cfg->colours[i][0]; g = cfg->colours[i][1]; b = cfg->colours[i][2]; } update = TRUE; } } else if (event == EVENT_VALCHANGE) { if (ctrl == cd->redit || ctrl == cd->gedit || ctrl == cd->bedit) { /* The user has changed the colour using the edit boxes. */ char buf[80]; int i, cval; dlg_editbox_get(ctrl, dlg, buf, lenof(buf)); cval = atoi(buf); if (cval > 255) cval = 255; if (cval < 0) cval = 0; i = dlg_listbox_index(cd->listbox, dlg); if (i >= 0) { if (ctrl == cd->redit) cfg->colours[i][0] = cval; else if (ctrl == cd->gedit) cfg->colours[i][1] = cval; else if (ctrl == cd->bedit) cfg->colours[i][2] = cval; } } } else if (event == EVENT_ACTION) { if (ctrl == cd->button) { int i = dlg_listbox_index(cd->listbox, dlg); if (i < 0) { dlg_beep(dlg); return; } /* * Start a colour selector, which will send us an * EVENT_CALLBACK when it's finished and allow us to * pick up the results. */ dlg_coloursel_start(ctrl, dlg, cfg->colours[i][0], cfg->colours[i][1], cfg->colours[i][2]); } } else if (event == EVENT_CALLBACK) { if (ctrl == cd->button) { int i = dlg_listbox_index(cd->listbox, dlg); /* * Collect the results of the colour selector. Will * return nonzero on success, or zero if the colour * selector did nothing (user hit Cancel, for example). */ if (dlg_coloursel_results(ctrl, dlg, &r, &g, &b)) { cfg->colours[i][0] = r; cfg->colours[i][1] = g; cfg->colours[i][2] = b; clear = FALSE; update = TRUE; } } } if (update) { |
︙ | ︙ | |||
903 904 905 906 907 908 909 | union control *modelist, *valradio, *valbox; union control *addbutton, *rembutton, *listbox; }; static void ttymodes_handler(union control *ctrl, void *dlg, void *data, int event) { | | | | | < | | > > | | > | > > > > > | > > | > > | | > > | > > > > > > > > | < > | < < < > > | | | > | | | | | | | | | > > > | > > > | | | < < < | > | | | < > > | | < < | > > > > > > > | > > | | | < < | > | > | > | > > > > > > > > > | | | > > > > | > > | > > > > > | < > > > > < | | < < < | < < < < < < < < < < < < < < < < < < | > | > > | < < | | | | > | | < > | > | > | < < | | | > > > > | > > > | < | | | > > > | > | < > | | < < < | | > | > | > | < < < | < | > > | | > > > | | < | > | | | < | < < > | < < < > | > > > > > > > > > > > | > > > | | > > | < > > > > < > > > > > | < < | 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 | union control *modelist, *valradio, *valbox; union control *addbutton, *rembutton, *listbox; }; static void ttymodes_handler(union control *ctrl, void *dlg, void *data, int event) { Config *cfg = (Config *)data; struct ttymodes_data *td = (struct ttymodes_data *)ctrl->generic.context.p; if (event == EVENT_REFRESH) { if (ctrl == td->listbox) { char *p = cfg->ttymodes; dlg_update_start(ctrl, dlg); dlg_listbox_clear(ctrl, dlg); while (*p) { int tabpos = strchr(p, '\t') - p; char *disp = dupprintf("%.*s\t%s", tabpos, p, (p[tabpos+1] == 'A') ? "(auto)" : p+tabpos+2); dlg_listbox_add(ctrl, dlg, disp); p += strlen(p) + 1; sfree(disp); } dlg_update_done(ctrl, dlg); } else if (ctrl == td->modelist) { int i; dlg_update_start(ctrl, dlg); dlg_listbox_clear(ctrl, dlg); for (i = 0; ttymodes[i]; i++) dlg_listbox_add(ctrl, dlg, ttymodes[i]); dlg_listbox_select(ctrl, dlg, 0); /* *shrug* */ dlg_update_done(ctrl, dlg); } else if (ctrl == td->valradio) { dlg_radiobutton_set(ctrl, dlg, 0); } } else if (event == EVENT_ACTION) { if (ctrl == td->addbutton) { int ind = dlg_listbox_index(td->modelist, dlg); if (ind >= 0) { char type = dlg_radiobutton_get(td->valradio, dlg) ? 'V' : 'A'; int slen, left; char *p, str[lenof(cfg->ttymodes)]; /* Construct new entry */ memset(str, 0, lenof(str)); strncpy(str, ttymodes[ind], lenof(str)-3); slen = strlen(str); str[slen] = '\t'; str[slen+1] = type; slen += 2; if (type == 'V') { dlg_editbox_get(td->valbox, dlg, str+slen, lenof(str)-slen); } /* Find end of list, deleting any existing instance */ p = cfg->ttymodes; left = lenof(cfg->ttymodes); while (*p) { int t = strchr(p, '\t') - p; if (t == strlen(ttymodes[ind]) && strncmp(p, ttymodes[ind], t) == 0) { memmove(p, p+strlen(p)+1, left - (strlen(p)+1)); continue; } left -= strlen(p) + 1; p += strlen(p) + 1; } /* Append new entry */ memset(p, 0, left); strncpy(p, str, left - 2); dlg_refresh(td->listbox, dlg); } else dlg_beep(dlg); } else if (ctrl == td->rembutton) { char *p = cfg->ttymodes; int i = 0, len = lenof(cfg->ttymodes); while (*p) { int multisel = dlg_listbox_index(td->listbox, dlg) < 0; if (dlg_listbox_issel(td->listbox, dlg, i)) { if (!multisel) { /* Populate controls with entry we're about to * delete, for ease of editing. * (If multiple entries were selected, don't * touch the controls.) */ char *val = strchr(p, '\t'); if (val) { int ind = 0; val++; while (ttymodes[ind]) { if (strlen(ttymodes[ind]) == val-p-1 && !strncmp(ttymodes[ind], p, val-p-1)) break; ind++; } dlg_listbox_select(td->modelist, dlg, ind); dlg_radiobutton_set(td->valradio, dlg, (*val == 'V')); dlg_editbox_set(td->valbox, dlg, val+1); } } memmove(p, p+strlen(p)+1, len - (strlen(p)+1)); i++; continue; } len -= strlen(p) + 1; p += strlen(p) + 1; i++; } memset(p, 0, lenof(cfg->ttymodes) - len); dlg_refresh(td->listbox, dlg); } } } struct environ_data { union control *varbox, *valbox, *addbutton, *rembutton, *listbox; }; static void environ_handler(union control *ctrl, void *dlg, void *data, int event) { Config *cfg = (Config *)data; struct environ_data *ed = (struct environ_data *)ctrl->generic.context.p; if (event == EVENT_REFRESH) { if (ctrl == ed->listbox) { char *p = cfg->environmt; dlg_update_start(ctrl, dlg); dlg_listbox_clear(ctrl, dlg); while (*p) { dlg_listbox_add(ctrl, dlg, p); p += strlen(p) + 1; } dlg_update_done(ctrl, dlg); } } else if (event == EVENT_ACTION) { if (ctrl == ed->addbutton) { char str[sizeof(cfg->environmt)]; char *p; dlg_editbox_get(ed->varbox, dlg, str, sizeof(str)-1); if (!*str) { dlg_beep(dlg); return; } p = str + strlen(str); *p++ = '\t'; dlg_editbox_get(ed->valbox, dlg, p, sizeof(str)-1 - (p - str)); if (!*p) { dlg_beep(dlg); return; } p = cfg->environmt; while (*p) { while (*p) p++; p++; } if ((p - cfg->environmt) + strlen(str) + 2 < sizeof(cfg->environmt)) { strcpy(p, str); p[strlen(str) + 1] = '\0'; dlg_listbox_add(ed->listbox, dlg, str); dlg_editbox_set(ed->varbox, dlg, ""); dlg_editbox_set(ed->valbox, dlg, ""); } else { dlg_error_msg(dlg, "Environment too big"); } } else if (ctrl == ed->rembutton) { int i = dlg_listbox_index(ed->listbox, dlg); if (i < 0) { dlg_beep(dlg); } else { char *p, *q, *str; dlg_listbox_del(ed->listbox, dlg, i); p = cfg->environmt; while (i > 0) { if (!*p) goto disaster; while (*p) p++; p++; i--; } q = p; if (!*p) goto disaster; /* Populate controls with the entry we're about to delete * for ease of editing */ str = p; p = strchr(p, '\t'); if (!p) goto disaster; *p = '\0'; dlg_editbox_set(ed->varbox, dlg, str); p++; str = p; dlg_editbox_set(ed->valbox, dlg, str); p = strchr(p, '\0'); if (!p) goto disaster; p++; while (*p) { while (*p) *q++ = *p++; *q++ = *p++; } *q = '\0'; disaster:; } } } } struct portfwd_data { union control *addbutton, *rembutton, *listbox; union control *sourcebox, *destbox, *direction; #ifndef NO_IPV6 union control *addressfamily; #endif }; static void portfwd_handler(union control *ctrl, void *dlg, void *data, int event) { Config *cfg = (Config *)data; struct portfwd_data *pfd = (struct portfwd_data *)ctrl->generic.context.p; if (event == EVENT_REFRESH) { if (ctrl == pfd->listbox) { char *p = cfg->portfwd; dlg_update_start(ctrl, dlg); dlg_listbox_clear(ctrl, dlg); while (*p) { dlg_listbox_add(ctrl, dlg, p); p += strlen(p) + 1; } dlg_update_done(ctrl, dlg); } else if (ctrl == pfd->direction) { /* * Default is Local. */ dlg_radiobutton_set(ctrl, dlg, 0); #ifndef NO_IPV6 } else if (ctrl == pfd->addressfamily) { dlg_radiobutton_set(ctrl, dlg, 0); #endif } } else if (event == EVENT_ACTION) { if (ctrl == pfd->addbutton) { char str[sizeof(cfg->portfwd)]; char *p; int i, type; int whichbutton; i = 0; #ifndef NO_IPV6 whichbutton = dlg_radiobutton_get(pfd->addressfamily, dlg); if (whichbutton == 1) str[i++] = '4'; else if (whichbutton == 2) str[i++] = '6'; #endif whichbutton = dlg_radiobutton_get(pfd->direction, dlg); if (whichbutton == 0) type = 'L'; else if (whichbutton == 1) type = 'R'; else type = 'D'; str[i++] = type; dlg_editbox_get(pfd->sourcebox, dlg, str+i, sizeof(str) - i); if (!str[i]) { dlg_error_msg(dlg, "You need to specify a source port number"); return; } p = str + strlen(str); if (type != 'D') { *p++ = '\t'; dlg_editbox_get(pfd->destbox, dlg, p, sizeof(str) - (p - str)); if (!*p || !strchr(p, ':')) { dlg_error_msg(dlg, "You need to specify a destination address\n" "in the form \"host.name:port\""); return; } } else *p = '\0'; p = cfg->portfwd; while (*p) { if (strcmp(p,str) == 0) { dlg_error_msg(dlg, "Specified forwarding already exists"); break; } while (*p) p++; p++; } if (!*p) { if ((p - cfg->portfwd) + strlen(str) + 2 <= sizeof(cfg->portfwd)) { strcpy(p, str); p[strlen(str) + 1] = '\0'; dlg_listbox_add(pfd->listbox, dlg, str); dlg_editbox_set(pfd->sourcebox, dlg, ""); dlg_editbox_set(pfd->destbox, dlg, ""); } else { dlg_error_msg(dlg, "Too many forwardings"); } } } else if (ctrl == pfd->rembutton) { int i = dlg_listbox_index(pfd->listbox, dlg); if (i < 0) dlg_beep(dlg); else { char *p, *q, *src, *dst; char dir; dlg_listbox_del(pfd->listbox, dlg, i); p = cfg->portfwd; while (i > 0) { if (!*p) goto disaster2; while (*p) p++; p++; i--; } q = p; if (!*p) goto disaster2; /* Populate the controls with the entry we're about to * delete, for ease of editing. */ { static const char *const afs = "A46"; char *afp = strchr(afs, *p); #ifndef NO_IPV6 int idx = afp ? afp-afs : 0; #endif if (afp) p++; #ifndef NO_IPV6 dlg_radiobutton_set(pfd->addressfamily, dlg, idx); #endif } { static const char *const dirs = "LRD"; dir = *p; dlg_radiobutton_set(pfd->direction, dlg, strchr(dirs, dir) - dirs); } p++; if (dir != 'D') { src = p; p = strchr(p, '\t'); if (!p) goto disaster2; *p = '\0'; p++; dst = p; } else { src = p; dst = ""; } p = strchr(p, '\0'); if (!p) goto disaster2; dlg_editbox_set(pfd->sourcebox, dlg, src); dlg_editbox_set(pfd->destbox, dlg, dst); p++; while (*p) { while (*p) *q++ = *p++; *q++ = *p++; } *q = '\0'; disaster2:; } } } } void setup_config_box(struct controlbox *b, int midsession, int protocol, int protcfginfo) { struct controlset *s; struct sessionsaver_data *ssd; struct charclass_data *ccd; struct colour_data *cd; /* PuTTY CAPI start */ #ifdef _WINDOWS struct capi_data *capid; #endif /* PuTTY CAPI end */ struct ttymodes_data *td; struct environ_data *ed; struct portfwd_data *pfd; union control *c; char *str; ssd = (struct sessionsaver_data *) ctrl_alloc(b, sizeof(struct sessionsaver_data)); memset(ssd, 0, sizeof(*ssd)); ssd->midsession = midsession; /* * The standard panel that appears at the bottom of all panels: * Open, Cancel, Apply etc. */ s = ctrl_getset(b, "", "", ""); |
︙ | ︙ | |||
1357 1358 1359 1360 1361 1362 1363 | } else { /* Disable the Delete button mid-session too, for UI consistency. */ ssd->delbutton = NULL; } ctrl_columns(s, 1, 100); s = ctrl_getset(b, "Session", "otheropts", NULL); | | | | | | | | | 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 | } else { /* Disable the Delete button mid-session too, for UI consistency. */ ssd->delbutton = NULL; } ctrl_columns(s, 1, 100); s = ctrl_getset(b, "Session", "otheropts", NULL); c = ctrl_radiobuttons(s, "Close window on exit:", 'x', 4, HELPCTX(session_coe), dlg_stdradiobutton_handler, I(offsetof(Config, close_on_exit)), "Always", I(FORCE_ON), "Never", I(FORCE_OFF), "Only on clean exit", I(AUTO), NULL); /* * The Session/Logging panel. */ ctrl_settitle(b, "Session/Logging", "Options controlling session logging"); s = ctrl_getset(b, "Session/Logging", "main", NULL); |
︙ | ︙ | |||
1388 1389 1390 1391 1392 1393 1394 | } else { sshlogname = NULL; /* this will disable both buttons */ sshrawlogname = NULL; /* this will just placate optimisers */ } ctrl_radiobuttons(s, "Session logging:", NO_SHORTCUT, 2, HELPCTX(logging_main), loggingbuttons_handler, | | | | | | | | | | | | | | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > | | | | | | | | | | | 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 | } else { sshlogname = NULL; /* this will disable both buttons */ sshrawlogname = NULL; /* this will just placate optimisers */ } ctrl_radiobuttons(s, "Session logging:", NO_SHORTCUT, 2, HELPCTX(logging_main), loggingbuttons_handler, I(offsetof(Config, logtype)), "None", 't', I(LGTYP_NONE), "Printable output", 'p', I(LGTYP_ASCII), "All session output", 'l', I(LGTYP_DEBUG), sshlogname, 's', I(LGTYP_PACKETS), sshrawlogname, 'r', I(LGTYP_SSHRAW), NULL); } ctrl_filesel(s, "Log file name:", 'f', NULL, TRUE, "Select session log file name", HELPCTX(logging_filename), dlg_stdfilesel_handler, I(offsetof(Config, logfilename))); ctrl_text(s, "(Log file name can contain &Y, &M, &D for date," " &T for time, and &H for host name)", HELPCTX(logging_filename)); ctrl_radiobuttons(s, "What to do if the log file already exists:", 'e', 1, HELPCTX(logging_exists), dlg_stdradiobutton_handler, I(offsetof(Config,logxfovr)), "Always overwrite it", I(LGXF_OVR), "Always append to the end of it", I(LGXF_APN), "Ask the user every time", I(LGXF_ASK), NULL); ctrl_checkbox(s, "Flush log file frequently", 'u', HELPCTX(logging_flush), dlg_stdcheckbox_handler, I(offsetof(Config,logflush))); if ((midsession && protocol == PROT_SSH) || (!midsession && backend_from_proto(PROT_SSH))) { s = ctrl_getset(b, "Session/Logging", "ssh", "Options specific to SSH packet logging"); ctrl_checkbox(s, "Omit known password fields", 'k', HELPCTX(logging_ssh_omit_password), dlg_stdcheckbox_handler, I(offsetof(Config,logomitpass))); ctrl_checkbox(s, "Omit session data", 'd', HELPCTX(logging_ssh_omit_data), dlg_stdcheckbox_handler, I(offsetof(Config,logomitdata))); } /* * The Terminal panel. */ ctrl_settitle(b, "Terminal", "Options controlling the terminal emulation"); s = ctrl_getset(b, "Terminal", "general", "Set various terminal options"); ctrl_checkbox(s, "Auto wrap mode initially on", 'w', HELPCTX(terminal_autowrap), dlg_stdcheckbox_handler, I(offsetof(Config,wrap_mode))); ctrl_checkbox(s, "DEC Origin Mode initially on", 'd', HELPCTX(terminal_decom), dlg_stdcheckbox_handler, I(offsetof(Config,dec_om))); ctrl_checkbox(s, "Implicit CR in every LF", 'r', HELPCTX(terminal_lfhascr), dlg_stdcheckbox_handler, I(offsetof(Config,lfhascr))); ctrl_checkbox(s, "Implicit LF in every CR", 'f', HELPCTX(terminal_crhaslf), dlg_stdcheckbox_handler, I(offsetof(Config,crhaslf))); ctrl_checkbox(s, "Use background colour to erase screen", 'e', HELPCTX(terminal_bce), dlg_stdcheckbox_handler, I(offsetof(Config,bce))); ctrl_checkbox(s, "Enable blinking text", 'n', HELPCTX(terminal_blink), dlg_stdcheckbox_handler, I(offsetof(Config,blinktext))); ctrl_editbox(s, "Answerback to ^E:", 's', 100, HELPCTX(terminal_answerback), dlg_stdeditbox_handler, I(offsetof(Config,answerback)), I(sizeof(((Config *)0)->answerback))); s = ctrl_getset(b, "Terminal", "ldisc", "Line discipline options"); ctrl_radiobuttons(s, "Local echo:", 'l', 3, HELPCTX(terminal_localecho), dlg_stdradiobutton_handler,I(offsetof(Config,localecho)), "Auto", I(AUTO), "Force on", I(FORCE_ON), "Force off", I(FORCE_OFF), NULL); ctrl_radiobuttons(s, "Local line editing:", 't', 3, HELPCTX(terminal_localedit), dlg_stdradiobutton_handler,I(offsetof(Config,localedit)), "Auto", I(AUTO), "Force on", I(FORCE_ON), "Force off", I(FORCE_OFF), NULL); s = ctrl_getset(b, "Terminal", "printing", "Remote-controlled printing"); ctrl_combobox(s, "Printer to send ANSI printer output to:", 'p', 100, HELPCTX(terminal_printing), printerbox_handler, P(NULL), P(NULL)); /* * The Terminal/Keyboard panel. */ ctrl_settitle(b, "Terminal/Keyboard", "Options controlling the effects of keys"); s = ctrl_getset(b, "Terminal/Keyboard", "mappings", "Change the sequences sent by:"); ctrl_radiobuttons(s, "The Backspace key", 'b', 2, HELPCTX(keyboard_backspace), dlg_stdradiobutton_handler, I(offsetof(Config, bksp_is_delete)), "Control-H", I(0), "Control-? (127)", I(1), NULL); ctrl_radiobuttons(s, "The Home and End keys", 'e', 2, HELPCTX(keyboard_homeend), dlg_stdradiobutton_handler, I(offsetof(Config, rxvt_homeend)), "Standard", I(0), "rxvt", I(1), NULL); ctrl_radiobuttons(s, "The Function keys and keypad", 'f', 3, HELPCTX(keyboard_funkeys), dlg_stdradiobutton_handler, I(offsetof(Config, funky_type)), "ESC[n~", I(0), "Linux", I(1), "Xterm R6", I(2), "VT400", I(3), "VT100+", I(4), "SCO", I(5), NULL); s = ctrl_getset(b, "Terminal/Keyboard", "appkeypad", "Application keypad settings:"); ctrl_radiobuttons(s, "Initial state of cursor keys:", 'r', 3, HELPCTX(keyboard_appcursor), dlg_stdradiobutton_handler, I(offsetof(Config, app_cursor)), "Normal", I(0), "Application", I(1), NULL); ctrl_radiobuttons(s, "Initial state of numeric keypad:", 'n', 3, HELPCTX(keyboard_appkeypad), numeric_keypad_handler, P(NULL), "Normal", I(0), "Application", I(1), "NetHack", I(2), NULL); /* * The Terminal/Bell panel. */ ctrl_settitle(b, "Terminal/Bell", "Options controlling the terminal bell"); s = ctrl_getset(b, "Terminal/Bell", "style", "Set the style of bell"); ctrl_radiobuttons(s, "Action to happen when a bell occurs:", 'b', 1, HELPCTX(bell_style), dlg_stdradiobutton_handler, I(offsetof(Config, beep)), "None (bell disabled)", I(BELL_DISABLED), "Make default system alert sound", I(BELL_DEFAULT), "Visual bell (flash window)", I(BELL_VISUAL), NULL); s = ctrl_getset(b, "Terminal/Bell", "overload", "Control the bell overload behaviour"); ctrl_checkbox(s, "Bell is temporarily disabled when over-used", 'd', HELPCTX(bell_overload), dlg_stdcheckbox_handler, I(offsetof(Config,bellovl))); ctrl_editbox(s, "Over-use means this many bells...", 'm', 20, HELPCTX(bell_overload), dlg_stdeditbox_handler, I(offsetof(Config,bellovl_n)), I(-1)); ctrl_editbox(s, "... in this many seconds", 't', 20, HELPCTX(bell_overload), dlg_stdeditbox_handler, I(offsetof(Config,bellovl_t)), I(-TICKSPERSEC)); ctrl_text(s, "The bell is re-enabled after a few seconds of silence.", HELPCTX(bell_overload)); ctrl_editbox(s, "Seconds of silence required", 's', 20, HELPCTX(bell_overload), dlg_stdeditbox_handler, I(offsetof(Config,bellovl_s)), I(-TICKSPERSEC)); /* * The Terminal/Features panel. */ ctrl_settitle(b, "Terminal/Features", "Enabling and disabling advanced terminal features"); s = ctrl_getset(b, "Terminal/Features", "main", NULL); ctrl_checkbox(s, "Disable application cursor keys mode", 'u', HELPCTX(features_application), dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_c))); ctrl_checkbox(s, "Disable application keypad mode", 'k', HELPCTX(features_application), dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_k))); ctrl_checkbox(s, "Disable xterm-style mouse reporting", 'x', HELPCTX(features_mouse), dlg_stdcheckbox_handler, I(offsetof(Config,no_mouse_rep))); ctrl_checkbox(s, "Disable remote-controlled terminal resizing", 's', HELPCTX(features_resize), dlg_stdcheckbox_handler, I(offsetof(Config,no_remote_resize))); ctrl_checkbox(s, "Disable switching to alternate terminal screen", 'w', HELPCTX(features_altscreen), dlg_stdcheckbox_handler, I(offsetof(Config,no_alt_screen))); ctrl_checkbox(s, "Disable remote-controlled window title changing", 't', HELPCTX(features_retitle), dlg_stdcheckbox_handler, I(offsetof(Config,no_remote_wintitle))); ctrl_radiobuttons(s, "Response to remote title query (SECURITY):", 'q', 3, HELPCTX(features_qtitle), dlg_stdradiobutton_handler, I(offsetof(Config,remote_qtitle_action)), "None", I(TITLE_NONE), "Empty string", I(TITLE_EMPTY), "Window title", I(TITLE_REAL), NULL); ctrl_checkbox(s, "Disable destructive backspace on server sending ^?",'b', HELPCTX(features_dbackspace), dlg_stdcheckbox_handler, I(offsetof(Config,no_dbackspace))); ctrl_checkbox(s, "Disable remote-controlled character set configuration", 'r', HELPCTX(features_charset), dlg_stdcheckbox_handler, I(offsetof(Config,no_remote_charset))); ctrl_checkbox(s, "Disable Arabic text shaping", 'l', HELPCTX(features_arabicshaping), dlg_stdcheckbox_handler, I(offsetof(Config, arabicshaping))); ctrl_checkbox(s, "Disable bidirectional text display", 'd', HELPCTX(features_bidi), dlg_stdcheckbox_handler, I(offsetof(Config, bidi))); /* * The Window panel. */ str = dupprintf("Options controlling %s's window", appname); ctrl_settitle(b, "Window", str); sfree(str); s = ctrl_getset(b, "Window", "size", "Set the size of the window"); ctrl_columns(s, 2, 50, 50); c = ctrl_editbox(s, "Columns", 'm', 100, HELPCTX(window_size), dlg_stdeditbox_handler, I(offsetof(Config,width)), I(-1)); c->generic.column = 0; c = ctrl_editbox(s, "Rows", 'r', 100, HELPCTX(window_size), dlg_stdeditbox_handler, I(offsetof(Config,height)),I(-1)); c->generic.column = 1; ctrl_columns(s, 1, 100); s = ctrl_getset(b, "Window", "scrollback", "Control the scrollback in the window"); ctrl_editbox(s, "Lines of scrollback", 's', 50, HELPCTX(window_scrollback), dlg_stdeditbox_handler, I(offsetof(Config,savelines)), I(-1)); ctrl_checkbox(s, "Display scrollbar", 'd', HELPCTX(window_scrollback), dlg_stdcheckbox_handler, I(offsetof(Config,scrollbar))); ctrl_checkbox(s, "Reset scrollback on keypress", 'k', HELPCTX(window_scrollback), dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_key))); ctrl_checkbox(s, "Reset scrollback on display activity", 'p', HELPCTX(window_scrollback), dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_disp))); ctrl_checkbox(s, "Push erased text into scrollback", 'e', HELPCTX(window_erased), dlg_stdcheckbox_handler, I(offsetof(Config,erase_to_scrollback))); /* * The Window/Appearance panel. */ str = dupprintf("Configure the appearance of %s's window", appname); ctrl_settitle(b, "Window/Appearance", str); sfree(str); s = ctrl_getset(b, "Window/Appearance", "cursor", "Adjust the use of the cursor"); ctrl_radiobuttons(s, "Cursor appearance:", NO_SHORTCUT, 3, HELPCTX(appearance_cursor), dlg_stdradiobutton_handler, I(offsetof(Config, cursor_type)), "Block", 'l', I(0), "Underline", 'u', I(1), "Vertical line", 'v', I(2), NULL); ctrl_checkbox(s, "Cursor blinks", 'b', HELPCTX(appearance_cursor), dlg_stdcheckbox_handler, I(offsetof(Config,blink_cur))); s = ctrl_getset(b, "Window/Appearance", "font", "Font settings"); ctrl_fontsel(s, "Font used in the terminal window", 'n', HELPCTX(appearance_font), dlg_stdfontsel_handler, I(offsetof(Config, font))); s = ctrl_getset(b, "Window/Appearance", "mouse", "Adjust the use of the mouse pointer"); ctrl_checkbox(s, "Hide mouse pointer when typing in window", 'p', HELPCTX(appearance_hidemouse), dlg_stdcheckbox_handler, I(offsetof(Config,hide_mouseptr))); s = ctrl_getset(b, "Window/Appearance", "border", "Adjust the window border"); ctrl_editbox(s, "Gap between text and window edge:", 'e', 20, HELPCTX(appearance_border), dlg_stdeditbox_handler, I(offsetof(Config,window_border)), I(-1)); /* * The Window/Behaviour panel. */ str = dupprintf("Configure the behaviour of %s's window", appname); ctrl_settitle(b, "Window/Behaviour", str); sfree(str); s = ctrl_getset(b, "Window/Behaviour", "title", "Adjust the behaviour of the window title"); ctrl_editbox(s, "Window title:", 't', 100, HELPCTX(appearance_title), dlg_stdeditbox_handler, I(offsetof(Config,wintitle)), I(sizeof(((Config *)0)->wintitle))); ctrl_checkbox(s, "Separate window and icon titles", 'i', HELPCTX(appearance_title), dlg_stdcheckbox_handler, I(CHECKBOX_INVERT | offsetof(Config,win_name_always))); s = ctrl_getset(b, "Window/Behaviour", "main", NULL); ctrl_checkbox(s, "Warn before closing window", 'w', HELPCTX(behaviour_closewarn), dlg_stdcheckbox_handler, I(offsetof(Config,warn_on_close))); /* * The Window/Translation panel. */ ctrl_settitle(b, "Window/Translation", "Options controlling character set translation"); s = ctrl_getset(b, "Window/Translation", "trans", "Character set translation"); ctrl_combobox(s, "Remote character set:", 'r', 100, HELPCTX(translation_codepage), codepage_handler, P(NULL), P(NULL)); s = ctrl_getset(b, "Window/Translation", "tweaks", NULL); ctrl_checkbox(s, "Treat CJK ambiguous characters as wide", 'w', HELPCTX(translation_cjk_ambig_wide), dlg_stdcheckbox_handler, I(offsetof(Config,cjk_ambig_wide))); str = dupprintf("Adjust how %s handles line drawing characters", appname); s = ctrl_getset(b, "Window/Translation", "linedraw", str); sfree(str); ctrl_radiobuttons(s, "Handling of line drawing characters:", NO_SHORTCUT,1, HELPCTX(translation_linedraw), dlg_stdradiobutton_handler, I(offsetof(Config, vtmode)), "Use Unicode line drawing code points",'u',I(VT_UNICODE), "Poor man's line drawing (+, - and |)",'p',I(VT_POORMAN), NULL); ctrl_checkbox(s, "Copy and paste line drawing characters as lqqqk",'d', HELPCTX(selection_linedraw), dlg_stdcheckbox_handler, I(offsetof(Config,rawcnp))); /* * The Window/Selection panel. */ ctrl_settitle(b, "Window/Selection", "Options controlling copy and paste"); s = ctrl_getset(b, "Window/Selection", "mouse", "Control use of mouse"); ctrl_checkbox(s, "Shift overrides application's use of mouse", 'p', HELPCTX(selection_shiftdrag), dlg_stdcheckbox_handler, I(offsetof(Config,mouse_override))); ctrl_radiobuttons(s, "Default selection mode (Alt+drag does the other one):", NO_SHORTCUT, 2, HELPCTX(selection_rect), dlg_stdradiobutton_handler, I(offsetof(Config, rect_select)), "Normal", 'n', I(0), "Rectangular block", 'r', I(1), NULL); s = ctrl_getset(b, "Window/Selection", "charclass", "Control the select-one-word-at-a-time mode"); ccd = (struct charclass_data *) ctrl_alloc(b, sizeof(struct charclass_data)); |
︙ | ︙ | |||
1773 1774 1775 1776 1777 1778 1779 | */ ctrl_settitle(b, "Window/Colours", "Options controlling use of colours"); s = ctrl_getset(b, "Window/Colours", "general", "General options for colour usage"); ctrl_checkbox(s, "Allow terminal to specify ANSI colours", 'i', HELPCTX(colours_ansi), | | | | | | | < < < < | 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 | */ ctrl_settitle(b, "Window/Colours", "Options controlling use of colours"); s = ctrl_getset(b, "Window/Colours", "general", "General options for colour usage"); ctrl_checkbox(s, "Allow terminal to specify ANSI colours", 'i', HELPCTX(colours_ansi), dlg_stdcheckbox_handler, I(offsetof(Config,ansi_colour))); ctrl_checkbox(s, "Allow terminal to use xterm 256-colour mode", '2', HELPCTX(colours_xterm256), dlg_stdcheckbox_handler, I(offsetof(Config,xterm_256_colour))); ctrl_checkbox(s, "Bolded text is a different colour", 'b', HELPCTX(colours_bold), dlg_stdcheckbox_handler, I(offsetof(Config,bold_colour))); str = dupprintf("Adjust the precise colours %s displays", appname); s = ctrl_getset(b, "Window/Colours", "adjust", str); sfree(str); ctrl_text(s, "Select a colour from the list, and then click the" " Modify button to change its appearance.", HELPCTX(colours_config)); |
︙ | ︙ | |||
1825 1826 1827 1828 1829 1830 1831 | if (protocol >= 0) { ctrl_settitle(b, "Connection", "Options controlling the connection"); s = ctrl_getset(b, "Connection", "keepalive", "Sending of null packets to keep session active"); ctrl_editbox(s, "Seconds between keepalives (0 to turn off)", 'k', 20, HELPCTX(connection_keepalive), | | | | | | | | | > | > | | | > | > | 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 | if (protocol >= 0) { ctrl_settitle(b, "Connection", "Options controlling the connection"); s = ctrl_getset(b, "Connection", "keepalive", "Sending of null packets to keep session active"); ctrl_editbox(s, "Seconds between keepalives (0 to turn off)", 'k', 20, HELPCTX(connection_keepalive), dlg_stdeditbox_handler, I(offsetof(Config,ping_interval)), I(-1)); if (!midsession) { s = ctrl_getset(b, "Connection", "tcp", "Low-level TCP connection options"); ctrl_checkbox(s, "Disable Nagle's algorithm (TCP_NODELAY option)", 'n', HELPCTX(connection_nodelay), dlg_stdcheckbox_handler, I(offsetof(Config,tcp_nodelay))); ctrl_checkbox(s, "Enable TCP keepalives (SO_KEEPALIVE option)", 'p', HELPCTX(connection_tcpkeepalive), dlg_stdcheckbox_handler, I(offsetof(Config,tcp_keepalives))); #ifndef NO_IPV6 s = ctrl_getset(b, "Connection", "ipversion", "Internet protocol version"); ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3, HELPCTX(connection_ipversion), dlg_stdradiobutton_handler, I(offsetof(Config, addressfamily)), "Auto", 'u', I(ADDRTYPE_UNSPEC), "IPv4", '4', I(ADDRTYPE_IPV4), "IPv6", '6', I(ADDRTYPE_IPV6), NULL); #endif { char *label = backend_from_proto(PROT_SSH) ? "Logical name of remote host (e.g. for SSH key lookup):" : "Logical name of remote host:"; s = ctrl_getset(b, "Connection", "identity", "Logical name of remote host"); ctrl_editbox(s, label, 'm', 100, HELPCTX(connection_loghost), dlg_stdeditbox_handler, I(offsetof(Config,loghost)), I(sizeof(((Config *)0)->loghost))); } } /* * A sub-panel Connection/Data, containing options that * decide on data to send to the server. */ if (!midsession) { ctrl_settitle(b, "Connection/Data", "Data to send to the server"); s = ctrl_getset(b, "Connection/Data", "login", "Login details"); ctrl_editbox(s, "Auto-login username", 'u', 50, HELPCTX(connection_username), dlg_stdeditbox_handler, I(offsetof(Config,username)), I(sizeof(((Config *)0)->username))); { /* We assume the local username is sufficiently stable * to include on the dialog box. */ char *user = get_username(); char *userlabel = dupprintf("Use system username (%s)", user ? user : ""); sfree(user); ctrl_radiobuttons(s, "When username is not specified:", 'n', 4, HELPCTX(connection_username_from_env), dlg_stdradiobutton_handler, I(offsetof(Config, username_from_env)), "Prompt", I(FALSE), userlabel, I(TRUE), NULL); sfree(userlabel); } s = ctrl_getset(b, "Connection/Data", "term", "Terminal details"); ctrl_editbox(s, "Terminal-type string", 't', 50, HELPCTX(connection_termtype), dlg_stdeditbox_handler, I(offsetof(Config,termtype)), I(sizeof(((Config *)0)->termtype))); ctrl_editbox(s, "Terminal speeds", 's', 50, HELPCTX(connection_termspeed), dlg_stdeditbox_handler, I(offsetof(Config,termspeed)), I(sizeof(((Config *)0)->termspeed))); s = ctrl_getset(b, "Connection/Data", "env", "Environment variables"); ctrl_columns(s, 2, 80, 20); ed = (struct environ_data *) ctrl_alloc(b, sizeof(struct environ_data)); ed->varbox = ctrl_editbox(s, "Variable", 'v', 60, |
︙ | ︙ | |||
1946 1947 1948 1949 1950 1951 1952 | */ ctrl_settitle(b, "Connection/Proxy", "Options controlling proxy usage"); s = ctrl_getset(b, "Connection/Proxy", "basics", NULL); ctrl_radiobuttons(s, "Proxy type:", 't', 3, HELPCTX(proxy_type), | | | | | > | | | | > | | | | | | > | | > | | > | | | | | | | | | > | 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 | */ ctrl_settitle(b, "Connection/Proxy", "Options controlling proxy usage"); s = ctrl_getset(b, "Connection/Proxy", "basics", NULL); ctrl_radiobuttons(s, "Proxy type:", 't', 3, HELPCTX(proxy_type), dlg_stdradiobutton_handler, I(offsetof(Config, proxy_type)), "None", I(PROXY_NONE), "SOCKS 4", I(PROXY_SOCKS4), "SOCKS 5", I(PROXY_SOCKS5), "HTTP", I(PROXY_HTTP), "Telnet", I(PROXY_TELNET), NULL); ctrl_columns(s, 2, 80, 20); c = ctrl_editbox(s, "Proxy hostname", 'y', 100, HELPCTX(proxy_main), dlg_stdeditbox_handler, I(offsetof(Config,proxy_host)), I(sizeof(((Config *)0)->proxy_host))); c->generic.column = 0; c = ctrl_editbox(s, "Port", 'p', 100, HELPCTX(proxy_main), dlg_stdeditbox_handler, I(offsetof(Config,proxy_port)), I(-1)); c->generic.column = 1; ctrl_columns(s, 1, 100); ctrl_editbox(s, "Exclude Hosts/IPs", 'e', 100, HELPCTX(proxy_exclude), dlg_stdeditbox_handler, I(offsetof(Config,proxy_exclude_list)), I(sizeof(((Config *)0)->proxy_exclude_list))); ctrl_checkbox(s, "Consider proxying local host connections", 'x', HELPCTX(proxy_exclude), dlg_stdcheckbox_handler, I(offsetof(Config,even_proxy_localhost))); ctrl_radiobuttons(s, "Do DNS name lookup at proxy end:", 'd', 3, HELPCTX(proxy_dns), dlg_stdradiobutton_handler, I(offsetof(Config, proxy_dns)), "No", I(FORCE_OFF), "Auto", I(AUTO), "Yes", I(FORCE_ON), NULL); ctrl_editbox(s, "Username", 'u', 60, HELPCTX(proxy_auth), dlg_stdeditbox_handler, I(offsetof(Config,proxy_username)), I(sizeof(((Config *)0)->proxy_username))); c = ctrl_editbox(s, "Password", 'w', 60, HELPCTX(proxy_auth), dlg_stdeditbox_handler, I(offsetof(Config,proxy_password)), I(sizeof(((Config *)0)->proxy_password))); c->editbox.password = 1; ctrl_editbox(s, "Telnet command", 'm', 100, HELPCTX(proxy_command), dlg_stdeditbox_handler, I(offsetof(Config,proxy_telnet_command)), I(sizeof(((Config *)0)->proxy_telnet_command))); } /* * The Telnet panel exists in the base config box, and in a * mid-session reconfig box _if_ we're using Telnet. */ if (!midsession || protocol == PROT_TELNET) { /* * The Connection/Telnet panel. */ ctrl_settitle(b, "Connection/Telnet", "Options controlling Telnet connections"); s = ctrl_getset(b, "Connection/Telnet", "protocol", "Telnet protocol adjustments"); if (!midsession) { ctrl_radiobuttons(s, "Handling of OLD_ENVIRON ambiguity:", NO_SHORTCUT, 2, HELPCTX(telnet_oldenviron), dlg_stdradiobutton_handler, I(offsetof(Config, rfc_environ)), "BSD (commonplace)", 'b', I(0), "RFC 1408 (unusual)", 'f', I(1), NULL); ctrl_radiobuttons(s, "Telnet negotiation mode:", 't', 2, HELPCTX(telnet_passive), dlg_stdradiobutton_handler, I(offsetof(Config, passive_telnet)), "Passive", I(1), "Active", I(0), NULL); } ctrl_checkbox(s, "Keyboard sends Telnet special commands", 'k', HELPCTX(telnet_specialkeys), dlg_stdcheckbox_handler, I(offsetof(Config,telnet_keyboard))); ctrl_checkbox(s, "Return key sends Telnet New Line instead of ^M", 'm', HELPCTX(telnet_newline), dlg_stdcheckbox_handler, I(offsetof(Config,telnet_newline))); } if (!midsession) { /* * The Connection/Rlogin panel. */ ctrl_settitle(b, "Connection/Rlogin", "Options controlling Rlogin connections"); s = ctrl_getset(b, "Connection/Rlogin", "data", "Data to send to the server"); ctrl_editbox(s, "Local username:", 'l', 50, HELPCTX(rlogin_localuser), dlg_stdeditbox_handler, I(offsetof(Config,localusername)), I(sizeof(((Config *)0)->localusername))); } /* * All the SSH stuff is omitted in PuTTYtel, or in a reconfig * when we're not doing SSH. */ |
︙ | ︙ | |||
2077 2078 2079 2080 2081 2082 2083 | if (!midsession) { s = ctrl_getset(b, "Connection/SSH", "data", "Data to send to the server"); ctrl_editbox(s, "Remote command:", 'r', 100, HELPCTX(ssh_command), | | > | | | | < < < < < < < < < < < < < < < < < < < < | | > > > > > > > > > > > > > | 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 | if (!midsession) { s = ctrl_getset(b, "Connection/SSH", "data", "Data to send to the server"); ctrl_editbox(s, "Remote command:", 'r', 100, HELPCTX(ssh_command), dlg_stdeditbox_handler, I(offsetof(Config,remote_cmd)), I(sizeof(((Config *)0)->remote_cmd))); s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options"); ctrl_checkbox(s, "Don't start a shell or command at all", 'n', HELPCTX(ssh_noshell), dlg_stdcheckbox_handler, I(offsetof(Config,ssh_no_shell))); } if (!midsession || protcfginfo != 1) { s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options"); ctrl_checkbox(s, "Enable compression", 'e', HELPCTX(ssh_compress), dlg_stdcheckbox_handler, I(offsetof(Config,compression))); } if (!midsession) { s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options"); ctrl_radiobuttons(s, "Preferred SSH protocol version:", NO_SHORTCUT, 4, HELPCTX(ssh_protocol), dlg_stdradiobutton_handler, I(offsetof(Config, sshprot)), "1 only", 'l', I(0), "1", '1', I(1), "2", '2', I(2), "2 only", 'y', I(3), NULL); } if (!midsession || protcfginfo != 1) { s = ctrl_getset(b, "Connection/SSH", "encryption", "Encryption options"); c = ctrl_draglist(s, "Encryption cipher selection policy:", 's', HELPCTX(ssh_ciphers), cipherlist_handler, P(NULL)); c->listbox.height = 6; ctrl_checkbox(s, "Enable legacy use of single-DES in SSH-2", 'i', HELPCTX(ssh_ciphers), dlg_stdcheckbox_handler, I(offsetof(Config,ssh2_des_cbc))); } /* * The Connection/SSH/Kex panel. (Owing to repeat key * exchange, this is all meaningful in mid-session _if_ * we're using SSH-2 or haven't decided yet.) */ if (protcfginfo != 1) { |
︙ | ︙ | |||
2149 2150 2151 2152 2153 2154 2155 | c->listbox.height = 5; s = ctrl_getset(b, "Connection/SSH/Kex", "repeat", "Options controlling key re-exchange"); ctrl_editbox(s, "Max minutes before rekey (0 for no limit)", 't', 20, HELPCTX(ssh_kex_repeat), | | | | | < < < < < < < < < < < < < < < < < < < < > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | | | | | | | | | | | | | 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 | c->listbox.height = 5; s = ctrl_getset(b, "Connection/SSH/Kex", "repeat", "Options controlling key re-exchange"); ctrl_editbox(s, "Max minutes before rekey (0 for no limit)", 't', 20, HELPCTX(ssh_kex_repeat), dlg_stdeditbox_handler, I(offsetof(Config,ssh_rekey_time)), I(-1)); ctrl_editbox(s, "Max data before rekey (0 for no limit)", 'x', 20, HELPCTX(ssh_kex_repeat), dlg_stdeditbox_handler, I(offsetof(Config,ssh_rekey_data)), I(16)); ctrl_text(s, "(Use 1M for 1 megabyte, 1G for 1 gigabyte etc)", HELPCTX(ssh_kex_repeat)); } if (!midsession) { /* PuTTY SC start */ /* * The Connection/SSH/Pkcs11 panel. */ ctrl_settitle(b, "Connection/SSH/Pkcs11", "Options controlling PKCS11 SSH authentication"); s = ctrl_getset(b, "Connection/SSH/Pkcs11", "methods", "Authentication methods"); ctrl_checkbox(s, "Use Windows event log", NO_SHORTCUT, HELPCTX(ssh_write_syslog), dlg_stdcheckbox_handler, I(offsetof(Config,try_write_syslog))); ctrl_checkbox(s, "Attempt \"PKCS#11 smartcard\" auth (SSH-2)", NO_SHORTCUT, HELPCTX(ssh_auth_pkcs11), dlg_stdcheckbox_handler, I(offsetof(Config,try_pkcs11_auth))); s = ctrl_getset(b, "Connection/SSH/Pkcs11", "params", "Authentication parameters"); ctrl_filesel(s, "PKCS#11 library for authentication:", NO_SHORTCUT, FALSE , FALSE, "Select PKCS#11 library file", HELPCTX(ssh_auth_pkcs11_libfile), sc_dlg_stdfilesel_handler11, I(offsetof(Config, pkcs11_libfile))); m_label_ctrl = ctrl_combobox(s, "Token label:", NO_SHORTCUT, 70, HELPCTX(ssh_auth_pkcs11_token_label), sc_tokenlabel_handler, P(NULL), P(NULL)); m_cert_ctrl = ctrl_combobox(s, "Certificate label:", NO_SHORTCUT, 70, HELPCTX(ssh_auth_pkcs11_cert_label), sc_cert_handler, P(NULL), P(NULL)); m_keystring_ctrl = ctrl_editbox(s, "SSH keystring:", NO_SHORTCUT, 100, HELPCTX(ssh_auth_pkcs11_cert_label), sc_keystring_handler, P(NULL), P(NULL)); /* PuTTY SC end */ /* PuTTY CAPI start */ #ifdef _WINDOWS /* * The Connection/SSH/CAPI panel. */ ctrl_settitle(b, "Connection/SSH/CAPI", "Options controlling MS CAPI SSH authentication"); capid = (struct capi_data *) ctrl_alloc(b, sizeof(struct capi_data)); s = ctrl_getset(b, "Connection/SSH/CAPI", "methods", "Authentication methods"); ctrl_checkbox(s, "Attempt \"CAPI Certificate\" (Key-only) auth (SSH-2)", NO_SHORTCUT, HELPCTX(ssh_auth_capi), dlg_stdcheckbox_handler, I(offsetof(Config,try_capi_auth))); s = ctrl_getset(b, "Connection/SSH/CAPI", "params", "Authentication parameters"); capid->certstore_droplist = ctrl_droplist(s, "Store:", NO_SHORTCUT, 85, HELPCTX(ssh_auth_capi_certstore_label), capi_certstore_handler, P(capid)); ctrl_columns(s, 2, 75, 25); capid->certID_text = ctrl_editbox(s, "Cert:", NO_SHORTCUT, 80, HELPCTX(ssh_auth_capi_certstore_label), capi_certID_handler , P(capid), P(NULL) ); capid->certID_text->generic.column = 0; capid->cert_browse = ctrl_pushbutton(s, "Browse", NO_SHORTCUT, HELPCTX(ssh_auth_capi), capi_certstore_browse_handler, P(capid)); capid->cert_browse->generic.column = 1; capid->keystring_text = ctrl_editbox(s, "SSH keystring:", NO_SHORTCUT, 100, HELPCTX(ssh_auth_capi), dlg_stdeditbox_handler, P(NULL), P(NULL)); /* m_label_ctrl = ctrl_combobox(s, "Certificate Store:", NO_SHORTCUT, 70, HELPCTX(ssh_auth_capi_certstore_label), capi_certstore_handler, P(NULL), P(NULL)); m_cert_ctrl = ctrl_combobox(s, "Certificate fingerprint:", NO_SHORTCUT, 70, HELPCTX(ssh_auth_capi_certfingerprint_label), capi_certfingerprint_handler, P(NULL), P(NULL)); m_keystring_ctrl = ctrl_editbox(s, "SSH keystring:", NO_SHORTCUT, 100, HELPCTX(ssh_auth_pkcs11_cert_label), capi_keystring_handler, P(NULL), P(NULL)); */ #endif /* PuTTY CAPI end */ /* * The Connection/SSH/Auth panel. */ ctrl_settitle(b, "Connection/SSH/Auth", "Options controlling SSH authentication"); s = ctrl_getset(b, "Connection/SSH/Auth", "main", NULL); ctrl_checkbox(s, "Bypass authentication entirely (SSH-2 only)", 'b', HELPCTX(ssh_auth_bypass), dlg_stdcheckbox_handler, I(offsetof(Config,ssh_no_userauth))); ctrl_checkbox(s, "Display pre-authentication banner (SSH-2 only)", 'd', HELPCTX(ssh_auth_banner), dlg_stdcheckbox_handler, I(offsetof(Config,ssh_show_banner))); s = ctrl_getset(b, "Connection/SSH/Auth", "methods", "Authentication methods"); ctrl_checkbox(s, "Attempt authentication using Pageant", 'p', HELPCTX(ssh_auth_pageant), dlg_stdcheckbox_handler, I(offsetof(Config,tryagent))); ctrl_checkbox(s, "Attempt TIS or CryptoCard auth (SSH-1)", 'm', HELPCTX(ssh_auth_tis), dlg_stdcheckbox_handler, I(offsetof(Config,try_tis_auth))); ctrl_checkbox(s, "Attempt \"keyboard-interactive\" auth (SSH-2)", 'i', HELPCTX(ssh_auth_ki), dlg_stdcheckbox_handler, I(offsetof(Config,try_ki_auth))); s = ctrl_getset(b, "Connection/SSH/Auth", "params", "Authentication parameters"); ctrl_checkbox(s, "Allow agent forwarding", 'f', HELPCTX(ssh_auth_agentfwd), dlg_stdcheckbox_handler, I(offsetof(Config,agentfwd))); ctrl_checkbox(s, "Allow attempted changes of username in SSH-2", NO_SHORTCUT, HELPCTX(ssh_auth_changeuser), dlg_stdcheckbox_handler, I(offsetof(Config,change_username))); ctrl_filesel(s, "Private key file for authentication:", 'k', FILTER_KEY_FILES, FALSE, "Select private key file", HELPCTX(ssh_auth_privkey), dlg_stdfilesel_handler, I(offsetof(Config, keyfile))); #ifndef NO_GSSAPI /* * Connection/SSH/Auth/GSSAPI, which sadly won't fit on * the main Auth panel. */ ctrl_settitle(b, "Connection/SSH/Auth/GSSAPI", "Options controlling GSSAPI authentication"); s = ctrl_getset(b, "Connection/SSH/Auth/GSSAPI", "gssapi", NULL); ctrl_checkbox(s, "Attempt GSSAPI authentication (SSH-2 only)", 't', HELPCTX(ssh_gssapi), dlg_stdcheckbox_handler, I(offsetof(Config,try_gssapi_auth))); ctrl_checkbox(s, "Allow GSSAPI credential delegation", 'l', HELPCTX(ssh_gssapi_delegation), dlg_stdcheckbox_handler, I(offsetof(Config,gssapifwd))); /* * GSSAPI library selection. */ if (ngsslibs > 1) { c = ctrl_draglist(s, "Preference order for GSSAPI libraries:", 'p', HELPCTX(ssh_gssapi_libraries), |
︙ | ︙ | |||
2278 2279 2280 2281 2282 2283 2284 | * ngsslibs to control whether the file selector is * displayed. */ ctrl_filesel(s, "User-supplied GSSAPI library path:", 's', FILTER_DYNLIB_FILES, FALSE, "Select library file", HELPCTX(ssh_gssapi_libraries), | | | | | | 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 | * ngsslibs to control whether the file selector is * displayed. */ ctrl_filesel(s, "User-supplied GSSAPI library path:", 's', FILTER_DYNLIB_FILES, FALSE, "Select library file", HELPCTX(ssh_gssapi_libraries), dlg_stdfilesel_handler, I(offsetof(Config, ssh_gss_custom))); } #endif } if (!midsession) { /* * The Connection/SSH/TTY panel. */ ctrl_settitle(b, "Connection/SSH/TTY", "Remote terminal settings"); s = ctrl_getset(b, "Connection/SSH/TTY", "sshtty", NULL); ctrl_checkbox(s, "Don't allocate a pseudo-terminal", 'p', HELPCTX(ssh_nopty), dlg_stdcheckbox_handler, I(offsetof(Config,nopty))); s = ctrl_getset(b, "Connection/SSH/TTY", "ttymodes", "Terminal modes"); td = (struct ttymodes_data *) ctrl_alloc(b, sizeof(struct ttymodes_data)); ctrl_columns(s, 2, 75, 25); c = ctrl_text(s, "Terminal modes to send:", HELPCTX(ssh_ttymodes)); |
︙ | ︙ | |||
2360 2361 2362 2363 2364 2365 2366 | */ ctrl_settitle(b, "Connection/SSH/X11", "Options controlling SSH X11 forwarding"); s = ctrl_getset(b, "Connection/SSH/X11", "x11", "X11 forwarding"); ctrl_checkbox(s, "Enable X11 forwarding", 'e', HELPCTX(ssh_tunnels_x11), | | | > | | | | | | | 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 | */ ctrl_settitle(b, "Connection/SSH/X11", "Options controlling SSH X11 forwarding"); s = ctrl_getset(b, "Connection/SSH/X11", "x11", "X11 forwarding"); ctrl_checkbox(s, "Enable X11 forwarding", 'e', HELPCTX(ssh_tunnels_x11), dlg_stdcheckbox_handler,I(offsetof(Config,x11_forward))); ctrl_editbox(s, "X display location", 'x', 50, HELPCTX(ssh_tunnels_x11), dlg_stdeditbox_handler, I(offsetof(Config,x11_display)), I(sizeof(((Config *)0)->x11_display))); ctrl_radiobuttons(s, "Remote X11 authentication protocol", 'u', 2, HELPCTX(ssh_tunnels_x11auth), dlg_stdradiobutton_handler, I(offsetof(Config, x11_auth)), "MIT-Magic-Cookie-1", I(X11_MIT), "XDM-Authorization-1", I(X11_XDM), NULL); } /* * The Tunnels panel _is_ still available in mid-session. */ ctrl_settitle(b, "Connection/SSH/Tunnels", "Options controlling SSH port forwarding"); s = ctrl_getset(b, "Connection/SSH/Tunnels", "portfwd", "Port forwarding"); ctrl_checkbox(s, "Local ports accept connections from other hosts",'t', HELPCTX(ssh_tunnels_portfwd_localhost), dlg_stdcheckbox_handler, I(offsetof(Config,lport_acceptall))); ctrl_checkbox(s, "Remote ports do the same (SSH-2 only)", 'p', HELPCTX(ssh_tunnels_portfwd_localhost), dlg_stdcheckbox_handler, I(offsetof(Config,rport_acceptall))); ctrl_columns(s, 3, 55, 20, 25); c = ctrl_text(s, "Forwarded ports:", HELPCTX(ssh_tunnels_portfwd)); c->generic.column = COLUMN_FIELD(0,2); /* You want to select from the list, _then_ hit Remove. So tab order * should be that way round. */ pfd = (struct portfwd_data *)ctrl_alloc(b,sizeof(struct portfwd_data)); |
︙ | ︙ | |||
2455 2456 2457 2458 2459 2460 2461 | ctrl_settitle(b, "Connection/SSH/Bugs", "Workarounds for SSH server bugs"); s = ctrl_getset(b, "Connection/SSH/Bugs", "main", "Detection of known bugs in SSH servers"); ctrl_droplist(s, "Chokes on SSH-1 ignore messages", 'i', 20, HELPCTX(ssh_bugs_ignore1), | | | | | < < < | | | | | | | 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 | ctrl_settitle(b, "Connection/SSH/Bugs", "Workarounds for SSH server bugs"); s = ctrl_getset(b, "Connection/SSH/Bugs", "main", "Detection of known bugs in SSH servers"); ctrl_droplist(s, "Chokes on SSH-1 ignore messages", 'i', 20, HELPCTX(ssh_bugs_ignore1), sshbug_handler, I(offsetof(Config,sshbug_ignore1))); ctrl_droplist(s, "Refuses all SSH-1 password camouflage", 's', 20, HELPCTX(ssh_bugs_plainpw1), sshbug_handler, I(offsetof(Config,sshbug_plainpw1))); ctrl_droplist(s, "Chokes on SSH-1 RSA authentication", 'r', 20, HELPCTX(ssh_bugs_rsa1), sshbug_handler, I(offsetof(Config,sshbug_rsa1))); ctrl_droplist(s, "Chokes on SSH-2 ignore messages", '2', 20, HELPCTX(ssh_bugs_ignore2), sshbug_handler, I(offsetof(Config,sshbug_ignore2))); ctrl_droplist(s, "Miscomputes SSH-2 HMAC keys", 'm', 20, HELPCTX(ssh_bugs_hmac2), sshbug_handler, I(offsetof(Config,sshbug_hmac2))); ctrl_droplist(s, "Miscomputes SSH-2 encryption keys", 'e', 20, HELPCTX(ssh_bugs_derivekey2), sshbug_handler, I(offsetof(Config,sshbug_derivekey2))); ctrl_droplist(s, "Requires padding on SSH-2 RSA signatures", 'p', 20, HELPCTX(ssh_bugs_rsapad2), sshbug_handler, I(offsetof(Config,sshbug_rsapad2))); ctrl_droplist(s, "Misuses the session ID in SSH-2 PK auth", 'n', 20, HELPCTX(ssh_bugs_pksessid2), sshbug_handler, I(offsetof(Config,sshbug_pksessid2))); ctrl_droplist(s, "Handles SSH-2 key re-exchange badly", 'k', 20, HELPCTX(ssh_bugs_rekey2), sshbug_handler, I(offsetof(Config,sshbug_rekey2))); ctrl_droplist(s, "Ignores SSH-2 maximum packet size", 'x', 20, HELPCTX(ssh_bugs_maxpkt2), sshbug_handler, I(offsetof(Config,sshbug_maxpkt2))); } } } |
Deleted configure.
|
| < < < |
Changes to contrib/cygtermd/pty.c.
︙ | ︙ | |||
118 119 120 121 122 123 124 | i = 0; #ifdef TIOCNOTTY if ((fd = open("/dev/tty", O_RDWR)) >= 0) { ioctl(fd, TIOCNOTTY, &i); close(fd); } #endif | < < < < < < < < < | < < < < < | 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | i = 0; #ifdef TIOCNOTTY if ((fd = open("/dev/tty", O_RDWR)) >= 0) { ioctl(fd, TIOCNOTTY, &i); close(fd); } #endif #ifdef TIOCSCTTY ioctl(0, TIOCSCTTY, &i); #endif tcsetpgrp(0, getpgrp()); for (i = 0; i < shdata->nenvvars; i++) putenv(shdata->envvars[i]); if (shdata->termtype) putenv(shdata->termtype); |
︙ | ︙ |
Changes to contrib/cygtermd/telnet.c.
︙ | ︙ | |||
420 421 422 423 424 425 426 | telnet->state = TOP_LEVEL; else if (c == IAC) telnet->state = SEENIAC; else { char cc = c; sel_write(telnet->pty, &cc, 1); | < | < < | 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 | telnet->state = TOP_LEVEL; else if (c == IAC) telnet->state = SEENIAC; else { char cc = c; sel_write(telnet->pty, &cc, 1); telnet->state = SEENCR; } break; case SEENIAC: if (c == DO) telnet->state = SEENDO; else if (c == DONT) telnet->state = SEENDONT; |
︙ | ︙ |
Deleted contrib/logparse.pl.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to cproxy.c.
︙ | ︙ | |||
126 127 128 129 130 131 132 | break; case 0x03: outbuf[0] = 0x01; /* Version */ outbuf[1] = 0x01; /* One attribute */ outbuf[2] = 0x04; /* Response */ outbuf[3] = 0x10; /* Length */ hmacmd5_chap(data, p->chap_current_datalen, | < | | 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | break; case 0x03: outbuf[0] = 0x01; /* Version */ outbuf[1] = 0x01; /* One attribute */ outbuf[2] = 0x04; /* Response */ outbuf[3] = 0x10; /* Length */ hmacmd5_chap(data, p->chap_current_datalen, p->cfg.proxy_password, &outbuf[4]); sk_write(p->sub_socket, (char *)outbuf, 20); break; case 0x11: /* Chose a protocol */ if (data[0] != 0x85) { plug_closing(p->plug, "Proxy error: Server chose " "CHAP of other than HMAC-MD5 but we " |
︙ | ︙ | |||
156 157 158 159 160 161 162 | } } return 0; } int proxy_socks5_selectchap(Proxy_Socket p) { | < < | | | | 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | } } return 0; } int proxy_socks5_selectchap(Proxy_Socket p) { if (p->cfg.proxy_username[0] || p->cfg.proxy_password[0]) { char chapbuf[514]; int ulen; chapbuf[0] = '\x01'; /* Version */ chapbuf[1] = '\x02'; /* Number of attributes sent */ chapbuf[2] = '\x11'; /* First attribute - algorithms list */ chapbuf[3] = '\x01'; /* Only one CHAP algorithm */ chapbuf[4] = '\x85'; /* ...and it's HMAC-MD5, the core one */ chapbuf[5] = '\x02'; /* Second attribute - username */ ulen = strlen(p->cfg.proxy_username); if (ulen > 255) ulen = 255; if (ulen < 1) ulen = 1; chapbuf[6] = ulen; memcpy(chapbuf+7, p->cfg.proxy_username, ulen); sk_write(p->sub_socket, chapbuf, ulen + 7); p->chap_num_attributes = 0; p->chap_num_attributes_processed = 0; p->chap_current_attribute = -1; p->chap_current_datalen = 0; |
︙ | ︙ |
Changes to dialog.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 15 16 17 18 19 20 21 | #include <stdarg.h> #include <stdlib.h> #define DEFINE_INTORPTR_FNS #include "putty.h" #include "dialog.h" int ctrl_path_elements(char *path) { int i = 1; while (*path) { if (*path == '/') i++; path++; | > > > > | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | #include <stdarg.h> #include <stdlib.h> #define DEFINE_INTORPTR_FNS #include "putty.h" #include "dialog.h" /* PuTTY SC start */ //#include <dirent.h> /* PuTTY SC end */ int ctrl_path_elements(char *path) { int i = 1; while (*path) { if (*path == '/') i++; path++; |
︙ | ︙ | |||
43 44 45 46 47 48 49 | { struct controlbox *ret = snew(struct controlbox); ret->nctrlsets = ret->ctrlsetsize = 0; ret->ctrlsets = NULL; ret->nfrees = ret->freesize = 0; ret->frees = NULL; | < | < | 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | { struct controlbox *ret = snew(struct controlbox); ret->nctrlsets = ret->ctrlsetsize = 0; ret->ctrlsets = NULL; ret->nfrees = ret->freesize = 0; ret->frees = NULL; return ret; } void ctrl_free_box(struct controlbox *b) { int i; for (i = 0; i < b->nctrlsets; i++) { ctrl_free_set(b->ctrlsets[i]); } for (i = 0; i < b->nfrees; i++) sfree(b->frees[i]); sfree(b->ctrlsets); sfree(b->frees); sfree(b); } void ctrl_free_set(struct controlset *s) { int i; |
︙ | ︙ | |||
179 180 181 182 183 184 185 | (b->nctrlsets-index) * sizeof(*b->ctrlsets)); b->ctrlsets[index] = s; b->nctrlsets++; return s; } /* Allocate some private data in a controlbox. */ | | < < | < < < < < < < < < < < < | 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 | (b->nctrlsets-index) * sizeof(*b->ctrlsets)); b->ctrlsets[index] = s; b->nctrlsets++; return s; } /* Allocate some private data in a controlbox. */ void *ctrl_alloc(struct controlbox *b, size_t size) { void *p; /* * This is an internal allocation routine, so it's allowed to * use smalloc directly. */ p = smalloc(size); if (b->nfrees >= b->freesize) { b->freesize = b->nfrees + 32; b->frees = sresize(b->frees, b->freesize, void *); } b->frees[b->nfrees++] = p; return p; } static union control *ctrl_new(struct controlset *s, int type, intorptr helpctx, handler_fn handler, intorptr context) { union control *c = snew(union control); |
︙ | ︙ | |||
468 469 470 471 472 473 474 | break; case CTRL_FILESELECT: sfree(ctrl->fileselect.title); break; } sfree(ctrl); } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 | break; case CTRL_FILESELECT: sfree(ctrl->fileselect.title); break; } sfree(ctrl); } void dlg_stdradiobutton_handler(union control *ctrl, void *dlg, void *data, int event) { int button; /* * For a standard radio button set, the context parameter gives * offsetof(targetfield, Config), and the extra data per button * gives the value the target field should take if that button * is the one selected. */ if (event == EVENT_REFRESH) { for (button = 0; button < ctrl->radio.nbuttons; button++) if (*(int *)ATOFFSET(data, ctrl->radio.context.i) == ctrl->radio.buttondata[button].i) break; /* We expected that `break' to happen, in all circumstances. */ assert(button < ctrl->radio.nbuttons); dlg_radiobutton_set(ctrl, dlg, button); } else if (event == EVENT_VALCHANGE) { button = dlg_radiobutton_get(ctrl, dlg); assert(button >= 0 && button < ctrl->radio.nbuttons); *(int *)ATOFFSET(data, ctrl->radio.context.i) = ctrl->radio.buttondata[button].i; } } void dlg_stdcheckbox_handler(union control *ctrl, void *dlg, void *data, int event) { int offset, invert; /* * For a standard checkbox, the context parameter gives * offsetof(targetfield, Config), optionally ORed with * CHECKBOX_INVERT. */ offset = ctrl->checkbox.context.i; if (offset & CHECKBOX_INVERT) { offset &= ~CHECKBOX_INVERT; invert = 1; } else invert = 0; /* * C lacks a logical XOR, so the following code uses the idiom * (!a ^ !b) to obtain the logical XOR of a and b. (That is, 1 * iff exactly one of a and b is nonzero, otherwise 0.) */ if (event == EVENT_REFRESH) { dlg_checkbox_set(ctrl,dlg, (!*(int *)ATOFFSET(data,offset) ^ !invert)); } else if (event == EVENT_VALCHANGE) { *(int *)ATOFFSET(data, offset) = !dlg_checkbox_get(ctrl,dlg) ^ !invert; } } void dlg_stdeditbox_handler(union control *ctrl, void *dlg, void *data, int event) { /* * The standard edit-box handler expects the main `context' * field to contain the `offsetof' a field in the structure * pointed to by `data'. The secondary `context2' field * indicates the type of this field: * * - if context2 > 0, the field is a char array and context2 * gives its size. * - if context2 == -1, the field is an int and the edit box * is numeric. * - if context2 < -1, the field is an int and the edit box is * _floating_, and (-context2) gives the scale. (E.g. if * context2 == -1000, then typing 1.2 into the box will set * the field to 1200.) */ int offset = ctrl->editbox.context.i; int length = ctrl->editbox.context2.i; if (length > 0) { char *field = (char *)ATOFFSET(data, offset); if (event == EVENT_REFRESH) { dlg_editbox_set(ctrl, dlg, field); } else if (event == EVENT_VALCHANGE) { dlg_editbox_get(ctrl, dlg, field, length); } } else if (length < 0) { int *field = (int *)ATOFFSET(data, offset); char data[80]; if (event == EVENT_REFRESH) { if (length == -1) sprintf(data, "%d", *field); else sprintf(data, "%g", (double)*field / (double)(-length)); dlg_editbox_set(ctrl, dlg, data); } else if (event == EVENT_VALCHANGE) { dlg_editbox_get(ctrl, dlg, data, lenof(data)); if (length == -1) *field = atoi(data); else *field = (int)((-length) * atof(data)); } } } void dlg_stdfilesel_handler(union control *ctrl, void *dlg, void *data, int event) { /* * The standard file-selector handler expects the `context' * field to contain the `offsetof' a Filename field in the * structure pointed to by `data'. */ int offset = ctrl->fileselect.context.i; if (event == EVENT_REFRESH) { dlg_filesel_set(ctrl, dlg, *(Filename *)ATOFFSET(data, offset)); } else if (event == EVENT_VALCHANGE) { dlg_filesel_get(ctrl, dlg, (Filename *)ATOFFSET(data, offset)); } } /* PuTTY SC start */ void *sc_get_label_dialog(); void *sc_get_label_ctrl(); void sc_tokenlabel_handler(union control *ctrl, void *dlg, void *data, int event ); void sc_dlg_stdfilesel_handler11(union control *ctrl, void *dlg, void *data, int event) { int offset = ctrl->fileselect.context.i; if (event == EVENT_REFRESH) { dlg_filesel_set(ctrl, dlg, *(Filename *)ATOFFSET(data, offset)); } else if (event == EVENT_VALCHANGE) { dlg_filesel_get(ctrl, dlg, (Filename *)ATOFFSET(data, offset)); } if(sc_get_label_dialog() != NULL) { sc_tokenlabel_handler(sc_get_label_ctrl(), sc_get_label_dialog(), data, EVENT_REFRESH); } } /* PuTTY SC end */ void dlg_stdfontsel_handler(union control *ctrl, void *dlg, void *data, int event) { /* * The standard file-selector handler expects the `context' * field to contain the `offsetof' a FontSpec field in the * structure pointed to by `data'. */ int offset = ctrl->fontselect.context.i; if (event == EVENT_REFRESH) { dlg_fontsel_set(ctrl, dlg, *(FontSpec *)ATOFFSET(data, offset)); } else if (event == EVENT_VALCHANGE) { dlg_fontsel_get(ctrl, dlg, (FontSpec *)ATOFFSET(data, offset)); } } |
Changes to dialog.h.
︙ | ︙ | |||
158 159 160 161 162 163 164 | /* * Most controls need to provide a function which gets * called when that control's setting is changed, or when * the control's setting needs initialising. * * The `data' parameter points to the writable data being * modified as a result of the configuration activity; for | | | 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | /* * Most controls need to provide a function which gets * called when that control's setting is changed, or when * the control's setting needs initialising. * * The `data' parameter points to the writable data being * modified as a result of the configuration activity; for * example, the PuTTY `Config' structure, although not * necessarily. * * The `dlg' parameter is passed back to the platform- * specific routines to read and write the actual control * state. */ handler_fn handler; |
︙ | ︙ | |||
423 424 425 426 427 428 429 | char *boxtitle; /* title of container box */ int ncolumns; /* current no. of columns at bottom */ int ncontrols; /* number of `union control' in array */ int ctrlsize; /* allocated size of array */ union control **ctrls; /* actual array */ }; | < < < | 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 | char *boxtitle; /* title of container box */ int ncolumns; /* current no. of columns at bottom */ int ncontrols; /* number of `union control' in array */ int ctrlsize; /* allocated size of array */ union control **ctrls; /* actual array */ }; /* * This is the container structure which holds a complete set of * controls. */ struct controlbox { int nctrlsets; /* number of ctrlsets */ int ctrlsetsize; /* ctrlset size */ struct controlset **ctrlsets; /* actual array of ctrlsets */ int nfrees; int freesize; void **frees; /* array of aux data areas to free */ }; struct controlbox *ctrl_new_box(void); void ctrl_free_box(struct controlbox *); /* * Standard functions used for populating a controlbox structure. |
︙ | ︙ | |||
463 464 465 466 467 468 469 | /* * This function works like `malloc', but the memory it returns * will be automatically freed when the controlbox is freed. Note * that a controlbox is a dialog-box _template_, not an instance, * and so data allocated through this function is better not used * to hold modifiable per-instance things. It's mostly here for * allocating structures to be passed as control handler params. | < < < < < < | 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 | /* * This function works like `malloc', but the memory it returns * will be automatically freed when the controlbox is freed. Note * that a controlbox is a dialog-box _template_, not an instance, * and so data allocated through this function is better not used * to hold modifiable per-instance things. It's mostly here for * allocating structures to be passed as control handler params. */ void *ctrl_alloc(struct controlbox *b, size_t size); /* * Individual routines to create `union control' structures in a controlset. * * Most of these routines allow the most common fields to be set * directly, and put default values in the rest. Each one returns a * pointer to the `union control' it created, so that final tweaks |
︙ | ︙ | |||
526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 | handler_fn handler, intorptr context); union control *ctrl_text(struct controlset *, char *text, intorptr helpctx); union control *ctrl_checkbox(struct controlset *, char *label, char shortcut, intorptr helpctx, handler_fn handler, intorptr context); union control *ctrl_tabdelay(struct controlset *, union control *); /* * Routines the platform-independent dialog code can call to read * and write the values of controls. */ void dlg_radiobutton_set(union control *ctrl, void *dlg, int whichbutton); int dlg_radiobutton_get(union control *ctrl, void *dlg); void dlg_checkbox_set(union control *ctrl, void *dlg, int checked); int dlg_checkbox_get(union control *ctrl, void *dlg); void dlg_editbox_set(union control *ctrl, void *dlg, char const *text); | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 | handler_fn handler, intorptr context); union control *ctrl_text(struct controlset *, char *text, intorptr helpctx); union control *ctrl_checkbox(struct controlset *, char *label, char shortcut, intorptr helpctx, handler_fn handler, intorptr context); union control *ctrl_tabdelay(struct controlset *, union control *); /* * Standard handler routines to cover most of the common cases in * the config box. */ /* * The standard radio-button handler expects the main `context' * field to contain the `offsetof' of an int field in the structure * pointed to by `data', and expects each of the individual button * data to give a value for that int field. */ void dlg_stdradiobutton_handler(union control *ctrl, void *dlg, void *data, int event); /* * The standard checkbox handler expects the main `context' field * to contain the `offsetof' an int field in the structure pointed * to by `data', optionally ORed with CHECKBOX_INVERT to indicate * that the sense of the datum is opposite to the sense of the * checkbox. */ #define CHECKBOX_INVERT (1<<30) void dlg_stdcheckbox_handler(union control *ctrl, void *dlg, void *data, int event); /* * The standard edit-box handler expects the main `context' field * to contain the `offsetof' a field in the structure pointed to by * `data'. The secondary `context2' field indicates the type of * this field: * * - if context2 > 0, the field is a char array and context2 gives * its size. * - if context2 == -1, the field is an int and the edit box is * numeric. * - if context2 < -1, the field is an int and the edit box is * _floating_, and (-context2) gives the scale. (E.g. if * context2 == -1000, then typing 1.2 into the box will set the * field to 1200.) */ void dlg_stdeditbox_handler(union control *ctrl, void *dlg, void *data, int event); /* * The standard file-selector handler expects the main `context' * field to contain the `offsetof' a Filename field in the * structure pointed to by `data'. */ void dlg_stdfilesel_handler(union control *ctrl, void *dlg, void *data, int event); /* PuTTY SC start */ void sc_dlg_stdfilesel_handler11(union control *ctrl, void *dlg, void *data, int event); /* PuTTY SC end */ /* * The standard font-selector handler expects the main `context' * field to contain the `offsetof' a Font field in the structure * pointed to by `data'. */ void dlg_stdfontsel_handler(union control *ctrl, void *dlg, void *data, int event); /* * Routines the platform-independent dialog code can call to read * and write the values of controls. */ void dlg_radiobutton_set(union control *ctrl, void *dlg, int whichbutton); int dlg_radiobutton_get(union control *ctrl, void *dlg); void dlg_checkbox_set(union control *ctrl, void *dlg, int checked); int dlg_checkbox_get(union control *ctrl, void *dlg); void dlg_editbox_set(union control *ctrl, void *dlg, char const *text); void dlg_editbox_get(union control *ctrl, void *dlg, char *buffer, int length); /* The `listbox' functions can also apply to combo boxes. */ void dlg_listbox_clear(union control *ctrl, void *dlg); void dlg_listbox_del(union control *ctrl, void *dlg, int index); void dlg_listbox_add(union control *ctrl, void *dlg, char const *text); /* * Each listbox entry may have a numeric id associated with it. * Note that some front ends only permit a string to be stored at * each position, which means that _if_ you put two identical * strings in any listbox then you MUST not assign them different * IDs and expect to get meaningful results back. */ void dlg_listbox_addwithid(union control *ctrl, void *dlg, char const *text, int id); int dlg_listbox_getid(union control *ctrl, void *dlg, int index); /* dlg_listbox_index returns <0 if no single element is selected. */ int dlg_listbox_index(union control *ctrl, void *dlg); int dlg_listbox_issel(union control *ctrl, void *dlg, int index); void dlg_listbox_select(union control *ctrl, void *dlg, int index); void dlg_text_set(union control *ctrl, void *dlg, char const *text); void dlg_filesel_set(union control *ctrl, void *dlg, Filename fn); void dlg_filesel_get(union control *ctrl, void *dlg, Filename *fn); void dlg_fontsel_set(union control *ctrl, void *dlg, FontSpec fn); void dlg_fontsel_get(union control *ctrl, void *dlg, FontSpec *fn); /* * Bracketing a large set of updates in these two functions will * cause the front end (if possible) to delay updating the screen * until it's all complete, thus avoiding flicker. */ void dlg_update_start(union control *ctrl, void *dlg); void dlg_update_done(union control *ctrl, void *dlg); |
︙ | ︙ |
Changes to doc/blurb.but.
|
| | < < | 1 2 3 4 5 6 7 8 | \define{versionidblurb} \versionid $Id: blurb.but 9072 2011-01-05 12:01:00Z jacob $ \title PuTTY User Manual \cfg{xhtml-leaf-level}{1} \cfg{xhtml-leaf-smallest-contents}{2} \cfg{xhtml-leaf-contains-contents}{true} \cfg{xhtml-body-end}{<p>If you want to provide feedback on this manual |
︙ | ︙ | |||
29 30 31 32 33 34 35 | Windows versions of the PuTTY utilities. Some options are therefore mentioned that are absent from the \i{Unix version}; the Unix version has features not described here; and the \i\cw{pterm} and command-line \cw{puttygen} utilities are not described at all. The only Unix-specific documentation that currently exists is the \I{man pages for PuTTY tools}man pages. | | | 27 28 29 30 31 32 33 34 35 36 | Windows versions of the PuTTY utilities. Some options are therefore mentioned that are absent from the \i{Unix version}; the Unix version has features not described here; and the \i\cw{pterm} and command-line \cw{puttygen} utilities are not described at all. The only Unix-specific documentation that currently exists is the \I{man pages for PuTTY tools}man pages. \copyright This manual is copyright 2001-2011 Simon Tatham. All rights reserved. You may distribute this documentation under the MIT licence. See \k{licence} for the licence text in full. |
Changes to doc/config.but.
|
| | | 1 2 3 4 5 6 7 8 | \define{versionidconfig} \versionid $Id: config.but 9063 2010-12-29 14:11:25Z simon $ \C{config} Configuring PuTTY This chapter describes all the \i{configuration options} in PuTTY. PuTTY is configured using the control panel that comes up before you start a session. Some options can also be changed in the middle of a |
︙ | ︙ | |||
1250 1251 1252 1253 1254 1255 1256 | needs to know what character set to interpret them in. Similarly, PuTTY needs to know how to translate your keystrokes into the encoding the server expects. Unfortunately, there is no satisfactory mechanism for PuTTY and the server to communicate this information, so it must usually be manually configured. There are a lot of character sets to choose from. The \q{Remote | | | < < < < | | | > > > > > > | 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 | needs to know what character set to interpret them in. Similarly, PuTTY needs to know how to translate your keystrokes into the encoding the server expects. Unfortunately, there is no satisfactory mechanism for PuTTY and the server to communicate this information, so it must usually be manually configured. There are a lot of character sets to choose from. The \q{Remote character set} option lets you select one. By default PuTTY will attempt to choose a character set that is right for your \i{locale} as reported by Windows; if it gets it wrong, you can select a different one using this control. A few notable character sets are: \b The \i{ISO-8859} series are all standard character sets that include various accented characters appropriate for different sets of languages. \b The \i{Win125x} series are defined by Microsoft, for similar purposes. In particular Win1252 is almost equivalent to ISO-8859-1, but contains a few extra characters such as matched quotes and the Euro symbol. \b If you want the old IBM PC character set with block graphics and line-drawing characters, you can select \q{\i{CP437}}. \b PuTTY also supports \i{Unicode} mode, in which the data coming from the server is interpreted as being in the \i{UTF-8} encoding of Unicode, and keystrokes are sent UTF-8 encoded. If you select \q{UTF-8} as a character set you can use this mode. Not all server-side applications will support it. If you need support for a numeric \i{code page} which is not listed in the drop-down list, such as code page 866, then you can try entering its name manually (\c{\i{CP866}} for example) in the list box. If the underlying version of Windows has the appropriate translation table installed, PuTTY will use it. |
︙ | ︙ | |||
1535 1536 1537 1538 1539 1540 1541 | \c colors#256, cols#80, it#8, lines#24, pairs#256, \e bbbbbbbbbb If you do not see \cq{colors#256} in the output, you may need to change your terminal setting. On modern Linux machines, you could try \cq{xterm-256color}. | | | | < | | | | | | < | 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 | \c colors#256, cols#80, it#8, lines#24, pairs#256, \e bbbbbbbbbb If you do not see \cq{colors#256} in the output, you may need to change your terminal setting. On modern Linux machines, you could try \cq{xterm-256color}. \S{config-boldcolour} \q{Bolded text is a different colour} \cfg{winhelp-topic}{colours.bold} When the server sends a \i{control sequence} indicating that some text should be displayed in \i{bold}, PuTTY can handle this two ways. It can either change the \i{font} for a bold version, or use the same font in a brighter colour. This control lets you choose which. By default the box is checked, so non-bold text is displayed in light grey and bold text is displayed in bright white (and similarly in other colours). If you uncheck the box, bold and non-bold text will be displayed in the same colour, and instead the font will change to indicate the difference. \S{config-logpalette} \q{Attempt to use \i{logical palettes}} \cfg{winhelp-topic}{colours.logpal} Logical palettes are a mechanism by which a Windows application running on an \i{8-bit colour} display can select precisely the colours |
︙ | ︙ | |||
2270 2271 2272 2273 2274 2275 2276 | PuTTY will attempt to use protocol 1 if the server you connect to does not offer protocol 2, and vice versa. If you select \q{1 only} or \q{2 only} here, PuTTY will only connect if the server you connect to offers the SSH protocol version you have specified. | | | > | > > | > > < < < < > < < | | | | | | | | < < < < > | < < > | | > < | | | > > | < < | < < < < | | < > | < < > > | < < < < > > > | 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 | PuTTY will attempt to use protocol 1 if the server you connect to does not offer protocol 2, and vice versa. If you select \q{1 only} or \q{2 only} here, PuTTY will only connect if the server you connect to offers the SSH protocol version you have specified. \S{config-ssh-encryption} \ii{Encryption} algorithm selection \cfg{winhelp-topic}{ssh.ciphers} PuTTY supports a variety of different \i{encryption algorithm}s, and allows you to choose which one you prefer to use. You can do this by dragging the algorithms up and down in the list box (or moving them using the Up and Down buttons) to specify a preference order. When you make an SSH connection, PuTTY will search down the list from the top until it finds an algorithm supported by the server, and then use that. PuTTY currently supports the following algorithms: \b \i{AES} (Rijndael) - 256, 192, or 128-bit SDCTR or CBC (SSH-2 only) \b \i{Arcfour} (RC4) - 256 or 128-bit stream cipher (SSH-2 only) \b \i{Blowfish} - 256-bit SDCTR (SSH-2 only) or 128-bit CBC \b \ii{Triple-DES} - 168-bit SDCTR (SSH-2 only) or CBC \b \ii{Single-DES} - 56-bit CBC (see below for SSH-2) If the algorithm PuTTY finds is below the \q{warn below here} line, you will see a warning box when you make the connection: \c The first cipher supported by the server \c is single-DES, which is below the configured \c warning threshold. \c Do you want to continue with this connection? This warns you that the first available encryption is not a very secure one. Typically you would put the \q{warn below here} line between the encryptions you consider secure and the ones you consider substandard. By default, PuTTY supplies a preference order intended to reflect a reasonable preference in terms of security and speed. In SSH-2, the encryption algorithm is negotiated independently for each direction of the connection, although PuTTY does not support separate configuration of the preference orders. As a result you may get two warnings similar to the one above, possibly with different encryptions. Single-DES is not recommended in the SSH-2 protocol standards, but one or two server implementations do support it. PuTTY can use single-DES to interoperate with these servers if you enable the \q{Enable legacy use of single-DES in SSH-2} option; by default this is disabled and PuTTY will stick to recommended ciphers. \H{config-ssh-kex} The Kex panel \# FIXME: This whole section is draft. Feel free to revise. The Kex panel (short for \q{\i{key exchange}}) allows you to configure options related to SSH-2 key exchange. |
︙ | ︙ | |||
2458 2459 2460 2461 2462 2463 2464 | and to a lesser extent, \i{confidentiality} of the SSH-2 protocol depend in part on rekeys occuring before a 32-bit packet sequence number wraps around. Unlike time-based rekeys, data-based rekeys won't occur when the SSH connection is idle, so they shouldn't cause the same problems. The SSH-1 protocol, incidentally, has even weaker integrity protection than SSH-2 without rekeys. | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 | and to a lesser extent, \i{confidentiality} of the SSH-2 protocol depend in part on rekeys occuring before a 32-bit packet sequence number wraps around. Unlike time-based rekeys, data-based rekeys won't occur when the SSH connection is idle, so they shouldn't cause the same problems. The SSH-1 protocol, incidentally, has even weaker integrity protection than SSH-2 without rekeys. \H{config-ssh-auth} The Auth panel The Auth panel allows you to configure \i{authentication} options for SSH sessions. \S{config-ssh-noauth} \q{Bypass authentication entirely} |
︙ | ︙ | |||
3263 3264 3265 3266 3267 3268 3269 | If this bug is detected, PuTTY never allows the channel's \i{flow-control window} to grow large enough to allow the server to send an over-sized packet. If this bug is enabled when talking to a correct server, the session will work correctly, but download performance will be less than it could be. | < < < < < < < < < < < < < < < < < < < < < < < | 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 | If this bug is detected, PuTTY never allows the channel's \i{flow-control window} to grow large enough to allow the server to send an over-sized packet. If this bug is enabled when talking to a correct server, the session will work correctly, but download performance will be less than it could be. \H{config-serial} The Serial panel The \i{Serial} panel allows you to configure options that only apply when PuTTY is connecting to a local \I{serial port}\i{serial line}. \S{config-serial-line} Selecting a serial line to connect to |
︙ | ︙ |
Changes to doc/errors.but.
|
| | | 1 2 3 4 5 6 7 8 | \define{versioniderrors} \versionid $Id: errors.but 8897 2010-03-13 14:47:14Z jacob $ \C{errors} Common \i{error messages} This chapter lists a number of common error messages which PuTTY and its associated tools can produce, and explains what they mean in more detail. |
︙ | ︙ | |||
54 55 56 57 58 59 60 61 62 63 64 65 66 67 | You should contact your server's administrator and see whether they expect the host key to have changed. If so, verify the new host key in the same way as you would if it was new. See \k{gs-hostkey} for more information on host keys. \H{errors-cipher-warning} \q{The first cipher supported by the server is ... below the configured warning threshold} This occurs when the SSH server does not offer any ciphers which you have configured PuTTY to consider strong enough. By default, PuTTY puts up this warning only for \ii{single-DES} and \i{Arcfour} encryption. | > > > > > > > > > > > > > > | 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | You should contact your server's administrator and see whether they expect the host key to have changed. If so, verify the new host key in the same way as you would if it was new. See \k{gs-hostkey} for more information on host keys. \H{errors-portfwd-space} \q{Out of space for port forwardings} PuTTY has a fixed-size buffer which it uses to store the details of all \i{port forwardings} you have set up in an SSH session. If you specify too many port forwardings on the PuTTY or Plink command line and this buffer becomes full, you will see this error message. We need to fix this (fixed-size buffers are almost always a mistake) but we haven't got round to it. If you actually have trouble with this, let us know and we'll move it up our priority list. If you're running into this limit, you may want to consider using dynamic port forwarding instead; see \k{using-port-forwarding}. \H{errors-cipher-warning} \q{The first cipher supported by the server is ... below the configured warning threshold} This occurs when the SSH server does not offer any ciphers which you have configured PuTTY to consider strong enough. By default, PuTTY puts up this warning only for \ii{single-DES} and \i{Arcfour} encryption. |
︙ | ︙ |
Changes to doc/faq.but.
|
| | | 1 2 3 4 5 6 7 8 | \define{versionidfaq} \versionid $Id: faq.but 8733 2009-11-01 22:06:05Z jacob $ \A{faq} PuTTY \i{FAQ} This FAQ is published on the PuTTY web site, and also provided as an appendix in the manual. \H{faq-intro} Introduction |
︙ | ︙ | |||
1039 1040 1041 1042 1043 1044 1045 | \q{the application configuration is incorrect}. This is caused by a bug in certain versions of \i{Windows XP} which is triggered by PuTTY 0.58. This was fixed in 0.59. The \W{http://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/xp-wont-run}{\q{xp-wont-run}} entry in PuTTY's wishlist has more details. | < < < < < < < < < < < < < < < < < | 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 | \q{the application configuration is incorrect}. This is caused by a bug in certain versions of \i{Windows XP} which is triggered by PuTTY 0.58. This was fixed in 0.59. The \W{http://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/xp-wont-run}{\q{xp-wont-run}} entry in PuTTY's wishlist has more details. \H{faq-secure} Security questions \S{faq-publicpc}{Question} Is it safe for me to download PuTTY and use it on a public PC? It depends on whether you trust that PC. If you don't trust the public PC, don't use PuTTY on it, and don't use any other software |
︙ | ︙ |
Changes to doc/index.but.
|
| | | 1 2 3 4 5 6 7 8 | \define{versionidindex} \versionid $Id: index.but 9009 2010-09-25 16:18:02Z jacob $ \IM{Unix version} Unix version of PuTTY tools \IM{Unix version} Linux version of PuTTY tools \IM{Unix} Unix \IM{Unix} Linux |
︙ | ︙ | |||
845 846 847 848 849 850 851 | \IM{logical host name} host key, caching policy \IM{web browsers} web browser \IM{GSSAPI credential delegation} GSSAPI credential delegation \IM{GSSAPI credential delegation} credential delegation, GSSAPI \IM{GSSAPI credential delegation} delegation, of GSSAPI credentials | < < < < < | 845 846 847 848 849 850 851 | \IM{logical host name} host key, caching policy \IM{web browsers} web browser \IM{GSSAPI credential delegation} GSSAPI credential delegation \IM{GSSAPI credential delegation} credential delegation, GSSAPI \IM{GSSAPI credential delegation} delegation, of GSSAPI credentials |
Changes to doc/licence.but.
|
| | | | 1 2 3 4 5 6 7 8 9 10 11 12 | \define{versionidlicence} \versionid $Id: licence.but 9072 2011-01-05 12:01:00Z jacob $ \A{licence} PuTTY \ii{Licence} PuTTY is \i{copyright} 1997-2011 Simon Tatham. Portions copyright Robert de Bath, Joris van Rantwijk, Delian Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry, Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, Markus Kuhn, Colin Watson, and CORE SDI S.A. Permission is hereby granted, free of charge, to any person |
︙ | ︙ |
Changes to doc/man-ptel.but.
︙ | ︙ | |||
33 34 35 36 37 38 39 | \dd Specify the font to use for normal text displayed in the terminal. \dt \cw{\-fb} \e{font-name} \dd Specify the font to use for bold text displayed in the terminal. If the \cw{BoldAsColour} resource is set to 1 (the default), bold text will be displayed in different colours instead of a different font, | | | | 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | \dd Specify the font to use for normal text displayed in the terminal. \dt \cw{\-fb} \e{font-name} \dd Specify the font to use for bold text displayed in the terminal. If the \cw{BoldAsColour} resource is set to 1 (the default), bold text will be displayed in different colours instead of a different font, so this option will be ignored. If \cw{BoldAsColour} is set to 0 and you do not specify a bold font, \cw{puttytel} will overprint the normal font to make it look bolder. \dt \cw{\-fw} \e{font-name} \dd Specify the font to use for double-width characters (typically Chinese, Japanese and Korean text) displayed in the terminal. \dt \cw{\-fwb} \e{font-name} \dd Specify the font to use for bold double-width characters (typically Chinese, Japanese and Korean text). Like \cw{-fb}, this will be ignored unless the \cw{BoldAsColour} resource is set to 0. \dt \cw{\-geometry} \e{geometry} \dd Specify the size of the terminal, in rows and columns of text. See \e{X(7)} for more information on the syntax of geometry specifications. |
︙ | ︙ | |||
70 71 72 73 74 75 76 | \dt \cw{\-bg} \e{colour} \dd Specify the background colour to use for normal text. \dt \cw{\-bfg} \e{colour} \dd Specify the foreground colour to use for bold text, if the | | | | 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | \dt \cw{\-bg} \e{colour} \dd Specify the background colour to use for normal text. \dt \cw{\-bfg} \e{colour} \dd Specify the foreground colour to use for bold text, if the \cw{BoldAsColour} resource is set to 1 (the default). \dt \cw{\-bbg} \e{colour} \dd Specify the foreground colour to use for bold reverse-video text, if the \cw{BoldAsColour} resource is set to 1 (the default). (This colour is best thought of as the bold version of the background colour; so it only appears when text is displayed \e{in} the background colour.) \dt \cw{\-cfg} \e{colour} \dd Specify the foreground colour to use for text covered by the cursor. |
︙ | ︙ |
Changes to doc/man-pter.but.
︙ | ︙ | |||
53 54 55 56 57 58 59 | \dd Specify the font to use for normal text displayed in the terminal. \dt \cw{\-fb} \e{font-name} \dd Specify the font to use for bold text displayed in the terminal. If the \cw{BoldAsColour} resource is set to 1 (the default), bold text will be displayed in different colours instead of a different font, | | | | 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | \dd Specify the font to use for normal text displayed in the terminal. \dt \cw{\-fb} \e{font-name} \dd Specify the font to use for bold text displayed in the terminal. If the \cw{BoldAsColour} resource is set to 1 (the default), bold text will be displayed in different colours instead of a different font, so this option will be ignored. If \cw{BoldAsColour} is set to 0 and you do not specify a bold font, \cw{pterm} will overprint the normal font to make it look bolder. \dt \cw{\-fw} \e{font-name} \dd Specify the font to use for double-width characters (typically Chinese, Japanese and Korean text) displayed in the terminal. \dt \cw{\-fwb} \e{font-name} \dd Specify the font to use for bold double-width characters (typically Chinese, Japanese and Korean text). Like \cw{-fb}, this will be ignored unless the \cw{BoldAsColour} resource is set to 0. \dt \cw{\-geometry} \e{geometry} \dd Specify the size of the terminal, in rows and columns of text. See \e{X(7)} for more information on the syntax of geometry specifications. |
︙ | ︙ | |||
90 91 92 93 94 95 96 | \dt \cw{\-bg} \e{colour} \dd Specify the background colour to use for normal text. \dt \cw{\-bfg} \e{colour} \dd Specify the foreground colour to use for bold text, if the | | | | 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | \dt \cw{\-bg} \e{colour} \dd Specify the background colour to use for normal text. \dt \cw{\-bfg} \e{colour} \dd Specify the foreground colour to use for bold text, if the \cw{BoldAsColour} resource is set to 1 (the default). \dt \cw{\-bbg} \e{colour} \dd Specify the foreground colour to use for bold reverse-video text, if the \cw{BoldAsColour} resource is set to 1 (the default). (This colour is best thought of as the bold version of the background colour; so it only appears when text is displayed \e{in} the background colour.) \dt \cw{\-cfg} \e{colour} \dd Specify the foreground colour to use for text covered by the cursor. |
︙ | ︙ | |||
494 495 496 497 498 499 500 | controls the font used to display normal text. The default is \q{\cw{fixed}}. \dt \cw{pterm.BoldFont} \dd This resource is the same as the \cw{\-fb} command-line option: it controls the font used to display bold text when \cw{BoldAsColour} | | | | | | < | 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 | controls the font used to display normal text. The default is \q{\cw{fixed}}. \dt \cw{pterm.BoldFont} \dd This resource is the same as the \cw{\-fb} command-line option: it controls the font used to display bold text when \cw{BoldAsColour} is turned off. The default is unset (the font will be bolded by printing it twice at a one-pixel offset). \dt \cw{pterm.WideFont} \dd This resource is the same as the \cw{\-fw} command-line option: it controls the font used to display double-width characters. The default is unset (double-width characters cannot be displayed). \dt \cw{pterm.WideBoldFont} \dd This resource is the same as the \cw{\-fwb} command-line option: it controls the font used to display double-width characters in bold, when \cw{BoldAsColour} is turned off. The default is unset (double-width characters are displayed in bold by printing them twice at a one-pixel offset). \dt \cw{pterm.ShadowBoldOffset} \dd This resource can be set to an integer; the default is \-1. It specifies the offset at which text is overprinted when using \q{shadow bold} mode. The default (1) means that the text will be printed in the normal place, and also one character to the right; this seems to work well for most X bitmap fonts, which have a blank line of pixels down the right-hand side. For some fonts, you may need to set this to \-1, so that the text is overprinted one pixel to the left; for really large fonts, you may want to set it higher than 1 (in one direction or the other). \dt \cw{pterm.BoldAsColour} \dd This option should be set to either 0 or 1; the default is 1. It specifies the default state of auto wrap mode. When set to 1, bold text is shown by displaying it in a brighter colour; when set to 0, bold text is shown by displaying it in a heavier font. \dt \cw{pterm.Colour0}, \cw{pterm.Colour1}, ..., \cw{pterm.Colour21} \dd These options control the various colours used to display text in the \cw{pterm} window. Each one should be specified as a triple of decimal numbers giving red, green and blue values: so that black is \q{\cw{0,0,0}}, white is \q{\cw{255,255,255}}, red is |
︙ | ︙ |
Changes to doc/man-putt.but.
︙ | ︙ | |||
33 34 35 36 37 38 39 | \dt \cw{\-fb} \e{font-name} \dd Specify the font to use for bold text displayed in the terminal. If the \cw{BoldAsColour} resource is set to 1 (the default), bold text will be displayed in different colours instead of a different font, so this option will be ignored. If \cw{BoldAsColour} is set to | | | | 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | \dt \cw{\-fb} \e{font-name} \dd Specify the font to use for bold text displayed in the terminal. If the \cw{BoldAsColour} resource is set to 1 (the default), bold text will be displayed in different colours instead of a different font, so this option will be ignored. If \cw{BoldAsColour} is set to 0 and you do not specify a bold font, \cw{putty} will overprint the normal font to make it look bolder. \dt \cw{\-fw} \e{font-name} \dd Specify the font to use for double-width characters (typically Chinese, Japanese and Korean text) displayed in the terminal. \dt \cw{\-fwb} \e{font-name} \dd Specify the font to use for bold double-width characters (typically Chinese, Japanese and Korean text). Like \cw{-fb}, this will be ignored unless the \cw{BoldAsColour} resource is set to 0. \dt \cw{\-geometry} \e{geometry} \dd Specify the size of the terminal, in rows and columns of text. See \e{X(7)} for more information on the syntax of geometry specifications. |
︙ | ︙ | |||
69 70 71 72 73 74 75 | \dt \cw{\-bg} \e{colour} \dd Specify the background colour to use for normal text. \dt \cw{\-bfg} \e{colour} \dd Specify the foreground colour to use for bold text, if the | | | | 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | \dt \cw{\-bg} \e{colour} \dd Specify the background colour to use for normal text. \dt \cw{\-bfg} \e{colour} \dd Specify the foreground colour to use for bold text, if the \cw{BoldAsColour} resource is set to 1 (the default). \dt \cw{\-bbg} \e{colour} \dd Specify the foreground colour to use for bold reverse-video text, if the \cw{BoldAsColour} resource is set to 1 (the default). (This colour is best thought of as the bold version of the background colour; so it only appears when text is displayed \e{in} the background colour.) \dt \cw{\-cfg} \e{colour} \dd Specify the foreground colour to use for text covered by the cursor. |
︙ | ︙ |
Changes to doc/pgpkeys.but.
|
| | | 1 2 3 4 5 6 7 8 | \define{versionidpgpkeys} \versionid $Id: pgpkeys.but 5598 2005-04-05 19:36:25Z simon $ \A{pgpkeys} PuTTY download keys and signatures \cfg{winhelp-topic}{pgpfingerprints} \I{verifying new versions}We create \i{PGP signatures} for all the PuTTY files distributed from our web site, so that users can be confident |
︙ | ︙ |
Changes to doc/plink.but.
|
| | | 1 2 3 4 5 6 7 8 | \define{versionidplink} \versionid $Id: plink.but 9366 2011-12-10 12:08:09Z simon $ \C{plink} Using the command-line connection tool \i{Plink} \i{Plink} (PuTTY Link) is a command-line connection tool similar to UNIX \c{ssh}. It is mostly used for \i{automated operations}, such as making CVS access a repository on a remote server. |
︙ | ︙ | |||
39 40 41 42 43 44 45 | Once you've got a console window to type into, you can just type \c{plink} on its own to bring up a usage message. This tells you the version of Plink you're using, and gives you a brief summary of how to use Plink: \c Z:\sysosd>plink \c PuTTY Link: command-line connection utility | | | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | Once you've got a console window to type into, you can just type \c{plink} on its own to bring up a usage message. This tells you the version of Plink you're using, and gives you a brief summary of how to use Plink: \c Z:\sysosd>plink \c PuTTY Link: command-line connection utility \c Release 0.62 \c Usage: plink [options] [user@]host [command] \c ("host" can also be a PuTTY saved session name) \c Options: \c -V print version information and exit \c -pgpfp print PGP key fingerprints and exit \c -v show verbose messages \c -load sessname Load settings from saved session |
︙ | ︙ |
Changes to doc/pscp.but.
|
| | | 1 2 3 4 5 6 7 8 | \define{versionidpscp} \versionid $Id: pscp.but 9366 2011-12-10 12:08:09Z simon $ \#FIXME: Need examples \C{pscp} Using \i{PSCP} to transfer files securely \i{PSCP}, the PuTTY Secure Copy client, is a tool for \i{transferring files} securely between computers using an SSH connection. |
︙ | ︙ | |||
37 38 39 40 41 42 43 | Once you've got a console window to type into, you can just type \c{pscp} on its own to bring up a usage message. This tells you the version of PSCP you're using, and gives you a brief summary of how to use PSCP: \c Z:\owendadmin>pscp \c PuTTY Secure Copy client | | | 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | Once you've got a console window to type into, you can just type \c{pscp} on its own to bring up a usage message. This tells you the version of PSCP you're using, and gives you a brief summary of how to use PSCP: \c Z:\owendadmin>pscp \c PuTTY Secure Copy client \c Release 0.62 \c Usage: pscp [options] [user@]host:source target \c pscp [options] source [source...] [user@]host:target \c pscp [options] -ls [user@]host:filespec \c Options: \c -V print version information and exit \c -pgpfp print PGP key fingerprints and exit \c -p preserve file attributes |
︙ | ︙ |
Changes to doc/pubkey.but.
|
| | | 1 2 3 4 5 6 7 8 | \define{versionidpubkey} \versionid $Id: pubkey.but 8607 2009-07-12 12:02:58Z simon $ \C{pubkey} Using public keys for SSH authentication \H{pubkey-intro} \ii{Public key authentication} - an introduction Public key authentication is an alternative means of identifying yourself to a login server, instead of typing a password. It is more |
︙ | ︙ | |||
146 147 148 149 150 151 152 153 154 155 156 157 158 159 | \cfg{winhelp-topic}{puttygen.bits} The \q{Number of bits} input box allows you to choose the strength of the key PuTTYgen will generate. Currently 1024 bits should be sufficient for most purposes. \S{puttygen-generate} The \q{Generate} button \cfg{winhelp-topic}{puttygen.generate} Once you have chosen the type of key you want, and the strength of the key, press the \q{Generate} button and PuTTYgen will begin the | > > > > > > > > > > > > | 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 | \cfg{winhelp-topic}{puttygen.bits} The \q{Number of bits} input box allows you to choose the strength of the key PuTTYgen will generate. Currently 1024 bits should be sufficient for most purposes. Note that an RSA key is generated by finding two primes of half the length requested, and then multiplying them together. For example, if you ask PuTTYgen for a 1024-bit RSA key, it will create two 512-bit primes and multiply them. The result of this multiplication might be 1024 bits long, or it might be only 1023; so you may not get the exact length of key you asked for. This is perfectly normal, and you do not need to worry. The lengths should only ever differ by one, and there is no perceptible drop in security as a result. DSA keys are not created by multiplying primes together, so they should always be exactly the length you asked for. \S{puttygen-generate} The \q{Generate} button \cfg{winhelp-topic}{puttygen.generate} Once you have chosen the type of key you want, and the strength of the key, press the \q{Generate} button and PuTTYgen will begin the |
︙ | ︙ |
Deleted errsock.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to import.c.
︙ | ︙ | |||
285 286 287 288 289 290 291 | static int ssh2_read_mpint(void *data, int len, struct mpint_pos *ret) { int bytes; unsigned char *d = (unsigned char *) data; if (len < 4) goto error; | | | | 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 | static int ssh2_read_mpint(void *data, int len, struct mpint_pos *ret) { int bytes; unsigned char *d = (unsigned char *) data; if (len < 4) goto error; bytes = GET_32BIT(d); if (len < 4+bytes) goto error; ret->start = d + 4; ret->bytes = bytes; return bytes+4; error: |
︙ | ︙ | |||
317 318 319 320 321 322 323 | int keyblob_len, keyblob_size; }; static struct openssh_key *load_openssh_key(const Filename *filename, const char **errmsg_p) { struct openssh_key *ret; | | | | 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 | int keyblob_len, keyblob_size; }; static struct openssh_key *load_openssh_key(const Filename *filename, const char **errmsg_p) { struct openssh_key *ret; FILE *fp; char *line = NULL; char *errmsg, *p; int headers_done; char base64_bit[4]; int base64_chars = 0; ret = snew(struct openssh_key); ret->keyblob = NULL; ret->keyblob_len = ret->keyblob_size = 0; ret->encrypted = 0; memset(ret->iv, 0, sizeof(ret->iv)); fp = f_open(*filename, "r", FALSE); if (!fp) { errmsg = "unable to open key file"; goto error; } if (!(line = fgetline(fp))) { errmsg = "unexpected end of file"; |
︙ | ︙ | |||
354 355 356 357 358 359 360 | ret->type = OSSH_RSA; else if (!strcmp(line, "-----BEGIN DSA PRIVATE KEY-----")) ret->type = OSSH_DSA; else { errmsg = "unrecognised key type"; goto error; } | | | < < < | 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 | ret->type = OSSH_RSA; else if (!strcmp(line, "-----BEGIN DSA PRIVATE KEY-----")) ret->type = OSSH_DSA; else { errmsg = "unrecognised key type"; goto error; } memset(line, 0, strlen(line)); sfree(line); line = NULL; headers_done = 0; while (1) { if (!(line = fgetline(fp))) { errmsg = "unexpected end of file"; goto error; } strip_crlf(line); if (0 == strncmp(line, "-----END ", 9) && 0 == strcmp(line+strlen(line)-16, "PRIVATE KEY-----")) break; /* done */ if ((p = strchr(line, ':')) != NULL) { if (headers_done) { errmsg = "header found in body of key data"; goto error; } *p++ = '\0'; while (*p && isspace((unsigned char)*p)) p++; |
︙ | ︙ | |||
441 442 443 444 445 446 447 | ret->keyblob = sresize(ret->keyblob, ret->keyblob_size, unsigned char); } memcpy(ret->keyblob + ret->keyblob_len, out, len); ret->keyblob_len += len; | | | < < < | | | | | < | | | 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 | ret->keyblob = sresize(ret->keyblob, ret->keyblob_size, unsigned char); } memcpy(ret->keyblob + ret->keyblob_len, out, len); ret->keyblob_len += len; memset(out, 0, sizeof(out)); } p++; } } memset(line, 0, strlen(line)); sfree(line); line = NULL; } if (ret->keyblob_len == 0 || !ret->keyblob) { errmsg = "key body not present"; goto error; } if (ret->encrypted && ret->keyblob_len % 8 != 0) { errmsg = "encrypted key blob is not a multiple of cipher block size"; goto error; } memset(base64_bit, 0, sizeof(base64_bit)); if (errmsg_p) *errmsg_p = NULL; return ret; error: if (line) { memset(line, 0, strlen(line)); sfree(line); line = NULL; } memset(base64_bit, 0, sizeof(base64_bit)); if (ret) { if (ret->keyblob) { memset(ret->keyblob, 0, ret->keyblob_size); sfree(ret->keyblob); } memset(ret, 0, sizeof(*ret)); sfree(ret); } if (errmsg_p) *errmsg_p = errmsg; return NULL; } int openssh_encrypted(const Filename *filename) { struct openssh_key *key = load_openssh_key(filename, NULL); int ret; if (!key) return 0; ret = key->encrypted; memset(key->keyblob, 0, key->keyblob_size); sfree(key->keyblob); memset(key, 0, sizeof(*key)); sfree(key); return ret; } struct ssh2_userkey *openssh_read(const Filename *filename, char *passphrase, const char **errmsg_p) { |
︙ | ︙ | |||
567 568 569 570 571 572 573 | ctx = aes_make_context(); aes128_key(ctx, keybuf); aes_iv(ctx, (unsigned char *)key->iv); aes_ssh2_decrypt_blk(ctx, key->keyblob, key->keyblob_len); aes_free_context(ctx); } | | | | 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 | ctx = aes_make_context(); aes128_key(ctx, keybuf); aes_iv(ctx, (unsigned char *)key->iv); aes_ssh2_decrypt_blk(ctx, key->keyblob, key->keyblob_len); aes_free_context(ctx); } memset(&md5c, 0, sizeof(md5c)); memset(keybuf, 0, sizeof(keybuf)); } /* * Now we have a decrypted key blob, which contains an ASN.1 * encoded private key. We must now untangle the ASN.1. * * We expect the whole key blob to be formatted as a SEQUENCE |
︙ | ︙ | |||
591 592 593 594 595 596 597 | * * - For DSA, we expect them to be 0, p, q, g, y, x in that * order. */ p = key->keyblob; | | < | | 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 | * * - For DSA, we expect them to be 0, p, q, g, y, x in that * order. */ p = key->keyblob; /* Expect the SEQUENCE header. Take its absence as a failure to decrypt. */ ret = ber_read_id_len(p, key->keyblob_len, &id, &len, &flags); p += ret; if (ret < 0 || id != 16) { errmsg = "ASN.1 decoding failure"; retval = SSH2_WRONG_PASSPHRASE; goto error; } /* Expect a load of INTEGERs. */ if (key->type == OSSH_RSA) num_integers = 9; else if (key->type == OSSH_DSA) |
︙ | ︙ | |||
629 630 631 632 633 634 635 | for (i = 0; i < num_integers; i++) { ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p, &id, &len, &flags); p += ret; if (ret < 0 || id != 2 || key->keyblob+key->keyblob_len-p < len) { errmsg = "ASN.1 decoding failure"; | | | 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 | for (i = 0; i < num_integers; i++) { ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p, &id, &len, &flags); p += ret; if (ret < 0 || id != 2 || key->keyblob+key->keyblob_len-p < len) { errmsg = "ASN.1 decoding failure"; retval = SSH2_WRONG_PASSPHRASE; goto error; } if (i == 0) { /* * The first integer should be zero always (I think * this is some sort of version indication). |
︙ | ︙ | |||
702 703 704 705 706 707 708 | retkey->comment = dupstr("imported-openssh-key"); errmsg = NULL; /* no error */ retval = retkey; error: if (blob) { | | | | | 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 | retkey->comment = dupstr("imported-openssh-key"); errmsg = NULL; /* no error */ retval = retkey; error: if (blob) { memset(blob, 0, blobsize); sfree(blob); } memset(key->keyblob, 0, key->keyblob_size); sfree(key->keyblob); memset(key, 0, sizeof(*key)); sfree(key); if (errmsg_p) *errmsg_p = errmsg; return retval; } int openssh_write(const Filename *filename, struct ssh2_userkey *key, char *passphrase) |
︙ | ︙ | |||
744 745 746 747 748 749 750 | * key blob, and also decide on the header line. */ if (key->alg == &ssh_rsa) { int pos; struct mpint_pos n, e, d, p, q, iqmp, dmp1, dmq1; Bignum bd, bp, bq, bdmp1, bdmq1; | < < < < | 736 737 738 739 740 741 742 743 744 745 746 747 748 749 | * key blob, and also decide on the header line. */ if (key->alg == &ssh_rsa) { int pos; struct mpint_pos n, e, d, p, q, iqmp, dmp1, dmq1; Bignum bd, bp, bq, bdmp1, bdmq1; pos = 4 + GET_32BIT(pubblob); pos += ssh2_read_mpint(pubblob+pos, publen-pos, &e); pos += ssh2_read_mpint(pubblob+pos, publen-pos, &n); pos = 0; pos += ssh2_read_mpint(privblob+pos, privlen-pos, &d); pos += ssh2_read_mpint(privblob+pos, privlen-pos, &p); pos += ssh2_read_mpint(privblob+pos, privlen-pos, &q); |
︙ | ︙ | |||
801 802 803 804 805 806 807 | nnumbers = 9; header = "-----BEGIN RSA PRIVATE KEY-----\n"; footer = "-----END RSA PRIVATE KEY-----\n"; } else if (key->alg == &ssh_dss) { int pos; struct mpint_pos p, q, g, y, x; | < < < < | 789 790 791 792 793 794 795 796 797 798 799 800 801 802 | nnumbers = 9; header = "-----BEGIN RSA PRIVATE KEY-----\n"; footer = "-----END RSA PRIVATE KEY-----\n"; } else if (key->alg == &ssh_dss) { int pos; struct mpint_pos p, q, g, y, x; pos = 4 + GET_32BIT(pubblob); pos += ssh2_read_mpint(pubblob+pos, publen-pos, &p); pos += ssh2_read_mpint(pubblob+pos, publen-pos, &q); pos += ssh2_read_mpint(pubblob+pos, publen-pos, &g); pos += ssh2_read_mpint(pubblob+pos, publen-pos, &y); pos = 0; pos += ssh2_read_mpint(privblob+pos, privlen-pos, &x); |
︙ | ︙ | |||
923 924 925 926 927 928 929 | MD5Final(keybuf+16, &md5c); /* * Now encrypt the key blob. */ des3_encrypt_pubkey_ossh(keybuf, iv, outblob, outlen); | | | | | | | | | 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 | MD5Final(keybuf+16, &md5c); /* * Now encrypt the key blob. */ des3_encrypt_pubkey_ossh(keybuf, iv, outblob, outlen); memset(&md5c, 0, sizeof(md5c)); memset(keybuf, 0, sizeof(keybuf)); } /* * And save it. We'll use Unix line endings just in case it's * subsequently transferred in binary mode. */ fp = f_open(*filename, "wb", TRUE); /* ensure Unix line endings */ if (!fp) goto error; fputs(header, fp); if (passphrase) { fprintf(fp, "Proc-Type: 4,ENCRYPTED\nDEK-Info: DES-EDE3-CBC,"); for (i = 0; i < 8; i++) fprintf(fp, "%02X", iv[i]); fprintf(fp, "\n\n"); } base64_encode(fp, outblob, outlen, 64); fputs(footer, fp); fclose(fp); ret = 1; error: if (outblob) { memset(outblob, 0, outlen); sfree(outblob); } if (spareblob) { memset(spareblob, 0, sparelen); sfree(spareblob); } if (privblob) { memset(privblob, 0, privlen); sfree(privblob); } if (pubblob) { memset(pubblob, 0, publen); sfree(pubblob); } return ret; } /* ---------------------------------------------------------------------- * Code to read ssh.com private keys. |
︙ | ︙ | |||
1065 1066 1067 1068 1069 1070 1071 | int base64_chars = 0; ret = snew(struct sshcom_key); ret->comment[0] = '\0'; ret->keyblob = NULL; ret->keyblob_len = ret->keyblob_size = 0; | | | | < < < | 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 | int base64_chars = 0; ret = snew(struct sshcom_key); ret->comment[0] = '\0'; ret->keyblob = NULL; ret->keyblob_len = ret->keyblob_size = 0; fp = f_open(*filename, "r", FALSE); if (!fp) { errmsg = "unable to open key file"; goto error; } if (!(line = fgetline(fp))) { errmsg = "unexpected end of file"; goto error; } strip_crlf(line); if (0 != strcmp(line, "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----")) { errmsg = "file does not begin with ssh.com key header"; goto error; } memset(line, 0, strlen(line)); sfree(line); line = NULL; headers_done = 0; while (1) { if (!(line = fgetline(fp))) { errmsg = "unexpected end of file"; goto error; } strip_crlf(line); if (!strcmp(line, "---- END SSH2 ENCRYPTED PRIVATE KEY ----")) break; /* done */ if ((p = strchr(line, ':')) != NULL) { if (headers_done) { errmsg = "header found in body of key data"; goto error; } *p++ = '\0'; while (*p && isspace((unsigned char)*p)) p++; |
︙ | ︙ | |||
1127 1128 1129 1130 1131 1132 1133 | line2len = strlen(line2); line = sresize(line, len + line2len + 1, char); strcpy(line + len - 1, line2); len += line2len - 1; assert(!line[len]); | | | 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 | line2len = strlen(line2); line = sresize(line, len + line2len + 1, char); strcpy(line + len - 1, line2); len += line2len - 1; assert(!line[len]); memset(line2, 0, strlen(line2)); sfree(line2); line2 = NULL; } p = line + hdrstart; strip_crlf(p); if (!strcmp(line, "Comment")) { /* Strip quotes in comment if present. */ |
︙ | ︙ | |||
1173 1174 1175 1176 1177 1178 1179 | memcpy(ret->keyblob + ret->keyblob_len, out, len); ret->keyblob_len += len; } p++; } } | | < < < < | | | < < | | | < > | | < | | < | | | | | < < < > | | 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 | memcpy(ret->keyblob + ret->keyblob_len, out, len); ret->keyblob_len += len; } p++; } } memset(line, 0, strlen(line)); sfree(line); line = NULL; } if (ret->keyblob_len == 0 || !ret->keyblob) { errmsg = "key body not present"; goto error; } if (errmsg_p) *errmsg_p = NULL; return ret; error: if (line) { memset(line, 0, strlen(line)); sfree(line); line = NULL; } if (ret) { if (ret->keyblob) { memset(ret->keyblob, 0, ret->keyblob_size); sfree(ret->keyblob); } memset(ret, 0, sizeof(*ret)); sfree(ret); } if (errmsg_p) *errmsg_p = errmsg; return NULL; } int sshcom_encrypted(const Filename *filename, char **comment) { struct sshcom_key *key = load_sshcom_key(filename, NULL); int pos, len, answer; *comment = NULL; if (!key) return 0; /* * Check magic number. */ if (GET_32BIT(key->keyblob) != 0x3f6ff9eb) return 0; /* key is invalid */ /* * Find the cipher-type string. */ answer = 0; pos = 8; if (key->keyblob_len < pos+4) goto done; /* key is far too short */ pos += 4 + GET_32BIT(key->keyblob + pos); /* skip key type */ if (key->keyblob_len < pos+4) goto done; /* key is far too short */ len = GET_32BIT(key->keyblob + pos); /* find cipher-type length */ if (key->keyblob_len < pos+4+len) goto done; /* cipher type string is incomplete */ if (len != 4 || 0 != memcmp(key->keyblob + pos + 4, "none", 4)) answer = 1; done: *comment = dupstr(key->comment); memset(key->keyblob, 0, key->keyblob_size); sfree(key->keyblob); memset(key, 0, sizeof(*key)); sfree(key); return answer; } static int sshcom_read_mpint(void *data, int len, struct mpint_pos *ret) { int bits; int bytes; unsigned char *d = (unsigned char *) data; if (len < 4) goto error; bits = GET_32BIT(d); bytes = (bits + 7) / 8; |
︙ | ︙ | |||
1329 1330 1331 1332 1333 1334 1335 | } /* * Determine the key type. */ pos = 8; if (key->keyblob_len < pos+4 || | | < | < | < | 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 | } /* * Determine the key type. */ pos = 8; if (key->keyblob_len < pos+4 || (len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) { errmsg = "key blob does not contain a key type string"; goto error; } if (len > sizeof(prefix_rsa) - 1 && !memcmp(key->keyblob+pos+4, prefix_rsa, sizeof(prefix_rsa) - 1)) { type = RSA; } else if (len > sizeof(prefix_dsa) - 1 && !memcmp(key->keyblob+pos+4, prefix_dsa, sizeof(prefix_dsa) - 1)) { type = DSA; } else { errmsg = "key is of unknown type"; goto error; } pos += 4+len; /* * Determine the cipher type. */ if (key->keyblob_len < pos+4 || (len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) { errmsg = "key blob does not contain a cipher type string"; goto error; } if (len == 4 && !memcmp(key->keyblob+pos+4, "none", 4)) encrypted = 0; else if (len == 8 && !memcmp(key->keyblob+pos+4, "3des-cbc", 8)) encrypted = 1; else { errmsg = "key encryption is of unknown type"; goto error; } pos += 4+len; /* * Get hold of the encrypted part of the key. */ if (key->keyblob_len < pos+4 || (len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) { errmsg = "key blob does not contain actual key data"; goto error; } ciphertext = (char *)key->keyblob + pos + 4; cipherlen = len; if (cipherlen == 0) { errmsg = "length of key data is zero"; |
︙ | ︙ | |||
1418 1419 1420 1421 1422 1423 1424 | /* * Now decrypt the key blob. */ memset(iv, 0, sizeof(iv)); des3_decrypt_pubkey_ossh(keybuf, iv, (unsigned char *)ciphertext, cipherlen); | | | | | 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 | /* * Now decrypt the key blob. */ memset(iv, 0, sizeof(iv)); des3_decrypt_pubkey_ossh(keybuf, iv, (unsigned char *)ciphertext, cipherlen); memset(&md5c, 0, sizeof(md5c)); memset(keybuf, 0, sizeof(keybuf)); /* * Hereafter we return WRONG_PASSPHRASE for any parsing * error. (But only if we've just tried to decrypt it! * Returning WRONG_PASSPHRASE for an unencrypted key is * automatic doom.) */ if (encrypted) ret = SSH2_WRONG_PASSPHRASE; } /* * Strip away the containing string to get to the real meat. */ len = GET_32BIT(ciphertext); if (len < 0 || len > cipherlen-4) { errmsg = "containing string was ill-formed"; goto error; } ciphertext += 4; cipherlen = len; |
︙ | ︙ | |||
1475 1476 1477 1478 1479 1480 1481 | pos += put_mp(blob+pos, n.start, n.bytes); publen = pos; pos += put_string(blob+pos, d.start, d.bytes); pos += put_mp(blob+pos, q.start, q.bytes); pos += put_mp(blob+pos, p.start, p.bytes); pos += put_mp(blob+pos, u.start, u.bytes); privlen = pos - publen; | | < < < | 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 | pos += put_mp(blob+pos, n.start, n.bytes); publen = pos; pos += put_string(blob+pos, d.start, d.bytes); pos += put_mp(blob+pos, q.start, q.bytes); pos += put_mp(blob+pos, p.start, p.bytes); pos += put_mp(blob+pos, u.start, u.bytes); privlen = pos - publen; } else if (type == DSA) { struct mpint_pos p, q, g, x, y; int pos = 4; if (GET_32BIT(ciphertext) != 0) { errmsg = "predefined DSA parameters not supported"; goto error; } pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &p); pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &g); pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &q); |
︙ | ︙ | |||
1505 1506 1507 1508 1509 1510 1511 | pos += put_mp(blob+pos, p.start, p.bytes); pos += put_mp(blob+pos, q.start, q.bytes); pos += put_mp(blob+pos, g.start, g.bytes); pos += put_mp(blob+pos, y.start, y.bytes); publen = pos; pos += put_mp(blob+pos, x.start, x.bytes); privlen = pos - publen; | | > | | | | 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 | pos += put_mp(blob+pos, p.start, p.bytes); pos += put_mp(blob+pos, q.start, q.bytes); pos += put_mp(blob+pos, g.start, g.bytes); pos += put_mp(blob+pos, y.start, y.bytes); publen = pos; pos += put_mp(blob+pos, x.start, x.bytes); privlen = pos - publen; } else return NULL; assert(privlen > 0); /* should have bombed by now if not */ retkey = snew(struct ssh2_userkey); retkey->alg = alg; retkey->data = alg->createkey(blob, publen, blob+publen, privlen); if (!retkey->data) { sfree(retkey); errmsg = "unable to create key data structure"; goto error; } retkey->comment = dupstr(key->comment); errmsg = NULL; /* no error */ ret = retkey; error: if (blob) { memset(blob, 0, blobsize); sfree(blob); } memset(key->keyblob, 0, key->keyblob_size); sfree(key->keyblob); memset(key, 0, sizeof(*key)); sfree(key); if (errmsg_p) *errmsg_p = errmsg; return ret; } int sshcom_write(const Filename *filename, struct ssh2_userkey *key, char *passphrase) |
︙ | ︙ | |||
1565 1566 1567 1568 1569 1570 1571 | * Find the sequence of integers to be encoded into the OpenSSH * key blob, and also decide on the header line. */ if (key->alg == &ssh_rsa) { int pos; struct mpint_pos n, e, d, p, q, iqmp; | < < < < | 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 | * Find the sequence of integers to be encoded into the OpenSSH * key blob, and also decide on the header line. */ if (key->alg == &ssh_rsa) { int pos; struct mpint_pos n, e, d, p, q, iqmp; pos = 4 + GET_32BIT(pubblob); pos += ssh2_read_mpint(pubblob+pos, publen-pos, &e); pos += ssh2_read_mpint(pubblob+pos, publen-pos, &n); pos = 0; pos += ssh2_read_mpint(privblob+pos, privlen-pos, &d); pos += ssh2_read_mpint(privblob+pos, privlen-pos, &p); pos += ssh2_read_mpint(privblob+pos, privlen-pos, &q); |
︙ | ︙ | |||
1594 1595 1596 1597 1598 1599 1600 | nnumbers = 6; initial_zero = 0; type = "if-modn{sign{rsa-pkcs1-sha1},encrypt{rsa-pkcs1v2-oaep}}"; } else if (key->alg == &ssh_dss) { int pos; struct mpint_pos p, q, g, y, x; | < < < < | 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 | nnumbers = 6; initial_zero = 0; type = "if-modn{sign{rsa-pkcs1-sha1},encrypt{rsa-pkcs1v2-oaep}}"; } else if (key->alg == &ssh_dss) { int pos; struct mpint_pos p, q, g, y, x; pos = 4 + GET_32BIT(pubblob); pos += ssh2_read_mpint(pubblob+pos, publen-pos, &p); pos += ssh2_read_mpint(pubblob+pos, publen-pos, &q); pos += ssh2_read_mpint(pubblob+pos, publen-pos, &g); pos += ssh2_read_mpint(pubblob+pos, publen-pos, &y); pos = 0; pos += ssh2_read_mpint(privblob+pos, privlen-pos, &x); |
︙ | ︙ | |||
1702 1703 1704 1705 1706 1707 1708 | /* * Now decrypt the key blob. */ memset(iv, 0, sizeof(iv)); des3_encrypt_pubkey_ossh(keybuf, iv, (unsigned char *)ciphertext, cipherlen); | | | | | 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 | /* * Now decrypt the key blob. */ memset(iv, 0, sizeof(iv)); des3_encrypt_pubkey_ossh(keybuf, iv, (unsigned char *)ciphertext, cipherlen); memset(&md5c, 0, sizeof(md5c)); memset(keybuf, 0, sizeof(keybuf)); } /* * And save it. We'll use Unix line endings just in case it's * subsequently transferred in binary mode. */ fp = f_open(*filename, "wb", TRUE); /* ensure Unix line endings */ if (!fp) goto error; fputs("---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----\n", fp); fprintf(fp, "Comment: \""); /* * Comment header is broken with backslash-newline if it goes * over 70 chars. Although it's surrounded by quotes, it |
︙ | ︙ | |||
1738 1739 1740 1741 1742 1743 1744 | base64_encode(fp, outblob, pos, 70); fputs("---- END SSH2 ENCRYPTED PRIVATE KEY ----\n", fp); fclose(fp); ret = 1; error: if (outblob) { | | | | | 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 | base64_encode(fp, outblob, pos, 70); fputs("---- END SSH2 ENCRYPTED PRIVATE KEY ----\n", fp); fclose(fp); ret = 1; error: if (outblob) { memset(outblob, 0, outlen); sfree(outblob); } if (privblob) { memset(privblob, 0, privlen); sfree(privblob); } if (pubblob) { memset(pubblob, 0, publen); sfree(pubblob); } return ret; } |
Changes to ldisc.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | #include <stdio.h> #include <ctype.h> #include "putty.h" #include "terminal.h" #include "ldisc.h" | | | | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | #include <stdio.h> #include <ctype.h> #include "putty.h" #include "terminal.h" #include "ldisc.h" #define ECHOING (ldisc->cfg->localecho == FORCE_ON || \ (ldisc->cfg->localecho == AUTO && \ (ldisc->back->ldisc(ldisc->backhandle, LD_ECHO) || \ term_ldisc(ldisc->term, LD_ECHO)))) #define EDITING (ldisc->cfg->localedit == FORCE_ON || \ (ldisc->cfg->localedit == AUTO && \ (ldisc->back->ldisc(ldisc->backhandle, LD_EDIT) || \ term_ldisc(ldisc->term, LD_EDIT)))) static void c_write(Ldisc ldisc, char *buf, int len) { from_backend(ldisc->frontend, 0, buf, len); } |
︙ | ︙ | |||
72 73 74 75 76 77 78 | while (n--) c_write(ldisc, "\010 \010", 3); } #define CTRL(x) (x^'@') #define KCTRL(x) ((x^'@') | 0x100) | | > < < < < < < < < < < < < < | 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | while (n--) c_write(ldisc, "\010 \010", 3); } #define CTRL(x) (x^'@') #define KCTRL(x) ((x^'@') | 0x100) void *ldisc_create(Config *mycfg, Terminal *term, Backend *back, void *backhandle, void *frontend) { Ldisc ldisc = snew(struct ldisc_tag); ldisc->buf = NULL; ldisc->buflen = 0; ldisc->bufsiz = 0; ldisc->quotenext = 0; ldisc->cfg = mycfg; ldisc->back = back; ldisc->backhandle = backhandle; ldisc->term = term; ldisc->frontend = frontend; /* Link ourselves into the backend and the terminal */ if (term) term->ldisc = ldisc; if (back) back->provide_ldisc(backhandle, ldisc); return ldisc; } void ldisc_free(void *handle) { Ldisc ldisc = (Ldisc) handle; if (ldisc->term) ldisc->term->ldisc = NULL; if (ldisc->back) |
︙ | ︙ | |||
142 143 144 145 146 147 148 | /* * Notify the front end that something was pressed, in case * it's depending on finding out (e.g. keypress termination for * Close On Exit). */ frontend_keypress(ldisc->frontend); | < < < < < < < < < < < < | 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | /* * Notify the front end that something was pressed, in case * it's depending on finding out (e.g. keypress termination for * Close On Exit). */ frontend_keypress(ldisc->frontend); /* * Less than zero means null terminated special string. */ if (len < 0) { len = strlen(buf); keyflag = KCTRL('@'); } |
︙ | ︙ | |||
223 224 225 226 227 228 229 | } ldisc->back->special(ldisc->backhandle, TS_EL); /* * We don't send IP, SUSP or ABORT if the user has * configured telnet specials off! This breaks * talkers otherwise. */ | | | 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 | } ldisc->back->special(ldisc->backhandle, TS_EL); /* * We don't send IP, SUSP or ABORT if the user has * configured telnet specials off! This breaks * talkers otherwise. */ if (!ldisc->cfg->telnet_keyboard) goto default_case; if (c == CTRL('C')) ldisc->back->special(ldisc->backhandle, TS_IP); if (c == CTRL('Z')) ldisc->back->special(ldisc->backhandle, TS_SUSP); if (c == CTRL('\\')) ldisc->back->special(ldisc->backhandle, TS_ABORT); |
︙ | ︙ | |||
275 276 277 278 279 280 281 | * - receiving a magic-^M empties the line buffer, * signals end-of-line in one of the various * entertaining ways, and _doesn't_ fall out of * the bottom of the if and through to the * default clause because of the break. */ case CTRL('J'): | | | | | 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 | * - receiving a magic-^M empties the line buffer, * signals end-of-line in one of the various * entertaining ways, and _doesn't_ fall out of * the bottom of the if and through to the * default clause because of the break. */ case CTRL('J'): if (ldisc->cfg->protocol == PROT_RAW && ldisc->buflen > 0 && ldisc->buf[ldisc->buflen - 1] == '\r') { if (ECHOING) bsb(ldisc, plen(ldisc, ldisc->buf[ldisc->buflen - 1])); ldisc->buflen--; /* FALLTHROUGH */ case KCTRL('M'): /* send with newline */ if (ldisc->buflen > 0) ldisc->back->send(ldisc->backhandle, ldisc->buf, ldisc->buflen); if (ldisc->cfg->protocol == PROT_RAW) ldisc->back->send(ldisc->backhandle, "\r\n", 2); else if (ldisc->cfg->protocol == PROT_TELNET && ldisc->cfg->telnet_newline) ldisc->back->special(ldisc->backhandle, TS_EOL); else ldisc->back->send(ldisc->backhandle, "\r", 1); if (ECHOING) c_write(ldisc, "\r\n", 2); ldisc->buflen = 0; break; |
︙ | ︙ | |||
320 321 322 323 324 325 326 | bsb(ldisc, plen(ldisc, ldisc->buf[ldisc->buflen - 1])); ldisc->buflen--; } } if (len > 0) { if (ECHOING) c_write(ldisc, buf, len); | | | | | | | 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 | bsb(ldisc, plen(ldisc, ldisc->buf[ldisc->buflen - 1])); ldisc->buflen--; } } if (len > 0) { if (ECHOING) c_write(ldisc, buf, len); if (keyflag && ldisc->cfg->protocol == PROT_TELNET && len == 1) { switch (buf[0]) { case CTRL('M'): if (ldisc->cfg->protocol == PROT_TELNET && ldisc->cfg->telnet_newline) ldisc->back->special(ldisc->backhandle, TS_EOL); else ldisc->back->send(ldisc->backhandle, "\r", 1); break; case CTRL('?'): case CTRL('H'): if (ldisc->cfg->telnet_keyboard) { ldisc->back->special(ldisc->backhandle, TS_EC); break; } case CTRL('C'): if (ldisc->cfg->telnet_keyboard) { ldisc->back->special(ldisc->backhandle, TS_IP); break; } case CTRL('Z'): if (ldisc->cfg->telnet_keyboard) { ldisc->back->special(ldisc->backhandle, TS_SUSP); break; } default: ldisc->back->send(ldisc->backhandle, buf, len); break; } } else ldisc->back->send(ldisc->backhandle, buf, len); } } } |
Changes to ldisc.h.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | /* * ldisc.h: defines the Ldisc data structure used by ldisc.c and * ldiscucs.c. (Unfortunately it was necessary to split the ldisc * module in two, to avoid unnecessarily linking in the Unicode * stuff in tools that don't require it.) */ #ifndef PUTTY_LDISC_H #define PUTTY_LDISC_H typedef struct ldisc_tag { Terminal *term; Backend *back; void *backhandle; void *frontend; | > < < < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | /* * ldisc.h: defines the Ldisc data structure used by ldisc.c and * ldiscucs.c. (Unfortunately it was necessary to split the ldisc * module in two, to avoid unnecessarily linking in the Unicode * stuff in tools that don't require it.) */ #ifndef PUTTY_LDISC_H #define PUTTY_LDISC_H typedef struct ldisc_tag { Terminal *term; Backend *back; Config *cfg; void *backhandle; void *frontend; char *buf; int buflen, bufsiz, quotenext; } *Ldisc; #endif /* PUTTY_LDISC_H */ |
Changes to ldiscucs.c.
︙ | ︙ | |||
47 48 49 50 51 52 53 | linebuffer = snewn(linesize, char); if (in_utf(ldisc->term)) { /* UTF is a simple algorithm */ for (p = linebuffer, i = 0; i < len; i++) { unsigned long ch = widebuf[i]; | | | > | | 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | linebuffer = snewn(linesize, char); if (in_utf(ldisc->term)) { /* UTF is a simple algorithm */ for (p = linebuffer, i = 0; i < len; i++) { unsigned long ch = widebuf[i]; if ((ch & 0xF800) == 0xD800) { #ifdef PLATFORM_IS_UTF16 if (i+1 < len) { unsigned long ch2 = widebuf[i+1]; if ((ch & 0xFC00) == 0xD800 && (ch2 & 0xFC00) == 0xDC00) { ch = 0x10000 + ((ch & 0x3FF) << 10) + (ch2 & 0x3FF); i++; } } else #endif { /* Unrecognised UTF-16 sequence */ ch = '.'; |
︙ | ︙ |
Changes to logging.c.
︙ | ︙ | |||
12 13 14 15 16 17 18 | #include "putty.h" /* log session to file stuff ... */ struct LogContext { FILE *lgfp; enum { L_CLOSED, L_OPENING, L_OPEN, L_ERROR } state; bufchain queue; | | | < | | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | #include "putty.h" /* log session to file stuff ... */ struct LogContext { FILE *lgfp; enum { L_CLOSED, L_OPENING, L_OPEN, L_ERROR } state; bufchain queue; Filename currlogfilename; void *frontend; Config cfg; }; static void xlatlognam(Filename *d, Filename s, char *hostname, struct tm *tm); /* * Internal wrapper function which must be called for _all_ output * to the log file. It takes care of opening the log file if it * isn't open, buffering data if it's in the process of being * opened asynchronously, etc. */ |
︙ | ︙ | |||
72 73 74 75 76 77 78 | } /* * Flush any open log file. */ void logflush(void *handle) { struct LogContext *ctx = (struct LogContext *)handle; | | | 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | } /* * Flush any open log file. */ void logflush(void *handle) { struct LogContext *ctx = (struct LogContext *)handle; if (ctx->cfg.logtype > 0) if (ctx->state == L_OPEN) fflush(ctx->lgfp); } static void logfopen_callback(void *handle, int mode) { struct LogContext *ctx = (struct LogContext *)handle; |
︙ | ︙ | |||
107 108 109 110 111 112 113 | " =~=~=~=~=~=~=~=~=~=~=~=\r\n", buf); } event = dupprintf("%s session log (%s mode) to file: %s", ctx->state == L_ERROR ? (mode == 0 ? "Disabled writing" : "Error writing") : (mode == 1 ? "Appending" : "Writing new"), | | | | | | | 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | " =~=~=~=~=~=~=~=~=~=~=~=\r\n", buf); } event = dupprintf("%s session log (%s mode) to file: %s", ctx->state == L_ERROR ? (mode == 0 ? "Disabled writing" : "Error writing") : (mode == 1 ? "Appending" : "Writing new"), (ctx->cfg.logtype == LGTYP_ASCII ? "ASCII" : ctx->cfg.logtype == LGTYP_DEBUG ? "raw" : ctx->cfg.logtype == LGTYP_PACKETS ? "SSH packets" : ctx->cfg.logtype == LGTYP_SSHRAW ? "SSH raw data" : "unknown"), filename_to_str(&ctx->currlogfilename)); logevent(ctx->frontend, event); sfree(event); /* * Having either succeeded or failed in opening the log file, * we should write any queued data out. */ |
︙ | ︙ | |||
145 146 147 148 149 150 151 | struct tm tm; int mode; /* Prevent repeat calls */ if (ctx->state != L_CLOSED) return; | | < < | < < < | | | 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | struct tm tm; int mode; /* Prevent repeat calls */ if (ctx->state != L_CLOSED) return; if (!ctx->cfg.logtype) return; tm = ltime(); /* substitute special codes in file name */ xlatlognam(&ctx->currlogfilename, ctx->cfg.logfilename,ctx->cfg.host, &tm); ctx->lgfp = f_open(ctx->currlogfilename, "r", FALSE); /* file already present? */ if (ctx->lgfp) { fclose(ctx->lgfp); if (ctx->cfg.logxfovr != LGXF_ASK) { mode = ((ctx->cfg.logxfovr == LGXF_OVR) ? 2 : 1); } else mode = askappend(ctx->frontend, ctx->currlogfilename, logfopen_callback, ctx); } else mode = 2; /* create == overwrite */ if (mode < 0) |
︙ | ︙ | |||
191 192 193 194 195 196 197 | /* * Log session traffic. */ void logtraffic(void *handle, unsigned char c, int logmode) { struct LogContext *ctx = (struct LogContext *)handle; | | | | 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 | /* * Log session traffic. */ void logtraffic(void *handle, unsigned char c, int logmode) { struct LogContext *ctx = (struct LogContext *)handle; if (ctx->cfg.logtype > 0) { if (ctx->cfg.logtype == logmode) logwrite(ctx, &c, 1); } } /* * Log an Event Log entry. Used in SSH packet logging mode; this is * also as convenient a place as any to put the output of Event Log |
︙ | ︙ | |||
216 217 218 219 220 221 222 | if ((flags & FLAG_STDERR) && (flags & FLAG_VERBOSE)) { fprintf(stderr, "%s\n", event); fflush(stderr); } /* If we don't have a context yet (eg winnet.c init) then skip entirely */ if (!ctx) return; | | | | < | | > | | | | | | | | < < < < < < < < < < < < < < < < < < < | | < | 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 | if ((flags & FLAG_STDERR) && (flags & FLAG_VERBOSE)) { fprintf(stderr, "%s\n", event); fflush(stderr); } /* If we don't have a context yet (eg winnet.c init) then skip entirely */ if (!ctx) return; if (ctx->cfg.logtype != LGTYP_PACKETS && ctx->cfg.logtype != LGTYP_SSHRAW) return; logprintf(ctx, "Event Log: %s\r\n", event); logflush(ctx); } /* * Log an SSH packet. * If n_blanks != 0, blank or omit some parts. * Set of blanking areas must be in increasing order. */ void log_packet(void *handle, int direction, int type, char *texttype, const void *data, int len, int n_blanks, const struct logblank_t *blanks, const unsigned long *seq) { struct LogContext *ctx = (struct LogContext *)handle; char dumpdata[80], smalldata[5]; int p = 0, b = 0, omitted = 0; int output_pos = 0; /* NZ if pending output in dumpdata */ if (!(ctx->cfg.logtype == LGTYP_SSHRAW || (ctx->cfg.logtype == LGTYP_PACKETS && texttype))) return; /* Packet header. */ if (texttype) { if (seq) { logprintf(ctx, "%s packet #0x%lx, type %d / 0x%02x (%s)\r\n", direction == PKT_INCOMING ? "Incoming" : "Outgoing", *seq, type, type, texttype); } else { logprintf(ctx, "%s packet type %d / 0x%02x (%s)\r\n", direction == PKT_INCOMING ? "Incoming" : "Outgoing", type, type, texttype); } } else { logprintf(ctx, "%s raw data\r\n", direction == PKT_INCOMING ? "Incoming" : "Outgoing"); } /* * Output a hex/ASCII dump of the packet body, blanking/omitting * parts as specified. */ while (p < len) { |
︙ | ︙ | |||
348 349 350 351 352 353 354 | /* Tidy up */ if (omitted) logprintf(ctx, " (%d byte%s omitted)\r\n", omitted, (omitted==1?"":"s")); logflush(ctx); } | | | < < < < | | < < | < < | < > | < > > | < < < | < | | 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 | /* Tidy up */ if (omitted) logprintf(ctx, " (%d byte%s omitted)\r\n", omitted, (omitted==1?"":"s")); logflush(ctx); } void *log_init(void *frontend, Config *cfg) { struct LogContext *ctx = snew(struct LogContext); ctx->lgfp = NULL; ctx->state = L_CLOSED; ctx->frontend = frontend; ctx->cfg = *cfg; /* STRUCTURE COPY */ bufchain_init(&ctx->queue); return ctx; } void log_free(void *handle) { struct LogContext *ctx = (struct LogContext *)handle; logfclose(ctx); bufchain_clear(&ctx->queue); sfree(ctx); } void log_reconfig(void *handle, Config *cfg) { struct LogContext *ctx = (struct LogContext *)handle; int reset_logging; if (!filename_equal(ctx->cfg.logfilename, cfg->logfilename) || ctx->cfg.logtype != cfg->logtype) reset_logging = TRUE; else reset_logging = FALSE; if (reset_logging) logfclose(ctx); ctx->cfg = *cfg; /* STRUCTURE COPY */ if (reset_logging) logfopen(ctx); } /* * translate format codes into time/date strings * and insert them into log file name * * "&Y":YYYY "&m":MM "&d":DD "&T":hhmmss "&h":<hostname> "&&":& */ static void xlatlognam(Filename *dest, Filename src, char *hostname, struct tm *tm) { char buf[10], *bufp; int size; char buffer[FILENAME_MAX]; int len = sizeof(buffer)-1; char *d; const char *s; d = buffer; s = filename_to_str(&src); while (*s) { /* Let (bufp, len) be the string to append. */ bufp = buf; /* don't usually override this */ if (*s == '&') { char c; s++; |
︙ | ︙ | |||
451 452 453 454 455 456 457 | if (c != '&') buf[size++] = c; } } else { buf[0] = *s++; size = 1; } | | | < < | | > | | < < | 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 | if (c != '&') buf[size++] = c; } } else { buf[0] = *s++; size = 1; } if (size > len) size = len; memcpy(d, bufp, size); d += size; len -= size; } *d = '\0'; *dest = filename_from_str(buffer); } |
Changes to macosx/README.OSX.
︙ | ︙ | |||
16 17 18 19 20 21 22 | load of saved sessions, you should not be surprised if a future version of the port decides to look somewhere completely different for the data and therefore loses them all. If that happens, don't say you weren't warned! Other ways in which the port is currently unfinished include: | < < < < < < < < < | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | load of saved sessions, you should not be surprised if a future version of the port decides to look somewhere completely different for the data and therefore loses them all. If that happens, don't say you weren't warned! Other ways in which the port is currently unfinished include: Missing terminal window features -------------------------------- - terminal display is horribly slow - fonts aren't configurable |
︙ | ︙ |
Changes to macosx/osxmain.m.
︙ | ︙ | |||
81 82 83 84 85 86 87 | [alert addButtonWithTitle:@"Terminate"]; [alert setInformativeText:[NSString stringWithCString:errorbuf]]; [alert runModal]; } exit(1); } | < < < < < < < < < < < < < < < < < < | 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | [alert addButtonWithTitle:@"Terminate"]; [alert setInformativeText:[NSString stringWithCString:errorbuf]]; [alert runModal]; } exit(1); } void fatalbox(char *p, ...) { va_list ap; va_start(ap, p); commonfatalbox(p, ap); va_end(ap); } |
︙ | ︙ |
Changes to macosx/osxwin.m.
︙ | ︙ | |||
105 106 107 108 109 110 111 | nfg = ((attr & ATTR_FGMASK) >> ATTR_FGSHIFT); nbg = ((attr & ATTR_BGMASK) >> ATTR_BGSHIFT); if (attr & ATTR_REVERSE) { int t = nfg; nfg = nbg; nbg = t; } | | | | | 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | nfg = ((attr & ATTR_FGMASK) >> ATTR_FGSHIFT); nbg = ((attr & ATTR_BGMASK) >> ATTR_BGSHIFT); if (attr & ATTR_REVERSE) { int t = nfg; nfg = nbg; nbg = t; } if (cfg.bold_colour && (attr & ATTR_BOLD)) { if (nfg < 16) nfg |= 8; else if (nfg >= 256) nfg |= 1; } if (cfg.bold_colour && (attr & ATTR_BLINK)) { if (nbg < 16) nbg |= 8; else if (nbg >= 256) nbg |= 1; } if (attr & TATTR_ACTCURS) { nfg = 260; nbg = 261; } if (attr & ATTR_WIDE) { widefactor = 2; /* FIXME: what do we actually have to do about wide characters? */ } else { widefactor = 1; } /* FIXME: ATTR_BOLD without cfg.bold_colour */ if ((lattr & LATTR_MODE) != LATTR_NORM) { x *= 2; if (x >= term->cols) return; if (x + len*2*widefactor > term->cols) len = (term->cols-x)/2/widefactor;/* trim to LH half */ |
︙ | ︙ | |||
953 954 955 956 957 958 959 | void palette_set(void *frontend, int n, int r, int g, int b) { SessionWindow *win = (SessionWindow *)frontend; if (n >= 16) n += 256 - 16; | | | 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 | void palette_set(void *frontend, int n, int r, int g, int b) { SessionWindow *win = (SessionWindow *)frontend; if (n >= 16) n += 256 - 16; if (n > NALLCOLOURS) return; [win setColour:n r:r/255.0 g:g/255.0 b:b/255.0]; /* * FIXME: do we need an OS X equivalent of set_window_background? */ } |
︙ | ︙ |
Changes to minibidi.c.
1 | /************************************************************************ | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | /************************************************************************ * $Id: minibidi.c 9169 2011-05-07 10:57:19Z simon $ * * ------------ * Description: * ------------ * This is an implemention of Unicode's Bidirectional Algorithm * (known as UAX #9). * * http://www.unicode.org/reports/tr9/ * * Author: Ahmad Khalifa * * ----------------- * Revision Details: (Updated by Revision Control System) * ----------------- * $Date: 2011-05-07 05:57:19 -0500 (Sat, 07 May 2011) $ * $Author: simon $ * $Revision: 9169 $ * * (www.arabeyes.org - under MIT license) * ************************************************************************/ /* * TODO: |
︙ | ︙ | |||
54 55 56 57 58 59 60 | #define SINITIAL(xh) ((xh)+2) #define SMEDIAL(ch) ((ch)+3) #define leastGreaterOdd(x) ( ((x)+1) | 1 ) #define leastGreaterEven(x) ( ((x)+2) &~ 1 ) typedef struct bidi_char { | | | | 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | #define SINITIAL(xh) ((xh)+2) #define SMEDIAL(ch) ((ch)+3) #define leastGreaterOdd(x) ( ((x)+1) | 1 ) #define leastGreaterEven(x) ( ((x)+2) &~ 1 ) typedef struct bidi_char { wchar_t origwc, wc; unsigned short index; } bidi_char; /* function declarations */ void flipThisRun(bidi_char *from, unsigned char* level, int max, int count); int findIndexOfRun(unsigned char* level , int start, int count, int tlevel); unsigned char getType(int ch); unsigned char setOverrideBits(unsigned char level, unsigned char override); int getPreviousLevel(unsigned char* level, int from); int do_shape(bidi_char *line, bidi_char *to, int count); int do_bidi(bidi_char *line, int count); void doMirror(wchar_t* ch); /* character types */ enum { L, LRE, LRO, R, |
︙ | ︙ | |||
1632 1633 1634 1635 1636 1637 1638 | /* * Bad, Horrible function * takes a pointer to a character that is checked for * having a mirror glyph. */ | | | 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 | /* * Bad, Horrible function * takes a pointer to a character that is checked for * having a mirror glyph. */ void doMirror(wchar_t* ch) { if ((*ch & 0xFF00) == 0) { switch (*ch) { case 0x0028: *ch = 0x0029; break; case 0x0029: *ch = 0x0028; break; case 0x003C: *ch = 0x003E; break; case 0x003E: *ch = 0x003C; break; |
︙ | ︙ |
Changes to misc.c.
︙ | ︙ | |||
95 96 97 98 99 100 101 | p->frontend = frontend; p->data = NULL; p->to_server = TRUE; /* to be on the safe side */ p->name = p->instruction = NULL; p->name_reqd = p->instr_reqd = FALSE; return p; } | | > | | < < < < < < < < < < < < < < < < < < < < < < < < < | | 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | p->frontend = frontend; p->data = NULL; p->to_server = TRUE; /* to be on the safe side */ p->name = p->instruction = NULL; p->name_reqd = p->instr_reqd = FALSE; return p; } void add_prompt(prompts_t *p, char *promptstr, int echo, size_t len) { prompt_t *pr = snew(prompt_t); char *result = snewn(len, char); pr->prompt = promptstr; pr->echo = echo; pr->result = result; pr->result_len = len; p->n_prompts++; p->prompts = sresize(p->prompts, p->n_prompts, prompt_t *); p->prompts[p->n_prompts-1] = pr; } void free_prompts(prompts_t *p) { size_t i; for (i=0; i < p->n_prompts; i++) { prompt_t *pr = p->prompts[i]; memset(pr->result, 0, pr->result_len); /* burn the evidence */ sfree(pr->result); sfree(pr->prompt); sfree(pr); } sfree(p->prompts); sfree(p->name); sfree(p->instruction); |
︙ | ︙ | |||
196 197 198 199 200 201 202 | q += strlen(q); } va_end(ap); return p; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | q += strlen(q); } va_end(ap); return p; } /* * Do an sprintf(), but into a custom-allocated buffer. * * Currently I'm doing this via vsnprintf. This has worked so far, * but it's not good, because vsnprintf is not available on all * platforms. There's an ifdef to use `_vsnprintf', which seems * to be the local name for it on Windows. Other platforms may |
︙ | ︙ | |||
383 384 385 386 387 388 389 | * - return a (pointer,length) pair giving some initial data in * the list, suitable for passing to a send or write system * call * - retrieve a larger amount of initial data from the list * - return the current size of the buffer chain in bytes */ | | | > | 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 | * - return a (pointer,length) pair giving some initial data in * the list, suitable for passing to a send or write system * call * - retrieve a larger amount of initial data from the list * - return the current size of the buffer chain in bytes */ #define BUFFER_GRANULE 512 struct bufchain_granule { struct bufchain_granule *next; int buflen, bufpos; char buf[BUFFER_GRANULE]; }; void bufchain_init(bufchain *ch) { ch->head = ch->tail = NULL; ch->buffersize = 0; } |
︙ | ︙ | |||
421 422 423 424 425 426 427 | { const char *buf = (const char *)data; if (len == 0) return; ch->buffersize += len; | < | | | | | | | | | < | | | < | | > > | | | | > | < | | > < | | | | | | 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 | { const char *buf = (const char *)data; if (len == 0) return; ch->buffersize += len; if (ch->tail && ch->tail->buflen < BUFFER_GRANULE) { int copylen = min(len, BUFFER_GRANULE - ch->tail->buflen); memcpy(ch->tail->buf + ch->tail->buflen, buf, copylen); buf += copylen; len -= copylen; ch->tail->buflen += copylen; } while (len > 0) { int grainlen = min(len, BUFFER_GRANULE); struct bufchain_granule *newbuf; newbuf = snew(struct bufchain_granule); newbuf->bufpos = 0; newbuf->buflen = grainlen; memcpy(newbuf->buf, buf, grainlen); buf += grainlen; len -= grainlen; if (ch->tail) ch->tail->next = newbuf; else ch->head = ch->tail = newbuf; newbuf->next = NULL; ch->tail = newbuf; } } void bufchain_consume(bufchain *ch, int len) { struct bufchain_granule *tmp; assert(ch->buffersize >= len); while (len > 0) { int remlen = len; assert(ch->head != NULL); if (remlen >= ch->head->buflen - ch->head->bufpos) { remlen = ch->head->buflen - ch->head->bufpos; tmp = ch->head; ch->head = tmp->next; sfree(tmp); if (!ch->head) ch->tail = NULL; } else ch->head->bufpos += remlen; ch->buffersize -= remlen; len -= remlen; } } void bufchain_prefix(bufchain *ch, void **data, int *len) { *len = ch->head->buflen - ch->head->bufpos; *data = ch->head->buf + ch->head->bufpos; } void bufchain_fetch(bufchain *ch, void *data, int len) { struct bufchain_granule *tmp; char *data_c = (char *)data; tmp = ch->head; assert(ch->buffersize >= len); while (len > 0) { int remlen = len; assert(tmp != NULL); if (remlen >= tmp->buflen - tmp->bufpos) remlen = tmp->buflen - tmp->bufpos; memcpy(data_c, tmp->buf + tmp->bufpos, remlen); tmp = tmp->next; len -= remlen; data_c += remlen; } } |
︙ | ︙ | |||
686 687 688 689 690 691 692 | debug_printf("%*s%s\n", (16 - i) * 3 + 2, "", foo); } } #endif /* def DEBUG */ /* | | | | | | | | | | < < | < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < | 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 | debug_printf("%*s%s\n", (16 - i) * 3 + 2, "", foo); } } #endif /* def DEBUG */ /* * Determine whether or not a Config structure represents a session * which can sensibly be launched right now. */ int cfg_launchable(const Config *cfg) { if (cfg->protocol == PROT_SERIAL) return cfg->serline[0] != 0; else return cfg->host[0] != 0; } char const *cfg_dest(const Config *cfg) { if (cfg->protocol == PROT_SERIAL) return cfg->serline; else return cfg->host; } |
Changes to misc.h.
︙ | ︙ | |||
22 23 24 25 26 27 28 | typedef struct FontSpec FontSpec; unsigned long parse_blocksize(const char *bs); char ctrlparse(char *s, char **next); char *dupstr(const char *s); char *dupcat(const char *s1, ...); | | < < < < < < < | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | typedef struct FontSpec FontSpec; unsigned long parse_blocksize(const char *bs); char ctrlparse(char *s, char **next); char *dupstr(const char *s); char *dupcat(const char *s1, ...); char *dupprintf(const char *fmt, ...); char *dupvprintf(const char *fmt, va_list ap); char *fgetline(FILE *fp); void base64_encode_atom(unsigned char *data, int n, char *out); struct bufchain_granule; typedef struct bufchain_tag { |
︙ | ︙ | |||
52 53 54 55 56 57 58 | void bufchain_add(bufchain *ch, const void *data, int len); void bufchain_prefix(bufchain *ch, void **data, int *len); void bufchain_consume(bufchain *ch, int len); void bufchain_fetch(bufchain *ch, void *data, int len); struct tm ltime(void); | < < | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | void bufchain_add(bufchain *ch, const void *data, int len); void bufchain_prefix(bufchain *ch, void **data, int *len); void bufchain_consume(bufchain *ch, int len); void bufchain_fetch(bufchain *ch, void *data, int len); struct tm ltime(void); /* * Debugging functions. * * Output goes to debug.log * * debug(()) (note the double brackets) is like printf(). * |
︙ | ︙ |
Changes to mkauto.sh.
1 2 3 4 5 6 7 8 9 | #! /bin/sh # This script makes the autoconf mechanism for the Unix port work. # It's separate from mkfiles.pl because it won't work (and isn't needed) # on a non-Unix system. # It's nice to be able to run this from inside the unix subdir as # well as from outside. test -f unix.h && cd .. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | #! /bin/sh # This script makes the autoconf mechanism for the Unix port work. # It's separate from mkfiles.pl because it won't work (and isn't needed) # on a non-Unix system. # It's nice to be able to run this from inside the unix subdir as # well as from outside. test -f unix.h && cd .. # Persuade automake to give us a copy of its install-sh. This is a # pain because I don't actually want to have to _use_ automake. # Instead, I construct a trivial unrelated automake project in a # temporary subdirectory, run automake so that it'll copy # install-sh into that directory, then copy it back out again. # Hideous, but it should work. mkdir automake-grievous-hack cat > automake-grievous-hack/hello.c << EOF #include <stdio.h> int main(int argc, char **argv) { printf("hello, world\n"); return 0; } EOF cat > automake-grievous-hack/Makefile.am << EOF bin_PROGRAMS = hello hello_SOURCES = hello.c EOF cat > automake-grievous-hack/configure.ac << EOF AC_INIT AM_INIT_AUTOMAKE(hello, 1.0) AC_CONFIG_FILES([Makefile]) AC_PROG_CC AC_OUTPUT EOF echo Some news > automake-grievous-hack/NEWS echo Some text > automake-grievous-hack/README echo Some people > automake-grievous-hack/AUTHORS echo Some changes > automake-grievous-hack/ChangeLog rm -f install-sh # this won't work if we accidentally have one _here_ (cd automake-grievous-hack && autoreconf -i && \ cp install-sh ../unix/install-sh) rm -rf automake-grievous-hack # That was the hard bit. Now run autoconf on our real configure.in. (cd unix && autoreconf && rm -rf aclocal.m4 autom4te.cache) |
Changes to mkfiles.pl.
︙ | ︙ | |||
13 14 15 16 17 18 19 | # mainly because I was too scared to go anywhere near it. # - sbcsgen.pl is still run at startup. # # FIXME: no attempt made to handle !forceobj in the project files. use warnings; use FileHandle; | < < < < < < < < < < < < < < < < | | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | # mainly because I was too scared to go anywhere near it. # - sbcsgen.pl is still run at startup. # # FIXME: no attempt made to handle !forceobj in the project files. use warnings; use FileHandle; use Cwd; open IN, "Recipe" or do { # We want to deal correctly with being run from one of the # subdirs in the source tree. So if we can't find Recipe here, # try one level up. chdir ".."; open IN, "Recipe" or die "unable to open Recipe file\n"; }; # HACK: One of the source files in `charset' is auto-generated by # sbcsgen.pl. We need to generate that _now_, before attempting # dependency analysis. eval 'chdir "charset"; require "sbcsgen.pl"; chdir ".."'; @srcdirs = ("./"); $divert = undef; # ref to scalar in which text is currently being put $help = ""; # list of newline-free lines of help text $project_name = "project"; # this is a good enough default %makefiles = (); # maps makefile types to output makefile pathnames |
︙ | ︙ | |||
76 77 78 79 80 81 82 | if ($_[0] eq "!begin" and $_[1] eq "help") { $divert = \$help; next; } if ($_[0] eq "!end") { $divert = undef; next; } if ($_[0] eq "!name") { $project_name = $_[1]; next; } if ($_[0] eq "!srcdir") { push @srcdirs, $_[1]; next; } if ($_[0] eq "!makefile" and &mfval($_[1])) { $makefiles{$_[1]}=$_[2]; next;} if ($_[0] eq "!specialobj" and &mfval($_[1])) { $specialobj{$_[1]}->{$_[2]} = 1; next;} | < < < < < < < < | | 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | if ($_[0] eq "!begin" and $_[1] eq "help") { $divert = \$help; next; } if ($_[0] eq "!end") { $divert = undef; next; } if ($_[0] eq "!name") { $project_name = $_[1]; next; } if ($_[0] eq "!srcdir") { push @srcdirs, $_[1]; next; } if ($_[0] eq "!makefile" and &mfval($_[1])) { $makefiles{$_[1]}=$_[2]; next;} if ($_[0] eq "!specialobj" and &mfval($_[1])) { $specialobj{$_[1]}->{$_[2]} = 1; next;} if ($_[0] eq "!forceobj") { $forceobj{$_[1]} = 1; next; } if ($_[0] eq "!begin") { if (&mfval($_[1])) { $sect = $_[2] ? $_[2] : "end"; $divert = \($makefile_extra{$_[1]}->{$sect}); } else { $dummy = ''; $divert = \$dummy; } next; |
︙ | ︙ | |||
143 144 145 146 147 148 149 | $programs{$prog . "," . $type} = $listref; } $lastlistref = $listref; } close IN; | < < < < < < | 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | $programs{$prog . "," . $type} = $listref; } $lastlistref = $listref; } close IN; # Now retrieve the complete list of objects and resource files, and # construct dependency data for them. While we're here, expand the # object list for each program, and complain if its type isn't set. @prognames = sort keys %programs; %depends = (); @scanlist = (); foreach $i (@prognames) { |
︙ | ︙ | |||
203 204 205 206 207 208 209 | # Files included by this method are not added to @scanlist because # they can never include further files. # # In this pass we write out a hash %further which maps a source # file name into a listref containing further source file names. %further = (); | < < | 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 | # Files included by this method are not added to @scanlist because # they can never include further files. # # In this pass we write out a hash %further which maps a source # file name into a listref containing further source file names. %further = (); while (scalar @scanlist > 0) { $file = shift @scanlist; next if defined $further{$file}; # skip if we've already done it $further{$file} = []; $dirfile = &findfile($file); open IN, "$dirfile" or die "unable to open source file $file\n"; while (<IN>) { chomp; /^\s*#include\s+\"([^\"]+)\"/ and do { push @{$further{$file}}, $1; push @scanlist, $1; next; |
︙ | ︙ | |||
254 255 256 257 258 259 260 | sub mfval($) { my ($type) = @_; # Returns true if the argument is a known makefile type. Otherwise, # prints a warning and returns false; if (grep { $type eq $_ } ("vc","vcproj","cygwin","borland","lcc","devcppproj","gtk","unix", | | | 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 | sub mfval($) { my ($type) = @_; # Returns true if the argument is a known makefile type. Otherwise, # prints a warning and returns false; if (grep { $type eq $_ } ("vc","vcproj","cygwin","borland","lcc","devcppproj","gtk","unix", "ac","osx",)) { return 1; } warn "$.:unknown makefile type '$type'\n"; return 0; } # Utility routines while writing out the Makefiles. |
︙ | ︙ | |||
419 420 421 422 423 424 425 | # assume that all UNIX programs have a man page if($suffix eq "1" && $types =~ /:X:/) { return map("$_.1", &progrealnames($types)); } return (); } | < < | | | 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 | # assume that all UNIX programs have a man page if($suffix eq "1" && $types =~ /:X:/) { return map("$_.1", &progrealnames($types)); } return (); } # Now we're ready to output the actual Makefiles. if (defined $makefiles{'cygwin'}) { $dirpfx = &dirpfx($makefiles{'cygwin'}, "/"); ##-- CygWin makefile open OUT, ">$makefiles{'cygwin'}"; select OUT; print "# Makefile for $project_name under cygwin.\n". "#\n# This file was created by `mkfiles.pl' from the `Recipe' file.\n". "# DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead.\n"; # gcc command line option is -D not /D ($_ = $help) =~ s/([=" ])\/D/$1-D/gs; print $_; print "\n". "# You can define this path to point at your tools if you need to\n". "# TOOLPATH = c:\\cygwin\\bin\\ # or similar, if you're running Windows\n". "# TOOLPATH = /pkg/mingw32msvc/i386-mingw32msvc/bin/\n". "CC = \$(TOOLPATH)gcc\n". "RC = \$(TOOLPATH)windres\n". "# Uncomment the following two lines to compile under Winelib\n". "# CC = winegcc\n". "# RC = wrc\n". "# You may also need to tell windres where to find include files:\n". "# RCINC = --include-dir c:\\cygwin\\include\\\n". "\n". &splitline("CFLAGS = -mno-cygwin -Wall -O2 -D_WINDOWS -DDEBUG -DWIN32S_COMPAT". " -D_NO_OLDNAMES -DNO_MULTIMON -DNO_HTMLHELP " . (join " ", map {"-I$dirpfx$_"} @srcdirs)) . "\n". "LDFLAGS = -mno-cygwin -s\n". &splitline("RCFLAGS = \$(RCINC) --define WIN32=1 --define _WIN32=1". " --define WINVER=0x0400")."\n". "\n". $makefile_extra{'cygwin'}->{'vars'} . |
︙ | ︙ | |||
480 481 482 483 484 485 486 | if ($forceobj{$d->{obj_orig}}) { printf ("%s: FORCE\n", $d->{obj}); } else { print &splitline(sprintf("%s: %s", $d->{obj}, join " ", @{$d->{deps}})), "\n"; } if ($d->{obj} =~ /\.res\.o$/) { | | | | 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 | if ($forceobj{$d->{obj_orig}}) { printf ("%s: FORCE\n", $d->{obj}); } else { print &splitline(sprintf("%s: %s", $d->{obj}, join " ", @{$d->{deps}})), "\n"; } if ($d->{obj} =~ /\.res\.o$/) { print "\t\$(RC) \$(RCFL) \$(RCFLAGS) ".$d->{deps}->[0]." ".$d->{obj}."\n\n"; } else { print "\t\$(CC) \$(COMPAT) \$(CFLAGS) \$(XFLAGS) -c ".$d->{deps}->[0]."\n\n"; } } print "\n"; print $makefile_extra{'cygwin'}->{'end'}; print "\nclean:\n". "\trm -f *.o *.exe *.res.o *.map\n". "\n". "FORCE:\n"; select STDOUT; close OUT; } ##-- Borland makefile |
︙ | ︙ | |||
698 699 700 701 702 703 704 705 706 707 708 709 710 711 | "\t-del *.idb\n". "\t-del debug.log\n"; select STDOUT; close OUT; } if (defined $makefiles{'vcproj'}) { $dirpfx = &dirpfx($makefiles{'vcproj'}, "\\"); ##-- MSVC 6 Workspace and projects # # Note: All files created in this section are written in binary # mode, because although MSVC's command-line make can deal with # LF-only line endings, MSVC project files really _need_ to be # CRLF. Hence, in order for mkfiles.pl to generate usable project | > > | 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 | "\t-del *.idb\n". "\t-del debug.log\n"; select STDOUT; close OUT; } if (defined $makefiles{'vcproj'}) { $dirpfx = &dirpfx($makefiles{'vcproj'}, "\\"); $orig_dir = cwd; ##-- MSVC 6 Workspace and projects # # Note: All files created in this section are written in binary # mode, because although MSVC's command-line make can deal with # LF-only line endings, MSVC project files really _need_ to be # CRLF. Hence, in order for mkfiles.pl to generate usable project |
︙ | ︙ | |||
1112 1113 1114 1115 1116 1117 1118 | print &def($makefile_extra{'unix'}->{'end'}); print "\nclean:\n". "\trm -f *.o". (join "", map { " $_" } &progrealnames("U")) . "\n"; print "\nFORCE:\n"; select STDOUT; close OUT; } | | | | | | | | < < < < < < < | < < < < < < < < < < | < | | > | | > > > > > > > | | | < | > | | | < | < | | < | | < < < | < < < | < | < < < < | | | < < < > > | > > > | < | < | < | | < | < | > > > > > > | 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 | print &def($makefile_extra{'unix'}->{'end'}); print "\nclean:\n". "\trm -f *.o". (join "", map { " $_" } &progrealnames("U")) . "\n"; print "\nFORCE:\n"; select STDOUT; close OUT; } if (defined $makefiles{'ac'}) { $dirpfx = &dirpfx($makefiles{'ac'}, "/"); ##-- Unix/autoconf makefile open OUT, ">$makefiles{'ac'}"; select OUT; print "# Makefile.in for $project_name under Unix with Autoconf.\n". "#\n# This file was created by `mkfiles.pl' from the `Recipe' file.\n". "# DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead.\n"; # gcc command line option is -D not /D ($_ = $help) =~ s/([=" ])\/D/$1-D/gs; print $_; print "\n". "CC = \@CC\@\n". "\n". &splitline("CFLAGS = \@CFLAGS\@ \@PUTTYCFLAGS\@ \@CPPFLAGS\@ " . "\@DEFS\@ \@GTK_CFLAGS\@ " . (join " ", map {"-I$dirpfx$_"} @srcdirs))."\n". "XLDFLAGS = \@LDFLAGS\@ \@LIBS\@ \@GTK_LIBS\@\n". "ULDFLAGS = \@LDFLAGS\@ \@LIBS\@\n". "INSTALL=\@INSTALL\@\n". "INSTALL_PROGRAM=\$(INSTALL)\n". "INSTALL_DATA=\$(INSTALL)\n". "prefix=\@prefix\@\n". "exec_prefix=\@exec_prefix\@\n". "bindir=\@bindir\@\n". "datarootdir=\@datarootdir\@\n". "mandir=\@mandir\@\n". "man1dir=\$(mandir)/man1\n". "\n". &def($makefile_extra{'gtk'}->{'vars'}) . "\n". ".SUFFIXES:\n". "\n". "\n". "all: \@all_targets\@\n". &splitline("all-cli:" . join "", map { " $_" } &progrealnames("U"))."\n". &splitline("all-gtk:" . join "", map { " $_" } &progrealnames("X"))."\n"; print "\n"; foreach $p (&prognames("X:U")) { ($prog, $type) = split ",", $p; $objstr = &objects($p, "X.o", undef, undef); print &splitline($prog . ": " . $objstr), "\n"; $libstr = &objects($p, undef, undef, "-lX"); print &splitline("\t\$(CC) -o \$@ " . $objstr . " \$(${type}LDFLAGS) $libstr", 69), "\n\n"; } foreach $d (&deps("X.o", undef, $dirpfx, "/", "gtk")) { if ($forceobj{$d->{obj_orig}}) { printf("%s: FORCE\n", $d->{obj}); } else { print &splitline(sprintf("%s: %s", $d->{obj}, join " ", @{$d->{deps}})), "\n"; } print &splitline("\t\$(CC) \$(COMPAT) \$(CFLAGS) \$(XFLAGS) -c $d->{deps}->[0]\n"); } print "\n"; print $makefile_extra{'gtk'}->{'end'}; print "\nclean:\n". "\trm -f *.o". (join "", map { " $_" } &progrealnames("X:U")) . "\n"; print "\ndistclean: clean\n". "\t". &splitline("rm -f config.status config.cache config.log ". "configure.lineno config.status.lineno Makefile") . "\n"; print "\nFORCE:\n"; select STDOUT; close OUT; } if (defined $makefiles{'lcc'}) { $dirpfx = &dirpfx($makefiles{'lcc'}, "\\"); ##-- lcc makefile |
︙ | ︙ | |||
1385 1386 1387 1388 1389 1390 1391 | # Create the project files # Get names of all Windows projects (GUI and console) my @prognames = &prognames("G:C"); foreach $progname (@prognames) { create_devcpp_project(\%all_object_deps, $progname); } | < < | 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 | # Create the project files # Get names of all Windows projects (GUI and console) my @prognames = &prognames("G:C"); foreach $progname (@prognames) { create_devcpp_project(\%all_object_deps, $progname); } sub create_devcpp_project { my ($all_object_deps, $progname) = @_; # Construct program's dependency info (Taken from 'vcproj', seems to work right here, too.) %seen_objects = (); %lib_files = (); %source_files = (); %header_files = (); |
︙ | ︙ | |||
1542 1543 1544 1545 1546 1547 1548 | "ProductName=$windows_project\r\n". "ProductVersion=0.1\r\n". "AutoIncBuildNr=0\r\n"; select STDOUT; close OUT; chdir ".."; } } | < < < < < < < < < < < < < < | 1487 1488 1489 1490 1491 1492 1493 | "ProductName=$windows_project\r\n". "ProductVersion=0.1\r\n". "AutoIncBuildNr=0\r\n"; select STDOUT; close OUT; chdir ".."; } } |
Changes to mksrcarc.sh.
︙ | ︙ | |||
16 17 18 19 20 21 22 | # /dev/null! Apparently its heuristics are doubtful of UTF-8 text # files. bintext=testdata/*.txt # These are actual binary files which we don't want transforming. bin=`{ ls -1 windows/*.ico windows/putty.iss windows/website.url macosx/*.icns; \ find . -name '*.dsp' -print -o -name '*.dsw' -print; }` zip -k -l putty-src.zip $text > /dev/null | | | 16 17 18 19 20 21 22 23 24 | # /dev/null! Apparently its heuristics are doubtful of UTF-8 text # files. bintext=testdata/*.txt # These are actual binary files which we don't want transforming. bin=`{ ls -1 windows/*.ico windows/putty.iss windows/website.url macosx/*.icns; \ find . -name '*.dsp' -print -o -name '*.dsw' -print; }` zip -k -l putty-src.zip $text > /dev/null zip -k -l putty-src.zip $bintext >& /dev/null zip -k putty-src.zip $bin > /dev/null |
Changes to mkunxarc.sh.
|
| | | < < | | < < | > < < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | #!/bin/sh # Build a Unix source distribution from the PuTTY CVS area. # # Pass an argument of the form `2004-02-08' to have the archive # tagged as a development snapshot; of the form `0.54' to have it # tagged as a release; of the form `r1234' to have it tagged as a # custom build. Otherwise it'll be tagged as unidentified. case "$1" in ????-??-??) case "$1" in *[!-0-9]*) echo "Malformed snapshot ID '$1'" >&2;exit 1;;esac arcsuffix="-`cat LATEST.VER`-$1" ver="-DSNAPSHOT=$1" docver= ;; r*) arcsuffix="-$1" ver="-DSVN_REV=$1" docver= ;; '') arcsuffix= ver= docver= ;; *pre) set -- "${1%pre}" "$2" case "$1" in *[!.0-9a-z~]*) echo "Malformed prerelease ID '$1'">&2;exit 1;;esac case "$2" in *[!.0-9a-z~]*) echo "Malformed prerelease revision '$1'">&2;exit 1;;esac autoconfver="$1~pre$2" arcsuffix="-$autoconfver" ver="-DPRERELEASE=$1 -DSVN_REV=$2" docver="VERSION=\"PuTTY prerelease $1:r$2\"" ;; *) case "$1" in *[!.0-9a-z~]*) echo "Malformed release ID '$1'">&2;exit 1;;esac arcsuffix="-$1" ver="-DRELEASE=$1" docver="VERSION=\"PuTTY release $1\"" ;; esac perl mkfiles.pl (cd doc && make -s ${docver:+"$docver"}) sh mkauto.sh 2>/dev/null relver=`cat LATEST.VER` arcname="putty$arcsuffix" mkdir uxarc mkdir uxarc/$arcname find . -name uxarc -prune -o \ -name CVS -prune -o \ -name .svn -prune -o \ -name . -o \ -type d -exec mkdir uxarc/$arcname/{} \; find . -name uxarc -prune -o \ -name CVS -prune -o \ -name .cvsignore -prune -o \ -name .svn -prune -o \ -name '*.zip' -prune -o \ -name '*.tar.gz' -prune -o \ -type f -exec ln -s $PWD/{} uxarc/$arcname/{} \; if test "x$ver" != "x"; then (cd uxarc/$arcname; md5sum `find . -name '*.[ch]' -print` > manifest; echo "$ver" > version.def) fi tar -C uxarc -chzof $arcname.tar.gz $arcname rm -rf uxarc |
Changes to network.h.
︙ | ︙ | |||
11 12 13 14 15 16 17 | */ #ifndef PUTTY_NETWORK_H #define PUTTY_NETWORK_H #ifndef DONE_TYPEDEFS #define DONE_TYPEDEFS | | > > > > < > > < < < | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | */ #ifndef PUTTY_NETWORK_H #define PUTTY_NETWORK_H #ifndef DONE_TYPEDEFS #define DONE_TYPEDEFS typedef struct config_tag Config; typedef struct backend_tag Backend; typedef struct terminal_tag Terminal; #endif typedef struct SockAddr_tag *SockAddr; /* pay attention to levels of indirection */ typedef struct socket_function_table **Socket; typedef struct plug_function_table **Plug; #ifndef OSSOCKET_DEFINED typedef void *OSSocket; #endif struct socket_function_table { Plug(*plug) (Socket s, Plug p); /* use a different plug (return the old one) */ /* if p is NULL, it doesn't change the plug */ /* but it does return the one it's using */ void (*close) (Socket s); int (*write) (Socket s, const char *data, int len); int (*write_oob) (Socket s, const char *data, int len); void (*flush) (Socket s); void (*set_private_ptr) (Socket s, void *ptr); void *(*get_private_ptr) (Socket s); void (*set_frozen) (Socket s, int is_frozen); /* ignored by tcp, but vital for ssl */ const char *(*socket_error) (Socket s); }; struct plug_function_table { void (*log)(Plug p, int type, SockAddr addr, int port, const char *error_msg, int error_code); /* * Passes the client progress reports on the process of setting * up the connection. * |
︙ | ︙ | |||
76 77 78 79 80 81 82 | */ void (*sent) (Plug p, int bufsize); /* * The `sent' function is called when the pending send backlog * on a socket is cleared or partially cleared. The new backlog * size is passed in the `bufsize' parameter. */ | | < < | < | | | < < | < | < > > < | > > > > > > > > > > | 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 | */ void (*sent) (Plug p, int bufsize); /* * The `sent' function is called when the pending send backlog * on a socket is cleared or partially cleared. The new backlog * size is passed in the `bufsize' parameter. */ int (*accepting)(Plug p, OSSocket sock); /* * returns 0 if the host at address addr is a valid host for connecting or error */ }; /* proxy indirection layer */ /* NB, control of 'addr' is passed via new_connection, which takes * responsibility for freeing it */ Socket new_connection(SockAddr addr, char *hostname, int port, int privport, int oobinline, int nodelay, int keepalive, Plug plug, const Config *cfg); Socket new_listener(char *srcaddr, int port, Plug plug, int local_host_only, const Config *cfg, int addressfamily); SockAddr name_lookup(char *host, int port, char **canonicalname, const Config *cfg, int addressfamily); /* platform-dependent callback from new_connection() */ /* (same caveat about addr as new_connection()) */ Socket platform_new_connection(SockAddr addr, char *hostname, int port, int privport, int oobinline, int nodelay, int keepalive, Plug plug, const Config *cfg); /* socket functions */ void sk_init(void); /* called once at program startup */ void sk_cleanup(void); /* called just before program exit */ SockAddr sk_namelookup(const char *host, char **canonicalname, int address_family); SockAddr sk_nonamelookup(const char *host); void sk_getaddr(SockAddr addr, char *buf, int buflen); int sk_hostname_is_local(char *name); int sk_address_is_local(SockAddr addr); int sk_addrtype(SockAddr addr); void sk_addrcopy(SockAddr addr, char *buf); void sk_addr_free(SockAddr addr); /* sk_addr_dup generates another SockAddr which contains the same data * as the original one and can be freed independently. May not actually * physically _duplicate_ it: incrementing a reference count so that * one more free is required before it disappears is an acceptable * implementation. */ SockAddr sk_addr_dup(SockAddr addr); /* NB, control of 'addr' is passed via sk_new, which takes responsibility * for freeing it, as for new_connection() */ Socket sk_new(SockAddr addr, int port, int privport, int oobinline, int nodelay, int keepalive, Plug p); Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only, int address_family); Socket sk_register(OSSocket sock, Plug plug); #define sk_plug(s,p) (((*s)->plug) (s, p)) #define sk_close(s) (((*s)->close) (s)) #define sk_write(s,buf,len) (((*s)->write) (s, buf, len)) #define sk_write_oob(s,buf,len) (((*s)->write_oob) (s, buf, len)) #define sk_flush(s) (((*s)->flush) (s)) #ifdef DEFINE_PLUG_METHOD_MACROS #define plug_log(p,type,addr,port,msg,code) (((*p)->log) (p, type, addr, port, msg, code)) #define plug_closing(p,msg,code,callback) (((*p)->closing) (p, msg, code, callback)) #define plug_receive(p,urgent,buf,len) (((*p)->receive) (p, urgent, buf, len)) #define plug_sent(p,bufsize) (((*p)->sent) (p, bufsize)) #define plug_accepting(p, sock) (((*p)->accepting)(p, sock)) #endif /* * Each socket abstraction contains a `void *' private field in * which the client can keep state. * * This is perhaps unnecessary now that we have the notion of a plug, * but there is some existing code that uses it, so it stays. */ #define sk_set_private_ptr(s, ptr) (((*s)->set_private_ptr) (s, ptr)) #define sk_get_private_ptr(s) (((*s)->get_private_ptr) (s)) /* * Special error values are returned from sk_namelookup and sk_new * if there's a problem. These functions extract an error message, * or return NULL if there's no problem. */ const char *sk_addr_error(SockAddr addr); #define sk_socket_error(s) (((*s)->socket_error) (s)) |
︙ | ︙ | |||
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 | * - Socket buffering: if an SSH channel (or the whole connection) * backs up or presents a zero window, we must freeze the * associated local socket in order to avoid unbounded buffer * growth. */ #define sk_set_frozen(s, is_frozen) (((*s)->set_frozen) (s, is_frozen)) /* * Simple wrapper on getservbyname(), needed by ssh.c. Returns the * port number, in host byte order (suitable for printf and so on). * Returns 0 on failure. Any platform not supporting getservbyname * can just return 0 - this function is not required to handle * numeric port specifications. */ int net_service_lookup(char *service); /* * Look up the local hostname; return value needs freeing. * May return NULL. */ char *get_hostname(void); | > > > > > > < < < < < < | 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 | * - Socket buffering: if an SSH channel (or the whole connection) * backs up or presents a zero window, we must freeze the * associated local socket in order to avoid unbounded buffer * growth. */ #define sk_set_frozen(s, is_frozen) (((*s)->set_frozen) (s, is_frozen)) /* * Call this after an operation that might have tried to send on a * socket, to clean up any pending network errors. */ void net_pending_errors(void); /* * Simple wrapper on getservbyname(), needed by ssh.c. Returns the * port number, in host byte order (suitable for printf and so on). * Returns 0 on failure. Any platform not supporting getservbyname * can just return 0 - this function is not required to handle * numeric port specifications. */ int net_service_lookup(char *service); /* * Look up the local hostname; return value needs freeing. * May return NULL. */ char *get_hostname(void); /********** SSL stuff **********/ /* * This section is subject to change, but you get the general idea * of what it will eventually look like. */ |
︙ | ︙ |
Deleted noshare.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted noterm.c.
|
| < < < < < < < < < < < |
Changes to notiming.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* * notiming.c: stub version of timing API. * * Used in any tool which needs a subsystem linked against the * timing API but doesn't want to actually provide timing. For * example, key generation tools need the random number generator, * but they don't want the hassle of calling noise_regular() at * regular intervals - and they don't _need_ it either, since they * have their own rigorous and different means of noise collection. */ #include "putty.h" | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /* * notiming.c: stub version of timing API. * * Used in any tool which needs a subsystem linked against the * timing API but doesn't want to actually provide timing. For * example, key generation tools need the random number generator, * but they don't want the hassle of calling noise_regular() at * regular intervals - and they don't _need_ it either, since they * have their own rigorous and different means of noise collection. */ #include "putty.h" long schedule_timer(int ticks, timer_fn_t fn, void *ctx) { return 0; } void expire_timer_context(void *ctx) { } |
Changes to pinger.c.
1 2 3 4 5 6 7 8 9 10 | /* * pinger.c: centralised module that deals with sending TS_PING * keepalives, to avoid replicating this code in multiple backends. */ #include "putty.h" struct pinger_tag { int interval; int pending; | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | /* * pinger.c: centralised module that deals with sending TS_PING * keepalives, to avoid replicating this code in multiple backends. */ #include "putty.h" struct pinger_tag { int interval; int pending; long next; Backend *back; void *backhandle; }; static void pinger_schedule(Pinger pinger); static void pinger_timer(void *ctx, long now) { Pinger pinger = (Pinger)ctx; if (pinger->pending && now - pinger->next >= 0) { pinger->back->special(pinger->backhandle, TS_PING); pinger->pending = FALSE; pinger_schedule(pinger); } } static void pinger_schedule(Pinger pinger) |
︙ | ︙ | |||
39 40 41 42 43 44 45 | pinger_timer, pinger); if (!pinger->pending || next < pinger->next) { pinger->next = next; pinger->pending = TRUE; } } | | | | < | | | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | pinger_timer, pinger); if (!pinger->pending || next < pinger->next) { pinger->next = next; pinger->pending = TRUE; } } Pinger pinger_new(Config *cfg, Backend *back, void *backhandle) { Pinger pinger = snew(struct pinger_tag); pinger->interval = cfg->ping_interval; pinger->pending = FALSE; pinger->back = back; pinger->backhandle = backhandle; pinger_schedule(pinger); return pinger; } void pinger_reconfig(Pinger pinger, Config *oldcfg, Config *newcfg) { if (oldcfg->ping_interval != newcfg->ping_interval) { pinger->interval = newcfg->ping_interval; pinger_schedule(pinger); } } void pinger_free(Pinger pinger) { expire_timer_context(pinger); sfree(pinger); } |
Added pkcs11.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 | /* pkcs11.h Copyright 2006, 2007 g10 Code GmbH Copyright 2006 Andreas Jellinghaus This file is free software; as a special exception the author gives unlimited permission to copy and/or distribute it, with or without modifications, as long as this notice is preserved. This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY, to the extent permitted by law; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ /* Please submit changes back to the Scute project at http://www.scute.org/ (or send them to marcus@g10code.com), so that they can be picked up by other projects from there as well. */ /* This file is a modified implementation of the PKCS #11 standard by RSA Security Inc. It is mostly a drop-in replacement, with the following change: This header file does not require any macro definitions by the user (like CK_DEFINE_FUNCTION etc). In fact, it defines those macros for you (if useful, some are missing, let me know if you need more). There is an additional API available that does comply better to the GNU coding standard. It can be switched on by defining CRYPTOKI_GNU before including this header file. For this, the following changes are made to the specification: All structure types are changed to a "struct ck_foo" where CK_FOO is the type name in PKCS #11. All non-structure types are changed to ck_foo_t where CK_FOO is the lowercase version of the type name in PKCS #11. The basic types (CK_ULONG et al.) are removed without substitute. All members of structures are modified in the following way: Type indication prefixes are removed, and underscore characters are inserted before words. Then the result is lowercased. Note that function names are still in the original case, as they need for ABI compatibility. CK_FALSE, CK_TRUE and NULL_PTR are removed without substitute. Use <stdbool.h>. If CRYPTOKI_COMPAT is defined before including this header file, then none of the API changes above take place, and the API is the one defined by the PKCS #11 standard. */ #ifndef PKCS11_H #define PKCS11_H 1 #if defined(__cplusplus) extern "C" { #endif /* The version of cryptoki we implement. The revision is changed with each modification of this file. If you do not use the "official" version of this file, please consider deleting the revision macro (you may use a macro with a different name to keep track of your versions). */ #define CRYPTOKI_VERSION_MAJOR 2 #define CRYPTOKI_VERSION_MINOR 20 #define CRYPTOKI_VERSION_REVISION 6 /* Compatibility interface is default, unless CRYPTOKI_GNU is given. */ #ifndef CRYPTOKI_GNU #ifndef CRYPTOKI_COMPAT #define CRYPTOKI_COMPAT 1 #endif #endif /* System dependencies. */ #if defined(_WIN32) || defined(CRYPTOKI_FORCE_WIN32) /* There is a matching pop below. */ #pragma pack(push, cryptoki, 1) #ifdef CRYPTOKI_EXPORTS #define CK_SPEC __declspec(dllexport) #else #define CK_SPEC __declspec(dllimport) #endif #else #define CK_SPEC #endif #ifdef CRYPTOKI_COMPAT /* If we are in compatibility mode, switch all exposed names to the PKCS #11 variant. There are corresponding #undefs below. */ #define ck_flags_t CK_FLAGS #define ck_version _CK_VERSION #define ck_info _CK_INFO #define cryptoki_version cryptokiVersion #define manufacturer_id manufacturerID #define library_description libraryDescription #define library_version libraryVersion #define ck_notification_t CK_NOTIFICATION #define ck_slot_id_t CK_SLOT_ID #define ck_slot_info _CK_SLOT_INFO #define slot_description slotDescription #define hardware_version hardwareVersion #define firmware_version firmwareVersion #define ck_token_info _CK_TOKEN_INFO #define serial_number serialNumber #define max_session_count ulMaxSessionCount #define session_count ulSessionCount #define max_rw_session_count ulMaxRwSessionCount #define rw_session_count ulRwSessionCount #define max_pin_len ulMaxPinLen #define min_pin_len ulMinPinLen #define total_public_memory ulTotalPublicMemory #define free_public_memory ulFreePublicMemory #define total_private_memory ulTotalPrivateMemory #define free_private_memory ulFreePrivateMemory #define utc_time utcTime #define ck_session_handle_t CK_SESSION_HANDLE #define ck_user_type_t CK_USER_TYPE #define ck_state_t CK_STATE #define ck_session_info _CK_SESSION_INFO #define slot_id slotID #define device_error ulDeviceError #define ck_object_handle_t CK_OBJECT_HANDLE #define ck_object_class_t CK_OBJECT_CLASS #define ck_hw_feature_type_t CK_HW_FEATURE_TYPE #define ck_key_type_t CK_KEY_TYPE #define ck_certificate_type_t CK_CERTIFICATE_TYPE #define ck_attribute_type_t CK_ATTRIBUTE_TYPE #define ck_attribute _CK_ATTRIBUTE #define value pValue #define value_len ulValueLen #define ck_date _CK_DATE #define ck_mechanism_type_t CK_MECHANISM_TYPE #define ck_mechanism _CK_MECHANISM #define parameter pParameter #define parameter_len ulParameterLen #define ck_mechanism_info _CK_MECHANISM_INFO #define min_key_size ulMinKeySize #define max_key_size ulMaxKeySize #define ck_rv_t CK_RV #define ck_notify_t CK_NOTIFY #define ck_function_list _CK_FUNCTION_LIST #define ck_createmutex_t CK_CREATEMUTEX #define ck_destroymutex_t CK_DESTROYMUTEX #define ck_lockmutex_t CK_LOCKMUTEX #define ck_unlockmutex_t CK_UNLOCKMUTEX #define ck_c_initialize_args _CK_C_INITIALIZE_ARGS #define create_mutex CreateMutex #define destroy_mutex DestroyMutex #define lock_mutex LockMutex #define unlock_mutex UnlockMutex #define reserved pReserved #endif /* CRYPTOKI_COMPAT */ typedef unsigned long ck_flags_t; struct ck_version { unsigned char major; unsigned char minor; }; struct ck_info { struct ck_version cryptoki_version; unsigned char manufacturer_id[32]; ck_flags_t flags; unsigned char library_description[32]; struct ck_version library_version; }; typedef unsigned long ck_notification_t; #define CKN_SURRENDER (0) typedef unsigned long ck_slot_id_t; struct ck_slot_info { unsigned char slot_description[64]; unsigned char manufacturer_id[32]; ck_flags_t flags; struct ck_version hardware_version; struct ck_version firmware_version; }; #define CKF_TOKEN_PRESENT (1 << 0) #define CKF_REMOVABLE_DEVICE (1 << 1) #define CKF_HW_SLOT (1 << 2) #define CKF_ARRAY_ATTRIBUTE (1 << 30) struct ck_token_info { unsigned char label[32]; unsigned char manufacturer_id[32]; unsigned char model[16]; unsigned char serial_number[16]; ck_flags_t flags; unsigned long max_session_count; unsigned long session_count; unsigned long max_rw_session_count; unsigned long rw_session_count; unsigned long max_pin_len; unsigned long min_pin_len; unsigned long total_public_memory; unsigned long free_public_memory; unsigned long total_private_memory; unsigned long free_private_memory; struct ck_version hardware_version; struct ck_version firmware_version; unsigned char utc_time[16]; }; #define CKF_RNG (1 << 0) #define CKF_WRITE_PROTECTED (1 << 1) #define CKF_LOGIN_REQUIRED (1 << 2) #define CKF_USER_PIN_INITIALIZED (1 << 3) #define CKF_RESTORE_KEY_NOT_NEEDED (1 << 5) #define CKF_CLOCK_ON_TOKEN (1 << 6) #define CKF_PROTECTED_AUTHENTICATION_PATH (1 << 8) #define CKF_DUAL_CRYPTO_OPERATIONS (1 << 9) #define CKF_TOKEN_INITIALIZED (1 << 10) #define CKF_SECONDARY_AUTHENTICATION (1 << 11) #define CKF_USER_PIN_COUNT_LOW (1 << 16) #define CKF_USER_PIN_FINAL_TRY (1 << 17) #define CKF_USER_PIN_LOCKED (1 << 18) #define CKF_USER_PIN_TO_BE_CHANGED (1 << 19) #define CKF_SO_PIN_COUNT_LOW (1 << 20) #define CKF_SO_PIN_FINAL_TRY (1 << 21) #define CKF_SO_PIN_LOCKED (1 << 22) #define CKF_SO_PIN_TO_BE_CHANGED (1 << 23) #define CK_UNAVAILABLE_INFORMATION ((unsigned long) -1) #define CK_EFFECTIVELY_INFINITE (0) typedef unsigned long ck_session_handle_t; #define CK_INVALID_HANDLE (0) typedef unsigned long ck_user_type_t; #define CKU_SO (0) #define CKU_USER (1) #define CKU_CONTEXT_SPECIFIC (2) typedef unsigned long ck_state_t; #define CKS_RO_PUBLIC_SESSION (0) #define CKS_RO_USER_FUNCTIONS (1) #define CKS_RW_PUBLIC_SESSION (2) #define CKS_RW_USER_FUNCTIONS (3) #define CKS_RW_SO_FUNCTIONS (4) struct ck_session_info { ck_slot_id_t slot_id; ck_state_t state; ck_flags_t flags; unsigned long device_error; }; #define CKF_RW_SESSION (1 << 1) #define CKF_SERIAL_SESSION (1 << 2) typedef unsigned long ck_object_handle_t; typedef unsigned long ck_object_class_t; #define CKO_DATA (0) #define CKO_CERTIFICATE (1) #define CKO_PUBLIC_KEY (2) #define CKO_PRIVATE_KEY (3) #define CKO_SECRET_KEY (4) #define CKO_HW_FEATURE (5) #define CKO_DOMAIN_PARAMETERS (6) #define CKO_MECHANISM (7) #define CKO_VENDOR_DEFINED ((unsigned long) (1 << 31)) typedef unsigned long ck_hw_feature_type_t; #define CKH_MONOTONIC_COUNTER (1) #define CKH_CLOCK (2) #define CKH_USER_INTERFACE (3) #define CKH_VENDOR_DEFINED ((unsigned long) (1 << 31)) typedef unsigned long ck_key_type_t; #define CKK_RSA (0) #define CKK_DSA (1) #define CKK_DH (2) #define CKK_ECDSA (3) #define CKK_EC (3) #define CKK_X9_42_DH (4) #define CKK_KEA (5) #define CKK_GENERIC_SECRET (0x10) #define CKK_RC2 (0x11) #define CKK_RC4 (0x12) #define CKK_DES (0x13) #define CKK_DES2 (0x14) #define CKK_DES3 (0x15) #define CKK_CAST (0x16) #define CKK_CAST3 (0x17) #define CKK_CAST128 (0x18) #define CKK_RC5 (0x19) #define CKK_IDEA (0x1a) #define CKK_SKIPJACK (0x1b) #define CKK_BATON (0x1c) #define CKK_JUNIPER (0x1d) #define CKK_CDMF (0x1e) #define CKK_AES (0x1f) #define CKK_BLOWFISH (0x20) #define CKK_TWOFISH (0x21) #define CKK_VENDOR_DEFINED ((unsigned long) (1 << 31)) typedef unsigned long ck_certificate_type_t; #define CKC_X_509 (0) #define CKC_X_509_ATTR_CERT (1) #define CKC_WTLS (2) #define CKC_VENDOR_DEFINED ((unsigned long) (1 << 31)) typedef unsigned long ck_attribute_type_t; #define CKA_CLASS (0) #define CKA_TOKEN (1) #define CKA_PRIVATE (2) #define CKA_LABEL (3) #define CKA_APPLICATION (0x10) #define CKA_VALUE (0x11) #define CKA_OBJECT_ID (0x12) #define CKA_CERTIFICATE_TYPE (0x80) #define CKA_ISSUER (0x81) #define CKA_SERIAL_NUMBER (0x82) #define CKA_AC_ISSUER (0x83) #define CKA_OWNER (0x84) #define CKA_ATTR_TYPES (0x85) #define CKA_TRUSTED (0x86) #define CKA_CERTIFICATE_CATEGORY (0x87) #define CKA_JAVA_MIDP_SECURITY_DOMAIN (0x88) #define CKA_URL (0x89) #define CKA_HASH_OF_SUBJECT_PUBLIC_KEY (0x8a) #define CKA_HASH_OF_ISSUER_PUBLIC_KEY (0x8b) #define CKA_CHECK_VALUE (0x90) #define CKA_KEY_TYPE (0x100) #define CKA_SUBJECT (0x101) #define CKA_ID (0x102) #define CKA_SENSITIVE (0x103) #define CKA_ENCRYPT (0x104) #define CKA_DECRYPT (0x105) #define CKA_WRAP (0x106) #define CKA_UNWRAP (0x107) #define CKA_SIGN (0x108) #define CKA_SIGN_RECOVER (0x109) #define CKA_VERIFY (0x10a) #define CKA_VERIFY_RECOVER (0x10b) #define CKA_DERIVE (0x10c) #define CKA_START_DATE (0x110) #define CKA_END_DATE (0x111) #define CKA_MODULUS (0x120) #define CKA_MODULUS_BITS (0x121) #define CKA_PUBLIC_EXPONENT (0x122) #define CKA_PRIVATE_EXPONENT (0x123) #define CKA_PRIME_1 (0x124) #define CKA_PRIME_2 (0x125) #define CKA_EXPONENT_1 (0x126) #define CKA_EXPONENT_2 (0x127) #define CKA_COEFFICIENT (0x128) #define CKA_PRIME (0x130) #define CKA_SUBPRIME (0x131) #define CKA_BASE (0x132) #define CKA_PRIME_BITS (0x133) #define CKA_SUB_PRIME_BITS (0x134) #define CKA_VALUE_BITS (0x160) #define CKA_VALUE_LEN (0x161) #define CKA_EXTRACTABLE (0x162) #define CKA_LOCAL (0x163) #define CKA_NEVER_EXTRACTABLE (0x164) #define CKA_ALWAYS_SENSITIVE (0x165) #define CKA_KEY_GEN_MECHANISM (0x166) #define CKA_MODIFIABLE (0x170) #define CKA_ECDSA_PARAMS (0x180) #define CKA_EC_PARAMS (0x180) #define CKA_EC_POINT (0x181) #define CKA_SECONDARY_AUTH (0x200) #define CKA_AUTH_PIN_FLAGS (0x201) #define CKA_ALWAYS_AUTHENTICATE (0x202) #define CKA_WRAP_WITH_TRUSTED (0x210) #define CKA_HW_FEATURE_TYPE (0x300) #define CKA_RESET_ON_INIT (0x301) #define CKA_HAS_RESET (0x302) #define CKA_PIXEL_X (0x400) #define CKA_PIXEL_Y (0x401) #define CKA_RESOLUTION (0x402) #define CKA_CHAR_ROWS (0x403) #define CKA_CHAR_COLUMNS (0x404) #define CKA_COLOR (0x405) #define CKA_BITS_PER_PIXEL (0x406) #define CKA_CHAR_SETS (0x480) #define CKA_ENCODING_METHODS (0x481) #define CKA_MIME_TYPES (0x482) #define CKA_MECHANISM_TYPE (0x500) #define CKA_REQUIRED_CMS_ATTRIBUTES (0x501) #define CKA_DEFAULT_CMS_ATTRIBUTES (0x502) #define CKA_SUPPORTED_CMS_ATTRIBUTES (0x503) #define CKA_WRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE | 0x211) #define CKA_UNWRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE | 0x212) #define CKA_ALLOWED_MECHANISMS (CKF_ARRAY_ATTRIBUTE | 0x600) #define CKA_VENDOR_DEFINED ((unsigned long) (1 << 31)) struct ck_attribute { ck_attribute_type_t type; void *value; unsigned long value_len; }; struct ck_date { unsigned char year[4]; unsigned char month[2]; unsigned char day[2]; }; typedef unsigned long ck_mechanism_type_t; #define CKM_RSA_PKCS_KEY_PAIR_GEN (0) #define CKM_RSA_PKCS (1) #define CKM_RSA_9796 (2) #define CKM_RSA_X_509 (3) #define CKM_MD2_RSA_PKCS (4) #define CKM_MD5_RSA_PKCS (5) #define CKM_SHA1_RSA_PKCS (6) #define CKM_RIPEMD128_RSA_PKCS (7) #define CKM_RIPEMD160_RSA_PKCS (8) #define CKM_RSA_PKCS_OAEP (9) #define CKM_RSA_X9_31_KEY_PAIR_GEN (0xa) #define CKM_RSA_X9_31 (0xb) #define CKM_SHA1_RSA_X9_31 (0xc) #define CKM_RSA_PKCS_PSS (0xd) #define CKM_SHA1_RSA_PKCS_PSS (0xe) #define CKM_DSA_KEY_PAIR_GEN (0x10) #define CKM_DSA (0x11) #define CKM_DSA_SHA1 (0x12) #define CKM_DH_PKCS_KEY_PAIR_GEN (0x20) #define CKM_DH_PKCS_DERIVE (0x21) #define CKM_X9_42_DH_KEY_PAIR_GEN (0x30) #define CKM_X9_42_DH_DERIVE (0x31) #define CKM_X9_42_DH_HYBRID_DERIVE (0x32) #define CKM_X9_42_MQV_DERIVE (0x33) #define CKM_SHA256_RSA_PKCS (0x40) #define CKM_SHA384_RSA_PKCS (0x41) #define CKM_SHA512_RSA_PKCS (0x42) #define CKM_SHA256_RSA_PKCS_PSS (0x43) #define CKM_SHA384_RSA_PKCS_PSS (0x44) #define CKM_SHA512_RSA_PKCS_PSS (0x45) #define CKM_RC2_KEY_GEN (0x100) #define CKM_RC2_ECB (0x101) #define CKM_RC2_CBC (0x102) #define CKM_RC2_MAC (0x103) #define CKM_RC2_MAC_GENERAL (0x104) #define CKM_RC2_CBC_PAD (0x105) #define CKM_RC4_KEY_GEN (0x110) #define CKM_RC4 (0x111) #define CKM_DES_KEY_GEN (0x120) #define CKM_DES_ECB (0x121) #define CKM_DES_CBC (0x122) #define CKM_DES_MAC (0x123) #define CKM_DES_MAC_GENERAL (0x124) #define CKM_DES_CBC_PAD (0x125) #define CKM_DES2_KEY_GEN (0x130) #define CKM_DES3_KEY_GEN (0x131) #define CKM_DES3_ECB (0x132) #define CKM_DES3_CBC (0x133) #define CKM_DES3_MAC (0x134) #define CKM_DES3_MAC_GENERAL (0x135) #define CKM_DES3_CBC_PAD (0x136) #define CKM_CDMF_KEY_GEN (0x140) #define CKM_CDMF_ECB (0x141) #define CKM_CDMF_CBC (0x142) #define CKM_CDMF_MAC (0x143) #define CKM_CDMF_MAC_GENERAL (0x144) #define CKM_CDMF_CBC_PAD (0x145) #define CKM_MD2 (0x200) #define CKM_MD2_HMAC (0x201) #define CKM_MD2_HMAC_GENERAL (0x202) #define CKM_MD5 (0x210) #define CKM_MD5_HMAC (0x211) #define CKM_MD5_HMAC_GENERAL (0x212) #define CKM_SHA_1 (0x220) #define CKM_SHA_1_HMAC (0x221) #define CKM_SHA_1_HMAC_GENERAL (0x222) #define CKM_RIPEMD128 (0x230) #define CKM_RIPEMD128_HMAC (0x231) #define CKM_RIPEMD128_HMAC_GENERAL (0x232) #define CKM_RIPEMD160 (0x240) #define CKM_RIPEMD160_HMAC (0x241) #define CKM_RIPEMD160_HMAC_GENERAL (0x242) #define CKM_SHA256 (0x250) #define CKM_SHA256_HMAC (0x251) #define CKM_SHA256_HMAC_GENERAL (0x252) #define CKM_SHA384 (0x260) #define CKM_SHA384_HMAC (0x261) #define CKM_SHA384_HMAC_GENERAL (0x262) #define CKM_SHA512 (0x270) #define CKM_SHA512_HMAC (0x271) #define CKM_SHA512_HMAC_GENERAL (0x272) #define CKM_CAST_KEY_GEN (0x300) #define CKM_CAST_ECB (0x301) #define CKM_CAST_CBC (0x302) #define CKM_CAST_MAC (0x303) #define CKM_CAST_MAC_GENERAL (0x304) #define CKM_CAST_CBC_PAD (0x305) #define CKM_CAST3_KEY_GEN (0x310) #define CKM_CAST3_ECB (0x311) #define CKM_CAST3_CBC (0x312) #define CKM_CAST3_MAC (0x313) #define CKM_CAST3_MAC_GENERAL (0x314) #define CKM_CAST3_CBC_PAD (0x315) #define CKM_CAST5_KEY_GEN (0x320) #define CKM_CAST128_KEY_GEN (0x320) #define CKM_CAST5_ECB (0x321) #define CKM_CAST128_ECB (0x321) #define CKM_CAST5_CBC (0x322) #define CKM_CAST128_CBC (0x322) #define CKM_CAST5_MAC (0x323) #define CKM_CAST128_MAC (0x323) #define CKM_CAST5_MAC_GENERAL (0x324) #define CKM_CAST128_MAC_GENERAL (0x324) #define CKM_CAST5_CBC_PAD (0x325) #define CKM_CAST128_CBC_PAD (0x325) #define CKM_RC5_KEY_GEN (0x330) #define CKM_RC5_ECB (0x331) #define CKM_RC5_CBC (0x332) #define CKM_RC5_MAC (0x333) #define CKM_RC5_MAC_GENERAL (0x334) #define CKM_RC5_CBC_PAD (0x335) #define CKM_IDEA_KEY_GEN (0x340) #define CKM_IDEA_ECB (0x341) #define CKM_IDEA_CBC (0x342) #define CKM_IDEA_MAC (0x343) #define CKM_IDEA_MAC_GENERAL (0x344) #define CKM_IDEA_CBC_PAD (0x345) #define CKM_GENERIC_SECRET_KEY_GEN (0x350) #define CKM_CONCATENATE_BASE_AND_KEY (0x360) #define CKM_CONCATENATE_BASE_AND_DATA (0x362) #define CKM_CONCATENATE_DATA_AND_BASE (0x363) #define CKM_XOR_BASE_AND_DATA (0x364) #define CKM_EXTRACT_KEY_FROM_KEY (0x365) #define CKM_SSL3_PRE_MASTER_KEY_GEN (0x370) #define CKM_SSL3_MASTER_KEY_DERIVE (0x371) #define CKM_SSL3_KEY_AND_MAC_DERIVE (0x372) #define CKM_SSL3_MASTER_KEY_DERIVE_DH (0x373) #define CKM_TLS_PRE_MASTER_KEY_GEN (0x374) #define CKM_TLS_MASTER_KEY_DERIVE (0x375) #define CKM_TLS_KEY_AND_MAC_DERIVE (0x376) #define CKM_TLS_MASTER_KEY_DERIVE_DH (0x377) #define CKM_SSL3_MD5_MAC (0x380) #define CKM_SSL3_SHA1_MAC (0x381) #define CKM_MD5_KEY_DERIVATION (0x390) #define CKM_MD2_KEY_DERIVATION (0x391) #define CKM_SHA1_KEY_DERIVATION (0x392) #define CKM_PBE_MD2_DES_CBC (0x3a0) #define CKM_PBE_MD5_DES_CBC (0x3a1) #define CKM_PBE_MD5_CAST_CBC (0x3a2) #define CKM_PBE_MD5_CAST3_CBC (0x3a3) #define CKM_PBE_MD5_CAST5_CBC (0x3a4) #define CKM_PBE_MD5_CAST128_CBC (0x3a4) #define CKM_PBE_SHA1_CAST5_CBC (0x3a5) #define CKM_PBE_SHA1_CAST128_CBC (0x3a5) #define CKM_PBE_SHA1_RC4_128 (0x3a6) #define CKM_PBE_SHA1_RC4_40 (0x3a7) #define CKM_PBE_SHA1_DES3_EDE_CBC (0x3a8) #define CKM_PBE_SHA1_DES2_EDE_CBC (0x3a9) #define CKM_PBE_SHA1_RC2_128_CBC (0x3aa) #define CKM_PBE_SHA1_RC2_40_CBC (0x3ab) #define CKM_PKCS5_PBKD2 (0x3b0) #define CKM_PBA_SHA1_WITH_SHA1_HMAC (0x3c0) #define CKM_KEY_WRAP_LYNKS (0x400) #define CKM_KEY_WRAP_SET_OAEP (0x401) #define CKM_SKIPJACK_KEY_GEN (0x1000) #define CKM_SKIPJACK_ECB64 (0x1001) #define CKM_SKIPJACK_CBC64 (0x1002) #define CKM_SKIPJACK_OFB64 (0x1003) #define CKM_SKIPJACK_CFB64 (0x1004) #define CKM_SKIPJACK_CFB32 (0x1005) #define CKM_SKIPJACK_CFB16 (0x1006) #define CKM_SKIPJACK_CFB8 (0x1007) #define CKM_SKIPJACK_WRAP (0x1008) #define CKM_SKIPJACK_PRIVATE_WRAP (0x1009) #define CKM_SKIPJACK_RELAYX (0x100a) #define CKM_KEA_KEY_PAIR_GEN (0x1010) #define CKM_KEA_KEY_DERIVE (0x1011) #define CKM_FORTEZZA_TIMESTAMP (0x1020) #define CKM_BATON_KEY_GEN (0x1030) #define CKM_BATON_ECB128 (0x1031) #define CKM_BATON_ECB96 (0x1032) #define CKM_BATON_CBC128 (0x1033) #define CKM_BATON_COUNTER (0x1034) #define CKM_BATON_SHUFFLE (0x1035) #define CKM_BATON_WRAP (0x1036) #define CKM_ECDSA_KEY_PAIR_GEN (0x1040) #define CKM_EC_KEY_PAIR_GEN (0x1040) #define CKM_ECDSA (0x1041) #define CKM_ECDSA_SHA1 (0x1042) #define CKM_ECDH1_DERIVE (0x1050) #define CKM_ECDH1_COFACTOR_DERIVE (0x1051) #define CKM_ECMQV_DERIVE (0x1052) #define CKM_JUNIPER_KEY_GEN (0x1060) #define CKM_JUNIPER_ECB128 (0x1061) #define CKM_JUNIPER_CBC128 (0x1062) #define CKM_JUNIPER_COUNTER (0x1063) #define CKM_JUNIPER_SHUFFLE (0x1064) #define CKM_JUNIPER_WRAP (0x1065) #define CKM_FASTHASH (0x1070) #define CKM_AES_KEY_GEN (0x1080) #define CKM_AES_ECB (0x1081) #define CKM_AES_CBC (0x1082) #define CKM_AES_MAC (0x1083) #define CKM_AES_MAC_GENERAL (0x1084) #define CKM_AES_CBC_PAD (0x1085) #define CKM_DSA_PARAMETER_GEN (0x2000) #define CKM_DH_PKCS_PARAMETER_GEN (0x2001) #define CKM_X9_42_DH_PARAMETER_GEN (0x2002) #define CKM_VENDOR_DEFINED ((unsigned long) (1 << 31)) struct ck_mechanism { ck_mechanism_type_t mechanism; void *parameter; unsigned long parameter_len; }; struct ck_mechanism_info { unsigned long min_key_size; unsigned long max_key_size; ck_flags_t flags; }; #define CKF_HW (1 << 0) #define CKF_ENCRYPT (1 << 8) #define CKF_DECRYPT (1 << 9) #define CKF_DIGEST (1 << 10) #define CKF_SIGN (1 << 11) #define CKF_SIGN_RECOVER (1 << 12) #define CKF_VERIFY (1 << 13) #define CKF_VERIFY_RECOVER (1 << 14) #define CKF_GENERATE (1 << 15) #define CKF_GENERATE_KEY_PAIR (1 << 16) #define CKF_WRAP (1 << 17) #define CKF_UNWRAP (1 << 18) #define CKF_DERIVE (1 << 19) #define CKF_EXTENSION ((unsigned long) (1 << 31)) /* Flags for C_WaitForSlotEvent. */ #define CKF_DONT_BLOCK (1) typedef unsigned long ck_rv_t; typedef ck_rv_t (*ck_notify_t) (ck_session_handle_t session, ck_notification_t event, void *application); /* Forward reference. */ struct ck_function_list; #define _CK_DECLARE_FUNCTION(name, args) \ typedef ck_rv_t (*CK_ ## name) args; \ ck_rv_t CK_SPEC name args _CK_DECLARE_FUNCTION (C_Initialize, (void *init_args)); _CK_DECLARE_FUNCTION (C_Finalize, (void *reserved)); _CK_DECLARE_FUNCTION (C_GetInfo, (struct ck_info *info)); _CK_DECLARE_FUNCTION (C_GetFunctionList, (struct ck_function_list **function_list)); _CK_DECLARE_FUNCTION (C_GetSlotList, (unsigned char token_present, ck_slot_id_t *slot_list, unsigned long *count)); _CK_DECLARE_FUNCTION (C_GetSlotInfo, (ck_slot_id_t slot_id, struct ck_slot_info *info)); _CK_DECLARE_FUNCTION (C_GetTokenInfo, (ck_slot_id_t slot_id, struct ck_token_info *info)); _CK_DECLARE_FUNCTION (C_WaitForSlotEvent, (ck_flags_t flags, ck_slot_id_t *slot, void *reserved)); _CK_DECLARE_FUNCTION (C_GetMechanismList, (ck_slot_id_t slot_id, ck_mechanism_type_t *mechanism_list, unsigned long *count)); _CK_DECLARE_FUNCTION (C_GetMechanismInfo, (ck_slot_id_t slot_id, ck_mechanism_type_t type, struct ck_mechanism_info *info)); _CK_DECLARE_FUNCTION (C_InitToken, (ck_slot_id_t slot_id, unsigned char *pin, unsigned long pin_len, unsigned char *label)); _CK_DECLARE_FUNCTION (C_InitPIN, (ck_session_handle_t session, unsigned char *pin, unsigned long pin_len)); _CK_DECLARE_FUNCTION (C_SetPIN, (ck_session_handle_t session, unsigned char *old_pin, unsigned long old_len, unsigned char *new_pin, unsigned long new_len)); _CK_DECLARE_FUNCTION (C_OpenSession, (ck_slot_id_t slot_id, ck_flags_t flags, void *application, ck_notify_t notify, ck_session_handle_t *session)); _CK_DECLARE_FUNCTION (C_CloseSession, (ck_session_handle_t session)); _CK_DECLARE_FUNCTION (C_CloseAllSessions, (ck_slot_id_t slot_id)); _CK_DECLARE_FUNCTION (C_GetSessionInfo, (ck_session_handle_t session, struct ck_session_info *info)); _CK_DECLARE_FUNCTION (C_GetOperationState, (ck_session_handle_t session, unsigned char *operation_state, unsigned long *operation_state_len)); _CK_DECLARE_FUNCTION (C_SetOperationState, (ck_session_handle_t session, unsigned char *operation_state, unsigned long operation_state_len, ck_object_handle_t encryption_key, ck_object_handle_t authentiation_key)); _CK_DECLARE_FUNCTION (C_Login, (ck_session_handle_t session, ck_user_type_t user_type, unsigned char *pin, unsigned long pin_len)); _CK_DECLARE_FUNCTION (C_Logout, (ck_session_handle_t session)); _CK_DECLARE_FUNCTION (C_CreateObject, (ck_session_handle_t session, struct ck_attribute *templ, unsigned long count, ck_object_handle_t *object)); _CK_DECLARE_FUNCTION (C_CopyObject, (ck_session_handle_t session, ck_object_handle_t object, struct ck_attribute *templ, unsigned long count, ck_object_handle_t *new_object)); _CK_DECLARE_FUNCTION (C_DestroyObject, (ck_session_handle_t session, ck_object_handle_t object)); _CK_DECLARE_FUNCTION (C_GetObjectSize, (ck_session_handle_t session, ck_object_handle_t object, unsigned long *size)); _CK_DECLARE_FUNCTION (C_GetAttributeValue, (ck_session_handle_t session, ck_object_handle_t object, struct ck_attribute *templ, unsigned long count)); _CK_DECLARE_FUNCTION (C_SetAttributeValue, (ck_session_handle_t session, ck_object_handle_t object, struct ck_attribute *templ, unsigned long count)); _CK_DECLARE_FUNCTION (C_FindObjectsInit, (ck_session_handle_t session, struct ck_attribute *templ, unsigned long count)); _CK_DECLARE_FUNCTION (C_FindObjects, (ck_session_handle_t session, ck_object_handle_t *object, unsigned long max_object_count, unsigned long *object_count)); _CK_DECLARE_FUNCTION (C_FindObjectsFinal, (ck_session_handle_t session)); _CK_DECLARE_FUNCTION (C_EncryptInit, (ck_session_handle_t session, struct ck_mechanism *mechanism, ck_object_handle_t key)); _CK_DECLARE_FUNCTION (C_Encrypt, (ck_session_handle_t session, unsigned char *data, unsigned long data_len, unsigned char *encrypted_data, unsigned long *encrypted_data_len)); _CK_DECLARE_FUNCTION (C_EncryptUpdate, (ck_session_handle_t session, unsigned char *part, unsigned long part_len, unsigned char *encrypted_part, unsigned long *encrypted_part_len)); _CK_DECLARE_FUNCTION (C_EncryptFinal, (ck_session_handle_t session, unsigned char *last_encrypted_part, unsigned long *last_encrypted_part_len)); _CK_DECLARE_FUNCTION (C_DecryptInit, (ck_session_handle_t session, struct ck_mechanism *mechanism, ck_object_handle_t key)); _CK_DECLARE_FUNCTION (C_Decrypt, (ck_session_handle_t session, unsigned char *encrypted_data, unsigned long encrypted_data_len, unsigned char *data, unsigned long *data_len)); _CK_DECLARE_FUNCTION (C_DecryptUpdate, (ck_session_handle_t session, unsigned char *encrypted_part, unsigned long encrypted_part_len, unsigned char *part, unsigned long *part_len)); _CK_DECLARE_FUNCTION (C_DecryptFinal, (ck_session_handle_t session, unsigned char *last_part, unsigned long *last_part_len)); _CK_DECLARE_FUNCTION (C_DigestInit, (ck_session_handle_t session, struct ck_mechanism *mechanism)); _CK_DECLARE_FUNCTION (C_Digest, (ck_session_handle_t session, unsigned char *data, unsigned long data_len, unsigned char *digest, unsigned long *digest_len)); _CK_DECLARE_FUNCTION (C_DigestUpdate, (ck_session_handle_t session, unsigned char *part, unsigned long part_len)); _CK_DECLARE_FUNCTION (C_DigestKey, (ck_session_handle_t session, ck_object_handle_t key)); _CK_DECLARE_FUNCTION (C_DigestFinal, (ck_session_handle_t session, unsigned char *digest, unsigned long *digest_len)); _CK_DECLARE_FUNCTION (C_SignInit, (ck_session_handle_t session, struct ck_mechanism *mechanism, ck_object_handle_t key)); _CK_DECLARE_FUNCTION (C_Sign, (ck_session_handle_t session, unsigned char *data, unsigned long data_len, unsigned char *signature, unsigned long *signature_len)); _CK_DECLARE_FUNCTION (C_SignUpdate, (ck_session_handle_t session, unsigned char *part, unsigned long part_len)); _CK_DECLARE_FUNCTION (C_SignFinal, (ck_session_handle_t session, unsigned char *signature, unsigned long *signature_len)); _CK_DECLARE_FUNCTION (C_SignRecoverInit, (ck_session_handle_t session, struct ck_mechanism *mechanism, ck_object_handle_t key)); _CK_DECLARE_FUNCTION (C_SignRecover, (ck_session_handle_t session, unsigned char *data, unsigned long data_len, unsigned char *signature, unsigned long *signature_len)); _CK_DECLARE_FUNCTION (C_VerifyInit, (ck_session_handle_t session, struct ck_mechanism *mechanism, ck_object_handle_t key)); _CK_DECLARE_FUNCTION (C_Verify, (ck_session_handle_t session, unsigned char *data, unsigned long data_len, unsigned char *signature, unsigned long signature_len)); _CK_DECLARE_FUNCTION (C_VerifyUpdate, (ck_session_handle_t session, unsigned char *part, unsigned long part_len)); _CK_DECLARE_FUNCTION (C_VerifyFinal, (ck_session_handle_t session, unsigned char *signature, unsigned long signature_len)); _CK_DECLARE_FUNCTION (C_VerifyRecoverInit, (ck_session_handle_t session, struct ck_mechanism *mechanism, ck_object_handle_t key)); _CK_DECLARE_FUNCTION (C_VerifyRecover, (ck_session_handle_t session, unsigned char *signature, unsigned long signature_len, unsigned char *data, unsigned long *data_len)); _CK_DECLARE_FUNCTION (C_DigestEncryptUpdate, (ck_session_handle_t session, unsigned char *part, unsigned long part_len, unsigned char *encrypted_part, unsigned long *encrypted_part_len)); _CK_DECLARE_FUNCTION (C_DecryptDigestUpdate, (ck_session_handle_t session, unsigned char *encrypted_part, unsigned long encrypted_part_len, unsigned char *part, unsigned long *part_len)); _CK_DECLARE_FUNCTION (C_SignEncryptUpdate, (ck_session_handle_t session, unsigned char *part, unsigned long part_len, unsigned char *encrypted_part, unsigned long *encrypted_part_len)); _CK_DECLARE_FUNCTION (C_DecryptVerifyUpdate, (ck_session_handle_t session, unsigned char *encrypted_part, unsigned long encrypted_part_len, unsigned char *part, unsigned long *part_len)); _CK_DECLARE_FUNCTION (C_GenerateKey, (ck_session_handle_t session, struct ck_mechanism *mechanism, struct ck_attribute *templ, unsigned long count, ck_object_handle_t *key)); _CK_DECLARE_FUNCTION (C_GenerateKeyPair, (ck_session_handle_t session, struct ck_mechanism *mechanism, struct ck_attribute *public_key_template, unsigned long public_key_attribute_count, struct ck_attribute *private_key_template, unsigned long private_key_attribute_count, ck_object_handle_t *public_key, ck_object_handle_t *private_key)); _CK_DECLARE_FUNCTION (C_WrapKey, (ck_session_handle_t session, struct ck_mechanism *mechanism, ck_object_handle_t wrapping_key, ck_object_handle_t key, unsigned char *wrapped_key, unsigned long *wrapped_key_len)); _CK_DECLARE_FUNCTION (C_UnwrapKey, (ck_session_handle_t session, struct ck_mechanism *mechanism, ck_object_handle_t unwrapping_key, unsigned char *wrapped_key, unsigned long wrapped_key_len, struct ck_attribute *templ, unsigned long attribute_count, ck_object_handle_t *key)); _CK_DECLARE_FUNCTION (C_DeriveKey, (ck_session_handle_t session, struct ck_mechanism *mechanism, ck_object_handle_t base_key, struct ck_attribute *templ, unsigned long attribute_count, ck_object_handle_t *key)); _CK_DECLARE_FUNCTION (C_SeedRandom, (ck_session_handle_t session, unsigned char *seed, unsigned long seed_len)); _CK_DECLARE_FUNCTION (C_GenerateRandom, (ck_session_handle_t session, unsigned char *random_data, unsigned long random_len)); _CK_DECLARE_FUNCTION (C_GetFunctionStatus, (ck_session_handle_t session)); _CK_DECLARE_FUNCTION (C_CancelFunction, (ck_session_handle_t session)); struct ck_function_list { struct ck_version version; CK_C_Initialize C_Initialize; CK_C_Finalize C_Finalize; CK_C_GetInfo C_GetInfo; CK_C_GetFunctionList C_GetFunctionList; CK_C_GetSlotList C_GetSlotList; CK_C_GetSlotInfo C_GetSlotInfo; CK_C_GetTokenInfo C_GetTokenInfo; CK_C_GetMechanismList C_GetMechanismList; CK_C_GetMechanismInfo C_GetMechanismInfo; CK_C_InitToken C_InitToken; CK_C_InitPIN C_InitPIN; CK_C_SetPIN C_SetPIN; CK_C_OpenSession C_OpenSession; CK_C_CloseSession C_CloseSession; CK_C_CloseAllSessions C_CloseAllSessions; CK_C_GetSessionInfo C_GetSessionInfo; CK_C_GetOperationState C_GetOperationState; CK_C_SetOperationState C_SetOperationState; CK_C_Login C_Login; CK_C_Logout C_Logout; CK_C_CreateObject C_CreateObject; CK_C_CopyObject C_CopyObject; CK_C_DestroyObject C_DestroyObject; CK_C_GetObjectSize C_GetObjectSize; CK_C_GetAttributeValue C_GetAttributeValue; CK_C_SetAttributeValue C_SetAttributeValue; CK_C_FindObjectsInit C_FindObjectsInit; CK_C_FindObjects C_FindObjects; CK_C_FindObjectsFinal C_FindObjectsFinal; CK_C_EncryptInit C_EncryptInit; CK_C_Encrypt C_Encrypt; CK_C_EncryptUpdate C_EncryptUpdate; CK_C_EncryptFinal C_EncryptFinal; CK_C_DecryptInit C_DecryptInit; CK_C_Decrypt C_Decrypt; CK_C_DecryptUpdate C_DecryptUpdate; CK_C_DecryptFinal C_DecryptFinal; CK_C_DigestInit C_DigestInit; CK_C_Digest C_Digest; CK_C_DigestUpdate C_DigestUpdate; CK_C_DigestKey C_DigestKey; CK_C_DigestFinal C_DigestFinal; CK_C_SignInit C_SignInit; CK_C_Sign C_Sign; CK_C_SignUpdate C_SignUpdate; CK_C_SignFinal C_SignFinal; CK_C_SignRecoverInit C_SignRecoverInit; CK_C_SignRecover C_SignRecover; CK_C_VerifyInit C_VerifyInit; CK_C_Verify C_Verify; CK_C_VerifyUpdate C_VerifyUpdate; CK_C_VerifyFinal C_VerifyFinal; CK_C_VerifyRecoverInit C_VerifyRecoverInit; CK_C_VerifyRecover C_VerifyRecover; CK_C_DigestEncryptUpdate C_DigestEncryptUpdate; CK_C_DecryptDigestUpdate C_DecryptDigestUpdate; CK_C_SignEncryptUpdate C_SignEncryptUpdate; CK_C_DecryptVerifyUpdate C_DecryptVerifyUpdate; CK_C_GenerateKey C_GenerateKey; CK_C_GenerateKeyPair C_GenerateKeyPair; CK_C_WrapKey C_WrapKey; CK_C_UnwrapKey C_UnwrapKey; CK_C_DeriveKey C_DeriveKey; CK_C_SeedRandom C_SeedRandom; CK_C_GenerateRandom C_GenerateRandom; CK_C_GetFunctionStatus C_GetFunctionStatus; CK_C_CancelFunction C_CancelFunction; CK_C_WaitForSlotEvent C_WaitForSlotEvent; }; typedef ck_rv_t (*ck_createmutex_t) (void **mutex); typedef ck_rv_t (*ck_destroymutex_t) (void *mutex); typedef ck_rv_t (*ck_lockmutex_t) (void *mutex); typedef ck_rv_t (*ck_unlockmutex_t) (void *mutex); struct ck_c_initialize_args { ck_createmutex_t create_mutex; ck_destroymutex_t destroy_mutex; ck_lockmutex_t lock_mutex; ck_unlockmutex_t unlock_mutex; ck_flags_t flags; void *reserved; }; #define CKF_LIBRARY_CANT_CREATE_OS_THREADS (1 << 0) #define CKF_OS_LOCKING_OK (1 << 1) #define CKR_OK (0) #define CKR_CANCEL (1) #define CKR_HOST_MEMORY (2) #define CKR_SLOT_ID_INVALID (3) #define CKR_GENERAL_ERROR (5) #define CKR_FUNCTION_FAILED (6) #define CKR_ARGUMENTS_BAD (7) #define CKR_NO_EVENT (8) #define CKR_NEED_TO_CREATE_THREADS (9) #define CKR_CANT_LOCK (0xa) #define CKR_ATTRIBUTE_READ_ONLY (0x10) #define CKR_ATTRIBUTE_SENSITIVE (0x11) #define CKR_ATTRIBUTE_TYPE_INVALID (0x12) #define CKR_ATTRIBUTE_VALUE_INVALID (0x13) #define CKR_DATA_INVALID (0x20) #define CKR_DATA_LEN_RANGE (0x21) #define CKR_DEVICE_ERROR (0x30) #define CKR_DEVICE_MEMORY (0x31) #define CKR_DEVICE_REMOVED (0x32) #define CKR_ENCRYPTED_DATA_INVALID (0x40) #define CKR_ENCRYPTED_DATA_LEN_RANGE (0x41) #define CKR_FUNCTION_CANCELED (0x50) #define CKR_FUNCTION_NOT_PARALLEL (0x51) #define CKR_FUNCTION_NOT_SUPPORTED (0x54) #define CKR_KEY_HANDLE_INVALID (0x60) #define CKR_KEY_SIZE_RANGE (0x62) #define CKR_KEY_TYPE_INCONSISTENT (0x63) #define CKR_KEY_NOT_NEEDED (0x64) #define CKR_KEY_CHANGED (0x65) #define CKR_KEY_NEEDED (0x66) #define CKR_KEY_INDIGESTIBLE (0x67) #define CKR_KEY_FUNCTION_NOT_PERMITTED (0x68) #define CKR_KEY_NOT_WRAPPABLE (0x69) #define CKR_KEY_UNEXTRACTABLE (0x6a) #define CKR_MECHANISM_INVALID (0x70) #define CKR_MECHANISM_PARAM_INVALID (0x71) #define CKR_OBJECT_HANDLE_INVALID (0x82) #define CKR_OPERATION_ACTIVE (0x90) #define CKR_OPERATION_NOT_INITIALIZED (0x91) #define CKR_PIN_INCORRECT (0xa0) #define CKR_PIN_INVALID (0xa1) #define CKR_PIN_LEN_RANGE (0xa2) #define CKR_PIN_EXPIRED (0xa3) #define CKR_PIN_LOCKED (0xa4) #define CKR_SESSION_CLOSED (0xb0) #define CKR_SESSION_COUNT (0xb1) #define CKR_SESSION_HANDLE_INVALID (0xb3) #define CKR_SESSION_PARALLEL_NOT_SUPPORTED (0xb4) #define CKR_SESSION_READ_ONLY (0xb5) #define CKR_SESSION_EXISTS (0xb6) #define CKR_SESSION_READ_ONLY_EXISTS (0xb7) #define CKR_SESSION_READ_WRITE_SO_EXISTS (0xb8) #define CKR_SIGNATURE_INVALID (0xc0) #define CKR_SIGNATURE_LEN_RANGE (0xc1) #define CKR_TEMPLATE_INCOMPLETE (0xd0) #define CKR_TEMPLATE_INCONSISTENT (0xd1) #define CKR_TOKEN_NOT_PRESENT (0xe0) #define CKR_TOKEN_NOT_RECOGNIZED (0xe1) #define CKR_TOKEN_WRITE_PROTECTED (0xe2) #define CKR_UNWRAPPING_KEY_HANDLE_INVALID (0xf0) #define CKR_UNWRAPPING_KEY_SIZE_RANGE (0xf1) #define CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT (0xf2) #define CKR_USER_ALREADY_LOGGED_IN (0x100) #define CKR_USER_NOT_LOGGED_IN (0x101) #define CKR_USER_PIN_NOT_INITIALIZED (0x102) #define CKR_USER_TYPE_INVALID (0x103) #define CKR_USER_ANOTHER_ALREADY_LOGGED_IN (0x104) #define CKR_USER_TOO_MANY_TYPES (0x105) #define CKR_WRAPPED_KEY_INVALID (0x110) #define CKR_WRAPPED_KEY_LEN_RANGE (0x112) #define CKR_WRAPPING_KEY_HANDLE_INVALID (0x113) #define CKR_WRAPPING_KEY_SIZE_RANGE (0x114) #define CKR_WRAPPING_KEY_TYPE_INCONSISTENT (0x115) #define CKR_RANDOM_SEED_NOT_SUPPORTED (0x120) #define CKR_RANDOM_NO_RNG (0x121) #define CKR_DOMAIN_PARAMS_INVALID (0x130) #define CKR_BUFFER_TOO_SMALL (0x150) #define CKR_SAVED_STATE_INVALID (0x160) #define CKR_INFORMATION_SENSITIVE (0x170) #define CKR_STATE_UNSAVEABLE (0x180) #define CKR_CRYPTOKI_NOT_INITIALIZED (0x190) #define CKR_CRYPTOKI_ALREADY_INITIALIZED (0x191) #define CKR_MUTEX_BAD (0x1a0) #define CKR_MUTEX_NOT_LOCKED (0x1a1) #define CKR_FUNCTION_REJECTED (0x200) #define CKR_VENDOR_DEFINED ((unsigned long) (1 << 31)) /* Compatibility layer. */ #ifdef CRYPTOKI_COMPAT #undef CK_DEFINE_FUNCTION #define CK_DEFINE_FUNCTION(retval, name) retval CK_SPEC name /* For NULL. */ #include <stddef.h> typedef unsigned char CK_BYTE; typedef unsigned char CK_CHAR; typedef unsigned char CK_UTF8CHAR; typedef unsigned char CK_BBOOL; typedef unsigned long int CK_ULONG; typedef long int CK_LONG; typedef CK_BYTE *CK_BYTE_PTR; typedef CK_CHAR *CK_CHAR_PTR; typedef CK_UTF8CHAR *CK_UTF8CHAR_PTR; typedef CK_ULONG *CK_ULONG_PTR; typedef void *CK_VOID_PTR; typedef void **CK_VOID_PTR_PTR; #define CK_FALSE 0 #define CK_TRUE 1 #ifndef CK_DISABLE_TRUE_FALSE #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE 1 #endif #endif typedef struct ck_version CK_VERSION; typedef struct ck_version *CK_VERSION_PTR; typedef struct ck_info CK_INFO; typedef struct ck_info *CK_INFO_PTR; typedef ck_slot_id_t *CK_SLOT_ID_PTR; typedef struct ck_slot_info CK_SLOT_INFO; typedef struct ck_slot_info *CK_SLOT_INFO_PTR; typedef struct ck_token_info CK_TOKEN_INFO; typedef struct ck_token_info *CK_TOKEN_INFO_PTR; typedef ck_session_handle_t *CK_SESSION_HANDLE_PTR; typedef struct ck_session_info CK_SESSION_INFO; typedef struct ck_session_info *CK_SESSION_INFO_PTR; typedef ck_object_handle_t *CK_OBJECT_HANDLE_PTR; typedef ck_object_class_t *CK_OBJECT_CLASS_PTR; typedef struct ck_attribute CK_ATTRIBUTE; typedef struct ck_attribute *CK_ATTRIBUTE_PTR; typedef struct ck_date CK_DATE; typedef struct ck_date *CK_DATE_PTR; typedef ck_mechanism_type_t *CK_MECHANISM_TYPE_PTR; typedef struct ck_mechanism CK_MECHANISM; typedef struct ck_mechanism *CK_MECHANISM_PTR; typedef struct ck_mechanism_info CK_MECHANISM_INFO; typedef struct ck_mechanism_info *CK_MECHANISM_INFO_PTR; typedef struct ck_function_list CK_FUNCTION_LIST; typedef struct ck_function_list *CK_FUNCTION_LIST_PTR; typedef struct ck_function_list **CK_FUNCTION_LIST_PTR_PTR; typedef struct ck_c_initialize_args CK_C_INITIALIZE_ARGS; typedef struct ck_c_initialize_args *CK_C_INITIALIZE_ARGS_PTR; #define NULL_PTR NULL /* Delete the helper macros defined at the top of the file. */ #undef ck_flags_t #undef ck_version #undef ck_info #undef cryptoki_version #undef manufacturer_id #undef library_description #undef library_version #undef ck_notification_t #undef ck_slot_id_t #undef ck_slot_info #undef slot_description #undef hardware_version #undef firmware_version #undef ck_token_info #undef serial_number #undef max_session_count #undef session_count #undef max_rw_session_count #undef rw_session_count #undef max_pin_len #undef min_pin_len #undef total_public_memory #undef free_public_memory #undef total_private_memory #undef free_private_memory #undef utc_time #undef ck_session_handle_t #undef ck_user_type_t #undef ck_state_t #undef ck_session_info #undef slot_id #undef device_error #undef ck_object_handle_t #undef ck_object_class_t #undef ck_hw_feature_type_t #undef ck_key_type_t #undef ck_certificate_type_t #undef ck_attribute_type_t #undef ck_attribute #undef value #undef value_len #undef ck_date #undef ck_mechanism_type_t #undef ck_mechanism #undef parameter #undef parameter_len #undef ck_mechanism_info #undef min_key_size #undef max_key_size #undef ck_rv_t #undef ck_notify_t #undef ck_function_list #undef ck_createmutex_t #undef ck_destroymutex_t #undef ck_lockmutex_t #undef ck_unlockmutex_t #undef ck_c_initialize_args #undef create_mutex #undef destroy_mutex #undef lock_mutex #undef unlock_mutex #undef reserved #endif /* CRYPTOKI_COMPAT */ /* System dependencies. */ #if defined(_WIN32) || defined(CRYPTOKI_FORCE_WIN32) #pragma pack(pop, cryptoki) #endif #if defined(__cplusplus) } #endif #endif /* PKCS11_H */ |
Changes to portfwd.c.
︙ | ︙ | |||
11 12 13 14 15 16 17 | #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE 1 #endif | | | | | | > > > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | > | > | | < < < < < < | < | < < < < < < < < < < < < < < < < < < | | > > > > | < > > > | > > > | > > > | | | | | < | | | | < | | | | | | | | | | | | < < | | | | | | | | | | | | | | | < | | | | | | | | | | | | | | | | | | | | | | | | | < | | | < < | | | | | | | | | | | | | | | | | < < < < | | | | < < | > | | | | | | | | | < | < < | < | > | < | | > | | | | | | > > | | | | | | | | | | | | < | < < < > | | | | | | | | | > > | | > | | | | > > | | < | | < | < < | > > > > | > > | > > > > > | < | < < < | < | > | > | | | > | > | | | | | < | < < > | | | | > | | | | | | | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 | #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE 1 #endif struct PFwdPrivate { const struct plug_function_table *fn; /* the above variable absolutely *must* be the first in this structure */ void *c; /* (channel) data used by ssh.c */ void *backhandle; /* instance of SSH backend itself */ /* Note that backhandle need not be filled in if c is non-NULL */ Socket s; int throttled, throttle_override; int ready; /* * `dynamic' does double duty. It's set to 0 for an ordinary * forwarded port, and nonzero for SOCKS-style dynamic port * forwarding; but it also represents the state of the SOCKS * exchange. */ int dynamic; /* * `hostname' and `port' are the real hostname and port, once * we know what we're connecting to; they're unused for this * purpose while conducting a local SOCKS exchange, which means * we can also use them as a buffer and pointer for reading * data from the SOCKS client. */ char hostname[256+8]; int port; /* * When doing dynamic port forwarding, we can receive * connection data before we are actually able to send it; so * we may have to temporarily hold some in a dynamically * allocated buffer here. */ void *buffer; int buflen; }; static void pfd_log(Plug plug, int type, SockAddr addr, int port, const char *error_msg, int error_code) { /* we have to dump these since we have no interface to logging.c */ } static int pfd_closing(Plug plug, const char *error_msg, int error_code, int calling_back) { struct PFwdPrivate *pr = (struct PFwdPrivate *) plug; /* * We have no way to communicate down the forwarded connection, * so if an error occurred on the socket, we just ignore it * and treat it like a proper close. */ if (pr->c) sshfwd_close(pr->c); pfd_close(pr->s); return 1; } static int pfd_receive(Plug plug, int urgent, char *data, int len) { struct PFwdPrivate *pr = (struct PFwdPrivate *) plug; if (pr->dynamic) { while (len--) { /* * Throughout SOCKS negotiation, "hostname" is re-used as a * random protocol buffer with "port" storing the length. */ if (pr->port >= lenof(pr->hostname)) { /* Request too long. */ if ((pr->dynamic >> 12) == 4) { /* Send back a SOCKS 4 error before closing. */ char data[8]; memset(data, 0, sizeof(data)); data[1] = 91; /* generic `request rejected' */ sk_write(pr->s, data, 8); } pfd_close(pr->s); return 1; } pr->hostname[pr->port++] = *data++; /* * Now check what's in the buffer to see if it's a * valid and complete message in the SOCKS exchange. */ if ((pr->dynamic == 1 || (pr->dynamic >> 12) == 4) && pr->hostname[0] == 4) { /* * SOCKS 4. */ if (pr->dynamic == 1) pr->dynamic = 0x4000; if (pr->port < 2) continue;/* don't have command code yet */ if (pr->hostname[1] != 1) { /* Not CONNECT. */ /* Send back a SOCKS 4 error before closing. */ char data[8]; memset(data, 0, sizeof(data)); data[1] = 91; /* generic `request rejected' */ sk_write(pr->s, data, 8); pfd_close(pr->s); return 1; } if (pr->port <= 8) continue; /* haven't started user/hostname */ if (pr->hostname[pr->port-1] != 0) continue; /* haven't _finished_ user/hostname */ /* * Now we have a full SOCKS 4 request. Check it to * see if it's a SOCKS 4A request. */ if (pr->hostname[4] == 0 && pr->hostname[5] == 0 && pr->hostname[6] == 0 && pr->hostname[7] != 0) { /* * It's SOCKS 4A. So if we haven't yet * collected the host name, we should continue * waiting for data in order to do so; if we * have, we can go ahead. */ int len; if (pr->dynamic == 0x4000) { pr->dynamic = 0x4001; pr->port = 8; /* reset buffer to overwrite name */ continue; } pr->hostname[0] = 0; /* reply version code */ pr->hostname[1] = 90; /* request granted */ sk_write(pr->s, pr->hostname, 8); len= pr->port - 8; pr->port = GET_16BIT_MSB_FIRST(pr->hostname+2); memmove(pr->hostname, pr->hostname + 8, len); goto connect; } else { /* * It's SOCKS 4, which means we should format * the IP address into the hostname string and * then just go. */ pr->hostname[0] = 0; /* reply version code */ pr->hostname[1] = 90; /* request granted */ sk_write(pr->s, pr->hostname, 8); pr->port = GET_16BIT_MSB_FIRST(pr->hostname+2); sprintf(pr->hostname, "%d.%d.%d.%d", (unsigned char)pr->hostname[4], (unsigned char)pr->hostname[5], (unsigned char)pr->hostname[6], (unsigned char)pr->hostname[7]); goto connect; } } if ((pr->dynamic == 1 || (pr->dynamic >> 12) == 5) && pr->hostname[0] == 5) { /* * SOCKS 5. */ if (pr->dynamic == 1) pr->dynamic = 0x5000; if (pr->dynamic == 0x5000) { int i, method; char data[2]; /* * We're receiving a set of method identifiers. */ if (pr->port < 2) continue;/* no method count yet */ if (pr->port < 2 + (unsigned char)pr->hostname[1]) continue; /* no methods yet */ method = 0xFF; /* invalid */ for (i = 0; i < (unsigned char)pr->hostname[1]; i++) if (pr->hostname[2+i] == 0) { method = 0;/* no auth */ break; } data[0] = 5; data[1] = method; sk_write(pr->s, data, 2); pr->dynamic = 0x5001; pr->port = 0; /* re-empty the buffer */ continue; } if (pr->dynamic == 0x5001) { /* * We're receiving a SOCKS request. */ unsigned char reply[10]; /* SOCKS5 atyp=1 reply */ int atype, alen = 0; /* * Pre-fill reply packet. * In all cases, we set BND.{HOST,ADDR} to 0.0.0.0:0 * (atyp=1) in the reply; if we succeed, we don't know * the right answers, and if we fail, they should be * ignored. */ memset(reply, 0, lenof(reply)); reply[0] = 5; /* VER */ reply[3] = 1; /* ATYP = 1 (IPv4, 0.0.0.0:0) */ if (pr->port < 6) continue; atype = (unsigned char)pr->hostname[3]; if (atype == 1) /* IPv4 address */ alen = 4; if (atype == 4) /* IPv6 address */ alen = 16; if (atype == 3) /* domain name has leading length */ alen = 1 + (unsigned char)pr->hostname[4]; if (pr->port < 6 + alen) continue; if (pr->hostname[1] != 1 || pr->hostname[2] != 0) { /* Not CONNECT or reserved field nonzero - error */ reply[1] = 1; /* generic failure */ sk_write(pr->s, (char *) reply, lenof(reply)); pfd_close(pr->s); return 1; } /* * Now we have a viable connect request. Switch * on atype. */ pr->port = GET_16BIT_MSB_FIRST(pr->hostname+4+alen); if (atype == 1) { /* REP=0 (success) already */ sk_write(pr->s, (char *) reply, lenof(reply)); sprintf(pr->hostname, "%d.%d.%d.%d", (unsigned char)pr->hostname[4], (unsigned char)pr->hostname[5], (unsigned char)pr->hostname[6], (unsigned char)pr->hostname[7]); goto connect; } else if (atype == 3) { /* REP=0 (success) already */ sk_write(pr->s, (char *) reply, lenof(reply)); memmove(pr->hostname, pr->hostname + 5, alen-1); pr->hostname[alen-1] = '\0'; goto connect; } else { /* * Unknown address type. (FIXME: support IPv6!) */ reply[1] = 8; /* atype not supported */ sk_write(pr->s, (char *) reply, lenof(reply)); pfd_close(pr->s); return 1; } } } /* * If we get here without either having done `continue' * or `goto connect', it must be because there is no * sensible interpretation of what's in our buffer. So * close the connection rudely. */ pfd_close(pr->s); return 1; } return 1; /* * We come here when we're ready to make an actual * connection. */ connect: /* * Freeze the socket until the SSH server confirms the * connection. */ sk_set_frozen(pr->s, 1); pr->c = new_sock_channel(pr->backhandle, pr->s); if (pr->c == NULL) { pfd_close(pr->s); return 1; } else { /* asks to forward to the specified host/port for this */ ssh_send_port_open(pr->c, pr->hostname, pr->port, "forwarding"); } pr->dynamic = 0; /* * If there's any data remaining in our current buffer, * save it to be sent on pfd_confirm(). */ if (len > 0) { pr->buffer = snewn(len, char); memcpy(pr->buffer, data, len); pr->buflen = len; } } if (pr->ready) { if (sshfwd_write(pr->c, data, len) > 0) { pr->throttled = 1; sk_set_frozen(pr->s, 1); } } return 1; } static void pfd_sent(Plug plug, int bufsize) { struct PFwdPrivate *pr = (struct PFwdPrivate *) plug; if (pr->c) sshfwd_unthrottle(pr->c, bufsize); } /* * Called when receiving a PORT OPEN from the server */ const char *pfd_newconnect(Socket *s, char *hostname, int port, void *c, const Config *cfg, int addressfamily) { static const struct plug_function_table fn_table = { pfd_log, pfd_closing, pfd_receive, pfd_sent, NULL }; SockAddr addr; const char *err; char *dummy_realhost; struct PFwdPrivate *pr; /* * Try to find host. */ addr = name_lookup(hostname, port, &dummy_realhost, cfg, addressfamily); if ((err = sk_addr_error(addr)) != NULL) { sk_addr_free(addr); return err; } /* * Open socket. */ pr = snew(struct PFwdPrivate); pr->buffer = NULL; pr->fn = &fn_table; pr->throttled = pr->throttle_override = 0; pr->ready = 1; pr->c = c; pr->backhandle = NULL; /* we shouldn't need this */ pr->dynamic = 0; pr->s = *s = new_connection(addr, dummy_realhost, port, 0, 1, 0, 0, (Plug) pr, cfg); if ((err = sk_socket_error(*s)) != NULL) { sfree(pr); return err; } sk_set_private_ptr(*s, pr); return NULL; } /* called when someone connects to the local port */ static int pfd_accepting(Plug p, OSSocket sock) { static const struct plug_function_table fn_table = { pfd_log, pfd_closing, pfd_receive, pfd_sent, NULL }; struct PFwdPrivate *pr, *org; Socket s; const char *err; org = (struct PFwdPrivate *)p; pr = snew(struct PFwdPrivate); pr->buffer = NULL; pr->fn = &fn_table; pr->c = NULL; pr->backhandle = org->backhandle; pr->s = s = sk_register(sock, (Plug) pr); if ((err = sk_socket_error(s)) != NULL) { sfree(pr); return err != NULL; } sk_set_private_ptr(s, pr); pr->throttled = pr->throttle_override = 0; pr->ready = 0; if (org->dynamic) { pr->dynamic = 1; pr->port = 0; /* "hostname" buffer is so far empty */ sk_set_frozen(s, 0); /* we want to receive SOCKS _now_! */ } else { pr->dynamic = 0; strcpy(pr->hostname, org->hostname); pr->port = org->port; pr->c = new_sock_channel(org->backhandle, s); if (pr->c == NULL) { sfree(pr); return 1; } else { /* asks to forward to the specified host/port for this */ ssh_send_port_open(pr->c, pr->hostname, pr->port, "forwarding"); } } return 0; } /* Add a new forwarding from port -> desthost:destport sets up a listener on the local machine on (srcaddr:)port */ const char *pfd_addforward(char *desthost, int destport, char *srcaddr, int port, void *backhandle, const Config *cfg, void **sockdata, int address_family) { static const struct plug_function_table fn_table = { pfd_log, pfd_closing, pfd_receive, /* should not happen... */ pfd_sent, /* also should not happen */ pfd_accepting }; const char *err; struct PFwdPrivate *pr; Socket s; /* * Open socket. */ pr = snew(struct PFwdPrivate); pr->buffer = NULL; pr->fn = &fn_table; pr->c = NULL; if (desthost) { strcpy(pr->hostname, desthost); pr->port = destport; pr->dynamic = 0; } else pr->dynamic = 1; pr->throttled = pr->throttle_override = 0; pr->ready = 0; pr->backhandle = backhandle; pr->s = s = new_listener(srcaddr, port, (Plug) pr, !cfg->lport_acceptall, cfg, address_family); if ((err = sk_socket_error(s)) != NULL) { sfree(pr); return err; } sk_set_private_ptr(s, pr); *sockdata = (void *)s; return NULL; } void pfd_close(Socket s) { struct PFwdPrivate *pr; if (!s) return; pr = (struct PFwdPrivate *) sk_get_private_ptr(s); sfree(pr->buffer); sfree(pr); sk_close(s); } /* * Terminate a listener. */ void pfd_terminate(void *sv) { pfd_close((Socket)sv); } void pfd_unthrottle(Socket s) { struct PFwdPrivate *pr; if (!s) return; pr = (struct PFwdPrivate *) sk_get_private_ptr(s); pr->throttled = 0; sk_set_frozen(s, pr->throttled || pr->throttle_override); } void pfd_override_throttle(Socket s, int enable) { struct PFwdPrivate *pr; if (!s) return; pr = (struct PFwdPrivate *) sk_get_private_ptr(s); pr->throttle_override = enable; sk_set_frozen(s, pr->throttled || pr->throttle_override); } /* * Called to send data down the raw connection. */ int pfd_send(Socket s, char *data, int len) { if (s == NULL) return 0; return sk_write(s, data, len); } void pfd_confirm(Socket s) { struct PFwdPrivate *pr; if (s == NULL) return; pr = (struct PFwdPrivate *) sk_get_private_ptr(s); pr->ready = 1; sk_set_frozen(s, 0); sk_write(s, NULL, 0); if (pr->buffer) { sshfwd_write(pr->c, pr->buffer, pr->buflen); sfree(pr->buffer); pr->buffer = NULL; } } |
Changes to pproxy.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* * pproxy.c: dummy implementation of platform_new_connection(), to * be supplanted on any platform which has its own local proxy * method. */ #include "putty.h" #include "network.h" #include "proxy.h" Socket platform_new_connection(SockAddr addr, char *hostname, int port, int privport, int oobinline, int nodelay, int keepalive, | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | /* * pproxy.c: dummy implementation of platform_new_connection(), to * be supplanted on any platform which has its own local proxy * method. */ #include "putty.h" #include "network.h" #include "proxy.h" Socket platform_new_connection(SockAddr addr, char *hostname, int port, int privport, int oobinline, int nodelay, int keepalive, Plug plug, const Config *cfg) { return NULL; } |
Changes to proxy.c.
︙ | ︙ | |||
10 11 12 13 14 15 16 | #include <string.h> #define DEFINE_PLUG_METHOD_MACROS #include "putty.h" #include "network.h" #include "proxy.h" | | | < | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #include <string.h> #define DEFINE_PLUG_METHOD_MACROS #include "putty.h" #include "network.h" #include "proxy.h" #define do_proxy_dns(cfg) \ (cfg->proxy_dns == FORCE_ON || \ (cfg->proxy_dns == AUTO && cfg->proxy_type != PROXY_SOCKS4)) /* * Call this when proxy negotiation is complete, so that this * socket can begin working normally. */ void proxy_activate (Proxy_Socket p) { |
︙ | ︙ | |||
61 62 63 64 65 66 67 | plug_sent(p->plug, output_after); /* if we were asked to flush the output during * the proxy negotiation process, do so now. */ if (p->pending_flush) sk_flush(p->sub_socket); | < < < | 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | plug_sent(p->plug, output_after); /* if we were asked to flush the output during * the proxy negotiation process, do so now. */ if (p->pending_flush) sk_flush(p->sub_socket); /* if the backend wanted the socket unfrozen, try to unfreeze. * our set_frozen handler will flush buffered receive data before * unfreezing the actual underlying socket. */ if (!p->freeze) sk_set_frozen((Socket)p, 0); } |
︙ | ︙ | |||
116 117 118 119 120 121 122 | bufchain_clear(&ps->pending_oob_output_data); bufchain_add(&ps->pending_oob_output_data, data, len); return len; } return sk_write_oob(ps->sub_socket, data, len); } | < < < < < < < < < < < > > > > > > > > > > > > | 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | bufchain_clear(&ps->pending_oob_output_data); bufchain_add(&ps->pending_oob_output_data, data, len); return len; } return sk_write_oob(ps->sub_socket, data, len); } static void sk_proxy_flush (Socket s) { Proxy_Socket ps = (Proxy_Socket) s; if (ps->state != PROXY_STATE_ACTIVE) { ps->pending_flush = 1; return; } sk_flush(ps->sub_socket); } static void sk_proxy_set_private_ptr (Socket s, void *ptr) { Proxy_Socket ps = (Proxy_Socket) s; sk_set_private_ptr(ps->sub_socket, ptr); } static void * sk_proxy_get_private_ptr (Socket s) { Proxy_Socket ps = (Proxy_Socket) s; return sk_get_private_ptr(ps->sub_socket); } static void sk_proxy_set_frozen (Socket s, int is_frozen) { Proxy_Socket ps = (Proxy_Socket) s; if (ps->state != PROXY_STATE_ACTIVE) { ps->freeze = is_frozen; |
︙ | ︙ | |||
245 246 247 248 249 250 251 | ps->sent_bufsize = bufsize; ps->negotiate(ps, PROXY_CHANGE_SENT); return; } plug_sent(ps->plug, bufsize); } | | < < | | | | < < < < < < < < < | | | 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 | ps->sent_bufsize = bufsize; ps->negotiate(ps, PROXY_CHANGE_SENT); return; } plug_sent(ps->plug, bufsize); } static int plug_proxy_accepting (Plug p, OSSocket sock) { Proxy_Plug pp = (Proxy_Plug) p; Proxy_Socket ps = pp->proxy_socket; if (ps->state != PROXY_STATE_ACTIVE) { ps->accepting_sock = sock; return ps->negotiate(ps, PROXY_CHANGE_ACCEPTING); } return plug_accepting(ps->plug, sock); } /* * This function can accept a NULL pointer as `addr', in which case * it will only check the host name. */ static int proxy_for_destination (SockAddr addr, char *hostname, int port, const Config *cfg) { int s = 0, e = 0; char hostip[64]; int hostip_len, hostname_len; const char *exclude_list; /* * Check the host name and IP against the hard-coded * representations of `localhost'. */ if (!cfg->even_proxy_localhost && (sk_hostname_is_local(hostname) || (addr && sk_address_is_local(addr)))) return 0; /* do not proxy */ /* we want a string representation of the IP address for comparisons */ if (addr) { sk_getaddr(addr, hostip, 64); hostip_len = strlen(hostip); } else hostip_len = 0; /* placate gcc; shouldn't be required */ hostname_len = strlen(hostname); exclude_list = cfg->proxy_exclude_list; /* now parse the exclude list, and see if either our IP * or hostname matches anything in it. */ while (exclude_list[s]) { while (exclude_list[s] && |
︙ | ︙ | |||
359 360 361 362 363 364 365 | } /* no matches in the exclude list, so use the proxy */ return 1; } SockAddr name_lookup(char *host, int port, char **canonicalname, | | | | | | | | > | | < | | < | < | | | | | | < < < | < | | 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 | } /* no matches in the exclude list, so use the proxy */ return 1; } SockAddr name_lookup(char *host, int port, char **canonicalname, const Config *cfg, int addressfamily) { if (cfg->proxy_type != PROXY_NONE && do_proxy_dns(cfg) && proxy_for_destination(NULL, host, port, cfg)) { *canonicalname = dupstr(host); return sk_nonamelookup(host); } return sk_namelookup(host, canonicalname, addressfamily); } Socket new_connection(SockAddr addr, char *hostname, int port, int privport, int oobinline, int nodelay, int keepalive, Plug plug, const Config *cfg) { static const struct socket_function_table socket_fn_table = { sk_proxy_plug, sk_proxy_close, sk_proxy_write, sk_proxy_write_oob, sk_proxy_flush, sk_proxy_set_private_ptr, sk_proxy_get_private_ptr, sk_proxy_set_frozen, sk_proxy_socket_error }; static const struct plug_function_table plug_fn_table = { plug_proxy_log, plug_proxy_closing, plug_proxy_receive, plug_proxy_sent, plug_proxy_accepting }; if (cfg->proxy_type != PROXY_NONE && proxy_for_destination(addr, hostname, port, cfg)) { Proxy_Socket ret; Proxy_Plug pplug; SockAddr proxy_addr; char *proxy_canonical_name; Socket sret; if ((sret = platform_new_connection(addr, hostname, port, privport, oobinline, nodelay, keepalive, plug, cfg)) != NULL) return sret; ret = snew(struct Socket_proxy_tag); ret->fn = &socket_fn_table; ret->cfg = *cfg; /* STRUCTURE COPY */ ret->plug = plug; ret->remote_addr = addr; /* will need to be freed on close */ ret->remote_port = port; ret->error = NULL; ret->pending_flush = 0; ret->freeze = 0; bufchain_init(&ret->pending_input_data); bufchain_init(&ret->pending_output_data); bufchain_init(&ret->pending_oob_output_data); ret->sub_socket = NULL; ret->state = PROXY_STATE_NEW; ret->negotiate = NULL; if (cfg->proxy_type == PROXY_HTTP) { ret->negotiate = proxy_http_negotiate; } else if (cfg->proxy_type == PROXY_SOCKS4) { ret->negotiate = proxy_socks4_negotiate; } else if (cfg->proxy_type == PROXY_SOCKS5) { ret->negotiate = proxy_socks5_negotiate; } else if (cfg->proxy_type == PROXY_TELNET) { ret->negotiate = proxy_telnet_negotiate; } else { ret->error = "Proxy error: Unknown proxy method"; return (Socket) ret; } /* create the proxy plug to map calls from the actual * socket into our proxy socket layer */ pplug = snew(struct Plug_proxy_tag); pplug->fn = &plug_fn_table; pplug->proxy_socket = ret; /* look-up proxy */ proxy_addr = sk_namelookup(cfg->proxy_host, &proxy_canonical_name, cfg->addressfamily); if (sk_addr_error(proxy_addr) != NULL) { ret->error = "Proxy error: Unable to resolve proxy host name"; return (Socket)ret; } sfree(proxy_canonical_name); /* create the actual socket we will be using, * connected to our proxy server and port. */ ret->sub_socket = sk_new(proxy_addr, cfg->proxy_port, privport, oobinline, nodelay, keepalive, (Plug) pplug); if (sk_socket_error(ret->sub_socket) != NULL) return (Socket) ret; /* start the proxy negotiation process... */ sk_set_frozen(ret->sub_socket, 0); ret->negotiate(ret, PROXY_CHANGE_NEW); return (Socket) ret; } /* no proxy, so just return the direct socket */ return sk_new(addr, port, privport, oobinline, nodelay, keepalive, plug); } Socket new_listener(char *srcaddr, int port, Plug plug, int local_host_only, const Config *cfg, int addressfamily) { /* TODO: SOCKS (and potentially others) support inbound * TODO: connections via the proxy. support them. */ return sk_newlistener(srcaddr, port, plug, local_host_only, addressfamily); } |
︙ | ︙ | |||
541 542 543 544 545 546 547 | if (p->state == PROXY_STATE_NEW) { /* we are just beginning the proxy negotiate process, * so we'll send off the initial bits of the request. * for this proxy method, it's just a simple HTTP * request */ char *buf, dest[512]; | < | < | | | < < < | 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 | if (p->state == PROXY_STATE_NEW) { /* we are just beginning the proxy negotiate process, * so we'll send off the initial bits of the request. * for this proxy method, it's just a simple HTTP * request */ char *buf, dest[512]; sk_getaddr(p->remote_addr, dest, lenof(dest)); buf = dupprintf("CONNECT %s:%i HTTP/1.1\r\nHost: %s:%i\r\n", dest, p->remote_port, dest, p->remote_port); sk_write(p->sub_socket, buf, strlen(buf)); sfree(buf); if (p->cfg.proxy_username[0] || p->cfg.proxy_password[0]) { char buf[sizeof(p->cfg.proxy_username)+sizeof(p->cfg.proxy_password)]; char buf2[sizeof(buf)*4/3 + 100]; int i, j, len; sprintf(buf, "%s:%s", p->cfg.proxy_username, p->cfg.proxy_password); len = strlen(buf); sprintf(buf2, "Proxy-Authorization: Basic "); for (i = 0, j = strlen(buf2); i < len; i += 3, j += 4) base64_encode_atom((unsigned char *)(buf+i), (len-i > 3 ? 3 : len-i), buf2+j); strcpy(buf2+j, "\r\n"); sk_write(p->sub_socket, buf2, strlen(buf2)); } sk_write(p->sub_socket, "\r\n", 2); p->state = 1; return 0; } |
︙ | ︙ | |||
601 602 603 604 605 606 607 | if (change == PROXY_CHANGE_ACCEPTING) { /* we should _never_ see this, as we are using our socket to * connect to a proxy, not accepting inbound connections. * what should we do? close the socket with an appropriate * error message? */ | | < | 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 | if (change == PROXY_CHANGE_ACCEPTING) { /* we should _never_ see this, as we are using our socket to * connect to a proxy, not accepting inbound connections. * what should we do? close the socket with an appropriate * error message? */ return plug_accepting(p->plug, p->accepting_sock); } if (change == PROXY_CHANGE_RECEIVE) { /* we have received data from the underlying socket, which * we'll need to parse, process, and respond to appropriately. */ |
︙ | ︙ | |||
733 734 735 736 737 738 739 | * dest. port (2 bytes) [network order] * dest. address (4 bytes) * user ID (variable length, null terminated string) */ int length, type, namelen; char *command, addr[4], hostname[512]; | < | > < | | | < | 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 | * dest. port (2 bytes) [network order] * dest. address (4 bytes) * user ID (variable length, null terminated string) */ int length, type, namelen; char *command, addr[4], hostname[512]; type = sk_addrtype(p->remote_addr); if (type == ADDRTYPE_IPV6) { plug_closing(p->plug, "Proxy error: SOCKS version 4 does" " not support IPv6", PROXY_ERROR_GENERAL, 0); return 1; } else if (type == ADDRTYPE_IPV4) { namelen = 0; sk_addrcopy(p->remote_addr, addr); } else { /* type == ADDRTYPE_NAME */ assert(type == ADDRTYPE_NAME); sk_getaddr(p->remote_addr, hostname, lenof(hostname)); namelen = strlen(hostname) + 1; /* include the NUL */ addr[0] = addr[1] = addr[2] = 0; addr[3] = 1; } length = strlen(p->cfg.proxy_username) + namelen + 9; command = snewn(length, char); strcpy(command + 8, p->cfg.proxy_username); command[0] = 4; /* version 4 */ command[1] = 1; /* CONNECT command */ /* port */ command[2] = (char) (p->remote_port >> 8) & 0xff; command[3] = (char) p->remote_port & 0xff; /* address */ memcpy(command + 4, addr, 4); /* hostname */ memcpy(command + 8 + strlen(p->cfg.proxy_username) + 1, hostname, namelen); sk_write(p->sub_socket, command, length); sfree(command); p->state = 1; return 0; } if (change == PROXY_CHANGE_CLOSING) { |
︙ | ︙ | |||
804 805 806 807 808 809 810 | if (change == PROXY_CHANGE_ACCEPTING) { /* we should _never_ see this, as we are using our socket to * connect to a proxy, not accepting inbound connections. * what should we do? close the socket with an appropriate * error message? */ | | < | 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 | if (change == PROXY_CHANGE_ACCEPTING) { /* we should _never_ see this, as we are using our socket to * connect to a proxy, not accepting inbound connections. * what should we do? close the socket with an appropriate * error message? */ return plug_accepting(p->plug, p->accepting_sock); } if (change == PROXY_CHANGE_RECEIVE) { /* we have received data from the underlying socket, which * we'll need to parse, process, and respond to appropriately. */ |
︙ | ︙ | |||
893 894 895 896 897 898 899 | * 0x00 = no authentication * 0x01 = GSSAPI * 0x02 = username/password * 0x03 = CHAP */ char command[5]; | < < < | | 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 | * 0x00 = no authentication * 0x01 = GSSAPI * 0x02 = username/password * 0x03 = CHAP */ char command[5]; int len; command[0] = 5; /* version 5 */ if (p->cfg.proxy_username[0] || p->cfg.proxy_password[0]) { command[2] = 0x00; /* no authentication */ len = 3; proxy_socks5_offerencryptedauth (command, &len); command[len++] = 0x02; /* username/password */ command[1] = len - 2; /* Number of methods supported */ } else { command[1] = 1; /* one methods supported: */ |
︙ | ︙ | |||
944 945 946 947 948 949 950 | if (change == PROXY_CHANGE_ACCEPTING) { /* we should _never_ see this, as we are using our socket to * connect to a proxy, not accepting inbound connections. * what should we do? close the socket with an appropriate * error message? */ | | < | 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 | if (change == PROXY_CHANGE_ACCEPTING) { /* we should _never_ see this, as we are using our socket to * connect to a proxy, not accepting inbound connections. * what should we do? close the socket with an appropriate * error message? */ return plug_accepting(p->plug, p->accepting_sock); } if (change == PROXY_CHANGE_RECEIVE) { /* we have received data from the underlying socket, which * we'll need to parse, process, and respond to appropriately. */ |
︙ | ︙ | |||
1177 1178 1179 1180 1181 1182 1183 | /* TODO: Handle GSSAPI authentication */ plug_closing(p->plug, "Proxy error: We don't support GSSAPI authentication", PROXY_ERROR_GENERAL, 0); return 1; } if (p->state == 5) { | < < | | | | | | | 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 | /* TODO: Handle GSSAPI authentication */ plug_closing(p->plug, "Proxy error: We don't support GSSAPI authentication", PROXY_ERROR_GENERAL, 0); return 1; } if (p->state == 5) { if (p->cfg.proxy_username[0] || p->cfg.proxy_password[0]) { char userpwbuf[514]; int ulen, plen; ulen = strlen(p->cfg.proxy_username); if (ulen > 255) ulen = 255; if (ulen < 1) ulen = 1; plen = strlen(p->cfg.proxy_password); if (plen > 255) plen = 255; if (plen < 1) plen = 1; userpwbuf[0] = 1; /* version number of subnegotiation */ userpwbuf[1] = ulen; memcpy(userpwbuf+2, p->cfg.proxy_username, ulen); userpwbuf[ulen+2] = plen; memcpy(userpwbuf+ulen+3, p->cfg.proxy_password, plen); sk_write(p->sub_socket, userpwbuf, ulen + plen + 3); p->state = 7; } else plug_closing(p->plug, "Proxy error: Server chose " "username/password authentication but we " "didn't offer it!", PROXY_ERROR_GENERAL, 0); |
︙ | ︙ | |||
1223 1224 1225 1226 1227 1228 1229 | * * (This is for ad-hoc proxies where you connect to the proxy's * telnet port and send a command such as `connect host port'. The * command is configurable, since this proxy type is typically not * standardised or at all well-defined.) */ | | < | > | | | | | | | | 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 | * * (This is for ad-hoc proxies where you connect to the proxy's * telnet port and send a command such as `connect host port'. The * command is configurable, since this proxy type is typically not * standardised or at all well-defined.) */ char *format_telnet_command(SockAddr addr, int port, const Config *cfg) { char *ret = NULL; int retlen = 0, retsize = 0; int so = 0, eo = 0; #define ENSURE(n) do { \ if (retsize < retlen + n) { \ retsize = retlen + n + 512; \ ret = sresize(ret, retsize, char); \ } \ } while (0) /* we need to escape \\, \%, \r, \n, \t, \x??, \0???, * %%, %host, %port, %user, and %pass */ while (cfg->proxy_telnet_command[eo] != 0) { /* scan forward until we hit end-of-line, * or an escape character (\ or %) */ while (cfg->proxy_telnet_command[eo] != 0 && cfg->proxy_telnet_command[eo] != '%' && cfg->proxy_telnet_command[eo] != '\\') eo++; /* if we hit eol, break out of our escaping loop */ if (cfg->proxy_telnet_command[eo] == 0) break; /* if there was any unescaped text before the escape * character, send that now */ if (eo != so) { ENSURE(eo - so); memcpy(ret + retlen, cfg->proxy_telnet_command + so, eo - so); retlen += eo - so; } so = eo++; /* if the escape character was the last character of * the line, we'll just stop and send it. */ if (cfg->proxy_telnet_command[eo] == 0) break; if (cfg->proxy_telnet_command[so] == '\\') { /* we recognize \\, \%, \r, \n, \t, \x??. * anything else, we just send unescaped (including the \). */ switch (cfg->proxy_telnet_command[eo]) { case '\\': ENSURE(1); ret[retlen++] = '\\'; eo++; break; |
︙ | ︙ | |||
1311 1312 1313 1314 1315 1316 1317 | { /* escaped hexadecimal value (ie. \xff) */ unsigned char v = 0; int i = 0; for (;;) { eo++; | | > | | > | | > | | 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 | { /* escaped hexadecimal value (ie. \xff) */ unsigned char v = 0; int i = 0; for (;;) { eo++; if (cfg->proxy_telnet_command[eo] >= '0' && cfg->proxy_telnet_command[eo] <= '9') v += cfg->proxy_telnet_command[eo] - '0'; else if (cfg->proxy_telnet_command[eo] >= 'a' && cfg->proxy_telnet_command[eo] <= 'f') v += cfg->proxy_telnet_command[eo] - 'a' + 10; else if (cfg->proxy_telnet_command[eo] >= 'A' && cfg->proxy_telnet_command[eo] <= 'F') v += cfg->proxy_telnet_command[eo] - 'A' + 10; else { /* non hex character, so we abort and just * send the whole thing unescaped (including \x) */ ENSURE(1); ret[retlen++] = '\\'; eo = so + 1; |
︙ | ︙ | |||
1343 1344 1345 1346 1347 1348 1349 | v <<= 4; } } break; default: ENSURE(2); | | | > | > | > | < | | > | < | | > | < | | > | < | | 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 | v <<= 4; } } break; default: ENSURE(2); memcpy(ret+retlen, cfg->proxy_telnet_command + so, 2); retlen += 2; eo++; break; } } else { /* % escape. we recognize %%, %host, %port, %user, %pass. * %proxyhost, %proxyport. Anything else we just send * unescaped (including the %). */ if (cfg->proxy_telnet_command[eo] == '%') { ENSURE(1); ret[retlen++] = '%'; eo++; } else if (strnicmp(cfg->proxy_telnet_command + eo, "host", 4) == 0) { char dest[512]; int destlen; sk_getaddr(addr, dest, lenof(dest)); destlen = strlen(dest); ENSURE(destlen); memcpy(ret+retlen, dest, destlen); retlen += destlen; eo += 4; } else if (strnicmp(cfg->proxy_telnet_command + eo, "port", 4) == 0) { char portstr[8], portlen; portlen = sprintf(portstr, "%i", port); ENSURE(portlen); memcpy(ret + retlen, portstr, portlen); retlen += portlen; eo += 4; } else if (strnicmp(cfg->proxy_telnet_command + eo, "user", 4) == 0) { int userlen = strlen(cfg->proxy_username); ENSURE(userlen); memcpy(ret+retlen, cfg->proxy_username, userlen); retlen += userlen; eo += 4; } else if (strnicmp(cfg->proxy_telnet_command + eo, "pass", 4) == 0) { int passlen = strlen(cfg->proxy_password); ENSURE(passlen); memcpy(ret+retlen, cfg->proxy_password, passlen); retlen += passlen; eo += 4; } else if (strnicmp(cfg->proxy_telnet_command + eo, "proxyhost", 9) == 0) { int phlen = strlen(cfg->proxy_host); ENSURE(phlen); memcpy(ret+retlen, cfg->proxy_host, phlen); retlen += phlen; eo += 9; } else if (strnicmp(cfg->proxy_telnet_command + eo, "proxyport", 9) == 0) { char pport[50]; int pplen; sprintf(pport, "%d", cfg->proxy_port); pplen = strlen(pport); ENSURE(pplen); memcpy(ret+retlen, pport, pplen); retlen += pplen; eo += 9; } else { |
︙ | ︙ | |||
1430 1431 1432 1433 1434 1435 1436 | /* resume scanning for additional escapes after this one. */ so = eo; } /* if there is any unescaped text at the end of the line, send it */ if (eo != so) { ENSURE(eo - so); | | | | 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 | /* resume scanning for additional escapes after this one. */ so = eo; } /* if there is any unescaped text at the end of the line, send it */ if (eo != so) { ENSURE(eo - so); memcpy(ret + retlen, cfg->proxy_telnet_command + so, eo - so); retlen += eo - so; } ENSURE(1); ret[retlen] = '\0'; return ret; #undef ENSURE } int proxy_telnet_negotiate (Proxy_Socket p, int change) { if (p->state == PROXY_CHANGE_NEW) { char *formatted_cmd; formatted_cmd = format_telnet_command(p->remote_addr, p->remote_port, &p->cfg); sk_write(p->sub_socket, formatted_cmd, strlen(formatted_cmd)); sfree(formatted_cmd); p->state = 1; return 0; } |
︙ | ︙ | |||
1483 1484 1485 1486 1487 1488 1489 | if (change == PROXY_CHANGE_ACCEPTING) { /* we should _never_ see this, as we are using our socket to * connect to a proxy, not accepting inbound connections. * what should we do? close the socket with an appropriate * error message? */ | | < | 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 | if (change == PROXY_CHANGE_ACCEPTING) { /* we should _never_ see this, as we are using our socket to * connect to a proxy, not accepting inbound connections. * what should we do? close the socket with an appropriate * error message? */ return plug_accepting(p->plug, p->accepting_sock); } if (change == PROXY_CHANGE_RECEIVE) { /* we have received data from the underlying socket, which * we'll need to parse, process, and respond to appropriately. */ |
︙ | ︙ |
Changes to proxy.h.
︙ | ︙ | |||
26 27 28 29 30 31 32 | SockAddr remote_addr; int remote_port; bufchain pending_output_data; bufchain pending_oob_output_data; int pending_flush; bufchain pending_input_data; | < | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | SockAddr remote_addr; int remote_port; bufchain pending_output_data; bufchain pending_oob_output_data; int pending_flush; bufchain pending_input_data; #define PROXY_STATE_NEW -1 #define PROXY_STATE_ACTIVE 0 int state; /* proxy states greater than 0 are implementation * dependent, but represent various stages/states * of the initialization/setup/negotiation with the |
︙ | ︙ | |||
74 75 76 77 78 79 80 | char *receive_data; int receive_len; /* sent */ int sent_bufsize; /* accepting */ | < | | | 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | char *receive_data; int receive_len; /* sent */ int sent_bufsize; /* accepting */ OSSocket accepting_sock; /* configuration, used to look up proxy settings */ Config cfg; /* CHAP transient data */ int chap_num_attributes; int chap_num_attributes_processed; int chap_current_attribute; int chap_current_datalen; }; |
︙ | ︙ | |||
108 109 110 111 112 113 114 | extern int proxy_socks4_negotiate (Proxy_Socket, int); extern int proxy_socks5_negotiate (Proxy_Socket, int); /* * This may be reused by local-command proxies on individual * platforms. */ | | | 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | extern int proxy_socks4_negotiate (Proxy_Socket, int); extern int proxy_socks5_negotiate (Proxy_Socket, int); /* * This may be reused by local-command proxies on individual * platforms. */ char *format_telnet_command(SockAddr addr, int port, const Config *cfg); /* * These are implemented in cproxy.c or nocproxy.c, depending on * whether encrypted proxy authentication is available. */ extern void proxy_socks5_offerencryptedauth(char *command, int *len); extern int proxy_socks5_handlechap (Proxy_Socket p); extern int proxy_socks5_selectchap(Proxy_Socket p); #endif |
Changes to pscp.c.
︙ | ︙ | |||
37 38 39 40 41 42 43 | static int scp_unsafe_mode = 0; static int errs = 0; static int try_scp = 1; static int try_sftp = 1; static int main_cmd_is_sftp = 0; static int fallback_cmd_is_sftp = 0; static int using_sftp = 0; | < | < | 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | static int scp_unsafe_mode = 0; static int errs = 0; static int try_scp = 1; static int try_sftp = 1; static int main_cmd_is_sftp = 0; static int fallback_cmd_is_sftp = 0; static int using_sftp = 0; static Backend *back; static void *backhandle; static Config cfg; static void source(char *src); static void rsource(char *src); static void sink(char *targ, char *src); const char *const appname = "PSCP"; |
︙ | ︙ | |||
126 127 128 129 130 131 132 | va_end(ap); tell_str(stderr, str2); sfree(str2); errs++; cleanup_exit(1); } | < < < < < < < < < < < < < | 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | va_end(ap); tell_str(stderr, str2); sfree(str2); errs++; cleanup_exit(1); } void connection_fatal(void *frontend, char *fmt, ...) { char *str, *str2; va_list ap; va_start(ap, fmt); str = dupvprintf(fmt, ap); str2 = dupcat("Fatal: ", str, "\n", NULL); |
︙ | ︙ | |||
225 226 227 228 229 230 231 | /* * No "untrusted" output should get here (the way the code is * currently, it's all diverted by FLAG_STDERR). */ assert(!"Unexpected call to from_backend_untrusted()"); return 0; /* not reached */ } | < < < < < < < < < < < < < < | 210 211 212 213 214 215 216 217 218 219 220 221 222 223 | /* * No "untrusted" output should get here (the way the code is * currently, it's all diverted by FLAG_STDERR). */ assert(!"Unexpected call to from_backend_untrusted()"); return 0; /* not reached */ } static int ssh_scp_recv(unsigned char *buf, int len) { outptr = buf; outlen = len; /* * See if the pending-input block contains some of what we |
︙ | ︙ | |||
323 324 325 326 327 328 329 | tell_str(stderr, str2); sfree(str2); errs++; if (back != NULL && back->connected(backhandle)) { char ch; back->special(backhandle, TS_EOF); | < < < < < < < < < < < < < < < < < < < < < < < < | 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 | tell_str(stderr, str2); sfree(str2); errs++; if (back != NULL && back->connected(backhandle)) { char ch; back->special(backhandle, TS_EOF); ssh_scp_recv((unsigned char *) &ch, 1); } cleanup_exit(1); } /* * Open an SSH connection to user@host and execute cmd. */ static void do_cmd(char *host, char *user, char *cmd) { const char *err; char *realhost; |
︙ | ︙ | |||
382 383 384 385 386 387 388 | /* * If we haven't loaded session details already (e.g., from -load), * try looking for a session called "host". */ if (!loaded_session) { /* Try to load settings for `host' into a temporary config */ | | | | | | | > | > | | | | | | | < | < < < < < | < < | | > | | | > > | | | | | | < > | | | | | | | | < | | > | | > | | > | < < < < < | | | | | | | < | < | | | | | | < < < | | | | 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 | /* * If we haven't loaded session details already (e.g., from -load), * try looking for a session called "host". */ if (!loaded_session) { /* Try to load settings for `host' into a temporary config */ Config cfg2; cfg2.host[0] = '\0'; do_defaults(host, &cfg2); if (cfg2.host[0] != '\0') { /* Settings present and include hostname */ /* Re-load data into the real config. */ do_defaults(host, &cfg); } else { /* Session doesn't exist or mention a hostname. */ /* Use `host' as a bare hostname. */ strncpy(cfg.host, host, sizeof(cfg.host) - 1); cfg.host[sizeof(cfg.host) - 1] = '\0'; } } else { /* Patch in hostname `host' to session details. */ strncpy(cfg.host, host, sizeof(cfg.host) - 1); cfg.host[sizeof(cfg.host) - 1] = '\0'; } /* * Force use of SSH. (If they got the protocol wrong we assume the * port is useless too.) */ if (cfg.protocol != PROT_SSH) { cfg.protocol = PROT_SSH; cfg.port = 22; } /* * Enact command-line overrides. */ cmdline_run_saved(&cfg); /* * Trim leading whitespace off the hostname if it's there. */ { int space = strspn(cfg.host, " \t"); memmove(cfg.host, cfg.host+space, 1+strlen(cfg.host)-space); } /* See if host is of the form user@host */ if (cfg.host[0] != '\0') { char *atsign = strrchr(cfg.host, '@'); /* Make sure we're not overflowing the user field */ if (atsign) { if (atsign - cfg.host < sizeof cfg.username) { strncpy(cfg.username, cfg.host, atsign - cfg.host); cfg.username[atsign - cfg.host] = '\0'; } memmove(cfg.host, atsign + 1, 1 + strlen(atsign + 1)); } } /* * Remove any remaining whitespace from the hostname. */ { int p1 = 0, p2 = 0; while (cfg.host[p2] != '\0') { if (cfg.host[p2] != ' ' && cfg.host[p2] != '\t') { cfg.host[p1] = cfg.host[p2]; p1++; } p2++; } cfg.host[p1] = '\0'; } /* Set username */ if (user != NULL && user[0] != '\0') { strncpy(cfg.username, user, sizeof(cfg.username) - 1); cfg.username[sizeof(cfg.username) - 1] = '\0'; } else if (cfg.username[0] == '\0') { user = get_username(); if (!user) bump("Empty user name"); else { if (verbose) tell_user(stderr, "Guessing user name: %s", user); strncpy(cfg.username, user, sizeof(cfg.username) - 1); cfg.username[sizeof(cfg.username) - 1] = '\0'; sfree(user); } } /* * Disable scary things which shouldn't be enabled for simple * things like SCP and SFTP: agent forwarding, port forwarding, * X forwarding. */ cfg.x11_forward = 0; cfg.agentfwd = 0; cfg.portfwd[0] = cfg.portfwd[1] = '\0'; cfg.ssh_simple = TRUE; /* * Set up main and possibly fallback command depending on * options specified by user. * Attempt to start the SFTP subsystem as a first choice, * falling back to the provided scp command if that fails. */ cfg.remote_cmd_ptr2 = NULL; if (try_sftp) { /* First choice is SFTP subsystem. */ main_cmd_is_sftp = 1; strcpy(cfg.remote_cmd, "sftp"); cfg.ssh_subsys = TRUE; if (try_scp) { /* Fallback is to use the provided scp command. */ fallback_cmd_is_sftp = 0; cfg.remote_cmd_ptr2 = cmd; cfg.ssh_subsys2 = FALSE; } else { /* Since we're not going to try SCP, we may as well try * harder to find an SFTP server, since in the current * implementation we have a spare slot. */ fallback_cmd_is_sftp = 1; /* see psftp.c for full explanation of this kludge */ cfg.remote_cmd_ptr2 = "test -x /usr/lib/sftp-server && exec /usr/lib/sftp-server\n" "test -x /usr/local/lib/sftp-server && exec /usr/local/lib/sftp-server\n" "exec sftp-server"; cfg.ssh_subsys2 = FALSE; } } else { /* Don't try SFTP at all; just try the scp command. */ main_cmd_is_sftp = 0; cfg.remote_cmd_ptr = cmd; cfg.ssh_subsys = FALSE; } cfg.nopty = TRUE; back = &ssh_backend; err = back->init(NULL, &backhandle, &cfg, cfg.host, cfg.port, &realhost, 0, cfg.tcp_keepalives); if (err != NULL) bump("ssh_init: %s", err); logctx = log_init(NULL, &cfg); back->provide_logctx(backhandle, logctx); console_provide_logctx(logctx); ssh_scp_init(); if (verbose && realhost != NULL && errs == 0) tell_user(stderr, "Connected to %s\n", realhost); sfree(realhost); } /* * Update statistic information about current file. */ static void print_stats(char *name, uint64 size, uint64 done, |
︙ | ︙ | |||
686 687 688 689 690 691 692 | do { if (ssh_scp_recv((unsigned char *) &ch, 1) <= 0) bump("Protocol error: Lost connection"); rbuf[p++] = ch; } while (p < sizeof(rbuf) && ch != '\n'); rbuf[p - 1] = '\0'; if (resp == 1) | | | 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 | do { if (ssh_scp_recv((unsigned char *) &ch, 1) <= 0) bump("Protocol error: Lost connection"); rbuf[p++] = ch; } while (p < sizeof(rbuf) && ch != '\n'); rbuf[p - 1] = '\0'; if (resp == 1) tell_user(stderr, "%s\n", rbuf); else bump("%s", rbuf); errs++; return (-1); } } |
︙ | ︙ | |||
719 720 721 722 723 724 725 | } void scp_sftp_listdir(char *dirname) { struct fxp_handle *dirh; struct fxp_names *names; struct fxp_name *ournames; struct sftp_packet *pktin; | | | | > | | | > | | 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 | } void scp_sftp_listdir(char *dirname) { struct fxp_handle *dirh; struct fxp_names *names; struct fxp_name *ournames; struct sftp_packet *pktin; struct sftp_request *req, *rreq; int nnames, namesize; int i; if (!fxp_init()) { tell_user(stderr, "unable to initialise SFTP: %s", fxp_error()); errs++; return; } printf("Listing directory %s\n", dirname); sftp_register(req = fxp_opendir_send(dirname)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); dirh = fxp_opendir_recv(pktin, rreq); if (dirh == NULL) { printf("Unable to open %s: %s\n", dirname, fxp_error()); } else { nnames = namesize = 0; ournames = NULL; while (1) { sftp_register(req = fxp_readdir_send(dirh)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); names = fxp_readdir_recv(pktin, rreq); if (names == NULL) { if (fxp_error_type() == SSH_FX_EOF) break; printf("Reading directory %s: %s\n", dirname, fxp_error()); break; } |
︙ | ︙ | |||
768 769 770 771 772 773 774 | } for (i = 0; i < names->nnames; i++) ournames[nnames++] = names->names[i]; names->nnames = 0; /* prevent free_names */ fxp_free_names(names); } | | | > | < | < < | 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 | } for (i = 0; i < names->nnames; i++) ournames[nnames++] = names->names[i]; names->nnames = 0; /* prevent free_names */ fxp_free_names(names); } sftp_register(req = fxp_close_send(dirh)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); fxp_close_recv(pktin, rreq); /* * Now we have our filenames. Sort them by actual file * name, and then output the longname parts. */ qsort(ournames, nnames, sizeof(*ournames), sftp_ls_compare); /* * And print them. */ for (i = 0; i < nnames; i++) printf("%s\n", ournames[i].longname); } } /* ---------------------------------------------------------------------- * Helper routines that contain the actual SCP protocol elements, * implemented both as SCP1 and SFTP. */ |
︙ | ︙ | |||
820 821 822 823 824 825 826 | { if (using_sftp) { /* * Find out whether the target filespec is in fact a * directory. */ struct sftp_packet *pktin; | | | | > | | 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 | { if (using_sftp) { /* * Find out whether the target filespec is in fact a * directory. */ struct sftp_packet *pktin; struct sftp_request *req, *rreq; struct fxp_attrs attrs; int ret; if (!fxp_init()) { tell_user(stderr, "unable to initialise SFTP: %s", fxp_error()); errs++; return 1; } sftp_register(req = fxp_stat_send(target)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); ret = fxp_stat_recv(pktin, rreq, &attrs); if (!ret || !(attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS)) scp_sftp_targetisdir = 0; else scp_sftp_targetisdir = (attrs.permissions & 0040000) != 0; if (shouldbedir && !scp_sftp_targetisdir) { |
︙ | ︙ | |||
878 879 880 881 882 883 884 | char buf[80]; sprintf(buf, "T%lu 0 %lu 0\n", mtime, atime); back->send(backhandle, buf, strlen(buf)); return response(); } } | | | < < < < | | < | > | < < < | | | < < | 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 | char buf[80]; sprintf(buf, "T%lu 0 %lu 0\n", mtime, atime); back->send(backhandle, buf, strlen(buf)); return response(); } } int scp_send_filename(char *name, uint64 size, int modes) { if (using_sftp) { char *fullname; struct sftp_packet *pktin; struct sftp_request *req, *rreq; if (scp_sftp_targetisdir) { fullname = dupcat(scp_sftp_remotepath, "/", name, NULL); } else { fullname = dupstr(scp_sftp_remotepath); } sftp_register(req = fxp_open_send(fullname, SSH_FXF_WRITE | SSH_FXF_CREAT | SSH_FXF_TRUNC)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); scp_sftp_filehandle = fxp_open_recv(pktin, rreq); if (!scp_sftp_filehandle) { tell_user(stderr, "pscp: unable to open %s: %s", fullname, fxp_error()); errs++; return 1; } scp_sftp_fileoffset = uint64_make(0, 0); scp_sftp_xfer = xfer_upload_init(scp_sftp_filehandle, scp_sftp_fileoffset); sfree(fullname); return 0; } else { char buf[40]; char sizestr[40]; uint64_decimal(size, sizestr); sprintf(buf, "C%04o %s ", modes, sizestr); back->send(backhandle, buf, strlen(buf)); back->send(backhandle, name, strlen(name)); back->send(backhandle, "\n", 1); return response(); } } int scp_send_filedata(char *data, int len) { if (using_sftp) { int ret; struct sftp_packet *pktin; if (!scp_sftp_filehandle) { return 1; } while (!xfer_upload_ready(scp_sftp_xfer)) { pktin = sftp_recv(); ret = xfer_upload_gotpkt(scp_sftp_xfer, pktin); if (!ret) { tell_user(stderr, "error while writing: %s\n", fxp_error()); errs++; return 1; } } xfer_upload_data(scp_sftp_xfer, data, len); |
︙ | ︙ | |||
977 978 979 980 981 982 983 | } int scp_send_finish(void) { if (using_sftp) { struct fxp_attrs attrs; struct sftp_packet *pktin; | | | < < < < < < < | | > | | | | > | | 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 | } int scp_send_finish(void) { if (using_sftp) { struct fxp_attrs attrs; struct sftp_packet *pktin; struct sftp_request *req, *rreq; int ret; while (!xfer_done(scp_sftp_xfer)) { pktin = sftp_recv(); xfer_upload_gotpkt(scp_sftp_xfer, pktin); } xfer_cleanup(scp_sftp_xfer); if (!scp_sftp_filehandle) { return 1; } if (scp_has_times) { attrs.flags = SSH_FILEXFER_ATTR_ACMODTIME; attrs.atime = scp_sftp_atime; attrs.mtime = scp_sftp_mtime; sftp_register(req = fxp_fsetstat_send(scp_sftp_filehandle, attrs)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); ret = fxp_fsetstat_recv(pktin, rreq); if (!ret) { tell_user(stderr, "unable to set file times: %s\n", fxp_error()); errs++; } } sftp_register(req = fxp_close_send(scp_sftp_filehandle)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); fxp_close_recv(pktin, rreq); scp_has_times = 0; return 0; } else { back->send(backhandle, "", 1); return response(); } } |
︙ | ︙ | |||
1040 1041 1042 1043 1044 1045 1046 | int scp_send_dirname(char *name, int modes) { if (using_sftp) { char *fullname; char const *err; struct fxp_attrs attrs; struct sftp_packet *pktin; | | | | > | | | > | < | 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 | int scp_send_dirname(char *name, int modes) { if (using_sftp) { char *fullname; char const *err; struct fxp_attrs attrs; struct sftp_packet *pktin; struct sftp_request *req, *rreq; int ret; if (scp_sftp_targetisdir) { fullname = dupcat(scp_sftp_remotepath, "/", name, NULL); } else { fullname = dupstr(scp_sftp_remotepath); } /* * We don't worry about whether we managed to create the * directory, because if it exists already it's OK just to * use it. Instead, we will stat it afterwards, and if it * exists and is a directory we will assume we were either * successful or it didn't matter. */ sftp_register(req = fxp_mkdir_send(fullname)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); ret = fxp_mkdir_recv(pktin, rreq); if (!ret) err = fxp_error(); else err = "server reported no error"; sftp_register(req = fxp_stat_send(fullname)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); ret = fxp_stat_recv(pktin, rreq, &attrs); if (!ret || !(attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS) || !(attrs.permissions & 0040000)) { tell_user(stderr, "unable to create directory %s: %s", fullname, err); errs++; return 1; } scp_sftp_remotepath = fullname; return 0; |
︙ | ︙ | |||
1129 1130 1131 1132 1133 1134 1135 | * wildcardness comes before the final slash) and arrange * things so that a dirstack entry will be set up. */ newsource = snewn(1+strlen(source), char); if (!wc_unescape(newsource, source)) { /* Yes, here we go; it's a wildcard. Bah. */ char *dupsource, *lastpart, *dirpart, *wildcard; | < < < | 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 | * wildcardness comes before the final slash) and arrange * things so that a dirstack entry will be set up. */ newsource = snewn(1+strlen(source), char); if (!wc_unescape(newsource, source)) { /* Yes, here we go; it's a wildcard. Bah. */ char *dupsource, *lastpart, *dirpart, *wildcard; dupsource = dupstr(source); lastpart = stripslashes(dupsource, 0); wildcard = dupstr(lastpart); *lastpart = '\0'; if (*dupsource && dupsource[1]) { /* * The remains of dupsource are at least two |
︙ | ︙ | |||
1208 1209 1210 1211 1212 1213 1214 | #define SCP_SINK_DIR 2 #define SCP_SINK_ENDDIR 3 #define SCP_SINK_RETRY 4 /* not an action; just try again */ struct scp_sink_action { int action; /* FILE, DIR, ENDDIR */ char *buf; /* will need freeing after use */ char *name; /* filename or dirname (not ENDDIR) */ | | | | 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 | #define SCP_SINK_DIR 2 #define SCP_SINK_ENDDIR 3 #define SCP_SINK_RETRY 4 /* not an action; just try again */ struct scp_sink_action { int action; /* FILE, DIR, ENDDIR */ char *buf; /* will need freeing after use */ char *name; /* filename or dirname (not ENDDIR) */ int mode; /* access mode (not ENDDIR) */ uint64 size; /* file size (not ENDDIR) */ int settime; /* 1 if atime and mtime are filled */ unsigned long atime, mtime; /* access times for the file */ }; int scp_get_sink_action(struct scp_sink_action *act) { if (using_sftp) { char *fname; int must_free_fname; struct fxp_attrs attrs; struct sftp_packet *pktin; struct sftp_request *req, *rreq; int ret; if (!scp_sftp_dirstack_head) { if (!scp_sftp_donethistarget) { /* * Simple case: we are only dealing with one file. */ |
︙ | ︙ | |||
1290 1291 1292 1293 1294 1295 1296 | } } /* * Now we have a filename. Stat it, and see if it's a file * or a directory. */ | | | > | < | 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 | } } /* * Now we have a filename. Stat it, and see if it's a file * or a directory. */ sftp_register(req = fxp_stat_send(fname)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); ret = fxp_stat_recv(pktin, rreq, &attrs); if (!ret || !(attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS)) { tell_user(stderr, "unable to identify %s: %s", fname, ret ? "file type not supplied" : fxp_error()); errs++; return 1; } if (attrs.permissions & 0040000) { struct scp_sftp_dirstack *newitem; struct fxp_handle *dirhandle; |
︙ | ︙ | |||
1346 1347 1348 1349 1350 1351 1352 | * matching them against a wildcard if present. * * If targetisdir is _already_ set (meaning we're * already in the middle of going through another such * list), we must push the other (target,namelist) pair * on a stack. */ | | | > | | | | > | | < < < < < | 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 | * matching them against a wildcard if present. * * If targetisdir is _already_ set (meaning we're * already in the middle of going through another such * list), we must push the other (target,namelist) pair * on a stack. */ sftp_register(req = fxp_opendir_send(fname)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); dirhandle = fxp_opendir_recv(pktin, rreq); if (!dirhandle) { tell_user(stderr, "scp: unable to open directory %s: %s", fname, fxp_error()); if (must_free_fname) sfree(fname); errs++; return 1; } nnames = namesize = 0; ournames = NULL; while (1) { int i; sftp_register(req = fxp_readdir_send(dirhandle)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); names = fxp_readdir_recv(pktin, rreq); if (names == NULL) { if (fxp_error_type() == SSH_FX_EOF) break; tell_user(stderr, "scp: reading directory %s: %s\n", fname, fxp_error()); if (must_free_fname) sfree(fname); sfree(ournames); errs++; return 1; } if (names->nnames == 0) { fxp_free_names(names); |
︙ | ︙ | |||
1399 1400 1401 1402 1403 1404 1405 | /* * . and .. are normal consequences of * reading a directory, and aren't worth * complaining about. */ } else if (!vet_filename(names->names[i].filename)) { tell_user(stderr, "ignoring potentially dangerous server-" | | | | > | | 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 | /* * . and .. are normal consequences of * reading a directory, and aren't worth * complaining about. */ } else if (!vet_filename(names->names[i].filename)) { tell_user(stderr, "ignoring potentially dangerous server-" "supplied filename '%s'\n", names->names[i].filename); } else ournames[nnames++] = names->names[i]; } names->nnames = 0; /* prevent free_names */ fxp_free_names(names); } sftp_register(req = fxp_close_send(dirhandle)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); fxp_close_recv(pktin, rreq); newitem = snew(struct scp_sftp_dirstack); newitem->next = scp_sftp_dirstack_head; newitem->names = ournames; newitem->namepos = 0; newitem->namelen = nnames; if (must_free_fname) |
︙ | ︙ | |||
1436 1437 1438 1439 1440 1441 1442 | if (newitem->wildcard) { act->action = SCP_SINK_RETRY; } else { act->action = SCP_SINK_DIR; act->buf = dupstr(stripslashes(fname, 0)); act->name = act->buf; act->size = uint64_make(0,0); /* duhh, it's a directory */ | | | 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 | if (newitem->wildcard) { act->action = SCP_SINK_RETRY; } else { act->action = SCP_SINK_DIR; act->buf = dupstr(stripslashes(fname, 0)); act->name = act->buf; act->size = uint64_make(0,0); /* duhh, it's a directory */ act->mode = 07777 & attrs.permissions; if (scp_sftp_preserve && (attrs.flags & SSH_FILEXFER_ATTR_ACMODTIME)) { act->atime = attrs.atime; act->mtime = attrs.mtime; act->settime = 1; } else act->settime = 0; |
︙ | ︙ | |||
1458 1459 1460 1461 1462 1463 1464 | act->action = SCP_SINK_FILE; act->buf = dupstr(stripslashes(fname, 0)); act->name = act->buf; if (attrs.flags & SSH_FILEXFER_ATTR_SIZE) { act->size = attrs.size; } else act->size = uint64_make(ULONG_MAX,ULONG_MAX); /* no idea */ | | | 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 | act->action = SCP_SINK_FILE; act->buf = dupstr(stripslashes(fname, 0)); act->name = act->buf; if (attrs.flags & SSH_FILEXFER_ATTR_SIZE) { act->size = attrs.size; } else act->size = uint64_make(ULONG_MAX,ULONG_MAX); /* no idea */ act->mode = 07777 & attrs.permissions; if (scp_sftp_preserve && (attrs.flags & SSH_FILEXFER_ATTR_ACMODTIME)) { act->atime = attrs.atime; act->mtime = attrs.mtime; act->settime = 1; } else act->settime = 0; |
︙ | ︙ | |||
1502 1503 1504 1505 1506 1507 1508 | act->buf = sresize(act->buf, bufsize, char); } act->buf[i++] = ch; } while (ch != '\n'); act->buf[i - 1] = '\0'; switch (action) { case '\01': /* error */ | | | 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 | act->buf = sresize(act->buf, bufsize, char); } act->buf[i++] = ch; } while (ch != '\n'); act->buf[i - 1] = '\0'; switch (action) { case '\01': /* error */ tell_user(stderr, "%s\n", act->buf); errs++; continue; /* go round again */ case '\02': /* fatal error */ bump("%s", act->buf); case 'E': back->send(backhandle, "", 1); act->action = SCP_SINK_ENDDIR; |
︙ | ︙ | |||
1540 1541 1542 1543 1544 1545 1546 | /* * If we get here, we must have seen SCP_SINK_FILE or * SCP_SINK_DIR. */ { char sizestr[40]; | < | | | | > | | 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 | /* * If we get here, we must have seen SCP_SINK_FILE or * SCP_SINK_DIR. */ { char sizestr[40]; if (sscanf(act->buf, "%o %s %n", &act->mode, sizestr, &i) != 2) bump("Protocol error: Illegal file descriptor format"); act->size = uint64_from_decimal(sizestr); act->name = act->buf + i; return 0; } } } int scp_accept_filexfer(void) { if (using_sftp) { struct sftp_packet *pktin; struct sftp_request *req, *rreq; sftp_register(req = fxp_open_send(scp_sftp_currentname, SSH_FXF_READ)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); scp_sftp_filehandle = fxp_open_recv(pktin, rreq); if (!scp_sftp_filehandle) { tell_user(stderr, "pscp: unable to open %s: %s", scp_sftp_currentname, fxp_error()); errs++; return 1; } |
︙ | ︙ | |||
1587 1588 1589 1590 1591 1592 1593 | struct sftp_packet *pktin; int ret, actuallen; void *vbuf; xfer_download_queue(scp_sftp_xfer); pktin = sftp_recv(); ret = xfer_download_gotpkt(scp_sftp_xfer, pktin); | > | < < | 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 | struct sftp_packet *pktin; int ret, actuallen; void *vbuf; xfer_download_queue(scp_sftp_xfer); pktin = sftp_recv(); ret = xfer_download_gotpkt(scp_sftp_xfer, pktin); if (ret < 0) { tell_user(stderr, "pscp: error while reading: %s", fxp_error()); errs++; return -1; } if (xfer_download_data(scp_sftp_xfer, &vbuf, &actuallen)) { /* * This assertion relies on the fact that the natural |
︙ | ︙ | |||
1620 1621 1622 1623 1624 1625 1626 | } } int scp_finish_filerecv(void) { if (using_sftp) { struct sftp_packet *pktin; | | | | < < < < < < < | | > | | < | 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 | } } int scp_finish_filerecv(void) { if (using_sftp) { struct sftp_packet *pktin; struct sftp_request *req, *rreq; /* * Ensure that xfer_done() will work correctly, so we can * clean up any outstanding requests from the file * transfer. */ xfer_set_error(scp_sftp_xfer); while (!xfer_done(scp_sftp_xfer)) { void *vbuf; int len; pktin = sftp_recv(); xfer_download_gotpkt(scp_sftp_xfer, pktin); if (xfer_download_data(scp_sftp_xfer, &vbuf, &len)) sfree(vbuf); } xfer_cleanup(scp_sftp_xfer); sftp_register(req = fxp_close_send(scp_sftp_filehandle)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); fxp_close_recv(pktin, rreq); return 0; } else { back->send(backhandle, "", 1); return response(); } } /* ---------------------------------------------------------------------- * Send an error message to the other side and to the screen. * Increment error counter. */ static void run_err(const char *fmt, ...) { char *str, *str2; va_list ap; va_start(ap, fmt); errs++; str = dupvprintf(fmt, ap); str2 = dupcat("scp: ", str, "\n", NULL); sfree(str); scp_send_errmsg(str2); tell_user(stderr, "%s", str2); va_end(ap); sfree(str2); } /* * Execute the source part of the SCP protocol. */ static void source(char *src) { uint64 size; unsigned long mtime, atime; char *last; RFile *f; int attr; uint64 i; uint64 stat_bytes; time_t stat_starttime, stat_lasttime; |
︙ | ︙ | |||
1730 1731 1732 1733 1734 1735 1736 | else last++; if (strrchr(last, '\\') != NULL) last = strrchr(last, '\\') + 1; if (last == src && strchr(src, ':') != NULL) last = strchr(src, ':') + 1; | | | < < | < < | 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 | else last++; if (strrchr(last, '\\') != NULL) last = strrchr(last, '\\') + 1; if (last == src && strchr(src, ':') != NULL) last = strchr(src, ':') + 1; f = open_existing_file(src, &size, &mtime, &atime); if (f == NULL) { run_err("%s: Cannot open file", src); return; } if (preserve) { if (scp_send_filetimes(mtime, atime)) return; } if (verbose) { char sizestr[40]; uint64_decimal(size, sizestr); tell_user(stderr, "Sending file %s, size=%s", last, sizestr); } if (scp_send_filename(last, size, 0644)) return; stat_bytes = uint64_make(0,0); stat_starttime = time(NULL); stat_lasttime = 0; for (i = uint64_make(0,0); uint64_compare(i,size) < 0; |
︙ | ︙ | |||
1953 1954 1955 1956 1957 1958 1959 | } attr = file_type(destfname); exists = (attr != FILE_TYPE_NONEXISTENT); if (act.action == SCP_SINK_DIR) { if (exists && attr != FILE_TYPE_DIRECTORY) { run_err("%s: Not a directory", destfname); | < < < | < | < < < | 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 | } attr = file_type(destfname); exists = (attr != FILE_TYPE_NONEXISTENT); if (act.action == SCP_SINK_DIR) { if (exists && attr != FILE_TYPE_DIRECTORY) { run_err("%s: Not a directory", destfname); continue; } if (!exists) { if (!create_directory(destfname)) { run_err("%s: Cannot create directory", destfname); continue; } } sink(destfname, NULL); /* can we set the timestamp for directories ? */ continue; } f = open_new_file(destfname); if (f == NULL) { run_err("%s: Cannot create file", destfname); continue; } if (scp_accept_filexfer()) return; stat_bytes = uint64_make(0, 0); stat_starttime = time(NULL); stat_lasttime = 0; stat_name = stripslashes(destfname, 1); received = uint64_make(0, 0); |
︙ | ︙ | |||
2027 2028 2029 2030 2031 2032 2033 | if (act.settime) { set_file_times(f, act.mtime, act.atime); } close_wfile(f); if (wrerror) { run_err("%s: Write error", destfname); | < < < | 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 | if (act.settime) { set_file_times(f, act.mtime, act.atime); } close_wfile(f); if (wrerror) { run_err("%s: Write error", destfname); continue; } (void) scp_finish_filerecv(); sfree(destfname); sfree(act.buf); } } /* * We will copy local files to a remote server. */ static void toremote(int argc, char *argv[]) { char *src, *targ, *host, *user; char *cmd; int i, wc_type; targ = argv[argc - 1]; /* Separate host from filename */ host = targ; targ = colon(targ); if (targ == NULL) bump("targ == NULL in toremote()"); |
︙ | ︙ | |||
2136 2137 2138 2139 2140 2141 2142 | * We will copy files from a remote server to the local machine. */ static void tolocal(int argc, char *argv[]) { char *src, *targ, *host, *user; char *cmd; | < < | 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 | * We will copy files from a remote server to the local machine. */ static void tolocal(int argc, char *argv[]) { char *src, *targ, *host, *user; char *cmd; if (argc != 2) bump("More than one remote source not supported"); src = argv[0]; targ = argv[1]; /* Separate host from filename */ |
︙ | ︙ | |||
2303 2304 2305 2306 2307 2308 2309 | va_start(ap, p); vfprintf(stderr, p, ap); va_end(ap); fprintf(stderr, "\n try typing just \"pscp\" for help\n"); exit(1); } | < < < < | | | < < | < | 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 | va_start(ap, p); vfprintf(stderr, p, ap); va_end(ap); fprintf(stderr, "\n try typing just \"pscp\" for help\n"); exit(1); } /* * Main program. (Called `psftp_main' because it gets called from * *sftp.c; bit silly, I know, but it had to be called _something_.) */ int psftp_main(int argc, char *argv[]) { int i; default_protocol = PROT_TELNET; flags = FLAG_STDERR #ifdef FLAG_SYNCAGENT | FLAG_SYNCAGENT #endif ; cmdline_tooltype = TOOLTYPE_FILETRANSFER; sk_init(); /* Load Default Settings before doing anything else. */ do_defaults(NULL, &cfg); loaded_session = FALSE; for (i = 1; i < argc; i++) { int ret; if (argv[i][0] != '-') break; ret = cmdline_process_param(argv[i], i+1<argc?argv[i+1]:NULL, 1, &cfg); if (ret == -2) { cmdline_error("option \"%s\" requires an argument", argv[i]); } else if (ret == 2) { i++; /* skip next argument */ } else if (ret == 1) { /* We have our own verbosity in addition to `flags'. */ if (flags & FLAG_VERBOSE) verbose = 1; } else if (strcmp(argv[i], "-pgpfp") == 0) { pgp_fingerprints(); return 1; } else if (strcmp(argv[i], "-r") == 0) { recursive = 1; } else if (strcmp(argv[i], "-p") == 0) { preserve = 1; } else if (strcmp(argv[i], "-q") == 0) { statistics = 0; } else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "-?") == 0) { usage(); } else if (strcmp(argv[i], "-V") == 0) { version(); } else if (strcmp(argv[i], "-ls") == 0) { list = 1; } else if (strcmp(argv[i], "-batch") == 0) { console_batch_mode = 1; } else if (strcmp(argv[i], "-unsafe") == 0) { scp_unsafe_mode = 1; |
︙ | ︙ | |||
2400 2401 2402 2403 2404 2405 2406 | else tolocal(argc, argv); } if (back != NULL && back->connected(backhandle)) { char ch; back->special(backhandle, TS_EOF); | < | 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 | else tolocal(argc, argv); } if (back != NULL && back->connected(backhandle)) { char ch; back->special(backhandle, TS_EOF); ssh_scp_recv((unsigned char *) &ch, 1); } random_save_seed(); cmdline_cleanup(); console_provide_logctx(NULL); back->free(backhandle); |
︙ | ︙ |
Changes to psftp.c.
︙ | ︙ | |||
32 33 34 35 36 37 38 | /* ---------------------------------------------------------------------- * sftp client state. */ char *pwd, *homedir; static Backend *back; static void *backhandle; | | < < < < < < < < < < < < < < < < < < < < < | | | > | | 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | /* ---------------------------------------------------------------------- * sftp client state. */ char *pwd, *homedir; static Backend *back; static void *backhandle; static Config cfg; /* ---------------------------------------------------------------------- * Higher-level helper functions used in commands. */ /* * Attempt to canonify a pathname starting from the pwd. If * canonification fails, at least fall back to returning a _valid_ * pathname (though it may be ugly, eg /home/simon/../foobar). */ char *canonify(char *name) { char *fullname, *canonname; struct sftp_packet *pktin; struct sftp_request *req, *rreq; if (name[0] == '/') { fullname = dupstr(name); } else { char *slash; if (pwd[strlen(pwd) - 1] == '/') slash = ""; else slash = "/"; fullname = dupcat(pwd, slash, name, NULL); } sftp_register(req = fxp_realpath_send(fullname)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); canonname = fxp_realpath_recv(pktin, rreq); if (canonname) { sfree(fullname); return canonname; } else { /* * Attempt number 2. Some FXP_REALPATH implementations |
︙ | ︙ | |||
138 139 140 141 142 143 144 | /* * Now i points at the slash. Deal with the final special * case i==0 (ie the whole path was "/nonexistentfile"). */ fullname[i] = '\0'; /* separate the string */ if (i == 0) { | | | | > | | 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | /* * Now i points at the slash. Deal with the final special * case i==0 (ie the whole path was "/nonexistentfile"). */ fullname[i] = '\0'; /* separate the string */ if (i == 0) { sftp_register(req = fxp_realpath_send("/")); } else { sftp_register(req = fxp_realpath_send(fullname)); } rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); canonname = fxp_realpath_recv(pktin, rreq); if (!canonname) { /* Even that failed. Restore our best guess at the * constructed filename and give up */ fullname[i] = '/'; /* restore slash and last component */ return fullname; } |
︙ | ︙ | |||
222 223 224 225 226 227 228 | /* ---------------------------------------------------------------------- * The meat of the `get' and `put' commands. */ int sftp_get_file(char *fname, char *outfname, int recurse, int restart) { struct fxp_handle *fh; struct sftp_packet *pktin; | | < > | | > | | 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 | /* ---------------------------------------------------------------------- * The meat of the `get' and `put' commands. */ int sftp_get_file(char *fname, char *outfname, int recurse, int restart) { struct fxp_handle *fh; struct sftp_packet *pktin; struct sftp_request *req, *rreq; struct fxp_xfer *xfer; uint64 offset; WFile *file; int ret, shown_err = FALSE; /* * In recursive mode, see if we're dealing with a directory. * (If we're not in recursive mode, we need not even check: the * subsequent FXP_OPEN will return a usable error message.) */ if (recurse) { struct fxp_attrs attrs; int result; sftp_register(req = fxp_stat_send(fname)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); result = fxp_stat_recv(pktin, rreq, &attrs); if (result && (attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS) && (attrs.permissions & 0040000)) { struct fxp_handle *dirhandle; int nnames, namesize; |
︙ | ︙ | |||
265 266 267 268 269 270 271 | return 0; } /* * Now get the list of filenames in the remote * directory. */ | | | > | | | > | < < < < < | 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 | return 0; } /* * Now get the list of filenames in the remote * directory. */ sftp_register(req = fxp_opendir_send(fname)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); dirhandle = fxp_opendir_recv(pktin, rreq); if (!dirhandle) { printf("%s: unable to open directory: %s\n", fname, fxp_error()); return 0; } nnames = namesize = 0; ournames = NULL; while (1) { int i; sftp_register(req = fxp_readdir_send(dirhandle)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); names = fxp_readdir_recv(pktin, rreq); if (names == NULL) { if (fxp_error_type() == SSH_FX_EOF) break; printf("%s: reading directory: %s\n", fname, fxp_error()); sfree(ournames); return 0; } if (names->nnames == 0) { fxp_free_names(names); break; } |
︙ | ︙ | |||
317 318 319 320 321 322 323 | } else { ournames[nnames++] = fxp_dup_name(&names->names[i]); } } fxp_free_names(names); } | | | > | < | > | | > > | 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 | } else { ournames[nnames++] = fxp_dup_name(&names->names[i]); } } fxp_free_names(names); } sftp_register(req = fxp_close_send(dirhandle)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); fxp_close_recv(pktin, rreq); /* * Sort the names into a clear order. This ought to * make things more predictable when we're doing a * reget of the same directory, just in case two * readdirs on the same remote directory return a * different order. */ qsort(ournames, nnames, sizeof(*ournames), sftp_name_compare); /* * If we're in restart mode, find the last filename on * this list that already exists. We may have to do a * reget on _that_ file, but shouldn't have to do * anything on the previous files. * * If none of them exists, of course, we start at 0. */ i = 0; if (restart) { while (i < nnames) { char *nextoutfname; int ret; if (outfname) nextoutfname = dir_file_cat(outfname, ournames[i]->filename); else nextoutfname = dupstr(ournames[i]->filename); ret = (file_type(nextoutfname) == FILE_TYPE_NONEXISTENT); sfree(nextoutfname); if (ret) break; i++; } if (i > 0) |
︙ | ︙ | |||
367 368 369 370 371 372 373 | * call sftp_get_file again. */ for (; i < nnames; i++) { char *nextfname, *nextoutfname; int ret; nextfname = dupcat(fname, "/", ournames[i]->filename, NULL); | > | > > > | 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 | * call sftp_get_file again. */ for (; i < nnames; i++) { char *nextfname, *nextoutfname; int ret; nextfname = dupcat(fname, "/", ournames[i]->filename, NULL); if (outfname) nextoutfname = dir_file_cat(outfname, ournames[i]->filename); else nextoutfname = dupstr(ournames[i]->filename); ret = sftp_get_file(nextfname, nextoutfname, recurse, restart); restart = FALSE; /* after first partial file, do full */ sfree(nextoutfname); sfree(nextfname); if (!ret) { for (i = 0; i < nnames; i++) { fxp_free_name(ournames[i]); |
︙ | ︙ | |||
393 394 395 396 397 398 399 | } sfree(ournames); return 1; } } | < < < < < | | > | | | | > | | | > | | 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 | } sfree(ournames); return 1; } } sftp_register(req = fxp_open_send(fname, SSH_FXF_READ)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); fh = fxp_open_recv(pktin, rreq); if (!fh) { printf("%s: open for read: %s\n", fname, fxp_error()); return 0; } if (restart) { file = open_existing_wfile(outfname, NULL); } else { file = open_new_file(outfname); } if (!file) { printf("local: unable to open %s\n", outfname); sftp_register(req = fxp_close_send(fh)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); fxp_close_recv(pktin, rreq); return 0; } if (restart) { char decbuf[30]; if (seek_file(file, uint64_make(0,0) , FROM_END) == -1) { close_wfile(file); printf("reget: cannot restart %s - file too large\n", outfname); sftp_register(req = fxp_close_send(fh)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); fxp_close_recv(pktin, rreq); return 0; } offset = get_file_posn(file); uint64_decimal(offset, decbuf); printf("reget: restarting at file position %s\n", decbuf); |
︙ | ︙ | |||
459 460 461 462 463 464 465 | void *vbuf; int ret, len; int wpos, wlen; xfer_download_queue(xfer); pktin = sftp_recv(); ret = xfer_download_gotpkt(xfer, pktin); | > | < < | 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 | void *vbuf; int ret, len; int wpos, wlen; xfer_download_queue(xfer); pktin = sftp_recv(); ret = xfer_download_gotpkt(xfer, pktin); if (ret < 0) { if (!shown_err) { printf("error while reading: %s\n", fxp_error()); shown_err = TRUE; } ret = 0; } while (xfer_download_data(xfer, &vbuf, &len)) { unsigned char *buf = (unsigned char *)vbuf; wpos = 0; |
︙ | ︙ | |||
496 497 498 499 500 501 502 | } } xfer_cleanup(xfer); close_wfile(file); | | | > | | < < > | | > | | | > | | 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 | } } xfer_cleanup(xfer); close_wfile(file); sftp_register(req = fxp_close_send(fh)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); fxp_close_recv(pktin, rreq); return ret; } int sftp_put_file(char *fname, char *outfname, int recurse, int restart) { struct fxp_handle *fh; struct fxp_xfer *xfer; struct sftp_packet *pktin; struct sftp_request *req, *rreq; uint64 offset; RFile *file; int ret, err, eof; /* * In recursive mode, see if we're dealing with a directory. * (If we're not in recursive mode, we need not even check: the * subsequent fopen will return an error message.) */ if (recurse && file_type(fname) == FILE_TYPE_DIRECTORY) { struct fxp_attrs attrs; int result; int nnames, namesize; char *name, **ournames; DirHandle *dh; int i; /* * First, attempt to create the destination directory, * unless it already exists. */ sftp_register(req = fxp_stat_send(outfname)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); result = fxp_stat_recv(pktin, rreq, &attrs); if (!result || !(attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS) || !(attrs.permissions & 0040000)) { sftp_register(req = fxp_mkdir_send(outfname)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); result = fxp_mkdir_recv(pktin, rreq); if (!result) { printf("%s: create directory: %s\n", outfname, fxp_error()); return 0; } } |
︙ | ︙ | |||
574 575 576 577 578 579 580 | /* * Sort the names into a clear order. This ought to make * things more predictable when we're doing a reput of the * same directory, just in case two readdirs on the same * local directory return a different order. */ | < | | | > | > | > > | 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 | /* * Sort the names into a clear order. This ought to make * things more predictable when we're doing a reput of the * same directory, just in case two readdirs on the same * local directory return a different order. */ qsort(ournames, nnames, sizeof(*ournames), bare_name_compare); /* * If we're in restart mode, find the last filename on this * list that already exists. We may have to do a reput on * _that_ file, but shouldn't have to do anything on the * previous files. * * If none of them exists, of course, we start at 0. */ i = 0; if (restart) { while (i < nnames) { char *nextoutfname; nextoutfname = dupcat(outfname, "/", ournames[i], NULL); sftp_register(req = fxp_stat_send(nextoutfname)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); result = fxp_stat_recv(pktin, rreq, &attrs); sfree(nextoutfname); if (!result) break; i++; } if (i > 0) i--; } /* * Now we're ready to recurse. Starting at ournames[i] * and continuing on to the end of the list, we * construct a new source and target file name, and * call sftp_put_file again. */ for (; i < nnames; i++) { char *nextfname, *nextoutfname; int ret; if (fname) nextfname = dir_file_cat(fname, ournames[i]); else nextfname = dupstr(ournames[i]); nextoutfname = dupcat(outfname, "/", ournames[i], NULL); ret = sftp_put_file(nextfname, nextoutfname, recurse, restart); restart = FALSE; /* after first partial file, do full */ sfree(nextoutfname); sfree(nextfname); if (!ret) { for (i = 0; i < nnames; i++) { |
︙ | ︙ | |||
638 639 640 641 642 643 644 | sfree(ournames[i]); } sfree(ournames); return 1; } | | < < | | | < | > | | | > | | 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 | sfree(ournames[i]); } sfree(ournames); return 1; } file = open_existing_file(fname, NULL, NULL, NULL); if (!file) { printf("local: unable to open %s\n", fname); return 0; } if (restart) { sftp_register(req = fxp_open_send(outfname, SSH_FXF_WRITE)); } else { sftp_register(req = fxp_open_send(outfname, SSH_FXF_WRITE | SSH_FXF_CREAT | SSH_FXF_TRUNC)); } rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); fh = fxp_open_recv(pktin, rreq); if (!fh) { close_rfile(file); printf("%s: open for write: %s\n", outfname, fxp_error()); return 0; } if (restart) { char decbuf[30]; struct fxp_attrs attrs; int ret; sftp_register(req = fxp_fstat_send(fh)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); ret = fxp_fstat_recv(pktin, rreq, &attrs); if (!ret) { close_rfile(file); printf("read size of %s: %s\n", outfname, fxp_error()); return 0; } if (!(attrs.flags & SSH_FILEXFER_ATTR_SIZE)) { |
︙ | ︙ | |||
718 719 720 721 722 723 724 | xfer_upload_data(xfer, buffer, len); } } if (!xfer_done(xfer)) { pktin = sftp_recv(); ret = xfer_upload_gotpkt(xfer, pktin); | | < < < | | < | | > | | 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 | xfer_upload_data(xfer, buffer, len); } } if (!xfer_done(xfer)) { pktin = sftp_recv(); ret = xfer_upload_gotpkt(xfer, pktin); if (ret <= 0 && !err) { printf("error while writing: %s\n", fxp_error()); err = 1; } } } xfer_cleanup(xfer); sftp_register(req = fxp_close_send(fh)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); fxp_close_recv(pktin, rreq); close_rfile(file); return ret; } /* ---------------------------------------------------------------------- |
︙ | ︙ | |||
755 756 757 758 759 760 761 | int namepos; char *wildcard, *prefix; } SftpWildcardMatcher; SftpWildcardMatcher *sftp_begin_wildcard_matching(char *name) { struct sftp_packet *pktin; | | | 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 | int namepos; char *wildcard, *prefix; } SftpWildcardMatcher; SftpWildcardMatcher *sftp_begin_wildcard_matching(char *name) { struct sftp_packet *pktin; struct sftp_request *req, *rreq; char *wildcard; char *unwcdir, *tmpdir, *cdir; int len, check; SftpWildcardMatcher *swcm; struct fxp_handle *dirh; /* |
︙ | ︙ | |||
786 787 788 789 790 791 792 | printf("Multiple-level wildcards are not supported\n"); sfree(unwcdir); return NULL; } cdir = canonify(unwcdir); | | | > | | 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 | printf("Multiple-level wildcards are not supported\n"); sfree(unwcdir); return NULL; } cdir = canonify(unwcdir); sftp_register(req = fxp_opendir_send(cdir)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); dirh = fxp_opendir_recv(pktin, rreq); if (dirh) { swcm = snew(SftpWildcardMatcher); swcm->dirh = dirh; swcm->names = NULL; swcm->wildcard = dupstr(wildcard); swcm->prefix = unwcdir; |
︙ | ︙ | |||
811 812 813 814 815 816 817 | return swcm; } char *sftp_wildcard_get_filename(SftpWildcardMatcher *swcm) { struct fxp_name *name; struct sftp_packet *pktin; | | | | > | < < < < < < < < < < | | 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 | return swcm; } char *sftp_wildcard_get_filename(SftpWildcardMatcher *swcm) { struct fxp_name *name; struct sftp_packet *pktin; struct sftp_request *req, *rreq; while (1) { if (swcm->names && swcm->namepos >= swcm->names->nnames) { fxp_free_names(swcm->names); swcm->names = NULL; } if (!swcm->names) { sftp_register(req = fxp_readdir_send(swcm->dirh)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); swcm->names = fxp_readdir_recv(pktin, rreq); if (!swcm->names) { if (fxp_error_type() != SSH_FX_EOF) printf("%s: reading directory: %s\n", swcm->prefix, fxp_error()); return NULL; } swcm->namepos = 0; } assert(swcm->names && swcm->namepos < swcm->names->nnames); name = &swcm->names->names[swcm->namepos++]; |
︙ | ︙ | |||
874 875 876 877 878 879 880 | name->filename); } } void sftp_finish_wildcard_matching(SftpWildcardMatcher *swcm) { struct sftp_packet *pktin; | | | | > | | 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 | name->filename); } } void sftp_finish_wildcard_matching(SftpWildcardMatcher *swcm) { struct sftp_packet *pktin; struct sftp_request *req, *rreq; sftp_register(req = fxp_close_send(swcm->dirh)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); fxp_close_recv(pktin, rreq); if (swcm->names) fxp_free_names(swcm->names); sfree(swcm->prefix); sfree(swcm->wildcard); |
︙ | ︙ | |||
918 919 920 921 922 923 924 | while ( (newname = sftp_wildcard_get_filename(swcm)) != NULL ) { cname = canonify(newname); if (!cname) { printf("%s: canonify: %s\n", newname, fxp_error()); ret = 0; } | < | 895 896 897 898 899 900 901 902 903 904 905 906 907 908 | while ( (newname = sftp_wildcard_get_filename(swcm)) != NULL ) { cname = canonify(newname); if (!cname) { printf("%s: canonify: %s\n", newname, fxp_error()); ret = 0; } matched = TRUE; ret &= func(ctx, cname); sfree(cname); } if (!matched) { /* Politely warn the user that nothing matched. */ |
︙ | ︙ | |||
990 991 992 993 994 995 996 | not_connected(); return 0; } if (back != NULL && back->connected(backhandle)) { char ch; back->special(backhandle, TS_EOF); | < | < | 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 | not_connected(); return 0; } if (back != NULL && back->connected(backhandle)) { char ch; back->special(backhandle, TS_EOF); sftp_recvdata(&ch, 1); } do_sftp_cleanup(); return 0; } /* * List a directory. If no arguments are given, list pwd; otherwise * list the directory given in words[1]. */ int sftp_cmd_ls(struct sftp_command *cmd) { struct fxp_handle *dirh; struct fxp_names *names; struct fxp_name **ournames; int nnames, namesize; char *dir, *cdir, *unwcdir, *wildcard; struct sftp_packet *pktin; struct sftp_request *req, *rreq; int i; if (back == NULL) { not_connected(); return 0; } if (cmd->nwords < 2) dir = "."; else dir = cmd->words[1]; unwcdir = snewn(1 + strlen(dir), char); if (wc_unescape(unwcdir, dir)) { dir = unwcdir; wildcard = NULL; } else { char *tmpdir; int len, check; wildcard = stripslashes(dir, 0); unwcdir = dupstr(dir); len = wildcard - dir; unwcdir[len] = '\0'; if (len > 0 && unwcdir[len-1] == '/') unwcdir[len-1] = '\0'; tmpdir = snewn(1 + len, char); |
︙ | ︙ | |||
1058 1059 1060 1061 1062 1063 1064 | printf("%s: canonify: %s\n", dir, fxp_error()); sfree(unwcdir); return 0; } printf("Listing directory %s\n", cdir); | | | > | | | > | | 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 | printf("%s: canonify: %s\n", dir, fxp_error()); sfree(unwcdir); return 0; } printf("Listing directory %s\n", cdir); sftp_register(req = fxp_opendir_send(cdir)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); dirh = fxp_opendir_recv(pktin, rreq); if (dirh == NULL) { printf("Unable to open %s: %s\n", dir, fxp_error()); } else { nnames = namesize = 0; ournames = NULL; while (1) { sftp_register(req = fxp_readdir_send(dirh)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); names = fxp_readdir_recv(pktin, rreq); if (names == NULL) { if (fxp_error_type() == SSH_FX_EOF) break; printf("Reading directory %s: %s\n", dir, fxp_error()); break; } |
︙ | ︙ | |||
1096 1097 1098 1099 1100 1101 1102 | for (i = 0; i < names->nnames; i++) if (!wildcard || wc_match(wildcard, names->names[i].filename)) ournames[nnames++] = fxp_dup_name(&names->names[i]); fxp_free_names(names); } | | | > | < | | 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 | for (i = 0; i < names->nnames; i++) if (!wildcard || wc_match(wildcard, names->names[i].filename)) ournames[nnames++] = fxp_dup_name(&names->names[i]); fxp_free_names(names); } sftp_register(req = fxp_close_send(dirh)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); fxp_close_recv(pktin, rreq); /* * Now we have our filenames. Sort them by actual file * name, and then output the longname parts. */ qsort(ournames, nnames, sizeof(*ournames), sftp_name_compare); /* * And print them. */ for (i = 0; i < nnames; i++) { printf("%s\n", ournames[i]->longname); fxp_free_name(ournames[i]); |
︙ | ︙ | |||
1131 1132 1133 1134 1135 1136 1137 | * Change directories. We do this by canonifying the new name, then * trying to OPENDIR it. Only if that succeeds do we set the new pwd. */ int sftp_cmd_cd(struct sftp_command *cmd) { struct fxp_handle *dirh; struct sftp_packet *pktin; | | | | > | | | > | | 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 | * Change directories. We do this by canonifying the new name, then * trying to OPENDIR it. Only if that succeeds do we set the new pwd. */ int sftp_cmd_cd(struct sftp_command *cmd) { struct fxp_handle *dirh; struct sftp_packet *pktin; struct sftp_request *req, *rreq; char *dir; if (back == NULL) { not_connected(); return 0; } if (cmd->nwords < 2) dir = dupstr(homedir); else dir = canonify(cmd->words[1]); if (!dir) { printf("%s: canonify: %s\n", dir, fxp_error()); return 0; } sftp_register(req = fxp_opendir_send(dir)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); dirh = fxp_opendir_recv(pktin, rreq); if (!dirh) { printf("Directory %s: %s\n", dir, fxp_error()); sfree(dir); return 0; } sftp_register(req = fxp_close_send(dirh)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); fxp_close_recv(pktin, rreq); sfree(pwd); pwd = dir; printf("Remote directory is now %s\n", pwd); return 1; } |
︙ | ︙ | |||
1254 1255 1256 1257 1258 1259 1260 | swcm = NULL; } while (origwfname) { fname = canonify(origwfname); if (!fname) { | < < | 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 | swcm = NULL; } while (origwfname) { fname = canonify(origwfname); if (!fname) { printf("%s: canonify: %s\n", origwfname, fxp_error()); sfree(unwcfname); return 0; } if (!multiple && i < cmd->nwords) outfname = cmd->words[i++]; else |
︙ | ︙ | |||
1412 1413 1414 1415 1416 1417 1418 | return sftp_general_put(cmd, 1, 0); } int sftp_cmd_mkdir(struct sftp_command *cmd) { char *dir; struct sftp_packet *pktin; | | | 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 | return sftp_general_put(cmd, 1, 0); } int sftp_cmd_mkdir(struct sftp_command *cmd) { char *dir; struct sftp_packet *pktin; struct sftp_request *req, *rreq; int result; int i, ret; if (back == NULL) { not_connected(); return 0; } |
︙ | ︙ | |||
1434 1435 1436 1437 1438 1439 1440 | for (i = 1; i < cmd->nwords; i++) { dir = canonify(cmd->words[i]); if (!dir) { printf("%s: canonify: %s\n", dir, fxp_error()); return 0; } | | | > | | | | > | | 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 | for (i = 1; i < cmd->nwords; i++) { dir = canonify(cmd->words[i]); if (!dir) { printf("%s: canonify: %s\n", dir, fxp_error()); return 0; } sftp_register(req = fxp_mkdir_send(dir)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); result = fxp_mkdir_recv(pktin, rreq); if (!result) { printf("mkdir %s: %s\n", dir, fxp_error()); ret = 0; } else printf("mkdir %s: OK\n", dir); sfree(dir); } return ret; } static int sftp_action_rmdir(void *vctx, char *dir) { struct sftp_packet *pktin; struct sftp_request *req, *rreq; int result; sftp_register(req = fxp_rmdir_send(dir)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); result = fxp_rmdir_recv(pktin, rreq); if (!result) { printf("rmdir %s: %s\n", dir, fxp_error()); return 0; } printf("rmdir %s: OK\n", dir); |
︙ | ︙ | |||
1494 1495 1496 1497 1498 1499 1500 | return ret; } static int sftp_action_rm(void *vctx, char *fname) { struct sftp_packet *pktin; | | | | > | | 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 | return ret; } static int sftp_action_rm(void *vctx, char *fname) { struct sftp_packet *pktin; struct sftp_request *req, *rreq; int result; sftp_register(req = fxp_remove_send(fname)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); result = fxp_remove_recv(pktin, rreq); if (!result) { printf("rm %s: %s\n", fname, fxp_error()); return 0; } printf("rm %s: OK\n", fname); |
︙ | ︙ | |||
1535 1536 1537 1538 1539 1540 1541 | return ret; } static int check_is_dir(char *dstfname) { struct sftp_packet *pktin; | | | | > | | | 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 | return ret; } static int check_is_dir(char *dstfname) { struct sftp_packet *pktin; struct sftp_request *req, *rreq; struct fxp_attrs attrs; int result; sftp_register(req = fxp_stat_send(dstfname)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); result = fxp_stat_recv(pktin, rreq, &attrs); if (result && (attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS) && (attrs.permissions & 0040000)) return TRUE; else return FALSE; } struct sftp_context_mv { char *dstfname; int dest_is_dir; }; static int sftp_action_mv(void *vctx, char *srcfname) { struct sftp_context_mv *ctx = (struct sftp_context_mv *)vctx; struct sftp_packet *pktin; struct sftp_request *req, *rreq; const char *error; char *finalfname, *newcanon = NULL; int ret, result; if (ctx->dest_is_dir) { char *p; char *newname; |
︙ | ︙ | |||
1585 1586 1587 1588 1589 1590 1591 | sfree(newname); finalfname = newcanon; } else { finalfname = ctx->dstfname; } | | | > | | 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 | sfree(newname); finalfname = newcanon; } else { finalfname = ctx->dstfname; } sftp_register(req = fxp_rename_send(srcfname, finalfname)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); result = fxp_rename_recv(pktin, rreq); error = result ? NULL : fxp_error(); if (error) { printf("mv %s %s: %s\n", srcfname, finalfname, error); ret = 0; } else { |
︙ | ︙ | |||
1656 1657 1658 1659 1660 1661 1662 | unsigned attrs_clr, attrs_xor; }; static int sftp_action_chmod(void *vctx, char *fname) { struct fxp_attrs attrs; struct sftp_packet *pktin; | | | | > | | | > | | 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 | unsigned attrs_clr, attrs_xor; }; static int sftp_action_chmod(void *vctx, char *fname) { struct fxp_attrs attrs; struct sftp_packet *pktin; struct sftp_request *req, *rreq; int result; unsigned oldperms, newperms; struct sftp_context_chmod *ctx = (struct sftp_context_chmod *)vctx; sftp_register(req = fxp_stat_send(fname)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); result = fxp_stat_recv(pktin, rreq, &attrs); if (!result || !(attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS)) { printf("get attrs for %s: %s\n", fname, result ? "file permissions not provided" : fxp_error()); return 0; } attrs.flags = SSH_FILEXFER_ATTR_PERMISSIONS; /* perms _only_ */ oldperms = attrs.permissions & 07777; attrs.permissions &= ~ctx->attrs_clr; attrs.permissions ^= ctx->attrs_xor; newperms = attrs.permissions & 07777; if (oldperms == newperms) return 1; /* no need to do anything! */ sftp_register(req = fxp_setstat_send(fname, attrs)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); result = fxp_setstat_recv(pktin, rreq); if (!result) { printf("set attrs for %s: %s\n", fname, fxp_error()); return 0; } printf("%s: %04o -> %04o\n", fname, oldperms, newperms); |
︙ | ︙ | |||
2232 2233 2234 2235 2236 2237 2238 | line = ssh_sftp_get_cmdline("psftp> ", back == NULL); } if (!line || !*line) { cmd->obey = sftp_cmd_quit; if ((mode == 0) || (modeflags & 1)) printf("quit\n"); | < | 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 | line = ssh_sftp_get_cmdline("psftp> ", back == NULL); } if (!line || !*line) { cmd->obey = sftp_cmd_quit; if ((mode == 0) || (modeflags & 1)) printf("quit\n"); return cmd; /* eof */ } line[strcspn(line, "\r\n")] = '\0'; if (modeflags & 1) { printf("%s\n", line); |
︙ | ︙ | |||
2279 2280 2281 2282 2283 2284 2285 | * becomes * * >firstword< * >second word< * >this has "quotes" in< * >and"this"< */ | | < < < | 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 | * becomes * * >firstword< * >second word< * >this has "quotes" in< * >and"this"< */ while (*p) { /* skip whitespace */ while (*p && (*p == ' ' || *p == '\t')) p++; /* mark start of word */ q = r = p; /* q sits at start, r writes word */ quoting = 0; while (*p) { if (!quoting && (*p == ' ' || *p == '\t')) break; /* reached end of word */ else if (*p == '"' && p[1] == '"') |
︙ | ︙ | |||
2333 2334 2335 2336 2337 2338 2339 | return cmd; } static int do_sftp_init(void) { struct sftp_packet *pktin; | | | | > | < | 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 | return cmd; } static int do_sftp_init(void) { struct sftp_packet *pktin; struct sftp_request *req, *rreq; /* * Do protocol initialisation. */ if (!fxp_init()) { fprintf(stderr, "Fatal: unable to initialise SFTP: %s\n", fxp_error()); return 1; /* failure */ } /* * Find out where our home directory is. */ sftp_register(req = fxp_realpath_send(".")); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); homedir = fxp_realpath_recv(pktin, rreq); if (!homedir) { fprintf(stderr, "Warning: failed to resolve home directory: %s\n", fxp_error()); homedir = dupstr("."); } else { printf("Remote working directory is %s\n", homedir); } pwd = dupstr(homedir); return 0; } void do_sftp_cleanup() { char ch; if (back) { back->special(backhandle, TS_EOF); sftp_recvdata(&ch, 1); back->free(backhandle); sftp_cleanup_request(); back = NULL; backhandle = NULL; } if (pwd) { |
︙ | ︙ | |||
2475 2476 2477 2478 2479 2480 2481 | sfree(str); va_end(ap); fputs(str2, stderr); sfree(str2); cleanup_exit(1); } | < < < < < < < < < < < < | 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 | sfree(str); va_end(ap); fputs(str2, stderr); sfree(str2); cleanup_exit(1); } void connection_fatal(void *frontend, char *fmt, ...) { char *str, *str2; va_list ap; va_start(ap, fmt); str = dupvprintf(fmt, ap); str2 = dupcat("Fatal: ", str, "\n", NULL); |
︙ | ︙ | |||
2589 2590 2591 2592 2593 2594 2595 | /* * No "untrusted" output should get here (the way the code is * currently, it's all diverted by FLAG_STDERR). */ assert(!"Unexpected call to from_backend_untrusted()"); return 0; /* not reached */ } | < < < < < < < < < < < < < | 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 | /* * No "untrusted" output should get here (the way the code is * currently, it's all diverted by FLAG_STDERR). */ assert(!"Unexpected call to from_backend_untrusted()"); return 0; /* not reached */ } int sftp_recvdata(char *buf, int len) { outptr = (unsigned char *) buf; outlen = len; /* * See if the pending-input block contains some of what we |
︙ | ︙ | |||
2706 2707 2708 2709 2710 2711 2712 | /* * If we haven't loaded session details already (e.g., from -load), * try looking for a session called "host". */ if (!loaded_session) { /* Try to load settings for `host' into a temporary config */ | | | | | | | > < | > | | | | | | | | | < | < < < < < | < < | | > | | | > > | | | | > > > > > | | < > | | | | | | | | < | | > | | | > | | < < < < < | | | | | < | < | | | < < < | | | 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 | /* * If we haven't loaded session details already (e.g., from -load), * try looking for a session called "host". */ if (!loaded_session) { /* Try to load settings for `host' into a temporary config */ Config cfg2; cfg2.host[0] = '\0'; do_defaults(host, &cfg2); if (cfg2.host[0] != '\0') { /* Settings present and include hostname */ /* Re-load data into the real config. */ do_defaults(host, &cfg); } else { /* Session doesn't exist or mention a hostname. */ /* Use `host' as a bare hostname. */ strncpy(cfg.host, host, sizeof(cfg.host) - 1); cfg.host[sizeof(cfg.host) - 1] = '\0'; } } else { /* Patch in hostname `host' to session details. */ strncpy(cfg.host, host, sizeof(cfg.host) - 1); cfg.host[sizeof(cfg.host) - 1] = '\0'; } /* * Force use of SSH. (If they got the protocol wrong we assume the * port is useless too.) */ if (cfg.protocol != PROT_SSH) { cfg.protocol = PROT_SSH; cfg.port = 22; } /* * If saved session / Default Settings says SSH-1 (`1 only' or `1'), * then change it to SSH-2, on the grounds that that's more likely to * work for SFTP. (Can be overridden with `-1' option.) * But if it says `2 only' or `2', respect which. */ if (cfg.sshprot != 2 && cfg.sshprot != 3) cfg.sshprot = 2; /* * Enact command-line overrides. */ cmdline_run_saved(&cfg); /* * Trim leading whitespace off the hostname if it's there. */ { int space = strspn(cfg.host, " \t"); memmove(cfg.host, cfg.host+space, 1+strlen(cfg.host)-space); } /* See if host is of the form user@host */ if (cfg.host[0] != '\0') { char *atsign = strrchr(cfg.host, '@'); /* Make sure we're not overflowing the user field */ if (atsign) { if (atsign - cfg.host < sizeof cfg.username) { strncpy(cfg.username, cfg.host, atsign - cfg.host); cfg.username[atsign - cfg.host] = '\0'; } memmove(cfg.host, atsign + 1, 1 + strlen(atsign + 1)); } } /* * Trim a colon suffix off the hostname if it's there. */ cfg.host[strcspn(cfg.host, ":")] = '\0'; /* * Remove any remaining whitespace from the hostname. */ { int p1 = 0, p2 = 0; while (cfg.host[p2] != '\0') { if (cfg.host[p2] != ' ' && cfg.host[p2] != '\t') { cfg.host[p1] = cfg.host[p2]; p1++; } p2++; } cfg.host[p1] = '\0'; } /* Set username */ if (user != NULL && user[0] != '\0') { strncpy(cfg.username, user, sizeof(cfg.username) - 1); cfg.username[sizeof(cfg.username) - 1] = '\0'; } if (portnumber) cfg.port = portnumber; /* * Disable scary things which shouldn't be enabled for simple * things like SCP and SFTP: agent forwarding, port forwarding, * X forwarding. */ cfg.x11_forward = 0; cfg.agentfwd = 0; cfg.portfwd[0] = cfg.portfwd[1] = '\0'; cfg.ssh_simple = TRUE; /* Set up subsystem name. */ strcpy(cfg.remote_cmd, "sftp"); cfg.ssh_subsys = TRUE; cfg.nopty = TRUE; /* * Set up fallback option, for SSH-1 servers or servers with the * sftp subsystem not enabled but the server binary installed * in the usual place. We only support fallback on Unix * systems, and we use a kludgy piece of shellery which should * try to find sftp-server in various places (the obvious * systemwide spots /usr/lib and /usr/local/lib, and then the * user's PATH) and finally give up. * * test -x /usr/lib/sftp-server && exec /usr/lib/sftp-server * test -x /usr/local/lib/sftp-server && exec /usr/local/lib/sftp-server * exec sftp-server * * the idea being that this will attempt to use either of the * obvious pathnames and then give up, and when it does give up * it will print the preferred pathname in the error messages. */ cfg.remote_cmd_ptr2 = "test -x /usr/lib/sftp-server && exec /usr/lib/sftp-server\n" "test -x /usr/local/lib/sftp-server && exec /usr/local/lib/sftp-server\n" "exec sftp-server"; cfg.ssh_subsys2 = FALSE; back = &ssh_backend; err = back->init(NULL, &backhandle, &cfg, cfg.host, cfg.port, &realhost, 0, cfg.tcp_keepalives); if (err != NULL) { fprintf(stderr, "ssh_init: %s\n", err); return 1; } logctx = log_init(NULL, &cfg); back->provide_logctx(backhandle, logctx); console_provide_logctx(logctx); while (!back->sendok(backhandle)) { if (back->exitcode(backhandle) >= 0) return 1; if (ssh_sftp_loop_iteration() < 0) { fprintf(stderr, "ssh_init: error during SSH connection setup\n"); |
︙ | ︙ | |||
2881 2882 2883 2884 2885 2886 2887 | va_start(ap, p); vfprintf(stderr, p, ap); va_end(ap); fprintf(stderr, "\n try typing \"psftp -h\" for help\n"); exit(1); } | < < < | 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 | va_start(ap, p); vfprintf(stderr, p, ap); va_end(ap); fprintf(stderr, "\n try typing \"psftp -h\" for help\n"); exit(1); } /* * Main program. Parse arguments etc. */ int psftp_main(int argc, char *argv[]) { int i; int portnumber = 0; |
︙ | ︙ | |||
2907 2908 2909 2910 2911 2912 2913 | ; cmdline_tooltype = TOOLTYPE_FILETRANSFER; sk_init(); userhost = user = NULL; /* Load Default Settings before doing anything else. */ | < | | | < | < | 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 | ; cmdline_tooltype = TOOLTYPE_FILETRANSFER; sk_init(); userhost = user = NULL; /* Load Default Settings before doing anything else. */ do_defaults(NULL, &cfg); loaded_session = FALSE; for (i = 1; i < argc; i++) { int ret; if (argv[i][0] != '-') { if (userhost) usage(); else userhost = dupstr(argv[i]); continue; } ret = cmdline_process_param(argv[i], i+1<argc?argv[i+1]:NULL, 1, &cfg); if (ret == -2) { cmdline_error("option \"%s\" requires an argument", argv[i]); } else if (ret == 2) { i++; /* skip next argument */ } else if (ret == 1) { /* We have our own verbosity in addition to `flags'. */ if (flags & FLAG_VERBOSE) verbose = 1; } else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "-?") == 0) { usage(); } else if (strcmp(argv[i], "-pgpfp") == 0) { pgp_fingerprints(); return 1; } else if (strcmp(argv[i], "-V") == 0) { version(); } else if (strcmp(argv[i], "-batch") == 0) { console_batch_mode = 1; } else if (strcmp(argv[i], "-b") == 0 && i + 1 < argc) { mode = 1; batchfile = argv[++i]; } else if (strcmp(argv[i], "-bc") == 0) { |
︙ | ︙ | |||
2964 2965 2966 2967 2968 2969 2970 | back = NULL; /* * If the loaded session provides a hostname, and a hostname has not * otherwise been specified, pop it in `userhost' so that * `psftp -load sessname' is sufficient to start a session. */ | | | | 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 | back = NULL; /* * If the loaded session provides a hostname, and a hostname has not * otherwise been specified, pop it in `userhost' so that * `psftp -load sessname' is sufficient to start a session. */ if (!userhost && cfg.host[0] != '\0') { userhost = dupstr(cfg.host); } /* * If a user@host string has already been provided, connect to * it now. */ if (userhost) { |
︙ | ︙ | |||
2990 2991 2992 2993 2994 2995 2996 | } do_sftp(mode, modeflags, batchfile); if (back != NULL && back->connected(backhandle)) { char ch; back->special(backhandle, TS_EOF); | < | 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 | } do_sftp(mode, modeflags, batchfile); if (back != NULL && back->connected(backhandle)) { char ch; back->special(backhandle, TS_EOF); sftp_recvdata(&ch, 1); } do_sftp_cleanup(); random_save_seed(); cmdline_cleanup(); console_provide_logctx(NULL); sk_cleanup(); return 0; } |
Changes to psftp.h.
︙ | ︙ | |||
81 82 83 84 85 86 87 | * * On the other hand, the abstraction is pretty simple: it supports * only opening a file and reading it, or creating a file and writing * it. None of this read-and-write, seeking-back-and-forth stuff. */ typedef struct RFile RFile; typedef struct WFile WFile; | | < | < | | 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | * * On the other hand, the abstraction is pretty simple: it supports * only opening a file and reading it, or creating a file and writing * it. None of this read-and-write, seeking-back-and-forth stuff. */ typedef struct RFile RFile; typedef struct WFile WFile; /* Output params size, mtime and atime can all be NULL if desired */ RFile *open_existing_file(char *name, uint64 *size, unsigned long *mtime, unsigned long *atime); WFile *open_existing_wfile(char *name, uint64 *size); /* Returns <0 on error, 0 on eof, or number of bytes read, as usual */ int read_from_file(RFile *f, void *buffer, int length); /* Closes and frees the RFile */ void close_rfile(RFile *f); WFile *open_new_file(char *name); /* Returns <0 on error, 0 on eof, or number of bytes written, as usual */ int write_to_file(WFile *f, void *buffer, int length); void set_file_times(WFile *f, unsigned long mtime, unsigned long atime); /* Closes and frees the WFile */ void close_wfile(WFile *f); /* Seek offset bytes through file */ enum { FROM_START, FROM_CURRENT, FROM_END }; |
︙ | ︙ |
Changes to putty.h.
︙ | ︙ | |||
14 15 16 17 18 19 20 | #else #define GLOBAL extern #endif #endif #ifndef DONE_TYPEDEFS #define DONE_TYPEDEFS | | | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | #else #define GLOBAL extern #endif #endif #ifndef DONE_TYPEDEFS #define DONE_TYPEDEFS typedef struct config_tag Config; typedef struct backend_tag Backend; typedef struct terminal_tag Terminal; #endif #include "puttyps.h" #include "network.h" #include "misc.h" |
︙ | ︙ | |||
300 301 302 303 304 305 306 | enum { /* Actions on remote window title query */ TITLE_NONE, TITLE_EMPTY, TITLE_REAL }; enum { | | | | | | | 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 | enum { /* Actions on remote window title query */ TITLE_NONE, TITLE_EMPTY, TITLE_REAL }; enum { /* Protocol back ends. (cfg.protocol) */ PROT_RAW, PROT_TELNET, PROT_RLOGIN, PROT_SSH, /* PROT_SERIAL is supported on a subset of platforms, but it doesn't * hurt to define it globally. */ PROT_SERIAL }; enum { /* Bell settings (cfg.beep) */ BELL_DISABLED, BELL_DEFAULT, BELL_VISUAL, BELL_WAVEFILE, BELL_PCSPEAKER }; enum { /* Taskbar flashing indication on bell (cfg.beep_ind) */ B_IND_DISABLED, B_IND_FLASH, B_IND_STEADY }; enum { /* Resize actions (cfg.resize_action) */ RESIZE_TERM, RESIZE_DISABLED, RESIZE_FONT, RESIZE_EITHER }; enum { /* Function key types (cfg.funky_type) */ FUNKY_TILDE, FUNKY_LINUX, FUNKY_XTERM, FUNKY_VT400, FUNKY_VT100P, FUNKY_SCO }; |
︙ | ︙ | |||
411 412 413 414 415 416 417 | * the proxy end. */ ADDRTYPE_UNSPEC, ADDRTYPE_IPV4, ADDRTYPE_IPV6, ADDRTYPE_NAME }; struct backend_tag { const char *(*init) (void *frontend_handle, void **backend_handle, | > | | | | 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 | * the proxy end. */ ADDRTYPE_UNSPEC, ADDRTYPE_IPV4, ADDRTYPE_IPV6, ADDRTYPE_NAME }; struct backend_tag { const char *(*init) (void *frontend_handle, void **backend_handle, Config *cfg, char *host, int port, char **realhost, int nodelay, int keepalive); void (*free) (void *handle); /* back->reconfig() passes in a replacement configuration. */ void (*reconfig) (void *handle, Config *cfg); /* back->send() returns the current amount of buffered data. */ int (*send) (void *handle, char *buf, int len); /* back->sendbuffer() does the same thing but without attempting a send */ int (*sendbuffer) (void *handle); void (*size) (void *handle, int width, int height); void (*special) (void *handle, Telnet_Special code); const struct telnet_special *(*get_specials) (void *handle); |
︙ | ︙ | |||
455 456 457 458 459 460 461 462 463 464 465 466 467 468 | extern const int be_default_protocol; /* * Name of this particular application, for use in the config box * and other pieces of text. */ extern const char *const appname; /* * Some global flags denoting the type of application. * * FLAG_VERBOSE is set when the user requests verbose details. * * FLAG_STDERR is set in command-line applications (which have a | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 | extern const int be_default_protocol; /* * Name of this particular application, for use in the config box * and other pieces of text. */ extern const char *const appname; /* * IMPORTANT POLICY POINT: everything in this structure which wants * to be treated like an integer must be an actual, honest-to- * goodness `int'. No enum-typed variables. This is because parts * of the code will want to pass around `int *' pointers to them * and we can't run the risk of porting to some system on which the * enum comes out as a different size from int. */ struct config_tag { /* Basic options */ char host[512]; int port; int protocol; int addressfamily; int close_on_exit; int warn_on_close; int ping_interval; /* in seconds */ int tcp_nodelay; int tcp_keepalives; char loghost[512]; /* logical host being contacted, for host key check */ /* Proxy options */ char proxy_exclude_list[512]; int proxy_dns; int even_proxy_localhost; int proxy_type; char proxy_host[512]; int proxy_port; char proxy_username[128]; char proxy_password[128]; char proxy_telnet_command[512]; /* SSH options */ char remote_cmd[512]; char *remote_cmd_ptr; /* might point to a larger command * but never for loading/saving */ char *remote_cmd_ptr2; /* might point to a larger command * but never for loading/saving */ int nopty; int compression; int ssh_kexlist[KEX_MAX]; int ssh_rekey_time; /* in minutes */ char ssh_rekey_data[16]; int tryagent; int agentfwd; int change_username; /* allow username switching in SSH-2 */ int ssh_cipherlist[CIPHER_MAX]; Filename keyfile; int sshprot; /* use v1 or v2 when both available */ int ssh2_des_cbc; /* "des-cbc" unrecommended SSH-2 cipher */ int ssh_no_userauth; /* bypass "ssh-userauth" (SSH-2 only) */ int ssh_show_banner; /* show USERAUTH_BANNERs (SSH-2 only) */ int try_tis_auth; int try_ki_auth; /* PuTTY SC start */ int try_write_syslog; /* check box (not persistent) */ int try_pkcs11_auth; /* check box */ Filename pkcs11_libfile; /* token lib */ void *sclib; /* sc's owned struct */ char pkcs11_token_label[70]; /* token label */ char pkcs11_cert_label[70]; /* cert label */ /* PuTTY SC end */ /* PuTTY CAPI start */ int try_capi_auth; /* check box */ char capi_certID[150]; /* {Machine|User}\{Store Name}\cert sha-1 fingerprint (in hex) */ /* PuTTY end start */ int try_gssapi_auth; /* attempt gssapi auth */ int gssapifwd; /* forward tgt via gss */ int ssh_gsslist[4]; /* preference order for local GSS libs */ Filename ssh_gss_custom; int ssh_subsys; /* run a subsystem rather than a command */ int ssh_subsys2; /* fallback to go with remote_cmd_ptr2 */ int ssh_no_shell; /* avoid running a shell */ char ssh_nc_host[512]; /* host to connect to in `nc' mode */ int ssh_nc_port; /* port to connect to in `nc' mode */ /* Telnet options */ char termtype[32]; char termspeed[32]; char ttymodes[768]; /* MODE\tVvalue\0MODE\tA\0\0 */ char environmt[1024]; /* VAR\tvalue\0VAR\tvalue\0\0 */ char username[100]; int username_from_env; char localusername[100]; int rfc_environ; int passive_telnet; /* Serial port options */ char serline[256]; int serspeed; int serdatabits, serstopbits; int serparity; int serflow; /* Keyboard options */ int bksp_is_delete; int rxvt_homeend; int funky_type; int no_applic_c; /* totally disable app cursor keys */ int no_applic_k; /* totally disable app keypad */ int no_mouse_rep; /* totally disable mouse reporting */ int no_remote_resize; /* disable remote resizing */ int no_alt_screen; /* disable alternate screen */ int no_remote_wintitle; /* disable remote retitling */ int no_dbackspace; /* disable destructive backspace */ int no_remote_charset; /* disable remote charset config */ int remote_qtitle_action; /* remote win title query action */ int app_cursor; int app_keypad; int nethack_keypad; int telnet_keyboard; int telnet_newline; int alt_f4; /* is it special? */ int alt_space; /* is it special? */ int alt_only; /* is it special? */ int localecho; int localedit; int alwaysontop; int fullscreenonaltenter; int scroll_on_key; int scroll_on_disp; int erase_to_scrollback; int compose_key; int ctrlaltkeys; char wintitle[256]; /* initial window title */ /* Terminal options */ int savelines; int dec_om; int wrap_mode; int lfhascr; int cursor_type; /* 0=block 1=underline 2=vertical */ int blink_cur; int beep; int beep_ind; int bellovl; /* bell overload protection active? */ int bellovl_n; /* number of bells to cause overload */ int bellovl_t; /* time interval for overload (seconds) */ int bellovl_s; /* period of silence to re-enable bell (s) */ Filename bell_wavefile; int scrollbar; int scrollbar_in_fullscreen; int resize_action; int bce; int blinktext; int win_name_always; int width, height; FontSpec font; int font_quality; Filename logfilename; int logtype; int logxfovr; int logflush; int logomitpass; int logomitdata; int hide_mouseptr; int sunken_edge; int window_border; char answerback[256]; char printer[128]; int arabicshaping; int bidi; /* Colour options */ int ansi_colour; int xterm_256_colour; int system_colour; int try_palette; int bold_colour; unsigned char colours[22][3]; /* Selection options */ int mouse_is_xterm; int rect_select; int rawcnp; int rtf_paste; int mouse_override; short wordness[256]; /* translations */ int vtmode; char line_codepage[128]; int cjk_ambig_wide; int utf8_override; int xlat_capslockcyr; /* X11 forwarding */ int x11_forward; char x11_display[128]; int x11_auth; Filename xauthfile; /* port forwarding */ int lport_acceptall; /* accept conns from hosts other than localhost */ int rport_acceptall; /* same for remote forwarded ports (SSH-2 only) */ /* * The port forwarding string contains a number of * NUL-terminated substrings, terminated in turn by an empty * string (i.e. a second NUL immediately after the previous * one). Each string can be of one of the following forms: * * [LR]localport\thost:port * [LR]localaddr:localport\thost:port * Dlocalport * Dlocaladdr:localport */ char portfwd[1024]; /* SSH bug compatibility modes */ int sshbug_ignore1, sshbug_plainpw1, sshbug_rsa1, sshbug_hmac2, sshbug_derivekey2, sshbug_rsapad2, sshbug_pksessid2, sshbug_rekey2, sshbug_maxpkt2, sshbug_ignore2; /* * ssh_simple means that we promise never to open any channel other * than the main one, which means it can safely use a very large * window in SSH-2. */ int ssh_simple; /* Options for pterm. Should split out into platform-dependent part. */ int stamp_utmp; int login_shell; int scrollbar_on_left; int shadowbold; FontSpec boldfont; FontSpec widefont; FontSpec wideboldfont; int shadowboldoffset; int crhaslf; char winclass[256]; }; /* * Some global flags denoting the type of application. * * FLAG_VERBOSE is set when the user requests verbose details. * * FLAG_STDERR is set in command-line applications (which have a |
︙ | ︙ | |||
521 522 523 524 525 526 527 | * generally not trust the strings. (But \n is required to behave * vaguely sensibly, at least in `instruction', and ideally in * `prompt[]' too.) */ typedef struct { char *prompt; int echo; | < < < < < < < < < < < | | | 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 | * generally not trust the strings. (But \n is required to behave * vaguely sensibly, at least in `instruction', and ideally in * `prompt[]' too.) */ typedef struct { char *prompt; int echo; char *result; /* allocated/freed by caller */ size_t result_len; } prompt_t; typedef struct { /* * Indicates whether the information entered is to be used locally * (for instance a key passphrase prompt), or is destined for the wire. * This is a hint only; the front-end is at liberty not to use this * information (so the caller should ensure that the supplied text is |
︙ | ︙ | |||
556 557 558 559 560 561 562 | * if any, and return success) */ prompt_t **prompts; void *frontend; void *data; /* slot for housekeeping data, managed by * get_userpass_input(); initially NULL */ } prompts_t; prompts_t *new_prompts(void *frontend); | | < < | 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 | * if any, and return success) */ prompt_t **prompts; void *frontend; void *data; /* slot for housekeeping data, managed by * get_userpass_input(); initially NULL */ } prompts_t; prompts_t *new_prompts(void *frontend); void add_prompt(prompts_t *p, char *promptstr, int echo, size_t len); /* Burn the evidence. (Assumes _all_ strings want free()ing.) */ void free_prompts(prompts_t *p); /* * Exports from the front end. */ void request_resize(void *frontend, int, int); |
︙ | ︙ | |||
585 586 587 588 589 590 591 | void palette_reset(void *frontend); void write_aclip(void *frontend, char *, int, int); void write_clip(void *frontend, wchar_t *, int *, int, int); void get_clip(void *frontend, wchar_t **, int *); void optimised_move(void *frontend, int, int, int); void set_raw_mouse_mode(void *frontend, int); void connection_fatal(void *frontend, char *, ...); | < < < < < < | 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 | void palette_reset(void *frontend); void write_aclip(void *frontend, char *, int, int); void write_clip(void *frontend, wchar_t *, int *, int, int); void get_clip(void *frontend, wchar_t **, int *); void optimised_move(void *frontend, int, int, int); void set_raw_mouse_mode(void *frontend, int); void connection_fatal(void *frontend, char *, ...); void fatalbox(char *, ...); void modalfatalbox(char *, ...); #ifdef macintosh #pragma noreturn(fatalbox) #pragma noreturn(modalfatalbox) #endif void do_beep(void *frontend, int); void begin_session(void *frontend); void sys_cursor(void *frontend, int x, int y); void request_paste(void *frontend); void frontend_keypress(void *frontend); void ldisc_update(void *frontend, int echo, int edit); /* It's the backend's responsibility to invoke this at the start of a * connection, if necessary; it can also invoke it later if the set of * special commands changes. It does not need to invoke it at session * shutdown. */ void update_specials_menu(void *frontend); int from_backend(void *frontend, int is_stderr, const char *data, int len); int from_backend_untrusted(void *frontend, const char *data, int len); void notify_remote_exit(void *frontend); /* Get a sensible value for a tty mode. NULL return = don't set. * Otherwise, returned value should be freed by caller. */ char *get_ttymode(void *frontend, const char *mode); /* * >0 = `got all results, carry on' * 0 = `user cancelled' (FIXME distinguish "give up entirely" and "next auth"?) |
︙ | ︙ | |||
644 645 646 647 648 649 650 | stuff is suspended */ BUSY_CPU /* Locally busy (e.g. crypto); user interaction suspended */ }; void set_busy_status(void *frontend, int status); void cleanup_exit(int); | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | < < < < | | | > > | | | | < | 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 | stuff is suspended */ BUSY_CPU /* Locally busy (e.g. crypto); user interaction suspended */ }; void set_busy_status(void *frontend, int status); void cleanup_exit(int); /* * Exports from noise.c. */ void noise_get_heavy(void (*func) (void *, int)); void noise_get_light(void (*func) (void *, int)); void noise_regular(void); void noise_ultralight(unsigned long data); void random_save_seed(void); void random_destroy_seed(void); /* * Exports from settings.c. */ Backend *backend_from_name(const char *name); Backend *backend_from_proto(int proto); int get_remote_username(Config *cfg, char *user, size_t len); char *save_settings(char *section, Config * cfg); void save_open_settings(void *sesskey, Config *cfg); void load_settings(char *section, Config * cfg); void load_open_settings(void *sesskey, Config *cfg); void get_sesslist(struct sesslist *, int allocate); void do_defaults(char *, Config *); void registry_cleanup(void); /* * Functions used by settings.c to provide platform-specific * default settings. * * (The integer one is expected to return `def' if it has no clear * opinion of its own. This is because there's no integer value * which I can reliably set aside to indicate `nil'. The string * function is perfectly all right returning NULL, of course. The * Filename and FontSpec functions are _not allowed_ to fail to * return, since these defaults _must_ be per-platform.) */ char *platform_default_s(const char *name); int platform_default_i(const char *name, int def); Filename platform_default_filename(const char *name); FontSpec platform_default_fontspec(const char *name); /* * Exports from terminal.c. */ Terminal *term_init(Config *, struct unicode_data *, void *); void term_free(Terminal *); void term_size(Terminal *, int, int, int); void term_paint(Terminal *, Context, int, int, int, int, int); void term_scroll(Terminal *, int, int); void term_scroll_to_selection(Terminal *, int); void term_pwron(Terminal *, int); void term_clrsb(Terminal *); void term_mouse(Terminal *, Mouse_Button, Mouse_Button, Mouse_Action, int,int,int,int,int); void term_key(Terminal *, Key_Sym, wchar_t *, size_t, unsigned int, unsigned int); void term_deselect(Terminal *); void term_update(Terminal *); void term_invalidate(Terminal *); void term_blink(Terminal *, int set_cursor); void term_do_paste(Terminal *); int term_paste_pending(Terminal *); void term_paste(Terminal *); void term_nopaste(Terminal *); int term_ldisc(Terminal *, int option); void term_copyall(Terminal *); void term_reconfig(Terminal *, Config *); void term_seen_key_event(Terminal *); int term_data(Terminal *, int is_stderr, const char *data, int len); int term_data_untrusted(Terminal *, const char *data, int len); void term_provide_resize_fn(Terminal *term, void (*resize_fn)(void *, int, int), void *resize_ctx); void term_provide_logctx(Terminal *term, void *logctx); void term_set_focus(Terminal *term, int has_focus); char *term_get_ttymode(Terminal *term, const char *mode); int term_get_userpass_input(Terminal *term, prompts_t *p, unsigned char *in, int inlen); int format_arrow_key(char *buf, Terminal *term, int xkey, int ctrl); /* * Exports from logging.c. */ void *log_init(void *frontend, Config *cfg); void log_free(void *logctx); void log_reconfig(void *logctx, Config *cfg); void logfopen(void *logctx); void logfclose(void *logctx); void logtraffic(void *logctx, unsigned char c, int logmode); void logflush(void *logctx); void log_eventlog(void *logctx, const char *string); enum { PKT_INCOMING, PKT_OUTGOING }; enum { PKTLOG_EMIT, PKTLOG_BLANK, PKTLOG_OMIT }; struct logblank_t { int offset; int len; int type; }; void log_packet(void *logctx, int direction, int type, char *texttype, const void *data, int len, int n_blanks, const struct logblank_t *blanks, const unsigned long *sequence); /* * Exports from testback.c */ extern Backend null_backend; extern Backend loop_backend; |
︙ | ︙ | |||
1051 1052 1053 1054 1055 1056 1057 | * Exports from ssh.c. */ extern Backend ssh_backend; /* * Exports from ldisc.c. */ | | < | 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 | * Exports from ssh.c. */ extern Backend ssh_backend; /* * Exports from ldisc.c. */ void *ldisc_create(Config *, Terminal *, Backend *, void *, void *); void ldisc_free(void *); void ldisc_send(void *handle, char *buf, int len, int interactive); /* * Exports from ldiscucs.c. */ void lpage_send(void *, int codepage, char *buf, int len, int interactive); |
︙ | ︙ | |||
1080 1081 1082 1083 1084 1085 1086 | void random_ref(void); void random_unref(void); /* * Exports from pinger.c. */ typedef struct pinger_tag *Pinger; | | | | | | | | | | | | 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 | void random_ref(void); void random_unref(void); /* * Exports from pinger.c. */ typedef struct pinger_tag *Pinger; Pinger pinger_new(Config *cfg, Backend *back, void *backhandle); void pinger_reconfig(Pinger, Config *oldcfg, Config *newcfg); void pinger_free(Pinger); /* * Exports from misc.c. */ #include "misc.h" int cfg_launchable(const Config *cfg); char const *cfg_dest(const Config *cfg); /* * Exports from sercfg.c. */ void ser_setup_config_box(struct controlbox *b, int midsession, int parity_mask, int flow_mask); /* * Exports from version.c. */ extern char ver[]; /* * Exports from unicode.c. */ #ifndef CP_UTF8 #define CP_UTF8 65001 #endif /* void init_ucs(void); -- this is now in platform-specific headers */ int is_dbcs_leadbyte(int codepage, char byte); int mb_to_wc(int codepage, int flags, char *mbstr, int mblen, wchar_t *wcstr, int wclen); int wc_to_mb(int codepage, int flags, wchar_t *wcstr, int wclen, char *mbstr, int mblen, char *defchr, int *defused, struct unicode_data *ucsdata); wchar_t xlat_uskbd2cyrllic(int ch); int check_compose(int first, int second); int decode_codepage(char *cp_name); const char *cp_enumerate (int index); const char *cp_name(int codepage); void get_unitab(int codepage, wchar_t * unitab, int ftype); /* * Exports from wcwidth.c */ int mk_wcwidth(wchar_t ucs); int mk_wcswidth(const wchar_t *pwcs, size_t n); int mk_wcwidth_cjk(wchar_t ucs); int mk_wcswidth_cjk(const wchar_t *pwcs, size_t n); /* * Exports from mscrypto.c */ #ifdef MSCRYPTOAPI int crypto_startup(); void crypto_wrapup(); |
︙ | ︙ | |||
1195 1196 1197 1198 1199 1200 1201 | * askappend can return four values: * * - 2 means overwrite the log file * - 1 means append to the log file * - 0 means cancel logging for this session * - -1 means please wait. */ | | | 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 | * askappend can return four values: * * - 2 means overwrite the log file * - 1 means append to the log file * - 0 means cancel logging for this session * - -1 means please wait. */ int askappend(void *frontend, Filename filename, void (*callback)(void *ctx, int result), void *ctx); /* * Exports from console frontends (wincons.c, uxcons.c) * that aren't equivalents to things in windlg.c et al. */ extern int console_batch_mode; |
︙ | ︙ | |||
1224 1225 1226 1227 1228 1229 1230 | void printer_finish_job(printer_job *); /* * Exports from cmdline.c (and also cmdline_error(), which is * defined differently in various places and required _by_ * cmdline.c). */ | | | < < < < < < < < < < < < | < < < | | | < < < < | 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 | void printer_finish_job(printer_job *); /* * Exports from cmdline.c (and also cmdline_error(), which is * defined differently in various places and required _by_ * cmdline.c). */ int cmdline_process_param(char *, char *, int, Config *); void cmdline_run_saved(Config *); void cmdline_cleanup(void); int cmdline_get_passwd_input(prompts_t *p, unsigned char *in, int inlen); #define TOOLTYPE_FILETRANSFER 1 #define TOOLTYPE_NONNETWORK 2 extern int cmdline_tooltype; void cmdline_error(char *, ...); /* * Exports from config.c. */ struct controlbox; void setup_config_box(struct controlbox *b, int midsession, int protocol, int protcfginfo); /* * Exports from minibidi.c. */ typedef struct bidi_char { wchar_t origwc, wc; unsigned short index; } bidi_char; int do_bidi(bidi_char *line, int count); int do_shape(bidi_char *line, bidi_char *to, int count); int is_rtl(int c); /* * X11 auth mechanisms we know about. */ enum { X11_NO_AUTH, X11_MIT, /* MIT-MAGIC-COOKIE-1 */ X11_XDM, /* XDM-AUTHORIZATION-1 */ X11_NAUTHS }; extern const char *const x11_authnames[]; /* declared in x11fwd.c */ /* * Miscellaneous exports from the platform-specific code. */ Filename filename_from_str(const char *string); const char *filename_to_str(const Filename *fn); int filename_equal(Filename f1, Filename f2); int filename_is_null(Filename fn); char *get_username(void); /* return value needs freeing */ char *get_random_data(int bytes); /* used in cmdgen.c */ /* * Exports and imports from timing.c. * * schedule_timer() asks the front end to schedule a callback to a |
︙ | ︙ | |||
1382 1383 1384 1385 1386 1387 1388 | * (It does also mean that the timer action in the above example * will occur 100ms early, but this is not generally critical. And * the hypothetical 1% error in wait() will be partially corrected * for anyway when, _after_ run_timers() returns, you call * GETTICKCOUNT() and compare the result with the returned `next' * value to find out how long you have to make your next wait().) */ | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 | * (It does also mean that the timer action in the above example * will occur 100ms early, but this is not generally critical. And * the hypothetical 1% error in wait() will be partially corrected * for anyway when, _after_ run_timers() returns, you call * GETTICKCOUNT() and compare the result with the returned `next' * value to find out how long you have to make your next wait().) */ typedef void (*timer_fn_t)(void *ctx, long now); long schedule_timer(int ticks, timer_fn_t fn, void *ctx); void expire_timer_context(void *ctx); int run_timers(long now, long *next); void timer_change_notify(long next); /* * Define no-op macros for the jump list functions, on platforms that * don't support them. (This is a bit of a hack, and it'd be nicer to * localise even the calls to those functions into the Windows front * end, but it'll do for the moment.) */ #ifndef JUMPLIST_SUPPORTED #define add_session_to_jumplist(x) ((void)0) #define remove_session_from_jumplist(x) ((void)0) #endif #endif |
Changes to puttymem.h.
︙ | ︙ | |||
30 31 32 33 34 35 36 | void safefree(void *); /* * Direct use of smalloc within the code should be avoided where * possible, in favour of these type-casting macros which ensure * you don't mistakenly allocate enough space for one sort of * structure and assign it to a different sort of pointer. | < < < < < < < < | < < | 30 31 32 33 34 35 36 37 38 39 40 41 42 | void safefree(void *); /* * Direct use of smalloc within the code should be avoided where * possible, in favour of these type-casting macros which ensure * you don't mistakenly allocate enough space for one sort of * structure and assign it to a different sort of pointer. */ #define snew(type) ((type *)snmalloc(1, sizeof(type))) #define snewn(n, type) ((type *)snmalloc((n), sizeof(type))) #define sresize(ptr, n, type) ((type *)snrealloc((ptr), (n), sizeof(type))) #endif |
Changes to raw.c.
1 2 3 4 5 6 | /* * "Raw" backend. */ #include <stdio.h> #include <stdlib.h> | < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | /* * "Raw" backend. */ #include <stdio.h> #include <stdlib.h> #include "putty.h" #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE 1 #endif #define RAW_MAX_BACKLOG 4096 typedef struct raw_backend_data { const struct plug_function_table *fn; /* the above field _must_ be first in the structure */ Socket s; int bufsize; void *frontend; } *Raw; static void raw_size(void *handle, int width, int height); static void c_write(Raw raw, char *buf, int len) { int backlog = from_backend(raw->frontend, 0, buf, len); |
︙ | ︙ | |||
46 47 48 49 50 51 52 | if (type == 0) msg = dupprintf("Connecting to %s port %d", addrbuf, port); else msg = dupprintf("Failed to connect to %s: %s", addrbuf, error_msg); logevent(raw->frontend, msg); | < < < < < < < < < < < < < < < < < < | | | < | | > > | | < | < < < < < < < < < < < < < < | 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | if (type == 0) msg = dupprintf("Connecting to %s port %d", addrbuf, port); else msg = dupprintf("Failed to connect to %s: %s", addrbuf, error_msg); logevent(raw->frontend, msg); } static int raw_closing(Plug plug, const char *error_msg, int error_code, int calling_back) { Raw raw = (Raw) plug; if (raw->s) { sk_close(raw->s); raw->s = NULL; notify_remote_exit(raw->frontend); } if (error_msg) { /* A socket error has occurred. */ logevent(raw->frontend, error_msg); connection_fatal(raw->frontend, "%s", error_msg); } /* Otherwise, the remote side closed the connection normally. */ return 0; } static int raw_receive(Plug plug, int urgent, char *data, int len) { Raw raw = (Raw) plug; c_write(raw, data, len); |
︙ | ︙ | |||
120 121 122 123 124 125 126 | * * Returns an error message, or NULL on success. * * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ static const char *raw_init(void *frontend_handle, void **backend_handle, | | < < < < < | | | | < | | | 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | * * Returns an error message, or NULL on success. * * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ static const char *raw_init(void *frontend_handle, void **backend_handle, Config *cfg, char *host, int port, char **realhost, int nodelay, int keepalive) { static const struct plug_function_table fn_table = { raw_log, raw_closing, raw_receive, raw_sent }; SockAddr addr; const char *err; Raw raw; raw = snew(struct raw_backend_data); raw->fn = &fn_table; raw->s = NULL; *backend_handle = raw; raw->frontend = frontend_handle; /* * Try to find host. */ { char *buf; buf = dupprintf("Looking up host \"%s\"%s", host, (cfg->addressfamily == ADDRTYPE_IPV4 ? " (IPv4)" : (cfg->addressfamily == ADDRTYPE_IPV6 ? " (IPv6)" : ""))); logevent(raw->frontend, buf); sfree(buf); } addr = name_lookup(host, port, realhost, cfg, cfg->addressfamily); if ((err = sk_addr_error(addr)) != NULL) { sk_addr_free(addr); return err; } if (port < 0) port = 23; /* default telnet port */ /* * Open socket. */ raw->s = new_connection(addr, *realhost, port, 0, 1, nodelay, keepalive, (Plug) raw, cfg); if ((err = sk_socket_error(raw->s)) != NULL) return err; if (*cfg->loghost) { char *colon; sfree(*realhost); *realhost = dupstr(cfg->loghost); colon = strrchr(*realhost, ':'); if (colon) { /* * FIXME: if we ever update this aspect of ssh.c for * IPv6 literal management, this should change in line * with it. */ |
︙ | ︙ | |||
207 208 209 210 211 212 213 | sk_close(raw->s); sfree(raw); } /* * Stub routine (we don't have any need to reconfigure this backend). */ | | | 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | sk_close(raw->s); sfree(raw); } /* * Stub routine (we don't have any need to reconfigure this backend). */ static void raw_reconfig(void *handle, Config *cfg) { } /* * Called to send data down the raw connection. */ static int raw_send(void *handle, char *buf, int len) |
︙ | ︙ | |||
245 246 247 248 249 250 251 | static void raw_size(void *handle, int width, int height) { /* Do nothing! */ return; } /* | | < < < < < < | | 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 | static void raw_size(void *handle, int width, int height) { /* Do nothing! */ return; } /* * Send raw special codes. */ static void raw_special(void *handle, Telnet_Special code) { /* Do nothing! */ return; } /* * Return a list of the special codes that make sense in this * protocol. */ |
︙ | ︙ | |||
307 308 309 310 311 312 313 | } static int raw_exitcode(void *handle) { Raw raw = (Raw) handle; if (raw->s != NULL) return -1; /* still connected */ | < < | 260 261 262 263 264 265 266 267 268 269 270 271 272 273 | } static int raw_exitcode(void *handle) { Raw raw = (Raw) handle; if (raw->s != NULL) return -1; /* still connected */ else /* Exit codes are a meaningless concept in the Raw protocol */ return 0; } /* * cfg_info for Raw does nothing at all. |
︙ | ︙ |
Changes to rlogin.c.
1 2 3 4 5 6 | /* * Rlogin backend. */ #include <stdio.h> #include <stdlib.h> | < < | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | /* * Rlogin backend. */ #include <stdio.h> #include <stdlib.h> #include <ctype.h> #include "putty.h" #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE 1 #endif #define RLOGIN_MAX_BACKLOG 4096 typedef struct rlogin_tag { const struct plug_function_table *fn; /* the above field _must_ be first in the structure */ Socket s; int bufsize; int firstbyte; int cansize; int term_width, term_height; void *frontend; Config cfg; /* In case we need to read a username from the terminal before starting */ prompts_t *prompt; } *Rlogin; static void rlogin_size(void *handle, int width, int height); |
︙ | ︙ | |||
54 55 56 57 58 59 60 | if (type == 0) msg = dupprintf("Connecting to %s port %d", addrbuf, port); else msg = dupprintf("Failed to connect to %s: %s", addrbuf, error_msg); logevent(rlogin->frontend, msg); | < < < < < < < < < < | 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | if (type == 0) msg = dupprintf("Connecting to %s port %d", addrbuf, port); else msg = dupprintf("Failed to connect to %s: %s", addrbuf, error_msg); logevent(rlogin->frontend, msg); } static int rlogin_closing(Plug plug, const char *error_msg, int error_code, int calling_back) { Rlogin rlogin = (Rlogin) plug; if (rlogin->s) { sk_close(rlogin->s); rlogin->s = NULL; notify_remote_exit(rlogin->frontend); } if (error_msg) { /* A socket error has occurred. */ logevent(rlogin->frontend, error_msg); connection_fatal(rlogin->frontend, "%s", error_msg); } /* Otherwise, the remote side closed the connection normally. */ |
︙ | ︙ | |||
130 131 132 133 134 135 136 | rlogin->bufsize = bufsize; } static void rlogin_startup(Rlogin rlogin, const char *ruser) { char z = 0; char *p; | | | | | | | < | > | | | | < < < | | | < | | | | < | | | < | > < | | 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 | rlogin->bufsize = bufsize; } static void rlogin_startup(Rlogin rlogin, const char *ruser) { char z = 0; char *p; sk_write(rlogin->s, &z, 1); sk_write(rlogin->s, rlogin->cfg.localusername, strlen(rlogin->cfg.localusername)); sk_write(rlogin->s, &z, 1); sk_write(rlogin->s, ruser, strlen(ruser)); sk_write(rlogin->s, &z, 1); sk_write(rlogin->s, rlogin->cfg.termtype, strlen(rlogin->cfg.termtype)); sk_write(rlogin->s, "/", 1); for (p = rlogin->cfg.termspeed; isdigit((unsigned char)*p); p++) continue; sk_write(rlogin->s, rlogin->cfg.termspeed, p - rlogin->cfg.termspeed); rlogin->bufsize = sk_write(rlogin->s, &z, 1); rlogin->prompt = NULL; } /* * Called to set up the rlogin connection. * * Returns an error message, or NULL on success. * * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ static const char *rlogin_init(void *frontend_handle, void **backend_handle, Config *cfg, char *host, int port, char **realhost, int nodelay, int keepalive) { static const struct plug_function_table fn_table = { rlogin_log, rlogin_closing, rlogin_receive, rlogin_sent }; SockAddr addr; const char *err; Rlogin rlogin; char ruser[sizeof(cfg->username)]; rlogin = snew(struct rlogin_tag); rlogin->fn = &fn_table; rlogin->s = NULL; rlogin->frontend = frontend_handle; rlogin->term_width = cfg->width; rlogin->term_height = cfg->height; rlogin->firstbyte = 1; rlogin->cansize = 0; rlogin->prompt = NULL; rlogin->cfg = *cfg; /* STRUCTURE COPY */ *backend_handle = rlogin; /* * Try to find host. */ { char *buf; buf = dupprintf("Looking up host \"%s\"%s", host, (cfg->addressfamily == ADDRTYPE_IPV4 ? " (IPv4)" : (cfg->addressfamily == ADDRTYPE_IPV6 ? " (IPv6)" : ""))); logevent(rlogin->frontend, buf); sfree(buf); } addr = name_lookup(host, port, realhost, cfg, cfg->addressfamily); if ((err = sk_addr_error(addr)) != NULL) { sk_addr_free(addr); return err; } if (port < 0) port = 513; /* default rlogin port */ /* * Open socket. */ rlogin->s = new_connection(addr, *realhost, port, 1, 0, nodelay, keepalive, (Plug) rlogin, cfg); if ((err = sk_socket_error(rlogin->s)) != NULL) return err; if (*cfg->loghost) { char *colon; sfree(*realhost); *realhost = dupstr(cfg->loghost); colon = strrchr(*realhost, ':'); if (colon) { /* * FIXME: if we ever update this aspect of ssh.c for * IPv6 literal management, this should change in line * with it. */ *colon++ = '\0'; } } /* * Send local username, remote username, terminal type and * terminal speed - unless we don't have the remote username yet, * in which case we prompt for it and may end up deferring doing * anything else until the local prompt mechanism returns. */ if (get_remote_username(cfg, ruser, sizeof(ruser))) { rlogin_startup(rlogin, ruser); } else { int ret; rlogin->prompt = new_prompts(rlogin->frontend); rlogin->prompt->to_server = TRUE; rlogin->prompt->name = dupstr("Rlogin login name"); add_prompt(rlogin->prompt, dupstr("rlogin username: "), TRUE, sizeof(cfg->username)); ret = get_userpass_input(rlogin->prompt, NULL, 0); if (ret >= 0) { rlogin_startup(rlogin, rlogin->prompt->prompts[0]->result); } } return NULL; } static void rlogin_free(void *handle) { Rlogin rlogin = (Rlogin) handle; if (rlogin->prompt) free_prompts(rlogin->prompt); if (rlogin->s) sk_close(rlogin->s); sfree(rlogin); } /* * Stub routine (we don't have any need to reconfigure this backend). */ static void rlogin_reconfig(void *handle, Config *cfg) { } /* * Called to send data down the rlogin connection. */ static int rlogin_send(void *handle, char *buf, int len) |
︙ | ︙ | |||
394 395 396 397 398 399 400 | } static int rlogin_exitcode(void *handle) { Rlogin rlogin = (Rlogin) handle; if (rlogin->s != NULL) return -1; /* still connected */ | < < | 376 377 378 379 380 381 382 383 384 385 386 387 388 389 | } static int rlogin_exitcode(void *handle) { Rlogin rlogin = (Rlogin) handle; if (rlogin->s != NULL) return -1; /* still connected */ else /* If we ever implement RSH, we'll probably need to do this properly */ return 0; } /* * cfg_info for rlogin does nothing at all. |
︙ | ︙ |
Added sc.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 | /* -*-mode: c; indent-tabs-mode: nil; c-basic-offset: 4; -*- */ /* * This file is part of PuTTY SC, a modification of PuTTY * supporting smartcard for authentication. * * PuTTY SC is available at http://www.joebar.ch/puttysc/ * * Copyright (C) 2005-2007 Pascal Buchbinder * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <assert.h> #include <windows.h> /* putty */ #include "ssh.h" #include "pkcs11.h" /* this */ #include "sc.h" #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE 1 #endif static const char rcsid_sc_c[] = "$Id: sc.c,v 1.34 2007/03/04 20:41:56 pbu Exp $"; /* this is the OID for rsaEncryption plus a required null object as the parameter field. */ /* for more on how ASN.1 works, see http://luca.ntop.org/Teaching/Appunti/asn1.html */ static const char OIDrsaEncryption[] = { 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00 }; int find_substring( char * haystack, long haysize, const char* needle, long needlesize) ; unsigned int asn1_length(unsigned char** cursor) ; int extract_key_from_cert(unsigned char* cert, int certsize, unsigned char **expo, unsigned char** modu, int* elen, int* mlen); #define SC_PUT_32BIT(cp, value) { \ (cp)[0] = (unsigned char)((value) >> 24); \ (cp)[1] = (unsigned char)((value) >> 16); \ (cp)[2] = (unsigned char)((value) >> 8); \ (cp)[3] = (unsigned char)(value); } static const u_char id_sha1[] = { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 }; #define SC_STR_MAX_LEN 8192 #define SC_MAX_O 20 void sc_write_syslog(char *msg) { char szSyslogBuffer[SC_STR_MAX_LEN]; HANDLE hEventLog; int rc; DWORD logw = 0x00000001L; sprintf(szSyslogBuffer, "%s: %s %s", "puttysc", "info", msg); if ((hEventLog = RegisterEventSource(NULL, "puttysc"))) { LPSTR aszStrings[] = {szSyslogBuffer}; rc = ReportEvent(hEventLog, (WORD)EVENTLOG_INFORMATION_TYPE, 0, (DWORD)logw, NULL, 1, 0, (LPCTSTR*)aszStrings, NULL); DeregisterEventSource(hEventLog); } } char *sc_base64key(char *data, int len) { int bi, bn; char out[4]; int datalen = len; char *buffi = calloc(len + len, sizeof(char *)); int buffi_pos = 0; for(bi=0;bi<(len + len); bi++) buffi[bi] = '\0'; while (datalen > 0) { bn = (datalen < 3 ? datalen : 3); base64_encode_atom(data, bn, out); data += bn; datalen -= bn; for (bi = 0; bi < 4; bi++) { buffi[buffi_pos] = out[bi]; buffi_pos++; } } return buffi; } void sc_free_sclib(sc_lib *sclib) { if(sclib->rsakey != NULL) { free(sclib->rsakey->exponent); free(sclib->rsakey->modulus); free(sclib->rsakey); } if (sclib->keystring != NULL) { free(sclib->keystring); sclib->keystring = NULL; } sclib->m_fl->C_Finalize(0); sclib->m_fl = 0; free(sclib->m_KeyID); sclib->m_KeyID = NULL; free(sclib->m_SshPK); sclib->m_SshPK = NULL; sclib->m_SshPK_len = 0; free(sclib->m_SshPk_alg); sclib->m_SshPk_alg = NULL; FreeLibrary(sclib->hLib); free(sclib); } int sc_init_library(void *f, int try_write_syslog, sc_lib *sclib, Filename *pkcs11_libfile) { CK_FUNCTION_LIST_PTR fl = 0; CK_C_GetFunctionList pGFL = 0; unsigned long slot_count = 16; CK_SLOT_ID slots[16]; CK_RV rv = 0; char *msg = ""; sclib->hLib = LoadLibrary((char *)pkcs11_libfile); if (sclib->hLib == NULL) { msg = "sc: Cannot load PKCS 11 DLL."; goto err; } pGFL= (CK_RV (*)(CK_FUNCTION_LIST_PTR_PTR))GetProcAddress(sclib->hLib, "C_GetFunctionList"); if (pGFL == NULL) { msg = "sc: Cannot find GetFunctionList()"; goto err; } rv = pGFL(&fl); if(rv != CKR_OK) { msg = "sc: Can't get function list"; goto err; } rv = fl->C_Initialize (0); if (CKR_OK != rv ) { msg = "sc: C_Initialize failed"; goto err; } rv = fl->C_GetSlotList (TRUE, slots, &slot_count); if (CKR_OK != rv) { msg = "sc: C_GetSlotList failed"; goto err; } if (slot_count < 1) { msg = "sc: No token available"; goto err; } sclib->m_fl = fl; return TRUE; err: logevent(f, msg); if(try_write_syslog) sc_write_syslog(msg); FreeLibrary(sclib->hLib); return FALSE; } /* In an attempt to work around the wierdness of the ActivClient library, I'm going to do an evil hack: If there's only one slot, I'm going to use it regardless of what the token_label is. ActivClient generates token labels on the fly, so we can't count on them being the same from one session to the next. */ CK_SESSION_HANDLE sc_get_session(void *f, int try_write_syslog, CK_FUNCTION_LIST_PTR fl, const char *token_label) { #define SC_MAX_SLOT 16 CK_SESSION_HANDLE session = 0; unsigned long slot_count = SC_MAX_SLOT; CK_TOKEN_INFO token_info; CK_SLOT_ID slots[SC_MAX_SLOT]; CK_SLOT_ID c_slot = SC_MAX_SLOT; CK_SLOT_ID slot = SC_MAX_SLOT; CK_RV rv = 0; int i; char msg[SC_STR_MAX_LEN] = ""; sprintf(msg, "sc: sc_get_session called"); logevent(f, msg); if(fl == 0) { sprintf(msg, "sc: Invalid state, no function list"); goto err; } rv = fl->C_GetSlotList(TRUE, slots, &slot_count); if(CKR_OK != rv) { sprintf(msg, "sc: C_GetSlotList failed 0x%.4x", (int)rv); goto err; } sprintf(msg, "sc: slot_count = %d", (int)slot_count); logevent(f, msg); if(slot_count < 1) { sprintf(msg, "sc: No token available"); goto err; } if (slot_count == 1) { char msg[SC_STR_MAX_LEN] = ""; CK_TOKEN_INFO token_info; rv = fl->C_GetTokenInfo(slots[0],&token_info); sprintf(msg, "sc: forcing token label to the only allowed value: %s", token_info.label); c_slot = 0; logevent(f, msg); } else { for(i=0; i<slot_count; i++) { slot = slots[i]; rv = fl->C_GetTokenInfo(slot,&token_info); if (CKR_OK != rv) { sprintf(msg, "sc: C_GetTokenInfo failed for token in slot %i", i); goto err; } { char buf[40]; memset(buf, 0, 40); strncpy(buf, token_info.label, 39); sprintf(msg, "sc: Found token in slot %i: %s", i, buf); logevent(f, msg); if(f) { if(try_write_syslog) sc_write_syslog(msg); } } if(strncmp(token_label, token_info.label, strlen(token_label)) == 0) { c_slot = i; break; } } if(c_slot == 64) { sprintf(msg, "sc: No token named: %s", token_label); goto err; } } rv = fl->C_OpenSession(slots[c_slot],CKF_SERIAL_SESSION|CKF_RW_SESSION, 0, 0, &session); if (CKR_OK != rv) { sprintf(msg, "sc: C_OpenSession failed"); goto err; } else { if(f) logevent(f, "sc: Session opened"); } return session; err: if(f) { logevent(f, msg); if(try_write_syslog) sc_write_syslog(msg); } // m_fl->C_Finalize(0); // m_fl = 0; return 0; } void sc_free_cert_list(sc_cert_list *cert_list) { sc_cert_list *cl = cert_list; while(cl != NULL) { sc_cert_list *next = cl->next; int i; for(i=0; i<sizeof(cl->cert_attr)/sizeof(CK_ATTRIBUTE); i++) { free(cl->cert_attr[i].pValue); cl->cert_attr[i].pValue = NULL; } free(cl); cl = next; } cert_list = NULL; } sc_cert_list *sc_get_cert_list(sc_lib *sclib, CK_SESSION_HANDLE session, char *err_msg) { CK_RV rv; int i; /* STORE OBJECTS AND ATTRIBUTES */ sc_cert_list *cl = NULL; sc_cert_list *pcl = NULL; CK_OBJECT_HANDLE list[SC_MAX_O]; CK_ULONG found = 0; /* TEMPLATES: */ CK_BBOOL bFalse = 0; CK_BBOOL bTrue = 1; CK_OBJECT_CLASS class_cert = CKO_CERTIFICATE; CK_ATTRIBUTE cert_template[] = { { CKA_CLASS, &class_cert, sizeof (class_cert) }, { CKA_TOKEN, &bTrue, sizeof (bTrue) }, { CKA_PRIVATE, &bFalse, sizeof (bFalse) } }; rv = sclib->m_fl->C_FindObjectsInit(session, cert_template, sizeof(cert_template)/sizeof(CK_ATTRIBUTE)); if (CKR_OK != rv) { sprintf(err_msg, "sc: C_FindObjectsInit (certificate) failed, 0x%.4x", (int)rv); return NULL; } rv = sclib->m_fl->C_FindObjects(session, list, SC_MAX_O-1, &found); if (CKR_OK != rv) { sprintf(err_msg, "sc: C_FindObjects (certificate) failed, 0x%.4x", (int)rv); return NULL; } rv = sclib->m_fl->C_FindObjectsFinal(session); if (CKR_OK != rv) { sprintf(err_msg, "sc: C_FindObjectsFinal (certificate) failed, 0x%.4x", (int)rv); return NULL; } if (found < 1) { sprintf(err_msg, "sc: No certificate found"); return NULL; } cl = calloc(1, sizeof(sc_cert_list)); cl->cert_attr[0].type = CKA_LABEL; /* first element is the label of the cert */ cl->cert_attr[1].type = CKA_ID; /* second element is the id */ cl->cert_attr[2].type = CKA_VALUE; /* third element is the value -add risacher */ pcl = cl; for(i=0; i<found; i++) { CK_OBJECT_HANDLE pO = list[i]; rv = sclib->m_fl->C_GetAttributeValue(session, pO, pcl->cert_attr, sizeof(pcl->cert_attr)/sizeof(CK_ATTRIBUTE)); if(CKR_OK == rv) { int nr; for(nr=0; nr<sizeof(pcl->cert_attr)/sizeof(CK_ATTRIBUTE); nr++) { pcl->cert_attr[nr].pValue = calloc(pcl->cert_attr[nr].ulValueLen+1, sizeof(char *)); } rv = sclib->m_fl->C_GetAttributeValue(session, pO, pcl->cert_attr, sizeof(pcl->cert_attr)/sizeof(CK_ATTRIBUTE)); if(CKR_OK == rv) { if(i<found-1) { pcl->next = calloc(1, sizeof(sc_cert_list)); pcl = pcl->next; pcl->cert_attr[0].type = CKA_LABEL; pcl->cert_attr[1].type = CKA_ID; pcl->cert_attr[2].type = CKA_VALUE; } else { pcl->next = NULL; } } else { sprintf(err_msg, "sc: GetAttributeValue failed, no data for cert"); for(nr=0; nr<sizeof(pcl->cert_attr)/sizeof(CK_ATTRIBUTE); nr++) { free(pcl->cert_attr[nr].pValue); pcl->cert_attr[nr].pValue = NULL; } free(pcl); pcl = NULL; return cl; } } else { sprintf(err_msg, "sc: GetAttributeValue failed (cert), 0x%.4x", (int)rv); free(pcl); pcl = NULL; return cl; } } // for objects return cl; } void sc_free_pub_list(sc_pub_list *pub_list) { sc_pub_list *cl = pub_list; while(cl != NULL) { sc_pub_list *next = cl->next; int i; for(i=0; i<sizeof(cl->pub_attr)/sizeof(CK_ATTRIBUTE); i++) { free(cl->pub_attr[i].pValue); cl->pub_attr[i].pValue = NULL; } free(cl); cl = next; } pub_list = NULL; } sc_pub_list *sc_get_pub_list(sc_lib *sclib, CK_SESSION_HANDLE session, char *err_msg) { CK_RV rv; int i; /* STORE OBJECTS AND ATTRIBUTES */ sc_pub_list *pl = NULL; sc_pub_list *ppl = NULL; CK_OBJECT_HANDLE list[SC_MAX_O]; CK_ULONG found = 0; /* TEMPLATES: */ CK_BBOOL bFalse = 0; CK_BBOOL bTrue = 1; CK_OBJECT_CLASS class_public_key = CKO_PUBLIC_KEY; CK_KEY_TYPE key_type = CKK_RSA; CK_ATTRIBUTE key_template[] = { { CKA_CLASS, &class_public_key, sizeof (class_public_key) }, /* { CKA_KEY_TYPE, &key_type, sizeof (key_type) }, */ { CKA_TOKEN, &bTrue, sizeof (bTrue) }, { CKA_PRIVATE, &bFalse, sizeof (bFalse) } }; rv = sclib->m_fl->C_FindObjectsInit(session, key_template, sizeof(key_template)/sizeof(CK_ATTRIBUTE)); if (CKR_OK != rv) { sprintf(err_msg, "sc: C_FindObjectsInit (pub key) failed, 0x%.4x", (int)rv); return NULL; } rv = sclib->m_fl->C_FindObjects(session, list, SC_MAX_O-1, &found); if (CKR_OK != rv) { sprintf(err_msg, "sc: C_FindObjects (pub key) failed, 0x%.4x", (int)rv); return NULL; } rv = sclib->m_fl->C_FindObjectsFinal(session); if (CKR_OK != rv) { sprintf(err_msg, "sc: C_FindObjectsFinal (pub key) failed, 0x%.4x", (int)rv); return NULL; } if (found < 1) { sprintf(err_msg, "sc: No pub key found (beta)"); return NULL; } pl = calloc(1, sizeof(sc_pub_list)); pl->pub_attr[0].type = CKA_ID; pl->pub_attr[1].type = CKA_MODULUS_BITS; pl->pub_attr[2].type = CKA_MODULUS; pl->pub_attr[3].type = CKA_PUBLIC_EXPONENT; ppl = pl; for(i=0; i<found; i++) { CK_OBJECT_HANDLE pO = list[i]; rv = sclib->m_fl->C_GetAttributeValue(session, pO, ppl->pub_attr, sizeof(ppl->pub_attr)/sizeof(CK_ATTRIBUTE)); if(CKR_OK == rv) { int nr; for(nr=0; nr<sizeof(ppl->pub_attr)/sizeof(CK_ATTRIBUTE); nr++) { ppl->pub_attr[nr].pValue = calloc(ppl->pub_attr[nr].ulValueLen+1, sizeof(char *)); } rv = sclib->m_fl->C_GetAttributeValue(session, pO, ppl->pub_attr, sizeof(ppl->pub_attr)/sizeof(CK_ATTRIBUTE)); if(CKR_OK == rv) { if(i<found-1) { ppl->next = calloc(1, sizeof(sc_pub_list)); ppl = ppl->next; ppl->pub_attr[0].type = CKA_ID; ppl->pub_attr[1].type = CKA_MODULUS_BITS; ppl->pub_attr[2].type = CKA_MODULUS; ppl->pub_attr[3].type = CKA_PUBLIC_EXPONENT; } else { ppl->next = NULL; } } else { sprintf(err_msg, "sc: GetAttributeValue failed, no data for pub key"); for(nr=0; nr<sizeof(ppl->pub_attr)/sizeof(CK_ATTRIBUTE); nr++) { free(ppl->pub_attr[nr].pValue); ppl->pub_attr[nr].pValue = NULL; } free(ppl); ppl = NULL; return pl; } } else { sprintf(err_msg, "sc: GetAttributeValue failed (pub), 0x%.4x", (int)rv); free(ppl); ppl = NULL; return pl; } } // for objects return pl; } /* x509 Certificates are encoded in ASN.1 DER form */ /* find exponent and modulus (and lengths thereof) inside a cert. return 1 on success, 0 on failure */ int extract_key_from_cert(unsigned char* cert, int certsize, unsigned char **expo, unsigned char** modu, int* elen, int* mlen) { unsigned char *cursor = cert; int oidpos; oidpos = find_substring(cursor, certsize, OIDrsaEncryption, sizeof(OIDrsaEncryption)); if (oidpos != -1) { cursor += oidpos; /* the OID, plus the NULL, consume 12 bytes */ cursor += 12; /* skip OID and NULL */ cursor += 2; /* skip 1st BIT STRING header */ asn1_length(&cursor); /* skip length of 1st BIT STRING header */ cursor += 2; /* skip 2nd BIT STRING header */ asn1_length(&cursor); /* skip length of 2nd BIT STRING header */ /* now we should be at the start of the ASN1 INTEGER for the pubkey (whew!) */ if (02 == *(cursor++)) { *mlen = asn1_length(&cursor); if (*mlen == ~0) {return 0;} *modu = cursor; cursor += *mlen; if (02 == *(cursor++)) { *elen = asn1_length(&cursor); if (*elen == ~0) {return 0;} *expo = cursor; return 1; } } } *expo = NULL; *modu = NULL; return 0; } /* Given a handle pointing to an asn.1 BER/DER length field, return the length as an unsigned integer and update the handle to point just past the length. Note that this obviously will fail horribly if the length field is larger than the size of an unsigned int; in which case it returns ~0 (-1). */ unsigned int asn1_length(unsigned char** cursor) { if (**cursor & 0x80) { /* long form */ unsigned int length = 0; unsigned int lenlen = 0x7f & *((*cursor)++); unsigned int i; if (lenlen > sizeof (unsigned int)) { return ~0; } for (i=0; i< lenlen; i++) { length = ((length)<<8) + *((*cursor)++); } return length; } else { /* short form */ return (unsigned int) *((*cursor)++); } } int find_substring(char* haystack, long haysize, const char* needle, long needlesize) { int i, j; for (i=0; i< haysize-needlesize; i++) { for (j=0; j < needlesize; j++) { if (*(haystack+i+j) != *(needle+j)) { goto nope; } } return i; nope: j=0; } return -1; } unsigned char *generate_keystring (sc_lib *sclib, char **algorithm, int *blob_len, unsigned char *expop, int elen, unsigned char *modup, int mlen) { unsigned char *expo, *modu; unsigned char *blob, *p; int i; expo = bignum_from_bytes(expop, elen); modu = bignum_from_bytes(modup, mlen); /* risacher: I'm not precisely sure why this is here */ /* or why it's written this way */ /* Are there any interesting cases where ((8 * x) + 8) / 8 != x+1 ? */ /* I suspect that this is to make sure that the modulus and exponent are non-negative, but this is duplicative if the public key was extracted from a certificate, since ASN.1 DER already requires that integers start with a zero bit if non-negative. If the public key was retrieved from the SmartCard directly, then PKCS#11 specifies that it should be a "Big Integer", which is unsigned, and thus adding a leading zero would be required (if the most significant bit is set), because OpenSSH treats them as signed integers. Since these are handled as multi-precision integers, in theory leading zeros won't matter but means that your public key string will be 1-2 bytes longer than otherwise. */ elen = ((8 * elen) + 8) / 8; mlen = ((8 * mlen) + 8) / 8; *blob_len = 19 + elen + mlen; *algorithm = calloc(sizeof(char *), strlen("ssh-rsa")+1); strcpy(*algorithm, "ssh-rsa"); /* ugly (but used in pagent prototype) */ if(sclib->rsakey != NULL) { free(sclib->rsakey->exponent); free(sclib->rsakey->modulus); free(sclib->rsakey); } sclib->rsakey = calloc(1, sizeof(struct RSAKey)); sclib->rsakey->exponent = expo; sclib->rsakey->modulus = modu; blob = calloc(sizeof(char *), *blob_len); p = blob; SC_PUT_32BIT(p, 7); p += 4; memcpy(p, "ssh-rsa", 7); p += 7; SC_PUT_32BIT(p, elen); p += 4; for (i = elen; i--;) *p++ = bignum_byte(expo, i); SC_PUT_32BIT(p, mlen); p += 4; for (i = mlen; i--;) *p++ = bignum_byte(modu, i); sclib->m_SshPK = calloc(sizeof(char *), *blob_len); memcpy(sclib->m_SshPK, blob, *blob_len); sclib->m_SshPK_len = *blob_len; sclib->m_SshPk_alg = calloc(sizeof(char *), strlen("ssh-rsa")+1); strcpy(sclib->m_SshPk_alg, "ssh-rsa"); return blob; } unsigned char *sc_get_pub(void *f, int try_write_syslog, sc_lib *sclib, const char *token_label, const char *cert_label, char **algorithm, int *blob_len) { /* return pub_key and blob_len */ unsigned char *pub_key = NULL; sc_cert_list *cl; unsigned char *expop, *modup; int elen, mlen; /* some local helper: */ char msg[SC_STR_MAX_LEN] = ""; /* STORE OBJECTS AND ATTRIBUTES */ CK_SESSION_HANDLE session = 0; sprintf(msg, "sc: Called sc_get_pub: token_label=%s, cert_label=%s", token_label, cert_label); logevent(f, msg); /* OPEN SESSION */ session = sc_get_session(f, try_write_syslog, sclib->m_fl, token_label); if(session == 0) { return NULL; } /* SEARCH THE SPECIFIED CERTIFICATE AND DETERMINE THE ID */ { sc_cert_list *pcl; msg[0]='\0'; cl = sc_get_cert_list(sclib, session, msg); if(cl == NULL) goto err; if(strlen(msg) > 0) { logevent(f, msg); if(try_write_syslog) sc_write_syslog(msg); } pcl = cl; while(pcl != NULL) { int len = strlen(cert_label); if(pcl->cert_attr[0].ulValueLen < len) len = pcl->cert_attr[0].ulValueLen; if(strncmp(cert_label, pcl->cert_attr[0].pValue, len) == 0) { sclib->m_KeyID = calloc(sizeof(char *), pcl->cert_attr[1].ulValueLen+1); strncpy(sclib->m_KeyID, pcl->cert_attr[1].pValue, pcl->cert_attr[1].ulValueLen); { char *p_buf = calloc(1,pcl->cert_attr[0].ulValueLen+1); strncpy(p_buf, pcl->cert_attr[0].pValue, pcl->cert_attr[0].ulValueLen); sprintf(msg, "sc: Found cert attr[0]: %s", p_buf); free(p_buf); } logevent(f, msg); if(try_write_syslog) sc_write_syslog(msg); sprintf(msg, "sc: Found cert attr[1] : type 0x%x length 0x%x", pcl->cert_attr[1].type, pcl->cert_attr[1].ulValueLen); logevent(f, msg); extract_key_from_cert(pcl->cert_attr[2].pValue, pcl->cert_attr[2].ulValueLen, &expop, &modup, &elen, &mlen); if(try_write_syslog) sc_write_syslog(msg); break; } pcl = pcl->next; } } /* NOW GET THE PUB KEY FOR THIS CERT */ if(sclib->m_KeyID == NULL) { sprintf(msg, "sc: No cert found (4) : %s", cert_label); goto err; } if (NULL == expop) { /* this is the old code path that shouldn't ever happen any more */ /* the key should already be extracted */ sc_pub_list *pl; sc_pub_list *ppl; msg[0]='\0'; pl = sc_get_pub_list(sclib, session, msg); if(pl == NULL) goto err; if(strlen(msg) > 0) { logevent(f, msg); if(try_write_syslog) sc_write_syslog(msg); } ppl = pl; while(ppl != NULL) { sprintf(msg, "sc: trying ppl at 0x%x", ppl); logevent(f, msg); if(strncmp(sclib->m_KeyID, ppl->pub_attr[0].pValue, ppl->pub_attr[0].ulValueLen) == 0) { // attr 0: id // attr 2: modulus // attr 3: exponent unsigned char *blob; { char *p_buf = calloc(1, ppl->pub_attr[0].ulValueLen+1); strncpy(p_buf, ppl->pub_attr[0].pValue, ppl->pub_attr[0].ulValueLen); sprintf(msg, "sc: Found key: %s", p_buf); free(p_buf); } logevent(f, msg); if(try_write_syslog) sc_write_syslog(msg); //used in sclib free(expo); //free(modu); break; } ppl = ppl->next; } sc_free_pub_list(pl); } pub_key = generate_keystring(sclib, algorithm, blob_len, expop, elen, modup, mlen); { char *buffi = sc_base64key(pub_key, *blob_len); if (sclib->keystring) { free(sclib->keystring); } sclib->keystring = calloc (1, strlen("ssh-rsa ")+strlen(buffi)+strlen(cert_label)); sprintf(sclib->keystring, "ssh-rsa %s %s", buffi, cert_label); sprintf(msg, "sc: %s", sclib->keystring); logevent(f, msg); if(try_write_syslog) sc_write_syslog(msg); free(buffi); } if(sclib->m_SshPK == NULL) { sprintf(msg, "sc: No pub key found: %s", cert_label); goto err; } sclib->m_fl->C_CloseSession(session); sc_free_cert_list(cl); return pub_key; err: if (cl) { sc_free_cert_list(cl); } logevent(f, msg); if(try_write_syslog) sc_write_syslog(msg); sclib->m_fl->C_CloseSession(session); return NULL; } /* elements within sc_pubkey_blob must NOT be freed */ struct sc_pubkey_blob *sc_login_pub(void *f, int try_write_syslog, sc_lib *sclib, const char *token_label, const char *password) { CK_RV rv = 0; struct sc_pubkey_blob *key11; CK_SESSION_HANDLE session = 0; session = sc_get_session(f, try_write_syslog, sclib->m_fl, token_label); if(session == 0) { return NULL; } rv = sclib->m_fl->C_Login(session, CKU_USER, (CK_CHAR_PTR)password, strlen(password)); if (CKR_OK != rv) { logevent(f, "sc: Login failed for public key"); if(try_write_syslog) sc_write_syslog("sc: Login failed"); sclib->m_fl->C_CloseSession(session); return (void *)SSH2_WRONG_PASSPHRASE; } logevent(f, "sc: Login successful"); sclib->m_fl->C_Logout(session); sclib->m_fl->C_CloseSession(session); /* free when deleting sclib! */ key11 = calloc(sizeof(struct sc_pubkey_blob), 1); key11->data = sclib->m_SshPK; key11->alg = sclib->m_SshPk_alg; key11->len = sclib->m_SshPK_len; return key11; } unsigned char *sc_sig(void *f, int try_write_syslog, sc_lib *sclib, const char *token_label, const char *password_s, char *sigdata, int sigdata_len, int *sigblob_len) { CK_RV rv = 0; char msg[SC_STR_MAX_LEN] = ""; CK_SESSION_HANDLE session = 0; const char *pwd = password_s; /* TEMPLATES: */ CK_BBOOL bTrue = 1; CK_OBJECT_CLASS class_private_key = CKO_PRIVATE_KEY; CK_KEY_TYPE key_type = CKK_RSA; CK_ATTRIBUTE key_template[] = { { CKA_CLASS, &class_private_key, sizeof (class_private_key) }, { CKA_KEY_TYPE, &key_type, sizeof (key_type) }, { CKA_TOKEN, &bTrue, sizeof (bTrue) }, { CKA_SIGN, &bTrue, sizeof (bTrue) }, { CKA_PRIVATE, &bTrue, sizeof (bTrue) } }; CK_ATTRIBUTE key_getattributes[] = { {CKA_ID, NULL_PTR, 0}, /* ID to search the key */ {CKA_MODULUS, NULL_PTR, 0} }; /* STORE OBJECTS AND ATTRIBUTES */ CK_OBJECT_HANDLE list[SC_MAX_O]; CK_ULONG found = 0; CK_OBJECT_HANDLE pO; int ii,j; unsigned char *ret = NULL; *sigblob_len = 0; session = sc_get_session(f, try_write_syslog, sclib->m_fl, token_label); if(session == 0) { return NULL; } rv = sclib->m_fl->C_Login(session, CKU_USER, (CK_CHAR_PTR)pwd, strlen(pwd)); if (CKR_OK != rv) { logevent(f, "sc: Login failed in sc_sig"); sclib->m_fl->C_CloseSession(session); return NULL; } rv = sclib->m_fl->C_FindObjectsInit(session, key_template, 4); if (CKR_OK != rv) { sprintf(msg, "sc: C_FindObjectsInit priv key failed, 0x%.4x", (int)rv); goto err; } rv = sclib->m_fl->C_FindObjects(session, list, SC_MAX_O-1, &found); if (CKR_OK != rv) { sprintf(msg, "sc: C_FindObjects priv key failed, 0x%.4x", (int)rv); goto err; } rv = sclib->m_fl->C_FindObjectsFinal(session); if (CKR_OK != rv) { sprintf(msg, "sc: C_FindObjectsFinal priv key failed, 0x%.4x", (int)rv); goto err; } if (found < 1) { sprintf(msg, "sc: No priv keys found"); goto err; } for(ii=0; ii<found; ii++) { int ts = 1;//sizeof (key_getattributes) / sizeof (CK_ATTRIBUTE); int nr; pO = list[ii]; sc_write_syslog("1"); for(nr=0;nr<ts;nr++) { key_getattributes[nr].ulValueLen = 0; key_getattributes[nr].pValue = NULL; } rv = sclib->m_fl->C_GetAttributeValue(session, pO, key_getattributes, ts); if(CKR_OK == rv) { for(nr=0;nr<ts;nr++) { key_getattributes[nr].pValue = calloc(sizeof(char *),key_getattributes[nr].ulValueLen+1); } if(sclib->m_fl->C_GetAttributeValue(session, pO, key_getattributes, ts) == CKR_OK) { if(strncmp(key_getattributes[0].pValue, sclib->m_KeyID, key_getattributes[0].ulValueLen) == 0) { CK_BYTE signature[500]; CK_ULONG signature_length = 500; CK_MECHANISM mechanism = { CKM_RSA_PKCS, NULL_PTR, 0 }; unsigned char *bytes; Bignum out; int nbytes; int r; unsigned char hash_sha[20]; char *p_buf = calloc(1, key_getattributes[0].ulValueLen+1); strncpy(p_buf, key_getattributes[0].pValue, key_getattributes[0].ulValueLen); sprintf(msg, "sc: Found pkey: %s", p_buf); free(p_buf); logevent(f, msg); if(try_write_syslog) sc_write_syslog(msg); rv = sclib->m_fl->C_SignInit(session, &mechanism, pO); if (CKR_OK != rv) { free(key_getattributes[0].pValue); free(key_getattributes[1].pValue); sprintf(msg, "sc: SignInit failed, 0x%.4x", (int)rv); goto err; } /* rsa2_sign() */ SHA_Simple(sigdata, sigdata_len, hash_sha); // MD5Simple(sigdata, sigdata_len, hash_md5); { int message_len = sizeof(id_sha1) + sizeof(hash_sha); CK_BYTE *message = calloc(sizeof(CK_BYTE), message_len); for(j=0;j<sizeof(id_sha1);j++) message[j] = id_sha1[j]; memcpy((char *) &message[sizeof(id_sha1)], hash_sha, sizeof(hash_sha)); rv = sclib->m_fl->C_Sign(session, message, message_len, signature, &signature_length); free(message); if (CKR_OK != rv) { free(key_getattributes[0].pValue); free(key_getattributes[1].pValue); sprintf(msg, "sc: Sign failed, 0x%.4x", (int)rv); goto err; } } out = bignum_from_bytes(signature, signature_length); nbytes = (bignum_bitcount(out) + 7) / 8; *sigblob_len = 4 + 7 + 4 + nbytes; bytes = calloc(sizeof(char *), *sigblob_len); SC_PUT_32BIT(bytes, 7); memcpy(bytes + 4, "ssh-rsa", 7); SC_PUT_32BIT(bytes + 4 + 7, nbytes); for (r = 0; r < nbytes; r++) bytes[4 + 7 + 4 + r] = bignum_byte(out, nbytes - 1 - r); ret = bytes; free(out); free(key_getattributes[0].pValue); free(key_getattributes[1].pValue); break; } } else { logevent(f, "sc: GetAttributeValue failed, no data loaded"); } free(key_getattributes[0].pValue); free(key_getattributes[1].pValue); } else { sprintf(msg, "sc: GetAttributeValue failed (pkey), 0x%.4x", (int)rv); logevent(f, msg); if(try_write_syslog) sc_write_syslog(msg); } } sclib->m_fl->C_Logout(session); sclib->m_fl->C_CloseSession(session); return ret; err: logevent(f, msg); if(try_write_syslog) sc_write_syslog(msg); sclib->m_fl->C_Logout(session); sclib->m_fl->C_CloseSession(session); if(ret != NULL) free(ret); /* just return an invalid signature ... */ *sigblob_len = 1; return " "; } |
Added sc.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | /* -*-mode: c; indent-tabs-mode: nil; c-basic-offset: 4; -*- */ /* * This file is part of PuTTY SC, a modification of PuTTY * supporting smartcard for authentication. * * PuTTY SC is available at http://www.joebar.ch/puttysc/ * * Copyright (C) 2005-2007 Pascal Buchbinder * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #ifndef PUTTY_SC_H #define PUTTY_SC_H static const char rcsid_sc_h[] = "$Id: sc.h,v 1.19 2007/03/04 20:41:56 pbu Exp $"; struct sc_pubkey_blob { void *data; int len; char *alg; }; typedef struct sc_lib_st { HINSTANCE hLib; CK_FUNCTION_LIST_PTR m_fl; unsigned char *m_KeyID; unsigned char *m_SshPK; int m_SshPK_len; char *m_SshPk_alg; char *keystring; struct RSAKey *rsakey; /* void (*sc_lib_close)(struct sc_lib_st *); */ } sc_lib; typedef struct sc_cert_list_st { CK_ATTRIBUTE cert_attr[3]; /* types: 0=CKA_LABEL 1=CKA_ID 3=CKA_VALUE */ struct sc_cert_list_st *next; } sc_cert_list; typedef struct sc_pub_list_st { CK_ATTRIBUTE pub_attr[4]; /* types: 0=CKA_ID, 1=CKA_MODULUS_BITS, 2=CKA_MODULUS, 3=CKA_PUBLIC_EXPONENT */ struct sc_pub_list_st *next; } sc_pub_list; void sc_write_syslog(char *msg); char *sc_base64key(char *data, int len); int sc_init_library(void *f, int try_write_syslog, sc_lib *sclib, Filename *pkcs11_libfile); void sc_free_sclib(sc_lib *sclib); CK_SESSION_HANDLE sc_get_session(void *f, int try_write_syslog, CK_FUNCTION_LIST_PTR fl, const char *token_label); sc_cert_list *sc_get_cert_list(sc_lib *sclib, CK_SESSION_HANDLE session, char *err_msg); void sc_free_cert_list(sc_cert_list *cert_list); sc_pub_list *sc_get_pub_list(sc_lib *sclib, CK_SESSION_HANDLE session, char *err_msg); void sc_free_pub_list(sc_pub_list *pub_list); unsigned char *sc_get_pub(void *f, int try_write_syslog, sc_lib *sclib, const char *token_label, const char *cert_label, char **algorithm, int *blob_len); struct sc_pubkey_blob *sc_login_pub(void *f, int try_write_syslog, sc_lib *sclib, const char *token_label, const char *password); unsigned char *sc_sig(void *f, int try_write_syslog, sc_lib *sclib, const char *token_label, const char *password_s, char *sigdata, int sigdata_len, int *sigblob_len); #endif |
Changes to sercfg.c.
︙ | ︙ | |||
27 28 29 30 31 32 33 | {"Odd", SER_PAR_ODD}, {"Even", SER_PAR_EVEN}, {"Mark", SER_PAR_MARK}, {"Space", SER_PAR_SPACE}, }; int mask = ctrl->listbox.context.i; int i, j; | | < < < < | | 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | {"Odd", SER_PAR_ODD}, {"Even", SER_PAR_EVEN}, {"Mark", SER_PAR_MARK}, {"Space", SER_PAR_SPACE}, }; int mask = ctrl->listbox.context.i; int i, j; Config *cfg = (Config *)data; if (event == EVENT_REFRESH) { int oldparity = cfg->serparity;/* preserve past reentrant calls */ dlg_update_start(ctrl, dlg); dlg_listbox_clear(ctrl, dlg); for (i = 0; i < lenof(parities); i++) { if (mask & (1 << i)) dlg_listbox_addwithid(ctrl, dlg, parities[i].name, parities[i].val); } |
︙ | ︙ | |||
56 57 58 59 60 61 62 | } } if (i == lenof(parities)) { /* an unsupported setting was chosen */ dlg_listbox_select(ctrl, dlg, 0); oldparity = SER_PAR_NONE; } dlg_update_done(ctrl, dlg); | | | | < < < < | | | | 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | } } if (i == lenof(parities)) { /* an unsupported setting was chosen */ dlg_listbox_select(ctrl, dlg, 0); oldparity = SER_PAR_NONE; } dlg_update_done(ctrl, dlg); cfg->serparity = oldparity; /* restore */ } else if (event == EVENT_SELCHANGE) { int i = dlg_listbox_index(ctrl, dlg); if (i < 0) i = SER_PAR_NONE; else i = dlg_listbox_getid(ctrl, dlg, i); cfg->serparity = i; } } static void serial_flow_handler(union control *ctrl, void *dlg, void *data, int event) { static const struct { const char *name; int val; } flows[] = { {"None", SER_FLOW_NONE}, {"XON/XOFF", SER_FLOW_XONXOFF}, {"RTS/CTS", SER_FLOW_RTSCTS}, {"DSR/DTR", SER_FLOW_DSRDTR}, }; int mask = ctrl->listbox.context.i; int i, j; Config *cfg = (Config *)data; if (event == EVENT_REFRESH) { int oldflow = cfg->serflow; /* preserve past reentrant calls */ dlg_update_start(ctrl, dlg); dlg_listbox_clear(ctrl, dlg); for (i = 0; i < lenof(flows); i++) { if (mask & (1 << i)) dlg_listbox_addwithid(ctrl, dlg, flows[i].name, flows[i].val); } for (i = j = 0; i < lenof(flows); i++) { if (mask & (1 << i)) { if (oldflow == flows[i].val) { dlg_listbox_select(ctrl, dlg, j); break; } j++; } } if (i == lenof(flows)) { /* an unsupported setting was chosen */ dlg_listbox_select(ctrl, dlg, 0); oldflow = SER_FLOW_NONE; } dlg_update_done(ctrl, dlg); cfg->serflow = oldflow; /* restore */ } else if (event == EVENT_SELCHANGE) { int i = dlg_listbox_index(ctrl, dlg); if (i < 0) i = SER_FLOW_NONE; else i = dlg_listbox_getid(ctrl, dlg, i); cfg->serflow = i; } } void ser_setup_config_box(struct controlbox *b, int midsession, int parity_mask, int flow_mask) { struct controlset *s; |
︙ | ︙ | |||
177 178 179 180 181 182 183 | * midflight, although we do allow all other * reconfiguration. */ s = ctrl_getset(b, "Connection/Serial", "serline", "Select a serial line"); ctrl_editbox(s, "Serial line to connect to", 'l', 40, HELPCTX(serial_line), | | > | | | | 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 | * midflight, although we do allow all other * reconfiguration. */ s = ctrl_getset(b, "Connection/Serial", "serline", "Select a serial line"); ctrl_editbox(s, "Serial line to connect to", 'l', 40, HELPCTX(serial_line), dlg_stdeditbox_handler, I(offsetof(Config,serline)), I(sizeof(((Config *)0)->serline))); } s = ctrl_getset(b, "Connection/Serial", "sercfg", "Configure the serial line"); ctrl_editbox(s, "Speed (baud)", 's', 40, HELPCTX(serial_speed), dlg_stdeditbox_handler, I(offsetof(Config,serspeed)), I(-1)); ctrl_editbox(s, "Data bits", 'b', 40, HELPCTX(serial_databits), dlg_stdeditbox_handler,I(offsetof(Config,serdatabits)),I(-1)); /* * Stop bits come in units of one half. */ ctrl_editbox(s, "Stop bits", 't', 40, HELPCTX(serial_stopbits), dlg_stdeditbox_handler,I(offsetof(Config,serstopbits)),I(-2)); ctrl_droplist(s, "Parity", 'p', 40, HELPCTX(serial_parity), serial_parity_handler, I(parity_mask)); ctrl_droplist(s, "Flow control", 'f', 40, HELPCTX(serial_flow), serial_flow_handler, I(flow_mask)); } |
Changes to settings.c.
︙ | ︙ | |||
66 67 68 69 70 71 72 | Backend **p; for (p = backends; *p != NULL; p++) if ((*p)->protocol == proto) return *p; return NULL; } | | < | > | > | | | > > > > | > > | > | | > | > | > | > | | | < > | | > | < < | < < | > | | | < | < < | | < | < < | | < < < < < | < | < < < < < < < < < < | < < < > < < | < < < < | | < < < < < < < < < < < < < | < < < < < < | < | < | < < | < | < < < < < < | < < < | < < < < < < < < < | < | < < < < < < | < | < | | | | < < < < < | < < < | < | | 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 | Backend **p; for (p = backends; *p != NULL; p++) if ((*p)->protocol == proto) return *p; return NULL; } int get_remote_username(Config *cfg, char *user, size_t len) { if (*cfg->username) { strncpy(user, cfg->username, len); user[len-1] = '\0'; } else { if (cfg->username_from_env) { /* Use local username. */ char *luser = get_username(); if (luser) { strncpy(user, luser, len); user[len-1] = '\0'; sfree(luser); } else { *user = '\0'; } } else { *user = '\0'; } } return (*user != '\0'); } static void gpps(void *handle, const char *name, const char *def, char *val, int len) { if (!read_setting_s(handle, name, val, len)) { char *pdef; pdef = platform_default_s(name); if (pdef) { strncpy(val, pdef, len); sfree(pdef); } else { strncpy(val, def, len); } val[len - 1] = '\0'; } } /* * gppfont and gppfile cannot have local defaults, since the very * format of a Filename or Font is platform-dependent. So the * platform-dependent functions MUST return some sort of value. */ static void gppfont(void *handle, const char *name, FontSpec *result) { if (!read_setting_fontspec(handle, name, result)) *result = platform_default_fontspec(name); } static void gppfile(void *handle, const char *name, Filename *result) { if (!read_setting_filename(handle, name, result)) *result = platform_default_filename(name); } static void gppi(void *handle, char *name, int def, int *i) { def = platform_default_i(name, def); *i = read_setting_i(handle, name, def); } /* * Read a set of name-value pairs in the format we occasionally use: * NAME\tVALUE\0NAME\tVALUE\0\0 in memory * NAME=VALUE,NAME=VALUE, in storage * `def' is in the storage format. */ static void gppmap(void *handle, char *name, char *def, char *val, int len) { char *buf = snewn(2*len, char), *p, *q; gpps(handle, name, def, buf, 2*len); p = buf; q = val; while (*p) { while (*p && *p != ',') { int c = *p++; if (c == '=') c = '\t'; if (c == '\\') c = *p++; *q++ = c; } if (*p == ',') p++; *q++ = '\0'; } *q = '\0'; sfree(buf); } /* * Write a set of name/value pairs in the above format. */ static void wmap(void *handle, char const *key, char const *value, int len) { char *buf = snewn(2*len, char), *p; const char *q; p = buf; q = value; while (*q) { while (*q) { int c = *q++; if (c == '=' || c == ',' || c == '\\') *p++ = '\\'; if (c == '\t') c = '='; *p++ = c; } *p++ = ','; q++; } *p = '\0'; write_setting_s(handle, key, buf); sfree(buf); } static int key2val(const struct keyvalwhere *mapping, int nmaps, char *key) { int i; |
︙ | ︙ | |||
290 291 292 293 294 295 296 | * Helper function to parse a comma-separated list of strings into * a preference list array of values. Any missing values are added * to the end and duplicates are weeded. * XXX: assumes vals in 'mapping' are small +ve integers */ static void gprefs(void *sesskey, char *name, char *def, const struct keyvalwhere *mapping, int nvals, | | | | < | < < | 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 | * Helper function to parse a comma-separated list of strings into * a preference list array of values. Any missing values are added * to the end and duplicates are weeded. * XXX: assumes vals in 'mapping' are small +ve integers */ static void gprefs(void *sesskey, char *name, char *def, const struct keyvalwhere *mapping, int nvals, int *array) { char commalist[256]; char *p, *q; int i, j, n, v, pos; unsigned long seen = 0; /* bitmap for weeding dups etc */ /* * Fetch the string which we'll parse as a comma-separated list. */ gpps(sesskey, name, def, commalist, sizeof(commalist)); /* * Go through that list and convert it into values. */ n = 0; p = commalist; while (1) { while (*p && *p == ',') p++; if (!*p) break; /* no more words */ q = p; while (*p && *p != ',') p++; if (*p) *p++ = '\0'; v = key2val(mapping, nvals, q); if (v != -1 && !(seen & (1 << v))) { seen |= (1 << v); array[n++] = v; } } /* * Now go through 'mapping' and add values that weren't mentioned * in the list we fetched. We may have to loop over it multiple * times so that we add values before other values whose default * positions depend on them. */ while (n < nvals) { |
︙ | ︙ | |||
351 352 353 354 355 356 357 | * OK, we can work out where to add this element, so * do so. */ if (mapping[i].vrel == -1) { pos = (mapping[i].where < 0 ? n : 0); } else { for (j = 0; j < n; j++) | < | | < | | | < | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > | | | | | | | | | > | > > > > > > > > > > > > > > > > > > | < < < < < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < < | | | | | | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | | | | | | | | | | | | | | | < < < | | | | | | | | | | | | | | | | | | | | | < | | | | | | | | | > | < > > > > > | > > > > > | > | > | | | | | | | | | | | | > | < | > | | > | > | | | | | > | | | | | | | | | | | > | | | | | | | | | | > > > > > > > > > > > > > > > > > > > > > | < < < < | | | | | | | | | | > | | | | | | | | | | | | | | | | > | | | | | | | | | | | | | | | | | < > | | | | < > | | | | | | | | | | | | | | | | | | | | | | | | < | | | | | | | | < | > | | | | | | | | | | | | | | > | | | | | | | | | | | | | | | | | | < | | | | | | | | | | | | | | | | < < < | | | 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 | * OK, we can work out where to add this element, so * do so. */ if (mapping[i].vrel == -1) { pos = (mapping[i].where < 0 ? n : 0); } else { for (j = 0; j < n; j++) if (array[j] == mapping[i].vrel) break; assert(j < n); /* implied by (seen & (1<<vrel)) */ pos = (mapping[i].where < 0 ? j : j+1); } /* * And add it. */ for (j = n-1; j >= pos; j--) array[j+1] = array[j]; array[pos] = mapping[i].v; n++; } } } } /* * Write out a preference list. */ static void wprefs(void *sesskey, char *name, const struct keyvalwhere *mapping, int nvals, int *array) { char *buf, *p; int i, maxlen; for (maxlen = i = 0; i < nvals; i++) { const char *s = val2key(mapping, nvals, array[i]); if (s) { maxlen += (maxlen > 0 ? 1 : 0) + strlen(s); } } buf = snewn(maxlen + 1, char); p = buf; for (i = 0; i < nvals; i++) { const char *s = val2key(mapping, nvals, array[i]); if (s) { p += sprintf(p, "%s%s", (p > buf ? "," : ""), s); } } assert(p - buf == maxlen); *p = '\0'; write_setting_s(sesskey, name, buf); sfree(buf); } char *save_settings(char *section, Config * cfg) { void *sesskey; char *errmsg; sesskey = open_settings_w(section, &errmsg); if (!sesskey) return errmsg; save_open_settings(sesskey, cfg); close_settings_w(sesskey); return NULL; } void save_open_settings(void *sesskey, Config *cfg) { int i; char *p; write_setting_i(sesskey, "Present", 1); write_setting_s(sesskey, "HostName", cfg->host); write_setting_filename(sesskey, "LogFileName", cfg->logfilename); write_setting_i(sesskey, "LogType", cfg->logtype); write_setting_i(sesskey, "LogFileClash", cfg->logxfovr); write_setting_i(sesskey, "LogFlush", cfg->logflush); write_setting_i(sesskey, "SSHLogOmitPasswords", cfg->logomitpass); write_setting_i(sesskey, "SSHLogOmitData", cfg->logomitdata); p = "raw"; { const Backend *b = backend_from_proto(cfg->protocol); if (b) p = b->name; } write_setting_s(sesskey, "Protocol", p); write_setting_i(sesskey, "PortNumber", cfg->port); /* The CloseOnExit numbers are arranged in a different order from * the standard FORCE_ON / FORCE_OFF / AUTO. */ write_setting_i(sesskey, "CloseOnExit", (cfg->close_on_exit+2)%3); write_setting_i(sesskey, "WarnOnClose", !!cfg->warn_on_close); write_setting_i(sesskey, "PingInterval", cfg->ping_interval / 60); /* minutes */ write_setting_i(sesskey, "PingIntervalSecs", cfg->ping_interval % 60); /* seconds */ write_setting_i(sesskey, "TCPNoDelay", cfg->tcp_nodelay); write_setting_i(sesskey, "TCPKeepalives", cfg->tcp_keepalives); write_setting_s(sesskey, "TerminalType", cfg->termtype); write_setting_s(sesskey, "TerminalSpeed", cfg->termspeed); wmap(sesskey, "TerminalModes", cfg->ttymodes, lenof(cfg->ttymodes)); /* Address family selection */ write_setting_i(sesskey, "AddressFamily", cfg->addressfamily); /* proxy settings */ write_setting_s(sesskey, "ProxyExcludeList", cfg->proxy_exclude_list); write_setting_i(sesskey, "ProxyDNS", (cfg->proxy_dns+2)%3); write_setting_i(sesskey, "ProxyLocalhost", cfg->even_proxy_localhost); write_setting_i(sesskey, "ProxyMethod", cfg->proxy_type); write_setting_s(sesskey, "ProxyHost", cfg->proxy_host); write_setting_i(sesskey, "ProxyPort", cfg->proxy_port); write_setting_s(sesskey, "ProxyUsername", cfg->proxy_username); write_setting_s(sesskey, "ProxyPassword", cfg->proxy_password); write_setting_s(sesskey, "ProxyTelnetCommand", cfg->proxy_telnet_command); wmap(sesskey, "Environment", cfg->environmt, lenof(cfg->environmt)); write_setting_s(sesskey, "UserName", cfg->username); write_setting_i(sesskey, "UserNameFromEnvironment", cfg->username_from_env); write_setting_s(sesskey, "LocalUserName", cfg->localusername); write_setting_i(sesskey, "NoPTY", cfg->nopty); write_setting_i(sesskey, "Compression", cfg->compression); write_setting_i(sesskey, "TryAgent", cfg->tryagent); write_setting_i(sesskey, "AgentFwd", cfg->agentfwd); write_setting_i(sesskey, "GssapiFwd", cfg->gssapifwd); write_setting_i(sesskey, "ChangeUsername", cfg->change_username); wprefs(sesskey, "Cipher", ciphernames, CIPHER_MAX, cfg->ssh_cipherlist); wprefs(sesskey, "KEX", kexnames, KEX_MAX, cfg->ssh_kexlist); write_setting_i(sesskey, "RekeyTime", cfg->ssh_rekey_time); write_setting_s(sesskey, "RekeyBytes", cfg->ssh_rekey_data); write_setting_i(sesskey, "SshNoAuth", cfg->ssh_no_userauth); write_setting_i(sesskey, "SshBanner", cfg->ssh_show_banner); write_setting_i(sesskey, "AuthTIS", cfg->try_tis_auth); write_setting_i(sesskey, "AuthKI", cfg->try_ki_auth); write_setting_i(sesskey, "AuthGSSAPI", cfg->try_gssapi_auth); #ifndef NO_GSSAPI wprefs(sesskey, "GSSLibs", gsslibkeywords, ngsslibs, cfg->ssh_gsslist); write_setting_filename(sesskey, "GSSCustom", cfg->ssh_gss_custom); #endif write_setting_i(sesskey, "SshNoShell", cfg->ssh_no_shell); write_setting_i(sesskey, "SshProt", cfg->sshprot); write_setting_s(sesskey, "LogHost", cfg->loghost); write_setting_i(sesskey, "SSH2DES", cfg->ssh2_des_cbc); write_setting_filename(sesskey, "PublicKeyFile", cfg->keyfile); write_setting_s(sesskey, "RemoteCommand", cfg->remote_cmd); write_setting_i(sesskey, "RFCEnviron", cfg->rfc_environ); /* PuTTY SC start */ write_setting_i(sesskey, "AuthPKCS11", cfg->try_pkcs11_auth); write_setting_filename(sesskey, "PKCS11LibFile", cfg->pkcs11_libfile); write_setting_s(sesskey, "PKCS11TokenLabel", cfg->pkcs11_token_label); write_setting_s(sesskey, "PKCS11CertLabel", cfg->pkcs11_cert_label); /* PuTTY SC end */ /* PuTTY CAPI start */ #ifdef _WINDOWS write_setting_i(sesskey, "AuthCAPI", cfg->try_capi_auth); write_setting_s(sesskey, "CAPICertID", cfg->capi_certID); #endif /* PuTTY CAPI end */ write_setting_i(sesskey, "PassiveTelnet", cfg->passive_telnet); write_setting_i(sesskey, "BackspaceIsDelete", cfg->bksp_is_delete); write_setting_i(sesskey, "RXVTHomeEnd", cfg->rxvt_homeend); write_setting_i(sesskey, "LinuxFunctionKeys", cfg->funky_type); write_setting_i(sesskey, "NoApplicationKeys", cfg->no_applic_k); write_setting_i(sesskey, "NoApplicationCursors", cfg->no_applic_c); write_setting_i(sesskey, "NoMouseReporting", cfg->no_mouse_rep); write_setting_i(sesskey, "NoRemoteResize", cfg->no_remote_resize); write_setting_i(sesskey, "NoAltScreen", cfg->no_alt_screen); write_setting_i(sesskey, "NoRemoteWinTitle", cfg->no_remote_wintitle); write_setting_i(sesskey, "RemoteQTitleAction", cfg->remote_qtitle_action); write_setting_i(sesskey, "NoDBackspace", cfg->no_dbackspace); write_setting_i(sesskey, "NoRemoteCharset", cfg->no_remote_charset); write_setting_i(sesskey, "ApplicationCursorKeys", cfg->app_cursor); write_setting_i(sesskey, "ApplicationKeypad", cfg->app_keypad); write_setting_i(sesskey, "NetHackKeypad", cfg->nethack_keypad); write_setting_i(sesskey, "AltF4", cfg->alt_f4); write_setting_i(sesskey, "AltSpace", cfg->alt_space); write_setting_i(sesskey, "AltOnly", cfg->alt_only); write_setting_i(sesskey, "ComposeKey", cfg->compose_key); write_setting_i(sesskey, "CtrlAltKeys", cfg->ctrlaltkeys); write_setting_i(sesskey, "TelnetKey", cfg->telnet_keyboard); write_setting_i(sesskey, "TelnetRet", cfg->telnet_newline); write_setting_i(sesskey, "LocalEcho", cfg->localecho); write_setting_i(sesskey, "LocalEdit", cfg->localedit); write_setting_s(sesskey, "Answerback", cfg->answerback); write_setting_i(sesskey, "AlwaysOnTop", cfg->alwaysontop); write_setting_i(sesskey, "FullScreenOnAltEnter", cfg->fullscreenonaltenter); write_setting_i(sesskey, "HideMousePtr", cfg->hide_mouseptr); write_setting_i(sesskey, "SunkenEdge", cfg->sunken_edge); write_setting_i(sesskey, "WindowBorder", cfg->window_border); write_setting_i(sesskey, "CurType", cfg->cursor_type); write_setting_i(sesskey, "BlinkCur", cfg->blink_cur); write_setting_i(sesskey, "Beep", cfg->beep); write_setting_i(sesskey, "BeepInd", cfg->beep_ind); write_setting_filename(sesskey, "BellWaveFile", cfg->bell_wavefile); write_setting_i(sesskey, "BellOverload", cfg->bellovl); write_setting_i(sesskey, "BellOverloadN", cfg->bellovl_n); write_setting_i(sesskey, "BellOverloadT", cfg->bellovl_t #ifdef PUTTY_UNIX_H * 1000 #endif ); write_setting_i(sesskey, "BellOverloadS", cfg->bellovl_s #ifdef PUTTY_UNIX_H * 1000 #endif ); write_setting_i(sesskey, "ScrollbackLines", cfg->savelines); write_setting_i(sesskey, "DECOriginMode", cfg->dec_om); write_setting_i(sesskey, "AutoWrapMode", cfg->wrap_mode); write_setting_i(sesskey, "LFImpliesCR", cfg->lfhascr); write_setting_i(sesskey, "CRImpliesLF", cfg->crhaslf); write_setting_i(sesskey, "DisableArabicShaping", cfg->arabicshaping); write_setting_i(sesskey, "DisableBidi", cfg->bidi); write_setting_i(sesskey, "WinNameAlways", cfg->win_name_always); write_setting_s(sesskey, "WinTitle", cfg->wintitle); write_setting_i(sesskey, "TermWidth", cfg->width); write_setting_i(sesskey, "TermHeight", cfg->height); write_setting_fontspec(sesskey, "Font", cfg->font); write_setting_i(sesskey, "FontQuality", cfg->font_quality); write_setting_i(sesskey, "FontVTMode", cfg->vtmode); write_setting_i(sesskey, "UseSystemColours", cfg->system_colour); write_setting_i(sesskey, "TryPalette", cfg->try_palette); write_setting_i(sesskey, "ANSIColour", cfg->ansi_colour); write_setting_i(sesskey, "Xterm256Colour", cfg->xterm_256_colour); write_setting_i(sesskey, "BoldAsColour", cfg->bold_colour); for (i = 0; i < 22; i++) { char buf[20], buf2[30]; sprintf(buf, "Colour%d", i); sprintf(buf2, "%d,%d,%d", cfg->colours[i][0], cfg->colours[i][1], cfg->colours[i][2]); write_setting_s(sesskey, buf, buf2); } write_setting_i(sesskey, "RawCNP", cfg->rawcnp); write_setting_i(sesskey, "PasteRTF", cfg->rtf_paste); write_setting_i(sesskey, "MouseIsXterm", cfg->mouse_is_xterm); write_setting_i(sesskey, "RectSelect", cfg->rect_select); write_setting_i(sesskey, "MouseOverride", cfg->mouse_override); for (i = 0; i < 256; i += 32) { char buf[20], buf2[256]; int j; sprintf(buf, "Wordness%d", i); *buf2 = '\0'; for (j = i; j < i + 32; j++) { sprintf(buf2 + strlen(buf2), "%s%d", (*buf2 ? "," : ""), cfg->wordness[j]); } write_setting_s(sesskey, buf, buf2); } write_setting_s(sesskey, "LineCodePage", cfg->line_codepage); write_setting_i(sesskey, "CJKAmbigWide", cfg->cjk_ambig_wide); write_setting_i(sesskey, "UTF8Override", cfg->utf8_override); write_setting_s(sesskey, "Printer", cfg->printer); write_setting_i(sesskey, "CapsLockCyr", cfg->xlat_capslockcyr); write_setting_i(sesskey, "ScrollBar", cfg->scrollbar); write_setting_i(sesskey, "ScrollBarFullScreen", cfg->scrollbar_in_fullscreen); write_setting_i(sesskey, "ScrollOnKey", cfg->scroll_on_key); write_setting_i(sesskey, "ScrollOnDisp", cfg->scroll_on_disp); write_setting_i(sesskey, "EraseToScrollback", cfg->erase_to_scrollback); write_setting_i(sesskey, "LockSize", cfg->resize_action); write_setting_i(sesskey, "BCE", cfg->bce); write_setting_i(sesskey, "BlinkText", cfg->blinktext); write_setting_i(sesskey, "X11Forward", cfg->x11_forward); write_setting_s(sesskey, "X11Display", cfg->x11_display); write_setting_i(sesskey, "X11AuthType", cfg->x11_auth); write_setting_filename(sesskey, "X11AuthFile", cfg->xauthfile); write_setting_i(sesskey, "LocalPortAcceptAll", cfg->lport_acceptall); write_setting_i(sesskey, "RemotePortAcceptAll", cfg->rport_acceptall); wmap(sesskey, "PortForwardings", cfg->portfwd, lenof(cfg->portfwd)); write_setting_i(sesskey, "BugIgnore1", 2-cfg->sshbug_ignore1); write_setting_i(sesskey, "BugPlainPW1", 2-cfg->sshbug_plainpw1); write_setting_i(sesskey, "BugRSA1", 2-cfg->sshbug_rsa1); write_setting_i(sesskey, "BugIgnore2", 2-cfg->sshbug_ignore2); write_setting_i(sesskey, "BugHMAC2", 2-cfg->sshbug_hmac2); write_setting_i(sesskey, "BugDeriveKey2", 2-cfg->sshbug_derivekey2); write_setting_i(sesskey, "BugRSAPad2", 2-cfg->sshbug_rsapad2); write_setting_i(sesskey, "BugPKSessID2", 2-cfg->sshbug_pksessid2); write_setting_i(sesskey, "BugRekey2", 2-cfg->sshbug_rekey2); write_setting_i(sesskey, "BugMaxPkt2", 2-cfg->sshbug_maxpkt2); write_setting_i(sesskey, "StampUtmp", cfg->stamp_utmp); write_setting_i(sesskey, "LoginShell", cfg->login_shell); write_setting_i(sesskey, "ScrollbarOnLeft", cfg->scrollbar_on_left); write_setting_fontspec(sesskey, "BoldFont", cfg->boldfont); write_setting_fontspec(sesskey, "WideFont", cfg->widefont); write_setting_fontspec(sesskey, "WideBoldFont", cfg->wideboldfont); write_setting_i(sesskey, "ShadowBold", cfg->shadowbold); write_setting_i(sesskey, "ShadowBoldOffset", cfg->shadowboldoffset); write_setting_s(sesskey, "SerialLine", cfg->serline); write_setting_i(sesskey, "SerialSpeed", cfg->serspeed); write_setting_i(sesskey, "SerialDataBits", cfg->serdatabits); write_setting_i(sesskey, "SerialStopHalfbits", cfg->serstopbits); write_setting_i(sesskey, "SerialParity", cfg->serparity); write_setting_i(sesskey, "SerialFlowControl", cfg->serflow); write_setting_s(sesskey, "WindowClass", cfg->winclass); } void load_settings(char *section, Config * cfg) { void *sesskey; sesskey = open_settings_r(section); load_open_settings(sesskey, cfg); close_settings_r(sesskey); if (cfg_launchable(cfg)) add_session_to_jumplist(section); } void load_open_settings(void *sesskey, Config *cfg) { int i; char prot[10]; cfg->ssh_subsys = 0; /* FIXME: load this properly */ cfg->remote_cmd_ptr = NULL; cfg->remote_cmd_ptr2 = NULL; cfg->ssh_nc_host[0] = '\0'; gpps(sesskey, "HostName", "", cfg->host, sizeof(cfg->host)); gppfile(sesskey, "LogFileName", &cfg->logfilename); gppi(sesskey, "LogType", 0, &cfg->logtype); gppi(sesskey, "LogFileClash", LGXF_ASK, &cfg->logxfovr); gppi(sesskey, "LogFlush", 1, &cfg->logflush); gppi(sesskey, "SSHLogOmitPasswords", 1, &cfg->logomitpass); gppi(sesskey, "SSHLogOmitData", 0, &cfg->logomitdata); gpps(sesskey, "Protocol", "default", prot, 10); cfg->protocol = default_protocol; cfg->port = default_port; { const Backend *b = backend_from_name(prot); if (b) { cfg->protocol = b->protocol; gppi(sesskey, "PortNumber", default_port, &cfg->port); } } /* Address family selection */ gppi(sesskey, "AddressFamily", ADDRTYPE_UNSPEC, &cfg->addressfamily); /* The CloseOnExit numbers are arranged in a different order from * the standard FORCE_ON / FORCE_OFF / AUTO. */ gppi(sesskey, "CloseOnExit", 1, &i); cfg->close_on_exit = (i+1)%3; gppi(sesskey, "WarnOnClose", 1, &cfg->warn_on_close); { /* This is two values for backward compatibility with 0.50/0.51 */ int pingmin, pingsec; gppi(sesskey, "PingInterval", 0, &pingmin); gppi(sesskey, "PingIntervalSecs", 0, &pingsec); cfg->ping_interval = pingmin * 60 + pingsec; } gppi(sesskey, "TCPNoDelay", 1, &cfg->tcp_nodelay); gppi(sesskey, "TCPKeepalives", 0, &cfg->tcp_keepalives); gpps(sesskey, "TerminalType", "xterm", cfg->termtype, sizeof(cfg->termtype)); gpps(sesskey, "TerminalSpeed", "38400,38400", cfg->termspeed, sizeof(cfg->termspeed)); { /* This hardcodes a big set of defaults in any new saved * sessions. Let's hope we don't change our mind. */ int i; char *def = dupstr(""); /* Default: all set to "auto" */ for (i = 0; ttymodes[i]; i++) { char *def2 = dupprintf("%s%s=A,", def, ttymodes[i]); sfree(def); def = def2; } gppmap(sesskey, "TerminalModes", def, cfg->ttymodes, lenof(cfg->ttymodes)); sfree(def); } /* proxy settings */ gpps(sesskey, "ProxyExcludeList", "", cfg->proxy_exclude_list, sizeof(cfg->proxy_exclude_list)); gppi(sesskey, "ProxyDNS", 1, &i); cfg->proxy_dns = (i+1)%3; gppi(sesskey, "ProxyLocalhost", 0, &cfg->even_proxy_localhost); gppi(sesskey, "ProxyMethod", -1, &cfg->proxy_type); if (cfg->proxy_type == -1) { int i; gppi(sesskey, "ProxyType", 0, &i); if (i == 0) cfg->proxy_type = PROXY_NONE; else if (i == 1) cfg->proxy_type = PROXY_HTTP; else if (i == 3) cfg->proxy_type = PROXY_TELNET; else if (i == 4) cfg->proxy_type = PROXY_CMD; else { gppi(sesskey, "ProxySOCKSVersion", 5, &i); if (i == 5) cfg->proxy_type = PROXY_SOCKS5; else cfg->proxy_type = PROXY_SOCKS4; } } gpps(sesskey, "ProxyHost", "proxy", cfg->proxy_host, sizeof(cfg->proxy_host)); gppi(sesskey, "ProxyPort", 80, &cfg->proxy_port); gpps(sesskey, "ProxyUsername", "", cfg->proxy_username, sizeof(cfg->proxy_username)); gpps(sesskey, "ProxyPassword", "", cfg->proxy_password, sizeof(cfg->proxy_password)); gpps(sesskey, "ProxyTelnetCommand", "connect %host %port\\n", cfg->proxy_telnet_command, sizeof(cfg->proxy_telnet_command)); gppmap(sesskey, "Environment", "", cfg->environmt, lenof(cfg->environmt)); gpps(sesskey, "UserName", "", cfg->username, sizeof(cfg->username)); gppi(sesskey, "UserNameFromEnvironment", 0, &cfg->username_from_env); gpps(sesskey, "LocalUserName", "", cfg->localusername, sizeof(cfg->localusername)); gppi(sesskey, "NoPTY", 0, &cfg->nopty); gppi(sesskey, "Compression", 0, &cfg->compression); gppi(sesskey, "TryAgent", 1, &cfg->tryagent); gppi(sesskey, "AgentFwd", 0, &cfg->agentfwd); gppi(sesskey, "ChangeUsername", 0, &cfg->change_username); gppi(sesskey, "GssapiFwd", 0, &cfg->gssapifwd); gprefs(sesskey, "Cipher", "\0", ciphernames, CIPHER_MAX, cfg->ssh_cipherlist); { /* Backward-compatibility: we used to have an option to * disable gex under the "bugs" panel after one report of * a server which offered it then choked, but we never got * a server version string or any other reports. */ char *default_kexes; gppi(sesskey, "BugDHGEx2", 0, &i); i = 2-i; if (i == FORCE_ON) default_kexes = "dh-group14-sha1,dh-group1-sha1,rsa,WARN,dh-gex-sha1"; else default_kexes = "dh-gex-sha1,dh-group14-sha1,dh-group1-sha1,rsa,WARN"; gprefs(sesskey, "KEX", default_kexes, kexnames, KEX_MAX, cfg->ssh_kexlist); } gppi(sesskey, "RekeyTime", 60, &cfg->ssh_rekey_time); gpps(sesskey, "RekeyBytes", "1G", cfg->ssh_rekey_data, sizeof(cfg->ssh_rekey_data)); gppi(sesskey, "SshProt", 2, &cfg->sshprot); gpps(sesskey, "LogHost", "", cfg->loghost, sizeof(cfg->loghost)); gppi(sesskey, "SSH2DES", 0, &cfg->ssh2_des_cbc); gppi(sesskey, "SshNoAuth", 0, &cfg->ssh_no_userauth); gppi(sesskey, "SshBanner", 1, &cfg->ssh_show_banner); gppi(sesskey, "AuthTIS", 0, &cfg->try_tis_auth); gppi(sesskey, "AuthKI", 1, &cfg->try_ki_auth); gppi(sesskey, "AuthGSSAPI", 1, &cfg->try_gssapi_auth); #ifndef NO_GSSAPI gprefs(sesskey, "GSSLibs", "\0", gsslibkeywords, ngsslibs, cfg->ssh_gsslist); gppfile(sesskey, "GSSCustom", &cfg->ssh_gss_custom); #endif gppi(sesskey, "SshNoShell", 0, &cfg->ssh_no_shell); gppfile(sesskey, "PublicKeyFile", &cfg->keyfile); gpps(sesskey, "RemoteCommand", "", cfg->remote_cmd, sizeof(cfg->remote_cmd)); gppi(sesskey, "RFCEnviron", 0, &cfg->rfc_environ); gppi(sesskey, "PassiveTelnet", 0, &cfg->passive_telnet); /* PuTTY SC start */ gppi(sesskey, "AuthPKCS11", 0, &cfg->try_pkcs11_auth); gppfile(sesskey, "PKCS11LibFile", &cfg->pkcs11_libfile); { int k; for(k=0;k<sizeof(cfg->pkcs11_token_label);k++) cfg->pkcs11_token_label[k] = '\0'; } gpps(sesskey, "PKCS11TokenLabel", "", cfg->pkcs11_token_label, sizeof(cfg->pkcs11_token_label)); { int k; for(k=0;k<sizeof(cfg->pkcs11_cert_label);k++) cfg->pkcs11_cert_label[k] = '\0'; } gpps(sesskey, "PKCS11CertLabel", "", cfg->pkcs11_cert_label, sizeof(cfg->pkcs11_cert_label)); /* PuTTY SC end */ /* PuTTY CAPI start */ #ifdef _WINDOWS gppi(sesskey, "AuthCAPI", 0, &cfg->try_capi_auth); gpps(sesskey, "CAPICertID", "", cfg->capi_certID, sizeof(cfg->capi_certID)); #endif /* PuTTY CAPI end */ gppi(sesskey, "BackspaceIsDelete", 1, &cfg->bksp_is_delete); gppi(sesskey, "RXVTHomeEnd", 0, &cfg->rxvt_homeend); gppi(sesskey, "LinuxFunctionKeys", 0, &cfg->funky_type); gppi(sesskey, "NoApplicationKeys", 0, &cfg->no_applic_k); gppi(sesskey, "NoApplicationCursors", 0, &cfg->no_applic_c); gppi(sesskey, "NoMouseReporting", 0, &cfg->no_mouse_rep); gppi(sesskey, "NoRemoteResize", 0, &cfg->no_remote_resize); gppi(sesskey, "NoAltScreen", 0, &cfg->no_alt_screen); gppi(sesskey, "NoRemoteWinTitle", 0, &cfg->no_remote_wintitle); { /* Backward compatibility */ int no_remote_qtitle; gppi(sesskey, "NoRemoteQTitle", 1, &no_remote_qtitle); /* We deliberately interpret the old setting of "no response" as * "empty string". This changes the behaviour, but hopefully for * the better; the user can always recover the old behaviour. */ gppi(sesskey, "RemoteQTitleAction", no_remote_qtitle ? TITLE_EMPTY : TITLE_REAL, &cfg->remote_qtitle_action); } gppi(sesskey, "NoDBackspace", 0, &cfg->no_dbackspace); gppi(sesskey, "NoRemoteCharset", 0, &cfg->no_remote_charset); gppi(sesskey, "ApplicationCursorKeys", 0, &cfg->app_cursor); gppi(sesskey, "ApplicationKeypad", 0, &cfg->app_keypad); gppi(sesskey, "NetHackKeypad", 0, &cfg->nethack_keypad); gppi(sesskey, "AltF4", 1, &cfg->alt_f4); gppi(sesskey, "AltSpace", 0, &cfg->alt_space); gppi(sesskey, "AltOnly", 0, &cfg->alt_only); gppi(sesskey, "ComposeKey", 0, &cfg->compose_key); gppi(sesskey, "CtrlAltKeys", 1, &cfg->ctrlaltkeys); gppi(sesskey, "TelnetKey", 0, &cfg->telnet_keyboard); gppi(sesskey, "TelnetRet", 1, &cfg->telnet_newline); gppi(sesskey, "LocalEcho", AUTO, &cfg->localecho); gppi(sesskey, "LocalEdit", AUTO, &cfg->localedit); gpps(sesskey, "Answerback", "PuTTY", cfg->answerback, sizeof(cfg->answerback)); gppi(sesskey, "AlwaysOnTop", 0, &cfg->alwaysontop); gppi(sesskey, "FullScreenOnAltEnter", 0, &cfg->fullscreenonaltenter); gppi(sesskey, "HideMousePtr", 0, &cfg->hide_mouseptr); gppi(sesskey, "SunkenEdge", 0, &cfg->sunken_edge); gppi(sesskey, "WindowBorder", 1, &cfg->window_border); gppi(sesskey, "CurType", 0, &cfg->cursor_type); gppi(sesskey, "BlinkCur", 0, &cfg->blink_cur); /* pedantic compiler tells me I can't use &cfg->beep as an int * :-) */ gppi(sesskey, "Beep", 1, &cfg->beep); gppi(sesskey, "BeepInd", 0, &cfg->beep_ind); gppfile(sesskey, "BellWaveFile", &cfg->bell_wavefile); gppi(sesskey, "BellOverload", 1, &cfg->bellovl); gppi(sesskey, "BellOverloadN", 5, &cfg->bellovl_n); gppi(sesskey, "BellOverloadT", 2*TICKSPERSEC #ifdef PUTTY_UNIX_H *1000 #endif , &i); cfg->bellovl_t = i #ifdef PUTTY_UNIX_H / 1000 #endif ; gppi(sesskey, "BellOverloadS", 5*TICKSPERSEC #ifdef PUTTY_UNIX_H *1000 #endif , &i); cfg->bellovl_s = i #ifdef PUTTY_UNIX_H / 1000 #endif ; gppi(sesskey, "ScrollbackLines", 200, &cfg->savelines); gppi(sesskey, "DECOriginMode", 0, &cfg->dec_om); gppi(sesskey, "AutoWrapMode", 1, &cfg->wrap_mode); gppi(sesskey, "LFImpliesCR", 0, &cfg->lfhascr); gppi(sesskey, "CRImpliesLF", 0, &cfg->crhaslf); gppi(sesskey, "DisableArabicShaping", 0, &cfg->arabicshaping); gppi(sesskey, "DisableBidi", 0, &cfg->bidi); gppi(sesskey, "WinNameAlways", 1, &cfg->win_name_always); gpps(sesskey, "WinTitle", "", cfg->wintitle, sizeof(cfg->wintitle)); gppi(sesskey, "TermWidth", 80, &cfg->width); gppi(sesskey, "TermHeight", 24, &cfg->height); gppfont(sesskey, "Font", &cfg->font); gppi(sesskey, "FontQuality", FQ_DEFAULT, &cfg->font_quality); gppi(sesskey, "FontVTMode", VT_UNICODE, (int *) &cfg->vtmode); gppi(sesskey, "UseSystemColours", 0, &cfg->system_colour); gppi(sesskey, "TryPalette", 0, &cfg->try_palette); gppi(sesskey, "ANSIColour", 1, &cfg->ansi_colour); gppi(sesskey, "Xterm256Colour", 1, &cfg->xterm_256_colour); gppi(sesskey, "BoldAsColour", 1, &cfg->bold_colour); for (i = 0; i < 22; i++) { static const char *const defaults[] = { "187,187,187", "255,255,255", "0,0,0", "85,85,85", "0,0,0", "0,255,0", "0,0,0", "85,85,85", "187,0,0", "255,85,85", "0,187,0", "85,255,85", "187,187,0", "255,255,85", "0,0,187", "85,85,255", "187,0,187", "255,85,255", "0,187,187", "85,255,255", "187,187,187", "255,255,255" }; char buf[20], buf2[30]; int c0, c1, c2; sprintf(buf, "Colour%d", i); gpps(sesskey, buf, defaults[i], buf2, sizeof(buf2)); if (sscanf(buf2, "%d,%d,%d", &c0, &c1, &c2) == 3) { cfg->colours[i][0] = c0; cfg->colours[i][1] = c1; cfg->colours[i][2] = c2; } } gppi(sesskey, "RawCNP", 0, &cfg->rawcnp); gppi(sesskey, "PasteRTF", 0, &cfg->rtf_paste); gppi(sesskey, "MouseIsXterm", 0, &cfg->mouse_is_xterm); gppi(sesskey, "RectSelect", 0, &cfg->rect_select); gppi(sesskey, "MouseOverride", 1, &cfg->mouse_override); for (i = 0; i < 256; i += 32) { static const char *const defaults[] = { "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0", "0,1,2,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1", "1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,2", "1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1", "1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1", "1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1", "2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2", "2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2" }; char buf[20], buf2[256], *p; int j; sprintf(buf, "Wordness%d", i); gpps(sesskey, buf, defaults[i / 32], buf2, sizeof(buf2)); p = buf2; for (j = i; j < i + 32; j++) { char *q = p; while (*p && *p != ',') p++; if (*p == ',') *p++ = '\0'; cfg->wordness[j] = atoi(q); } } /* * The empty default for LineCodePage will be converted later * into a plausible default for the locale. */ gpps(sesskey, "LineCodePage", "", cfg->line_codepage, sizeof(cfg->line_codepage)); gppi(sesskey, "CJKAmbigWide", 0, &cfg->cjk_ambig_wide); gppi(sesskey, "UTF8Override", 1, &cfg->utf8_override); gpps(sesskey, "Printer", "", cfg->printer, sizeof(cfg->printer)); gppi (sesskey, "CapsLockCyr", 0, &cfg->xlat_capslockcyr); gppi(sesskey, "ScrollBar", 1, &cfg->scrollbar); gppi(sesskey, "ScrollBarFullScreen", 0, &cfg->scrollbar_in_fullscreen); gppi(sesskey, "ScrollOnKey", 0, &cfg->scroll_on_key); gppi(sesskey, "ScrollOnDisp", 1, &cfg->scroll_on_disp); gppi(sesskey, "EraseToScrollback", 1, &cfg->erase_to_scrollback); gppi(sesskey, "LockSize", 0, &cfg->resize_action); gppi(sesskey, "BCE", 1, &cfg->bce); gppi(sesskey, "BlinkText", 0, &cfg->blinktext); gppi(sesskey, "X11Forward", 0, &cfg->x11_forward); gpps(sesskey, "X11Display", "", cfg->x11_display, sizeof(cfg->x11_display)); gppi(sesskey, "X11AuthType", X11_MIT, &cfg->x11_auth); gppfile(sesskey, "X11AuthFile", &cfg->xauthfile); gppi(sesskey, "LocalPortAcceptAll", 0, &cfg->lport_acceptall); gppi(sesskey, "RemotePortAcceptAll", 0, &cfg->rport_acceptall); gppmap(sesskey, "PortForwardings", "", cfg->portfwd, lenof(cfg->portfwd)); gppi(sesskey, "BugIgnore1", 0, &i); cfg->sshbug_ignore1 = 2-i; gppi(sesskey, "BugPlainPW1", 0, &i); cfg->sshbug_plainpw1 = 2-i; gppi(sesskey, "BugRSA1", 0, &i); cfg->sshbug_rsa1 = 2-i; gppi(sesskey, "BugIgnore2", 0, &i); cfg->sshbug_ignore2 = 2-i; { int i; gppi(sesskey, "BugHMAC2", 0, &i); cfg->sshbug_hmac2 = 2-i; if (cfg->sshbug_hmac2 == AUTO) { gppi(sesskey, "BuggyMAC", 0, &i); if (i == 1) cfg->sshbug_hmac2 = FORCE_ON; } } gppi(sesskey, "BugDeriveKey2", 0, &i); cfg->sshbug_derivekey2 = 2-i; gppi(sesskey, "BugRSAPad2", 0, &i); cfg->sshbug_rsapad2 = 2-i; gppi(sesskey, "BugPKSessID2", 0, &i); cfg->sshbug_pksessid2 = 2-i; gppi(sesskey, "BugRekey2", 0, &i); cfg->sshbug_rekey2 = 2-i; gppi(sesskey, "BugMaxPkt2", 0, &i); cfg->sshbug_maxpkt2 = 2-i; cfg->ssh_simple = FALSE; gppi(sesskey, "StampUtmp", 1, &cfg->stamp_utmp); gppi(sesskey, "LoginShell", 1, &cfg->login_shell); gppi(sesskey, "ScrollbarOnLeft", 0, &cfg->scrollbar_on_left); gppi(sesskey, "ShadowBold", 0, &cfg->shadowbold); gppfont(sesskey, "BoldFont", &cfg->boldfont); gppfont(sesskey, "WideFont", &cfg->widefont); gppfont(sesskey, "WideBoldFont", &cfg->wideboldfont); gppi(sesskey, "ShadowBoldOffset", 1, &cfg->shadowboldoffset); gpps(sesskey, "SerialLine", "", cfg->serline, sizeof(cfg->serline)); gppi(sesskey, "SerialSpeed", 9600, &cfg->serspeed); gppi(sesskey, "SerialDataBits", 8, &cfg->serdatabits); gppi(sesskey, "SerialStopHalfbits", 2, &cfg->serstopbits); gppi(sesskey, "SerialParity", SER_PAR_NONE, &cfg->serparity); gppi(sesskey, "SerialFlowControl", SER_FLOW_XONXOFF, &cfg->serflow); gpps(sesskey, "WindowClass", "", cfg->winclass, sizeof(cfg->winclass)); } void do_defaults(char *session, Config * cfg) { load_settings(session, cfg); } static int sessioncmp(const void *av, const void *bv) { const char *a = *(const char *const *) av; const char *b = *(const char *const *) bv; |
︙ | ︙ |
Changes to sftp.c.
︙ | ︙ | |||
41 42 43 44 45 46 47 | sftp_pkt_ensure(pkt, pkt->length); memcpy(pkt->data + pkt->length - len, data, len); } static void sftp_pkt_addbyte(struct sftp_packet *pkt, unsigned char byte) { sftp_pkt_adddata(pkt, &byte, 1); } | < < < < < < < < > > > > > > > | 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | sftp_pkt_ensure(pkt, pkt->length); memcpy(pkt->data + pkt->length - len, data, len); } static void sftp_pkt_addbyte(struct sftp_packet *pkt, unsigned char byte) { sftp_pkt_adddata(pkt, &byte, 1); } static struct sftp_packet *sftp_pkt_init(int pkt_type) { struct sftp_packet *pkt; pkt = snew(struct sftp_packet); pkt->data = NULL; pkt->savedpos = -1; pkt->length = 0; pkt->maxlen = 0; sftp_pkt_addbyte(pkt, (unsigned char) pkt_type); return pkt; } /* static void sftp_pkt_addbool(struct sftp_packet *pkt, unsigned char value) { sftp_pkt_adddata(pkt, &value, 1); } */ static void sftp_pkt_adduint32(struct sftp_packet *pkt, unsigned long value) { unsigned char x[4]; PUT_32BIT(x, value); sftp_pkt_adddata(pkt, x, 4); } static void sftp_pkt_adduint64(struct sftp_packet *pkt, uint64 value) { unsigned char x[8]; PUT_32BIT(x, value.hi); PUT_32BIT(x + 4, value.lo); sftp_pkt_adddata(pkt, x, 8); } |
︙ | ︙ | |||
146 147 148 149 150 151 152 | } static int sftp_pkt_getstring(struct sftp_packet *pkt, char **p, int *length) { *p = NULL; if (pkt->length - pkt->savedpos < 4) return 0; | | | 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | } static int sftp_pkt_getstring(struct sftp_packet *pkt, char **p, int *length) { *p = NULL; if (pkt->length - pkt->savedpos < 4) return 0; *length = GET_32BIT(pkt->data + pkt->savedpos); pkt->savedpos += 4; if ((int)(pkt->length - pkt->savedpos) < *length || *length < 0) { *length = 0; return 0; } *p = pkt->data + pkt->savedpos; pkt->savedpos += *length; |
︙ | ︙ | |||
212 213 214 215 216 217 218 | /* ---------------------------------------------------------------------- * Send and receive packet functions. */ int sftp_send(struct sftp_packet *pkt) { int ret; | > | | | 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 | /* ---------------------------------------------------------------------- * Send and receive packet functions. */ int sftp_send(struct sftp_packet *pkt) { int ret; char x[4]; PUT_32BIT(x, pkt->length); ret = (sftp_senddata(x, 4) && sftp_senddata(pkt->data, pkt->length)); sftp_pkt_free(pkt); return ret; } struct sftp_packet *sftp_recv(void) { struct sftp_packet *pkt; char x[4]; |
︙ | ︙ | |||
362 363 364 365 366 367 368 369 370 371 372 373 374 375 | fxp_internal_error("did not receive a valid SFTP packet\n"); return NULL; } req = find234(sftp_requests, &id, sftp_reqfind); if (!req || !req->registered) { fxp_internal_error("request ID mismatch\n"); return NULL; } del234(sftp_requests, req); return req; } | > | 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 | fxp_internal_error("did not receive a valid SFTP packet\n"); return NULL; } req = find234(sftp_requests, &id, sftp_reqfind); if (!req || !req->registered) { fxp_internal_error("request ID mismatch\n"); sftp_pkt_free(pktin); return NULL; } del234(sftp_requests, req); return req; } |
︙ | ︙ | |||
543 544 545 546 547 548 549 | return NULL; } } /* * Open a file. */ | | < < < < | | 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 | return NULL; } } /* * Open a file. */ struct sftp_request *fxp_open_send(char *path, int type) { struct sftp_request *req = sftp_alloc_request(); struct sftp_packet *pktout; pktout = sftp_pkt_init(SSH_FXP_OPEN); sftp_pkt_adduint32(pktout, req->id); sftp_pkt_addstring(pktout, path); sftp_pkt_adduint32(pktout, type); sftp_pkt_adduint32(pktout, 0); /* (FIXME) empty ATTRS structure */ sftp_send(pktout); return req; } struct fxp_handle *fxp_open_recv(struct sftp_packet *pktin, struct sftp_request *req) |
︙ | ︙ | |||
1192 1193 1194 1195 1196 1197 1198 | xfer->eof = FALSE; xfer_download_queue(xfer); return xfer; } | < < < < < < | < | < | 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 | xfer->eof = FALSE; xfer_download_queue(xfer); return xfer; } int xfer_download_gotpkt(struct fxp_xfer *xfer, struct sftp_packet *pktin) { struct sftp_request *rreq; struct req *rr; rreq = sftp_find_request(pktin); rr = (struct req *)fxp_get_userdata(rreq); if (!rr) return 0; /* this packet isn't ours */ rr->retlen = fxp_read_recv(pktin, rreq, rr->buffer, rr->len); #ifdef DEBUG_DOWNLOAD printf("read request %p has returned [%d]\n", rr, rr->retlen); #endif if ((rr->retlen < 0 && fxp_error_type()==SSH_FX_EOF) || rr->retlen == 0) { xfer->eof = TRUE; |
︙ | ︙ | |||
1379 1380 1381 1382 1383 1384 1385 | xfer->req_totalsize += rr->len; #ifdef DEBUG_UPLOAD { char buf[40]; uint64_decimal(rr->offset, buf); printf("queueing write request %p at %s [len %d]\n", rr, buf, len); } #endif } | < < < < < < | < | < | 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 | xfer->req_totalsize += rr->len; #ifdef DEBUG_UPLOAD { char buf[40]; uint64_decimal(rr->offset, buf); printf("queueing write request %p at %s [len %d]\n", rr, buf, len); } #endif } int xfer_upload_gotpkt(struct fxp_xfer *xfer, struct sftp_packet *pktin) { struct sftp_request *rreq; struct req *rr, *prev, *next; int ret; rreq = sftp_find_request(pktin); rr = (struct req *)fxp_get_userdata(rreq); if (!rr) return 0; /* this packet isn't ours */ ret = fxp_write_recv(pktin, rreq); #ifdef DEBUG_UPLOAD printf("write request %p has returned [%d]\n", rr, ret); #endif /* * Remove this one from the queue. |
︙ | ︙ |
Changes to sftp.h.
︙ | ︙ | |||
78 79 80 81 82 83 84 | unsigned long uid; unsigned long gid; unsigned long permissions; unsigned long atime; unsigned long mtime; }; | < < < < < < < < < < < < < | 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | unsigned long uid; unsigned long gid; unsigned long permissions; unsigned long atime; unsigned long mtime; }; struct fxp_handle { char *hstring; int hlen; }; struct fxp_name { char *filename, *longname; |
︙ | ︙ | |||
125 126 127 128 129 130 131 | * Canonify a pathname. Concatenate the two given path elements * with a separating slash, unless the second is NULL. */ struct sftp_request *fxp_realpath_send(char *path); char *fxp_realpath_recv(struct sftp_packet *pktin, struct sftp_request *req); /* | | < | < | 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | * Canonify a pathname. Concatenate the two given path elements * with a separating slash, unless the second is NULL. */ struct sftp_request *fxp_realpath_send(char *path); char *fxp_realpath_recv(struct sftp_packet *pktin, struct sftp_request *req); /* * Open a file. */ struct sftp_request *fxp_open_send(char *path, int type); struct fxp_handle *fxp_open_recv(struct sftp_packet *pktin, struct sftp_request *req); /* * Open a directory. */ struct sftp_request *fxp_opendir_send(char *path); |
︙ | ︙ |
Changes to ssh.c.
︙ | ︙ | |||
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | #include "tree234.h" #include "ssh.h" #ifndef NO_GSSAPI #include "sshgssc.h" #include "sshgss.h" #endif #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE 1 #endif /* * Packet type contexts, so that ssh2_pkt_type can correctly decode * the ambiguous type numbers back into the correct type strings. */ typedef enum { SSH2_PKTCTX_NOKEX, SSH2_PKTCTX_DHGROUP, SSH2_PKTCTX_DHGEX, SSH2_PKTCTX_RSAKEX } Pkt_KCtx; typedef enum { SSH2_PKTCTX_NOAUTH, SSH2_PKTCTX_PUBLICKEY, SSH2_PKTCTX_PASSWORD, SSH2_PKTCTX_GSSAPI, SSH2_PKTCTX_KBDINTER } Pkt_ACtx; static const char *const ssh2_disconnect_reasons[] = { NULL, "host not allowed to connect", "protocol error", "key exchange failed", "host authentication failed", "MAC error", "compression error", "service not available", "protocol version not supported", "host key not verifiable", "connection lost", "by application", "too many connections", "auth cancelled by user", "no more auth methods available", "illegal user name", }; /* * Various remote-bug flags. */ #define BUG_CHOKES_ON_SSH1_IGNORE 1 #define BUG_SSH2_HMAC 2 #define BUG_NEEDS_SSH1_PLAIN_PASSWORD 4 #define BUG_CHOKES_ON_RSA 8 #define BUG_SSH2_RSA_PADDING 16 #define BUG_SSH2_DERIVEKEY 32 #define BUG_SSH2_REKEY 64 #define BUG_SSH2_PK_SESSIONID 128 #define BUG_SSH2_MAXPKT 256 #define BUG_CHOKES_ON_SSH2_IGNORE 512 | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 | #include "tree234.h" #include "ssh.h" #ifndef NO_GSSAPI #include "sshgssc.h" #include "sshgss.h" #endif /* PuTTY SC start */ #include "pkcs11.h" #include "sc.h" /* PuTTY SC end */ /* PuTTY CAPI start */ #ifdef _WINDOWS #include "capi.h" #endif /* PuTTY CAPI end */ #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE 1 #endif #define SSH1_MSG_DISCONNECT 1 /* 0x1 */ #define SSH1_SMSG_PUBLIC_KEY 2 /* 0x2 */ #define SSH1_CMSG_SESSION_KEY 3 /* 0x3 */ #define SSH1_CMSG_USER 4 /* 0x4 */ #define SSH1_CMSG_AUTH_RSA 6 /* 0x6 */ #define SSH1_SMSG_AUTH_RSA_CHALLENGE 7 /* 0x7 */ #define SSH1_CMSG_AUTH_RSA_RESPONSE 8 /* 0x8 */ #define SSH1_CMSG_AUTH_PASSWORD 9 /* 0x9 */ #define SSH1_CMSG_REQUEST_PTY 10 /* 0xa */ #define SSH1_CMSG_WINDOW_SIZE 11 /* 0xb */ #define SSH1_CMSG_EXEC_SHELL 12 /* 0xc */ #define SSH1_CMSG_EXEC_CMD 13 /* 0xd */ #define SSH1_SMSG_SUCCESS 14 /* 0xe */ #define SSH1_SMSG_FAILURE 15 /* 0xf */ #define SSH1_CMSG_STDIN_DATA 16 /* 0x10 */ #define SSH1_SMSG_STDOUT_DATA 17 /* 0x11 */ #define SSH1_SMSG_STDERR_DATA 18 /* 0x12 */ #define SSH1_CMSG_EOF 19 /* 0x13 */ #define SSH1_SMSG_EXIT_STATUS 20 /* 0x14 */ #define SSH1_MSG_CHANNEL_OPEN_CONFIRMATION 21 /* 0x15 */ #define SSH1_MSG_CHANNEL_OPEN_FAILURE 22 /* 0x16 */ #define SSH1_MSG_CHANNEL_DATA 23 /* 0x17 */ #define SSH1_MSG_CHANNEL_CLOSE 24 /* 0x18 */ #define SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION 25 /* 0x19 */ #define SSH1_SMSG_X11_OPEN 27 /* 0x1b */ #define SSH1_CMSG_PORT_FORWARD_REQUEST 28 /* 0x1c */ #define SSH1_MSG_PORT_OPEN 29 /* 0x1d */ #define SSH1_CMSG_AGENT_REQUEST_FORWARDING 30 /* 0x1e */ #define SSH1_SMSG_AGENT_OPEN 31 /* 0x1f */ #define SSH1_MSG_IGNORE 32 /* 0x20 */ #define SSH1_CMSG_EXIT_CONFIRMATION 33 /* 0x21 */ #define SSH1_CMSG_X11_REQUEST_FORWARDING 34 /* 0x22 */ #define SSH1_CMSG_AUTH_RHOSTS_RSA 35 /* 0x23 */ #define SSH1_MSG_DEBUG 36 /* 0x24 */ #define SSH1_CMSG_REQUEST_COMPRESSION 37 /* 0x25 */ #define SSH1_CMSG_AUTH_TIS 39 /* 0x27 */ #define SSH1_SMSG_AUTH_TIS_CHALLENGE 40 /* 0x28 */ #define SSH1_CMSG_AUTH_TIS_RESPONSE 41 /* 0x29 */ #define SSH1_CMSG_AUTH_CCARD 70 /* 0x46 */ #define SSH1_SMSG_AUTH_CCARD_CHALLENGE 71 /* 0x47 */ #define SSH1_CMSG_AUTH_CCARD_RESPONSE 72 /* 0x48 */ #define SSH1_AUTH_RHOSTS 1 /* 0x1 */ #define SSH1_AUTH_RSA 2 /* 0x2 */ #define SSH1_AUTH_PASSWORD 3 /* 0x3 */ #define SSH1_AUTH_RHOSTS_RSA 4 /* 0x4 */ #define SSH1_AUTH_TIS 5 /* 0x5 */ #define SSH1_AUTH_CCARD 16 /* 0x10 */ #define SSH1_PROTOFLAG_SCREEN_NUMBER 1 /* 0x1 */ /* Mask for protoflags we will echo back to server if seen */ #define SSH1_PROTOFLAGS_SUPPORTED 0 /* 0x1 */ #define SSH2_MSG_DISCONNECT 1 /* 0x1 */ #define SSH2_MSG_IGNORE 2 /* 0x2 */ #define SSH2_MSG_UNIMPLEMENTED 3 /* 0x3 */ #define SSH2_MSG_DEBUG 4 /* 0x4 */ #define SSH2_MSG_SERVICE_REQUEST 5 /* 0x5 */ #define SSH2_MSG_SERVICE_ACCEPT 6 /* 0x6 */ #define SSH2_MSG_KEXINIT 20 /* 0x14 */ #define SSH2_MSG_NEWKEYS 21 /* 0x15 */ #define SSH2_MSG_KEXDH_INIT 30 /* 0x1e */ #define SSH2_MSG_KEXDH_REPLY 31 /* 0x1f */ #define SSH2_MSG_KEX_DH_GEX_REQUEST 30 /* 0x1e */ #define SSH2_MSG_KEX_DH_GEX_GROUP 31 /* 0x1f */ #define SSH2_MSG_KEX_DH_GEX_INIT 32 /* 0x20 */ #define SSH2_MSG_KEX_DH_GEX_REPLY 33 /* 0x21 */ #define SSH2_MSG_KEXRSA_PUBKEY 30 /* 0x1e */ #define SSH2_MSG_KEXRSA_SECRET 31 /* 0x1f */ #define SSH2_MSG_KEXRSA_DONE 32 /* 0x20 */ #define SSH2_MSG_USERAUTH_REQUEST 50 /* 0x32 */ #define SSH2_MSG_USERAUTH_FAILURE 51 /* 0x33 */ #define SSH2_MSG_USERAUTH_SUCCESS 52 /* 0x34 */ #define SSH2_MSG_USERAUTH_BANNER 53 /* 0x35 */ #define SSH2_MSG_USERAUTH_PK_OK 60 /* 0x3c */ #define SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ 60 /* 0x3c */ #define SSH2_MSG_USERAUTH_INFO_REQUEST 60 /* 0x3c */ #define SSH2_MSG_USERAUTH_INFO_RESPONSE 61 /* 0x3d */ #define SSH2_MSG_GLOBAL_REQUEST 80 /* 0x50 */ #define SSH2_MSG_REQUEST_SUCCESS 81 /* 0x51 */ #define SSH2_MSG_REQUEST_FAILURE 82 /* 0x52 */ #define SSH2_MSG_CHANNEL_OPEN 90 /* 0x5a */ #define SSH2_MSG_CHANNEL_OPEN_CONFIRMATION 91 /* 0x5b */ #define SSH2_MSG_CHANNEL_OPEN_FAILURE 92 /* 0x5c */ #define SSH2_MSG_CHANNEL_WINDOW_ADJUST 93 /* 0x5d */ #define SSH2_MSG_CHANNEL_DATA 94 /* 0x5e */ #define SSH2_MSG_CHANNEL_EXTENDED_DATA 95 /* 0x5f */ #define SSH2_MSG_CHANNEL_EOF 96 /* 0x60 */ #define SSH2_MSG_CHANNEL_CLOSE 97 /* 0x61 */ #define SSH2_MSG_CHANNEL_REQUEST 98 /* 0x62 */ #define SSH2_MSG_CHANNEL_SUCCESS 99 /* 0x63 */ #define SSH2_MSG_CHANNEL_FAILURE 100 /* 0x64 */ #define SSH2_MSG_USERAUTH_GSSAPI_RESPONSE 60 #define SSH2_MSG_USERAUTH_GSSAPI_TOKEN 61 #define SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE 63 #define SSH2_MSG_USERAUTH_GSSAPI_ERROR 64 #define SSH2_MSG_USERAUTH_GSSAPI_ERRTOK 65 #define SSH2_MSG_USERAUTH_GSSAPI_MIC 66 /* * Packet type contexts, so that ssh2_pkt_type can correctly decode * the ambiguous type numbers back into the correct type strings. */ typedef enum { SSH2_PKTCTX_NOKEX, SSH2_PKTCTX_DHGROUP, SSH2_PKTCTX_DHGEX, SSH2_PKTCTX_RSAKEX } Pkt_KCtx; typedef enum { SSH2_PKTCTX_NOAUTH, SSH2_PKTCTX_PUBLICKEY, SSH2_PKTCTX_PASSWORD, SSH2_PKTCTX_GSSAPI, SSH2_PKTCTX_KBDINTER } Pkt_ACtx; #define SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT 1 /* 0x1 */ #define SSH2_DISCONNECT_PROTOCOL_ERROR 2 /* 0x2 */ #define SSH2_DISCONNECT_KEY_EXCHANGE_FAILED 3 /* 0x3 */ #define SSH2_DISCONNECT_HOST_AUTHENTICATION_FAILED 4 /* 0x4 */ #define SSH2_DISCONNECT_MAC_ERROR 5 /* 0x5 */ #define SSH2_DISCONNECT_COMPRESSION_ERROR 6 /* 0x6 */ #define SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE 7 /* 0x7 */ #define SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED 8 /* 0x8 */ #define SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE 9 /* 0x9 */ #define SSH2_DISCONNECT_CONNECTION_LOST 10 /* 0xa */ #define SSH2_DISCONNECT_BY_APPLICATION 11 /* 0xb */ #define SSH2_DISCONNECT_TOO_MANY_CONNECTIONS 12 /* 0xc */ #define SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER 13 /* 0xd */ #define SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE 14 /* 0xe */ #define SSH2_DISCONNECT_ILLEGAL_USER_NAME 15 /* 0xf */ static const char *const ssh2_disconnect_reasons[] = { NULL, "host not allowed to connect", "protocol error", "key exchange failed", "host authentication failed", "MAC error", "compression error", "service not available", "protocol version not supported", "host key not verifiable", "connection lost", "by application", "too many connections", "auth cancelled by user", "no more auth methods available", "illegal user name", }; #define SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED 1 /* 0x1 */ #define SSH2_OPEN_CONNECT_FAILED 2 /* 0x2 */ #define SSH2_OPEN_UNKNOWN_CHANNEL_TYPE 3 /* 0x3 */ #define SSH2_OPEN_RESOURCE_SHORTAGE 4 /* 0x4 */ #define SSH2_EXTENDED_DATA_STDERR 1 /* 0x1 */ /* * Various remote-bug flags. */ #define BUG_CHOKES_ON_SSH1_IGNORE 1 #define BUG_SSH2_HMAC 2 #define BUG_NEEDS_SSH1_PLAIN_PASSWORD 4 #define BUG_CHOKES_ON_RSA 8 #define BUG_SSH2_RSA_PADDING 16 #define BUG_SSH2_DERIVEKEY 32 #define BUG_SSH2_REKEY 64 #define BUG_SSH2_PK_SESSIONID 128 #define BUG_SSH2_MAXPKT 256 #define BUG_CHOKES_ON_SSH2_IGNORE 512 /* * Codes for terminal modes. * Most of these are the same in SSH-1 and SSH-2. * This list is derived from RFC 4254 and * SSH-1 RFC-1.2.31. */ |
︙ | ︙ | |||
279 280 281 282 283 284 285 286 287 288 289 290 291 292 | } #undef translate #undef translatec /* Enumeration values for fields in SSH-1 packets */ enum { PKT_END, PKT_INT, PKT_CHAR, PKT_DATA, PKT_STR, PKT_BIGNUM, }; /* * Coroutine mechanics for the sillier bits of the code. If these * macros look impenetrable to you, you might find it helpful to * read * | > > > | 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 | } #undef translate #undef translatec /* Enumeration values for fields in SSH-1 packets */ enum { PKT_END, PKT_INT, PKT_CHAR, PKT_DATA, PKT_STR, PKT_BIGNUM, /* These values are for communicating relevant semantics of * fields to the packet logging code. */ PKTT_OTHER, PKTT_PASSWORD, PKTT_DATA }; /* * Coroutine mechanics for the sillier bits of the code. If these * macros look impenetrable to you, you might find it helpful to * read * |
︙ | ︙ | |||
302 303 304 305 306 307 308 | * - right-click ssh.c in the FileView * - click Settings * - select the C/C++ tab and the General category * - under `Debug info:', select anything _other_ than `Program * Database for Edit and Continue'. */ #define crBegin(v) { int *crLine = &v; switch(v) { case 0:; | < | | | | < < < > > > > > | | | | < < | 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 | * - right-click ssh.c in the FileView * - click Settings * - select the C/C++ tab and the General category * - under `Debug info:', select anything _other_ than `Program * Database for Edit and Continue'. */ #define crBegin(v) { int *crLine = &v; switch(v) { case 0:; #define crState(t) \ struct t *s; \ if (!ssh->t) ssh->t = snew(struct t); \ s = ssh->t; #define crFinish(z) } *crLine = 0; return (z); } #define crFinishV } *crLine = 0; return; } #define crReturn(z) \ do {\ *crLine =__LINE__; return (z); case __LINE__:;\ } while (0) #define crReturnV \ do {\ *crLine=__LINE__; return; case __LINE__:;\ } while (0) #define crStop(z) do{ *crLine = 0; return (z); }while(0) #define crStopV do{ *crLine = 0; return; }while(0) #define crWaitUntil(c) do { crReturn(0); } while (!(c)) #define crWaitUntilV(c) do { crReturnV; } while (!(c)) typedef struct ssh_tag *Ssh; struct Packet; /* PuTTY SC start */ int loaded_pkcs11=FALSE; /* PuTTY SC end */ static struct Packet *ssh1_pkt_init(int pkt_type); static struct Packet *ssh2_pkt_init(int pkt_type); static void ssh_pkt_ensure(struct Packet *, int length); static void ssh_pkt_adddata(struct Packet *, void *data, int len); static void ssh_pkt_addbyte(struct Packet *, unsigned char value); static void ssh2_pkt_addbool(struct Packet *, unsigned char value); static void ssh_pkt_adduint32(struct Packet *, unsigned long value); static void ssh_pkt_addstring_start(struct Packet *); static void ssh_pkt_addstring_str(struct Packet *, char *data); static void ssh_pkt_addstring_data(struct Packet *, char *data, int len); static void ssh_pkt_addstring(struct Packet *, char *data); static unsigned char *ssh2_mpint_fmt(Bignum b, int *len); static void ssh1_pkt_addmp(struct Packet *, Bignum b); static void ssh2_pkt_addmp(struct Packet *, Bignum b); static int ssh2_pkt_construct(Ssh, struct Packet *); static void ssh2_pkt_send(Ssh, struct Packet *); static void ssh2_pkt_send_noqueue(Ssh, struct Packet *); static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, struct Packet *pktin); static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, struct Packet *pktin); /* * Buffer management constants. There are several of these for * various different purposes: * * - SSH1_BUFFER_LIMIT is the amount of backlog that must build up * on a local data stream before we throttle the whole SSH |
︙ | ︙ | |||
391 392 393 394 395 396 397 398 399 400 401 | #define SSH1_BUFFER_LIMIT 32768 #define SSH_MAX_BACKLOG 32768 #define OUR_V2_WINSIZE 16384 #define OUR_V2_BIGWIN 0x7fffffff #define OUR_V2_MAXPKT 0x4000UL #define OUR_V2_PACKETLIMIT 0x9000UL const static struct ssh_signkey *hostkey_algs[] = { &ssh_rsa, &ssh_dss }; const static struct ssh_mac *macs[] = { | > > > | | 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 | #define SSH1_BUFFER_LIMIT 32768 #define SSH_MAX_BACKLOG 32768 #define OUR_V2_WINSIZE 16384 #define OUR_V2_BIGWIN 0x7fffffff #define OUR_V2_MAXPKT 0x4000UL #define OUR_V2_PACKETLIMIT 0x9000UL /* Maximum length of passwords/passphrases (arbitrary) */ #define SSH_MAX_PASSWORD_LEN 100 const static struct ssh_signkey *hostkey_algs[] = { &ssh_rsa, &ssh_dss }; const static struct ssh_mac *macs[] = { &ssh_hmac_sha1, &ssh_hmac_sha1_96, &ssh_hmac_md5 }; const static struct ssh_mac *buggymacs[] = { &ssh_hmac_sha1_buggy, &ssh_hmac_sha1_96_buggy, &ssh_hmac_md5 }; static void *ssh_comp_none_init(void) { |
︙ | ︙ | |||
433 434 435 436 437 438 439 | }; enum { /* channel types */ CHAN_MAINSESSION, CHAN_X11, CHAN_AGENT, CHAN_SOCKDATA, | | < < < < < < < < < < < < < < < < < < < < | < | | | < < < < < < < < < < < < < < < < < < | | | | | | | | | < < | | < < < | 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 | }; enum { /* channel types */ CHAN_MAINSESSION, CHAN_X11, CHAN_AGENT, CHAN_SOCKDATA, CHAN_SOCKDATA_DORMANT /* one the remote hasn't confirmed */ }; /* * little structure to keep track of outstanding WINDOW_ADJUSTs */ struct winadj { struct winadj *next; unsigned size; }; /* * 2-3-4 tree storing channels. */ struct ssh_channel { Ssh ssh; /* pointer back to main context */ unsigned remoteid, localid; int type; /* True if we opened this channel but server hasn't confirmed. */ int halfopen; /* * In SSH-1, this value contains four bits: * * 1 We have sent SSH1_MSG_CHANNEL_CLOSE. * 2 We have sent SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION. * 4 We have received SSH1_MSG_CHANNEL_CLOSE. * 8 We have received SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION. * * A channel is completely finished with when all four bits are set. */ int closes; /* * This flag indicates that a close is pending on the outgoing * side of the channel: that is, wherever we're getting the data * for this channel has sent us some data followed by EOF. We * can't actually close the channel until we've finished sending * the data, so we set this flag instead to remind us to * initiate the closing process once our buffer is clear. */ int pending_close; /* * True if this channel is causing the underlying connection to be * throttled. */ int throttling_conn; union { struct ssh2_data_channel { bufchain outbuffer; unsigned remwindow, remmaxpkt; /* locwindow is signed so we can cope with excess data. */ int locwindow, locmaxwin; /* * remlocwin is the amount of local window that we think * the remote end had available to it after it sent the * last data packet or window adjust ack. */ int remlocwin; /* * These store the list of window adjusts that haven't * been acked. */ struct winadj *winadj_head, *winadj_tail; enum { THROTTLED, UNTHROTTLING, UNTHROTTLED } throttle_state; } v2; } v; union { struct ssh_agent_channel { unsigned char *message; unsigned char msglen[4]; unsigned lensofar, totallen; } a; struct ssh_x11_channel { Socket s; } x11; struct ssh_pfd_channel { Socket s; } pfd; } u; }; /* * 2-3-4 tree storing remote->local port forwardings. SSH-1 and SSH-2 * use this structure in different ways, reflecting SSH-2's * altogether saner approach to port forwarding. |
︙ | ︙ | |||
590 591 592 593 594 595 596 | * Hence, in SSH-1 this structure is indexed by destination * host:port pair, whereas in SSH-2 it is indexed by source port. */ struct ssh_portfwd; /* forward declaration */ struct ssh_rportfwd { unsigned sport, dport; | | < < | < < | < < < < < | | | < < < < < | < < < | < < < | < < < < < < | < < < < < | < < < < | | | < | < < < < | < | 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 | * Hence, in SSH-1 this structure is indexed by destination * host:port pair, whereas in SSH-2 it is indexed by source port. */ struct ssh_portfwd; /* forward declaration */ struct ssh_rportfwd { unsigned sport, dport; char dhost[256]; char *sportdesc; struct ssh_portfwd *pfrec; }; #define free_rportfwd(pf) ( \ ((pf) ? (sfree((pf)->sportdesc)) : (void)0 ), sfree(pf) ) /* * Separately to the rportfwd tree (which is for looking up port * open requests from the server), a tree of _these_ structures is * used to keep track of all the currently open port forwardings, * so that we can reconfigure in mid-session if the user requests * it. */ struct ssh_portfwd { enum { DESTROY, KEEP, CREATE } status; int type; unsigned sport, dport; char *saddr, *daddr; char *sserv, *dserv; struct ssh_rportfwd *remote; int addressfamily; void *local; }; #define free_portfwd(pf) ( \ ((pf) ? (sfree((pf)->saddr), sfree((pf)->daddr), \ sfree((pf)->sserv), sfree((pf)->dserv)) : (void)0 ), sfree(pf) ) struct Packet { long length; /* length of `data' actually used */ long forcepad; /* SSH-2: force padding to at least this length */ int type; /* only used for incoming packets */ unsigned long sequence; /* SSH-2 incoming sequence number */ unsigned char *data; /* allocated storage */ unsigned char *body; /* offset of payload within `data' */ long savedpos; /* temporary index into `data' (for strings) */ long maxlen; /* amount of storage allocated for `data' */ long encrypted_len; /* for SSH-2 total-size counting */ /* * State associated with packet logging */ int logmode; int nblanks; struct logblank_t *blanks; }; static void ssh1_protocol(Ssh ssh, void *vin, int inlen, struct Packet *pktin); static void ssh2_protocol(Ssh ssh, void *vin, int inlen, struct Packet *pktin); static void ssh1_protocol_setup(Ssh ssh); static void ssh2_protocol_setup(Ssh ssh); static void ssh_size(void *handle, int width, int height); static void ssh_special(void *handle, Telnet_Special); static int ssh2_try_send(struct ssh_channel *c); static void ssh2_add_channel_data(struct ssh_channel *c, char *buf, int len); static void ssh_throttle_all(Ssh ssh, int enable, int bufsize); static void ssh2_set_window(struct ssh_channel *c, int newwin); static int ssh_sendbuffer(void *handle); static int ssh_do_close(Ssh ssh, int notify_exit); static unsigned long ssh_pkt_getuint32(struct Packet *pkt); static int ssh2_pkt_getbool(struct Packet *pkt); static void ssh_pkt_getstring(struct Packet *pkt, char **p, int *length); static void ssh2_timer(void *ctx, long now); static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, struct Packet *pktin); struct rdpkt1_state_tag { long len, pad, biglen, to_read; unsigned long realcrc, gotcrc; unsigned char *p; int i; int chunk; struct Packet *pktin; }; struct rdpkt2_state_tag { long len, pad, payload, packetlen, maclen; int i; int cipherblk; unsigned long incoming_sequence; struct Packet *pktin; }; typedef void (*handler_fn_t)(Ssh ssh, struct Packet *pktin); typedef void (*chandler_fn_t)(Ssh ssh, struct Packet *pktin, void *ctx); struct queued_handler; struct queued_handler { int msg1, msg2; chandler_fn_t handler; void *ctx; struct queued_handler *next; |
︙ | ︙ | |||
757 758 759 760 761 762 763 | void *cs_cipher_ctx, *sc_cipher_ctx; const struct ssh_mac *csmac, *scmac; void *cs_mac_ctx, *sc_mac_ctx; const struct ssh_compress *cscomp, *sccomp; void *cs_comp_ctx, *sc_comp_ctx; const struct ssh_kex *kex; const struct ssh_signkey *hostkey; | < < < < < | 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 | void *cs_cipher_ctx, *sc_cipher_ctx; const struct ssh_mac *csmac, *scmac; void *cs_mac_ctx, *sc_mac_ctx; const struct ssh_compress *cscomp, *sccomp; void *cs_comp_ctx, *sc_comp_ctx; const struct ssh_kex *kex; const struct ssh_signkey *hostkey; unsigned char v2_session_id[SSH2_KEX_MAX_HASH_LEN]; int v2_session_id_len; void *kex_ctx; char *savedhost; int savedport; int send_ok; int echoing, editing; void *frontend; |
︙ | ︙ | |||
794 795 796 797 798 799 800 | SSH_STATE_BEFORE_SIZE, SSH_STATE_INTERMED, SSH_STATE_SESSION, SSH_STATE_CLOSED } state; int size_needed, eof_needed; | < < | 841 842 843 844 845 846 847 848 849 850 851 852 853 854 | SSH_STATE_BEFORE_SIZE, SSH_STATE_INTERMED, SSH_STATE_SESSION, SSH_STATE_CLOSED } state; int size_needed, eof_needed; struct Packet **queue; int queuelen, queuesize; int queueing; unsigned char *deferred_send_data; int deferred_len, deferred_size; |
︙ | ︙ | |||
817 818 819 820 821 822 823 | bufchain banner; /* accumulates banners during do_ssh2_authconn */ Pkt_KCtx pkt_kctx; Pkt_ACtx pkt_actx; struct X11Display *x11disp; | < < | > > > < < < | > | | < | < < < < < < < < < < < < < < | 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 | bufchain banner; /* accumulates banners during do_ssh2_authconn */ Pkt_KCtx pkt_kctx; Pkt_ACtx pkt_actx; struct X11Display *x11disp; int version; int conn_throttle_count; int overall_bufsize; int throttled_all; int v1_stdout_throttling; unsigned long v2_outgoing_sequence; int ssh1_rdpkt_crstate; int ssh2_rdpkt_crstate; int do_ssh_init_crstate; int ssh_gotdata_crstate; int do_ssh1_login_crstate; int do_ssh1_connection_crstate; int do_ssh2_transport_crstate; int do_ssh2_authconn_crstate; void *do_ssh_init_state; void *do_ssh1_login_state; void *do_ssh2_transport_state; void *do_ssh2_authconn_state; struct rdpkt1_state_tag rdpkt1_state; struct rdpkt2_state_tag rdpkt2_state; /* SSH-1 and SSH-2 use this for different things, but both use it */ int protocol_initial_phase_done; void (*protocol) (Ssh ssh, void *vin, int inlen, struct Packet *pkt); struct Packet *(*s_rdpkt) (Ssh ssh, unsigned char **data, int *datalen); /* * We maintain a full _copy_ of a Config structure here, not * merely a pointer to it. That way, when we're passed a new * one for reconfiguration, we can check the differences and * potentially reconfigure port forwardings etc in mid-session. */ Config cfg; /* * Used to transfer data back from async callbacks. */ void *agent_response; int agent_response_len; int user_response; |
︙ | ︙ | |||
903 904 905 906 907 908 909 | handler_fn_t packet_dispatch[256]; /* * Queues of one-off handler functions for success/failure * indications from a request. */ struct queued_handler *qhead, *qtail; | < | | 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 | handler_fn_t packet_dispatch[256]; /* * Queues of one-off handler functions for success/failure * indications from a request. */ struct queued_handler *qhead, *qtail; /* * This module deals with sending keepalives. */ Pinger pinger; /* * Track incoming and outgoing data sizes and time, for * size-based rekeys. */ unsigned long incoming_data_size, outgoing_data_size, deferred_data_size; unsigned long max_data_size; int kex_in_progress; long next_rekey, last_rekey; char *deferred_rekey_reason; /* points to STATIC string; don't free */ /* * Fully qualified host name, which we need if doing GSSAPI. */ char *fullhostname; |
︙ | ︙ | |||
948 949 950 951 952 953 954 | va_start(ap, fmt); buf = dupvprintf(fmt, ap); va_end(ap); logevent(buf); sfree(buf); } | | | > | | | | > | > > > > > > | > | > > > > > > > > > | | > > > | | < | < < < < < < | | > > | | > | < < | | 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 | va_start(ap, fmt); buf = dupvprintf(fmt, ap); va_end(ap); logevent(buf); sfree(buf); } #define bombout(msg) \ do { \ char *text = dupprintf msg; \ ssh_do_close(ssh, FALSE); \ logevent(text); \ connection_fatal(ssh->frontend, "%s", text); \ sfree(text); \ } while (0) /* Functions to leave bits out of the SSH packet log file. */ static void dont_log_password(Ssh ssh, struct Packet *pkt, int blanktype) { if (ssh->cfg.logomitpass) pkt->logmode = blanktype; } static void dont_log_data(Ssh ssh, struct Packet *pkt, int blanktype) { if (ssh->cfg.logomitdata) pkt->logmode = blanktype; } static void end_log_omission(Ssh ssh, struct Packet *pkt) { pkt->logmode = PKTLOG_EMIT; } /* Helper function for common bits of parsing cfg.ttymodes. */ static void parse_ttymodes(Ssh ssh, char *modes, void (*do_mode)(void *data, char *mode, char *val), void *data) { while (*modes) { char *t = strchr(modes, '\t'); char *m = snewn(t-modes+1, char); char *val; strncpy(m, modes, t-modes); m[t-modes] = '\0'; if (*(t+1) == 'A') val = get_ttymode(ssh->frontend, m); else val = dupstr(t+2); if (val) do_mode(data, m, val); sfree(m); sfree(val); modes += strlen(modes) + 1; } } static int ssh_channelcmp(void *av, void *bv) { struct ssh_channel *a = (struct ssh_channel *) av; struct ssh_channel *b = (struct ssh_channel *) bv; |
︙ | ︙ | |||
1023 1024 1025 1026 1027 1028 1029 | return 0; } static int ssh_rportcmp_ssh2(void *av, void *bv) { struct ssh_rportfwd *a = (struct ssh_rportfwd *) av; struct ssh_rportfwd *b = (struct ssh_rportfwd *) bv; | | < < | 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 | return 0; } static int ssh_rportcmp_ssh2(void *av, void *bv) { struct ssh_rportfwd *a = (struct ssh_rportfwd *) av; struct ssh_rportfwd *b = (struct ssh_rportfwd *) bv; if (a->sport > b->sport) return +1; if (a->sport < b->sport) return -1; return 0; } |
︙ | ︙ | |||
1156 1157 1158 1159 1160 1161 1162 | } static struct Packet *ssh_new_packet(void) { struct Packet *pkt = snew(struct Packet); pkt->body = pkt->data = NULL; pkt->maxlen = 0; | | < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < | < < < < < < < < < < < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 | } static struct Packet *ssh_new_packet(void) { struct Packet *pkt = snew(struct Packet); pkt->body = pkt->data = NULL; pkt->maxlen = 0; pkt->logmode = PKTLOG_EMIT; pkt->nblanks = 0; pkt->blanks = NULL; return pkt; } /* * Collect incoming data in the incoming packet buffer. * Decipher and verify the packet when it is completely read. * Drop SSH1_MSG_DEBUG and SSH1_MSG_IGNORE packets. * Update the *data and *datalen variables. * Return a Packet structure when a packet is completed. */ |
︙ | ︙ | |||
1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 | if (st->gotcrc != st->realcrc) { bombout(("Incorrect CRC received on packet")); ssh_free_packet(st->pktin); crStop(NULL); } st->pktin->body = st->pktin->data + st->pad + 1; if (ssh->v1_compressing) { unsigned char *decompblk; int decomplen; if (!zlib_decompress_block(ssh->sc_comp_ctx, st->pktin->body - 1, st->pktin->length + 1, &decompblk, &decomplen)) { | > | 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 | if (st->gotcrc != st->realcrc) { bombout(("Incorrect CRC received on packet")); ssh_free_packet(st->pktin); crStop(NULL); } st->pktin->body = st->pktin->data + st->pad + 1; st->pktin->savedpos = 0; if (ssh->v1_compressing) { unsigned char *decompblk; int decomplen; if (!zlib_decompress_block(ssh->sc_comp_ctx, st->pktin->body - 1, st->pktin->length + 1, &decompblk, &decomplen)) { |
︙ | ︙ | |||
1370 1371 1372 1373 1374 1375 1376 | sfree(decompblk); st->pktin->length = decomplen - 1; } st->pktin->type = st->pktin->body[-1]; /* | < | < | < < < < < < < < < | | < < | < | < < < | < < < < < < < < < < < | < < < < < | < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | < < < < < < > | | > | < < < | < < < < < < | | < < | < < | | < > | < < < < | < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < | 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 | sfree(decompblk); st->pktin->length = decomplen - 1; } st->pktin->type = st->pktin->body[-1]; /* * Log incoming packet, possibly omitting sensitive fields. */ if (ssh->logctx) { int nblanks = 0; struct logblank_t blank; if (ssh->cfg.logomitdata) { int do_blank = FALSE, blank_prefix = 0; /* "Session data" packets - omit the data field */ if ((st->pktin->type == SSH1_SMSG_STDOUT_DATA) || (st->pktin->type == SSH1_SMSG_STDERR_DATA)) { do_blank = TRUE; blank_prefix = 4; } else if (st->pktin->type == SSH1_MSG_CHANNEL_DATA) { do_blank = TRUE; blank_prefix = 8; } if (do_blank) { blank.offset = blank_prefix; blank.len = st->pktin->length; blank.type = PKTLOG_OMIT; nblanks = 1; } } log_packet(ssh->logctx, PKT_INCOMING, st->pktin->type, ssh1_pkt_type(st->pktin->type), st->pktin->body, st->pktin->length, nblanks, &blank, NULL); } crFinish(st->pktin); } static struct Packet *ssh2_rdpkt(Ssh ssh, unsigned char **data, int *datalen) { struct rdpkt2_state_tag *st = &ssh->rdpkt2_state; crBegin(ssh->ssh2_rdpkt_crstate); |
︙ | ︙ | |||
1603 1604 1605 1606 1607 1608 1609 | /* Feed that block to the MAC. */ ssh->scmac->bytes(ssh->sc_mac_ctx, st->pktin->data + st->packetlen, st->cipherblk); st->packetlen += st->cipherblk; /* See if that gives us a valid packet. */ if (ssh->scmac->verresult(ssh->sc_mac_ctx, st->pktin->data + st->packetlen) && | | < | 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 | /* Feed that block to the MAC. */ ssh->scmac->bytes(ssh->sc_mac_ctx, st->pktin->data + st->packetlen, st->cipherblk); st->packetlen += st->cipherblk; /* See if that gives us a valid packet. */ if (ssh->scmac->verresult(ssh->sc_mac_ctx, st->pktin->data + st->packetlen) && (st->len = GET_32BIT(st->pktin->data)) + 4 == st->packetlen) break; if (st->packetlen >= OUR_V2_PACKETLIMIT) { bombout(("No valid incoming packet found")); ssh_free_packet(st->pktin); crStop(NULL); } } |
︙ | ︙ | |||
1637 1638 1639 1640 1641 1642 1643 | if (ssh->sccipher) ssh->sccipher->decrypt(ssh->sc_cipher_ctx, st->pktin->data, st->cipherblk); /* * Now get the length figure. */ | | | 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 | if (ssh->sccipher) ssh->sccipher->decrypt(ssh->sc_cipher_ctx, st->pktin->data, st->cipherblk); /* * Now get the length figure. */ st->len = GET_32BIT(st->pktin->data); /* * _Completely_ silly lengths should be stomped on before they * do us any more damage. */ if (st->len < 0 || st->len > OUR_V2_PACKETLIMIT || (st->len + 4) % st->cipherblk != 0) { |
︙ | ︙ | |||
1729 1730 1731 1732 1733 1734 1735 | } st->pktin->length = 5 + newlen; memcpy(st->pktin->data + 5, newpayload, newlen); sfree(newpayload); } } | < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < | < < | > > > > > | > > > | > > > > > > > > > | > > > | > > > > > | 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 | } st->pktin->length = 5 + newlen; memcpy(st->pktin->data + 5, newpayload, newlen); sfree(newpayload); } } st->pktin->savedpos = 6; st->pktin->body = st->pktin->data; st->pktin->type = st->pktin->data[5]; /* * Log incoming packet, possibly omitting sensitive fields. */ if (ssh->logctx) { int nblanks = 0; struct logblank_t blank; if (ssh->cfg.logomitdata) { int do_blank = FALSE, blank_prefix = 0; /* "Session data" packets - omit the data field */ if (st->pktin->type == SSH2_MSG_CHANNEL_DATA) { do_blank = TRUE; blank_prefix = 8; } else if (st->pktin->type == SSH2_MSG_CHANNEL_EXTENDED_DATA) { do_blank = TRUE; blank_prefix = 12; } if (do_blank) { blank.offset = blank_prefix; blank.len = (st->pktin->length-6) - blank_prefix; blank.type = PKTLOG_OMIT; nblanks = 1; } } log_packet(ssh->logctx, PKT_INCOMING, st->pktin->type, ssh2_pkt_type(ssh->pkt_kctx, ssh->pkt_actx, st->pktin->type), st->pktin->data+6, st->pktin->length-6, nblanks, &blank, &st->pktin->sequence); } crFinish(st->pktin); } static int s_wrpkt_prepare(Ssh ssh, struct Packet *pkt, int *offset_p) { int pad, biglen, i, pktoffs; unsigned long crc; #ifdef __SC__ /* * XXX various versions of SC (including 8.8.4) screw up the * register allocation in this function and use the same register * (D6) for len and as a temporary, with predictable results. The * following sledgehammer prevents this. */ volatile #endif int len; if (ssh->logctx) log_packet(ssh->logctx, PKT_OUTGOING, pkt->data[12], ssh1_pkt_type(pkt->data[12]), pkt->body, pkt->length - (pkt->body - pkt->data), pkt->nblanks, pkt->blanks, NULL); sfree(pkt->blanks); pkt->blanks = NULL; pkt->nblanks = 0; if (ssh->v1_compressing) { unsigned char *compblk; int complen; zlib_compress_block(ssh->cs_comp_ctx, pkt->data + 12, pkt->length - 12, &compblk, &complen); |
︙ | ︙ | |||
1860 1861 1862 1863 1864 1865 1866 | return biglen + 4; /* len(length+padding+type+data+CRC) */ } static int s_write(Ssh ssh, void *data, int len) { if (ssh->logctx) log_packet(ssh->logctx, PKT_OUTGOING, -1, NULL, data, len, | | < < | 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 | return biglen + 4; /* len(length+padding+type+data+CRC) */ } static int s_write(Ssh ssh, void *data, int len) { if (ssh->logctx) log_packet(ssh->logctx, PKT_OUTGOING, -1, NULL, data, len, 0, NULL, NULL); return sk_write(ssh->s, (char *)data, len); } static void s_wrpkt(Ssh ssh, struct Packet *pkt) { int len, backlog, offset; len = s_wrpkt_prepare(ssh, pkt, &offset); |
︙ | ︙ | |||
1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 | case PKT_STR: sargp = va_arg(ap, char *); ssh_pkt_addstring(pkt, sargp); break; case PKT_BIGNUM: bn = va_arg(ap, Bignum); ssh1_pkt_addmp(pkt, bn); break; } } return pkt; } | > > > > > > > > > > | 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 | case PKT_STR: sargp = va_arg(ap, char *); ssh_pkt_addstring(pkt, sargp); break; case PKT_BIGNUM: bn = va_arg(ap, Bignum); ssh1_pkt_addmp(pkt, bn); break; /* Tokens for modifications to packet logging */ case PKTT_PASSWORD: dont_log_password(ssh, pkt, PKTLOG_BLANK); break; case PKTT_DATA: dont_log_data(ssh, pkt, PKTLOG_OMIT); break; case PKTT_OTHER: end_log_omission(ssh, pkt); break; } } return pkt; } |
︙ | ︙ | |||
2011 2012 2013 2014 2015 2016 2017 | unsigned char *body = pkt->body; int offset = body ? body - pkt->data : 0; pkt->maxlen = length + 256; pkt->data = sresize(pkt->data, pkt->maxlen + APIEXTRA, unsigned char); if (body) pkt->body = pkt->data + offset; } } | | > > > > > > > > > | 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 | unsigned char *body = pkt->body; int offset = body ? body - pkt->data : 0; pkt->maxlen = length + 256; pkt->data = sresize(pkt->data, pkt->maxlen + APIEXTRA, unsigned char); if (body) pkt->body = pkt->data + offset; } } static void ssh_pkt_adddata(struct Packet *pkt, void *data, int len) { if (pkt->logmode != PKTLOG_EMIT) { pkt->nblanks++; pkt->blanks = sresize(pkt->blanks, pkt->nblanks, struct logblank_t); assert(pkt->body); pkt->blanks[pkt->nblanks-1].offset = pkt->length - (pkt->body - pkt->data); pkt->blanks[pkt->nblanks-1].len = len; pkt->blanks[pkt->nblanks-1].type = pkt->logmode; } pkt->length += len; ssh_pkt_ensure(pkt, pkt->length); memcpy(pkt->data + pkt->length - len, data, len); } static void ssh_pkt_addbyte(struct Packet *pkt, unsigned char byte) { ssh_pkt_adddata(pkt, &byte, 1); |
︙ | ︙ | |||
2036 2037 2038 2039 2040 2041 2042 | ssh_pkt_adddata(pkt, x, 4); } static void ssh_pkt_addstring_start(struct Packet *pkt) { ssh_pkt_adduint32(pkt, 0); pkt->savedpos = pkt->length; } | | | < | | 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 | ssh_pkt_adddata(pkt, x, 4); } static void ssh_pkt_addstring_start(struct Packet *pkt) { ssh_pkt_adduint32(pkt, 0); pkt->savedpos = pkt->length; } static void ssh_pkt_addstring_str(struct Packet *pkt, char *data) { ssh_pkt_adddata(pkt, data, strlen(data)); PUT_32BIT(pkt->data + pkt->savedpos - 4, pkt->length - pkt->savedpos); } static void ssh_pkt_addstring_data(struct Packet *pkt, char *data, int len) { ssh_pkt_adddata(pkt, data, len); PUT_32BIT(pkt->data + pkt->savedpos - 4, pkt->length - pkt->savedpos); } static void ssh_pkt_addstring(struct Packet *pkt, char *data) { ssh_pkt_addstring_start(pkt); ssh_pkt_addstring_str(pkt, data); } static void ssh1_pkt_addmp(struct Packet *pkt, Bignum b) { int len = ssh1_bignum_length(b); |
︙ | ︙ | |||
2091 2092 2093 2094 2095 2096 2097 | static struct Packet *ssh1_pkt_init(int pkt_type) { struct Packet *pkt = ssh_new_packet(); pkt->length = 4 + 8; /* space for length + max padding */ ssh_pkt_addbyte(pkt, pkt_type); pkt->body = pkt->data + pkt->length; | < < < < < < | | < < < < < | < | > | < | 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 | static struct Packet *ssh1_pkt_init(int pkt_type) { struct Packet *pkt = ssh_new_packet(); pkt->length = 4 + 8; /* space for length + max padding */ ssh_pkt_addbyte(pkt, pkt_type); pkt->body = pkt->data + pkt->length; return pkt; } /* For legacy code (SSH-1 and -2 packet construction used to be separate) */ #define ssh2_pkt_ensure(pkt, length) ssh_pkt_ensure(pkt, length) #define ssh2_pkt_adddata(pkt, data, len) ssh_pkt_adddata(pkt, data, len) #define ssh2_pkt_addbyte(pkt, byte) ssh_pkt_addbyte(pkt, byte) #define ssh2_pkt_adduint32(pkt, value) ssh_pkt_adduint32(pkt, value) #define ssh2_pkt_addstring_start(pkt) ssh_pkt_addstring_start(pkt) #define ssh2_pkt_addstring_str(pkt, data) ssh_pkt_addstring_str(pkt, data) #define ssh2_pkt_addstring_data(pkt, data, len) ssh_pkt_addstring_data(pkt, data, len) #define ssh2_pkt_addstring(pkt, data) ssh_pkt_addstring(pkt, data) static struct Packet *ssh2_pkt_init(int pkt_type) { struct Packet *pkt = ssh_new_packet(); pkt->length = 5; /* space for packet length + padding length */ pkt->forcepad = 0; ssh_pkt_addbyte(pkt, (unsigned char) pkt_type); pkt->body = pkt->data + pkt->length; /* after packet type */ return pkt; } /* * Construct an SSH-2 final-form packet: compress it, encrypt it, * put the MAC on it. Final packet, ready to be sent, is stored in * pkt->data. Total length is returned. */ static int ssh2_pkt_construct(Ssh ssh, struct Packet *pkt) { int cipherblk, maclen, padding, i; if (ssh->logctx) log_packet(ssh->logctx, PKT_OUTGOING, pkt->data[5], ssh2_pkt_type(ssh->pkt_kctx, ssh->pkt_actx, pkt->data[5]), pkt->body, pkt->length - (pkt->body - pkt->data), pkt->nblanks, pkt->blanks, &ssh->v2_outgoing_sequence); sfree(pkt->blanks); pkt->blanks = NULL; pkt->nblanks = 0; /* * Compress packet payload. */ { unsigned char *newpayload; int newlen; |
︙ | ︙ | |||
2192 2193 2194 2195 2196 2197 2198 | if (ssh->cscipher) ssh->cscipher->encrypt(ssh->cs_cipher_ctx, pkt->data, pkt->length + padding); pkt->encrypted_len = pkt->length + padding; /* Ready-to-send packet starts at pkt->data. We return length. */ | < | 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 | if (ssh->cscipher) ssh->cscipher->encrypt(ssh->cs_cipher_ctx, pkt->data, pkt->length + padding); pkt->encrypted_len = pkt->length + padding; /* Ready-to-send packet starts at pkt->data. We return length. */ return pkt->length + padding + maclen; } /* * Routines called from the main SSH code to send packets. There * are quite a few of these, because we have two separate * mechanisms for delaying the sending of packets: |
︙ | ︙ | |||
2250 2251 2252 2253 2254 2255 2256 | if (ssh->cscipher != NULL && (ssh->cscipher->flags & SSH_CIPHER_IS_CBC)) { /* We need to send two packets, so use the deferral mechanism. */ ssh2_pkt_defer_noqueue(ssh, pkt, FALSE); ssh_pkt_defersend(ssh); return; } len = ssh2_pkt_construct(ssh, pkt); | | < | 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 | if (ssh->cscipher != NULL && (ssh->cscipher->flags & SSH_CIPHER_IS_CBC)) { /* We need to send two packets, so use the deferral mechanism. */ ssh2_pkt_defer_noqueue(ssh, pkt, FALSE); ssh_pkt_defersend(ssh); return; } len = ssh2_pkt_construct(ssh, pkt); backlog = s_write(ssh, pkt->data, len); if (backlog > SSH_MAX_BACKLOG) ssh_throttle_all(ssh, 1, backlog); ssh->outgoing_data_size += pkt->encrypted_len; if (!ssh->kex_in_progress && ssh->max_data_size != 0 && ssh->outgoing_data_size > ssh->max_data_size) do_ssh2_transport(ssh, "too much data sent", -1, NULL); ssh_free_packet(pkt); } |
︙ | ︙ | |||
2288 2289 2290 2291 2292 2293 2294 | len = ssh2_pkt_construct(ssh, pkt); if (ssh->deferred_len + len > ssh->deferred_size) { ssh->deferred_size = ssh->deferred_len + len + 128; ssh->deferred_send_data = sresize(ssh->deferred_send_data, ssh->deferred_size, unsigned char); } | | | 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 | len = ssh2_pkt_construct(ssh, pkt); if (ssh->deferred_len + len > ssh->deferred_size) { ssh->deferred_size = ssh->deferred_len + len + 128; ssh->deferred_send_data = sresize(ssh->deferred_send_data, ssh->deferred_size, unsigned char); } memcpy(ssh->deferred_send_data + ssh->deferred_len, pkt->data, len); ssh->deferred_len += len; ssh->deferred_data_size += pkt->encrypted_len; ssh_free_packet(pkt); } /* * Queue an SSH-2 packet. |
︙ | ︙ | |||
2358 2359 2360 2361 2362 2363 2364 | sfree(ssh->deferred_send_data); ssh->deferred_send_data = NULL; if (backlog > SSH_MAX_BACKLOG) ssh_throttle_all(ssh, 1, backlog); ssh->outgoing_data_size += ssh->deferred_data_size; if (!ssh->kex_in_progress && | < | 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 | sfree(ssh->deferred_send_data); ssh->deferred_send_data = NULL; if (backlog > SSH_MAX_BACKLOG) ssh_throttle_all(ssh, 1, backlog); ssh->outgoing_data_size += ssh->deferred_data_size; if (!ssh->kex_in_progress && ssh->max_data_size != 0 && ssh->outgoing_data_size > ssh->max_data_size) do_ssh2_transport(ssh, "too much data sent", -1, NULL); ssh->deferred_data_size = 0; } /* |
︙ | ︙ | |||
2503 2504 2505 2506 2507 2508 2509 | static void ssh_pkt_getstring(struct Packet *pkt, char **p, int *length) { int len; *p = NULL; *length = 0; if (pkt->length - pkt->savedpos < 4) return; | | | 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 | static void ssh_pkt_getstring(struct Packet *pkt, char **p, int *length) { int len; *p = NULL; *length = 0; if (pkt->length - pkt->savedpos < 4) return; len = GET_32BIT(pkt->body + pkt->savedpos); if (len < 0) return; *length = len; pkt->savedpos += 4; if (pkt->length - pkt->savedpos < *length) return; *p = (char *)(pkt->body + pkt->savedpos); |
︙ | ︙ | |||
2587 2588 2589 2590 2591 2592 2593 | /* dmemdump(pkblob, pkblob_len); */ /* dmemdump(sigblob, sigblob_len); */ /* * See if this is in fact an ssh-rsa signature and a buggy * server; otherwise we can just do this the easy way. */ | | < < < | < < | < < < < | < < | 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 | /* dmemdump(pkblob, pkblob_len); */ /* dmemdump(sigblob, sigblob_len); */ /* * See if this is in fact an ssh-rsa signature and a buggy * server; otherwise we can just do this the easy way. */ if ((ssh->remote_bugs & BUG_SSH2_RSA_PADDING) && (GET_32BIT(pkblob) == 7 && !memcmp(pkblob+4, "ssh-rsa", 7))) { int pos, len, siglen; /* * Find the byte length of the modulus. */ pos = 4+7; /* skip over "ssh-rsa" */ pos += 4 + GET_32BIT(pkblob+pos); /* skip over exponent */ len = GET_32BIT(pkblob+pos); /* find length of modulus */ pos += 4; /* find modulus itself */ while (len > 0 && pkblob[pos] == 0) len--, pos++; /* debug(("modulus length is %d\n", len)); */ /* * Now find the signature integer. */ pos = 4+7; /* skip over "ssh-rsa" */ siglen = GET_32BIT(sigblob+pos); /* debug(("signature length is %d\n", siglen)); */ if (len != siglen) { unsigned char newlen[4]; ssh2_pkt_addstring_start(pkt); ssh2_pkt_addstring_data(pkt, (char *)sigblob, pos); /* dmemdump(sigblob, pos); */ |
︙ | ︙ | |||
2640 2641 2642 2643 2644 2645 2646 | /* dmemdump(newlen, 1); */ } ssh2_pkt_addstring_data(pkt, (char *)(sigblob+pos), siglen); /* dmemdump(sigblob+pos, siglen); */ return; } | | < < < | 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 | /* dmemdump(newlen, 1); */ } ssh2_pkt_addstring_data(pkt, (char *)(sigblob+pos), siglen); /* dmemdump(sigblob+pos, siglen); */ return; } /* Otherwise fall through and do it the easy way. */ } ssh2_pkt_addstring_start(pkt); ssh2_pkt_addstring_data(pkt, (char *)sigblob, sigblob_len); } /* |
︙ | ︙ | |||
2672 2673 2674 2675 2676 2677 2678 | /* * General notes on server version strings: * - Not all servers reporting "Cisco-1.25" have all the bugs listed * here -- in particular, we've heard of one that's perfectly happy * with SSH1_MSG_IGNOREs -- but this string never seems to change, * so we can't distinguish them. */ | | | | | | | | | | | | | | | | | | | | < < < < < < < < < | > > > > | | < | < < < | | | < | > | | < > > > | | | > < | | | | | | 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 | /* * General notes on server version strings: * - Not all servers reporting "Cisco-1.25" have all the bugs listed * here -- in particular, we've heard of one that's perfectly happy * with SSH1_MSG_IGNOREs -- but this string never seems to change, * so we can't distinguish them. */ if (ssh->cfg.sshbug_ignore1 == FORCE_ON || (ssh->cfg.sshbug_ignore1 == AUTO && (!strcmp(imp, "1.2.18") || !strcmp(imp, "1.2.19") || !strcmp(imp, "1.2.20") || !strcmp(imp, "1.2.21") || !strcmp(imp, "1.2.22") || !strcmp(imp, "Cisco-1.25") || !strcmp(imp, "OSU_1.4alpha3") || !strcmp(imp, "OSU_1.5alpha4")))) { /* * These versions don't support SSH1_MSG_IGNORE, so we have * to use a different defence against password length * sniffing. */ ssh->remote_bugs |= BUG_CHOKES_ON_SSH1_IGNORE; logevent("We believe remote version has SSH-1 ignore bug"); } if (ssh->cfg.sshbug_plainpw1 == FORCE_ON || (ssh->cfg.sshbug_plainpw1 == AUTO && (!strcmp(imp, "Cisco-1.25") || !strcmp(imp, "OSU_1.4alpha3")))) { /* * These versions need a plain password sent; they can't * handle having a null and a random length of data after * the password. */ ssh->remote_bugs |= BUG_NEEDS_SSH1_PLAIN_PASSWORD; logevent("We believe remote version needs a plain SSH-1 password"); } if (ssh->cfg.sshbug_rsa1 == FORCE_ON || (ssh->cfg.sshbug_rsa1 == AUTO && (!strcmp(imp, "Cisco-1.25")))) { /* * These versions apparently have no clue whatever about * RSA authentication and will panic and die if they see * an AUTH_RSA message. */ ssh->remote_bugs |= BUG_CHOKES_ON_RSA; logevent("We believe remote version can't handle SSH-1 RSA authentication"); } if (ssh->cfg.sshbug_hmac2 == FORCE_ON || (ssh->cfg.sshbug_hmac2 == AUTO && !wc_match("* VShell", imp) && (wc_match("2.1.0*", imp) || wc_match("2.0.*", imp) || wc_match("2.2.0*", imp) || wc_match("2.3.0*", imp) || wc_match("2.1 *", imp)))) { /* * These versions have the HMAC bug. */ ssh->remote_bugs |= BUG_SSH2_HMAC; logevent("We believe remote version has SSH-2 HMAC bug"); } if (ssh->cfg.sshbug_derivekey2 == FORCE_ON || (ssh->cfg.sshbug_derivekey2 == AUTO && !wc_match("* VShell", imp) && (wc_match("2.0.0*", imp) || wc_match("2.0.10*", imp) ))) { /* * These versions have the key-derivation bug (failing to * include the literal shared secret in the hashes that * generate the keys). */ ssh->remote_bugs |= BUG_SSH2_DERIVEKEY; logevent("We believe remote version has SSH-2 key-derivation bug"); } if (ssh->cfg.sshbug_rsapad2 == FORCE_ON || (ssh->cfg.sshbug_rsapad2 == AUTO && (wc_match("OpenSSH_2.[5-9]*", imp) || wc_match("OpenSSH_3.[0-2]*", imp)))) { /* * These versions have the SSH-2 RSA padding bug. */ ssh->remote_bugs |= BUG_SSH2_RSA_PADDING; logevent("We believe remote version has SSH-2 RSA padding bug"); } if (ssh->cfg.sshbug_pksessid2 == FORCE_ON || (ssh->cfg.sshbug_pksessid2 == AUTO && wc_match("OpenSSH_2.[0-2]*", imp))) { /* * These versions have the SSH-2 session-ID bug in * public-key authentication. */ ssh->remote_bugs |= BUG_SSH2_PK_SESSIONID; logevent("We believe remote version has SSH-2 public-key-session-ID bug"); } if (ssh->cfg.sshbug_rekey2 == FORCE_ON || (ssh->cfg.sshbug_rekey2 == AUTO && (wc_match("DigiSSH_2.0", imp) || wc_match("OpenSSH_2.[0-4]*", imp) || wc_match("OpenSSH_2.5.[0-3]*", imp) || wc_match("Sun_SSH_1.0", imp) || wc_match("Sun_SSH_1.0.1", imp) || /* All versions <= 1.2.6 (they changed their format in 1.2.7) */ wc_match("WeOnlyDo-*", imp)))) { /* * These versions have the SSH-2 rekey bug. */ ssh->remote_bugs |= BUG_SSH2_REKEY; logevent("We believe remote version has SSH-2 rekey bug"); } if (ssh->cfg.sshbug_maxpkt2 == FORCE_ON || (ssh->cfg.sshbug_maxpkt2 == AUTO && (wc_match("1.36_sshlib GlobalSCAPE", imp) || wc_match("1.36 sshlib: GlobalScape", imp)))) { /* * This version ignores our makpkt and needs to be throttled. */ ssh->remote_bugs |= BUG_SSH2_MAXPKT; logevent("We believe remote version ignores SSH-2 maximum packet size"); } if (ssh->cfg.sshbug_ignore2 == FORCE_ON) { /* * Servers that don't support SSH2_MSG_IGNORE. Currently, * none detected automatically. */ ssh->remote_bugs |= BUG_CHOKES_ON_SSH2_IGNORE; logevent("We believe remote version has SSH-2 ignore bug"); } } /* * The `software version' part of an SSH version string is required * to contain no spaces or minus signs. */ static void ssh_fix_verstring(char *str) { /* Eat "SSH-<protoversion>-". */ assert(*str == 'S'); str++; assert(*str == 'S'); str++; assert(*str == 'H'); str++; assert(*str == '-'); str++; while (*str && *str != '-') str++; assert(*str == '-'); str++; /* Convert minus signs and spaces in the remaining string into * underscores. */ while (*str) { if (*str == '-' || *str == ' ') *str = '_'; str++; } } /* * Send an appropriate SSH version string. */ static void ssh_send_verstring(Ssh ssh, char *svers) { char *verstring; if (ssh->version == 2) { /* * Construct a v2 version string. */ verstring = dupprintf("SSH-2.0-%s\015\012", sshver); } else { /* * Construct a v1 version string. */ verstring = dupprintf("SSH-%s-%s\012", (ssh_versioncmp(svers, "1.5") <= 0 ? svers : "1.5"), sshver); } ssh_fix_verstring(verstring); if (ssh->version == 2) { size_t len; /* * Record our version string. */ len = strcspn(verstring, "\015\012"); ssh->v_c = snewn(len + 1, char); memcpy(ssh->v_c, verstring, len); ssh->v_c[len] = 0; } logeventf(ssh, "We claim version: %.*s", strcspn(verstring, "\015\012"), verstring); s_write(ssh, verstring, strlen(verstring)); sfree(verstring); } static int do_ssh_init(Ssh ssh, unsigned char c) { struct do_ssh_init_state { int vslen; char version[10]; char *vstring; int vstrsize; int i; int proto1, proto2; }; crState(do_ssh_init_state); crBegin(ssh->do_ssh_init_crstate); /* Search for a line beginning with the string "SSH-" in the input. */ for (;;) { if (c != 'S') goto no; crReturn(1); if (c != 'S') goto no; crReturn(1); if (c != 'H') goto no; crReturn(1); if (c != '-') goto no; break; no: while (c != '\012') crReturn(1); crReturn(1); } s->vstrsize = 16; s->vstring = snewn(s->vstrsize, char); strcpy(s->vstring, "SSH-"); s->vslen = 4; s->i = 0; while (1) { crReturn(1); /* get another char */ if (s->vslen >= s->vstrsize - 1) { s->vstrsize += 16; s->vstring = sresize(s->vstring, s->vstrsize, char); } s->vstring[s->vslen++] = c; if (s->i >= 0) { if (c == '-') { s->version[s->i] = '\0'; s->i = -1; } else if (s->i < sizeof(s->version) - 1) s->version[s->i++] = c; } else if (c == '\012') break; } ssh->agentfwd_enabled = FALSE; ssh->rdpkt2_state.incoming_sequence = 0; s->vstring[s->vslen] = 0; s->vstring[strcspn(s->vstring, "\015\012")] = '\0';/* remove EOL chars */ logeventf(ssh, "Server version: %s", s->vstring); ssh_detect_bugs(ssh, s->vstring); /* * Decide which SSH protocol version to support. */ /* Anything strictly below "2.0" means protocol 1 is supported. */ s->proto1 = ssh_versioncmp(s->version, "2.0") < 0; /* Anything greater or equal to "1.99" means protocol 2 is supported. */ s->proto2 = ssh_versioncmp(s->version, "1.99") >= 0; if (ssh->cfg.sshprot == 0 && !s->proto1) { bombout(("SSH protocol version 1 required by user but not provided by server")); crStop(0); } if (ssh->cfg.sshprot == 3 && !s->proto2) { bombout(("SSH protocol version 2 required by user but not provided by server")); crStop(0); } if (s->proto2 && (ssh->cfg.sshprot >= 2 || !s->proto1)) ssh->version = 2; else ssh->version = 1; logeventf(ssh, "Using SSH protocol version %d", ssh->version); /* Send the version string, if we haven't already */ if (ssh->cfg.sshprot != 3) ssh_send_verstring(ssh, s->version); if (ssh->version == 2) { size_t len; /* * Record their version string. */ len = strcspn(s->vstring, "\015\012"); |
︙ | ︙ | |||
2985 2986 2987 2988 2989 2990 2991 | ssh->s_rdpkt = ssh1_rdpkt; } if (ssh->version == 2) do_ssh2_transport(ssh, NULL, -1, NULL); update_specials_menu(ssh->frontend); ssh->state = SSH_STATE_BEFORE_SIZE; | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 | ssh->s_rdpkt = ssh1_rdpkt; } if (ssh->version == 2) do_ssh2_transport(ssh, NULL, -1, NULL); update_specials_menu(ssh->frontend); ssh->state = SSH_STATE_BEFORE_SIZE; ssh->pinger = pinger_new(&ssh->cfg, &ssh_backend, ssh); sfree(s->vstring); crFinish(0); } static void ssh_process_incoming_data(Ssh ssh, |
︙ | ︙ | |||
3154 3155 3156 3157 3158 3159 3160 | } static void ssh_gotdata(Ssh ssh, unsigned char *data, int datalen) { /* Log raw data, if we're in that mode. */ if (ssh->logctx) log_packet(ssh->logctx, PKT_INCOMING, -1, NULL, data, datalen, | | | | 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 | } static void ssh_gotdata(Ssh ssh, unsigned char *data, int datalen) { /* Log raw data, if we're in that mode. */ if (ssh->logctx) log_packet(ssh->logctx, PKT_INCOMING, -1, NULL, data, datalen, 0, NULL, NULL); crBegin(ssh->ssh_gotdata_crstate); /* * To begin with, feed the characters one by one to the * protocol initialisation / selection function do_ssh_init(). * When that returns 0, we're done with the initial greeting * exchange and can move on to packet discipline. */ while (1) { int ret; /* need not be kept across crReturn */ if (datalen == 0) crReturnV; /* more data please */ ret = do_ssh_init(ssh, *data); data++; datalen--; if (ret == 0) break; } /* |
︙ | ︙ | |||
3232 3233 3234 3235 3236 3237 3238 | * Now we must shut down any port- and X-forwarded channels going * through this connection. */ if (ssh->channels) { while (NULL != (c = index234(ssh->channels, 0))) { switch (c->type) { case CHAN_X11: | | | | | | < < < < < < < < < < < | | < | | < < < | | < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 | * Now we must shut down any port- and X-forwarded channels going * through this connection. */ if (ssh->channels) { while (NULL != (c = index234(ssh->channels, 0))) { switch (c->type) { case CHAN_X11: x11_close(c->u.x11.s); break; case CHAN_SOCKDATA: case CHAN_SOCKDATA_DORMANT: pfd_close(c->u.pfd.s); break; } del234(ssh->channels, c); /* moving next one to index 0 */ if (ssh->version == 2) bufchain_clear(&c->v.v2.outbuffer); sfree(c); } } /* * Go through port-forwardings, and close any associated * listening sockets. */ if (ssh->portfwds) { struct ssh_portfwd *pf; while (NULL != (pf = index234(ssh->portfwds, 0))) { /* Dispose of any listening socket. */ if (pf->local) pfd_terminate(pf->local); del234(ssh->portfwds, pf); /* moving next one to index 0 */ free_portfwd(pf); } freetree234(ssh->portfwds); ssh->portfwds = NULL; } return ret; } static void ssh_log(Plug plug, int type, SockAddr addr, int port, const char *error_msg, int error_code) { Ssh ssh = (Ssh) plug; char addrbuf[256], *msg; sk_getaddr(addr, addrbuf, lenof(addrbuf)); if (type == 0) msg = dupprintf("Connecting to %s port %d", addrbuf, port); else msg = dupprintf("Failed to connect to %s: %s", addrbuf, error_msg); logevent(msg); sfree(msg); } static int ssh_closing(Plug plug, const char *error_msg, int error_code, int calling_back) { Ssh ssh = (Ssh) plug; int need_notify = ssh_do_close(ssh, FALSE); |
︙ | ︙ | |||
3390 3391 3392 3393 3394 3395 3396 | * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ static const char *connect_to_host(Ssh ssh, char *host, int port, char **realhost, int nodelay, int keepalive) { static const struct plug_function_table fn_table = { | | < < | < | | | 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 | * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ static const char *connect_to_host(Ssh ssh, char *host, int port, char **realhost, int nodelay, int keepalive) { static const struct plug_function_table fn_table = { ssh_log, ssh_closing, ssh_receive, ssh_sent, NULL }; SockAddr addr; const char *err; if (*ssh->cfg.loghost) { char *colon; ssh->savedhost = dupstr(ssh->cfg.loghost); ssh->savedport = 22; /* default ssh port */ /* * A colon suffix on savedhost also lets us affect * savedport. * * (FIXME: do something about IPv6 address literals here.) |
︙ | ︙ | |||
3428 3429 3430 3431 3432 3433 3434 | } else { ssh->savedhost = dupstr(host); if (port < 0) port = 22; /* default ssh port */ ssh->savedport = port; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < | | | | > | | | | | > > > > | | < | | | | < < | | | | | | 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 | } else { ssh->savedhost = dupstr(host); if (port < 0) port = 22; /* default ssh port */ ssh->savedport = port; } /* * Try to find host. */ logeventf(ssh, "Looking up host \"%s\"%s", host, (ssh->cfg.addressfamily == ADDRTYPE_IPV4 ? " (IPv4)" : (ssh->cfg.addressfamily == ADDRTYPE_IPV6 ? " (IPv6)" : ""))); addr = name_lookup(host, port, realhost, &ssh->cfg, ssh->cfg.addressfamily); if ((err = sk_addr_error(addr)) != NULL) { sk_addr_free(addr); return err; } ssh->fullhostname = dupstr(*realhost); /* save in case of GSSAPI */ /* * Open socket. */ ssh->fn = &fn_table; ssh->s = new_connection(addr, *realhost, port, 0, 1, nodelay, keepalive, (Plug) ssh, &ssh->cfg); if ((err = sk_socket_error(ssh->s)) != NULL) { ssh->s = NULL; notify_remote_exit(ssh->frontend); return err; } /* * If the SSH version number's fixed, set it now, and if it's SSH-2, * send the version string too. */ if (ssh->cfg.sshprot == 0) ssh->version = 1; if (ssh->cfg.sshprot == 3) { ssh->version = 2; ssh_send_verstring(ssh, NULL); } /* * loghost, if configured, overrides realhost. */ if (*ssh->cfg.loghost) { sfree(*realhost); *realhost = dupstr(ssh->cfg.loghost); } return NULL; } /* * Throttle or unthrottle the SSH connection. |
︙ | ︙ | |||
3543 3544 3545 3546 3547 3548 3549 | switch (c->type) { case CHAN_MAINSESSION: /* * This is treated separately, outside the switch. */ break; case CHAN_X11: | | | | 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 | switch (c->type) { case CHAN_MAINSESSION: /* * This is treated separately, outside the switch. */ break; case CHAN_X11: x11_override_throttle(c->u.x11.s, enable); break; case CHAN_AGENT: /* Agent channels require no buffer management. */ break; case CHAN_SOCKDATA: pfd_override_throttle(c->u.pfd.s, enable); break; } } } static void ssh_agent_callback(void *sshv, void *reply, int replylen) { |
︙ | ︙ | |||
3592 3593 3594 3595 3596 3597 3598 | static void ssh_agentf_callback(void *cv, void *reply, int replylen) { struct ssh_channel *c = (struct ssh_channel *)cv; Ssh ssh = c->ssh; void *sentreply = reply; | < > > < < < < < < | 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 | static void ssh_agentf_callback(void *cv, void *reply, int replylen) { struct ssh_channel *c = (struct ssh_channel *)cv; Ssh ssh = c->ssh; void *sentreply = reply; if (!sentreply) { /* Fake SSH_AGENT_FAILURE. */ sentreply = "\0\0\0\1\5"; replylen = 5; } if (ssh->version == 2) { ssh2_add_channel_data(c, sentreply, replylen); ssh2_try_send(c); } else { send_packet(ssh, SSH1_MSG_CHANNEL_DATA, PKT_INT, c->remoteid, PKT_INT, replylen, PKTT_DATA, PKT_DATA, sentreply, replylen, PKTT_OTHER, PKT_END); } if (reply) sfree(reply); } /* * Client-initiated disconnection. Send a DISCONNECT if `wire_reason' * non-NULL, otherwise just close the connection. `client_reason' == NULL * => log `wire_reason'. */ |
︙ | ︙ | |||
3659 3660 3661 3662 3663 3664 3665 3666 3667 | * Handle the key exchange and user authentication phases. */ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, struct Packet *pktin) { int i, j, ret; unsigned char cookie[8], *ptr; struct MD5Context md5c; struct do_ssh1_login_state { | > < > < < | | | | | | | | | < | | | | | 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 | * Handle the key exchange and user authentication phases. */ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, struct Packet *pktin) { int i, j, ret; unsigned char cookie[8], *ptr; struct RSAKey servkey, hostkey; struct MD5Context md5c; struct do_ssh1_login_state { int len; unsigned char *rsabuf, *keystr1, *keystr2; unsigned long supported_ciphers_mask, supported_auths_mask; int tried_publickey, tried_agent; int tis_auth_refused, ccard_auth_refused; unsigned char session_id[16]; int cipher_type; char username[100]; void *publickey_blob; int publickey_bloblen; char *publickey_comment; int publickey_encrypted; prompts_t *cur_prompt; char c; int pwpkt_type; unsigned char request[5], *response, *p; int responselen; int keyi, nkeys; int authed; struct RSAKey key; Bignum challenge; char *commentp; int commentlen; int dlgret; }; crState(do_ssh1_login_state); crBegin(ssh->do_ssh1_login_crstate); if (!pktin) crWaitUntil(pktin); if (pktin->type != SSH1_SMSG_PUBLIC_KEY) { bombout(("Public key packet not received")); crStop(0); } logevent("Received public keys"); ptr = ssh_pkt_getdata(pktin, 8); if (!ptr) { bombout(("SSH-1 public key packet stopped before random cookie")); crStop(0); } memcpy(cookie, ptr, 8); if (!ssh1_pkt_getrsakey(pktin, &servkey, &s->keystr1) || !ssh1_pkt_getrsakey(pktin, &hostkey, &s->keystr2)) { bombout(("Failed to read SSH-1 public keys from public key packet")); crStop(0); } /* * Log the host key fingerprint. */ { char logmsg[80]; logevent("Host key fingerprint is:"); strcpy(logmsg, " "); hostkey.comment = NULL; rsa_fingerprint(logmsg + strlen(logmsg), sizeof(logmsg) - strlen(logmsg), &hostkey); logevent(logmsg); } ssh->v1_remote_protoflags = ssh_pkt_getuint32(pktin); s->supported_ciphers_mask = ssh_pkt_getuint32(pktin); s->supported_auths_mask = ssh_pkt_getuint32(pktin); if ((ssh->remote_bugs & BUG_CHOKES_ON_RSA)) s->supported_auths_mask &= ~(1 << SSH1_AUTH_RSA); ssh->v1_local_protoflags = ssh->v1_remote_protoflags & SSH1_PROTOFLAGS_SUPPORTED; ssh->v1_local_protoflags |= SSH1_PROTOFLAG_SCREEN_NUMBER; MD5Init(&md5c); MD5Update(&md5c, s->keystr2, hostkey.bytes); MD5Update(&md5c, s->keystr1, servkey.bytes); MD5Update(&md5c, cookie, 8); MD5Final(s->session_id, &md5c); for (i = 0; i < 32; i++) ssh->session_key[i] = random_byte(); /* * Verify that the `bits' and `bytes' parameters match. */ if (hostkey.bits > hostkey.bytes * 8 || servkey.bits > servkey.bytes * 8) { bombout(("SSH-1 public keys were badly formatted")); crStop(0); } s->len = (hostkey.bytes > servkey.bytes ? hostkey.bytes : servkey.bytes); s->rsabuf = snewn(s->len, unsigned char); /* * Verify the host key. */ { /* * First format the key into a string. */ int len = rsastr_len(&hostkey); char fingerprint[100]; char *keystr = snewn(len, char); rsastr_fmt(keystr, &hostkey); rsa_fingerprint(fingerprint, sizeof(fingerprint), &hostkey); ssh_set_frozen(ssh, 1); s->dlgret = verify_ssh_host_key(ssh->frontend, ssh->savedhost, ssh->savedport, "rsa", keystr, fingerprint, ssh_dialog_callback, ssh); sfree(keystr); |
︙ | ︙ | |||
3806 3807 3808 3809 3810 3811 3812 | for (i = 0; i < 32; i++) { s->rsabuf[i] = ssh->session_key[i]; if (i < 16) s->rsabuf[i] ^= s->session_id[i]; } | | | | | | | < | 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 | for (i = 0; i < 32; i++) { s->rsabuf[i] = ssh->session_key[i]; if (i < 16) s->rsabuf[i] ^= s->session_id[i]; } if (hostkey.bytes > servkey.bytes) { ret = rsaencrypt(s->rsabuf, 32, &servkey); if (ret) ret = rsaencrypt(s->rsabuf, servkey.bytes, &hostkey); } else { ret = rsaencrypt(s->rsabuf, 32, &hostkey); if (ret) ret = rsaencrypt(s->rsabuf, hostkey.bytes, &servkey); } if (!ret) { bombout(("SSH-1 public key encryptions failed due to bad formatting")); crStop(0); } logevent("Encrypted session key"); { int cipher_chosen = 0, warn = 0; char *cipher_string = NULL; int i; for (i = 0; !cipher_chosen && i < CIPHER_MAX; i++) { int next_cipher = ssh->cfg.ssh_cipherlist[i]; if (next_cipher == CIPHER_WARN) { /* If/when we choose a cipher, warn about it */ warn = 1; } else if (next_cipher == CIPHER_AES) { /* XXX Probably don't need to mention this. */ logevent("AES not supported in SSH-1, skipping"); } else { |
︙ | ︙ | |||
3916 3917 3918 3919 3920 3921 3922 | ssh->v1_cipher_ctx = ssh->cipher->make_context(); ssh->cipher->sesskey(ssh->v1_cipher_ctx, ssh->session_key); logeventf(ssh, "Initialised %s encryption", ssh->cipher->text_name); ssh->crcda_ctx = crcda_make_context(); logevent("Installing CRC compensation attack detector"); | | | | | | | | | | | | | | > | > | > | | | 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 | ssh->v1_cipher_ctx = ssh->cipher->make_context(); ssh->cipher->sesskey(ssh->v1_cipher_ctx, ssh->session_key); logeventf(ssh, "Initialised %s encryption", ssh->cipher->text_name); ssh->crcda_ctx = crcda_make_context(); logevent("Installing CRC compensation attack detector"); if (servkey.modulus) { sfree(servkey.modulus); servkey.modulus = NULL; } if (servkey.exponent) { sfree(servkey.exponent); servkey.exponent = NULL; } if (hostkey.modulus) { sfree(hostkey.modulus); hostkey.modulus = NULL; } if (hostkey.exponent) { sfree(hostkey.exponent); hostkey.exponent = NULL; } crWaitUntil(pktin); if (pktin->type != SSH1_SMSG_SUCCESS) { bombout(("Encryption not successfully enabled")); crStop(0); } logevent("Successfully started encryption"); fflush(stdout); /* FIXME eh? */ { if (!get_remote_username(&ssh->cfg, s->username, sizeof(s->username))) { int ret; /* need not be kept over crReturn */ s->cur_prompt = new_prompts(ssh->frontend); s->cur_prompt->to_server = TRUE; s->cur_prompt->name = dupstr("SSH login name"); add_prompt(s->cur_prompt, dupstr("login as: "), TRUE, lenof(s->username)); ret = get_userpass_input(s->cur_prompt, NULL, 0); while (ret < 0) { ssh->send_ok = 1; crWaitUntil(!pktin); ret = get_userpass_input(s->cur_prompt, in, inlen); ssh->send_ok = 0; } if (!ret) { /* * Failed to get a username. Terminate. */ free_prompts(s->cur_prompt); ssh_disconnect(ssh, "No username provided", NULL, 0, TRUE); crStop(0); } memcpy(s->username, s->cur_prompt->prompts[0]->result, lenof(s->username)); free_prompts(s->cur_prompt); } send_packet(ssh, SSH1_CMSG_USER, PKT_STR, s->username, PKT_END); { char *userlog = dupprintf("Sent username \"%s\"", s->username); logevent(userlog); if (flags & FLAG_INTERACTIVE && (!((flags & FLAG_STDERR) && (flags & FLAG_VERBOSE)))) { c_write_str(ssh, userlog); c_write_str(ssh, "\r\n"); } sfree(userlog); |
︙ | ︙ | |||
3993 3994 3995 3996 3997 3998 3999 | } else { s->tried_publickey = s->tried_agent = 0; } s->tis_auth_refused = s->ccard_auth_refused = 0; /* * Load the public half of any configured keyfile for later use. */ | < | | | | | | | | | 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 | } else { s->tried_publickey = s->tried_agent = 0; } s->tis_auth_refused = s->ccard_auth_refused = 0; /* * Load the public half of any configured keyfile for later use. */ if (!filename_is_null(ssh->cfg.keyfile)) { int keytype; logeventf(ssh, "Reading private key file \"%.150s\"", filename_to_str(&ssh->cfg.keyfile)); keytype = key_type(&ssh->cfg.keyfile); if (keytype == SSH_KEYTYPE_SSH1) { const char *error; if (rsakey_pubblob(&ssh->cfg.keyfile, &s->publickey_blob, &s->publickey_bloblen, &s->publickey_comment, &error)) { s->publickey_encrypted = rsakey_encrypted(&ssh->cfg.keyfile, NULL); } else { char *msgbuf; logeventf(ssh, "Unable to load private key (%s)", error); msgbuf = dupprintf("Unable to load private key file " "\"%.150s\" (%s)\r\n", filename_to_str(&ssh->cfg.keyfile), error); c_write_str(ssh, msgbuf); sfree(msgbuf); s->publickey_blob = NULL; } } else { char *msgbuf; logeventf(ssh, "Unable to use this key file (%s)", key_type_to_str(keytype)); msgbuf = dupprintf("Unable to use key file \"%.150s\"" " (%s)\r\n", filename_to_str(&ssh->cfg.keyfile), key_type_to_str(keytype)); c_write_str(ssh, msgbuf); sfree(msgbuf); s->publickey_blob = NULL; } } else s->publickey_blob = NULL; while (pktin->type == SSH1_SMSG_FAILURE) { s->pwpkt_type = SSH1_CMSG_AUTH_PASSWORD; if (ssh->cfg.tryagent && agent_exists() && !s->tried_agent) { /* * Attempt RSA authentication using Pageant. */ void *r; s->authed = FALSE; s->tried_agent = 1; |
︙ | ︙ | |||
4065 4066 4067 4068 4069 4070 4071 | r = ssh->agent_response; s->responselen = ssh->agent_response_len; } s->response = (unsigned char *) r; if (s->response && s->responselen >= 5 && s->response[4] == SSH1_AGENT_RSA_IDENTITIES_ANSWER) { s->p = s->response + 5; | < < < < | < | | | | < | | 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 | r = ssh->agent_response; s->responselen = ssh->agent_response_len; } s->response = (unsigned char *) r; if (s->response && s->responselen >= 5 && s->response[4] == SSH1_AGENT_RSA_IDENTITIES_ANSWER) { s->p = s->response + 5; s->nkeys = GET_32BIT(s->p); s->p += 4; logeventf(ssh, "Pageant has %d SSH-1 keys", s->nkeys); for (s->keyi = 0; s->keyi < s->nkeys; s->keyi++) { unsigned char *pkblob = s->p; s->p += 4; { int n, ok = FALSE; do { /* do while (0) to make breaking easy */ n = ssh1_read_bignum (s->p, s->responselen-(s->p-s->response), &s->key.exponent); if (n < 0) break; s->p += n; n = ssh1_read_bignum (s->p, s->responselen-(s->p-s->response), &s->key.modulus); if (n < 0) break; s->p += n; if (s->responselen - (s->p-s->response) < 4) break; s->commentlen = GET_32BIT(s->p); s->p += 4; if (s->responselen - (s->p-s->response) < s->commentlen) break; s->commentp = (char *)s->p; s->p += s->commentlen; ok = TRUE; } while (0); if (!ok) { |
︙ | ︙ | |||
4225 4226 4227 4228 4229 4230 4231 | /* * Try public key authentication with the specified * key file. */ int got_passphrase; /* need not be kept over crReturn */ if (flags & FLAG_VERBOSE) c_write_str(ssh, "Trying public key authentication.\r\n"); | < | | > < | | | | 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 | /* * Try public key authentication with the specified * key file. */ int got_passphrase; /* need not be kept over crReturn */ if (flags & FLAG_VERBOSE) c_write_str(ssh, "Trying public key authentication.\r\n"); logeventf(ssh, "Trying public key \"%s\"", filename_to_str(&ssh->cfg.keyfile)); s->tried_publickey = 1; got_passphrase = FALSE; while (!got_passphrase) { /* * Get a passphrase, if necessary. */ char *passphrase = NULL; /* only written after crReturn */ const char *error; if (!s->publickey_encrypted) { if (flags & FLAG_VERBOSE) c_write_str(ssh, "No passphrase required.\r\n"); passphrase = NULL; } else { int ret; /* need not be kept over crReturn */ s->cur_prompt = new_prompts(ssh->frontend); s->cur_prompt->to_server = FALSE; s->cur_prompt->name = dupstr("SSH key passphrase"); add_prompt(s->cur_prompt, dupprintf("Passphrase for key \"%.100s\": ", s->publickey_comment), FALSE, SSH_MAX_PASSWORD_LEN); ret = get_userpass_input(s->cur_prompt, NULL, 0); while (ret < 0) { ssh->send_ok = 1; crWaitUntil(!pktin); ret = get_userpass_input(s->cur_prompt, in, inlen); ssh->send_ok = 0; } if (!ret) { /* Failed to get a passphrase. Terminate. */ free_prompts(s->cur_prompt); ssh_disconnect(ssh, NULL, "Unable to authenticate", 0, TRUE); crStop(0); } passphrase = dupstr(s->cur_prompt->prompts[0]->result); free_prompts(s->cur_prompt); } /* * Try decrypting key with passphrase. */ ret = loadrsakey(&ssh->cfg.keyfile, &s->key, passphrase, &error); if (passphrase) { memset(passphrase, 0, strlen(passphrase)); sfree(passphrase); } if (ret == 1) { /* Correct passphrase. */ got_passphrase = TRUE; } else if (ret == 0) { c_write_str(ssh, "Couldn't load private key from "); c_write_str(ssh, filename_to_str(&ssh->cfg.keyfile)); c_write_str(ssh, " ("); c_write_str(ssh, error); c_write_str(ssh, ").\r\n"); got_passphrase = FALSE; break; /* go and try something else */ } else if (ret == -1) { c_write_str(ssh, "Wrong passphrase.\r\n"); /* FIXME */ |
︙ | ︙ | |||
4363 4364 4365 4366 4367 4368 4369 | } /* * Otherwise, try various forms of password-like authentication. */ s->cur_prompt = new_prompts(ssh->frontend); | | | 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 | } /* * Otherwise, try various forms of password-like authentication. */ s->cur_prompt = new_prompts(ssh->frontend); if (ssh->cfg.try_tis_auth && (s->supported_auths_mask & (1 << SSH1_AUTH_TIS)) && !s->tis_auth_refused) { s->pwpkt_type = SSH1_CMSG_AUTH_TIS_RESPONSE; logevent("Requested TIS authentication"); send_packet(ssh, SSH1_CMSG_AUTH_TIS, PKT_END); crWaitUntil(pktin); if (pktin->type != SSH1_SMSG_AUTH_TIS_CHALLENGE) { |
︙ | ︙ | |||
4402 4403 4404 4405 4406 4407 4408 | prompt = dupstr("Response: "); } s->cur_prompt->instruction = dupprintf("Using TIS authentication.%s%s", (*instr_suf) ? "\n" : "", instr_suf); s->cur_prompt->instr_reqd = TRUE; | | | | 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 | prompt = dupstr("Response: "); } s->cur_prompt->instruction = dupprintf("Using TIS authentication.%s%s", (*instr_suf) ? "\n" : "", instr_suf); s->cur_prompt->instr_reqd = TRUE; add_prompt(s->cur_prompt, prompt, FALSE, SSH_MAX_PASSWORD_LEN); sfree(instr_suf); } } if (ssh->cfg.try_tis_auth && (s->supported_auths_mask & (1 << SSH1_AUTH_CCARD)) && !s->ccard_auth_refused) { s->pwpkt_type = SSH1_CMSG_AUTH_CCARD_RESPONSE; logevent("Requested CryptoCard authentication"); send_packet(ssh, SSH1_CMSG_AUTH_CCARD, PKT_END); crWaitUntil(pktin); if (pktin->type != SSH1_SMSG_AUTH_CCARD_CHALLENGE) { |
︙ | ︙ | |||
4445 4446 4447 4448 4449 4450 4451 | prompt = dupstr("Response: "); } s->cur_prompt->instruction = dupprintf("Using CryptoCard authentication.%s%s", (*instr_suf) ? "\n" : "", instr_suf); s->cur_prompt->instr_reqd = TRUE; | | | | | | 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 | prompt = dupstr("Response: "); } s->cur_prompt->instruction = dupprintf("Using CryptoCard authentication.%s%s", (*instr_suf) ? "\n" : "", instr_suf); s->cur_prompt->instr_reqd = TRUE; add_prompt(s->cur_prompt, prompt, FALSE, SSH_MAX_PASSWORD_LEN); sfree(instr_suf); } } if (s->pwpkt_type == SSH1_CMSG_AUTH_PASSWORD) { if ((s->supported_auths_mask & (1 << SSH1_AUTH_PASSWORD)) == 0) { bombout(("No supported authentication methods available")); crStop(0); } s->cur_prompt->to_server = TRUE; s->cur_prompt->name = dupstr("SSH password"); add_prompt(s->cur_prompt, dupprintf("%.90s@%.90s's password: ", s->username, ssh->savedhost), FALSE, SSH_MAX_PASSWORD_LEN); } /* * Show password prompt, having first obtained it via a TIS * or CryptoCard exchange if we're doing TIS or CryptoCard * authentication. */ |
︙ | ︙ | |||
4550 4551 4552 4553 4554 4555 4556 | assert(pwlen >= bottom && pwlen <= top); randomstr = snewn(top + 1, char); for (i = bottom; i <= top; i++) { if (i == pwlen) { defer_packet(ssh, s->pwpkt_type, | > | | | 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 | assert(pwlen >= bottom && pwlen <= top); randomstr = snewn(top + 1, char); for (i = bottom; i <= top; i++) { if (i == pwlen) { defer_packet(ssh, s->pwpkt_type, PKTT_PASSWORD, PKT_STR, s->cur_prompt->prompts[0]->result, PKTT_OTHER, PKT_END); } else { for (j = 0; j < i; j++) { do { randomstr[j] = random_byte(); } while (randomstr[j] == '\0'); } randomstr[i] = '\0'; |
︙ | ︙ | |||
4589 4590 4591 4592 4593 4594 4595 | while (len < sizeof(string)) { string[len++] = (char) random_byte(); } } else { ss = s->cur_prompt->prompts[0]->result; } logevent("Sending length-padded password"); | | | | | | | | 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 | while (len < sizeof(string)) { string[len++] = (char) random_byte(); } } else { ss = s->cur_prompt->prompts[0]->result; } logevent("Sending length-padded password"); send_packet(ssh, s->pwpkt_type, PKTT_PASSWORD, PKT_INT, len, PKT_DATA, ss, len, PKTT_OTHER, PKT_END); } else { /* * The server is believed unable to cope with * any of our password camouflage methods. */ int len; len = strlen(s->cur_prompt->prompts[0]->result); logevent("Sending unpadded password"); send_packet(ssh, s->pwpkt_type, PKTT_PASSWORD, PKT_INT, len, PKT_DATA, s->cur_prompt->prompts[0]->result, len, PKTT_OTHER, PKT_END); } } else { send_packet(ssh, s->pwpkt_type, PKTT_PASSWORD, PKT_STR, s->cur_prompt->prompts[0]->result, PKTT_OTHER, PKT_END); } logevent("Sent password"); free_prompts(s->cur_prompt); crWaitUntil(pktin); if (pktin->type == SSH1_SMSG_FAILURE) { if (flags & FLAG_VERBOSE) c_write_str(ssh, "Access denied\r\n"); |
︙ | ︙ | |||
4634 4635 4636 4637 4638 4639 4640 | } logevent("Authentication successful"); crFinish(1); } | < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < | < | | | > > > > > > > > > | | > > > | < > > > > > | | < < > > > > > > > > > > > > > > > > > > > > | | | | < < | | | | < | < < | < | | | 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 | } logevent("Authentication successful"); crFinish(1); } void sshfwd_close(struct ssh_channel *c) { Ssh ssh = c->ssh; if (ssh->state == SSH_STATE_CLOSED) return; if (!c->closes) { /* * If halfopen is true, we have sent * CHANNEL_OPEN for this channel, but it hasn't even been * acknowledged by the server. So we must set a close flag * on it now, and then when the server acks the channel * open, we can close it then. */ if (!c->halfopen) { if (ssh->version == 1) { send_packet(ssh, SSH1_MSG_CHANNEL_CLOSE, PKT_INT, c->remoteid, PKT_END); c->closes = 1; /* sent MSG_CLOSE */ } else { int bytes_to_send = bufchain_size(&c->v.v2.outbuffer); if (bytes_to_send > 0) { /* * If we still have unsent data in our outgoing * buffer for this channel, we can't actually * initiate a close operation yet or that data * will be lost. Instead, set the pending_close * flag so that when we do clear the buffer * we'll start closing the channel. */ char logmsg[160] = {'\0'}; sprintf( logmsg, "Forwarded port pending to be closed : " "%d bytes remaining", bytes_to_send); logevent(logmsg); c->pending_close = TRUE; } else { /* * No locally buffered data, so we can send the * close message immediately. */ struct Packet *pktout; pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_CLOSE); ssh2_pkt_adduint32(pktout, c->remoteid); ssh2_pkt_send(ssh, pktout); c->closes = 1; /* sent MSG_CLOSE */ logevent("Nothing left to send, closing channel"); } } } if (c->type == CHAN_X11) { c->u.x11.s = NULL; logevent("Forwarded X11 connection terminated"); } else if (c->type == CHAN_SOCKDATA || c->type == CHAN_SOCKDATA_DORMANT) { c->u.pfd.s = NULL; logevent("Forwarded port closed"); } } } int sshfwd_write(struct ssh_channel *c, char *buf, int len) { Ssh ssh = c->ssh; if (ssh->state == SSH_STATE_CLOSED) return 0; if (ssh->version == 1) { send_packet(ssh, SSH1_MSG_CHANNEL_DATA, PKT_INT, c->remoteid, PKT_INT, len, PKTT_DATA, PKT_DATA, buf, len, PKTT_OTHER, PKT_END); /* * In SSH-1 we can return 0 here - implying that forwarded * connections are never individually throttled - because * the only circumstance that can cause throttling will be * the whole SSH connection backing up, in which case * _everything_ will be throttled as a whole. */ |
︙ | ︙ | |||
4759 4760 4761 4762 4763 4764 4765 | assert(qh != NULL); assert(pktin->type == qh->msg1 || pktin->type == qh->msg2); if (qh->msg1 > 0) { assert(ssh->packet_dispatch[qh->msg1] == ssh_queueing_handler); | | | | | > | 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 | assert(qh != NULL); assert(pktin->type == qh->msg1 || pktin->type == qh->msg2); if (qh->msg1 > 0) { assert(ssh->packet_dispatch[qh->msg1] == ssh_queueing_handler); ssh->packet_dispatch[qh->msg1] = NULL; } if (qh->msg2 > 0) { assert(ssh->packet_dispatch[qh->msg2] == ssh_queueing_handler); ssh->packet_dispatch[qh->msg2] = NULL; } if (qh->next) { ssh->qhead = qh->next; if (ssh->qhead->msg1 > 0) { assert(ssh->packet_dispatch[ssh->qhead->msg1] == NULL); ssh->packet_dispatch[ssh->qhead->msg1] = ssh_queueing_handler; } if (ssh->qhead->msg2 > 0) { assert(ssh->packet_dispatch[ssh->qhead->msg2] == NULL); ssh->packet_dispatch[ssh->qhead->msg2] = ssh_queueing_handler; } } else { ssh->qhead = ssh->qtail = NULL; ssh->packet_dispatch[pktin->type] = NULL; } qh->handler(ssh, pktin, qh->ctx); sfree(qh); } |
︙ | ︙ | |||
4802 4803 4804 4805 4806 4807 4808 | qh->ctx = ctx; qh->next = NULL; if (ssh->qtail == NULL) { ssh->qhead = qh; if (qh->msg1 > 0) { | | | | 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 | qh->ctx = ctx; qh->next = NULL; if (ssh->qtail == NULL) { ssh->qhead = qh; if (qh->msg1 > 0) { assert(ssh->packet_dispatch[qh->msg1] == NULL); ssh->packet_dispatch[qh->msg1] = ssh_queueing_handler; } if (qh->msg2 > 0) { assert(ssh->packet_dispatch[qh->msg2] == NULL); ssh->packet_dispatch[qh->msg2] = ssh_queueing_handler; } } else { ssh->qtail->next = qh; } ssh->qtail = qh; } |
︙ | ︙ | |||
4834 4835 4836 4837 4838 4839 4840 | rpf = del234(ssh->rportfwds, pf); assert(rpf == pf); pf->pfrec->remote = NULL; free_rportfwd(pf); } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > < < < | < < | | > | > | | > > | > | > > > | | | > | > > | > > > > > > | > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 | rpf = del234(ssh->rportfwds, pf); assert(rpf == pf); pf->pfrec->remote = NULL; free_rportfwd(pf); } } static void ssh_setup_portfwd(Ssh ssh, const Config *cfg) { const char *portfwd_strptr = cfg->portfwd; struct ssh_portfwd *epf; int i; if (!ssh->portfwds) { ssh->portfwds = newtree234(ssh_portcmp); } else { /* * Go through the existing port forwardings and tag them * with status==DESTROY. Any that we want to keep will be * re-enabled (status==KEEP) as we go through the * configuration and find out which bits are the same as * they were before. */ struct ssh_portfwd *epf; int i; for (i = 0; (epf = index234(ssh->portfwds, i)) != NULL; i++) epf->status = DESTROY; } while (*portfwd_strptr) { char address_family, type; int sport,dport,sserv,dserv; char sports[256], dports[256], saddr[256], host[256]; int n; address_family = 'A'; type = 'L'; if (*portfwd_strptr == 'A' || *portfwd_strptr == '4' || *portfwd_strptr == '6') address_family = *portfwd_strptr++; if (*portfwd_strptr == 'L' || *portfwd_strptr == 'R' || *portfwd_strptr == 'D') type = *portfwd_strptr++; saddr[0] = '\0'; n = 0; while (*portfwd_strptr && *portfwd_strptr != '\t') { if (*portfwd_strptr == ':') { /* * We've seen a colon in the middle of the * source port number. This means that * everything we've seen until now is the * source _address_, so we'll move it into * saddr and start sports from the beginning * again. */ portfwd_strptr++; sports[n] = '\0'; if (ssh->version == 1 && type == 'R') { logeventf(ssh, "SSH-1 cannot handle remote source address " "spec \"%s\"; ignoring", sports); } else strcpy(saddr, sports); n = 0; } if (n < lenof(sports)-1) sports[n++] = *portfwd_strptr++; } sports[n] = 0; if (type != 'D') { if (*portfwd_strptr == '\t') portfwd_strptr++; n = 0; while (*portfwd_strptr && *portfwd_strptr != ':') { if (n < lenof(host)-1) host[n++] = *portfwd_strptr++; } host[n] = 0; if (*portfwd_strptr == ':') portfwd_strptr++; n = 0; while (*portfwd_strptr) { if (n < lenof(dports)-1) dports[n++] = *portfwd_strptr++; } dports[n] = 0; portfwd_strptr++; dport = atoi(dports); dserv = 0; if (dport == 0) { dserv = 1; dport = net_service_lookup(dports); if (!dport) { logeventf(ssh, "Service lookup failed for destination" " port \"%s\"", dports); } } } else { while (*portfwd_strptr) portfwd_strptr++; host[0] = 0; dports[0] = 0; dport = dserv = -1; portfwd_strptr++; /* eat the NUL and move to next one */ } sport = atoi(sports); sserv = 0; if (sport == 0) { sserv = 1; sport = net_service_lookup(sports); if (!sport) { logeventf(ssh, "Service lookup failed for source" " port \"%s\"", sports); } } if (sport && dport) { /* Set up a description of the source port. */ struct ssh_portfwd *pfrec, *epfrec; pfrec = snew(struct ssh_portfwd); pfrec->type = type; pfrec->saddr = *saddr ? dupstr(saddr) : NULL; pfrec->sserv = sserv ? dupstr(sports) : NULL; pfrec->sport = sport; pfrec->daddr = *host ? dupstr(host) : NULL; pfrec->dserv = dserv ? dupstr(dports) : NULL; pfrec->dport = dport; pfrec->local = NULL; pfrec->remote = NULL; pfrec->addressfamily = (address_family == '4' ? ADDRTYPE_IPV4 : address_family == '6' ? ADDRTYPE_IPV6 : ADDRTYPE_UNSPEC); |
︙ | ︙ | |||
4995 4996 4997 4998 4999 5000 5001 | * Anything else indicates that there was a duplicate * in our input, which we'll silently ignore. */ free_portfwd(pfrec); } else { pfrec->status = CREATE; } | < < < | 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 | * Anything else indicates that there was a duplicate * in our input, which we'll silently ignore. */ free_portfwd(pfrec); } else { pfrec->status = CREATE; } } } /* * Now go through and destroy any port forwardings which were * not re-enabled. */ |
︙ | ︙ | |||
5051 5052 5053 5054 5055 5056 5057 | */ } else { pktout = ssh2_pkt_init(SSH2_MSG_GLOBAL_REQUEST); ssh2_pkt_addstring(pktout, "cancel-tcpip-forward"); ssh2_pkt_addbool(pktout, 0);/* _don't_ want reply */ if (epf->saddr) { ssh2_pkt_addstring(pktout, epf->saddr); | | | | | | | 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 | */ } else { pktout = ssh2_pkt_init(SSH2_MSG_GLOBAL_REQUEST); ssh2_pkt_addstring(pktout, "cancel-tcpip-forward"); ssh2_pkt_addbool(pktout, 0);/* _don't_ want reply */ if (epf->saddr) { ssh2_pkt_addstring(pktout, epf->saddr); } else if (ssh->cfg.rport_acceptall) { /* XXX: ssh->cfg.rport_acceptall may not represent * what was used to open the original connection, * since it's reconfigurable. */ ssh2_pkt_addstring(pktout, "0.0.0.0"); } else { ssh2_pkt_addstring(pktout, "127.0.0.1"); } ssh2_pkt_adduint32(pktout, epf->sport); ssh2_pkt_send(ssh, pktout); } del234(ssh->rportfwds, rpf); free_rportfwd(rpf); } else if (epf->local) { pfd_terminate(epf->local); } delpos234(ssh->portfwds, i); free_portfwd(epf); i--; /* so we don't skip one in the list */ } |
︙ | ︙ | |||
5099 5100 5101 5102 5103 5104 5105 | epf->dserv ? epf->dserv : "", epf->dserv ? "(" : "", epf->dport, epf->dserv ? ")" : ""); } if (epf->type == 'L') { | | | > | | < < > | > | | < < < | | < < < < < < < | 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 | epf->dserv ? epf->dserv : "", epf->dserv ? "(" : "", epf->dport, epf->dserv ? ")" : ""); } if (epf->type == 'L') { const char *err = pfd_addforward(epf->daddr, epf->dport, epf->saddr, epf->sport, ssh, cfg, &epf->local, epf->addressfamily); logeventf(ssh, "Local %sport %s forwarding to %s%s%s", epf->addressfamily == ADDRTYPE_IPV4 ? "IPv4 " : epf->addressfamily == ADDRTYPE_IPV6 ? "IPv6 " : "", sportdesc, dportdesc, err ? " failed: " : "", err ? err : ""); } else if (epf->type == 'D') { const char *err = pfd_addforward(NULL, -1, epf->saddr, epf->sport, ssh, cfg, &epf->local, epf->addressfamily); logeventf(ssh, "Local %sport %s SOCKS dynamic forwarding%s%s", epf->addressfamily == ADDRTYPE_IPV4 ? "IPv4 " : epf->addressfamily == ADDRTYPE_IPV6 ? "IPv6 " : "", sportdesc, err ? " failed: " : "", err ? err : ""); } else { struct ssh_rportfwd *pf; /* * Ensure the remote port forwardings tree exists. */ if (!ssh->rportfwds) { if (ssh->version == 1) ssh->rportfwds = newtree234(ssh_rportcmp_ssh1); else ssh->rportfwds = newtree234(ssh_rportcmp_ssh2); } pf = snew(struct ssh_rportfwd); strncpy(pf->dhost, epf->daddr, lenof(pf->dhost)-1); pf->dhost[lenof(pf->dhost)-1] = '\0'; pf->dport = epf->dport; pf->sport = epf->sport; if (add234(ssh->rportfwds, pf) != pf) { logeventf(ssh, "Duplicate remote port forwarding to %s:%d", epf->daddr, epf->dport); sfree(pf); } else { logeventf(ssh, "Requesting remote port %s" |
︙ | ︙ | |||
5176 5177 5178 5179 5180 5181 5182 | SSH1_SMSG_FAILURE, ssh_rportfwd_succfail, pf); } else { struct Packet *pktout; pktout = ssh2_pkt_init(SSH2_MSG_GLOBAL_REQUEST); ssh2_pkt_addstring(pktout, "tcpip-forward"); ssh2_pkt_addbool(pktout, 1);/* want reply */ | > > > > > | > | | 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 | SSH1_SMSG_FAILURE, ssh_rportfwd_succfail, pf); } else { struct Packet *pktout; pktout = ssh2_pkt_init(SSH2_MSG_GLOBAL_REQUEST); ssh2_pkt_addstring(pktout, "tcpip-forward"); ssh2_pkt_addbool(pktout, 1);/* want reply */ if (epf->saddr) { ssh2_pkt_addstring(pktout, epf->saddr); } else if (cfg->rport_acceptall) { ssh2_pkt_addstring(pktout, "0.0.0.0"); } else { ssh2_pkt_addstring(pktout, "127.0.0.1"); } ssh2_pkt_adduint32(pktout, epf->sport); ssh2_pkt_send(ssh, pktout); ssh_queue_handler(ssh, SSH2_MSG_REQUEST_SUCCESS, SSH2_MSG_REQUEST_FAILURE, ssh_rportfwd_succfail, pf); } } |
︙ | ︙ | |||
5227 5228 5229 5230 5231 5232 5233 | send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE, PKT_INT, remoteid, PKT_END); logevent("Rejected X11 connect request"); } else { c = snew(struct ssh_channel); c->ssh = ssh; | | > > > > > > > > | | | | | | | | | | | | > | 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 | send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE, PKT_INT, remoteid, PKT_END); logevent("Rejected X11 connect request"); } else { c = snew(struct ssh_channel); c->ssh = ssh; if (x11_init(&c->u.x11.s, ssh->x11disp, c, NULL, -1, &ssh->cfg) != NULL) { logevent("Opening X11 forward connection failed"); sfree(c); send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE, PKT_INT, remoteid, PKT_END); } else { logevent ("Opening X11 forward connection succeeded"); c->remoteid = remoteid; c->halfopen = FALSE; c->localid = alloc_channel_id(ssh); c->closes = 0; c->pending_close = FALSE; c->throttling_conn = 0; c->type = CHAN_X11; /* identify channel type */ add234(ssh->channels, c); send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION, PKT_INT, c->remoteid, PKT_INT, c->localid, PKT_END); logevent("Opened X11 forward channel"); } } } static void ssh1_smsg_agent_open(Ssh ssh, struct Packet *pktin) { /* Remote side is trying to open a channel to talk to our * agent. Give them back a local channel number. */ |
︙ | ︙ | |||
5261 5262 5263 5264 5265 5266 5267 | } else { c = snew(struct ssh_channel); c->ssh = ssh; c->remoteid = remoteid; c->halfopen = FALSE; c->localid = alloc_channel_id(ssh); c->closes = 0; | | < < > | > > > > > | < < < | | | | < | < < | | | > | | > | < < < < < < | | | < | | < < < > | > | | < | < < < < < | < < < < | < | < < < | < < < | > | | < | | | < | < < < | 4789 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 | } else { c = snew(struct ssh_channel); c->ssh = ssh; c->remoteid = remoteid; c->halfopen = FALSE; c->localid = alloc_channel_id(ssh); c->closes = 0; c->pending_close = FALSE; c->throttling_conn = 0; c->type = CHAN_AGENT; /* identify channel type */ c->u.a.lensofar = 0; add234(ssh->channels, c); send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION, PKT_INT, c->remoteid, PKT_INT, c->localid, PKT_END); } } static void ssh1_msg_port_open(Ssh ssh, struct Packet *pktin) { /* Remote side is trying to open a channel to talk to a * forwarded port. Give them back a local channel number. */ struct ssh_channel *c; struct ssh_rportfwd pf, *pfp; int remoteid; int hostsize, port; char *host; const char *e; c = snew(struct ssh_channel); c->ssh = ssh; remoteid = ssh_pkt_getuint32(pktin); ssh_pkt_getstring(pktin, &host, &hostsize); port = ssh_pkt_getuint32(pktin); if (hostsize >= lenof(pf.dhost)) hostsize = lenof(pf.dhost)-1; memcpy(pf.dhost, host, hostsize); pf.dhost[hostsize] = '\0'; pf.dport = port; pfp = find234(ssh->rportfwds, &pf, NULL); if (pfp == NULL) { logeventf(ssh, "Rejected remote port open request for %s:%d", pf.dhost, port); send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE, PKT_INT, remoteid, PKT_END); } else { logeventf(ssh, "Received remote port open request for %s:%d", pf.dhost, port); e = pfd_newconnect(&c->u.pfd.s, pf.dhost, port, c, &ssh->cfg, pfp->pfrec->addressfamily); if (e != NULL) { logeventf(ssh, "Port open failed: %s", e); sfree(c); send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE, PKT_INT, remoteid, PKT_END); } else { c->remoteid = remoteid; c->halfopen = FALSE; c->localid = alloc_channel_id(ssh); c->closes = 0; c->pending_close = FALSE; c->throttling_conn = 0; c->type = CHAN_SOCKDATA; /* identify channel type */ add234(ssh->channels, c); send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION, PKT_INT, c->remoteid, PKT_INT, c->localid, PKT_END); logevent("Forwarded port opened successfully"); } } } static void ssh1_msg_channel_open_confirmation(Ssh ssh, struct Packet *pktin) { unsigned int remoteid = ssh_pkt_getuint32(pktin); unsigned int localid = ssh_pkt_getuint32(pktin); struct ssh_channel *c; c = find234(ssh->channels, &remoteid, ssh_channelfind); if (c && c->type == CHAN_SOCKDATA_DORMANT) { c->remoteid = localid; c->halfopen = FALSE; c->type = CHAN_SOCKDATA; c->throttling_conn = 0; pfd_confirm(c->u.pfd.s); } if (c && c->closes) { /* * We have a pending close on this channel, * which we decided on before the server acked * the channel open. So now we know the * remoteid, we can close it again. */ send_packet(ssh, SSH1_MSG_CHANNEL_CLOSE, PKT_INT, c->remoteid, PKT_END); } } static void ssh1_msg_channel_open_failure(Ssh ssh, struct Packet *pktin) { unsigned int remoteid = ssh_pkt_getuint32(pktin); struct ssh_channel *c; c = find234(ssh->channels, &remoteid, ssh_channelfind); if (c && c->type == CHAN_SOCKDATA_DORMANT) { logevent("Forwarded connection refused by server"); pfd_close(c->u.pfd.s); del234(ssh->channels, c); sfree(c); } } static void ssh1_msg_channel_close(Ssh ssh, struct Packet *pktin) { /* Remote side closes a channel. */ unsigned i = ssh_pkt_getuint32(pktin); struct ssh_channel *c; c = find234(ssh->channels, &i, ssh_channelfind); if (c && !c->halfopen) { int closetype; closetype = (pktin->type == SSH1_MSG_CHANNEL_CLOSE ? 1 : 2); if ((c->closes == 0) && (c->type == CHAN_X11)) { logevent("Forwarded X11 connection terminated"); assert(c->u.x11.s != NULL); x11_close(c->u.x11.s); c->u.x11.s = NULL; } if ((c->closes == 0) && (c->type == CHAN_SOCKDATA)) { logevent("Forwarded port closed"); assert(c->u.pfd.s != NULL); pfd_close(c->u.pfd.s); c->u.pfd.s = NULL; } c->closes |= (closetype << 2); /* seen this message */ if (!(c->closes & closetype)) { send_packet(ssh, pktin->type, PKT_INT, c->remoteid, PKT_END); c->closes |= closetype; /* sent it too */ } if (c->closes == 15) { del234(ssh->channels, c); sfree(c); } } else { bombout(("Received CHANNEL_CLOSE%s for %s channel %d\n", pktin->type == SSH1_MSG_CHANNEL_CLOSE ? "" : "_CONFIRMATION", c ? "half-open" : "nonexistent", i)); } } |
︙ | ︙ | |||
5456 5457 5458 5459 5460 5461 5462 | ssh_pkt_getstring(pktin, &p, &len); c = find234(ssh->channels, &i, ssh_channelfind); if (c) { int bufsize = 0; switch (c->type) { case CHAN_X11: | | | | 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 | ssh_pkt_getstring(pktin, &p, &len); c = find234(ssh->channels, &i, ssh_channelfind); if (c) { int bufsize = 0; switch (c->type) { case CHAN_X11: bufsize = x11_send(c->u.x11.s, p, len); break; case CHAN_SOCKDATA: bufsize = pfd_send(c->u.pfd.s, p, len); break; case CHAN_AGENT: /* Data for an agent message. Buffer it. */ while (len > 0) { if (c->u.a.lensofar < 4) { unsigned int l = min(4 - c->u.a.lensofar, (unsigned)len); memcpy(c->u.a.msglen + c->u.a.lensofar, p, |
︙ | ︙ | |||
5492 5493 5494 5495 5496 5497 5498 | p += l; len -= l; c->u.a.lensofar += l; } if (c->u.a.lensofar == c->u.a.totallen) { void *reply; int replylen; | < | 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 | p += l; len -= l; c->u.a.lensofar += l; } if (c->u.a.lensofar == c->u.a.totallen) { void *reply; int replylen; if (agent_query(c->u.a.message, c->u.a.totallen, &reply, &replylen, ssh_agentf_callback, c)) ssh_agentf_callback(c, reply, replylen); sfree(c->u.a.message); c->u.a.lensofar = 0; |
︙ | ︙ | |||
5547 5548 5549 5550 5551 5552 5553 | arg = ssh_tty_parse_boolean(val); break; } ssh2_pkt_addbyte(pktout, ssh_ttymodes[i].opcode); ssh2_pkt_addbyte(pktout, arg); } | < < < < | | | < | < < < < < < < < < | > > > > > > > | | | > | > | | | | | > | > | | | | | | | | | | | | | | | | | | < | | | | > | < > | | < < | | 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 | arg = ssh_tty_parse_boolean(val); break; } ssh2_pkt_addbyte(pktout, ssh_ttymodes[i].opcode); ssh2_pkt_addbyte(pktout, arg); } static void do_ssh1_connection(Ssh ssh, unsigned char *in, int inlen, struct Packet *pktin) { crBegin(ssh->do_ssh1_connection_crstate); ssh->packet_dispatch[SSH1_SMSG_STDOUT_DATA] = ssh->packet_dispatch[SSH1_SMSG_STDERR_DATA] = ssh1_smsg_stdout_stderr_data; ssh->packet_dispatch[SSH1_MSG_CHANNEL_OPEN_CONFIRMATION] = ssh1_msg_channel_open_confirmation; ssh->packet_dispatch[SSH1_MSG_CHANNEL_OPEN_FAILURE] = ssh1_msg_channel_open_failure; ssh->packet_dispatch[SSH1_MSG_CHANNEL_CLOSE] = ssh->packet_dispatch[SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION] = ssh1_msg_channel_close; ssh->packet_dispatch[SSH1_MSG_CHANNEL_DATA] = ssh1_msg_channel_data; ssh->packet_dispatch[SSH1_SMSG_EXIT_STATUS] = ssh1_smsg_exit_status; if (ssh->cfg.agentfwd && agent_exists()) { logevent("Requesting agent forwarding"); send_packet(ssh, SSH1_CMSG_AGENT_REQUEST_FORWARDING, PKT_END); do { crReturnV; } while (!pktin); if (pktin->type != SSH1_SMSG_SUCCESS && pktin->type != SSH1_SMSG_FAILURE) { bombout(("Protocol confusion")); crStopV; } else if (pktin->type == SSH1_SMSG_FAILURE) { logevent("Agent forwarding refused"); } else { logevent("Agent forwarding enabled"); ssh->agentfwd_enabled = TRUE; ssh->packet_dispatch[SSH1_SMSG_AGENT_OPEN] = ssh1_smsg_agent_open; } } if (ssh->cfg.x11_forward && (ssh->x11disp = x11_setup_display(ssh->cfg.x11_display, ssh->cfg.x11_auth, &ssh->cfg))) { logevent("Requesting X11 forwarding"); /* * Note that while we blank the X authentication data here, we don't * take any special action to blank the start of an X11 channel, * so using MIT-MAGIC-COOKIE-1 and actually opening an X connection * without having session blanking enabled is likely to leak your * cookie into the log. */ if (ssh->v1_local_protoflags & SSH1_PROTOFLAG_SCREEN_NUMBER) { send_packet(ssh, SSH1_CMSG_X11_REQUEST_FORWARDING, PKT_STR, ssh->x11disp->remoteauthprotoname, PKTT_PASSWORD, PKT_STR, ssh->x11disp->remoteauthdatastring, PKTT_OTHER, PKT_INT, ssh->x11disp->screennum, PKT_END); } else { send_packet(ssh, SSH1_CMSG_X11_REQUEST_FORWARDING, PKT_STR, ssh->x11disp->remoteauthprotoname, PKTT_PASSWORD, PKT_STR, ssh->x11disp->remoteauthdatastring, PKTT_OTHER, PKT_END); } do { crReturnV; } while (!pktin); if (pktin->type != SSH1_SMSG_SUCCESS && pktin->type != SSH1_SMSG_FAILURE) { bombout(("Protocol confusion")); crStopV; } else if (pktin->type == SSH1_SMSG_FAILURE) { logevent("X11 forwarding refused"); } else { logevent("X11 forwarding enabled"); ssh->X11_fwd_enabled = TRUE; ssh->packet_dispatch[SSH1_SMSG_X11_OPEN] = ssh1_smsg_x11_open; } } ssh_setup_portfwd(ssh, &ssh->cfg); ssh->packet_dispatch[SSH1_MSG_PORT_OPEN] = ssh1_msg_port_open; if (!ssh->cfg.nopty) { struct Packet *pkt; /* Unpick the terminal-speed string. */ /* XXX perhaps we should allow no speeds to be sent. */ ssh->ospeed = 38400; ssh->ispeed = 38400; /* last-resort defaults */ sscanf(ssh->cfg.termspeed, "%d,%d", &ssh->ospeed, &ssh->ispeed); /* Send the pty request. */ pkt = ssh1_pkt_init(SSH1_CMSG_REQUEST_PTY); ssh_pkt_addstring(pkt, ssh->cfg.termtype); ssh_pkt_adduint32(pkt, ssh->term_height); ssh_pkt_adduint32(pkt, ssh->term_width); ssh_pkt_adduint32(pkt, 0); /* width in pixels */ ssh_pkt_adduint32(pkt, 0); /* height in pixels */ parse_ttymodes(ssh, ssh->cfg.ttymodes, ssh1_send_ttymode, (void *)pkt); ssh_pkt_addbyte(pkt, SSH1_TTY_OP_ISPEED); ssh_pkt_adduint32(pkt, ssh->ispeed); ssh_pkt_addbyte(pkt, SSH1_TTY_OP_OSPEED); ssh_pkt_adduint32(pkt, ssh->ospeed); ssh_pkt_addbyte(pkt, SSH_TTY_OP_END); s_wrpkt(ssh, pkt); ssh->state = SSH_STATE_INTERMED; do { crReturnV; } while (!pktin); if (pktin->type != SSH1_SMSG_SUCCESS && pktin->type != SSH1_SMSG_FAILURE) { bombout(("Protocol confusion")); crStopV; } else if (pktin->type == SSH1_SMSG_FAILURE) { c_write_str(ssh, "Server refused to allocate pty\r\n"); ssh->editing = ssh->echoing = 1; } logeventf(ssh, "Allocated pty (ospeed %dbps, ispeed %dbps)", ssh->ospeed, ssh->ispeed); } else { ssh->editing = ssh->echoing = 1; } if (ssh->cfg.compression) { send_packet(ssh, SSH1_CMSG_REQUEST_COMPRESSION, PKT_INT, 6, PKT_END); do { crReturnV; } while (!pktin); if (pktin->type != SSH1_SMSG_SUCCESS && pktin->type != SSH1_SMSG_FAILURE) { bombout(("Protocol confusion")); |
︙ | ︙ | |||
5704 5705 5706 5707 5708 5709 5710 | * Start the shell or command. * * Special case: if the first-choice command is an SSH-2 * subsystem (hence not usable here) and the second choice * exists, we fall straight back to that. */ { | | | > | | | | 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 | * Start the shell or command. * * Special case: if the first-choice command is an SSH-2 * subsystem (hence not usable here) and the second choice * exists, we fall straight back to that. */ { char *cmd = ssh->cfg.remote_cmd_ptr; if (!cmd) cmd = ssh->cfg.remote_cmd; if (ssh->cfg.ssh_subsys && ssh->cfg.remote_cmd_ptr2) { cmd = ssh->cfg.remote_cmd_ptr2; ssh->fallback_cmd = TRUE; } if (*cmd) send_packet(ssh, SSH1_CMSG_EXEC_CMD, PKT_STR, cmd, PKT_END); else send_packet(ssh, SSH1_CMSG_EXEC_SHELL, PKT_END); logevent("Started session"); |
︙ | ︙ | |||
5751 5752 5753 5754 5755 5756 5757 | bombout(("Strange packet received: type %d", pktin->type)); crStopV; } } else { while (inlen > 0) { int len = min(inlen, 512); send_packet(ssh, SSH1_CMSG_STDIN_DATA, | | | | 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 | bombout(("Strange packet received: type %d", pktin->type)); crStopV; } } else { while (inlen > 0) { int len = min(inlen, 512); send_packet(ssh, SSH1_CMSG_STDIN_DATA, PKT_INT, len, PKTT_DATA, PKT_DATA, in, len, PKTT_OTHER, PKT_END); in += len; inlen -= len; } } } crFinishV; |
︙ | ︙ | |||
5913 5914 5915 5916 5917 5918 5919 | h->bytes(s, keyspace, h->hlen); h->final(s, keyspace + h->hlen); } /* * Handle the SSH-2 transport layer. */ | | < | 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 | h->bytes(s, keyspace, h->hlen); h->final(s, keyspace + h->hlen); } /* * Handle the SSH-2 transport layer. */ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, struct Packet *pktin) { unsigned char *in = (unsigned char *)vin; struct do_ssh2_transport_state { int nbits, pbits, warn_kex, warn_cscipher, warn_sccipher; Bignum p, g, e, f, K; void *our_kexinit; int our_kexinitlen; int kex_init_value, kex_reply_value; const struct ssh_mac **maclist; int nmacs; |
︙ | ︙ | |||
5952 5953 5954 5955 5956 5957 5958 | struct Packet *pktout; int dlgret; int guessok; int ignorepkt; }; crState(do_ssh2_transport_state); | < < | | | | 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 | struct Packet *pktout; int dlgret; int guessok; int ignorepkt; }; crState(do_ssh2_transport_state); crBegin(ssh->do_ssh2_transport_crstate); s->cscipher_tobe = s->sccipher_tobe = NULL; s->csmac_tobe = s->scmac_tobe = NULL; s->cscomp_tobe = s->sccomp_tobe = NULL; s->got_session_id = s->activated_authconn = FALSE; s->userauth_succeeded = FALSE; s->pending_compression = FALSE; /* * Be prepared to work around the buggy MAC problem. */ if (ssh->remote_bugs & BUG_SSH2_HMAC) s->maclist = buggymacs, s->nmacs = lenof(buggymacs); else s->maclist = macs, s->nmacs = lenof(macs); begin_key_exchange: ssh->pkt_kctx = SSH2_PKTCTX_NOKEX; { int i, j, commalist_started; /* * Set up the preferred key exchange. (NULL => warn below here) */ s->n_preferred_kex = 0; for (i = 0; i < KEX_MAX; i++) { switch (ssh->cfg.ssh_kexlist[i]) { case KEX_DHGEX: s->preferred_kex[s->n_preferred_kex++] = &ssh_diffiehellman_gex; break; case KEX_DHGROUP14: s->preferred_kex[s->n_preferred_kex++] = &ssh_diffiehellman_group14; |
︙ | ︙ | |||
6014 6015 6016 6017 6018 6019 6020 | } /* * Set up the preferred ciphers. (NULL => warn below here) */ s->n_preferred_ciphers = 0; for (i = 0; i < CIPHER_MAX; i++) { | | | | 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 | } /* * Set up the preferred ciphers. (NULL => warn below here) */ s->n_preferred_ciphers = 0; for (i = 0; i < CIPHER_MAX; i++) { switch (ssh->cfg.ssh_cipherlist[i]) { case CIPHER_BLOWFISH: s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_blowfish; break; case CIPHER_DES: if (ssh->cfg.ssh2_des_cbc) { s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_des; } break; case CIPHER_3DES: s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_3des; break; case CIPHER_AES: |
︙ | ︙ | |||
6045 6046 6047 6048 6049 6050 6051 | break; } } /* * Set up preferred compression. */ | | | 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 | break; } } /* * Set up preferred compression. */ if (ssh->cfg.compression) s->preferred_comp = &ssh_zlib; else s->preferred_comp = &ssh_comp_none; /* * Enable queueing of outgoing auth- or connection-layer * packets while we are in the middle of a key exchange. |
︙ | ︙ | |||
6081 6082 6083 6084 6085 6086 6087 | if (commalist_started) ssh2_pkt_addstring_str(s->pktout, ","); ssh2_pkt_addstring_str(s->pktout, k->list[j]->name); commalist_started = 1; } } /* List server host key algorithms. */ | < < < < < | | | | | | < < < < < < < < < < < | < | | | | | | | | | | | | > > > > > > > > > > > | > | < | | | | | | > > > > > > | 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 | if (commalist_started) ssh2_pkt_addstring_str(s->pktout, ","); ssh2_pkt_addstring_str(s->pktout, k->list[j]->name); commalist_started = 1; } } /* List server host key algorithms. */ ssh2_pkt_addstring_start(s->pktout); for (i = 0; i < lenof(hostkey_algs); i++) { ssh2_pkt_addstring_str(s->pktout, hostkey_algs[i]->name); if (i < lenof(hostkey_algs) - 1) ssh2_pkt_addstring_str(s->pktout, ","); } /* List client->server encryption algorithms. */ ssh2_pkt_addstring_start(s->pktout); commalist_started = 0; for (i = 0; i < s->n_preferred_ciphers; i++) { const struct ssh2_ciphers *c = s->preferred_ciphers[i]; if (!c) continue; /* warning flag */ for (j = 0; j < c->nciphers; j++) { if (commalist_started) ssh2_pkt_addstring_str(s->pktout, ","); ssh2_pkt_addstring_str(s->pktout, c->list[j]->name); commalist_started = 1; } } /* List server->client encryption algorithms. */ ssh2_pkt_addstring_start(s->pktout); commalist_started = 0; for (i = 0; i < s->n_preferred_ciphers; i++) { const struct ssh2_ciphers *c = s->preferred_ciphers[i]; if (!c) continue; /* warning flag */ for (j = 0; j < c->nciphers; j++) { if (commalist_started) ssh2_pkt_addstring_str(s->pktout, ","); ssh2_pkt_addstring_str(s->pktout, c->list[j]->name); commalist_started = 1; } } /* List client->server MAC algorithms. */ ssh2_pkt_addstring_start(s->pktout); for (i = 0; i < s->nmacs; i++) { ssh2_pkt_addstring_str(s->pktout, s->maclist[i]->name); if (i < s->nmacs - 1) ssh2_pkt_addstring_str(s->pktout, ","); } /* List server->client MAC algorithms. */ ssh2_pkt_addstring_start(s->pktout); for (i = 0; i < s->nmacs; i++) { ssh2_pkt_addstring_str(s->pktout, s->maclist[i]->name); if (i < s->nmacs - 1) ssh2_pkt_addstring_str(s->pktout, ","); } /* List client->server compression algorithms, * then server->client compression algorithms. (We use the * same set twice.) */ for (j = 0; j < 2; j++) { ssh2_pkt_addstring_start(s->pktout); assert(lenof(compressions) > 1); |
︙ | ︙ | |||
6172 6173 6174 6175 6176 6177 6178 | s->our_kexinitlen = s->pktout->length - 5; s->our_kexinit = snewn(s->our_kexinitlen, unsigned char); memcpy(s->our_kexinit, s->pktout->data + 5, s->our_kexinitlen); ssh2_pkt_send_noqueue(ssh, s->pktout); if (!pktin) | | | | 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 | s->our_kexinitlen = s->pktout->length - 5; s->our_kexinit = snewn(s->our_kexinitlen, unsigned char); memcpy(s->our_kexinit, s->pktout->data + 5, s->our_kexinitlen); ssh2_pkt_send_noqueue(ssh, s->pktout); if (!pktin) crWaitUntil(pktin); /* * Now examine the other side's KEXINIT to see what we're up * to. */ { char *str, *preferred; int i, j, len; if (pktin->type != SSH2_MSG_KEXINIT) { bombout(("expected key exchange packet from server")); crStop(0); } ssh->kex = NULL; ssh->hostkey = NULL; s->cscipher_tobe = NULL; s->sccipher_tobe = NULL; s->csmac_tobe = NULL; s->scmac_tobe = NULL; |
︙ | ︙ | |||
6219 6220 6221 6222 6223 6224 6225 | } if (ssh->kex) break; } if (!ssh->kex) { bombout(("Couldn't agree a key exchange algorithm (available: %s)", str ? str : "(null)")); | | < < < < < < | 5710 5711 5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 | } if (ssh->kex) break; } if (!ssh->kex) { bombout(("Couldn't agree a key exchange algorithm (available: %s)", str ? str : "(null)")); crStop(0); } /* * Note that the server's guess is considered wrong if it doesn't match * the first algorithm in our list, even if it's still the algorithm * we end up using. */ s->guessok = first_in_commasep_string(preferred, str, len); ssh_pkt_getstring(pktin, &str, &len); /* host key algorithms */ for (i = 0; i < lenof(hostkey_algs); i++) { if (in_commasep_string(hostkey_algs[i]->name, str, len)) { ssh->hostkey = hostkey_algs[i]; break; } } s->guessok = s->guessok && first_in_commasep_string(hostkey_algs[0]->name, str, len); ssh_pkt_getstring(pktin, &str, &len); /* client->server cipher */ for (i = 0; i < s->n_preferred_ciphers; i++) { const struct ssh2_ciphers *c = s->preferred_ciphers[i]; if (!c) { s->warn_cscipher = TRUE; |
︙ | ︙ | |||
6261 6262 6263 6264 6265 6266 6267 | } if (s->cscipher_tobe) break; } if (!s->cscipher_tobe) { bombout(("Couldn't agree a client-to-server cipher (available: %s)", str ? str : "(null)")); | | | 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 | } if (s->cscipher_tobe) break; } if (!s->cscipher_tobe) { bombout(("Couldn't agree a client-to-server cipher (available: %s)", str ? str : "(null)")); crStop(0); } ssh_pkt_getstring(pktin, &str, &len); /* server->client cipher */ for (i = 0; i < s->n_preferred_ciphers; i++) { const struct ssh2_ciphers *c = s->preferred_ciphers[i]; if (!c) { s->warn_sccipher = TRUE; |
︙ | ︙ | |||
6283 6284 6285 6286 6287 6288 6289 | } if (s->sccipher_tobe) break; } if (!s->sccipher_tobe) { bombout(("Couldn't agree a server-to-client cipher (available: %s)", str ? str : "(null)")); | | | 5768 5769 5770 5771 5772 5773 5774 5775 5776 5777 5778 5779 5780 5781 5782 | } if (s->sccipher_tobe) break; } if (!s->sccipher_tobe) { bombout(("Couldn't agree a server-to-client cipher (available: %s)", str ? str : "(null)")); crStop(0); } ssh_pkt_getstring(pktin, &str, &len); /* client->server mac */ for (i = 0; i < s->nmacs; i++) { if (in_commasep_string(s->maclist[i]->name, str, len)) { s->csmac_tobe = s->maclist[i]; break; |
︙ | ︙ | |||
6340 6341 6342 6343 6344 6345 6346 | logevent("Server supports delayed compression; " "will try this later"); } ssh_pkt_getstring(pktin, &str, &len); /* client->server language */ ssh_pkt_getstring(pktin, &str, &len); /* server->client language */ s->ignorepkt = ssh2_pkt_getbool(pktin) && !s->guessok; | < < < < < < < < < < | | | | | | | | | > > > > > > > > > > | | 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895 5896 5897 5898 5899 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 | logevent("Server supports delayed compression; " "will try this later"); } ssh_pkt_getstring(pktin, &str, &len); /* client->server language */ ssh_pkt_getstring(pktin, &str, &len); /* server->client language */ s->ignorepkt = ssh2_pkt_getbool(pktin) && !s->guessok; if (s->warn_kex) { ssh_set_frozen(ssh, 1); s->dlgret = askalg(ssh->frontend, "key-exchange algorithm", ssh->kex->name, ssh_dialog_callback, ssh); if (s->dlgret < 0) { do { crReturn(0); if (pktin) { bombout(("Unexpected data from server while" " waiting for user response")); crStop(0); } } while (pktin || inlen > 0); s->dlgret = ssh->user_response; } ssh_set_frozen(ssh, 0); if (s->dlgret == 0) { ssh_disconnect(ssh, "User aborted at kex warning", NULL, 0, TRUE); crStop(0); } } if (s->warn_cscipher) { ssh_set_frozen(ssh, 1); s->dlgret = askalg(ssh->frontend, "client-to-server cipher", s->cscipher_tobe->name, ssh_dialog_callback, ssh); if (s->dlgret < 0) { do { crReturn(0); if (pktin) { bombout(("Unexpected data from server while" " waiting for user response")); crStop(0); } } while (pktin || inlen > 0); s->dlgret = ssh->user_response; } ssh_set_frozen(ssh, 0); if (s->dlgret == 0) { ssh_disconnect(ssh, "User aborted at cipher warning", NULL, 0, TRUE); crStop(0); } } if (s->warn_sccipher) { ssh_set_frozen(ssh, 1); s->dlgret = askalg(ssh->frontend, "server-to-client cipher", s->sccipher_tobe->name, ssh_dialog_callback, ssh); if (s->dlgret < 0) { do { crReturn(0); if (pktin) { bombout(("Unexpected data from server while" " waiting for user response")); crStop(0); } } while (pktin || inlen > 0); s->dlgret = ssh->user_response; } ssh_set_frozen(ssh, 0); if (s->dlgret == 0) { ssh_disconnect(ssh, "User aborted at cipher warning", NULL, 0, TRUE); crStop(0); } } ssh->exhash = ssh->kex->hash->init(); hash_string(ssh->kex->hash, ssh->exhash, ssh->v_c, strlen(ssh->v_c)); hash_string(ssh->kex->hash, ssh->exhash, ssh->v_s, strlen(ssh->v_s)); hash_string(ssh->kex->hash, ssh->exhash, s->our_kexinit, s->our_kexinitlen); sfree(s->our_kexinit); if (pktin->length > 5) hash_string(ssh->kex->hash, ssh->exhash, pktin->data + 5, pktin->length - 5); if (s->ignorepkt) /* first_kex_packet_follows */ crWaitUntil(pktin); /* Ignore packet */ } if (ssh->kex->main_type == KEXTYPE_DH) { /* * Work out the number of bits of key we will need from the * key exchange. We start with the maximum key length of * either cipher... |
︙ | ︙ | |||
6462 6463 6464 6465 6466 6467 6468 | * much data. */ s->pbits = 512 << ((s->nbits - 1) / 64); s->pktout = ssh2_pkt_init(SSH2_MSG_KEX_DH_GEX_REQUEST); ssh2_pkt_adduint32(s->pktout, s->pbits); ssh2_pkt_send_noqueue(ssh, s->pktout); | | | | | 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 | * much data. */ s->pbits = 512 << ((s->nbits - 1) / 64); s->pktout = ssh2_pkt_init(SSH2_MSG_KEX_DH_GEX_REQUEST); ssh2_pkt_adduint32(s->pktout, s->pbits); ssh2_pkt_send_noqueue(ssh, s->pktout); crWaitUntil(pktin); if (pktin->type != SSH2_MSG_KEX_DH_GEX_GROUP) { bombout(("expected key exchange group packet from server")); crStop(0); } s->p = ssh2_pkt_getmp(pktin); s->g = ssh2_pkt_getmp(pktin); if (!s->p || !s->g) { bombout(("unable to read mp-ints from incoming group packet")); crStop(0); } ssh->kex_ctx = dh_setup_gex(s->p, s->g); s->kex_init_value = SSH2_MSG_KEX_DH_GEX_INIT; s->kex_reply_value = SSH2_MSG_KEX_DH_GEX_REPLY; } else { ssh->pkt_kctx = SSH2_PKTCTX_DHGROUP; ssh->kex_ctx = dh_setup_group(ssh->kex); |
︙ | ︙ | |||
6497 6498 6499 6500 6501 6502 6503 | set_busy_status(ssh->frontend, BUSY_CPU); /* this can take a while */ s->e = dh_create_e(ssh->kex_ctx, s->nbits * 2); s->pktout = ssh2_pkt_init(s->kex_init_value); ssh2_pkt_addmp(s->pktout, s->e); ssh2_pkt_send_noqueue(ssh, s->pktout); set_busy_status(ssh->frontend, BUSY_WAITING); /* wait for server */ | | | | | 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 5996 5997 5998 5999 6000 6001 6002 6003 6004 6005 6006 6007 | set_busy_status(ssh->frontend, BUSY_CPU); /* this can take a while */ s->e = dh_create_e(ssh->kex_ctx, s->nbits * 2); s->pktout = ssh2_pkt_init(s->kex_init_value); ssh2_pkt_addmp(s->pktout, s->e); ssh2_pkt_send_noqueue(ssh, s->pktout); set_busy_status(ssh->frontend, BUSY_WAITING); /* wait for server */ crWaitUntil(pktin); if (pktin->type != s->kex_reply_value) { bombout(("expected key exchange reply packet from server")); crStop(0); } set_busy_status(ssh->frontend, BUSY_CPU); /* cogitate */ ssh_pkt_getstring(pktin, &s->hostkeydata, &s->hostkeylen); s->hkey = ssh->hostkey->newkey(s->hostkeydata, s->hostkeylen); s->f = ssh2_pkt_getmp(pktin); if (!s->f) { bombout(("unable to parse key exchange reply packet")); crStop(0); } ssh_pkt_getstring(pktin, &s->sigdata, &s->siglen); s->K = dh_find_K(ssh->kex_ctx, s->f); /* We assume everything from now on will be quick, and it might * involve user interaction. */ |
︙ | ︙ | |||
6541 6542 6543 6544 6545 6546 6547 | logeventf(ssh, "Doing RSA key exchange with hash %s", ssh->kex->hash->text_name); ssh->pkt_kctx = SSH2_PKTCTX_RSAKEX; /* * RSA key exchange. First expect a KEXRSA_PUBKEY packet * from the server. */ | | | | | 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 6043 6044 6045 6046 6047 6048 6049 6050 6051 6052 6053 6054 6055 6056 6057 6058 6059 6060 6061 6062 | logeventf(ssh, "Doing RSA key exchange with hash %s", ssh->kex->hash->text_name); ssh->pkt_kctx = SSH2_PKTCTX_RSAKEX; /* * RSA key exchange. First expect a KEXRSA_PUBKEY packet * from the server. */ crWaitUntil(pktin); if (pktin->type != SSH2_MSG_KEXRSA_PUBKEY) { bombout(("expected RSA public key packet from server")); crStop(0); } ssh_pkt_getstring(pktin, &s->hostkeydata, &s->hostkeylen); hash_string(ssh->kex->hash, ssh->exhash, s->hostkeydata, s->hostkeylen); s->hkey = ssh->hostkey->newkey(s->hostkeydata, s->hostkeylen); { char *keydata; ssh_pkt_getstring(pktin, &keydata, &s->rsakeylen); s->rsakeydata = snewn(s->rsakeylen, char); memcpy(s->rsakeydata, keydata, s->rsakeylen); } s->rsakey = ssh_rsakex_newkey(s->rsakeydata, s->rsakeylen); if (!s->rsakey) { sfree(s->rsakeydata); bombout(("unable to parse RSA public key from server")); crStop(0); } hash_string(ssh->kex->hash, ssh->exhash, s->rsakeydata, s->rsakeylen); /* * Next, set up a shared secret K, of precisely KLEN - * 2*HLEN - 49 bits, where KLEN is the bit length of the |
︙ | ︙ | |||
6623 6624 6625 6626 6627 6628 6629 | sfree(kstr2); sfree(kstr1); sfree(outstr); } ssh_rsakex_freekey(s->rsakey); | | | | 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 | sfree(kstr2); sfree(kstr1); sfree(outstr); } ssh_rsakex_freekey(s->rsakey); crWaitUntil(pktin); if (pktin->type != SSH2_MSG_KEXRSA_DONE) { sfree(s->rsakeydata); bombout(("expected signature packet from server")); crStop(0); } ssh_pkt_getstring(pktin, &s->sigdata, &s->siglen); sfree(s->rsakeydata); } |
︙ | ︙ | |||
6651 6652 6653 6654 6655 6656 6657 | #endif if (!s->hkey || !ssh->hostkey->verifysig(s->hkey, s->sigdata, s->siglen, (char *)s->exchange_hash, ssh->kex->hash->hlen)) { bombout(("Server's host key did not match the signature supplied")); | | > > > > < < < < < | | | | | | | | | | | | | | | | | | | | | | | | > | | < < < < < < < < < < < < < < < < | > | < | 6136 6137 6138 6139 6140 6141 6142 6143 6144 6145 6146 6147 6148 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158 6159 6160 6161 6162 6163 6164 6165 6166 6167 6168 6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185 6186 6187 | #endif if (!s->hkey || !ssh->hostkey->verifysig(s->hkey, s->sigdata, s->siglen, (char *)s->exchange_hash, ssh->kex->hash->hlen)) { bombout(("Server's host key did not match the signature supplied")); crStop(0); } /* * Authenticate remote host: verify host key. (We've already * checked the signature of the exchange hash.) */ s->keystr = ssh->hostkey->fmtkey(s->hkey); s->fingerprint = ssh->hostkey->fingerprint(s->hkey); ssh_set_frozen(ssh, 1); s->dlgret = verify_ssh_host_key(ssh->frontend, ssh->savedhost, ssh->savedport, ssh->hostkey->keytype, s->keystr, s->fingerprint, ssh_dialog_callback, ssh); if (s->dlgret < 0) { do { crReturn(0); if (pktin) { bombout(("Unexpected data from server while waiting" " for user host key response")); crStop(0); } } while (pktin || inlen > 0); s->dlgret = ssh->user_response; } ssh_set_frozen(ssh, 0); if (s->dlgret == 0) { ssh_disconnect(ssh, "User aborted at host key verification", NULL, 0, TRUE); crStop(0); } if (!s->got_session_id) { /* don't bother logging this in rekeys */ logevent("Host key fingerprint is:"); logevent(s->fingerprint); } sfree(s->fingerprint); sfree(s->keystr); ssh->hostkey->freekey(s->hkey); /* * The exchange hash from the very first key exchange is also * the session id, used in session key construction and * authentication. */ |
︙ | ︙ | |||
6766 6767 6768 6769 6770 6771 6772 | assert(ssh->cscipher->blksize <= ssh->kex->hash->hlen * SSH2_MKKEY_ITERS); ssh->cscipher->setiv(ssh->cs_cipher_ctx, keyspace); ssh2_mkkey(ssh,s->K,s->exchange_hash,'E',keyspace); assert(ssh->csmac->len <= ssh->kex->hash->hlen * SSH2_MKKEY_ITERS); ssh->csmac->setkey(ssh->cs_mac_ctx, keyspace); | | | | | 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267 6268 6269 6270 6271 6272 6273 | assert(ssh->cscipher->blksize <= ssh->kex->hash->hlen * SSH2_MKKEY_ITERS); ssh->cscipher->setiv(ssh->cs_cipher_ctx, keyspace); ssh2_mkkey(ssh,s->K,s->exchange_hash,'E',keyspace); assert(ssh->csmac->len <= ssh->kex->hash->hlen * SSH2_MKKEY_ITERS); ssh->csmac->setkey(ssh->cs_mac_ctx, keyspace); memset(keyspace, 0, sizeof(keyspace)); } logeventf(ssh, "Initialised %.200s client->server encryption", ssh->cscipher->text_name); logeventf(ssh, "Initialised %.200s client->server MAC algorithm", ssh->csmac->text_name); if (ssh->cscomp->text_name) logeventf(ssh, "Initialised %s compression", ssh->cscomp->text_name); /* * Now our end of the key exchange is complete, we can send all * our queued higher-layer packets. */ ssh->queueing = FALSE; ssh2_pkt_queuesend(ssh); /* * Expect SSH2_MSG_NEWKEYS from server. */ crWaitUntil(pktin); if (pktin->type != SSH2_MSG_NEWKEYS) { bombout(("expected new-keys packet from server")); crStop(0); } ssh->incoming_data_size = 0; /* start counting from here */ /* * We've seen server NEWKEYS, so create and initialise * server-to-client session keys. */ |
︙ | ︙ | |||
6832 6833 6834 6835 6836 6837 6838 | assert(ssh->sccipher->blksize <= ssh->kex->hash->hlen * SSH2_MKKEY_ITERS); ssh->sccipher->setiv(ssh->sc_cipher_ctx, keyspace); ssh2_mkkey(ssh,s->K,s->exchange_hash,'F',keyspace); assert(ssh->scmac->len <= ssh->kex->hash->hlen * SSH2_MKKEY_ITERS); ssh->scmac->setkey(ssh->sc_mac_ctx, keyspace); | | | 6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 | assert(ssh->sccipher->blksize <= ssh->kex->hash->hlen * SSH2_MKKEY_ITERS); ssh->sccipher->setiv(ssh->sc_cipher_ctx, keyspace); ssh2_mkkey(ssh,s->K,s->exchange_hash,'F',keyspace); assert(ssh->scmac->len <= ssh->kex->hash->hlen * SSH2_MKKEY_ITERS); ssh->scmac->setkey(ssh->sc_mac_ctx, keyspace); memset(keyspace, 0, sizeof(keyspace)); } logeventf(ssh, "Initialised %.200s server->client encryption", ssh->sccipher->text_name); logeventf(ssh, "Initialised %.200s server->client MAC algorithm", ssh->scmac->text_name); if (ssh->sccomp->text_name) logeventf(ssh, "Initialised %s decompression", |
︙ | ︙ | |||
6863 6864 6865 6866 6867 6868 6869 | } /* * Otherwise, schedule a timer for our next rekey. */ ssh->kex_in_progress = FALSE; ssh->last_rekey = GETTICKCOUNT(); | | | > > > > > > > > > > > > > < < < < < < < | | 6332 6333 6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362 6363 6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 | } /* * Otherwise, schedule a timer for our next rekey. */ ssh->kex_in_progress = FALSE; ssh->last_rekey = GETTICKCOUNT(); if (ssh->cfg.ssh_rekey_time != 0) ssh->next_rekey = schedule_timer(ssh->cfg.ssh_rekey_time*60*TICKSPERSEC, ssh2_timer, ssh); /* * If this is the first key exchange phase, we must pass the * SSH2_MSG_NEWKEYS packet to the next layer, not because it * wants to see it but because it will need time to initialise * itself before it sees an actual packet. In subsequent key * exchange phases, we don't pass SSH2_MSG_NEWKEYS on, because * it would only confuse the layer above. */ if (s->activated_authconn) { crReturn(0); } s->activated_authconn = TRUE; /* * Now we're encrypting. Begin returning 1 to the protocol main * function so that other things can run on top of the * transport. If we ever see a KEXINIT, we must go back to the * start. * * We _also_ go back to the start if we see pktin==NULL and * inlen negative, because this is a special signal meaning * `initiate client-driven rekey', and `in' contains a message * giving the reason for the rekey. * * inlen==-1 means always initiate a rekey; * inlen==-2 means that userauth has completed successfully and * we should consider rekeying (for delayed compression). */ while (!((pktin && pktin->type == SSH2_MSG_KEXINIT) || (!pktin && inlen < 0))) { wait_for_rekey: crReturn(1); } if (pktin) { logevent("Server initiated key re-exchange"); } else { if (inlen == -2) { /* * authconn has seen a USERAUTH_SUCCEEDED. Time to enable |
︙ | ︙ | |||
6939 6940 6941 6942 6943 6944 6945 | if ((ssh->remote_bugs & BUG_SSH2_REKEY)) { logeventf(ssh, "Server bug prevents key re-exchange (%s)", (char *)in); /* Reset the counters, so that at least this message doesn't * hit the event log _too_ often. */ ssh->outgoing_data_size = 0; ssh->incoming_data_size = 0; | | | | < > > | < < < < < < < < < | | | | | < < < < < < < | > > > > > | | > > | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | < | < < < < < < < < > | > > > > > | | | | | > > > > > > > > > > > > > | 6414 6415 6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455 6456 6457 6458 6459 6460 6461 6462 6463 6464 6465 6466 6467 6468 6469 6470 6471 6472 6473 6474 6475 6476 6477 6478 6479 6480 6481 6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500 6501 6502 6503 6504 6505 6506 6507 6508 6509 6510 6511 6512 6513 6514 6515 6516 6517 6518 6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533 6534 6535 6536 6537 6538 6539 6540 6541 6542 6543 6544 6545 6546 6547 6548 6549 6550 6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 6569 6570 6571 6572 6573 6574 6575 6576 6577 6578 6579 6580 6581 6582 6583 6584 6585 6586 6587 6588 6589 6590 6591 6592 6593 6594 6595 6596 6597 6598 6599 6600 6601 6602 6603 6604 6605 6606 6607 6608 6609 6610 6611 6612 | if ((ssh->remote_bugs & BUG_SSH2_REKEY)) { logeventf(ssh, "Server bug prevents key re-exchange (%s)", (char *)in); /* Reset the counters, so that at least this message doesn't * hit the event log _too_ often. */ ssh->outgoing_data_size = 0; ssh->incoming_data_size = 0; if (ssh->cfg.ssh_rekey_time != 0) { ssh->next_rekey = schedule_timer(ssh->cfg.ssh_rekey_time*60*TICKSPERSEC, ssh2_timer, ssh); } goto wait_for_rekey; /* this is still utterly horrid */ } else { logeventf(ssh, "Initiating key re-exchange (%s)", (char *)in); } } goto begin_key_exchange; crFinish(1); } /* * Add data to an SSH-2 channel output buffer. */ static void ssh2_add_channel_data(struct ssh_channel *c, char *buf, int len) { bufchain_add(&c->v.v2.outbuffer, buf, len); } /* * Attempt to send data on an SSH-2 channel. */ static int ssh2_try_send(struct ssh_channel *c) { Ssh ssh = c->ssh; struct Packet *pktout; while (c->v.v2.remwindow > 0 && bufchain_size(&c->v.v2.outbuffer) > 0) { int len; void *data; bufchain_prefix(&c->v.v2.outbuffer, &data, &len); if ((unsigned)len > c->v.v2.remwindow) len = c->v.v2.remwindow; if ((unsigned)len > c->v.v2.remmaxpkt) len = c->v.v2.remmaxpkt; pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_DATA); ssh2_pkt_adduint32(pktout, c->remoteid); ssh2_pkt_addstring_start(pktout); dont_log_data(ssh, pktout, PKTLOG_OMIT); ssh2_pkt_addstring_data(pktout, data, len); end_log_omission(ssh, pktout); ssh2_pkt_send(ssh, pktout); bufchain_consume(&c->v.v2.outbuffer, len); c->v.v2.remwindow -= len; } /* * After having sent as much data as we can, return the amount * still buffered. */ return bufchain_size(&c->v.v2.outbuffer); } static void ssh2_try_send_and_unthrottle(Ssh ssh, struct ssh_channel *c) { int bufsize; if (c->closes) return; /* don't send on closing channels */ bufsize = ssh2_try_send(c); if (bufsize == 0) { switch (c->type) { case CHAN_MAINSESSION: /* stdin need not receive an unthrottle * notification since it will be polled */ break; case CHAN_X11: x11_unthrottle(c->u.x11.s); break; case CHAN_AGENT: /* agent sockets are request/response and need no * buffer management */ break; case CHAN_SOCKDATA: pfd_unthrottle(c->u.pfd.s); break; } } /* * If we've emptied the channel's output buffer and there's a * pending close event, start the channel-closing procedure. */ if (c->pending_close && bufchain_size(&c->v.v2.outbuffer) == 0) { struct Packet *pktout; pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_CLOSE); ssh2_pkt_adduint32(pktout, c->remoteid); ssh2_pkt_send(ssh, pktout); c->closes = 1; c->pending_close = FALSE; } } /* * Set up most of a new ssh_channel for SSH-2. */ static void ssh2_channel_init(struct ssh_channel *c) { Ssh ssh = c->ssh; c->localid = alloc_channel_id(ssh); c->closes = 0; c->pending_close = FALSE; c->throttling_conn = FALSE; c->v.v2.locwindow = c->v.v2.locmaxwin = c->v.v2.remlocwin = ssh->cfg.ssh_simple ? OUR_V2_BIGWIN : OUR_V2_WINSIZE; c->v.v2.winadj_head = c->v.v2.winadj_tail = NULL; c->v.v2.throttle_state = UNTHROTTLED; bufchain_init(&c->v.v2.outbuffer); } /* * Potentially enlarge the window on an SSH-2 channel. */ static void ssh2_set_window(struct ssh_channel *c, int newwin) { Ssh ssh = c->ssh; /* * Never send WINDOW_ADJUST for a channel that the remote side * already thinks it's closed; there's no point, since it won't * be sending any more data anyway. */ if (c->closes != 0) return; /* * If the remote end has a habit of ignoring maxpkt, limit the * window so that it has no choice (assuming it doesn't ignore the * window as well). */ if ((ssh->remote_bugs & BUG_SSH2_MAXPKT) && newwin > OUR_V2_MAXPKT) newwin = OUR_V2_MAXPKT; /* * Only send a WINDOW_ADJUST if there's significantly more window * available than the other end thinks there is. This saves us * sending a WINDOW_ADJUST for every character in a shell session. * * "Significant" is arbitrarily defined as half the window size. */ if (newwin / 2 >= c->v.v2.locwindow) { struct Packet *pktout; struct winadj *wa; /* * In order to keep track of how much window the client * actually has available, we'd like it to acknowledge each * WINDOW_ADJUST. We can't do that directly, so we accompany * it with a CHANNEL_REQUEST that has to be acknowledged. * * This is only necessary if we're opening the window wide. * If we're not, then throughput is being constrained by * something other than the maximum window size anyway. * * We also only send this if the main channel has finished its * initial CHANNEL_REQUESTs and installed the default * CHANNEL_FAILURE handler, so as not to risk giving it * unexpected CHANNEL_FAILUREs. */ if (newwin == c->v.v2.locmaxwin && ssh->packet_dispatch[SSH2_MSG_CHANNEL_FAILURE]) { pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST); ssh2_pkt_adduint32(pktout, c->remoteid); ssh2_pkt_addstring(pktout, "winadj@putty.projects.tartarus.org"); ssh2_pkt_addbool(pktout, TRUE); ssh2_pkt_send(ssh, pktout); /* * CHANNEL_FAILURE doesn't come with any indication of * what message caused it, so we have to keep track of the * outstanding CHANNEL_REQUESTs ourselves. */ wa = snew(struct winadj); wa->size = newwin - c->v.v2.locwindow; wa->next = NULL; if (!c->v.v2.winadj_head) c->v.v2.winadj_head = wa; else c->v.v2.winadj_tail->next = wa; c->v.v2.winadj_tail = wa; if (c->v.v2.throttle_state != UNTHROTTLED) c->v.v2.throttle_state = UNTHROTTLING; } else { /* Pretend the WINDOW_ADJUST was acked immediately. */ c->v.v2.remlocwin = newwin; c->v.v2.throttle_state = THROTTLED; } |
︙ | ︙ | |||
7214 7215 7216 7217 7218 7219 7220 | static struct ssh_channel *ssh2_channel_msg(Ssh ssh, struct Packet *pktin) { unsigned localid = ssh_pkt_getuint32(pktin); struct ssh_channel *c; c = find234(ssh->channels, &localid, ssh_channelfind); if (!c || | < | | < | | < < | < < < < | | | > | > > > > > > > > > > > > | < > | < < < | > > > > | < < < < | | < < > > | | | > > | > > > > > > < < < < < | < < < < < | | | 6625 6626 6627 6628 6629 6630 6631 6632 6633 6634 6635 6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 6646 6647 6648 6649 6650 6651 6652 6653 6654 6655 6656 6657 6658 6659 6660 6661 6662 6663 6664 6665 6666 6667 6668 6669 6670 6671 6672 6673 6674 6675 6676 6677 6678 6679 6680 6681 6682 6683 6684 6685 6686 6687 6688 6689 6690 6691 6692 6693 6694 6695 6696 6697 6698 6699 6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714 6715 6716 6717 6718 6719 6720 6721 6722 6723 6724 6725 6726 6727 6728 6729 6730 6731 6732 6733 6734 6735 6736 6737 6738 6739 6740 6741 6742 6743 6744 6745 6746 6747 6748 6749 6750 6751 6752 6753 | static struct ssh_channel *ssh2_channel_msg(Ssh ssh, struct Packet *pktin) { unsigned localid = ssh_pkt_getuint32(pktin); struct ssh_channel *c; c = find234(ssh->channels, &localid, ssh_channelfind); if (!c || (c->halfopen && pktin->type != SSH2_MSG_CHANNEL_OPEN_CONFIRMATION && pktin->type != SSH2_MSG_CHANNEL_OPEN_FAILURE)) { char *buf = dupprintf("Received %s for %s channel %u", ssh2_pkt_type(ssh->pkt_kctx, ssh->pkt_actx, pktin->type), c ? "half-open" : "nonexistent", localid); ssh_disconnect(ssh, NULL, buf, SSH2_DISCONNECT_PROTOCOL_ERROR, FALSE); sfree(buf); return NULL; } return c; } static int ssh2_handle_winadj_response(struct ssh_channel *c) { struct winadj *wa = c->v.v2.winadj_head; if (!wa) return FALSE; c->v.v2.winadj_head = wa->next; c->v.v2.remlocwin += wa->size; sfree(wa); /* * winadj messages are only sent when the window is fully open, so * if we get an ack of one, we know any pending unthrottle is * complete. */ if (c->v.v2.throttle_state == UNTHROTTLING) c->v.v2.throttle_state = UNTHROTTLED; return TRUE; } static void ssh2_msg_channel_success(Ssh ssh, struct Packet *pktin) { /* * This should never get called. All channel requests are either * sent with want_reply false, are sent before this handler gets * installed, or are "winadj@putty" requests, which servers should * never respond to with success. * * However, at least one server ("boks_sshd") is known to return * SUCCESS for channel requests it's never heard of, such as * "winadj@putty". Raised with foxt.com as bug 090916-090424, but * for the sake of a quiet life, we handle it just the same as the * expected FAILURE. */ struct ssh_channel *c; c = ssh2_channel_msg(ssh, pktin); if (!c) return; if (!ssh2_handle_winadj_response(c)) ssh_disconnect(ssh, NULL, "Received unsolicited SSH_MSG_CHANNEL_SUCCESS", SSH2_DISCONNECT_PROTOCOL_ERROR, FALSE); } static void ssh2_msg_channel_failure(Ssh ssh, struct Packet *pktin) { /* * The only time this should get called is for "winadj@putty" * messages sent above. All other channel requests are either * sent with want_reply false or are sent before this handler gets * installed. */ struct ssh_channel *c; c = ssh2_channel_msg(ssh, pktin); if (!c) return; if (!ssh2_handle_winadj_response(c)) ssh_disconnect(ssh, NULL, "Received unsolicited SSH_MSG_CHANNEL_FAILURE", SSH2_DISCONNECT_PROTOCOL_ERROR, FALSE); } static void ssh2_msg_channel_window_adjust(Ssh ssh, struct Packet *pktin) { struct ssh_channel *c; c = ssh2_channel_msg(ssh, pktin); if (!c) return; if (!c->closes) { c->v.v2.remwindow += ssh_pkt_getuint32(pktin); ssh2_try_send_and_unthrottle(ssh, c); } } static void ssh2_msg_channel_data(Ssh ssh, struct Packet *pktin) { char *data; int length; struct ssh_channel *c; c = ssh2_channel_msg(ssh, pktin); if (!c) return; if (pktin->type == SSH2_MSG_CHANNEL_EXTENDED_DATA && ssh_pkt_getuint32(pktin) != SSH2_EXTENDED_DATA_STDERR) return; /* extended but not stderr */ ssh_pkt_getstring(pktin, &data, &length); if (data) { int bufsize = 0; c->v.v2.locwindow -= length; c->v.v2.remlocwin -= length; switch (c->type) { case CHAN_MAINSESSION: bufsize = from_backend(ssh->frontend, pktin->type == SSH2_MSG_CHANNEL_EXTENDED_DATA, data, length); break; case CHAN_X11: bufsize = x11_send(c->u.x11.s, data, length); break; case CHAN_SOCKDATA: bufsize = pfd_send(c->u.pfd.s, data, length); break; case CHAN_AGENT: while (length > 0) { if (c->u.a.lensofar < 4) { unsigned int l = min(4 - c->u.a.lensofar, (unsigned)length); memcpy(c->u.a.msglen + c->u.a.lensofar, |
︙ | ︙ | |||
7361 7362 7363 7364 7365 7366 7367 | data += l; length -= l; c->u.a.lensofar += l; } if (c->u.a.lensofar == c->u.a.totallen) { void *reply; int replylen; | < < | 6772 6773 6774 6775 6776 6777 6778 6779 6780 6781 6782 6783 6784 6785 6786 6787 6788 6789 6790 6791 | data += l; length -= l; c->u.a.lensofar += l; } if (c->u.a.lensofar == c->u.a.totallen) { void *reply; int replylen; if (agent_query(c->u.a.message, c->u.a.totallen, &reply, &replylen, ssh_agentf_callback, c)) ssh_agentf_callback(c, reply, replylen); sfree(c->u.a.message); c->u.a.lensofar = 0; } } bufsize = 0; break; } /* |
︙ | ︙ | |||
7397 7398 7399 7400 7401 7402 7403 | ssh2_set_window(c, bufsize < c->v.v2.locmaxwin ? c->v.v2.locmaxwin - bufsize : 0); /* * If we're either buffering way too much data, or if we're * buffering anything at all and we're in "simple" mode, * throttle the whole channel. */ | | > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > | > > > > | < < > > > > > > > > < > < < < < < | < < < < < < < < < < < < < < < < < < | | | > | | > | > | > > > | > | > | | > > > > | < < < < | < < | > | > > | | < < | | > > > > > | > > > | < < | > | < < | < < > < < < | | | | < | < > | | | | < < < | < < < < < < < < | < < < < | < < | | < < < | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < | 6806 6807 6808 6809 6810 6811 6812 6813 6814 6815 6816 6817 6818 6819 6820 6821 6822 6823 6824 6825 6826 6827 6828 6829 6830 6831 6832 6833 6834 6835 6836 6837 6838 6839 6840 6841 6842 6843 6844 6845 6846 6847 6848 6849 6850 6851 6852 6853 6854 6855 6856 6857 6858 6859 6860 6861 6862 6863 6864 6865 6866 6867 6868 6869 6870 6871 6872 6873 6874 6875 6876 6877 6878 6879 6880 6881 6882 6883 6884 6885 6886 6887 6888 6889 6890 6891 6892 6893 6894 6895 6896 6897 6898 6899 6900 6901 6902 6903 6904 6905 6906 6907 6908 6909 6910 6911 6912 6913 6914 6915 6916 6917 6918 6919 6920 6921 6922 6923 6924 6925 6926 6927 6928 6929 6930 6931 6932 6933 6934 6935 6936 6937 6938 6939 6940 6941 6942 6943 6944 6945 6946 6947 6948 6949 6950 6951 6952 6953 6954 6955 6956 6957 6958 6959 6960 6961 6962 6963 6964 6965 6966 6967 6968 6969 6970 6971 6972 6973 6974 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984 | ssh2_set_window(c, bufsize < c->v.v2.locmaxwin ? c->v.v2.locmaxwin - bufsize : 0); /* * If we're either buffering way too much data, or if we're * buffering anything at all and we're in "simple" mode, * throttle the whole channel. */ if ((bufsize > c->v.v2.locmaxwin || (ssh->cfg.ssh_simple && bufsize > 0)) && !c->throttling_conn) { c->throttling_conn = 1; ssh_throttle_conn(ssh, +1); } } } static void ssh2_msg_channel_eof(Ssh ssh, struct Packet *pktin) { struct ssh_channel *c; c = ssh2_channel_msg(ssh, pktin); if (!c) return; if (c->type == CHAN_X11) { /* * Remote EOF on an X11 channel means we should * wrap up and close the channel ourselves. */ x11_close(c->u.x11.s); c->u.x11.s = NULL; sshfwd_close(c); } else if (c->type == CHAN_AGENT) { sshfwd_close(c); } else if (c->type == CHAN_SOCKDATA) { pfd_close(c->u.pfd.s); c->u.pfd.s = NULL; sshfwd_close(c); } } static void ssh2_msg_channel_close(Ssh ssh, struct Packet *pktin) { struct ssh_channel *c; struct Packet *pktout; c = ssh2_channel_msg(ssh, pktin); if (!c) return; /* Do pre-close processing on the channel. */ switch (c->type) { case CHAN_MAINSESSION: ssh->mainchan = NULL; update_specials_menu(ssh->frontend); break; case CHAN_X11: if (c->u.x11.s != NULL) x11_close(c->u.x11.s); sshfwd_close(c); break; case CHAN_AGENT: sshfwd_close(c); break; case CHAN_SOCKDATA: if (c->u.pfd.s != NULL) pfd_close(c->u.pfd.s); sshfwd_close(c); break; } if (c->closes == 0) { pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_CLOSE); ssh2_pkt_adduint32(pktout, c->remoteid); ssh2_pkt_send(ssh, pktout); } del234(ssh->channels, c); bufchain_clear(&c->v.v2.outbuffer); sfree(c); /* * See if that was the last channel left open. * (This is only our termination condition if we're * not running in -N mode.) */ if (!ssh->cfg.ssh_no_shell && count234(ssh->channels) == 0) { /* * We used to send SSH_MSG_DISCONNECT here, * because I'd believed that _every_ conforming * SSH-2 connection had to end with a disconnect * being sent by at least one side; apparently * I was wrong and it's perfectly OK to * unceremoniously slam the connection shut * when you're done, and indeed OpenSSH feels * this is more polite than sending a * DISCONNECT. So now we don't. */ ssh_disconnect(ssh, "All channels closed", NULL, 0, TRUE); } } static void ssh2_msg_channel_open_confirmation(Ssh ssh, struct Packet *pktin) { struct ssh_channel *c; struct Packet *pktout; c = ssh2_channel_msg(ssh, pktin); if (!c) return; if (c->type != CHAN_SOCKDATA_DORMANT) return; /* dunno why they're confirming this */ c->remoteid = ssh_pkt_getuint32(pktin); c->halfopen = FALSE; c->type = CHAN_SOCKDATA; c->v.v2.remwindow = ssh_pkt_getuint32(pktin); c->v.v2.remmaxpkt = ssh_pkt_getuint32(pktin); if (c->u.pfd.s) pfd_confirm(c->u.pfd.s); if (c->closes) { /* * We have a pending close on this channel, * which we decided on before the server acked * the channel open. So now we know the * remoteid, we can close it again. */ pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_CLOSE); ssh2_pkt_adduint32(pktout, c->remoteid); ssh2_pkt_send(ssh, pktout); } } static void ssh2_msg_channel_open_failure(Ssh ssh, struct Packet *pktin) { static const char *const reasons[] = { "<unknown reason code>", "Administratively prohibited", "Connect failed", "Unknown channel type", "Resource shortage", }; unsigned reason_code; char *reason_string; int reason_length; struct ssh_channel *c; c = ssh2_channel_msg(ssh, pktin); if (!c) return; if (c->type != CHAN_SOCKDATA_DORMANT) return; /* dunno why they're failing this */ reason_code = ssh_pkt_getuint32(pktin); if (reason_code >= lenof(reasons)) reason_code = 0; /* ensure reasons[reason_code] in range */ ssh_pkt_getstring(pktin, &reason_string, &reason_length); logeventf(ssh, "Forwarded connection refused by server: %s [%.*s]", reasons[reason_code], reason_length, reason_string); pfd_close(c->u.pfd.s); del234(ssh->channels, c); sfree(c); } static void ssh2_msg_channel_request(Ssh ssh, struct Packet *pktin) { char *type; int typelen, want_reply; int reply = SSH2_MSG_CHANNEL_FAILURE; /* default */ struct ssh_channel *c; struct Packet *pktout; c = ssh2_channel_msg(ssh, pktin); if (!c) return; ssh_pkt_getstring(pktin, &type, &typelen); want_reply = ssh2_pkt_getbool(pktin); /* * Having got the channel number, we now look at * the request type string to see if it's something * we recognise. |
︙ | ︙ | |||
7813 7814 7815 7816 7817 7818 7819 | long len = pktin->length - pktin->savedpos; unsigned long num = GET_32BIT(p); /* what is it? */ /* If it's 0, it hardly matters; assume string */ if (num == 0) { is_int = FALSE; } else { int maybe_int = FALSE, maybe_str = FALSE; | | | < | | | | | < | < > | | 7014 7015 7016 7017 7018 7019 7020 7021 7022 7023 7024 7025 7026 7027 7028 7029 7030 7031 7032 7033 7034 7035 7036 7037 | long len = pktin->length - pktin->savedpos; unsigned long num = GET_32BIT(p); /* what is it? */ /* If it's 0, it hardly matters; assume string */ if (num == 0) { is_int = FALSE; } else { int maybe_int = FALSE, maybe_str = FALSE; #define CHECK_HYPOTHESIS(offset, result) \ do { \ long q = offset; \ if (q >= 0 && q+4 <= len) { \ q = q + 4 + GET_32BIT(p+q); \ if (q >= 0 && q+4 <= len && \ ((q = q + 4 + GET_32BIT(p+q))!= 0) && q == len) \ result = TRUE; \ } \ } while(0) CHECK_HYPOTHESIS(4+1, maybe_int); CHECK_HYPOTHESIS(4+num+1, maybe_str); #undef CHECK_HYPOTHESIS if (maybe_int && !maybe_str) is_int = TRUE; else if (!maybe_int && maybe_str) is_int = FALSE; |
︙ | ︙ | |||
7962 7963 7964 7965 7966 7967 7968 | */ if (want_reply) { pktout = ssh2_pkt_init(SSH2_MSG_REQUEST_FAILURE); ssh2_pkt_send(ssh, pktout); } } | < < < < < < < < < < < < < < < < < < < < < < < < < > | < | | < < | < < < < < | < < < < | | > | | | < | | < < | | | < < < < < < < < < < < | < | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | 7161 7162 7163 7164 7165 7166 7167 7168 7169 7170 7171 7172 7173 7174 7175 7176 7177 7178 7179 7180 7181 7182 7183 7184 7185 7186 7187 7188 7189 7190 7191 7192 7193 7194 7195 7196 7197 7198 7199 7200 7201 7202 7203 7204 7205 7206 7207 7208 7209 7210 7211 7212 7213 7214 7215 7216 7217 7218 7219 7220 7221 7222 7223 7224 7225 7226 7227 7228 7229 7230 7231 7232 7233 7234 7235 7236 7237 7238 7239 7240 7241 7242 7243 7244 7245 7246 7247 7248 7249 7250 7251 7252 7253 7254 7255 7256 7257 7258 7259 7260 7261 7262 7263 7264 7265 7266 7267 7268 7269 7270 7271 7272 7273 7274 7275 7276 7277 7278 7279 7280 7281 7282 7283 7284 7285 7286 7287 7288 7289 7290 7291 7292 7293 7294 | */ if (want_reply) { pktout = ssh2_pkt_init(SSH2_MSG_REQUEST_FAILURE); ssh2_pkt_send(ssh, pktout); } } static void ssh2_msg_channel_open(Ssh ssh, struct Packet *pktin) { char *type; int typelen; char *peeraddr; int peeraddrlen; int peerport; char *error = NULL; struct ssh_channel *c; unsigned remid, winsize, pktsize; struct Packet *pktout; ssh_pkt_getstring(pktin, &type, &typelen); c = snew(struct ssh_channel); c->ssh = ssh; remid = ssh_pkt_getuint32(pktin); winsize = ssh_pkt_getuint32(pktin); pktsize = ssh_pkt_getuint32(pktin); if (typelen == 3 && !memcmp(type, "x11", 3)) { char *addrstr; const char *x11err; ssh_pkt_getstring(pktin, &peeraddr, &peeraddrlen); addrstr = snewn(peeraddrlen+1, char); memcpy(addrstr, peeraddr, peeraddrlen); addrstr[peeraddrlen] = '\0'; peerport = ssh_pkt_getuint32(pktin); logeventf(ssh, "Received X11 connect request from %s:%d", addrstr, peerport); if (!ssh->X11_fwd_enabled) error = "X11 forwarding is not enabled"; else if ((x11err = x11_init(&c->u.x11.s, ssh->x11disp, c, addrstr, peerport, &ssh->cfg)) != NULL) { logeventf(ssh, "Local X11 connection failed: %s", x11err); error = "Unable to open an X11 connection"; } else { logevent("Opening X11 forward connection succeeded"); c->type = CHAN_X11; } sfree(addrstr); } else if (typelen == 15 && !memcmp(type, "forwarded-tcpip", 15)) { struct ssh_rportfwd pf, *realpf; char *dummy; int dummylen; ssh_pkt_getstring(pktin, &dummy, &dummylen);/* skip address */ pf.sport = ssh_pkt_getuint32(pktin); ssh_pkt_getstring(pktin, &peeraddr, &peeraddrlen); peerport = ssh_pkt_getuint32(pktin); realpf = find234(ssh->rportfwds, &pf, NULL); logeventf(ssh, "Received remote port %d open request " "from %s:%d", pf.sport, peeraddr, peerport); if (realpf == NULL) { error = "Remote port is not recognised"; } else { const char *e = pfd_newconnect(&c->u.pfd.s, realpf->dhost, realpf->dport, c, &ssh->cfg, realpf->pfrec->addressfamily); logeventf(ssh, "Attempting to forward remote port to " "%s:%d", realpf->dhost, realpf->dport); if (e != NULL) { logeventf(ssh, "Port open failed: %s", e); error = "Port open failed"; } else { logevent("Forwarded port opened successfully"); c->type = CHAN_SOCKDATA; } } } else if (typelen == 22 && !memcmp(type, "auth-agent@openssh.com", 22)) { if (!ssh->agentfwd_enabled) error = "Agent forwarding is not enabled"; else { c->type = CHAN_AGENT; /* identify channel type */ c->u.a.lensofar = 0; } } else { error = "Unsupported channel type requested"; } c->remoteid = remid; c->halfopen = FALSE; if (error) { pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN_FAILURE); ssh2_pkt_adduint32(pktout, c->remoteid); ssh2_pkt_adduint32(pktout, SSH2_OPEN_CONNECT_FAILED); ssh2_pkt_addstring(pktout, error); ssh2_pkt_addstring(pktout, "en"); /* language tag */ ssh2_pkt_send(ssh, pktout); logeventf(ssh, "Rejected channel open: %s", error); sfree(c); } else { ssh2_channel_init(c); c->v.v2.remwindow = winsize; c->v.v2.remmaxpkt = pktsize; add234(ssh->channels, c); pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION); ssh2_pkt_adduint32(pktout, c->remoteid); ssh2_pkt_adduint32(pktout, c->localid); ssh2_pkt_adduint32(pktout, c->v.v2.locwindow); ssh2_pkt_adduint32(pktout, OUR_V2_MAXPKT); /* our max pkt size */ ssh2_pkt_send(ssh, pktout); } } /* * Buffer banner messages for later display at some convenient point, * if we're going to display them. */ static void ssh2_msg_userauth_banner(Ssh ssh, struct Packet *pktin) { /* Arbitrary limit to prevent unbounded inflation of buffer */ if (ssh->cfg.ssh_show_banner && bufchain_size(&ssh->banner) <= 131072) { char *banner = NULL; int size = 0; ssh_pkt_getstring(pktin, &banner, &size); if (banner) bufchain_add(&ssh->banner, banner, size); } |
︙ | ︙ | |||
8205 8206 8207 8208 8209 8210 8211 | arg = ssh_tty_parse_boolean(val); break; } ssh2_pkt_addbyte(pktout, ssh_ttymodes[i].opcode); ssh2_pkt_adduint32(pktout, arg); } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > > > > > > > | > < | < < < < < < < < < < < < < < < < < < < < < < < > > > > > > > > > > > | | | | | | | | | | | | | | | | | | | | | | | | | | < < < < | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 7310 7311 7312 7313 7314 7315 7316 7317 7318 7319 7320 7321 7322 7323 7324 7325 7326 7327 7328 7329 7330 7331 7332 7333 7334 7335 7336 7337 7338 7339 7340 7341 7342 7343 7344 7345 7346 7347 7348 7349 7350 7351 7352 7353 7354 7355 7356 7357 7358 7359 7360 7361 7362 7363 7364 7365 7366 7367 7368 7369 7370 7371 7372 7373 7374 7375 7376 7377 7378 7379 7380 7381 7382 7383 7384 7385 7386 7387 7388 7389 7390 7391 7392 7393 7394 7395 7396 7397 7398 7399 7400 7401 7402 7403 7404 7405 7406 7407 7408 7409 7410 7411 7412 7413 7414 7415 7416 7417 7418 7419 7420 7421 7422 7423 7424 7425 7426 7427 7428 7429 7430 7431 7432 7433 7434 7435 7436 7437 7438 7439 7440 7441 7442 7443 7444 7445 7446 7447 7448 7449 7450 7451 7452 7453 7454 7455 7456 7457 7458 7459 7460 7461 7462 7463 7464 7465 7466 7467 7468 7469 7470 7471 7472 7473 7474 7475 7476 7477 7478 7479 7480 7481 7482 7483 7484 7485 7486 7487 7488 7489 7490 7491 7492 7493 7494 7495 7496 7497 7498 7499 7500 7501 7502 7503 7504 7505 7506 7507 7508 7509 7510 7511 7512 7513 7514 7515 7516 7517 7518 7519 7520 7521 7522 7523 7524 7525 7526 7527 7528 7529 7530 7531 7532 7533 7534 7535 7536 7537 7538 7539 7540 7541 7542 | arg = ssh_tty_parse_boolean(val); break; } ssh2_pkt_addbyte(pktout, ssh_ttymodes[i].opcode); ssh2_pkt_adduint32(pktout, arg); } /* * Handle the SSH-2 userauth and connection layers. */ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, struct Packet *pktin) { struct do_ssh2_authconn_state { enum { AUTH_TYPE_NONE, AUTH_TYPE_PUBLICKEY, AUTH_TYPE_PUBLICKEY_OFFER_LOUD, AUTH_TYPE_PUBLICKEY_OFFER_QUIET, AUTH_TYPE_PASSWORD, AUTH_TYPE_GSSAPI, /* always QUIET */ AUTH_TYPE_KEYBOARD_INTERACTIVE, AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET } type; int done_service_req; int gotit, need_pw, can_pubkey, can_passwd, can_keyb_inter; /* PuTTY SC start */ int can_pkcs11, tried_pkcs11, pkcs11_key_loaded; /* PuTTY SC end */ /* PuTTY CAPI start */ int can_capi, tried_capi, capi_key_loaded; struct capi_keyhandle_struct* capi_keyhandle; /* PuTTY CAPI end */ int tried_pubkey_config, done_agent; #ifndef NO_GSSAPI int can_gssapi; int tried_gssapi; #endif int kbd_inter_refused; int we_are_in, userauth_success; prompts_t *cur_prompt; int num_prompts; char username[100]; char *password; int got_username; void *publickey_blob; int publickey_bloblen; int publickey_encrypted; char *publickey_algorithm; char *publickey_comment; unsigned char agent_request[5], *agent_response, *agentp; int agent_responselen; unsigned char *pkblob_in_agent; int keyi, nkeys; char *pkblob, *alg, *commentp; int pklen, alglen, commentlen; int siglen, retlen, len; char *q, *agentreq, *ret; int try_send; int num_env, env_left, env_ok; struct Packet *pktout; #ifndef NO_GSSAPI struct ssh_gss_library *gsslib; Ssh_gss_ctx gss_ctx; Ssh_gss_buf gss_buf; Ssh_gss_buf gss_rcvtok, gss_sndtok; Ssh_gss_name gss_srv_name; Ssh_gss_stat gss_stat; #endif }; crState(do_ssh2_authconn_state); crBegin(ssh->do_ssh2_authconn_crstate); s->done_service_req = FALSE; s->we_are_in = s->userauth_success = FALSE; #ifndef NO_GSSAPI s->tried_gssapi = FALSE; #endif /* PuTTY SC start */ s->tried_pkcs11 = FALSE; s->can_pkcs11 = FALSE; s->pkcs11_key_loaded = FALSE; /* PuTTY SC end */ /* PuTTY CAPI start */ s->tried_capi = FALSE; s->can_capi = FALSE; s->capi_key_loaded = FALSE; s->capi_keyhandle = NULL; /* PuTTY CAPI end */ if (!ssh->cfg.ssh_no_userauth) { /* * Request userauth protocol, and await a response to it. */ s->pktout = ssh2_pkt_init(SSH2_MSG_SERVICE_REQUEST); ssh2_pkt_addstring(s->pktout, "ssh-userauth"); ssh2_pkt_send(ssh, s->pktout); crWaitUntilV(pktin); if (pktin->type == SSH2_MSG_SERVICE_ACCEPT) s->done_service_req = TRUE; } if (!s->done_service_req) { /* * Request connection protocol directly, without authentication. */ s->pktout = ssh2_pkt_init(SSH2_MSG_SERVICE_REQUEST); ssh2_pkt_addstring(s->pktout, "ssh-connection"); ssh2_pkt_send(ssh, s->pktout); crWaitUntilV(pktin); if (pktin->type == SSH2_MSG_SERVICE_ACCEPT) { s->we_are_in = TRUE; /* no auth required */ } else { bombout(("Server refused service request")); crStopV; } } /* Arrange to be able to deal with any BANNERs that come in. * (We do this now as packets may come in during the next bit.) */ bufchain_init(&ssh->banner); ssh->packet_dispatch[SSH2_MSG_USERAUTH_BANNER] = ssh2_msg_userauth_banner; /* * Misc one-time setup for authentication. */ s->publickey_blob = NULL; if (!s->we_are_in) { /* * Load the public half of any configured public key file * for later use. */ if (!filename_is_null(ssh->cfg.keyfile)) { int keytype; logeventf(ssh, "Reading private key file \"%.150s\"", filename_to_str(&ssh->cfg.keyfile)); keytype = key_type(&ssh->cfg.keyfile); if (keytype == SSH_KEYTYPE_SSH2) { const char *error; s->publickey_blob = ssh2_userkey_loadpub(&ssh->cfg.keyfile, &s->publickey_algorithm, &s->publickey_bloblen, &s->publickey_comment, &error); if (s->publickey_blob) { s->publickey_encrypted = ssh2_userkey_encrypted(&ssh->cfg.keyfile, NULL); } else { char *msgbuf; logeventf(ssh, "Unable to load private key (%s)", error); msgbuf = dupprintf("Unable to load private key file " "\"%.150s\" (%s)\r\n", filename_to_str(&ssh->cfg.keyfile), error); c_write_str(ssh, msgbuf); sfree(msgbuf); } } else { char *msgbuf; logeventf(ssh, "Unable to use this key file (%s)", key_type_to_str(keytype)); msgbuf = dupprintf("Unable to use key file \"%.150s\"" " (%s)\r\n", filename_to_str(&ssh->cfg.keyfile), key_type_to_str(keytype)); c_write_str(ssh, msgbuf); sfree(msgbuf); s->publickey_blob = NULL; } } /* PuTTY SC start */ else if (ssh->cfg.try_pkcs11_auth) { if(!loaded_pkcs11 && !filename_is_null(ssh->cfg.pkcs11_libfile)) { if (ssh->cfg.sclib == NULL) { ssh->cfg.sclib = calloc(sizeof(sc_lib), 1); } if(s->can_pkcs11 = sc_init_library(ssh->frontend, ssh->cfg.try_write_syslog, ssh->cfg.sclib, &ssh->cfg.pkcs11_libfile)) { loaded_pkcs11=1; } else { free(ssh->cfg.sclib); sc_write_syslog("sc: Failed to load pkcs11 library"); logevent("sc: Failed to load pkcs11 library"); } } if(loaded_pkcs11) { logeventf(ssh, "Using key (%s) from token (%s)", ssh->cfg.pkcs11_cert_label, ssh->cfg.pkcs11_token_label); s->publickey_blob = (unsigned char *)sc_get_pub(ssh->frontend, ssh->cfg.try_write_syslog, ssh->cfg.sclib, ssh->cfg.pkcs11_token_label, ssh->cfg.pkcs11_cert_label, &s->publickey_algorithm, &s->publickey_bloblen); s->pkcs11_key_loaded = TRUE; s->publickey_encrypted = TRUE; s->publickey_comment = calloc(strlen(ssh->cfg.pkcs11_cert_label) + 1, 1); strcpy(s->publickey_comment, ssh->cfg.pkcs11_cert_label); } } /* PuTTY SC end */ /* PuTTY CAPI start */ else if (ssh->cfg.try_capi_auth) { logeventf(ssh, "Using cert (%s) from CAPI", ssh->cfg.capi_certID); if (capi_get_pubkey(ssh->frontend, ssh->cfg.capi_certID, (unsigned char**) &s->publickey_blob, &s->publickey_algorithm, &s->publickey_bloblen)) { s->capi_key_loaded = TRUE; s->publickey_encrypted = FALSE; // never encrypted (as far as PuTTY knows) s->publickey_comment = calloc(sizeof(ssh->cfg.capi_certID) + 6, 1); _snprintf(s->publickey_comment, sizeof(ssh->cfg.capi_certID) + 5, "CAPI:%s", ssh->cfg.capi_certID); } } /* PuTTY CAPI end */ /* * Find out about any keys Pageant has (but if there's a * public key configured, filter out all others). */ s->nkeys = 0; s->agent_response = NULL; s->pkblob_in_agent = NULL; if (ssh->cfg.tryagent && agent_exists()) { void *r; logevent("Pageant is running. Requesting keys."); /* Request the keys held by the agent. */ PUT_32BIT(s->agent_request, 1); |
︙ | ︙ | |||
8615 8616 8617 8618 8619 8620 8621 | } s->agent_response = (unsigned char *) r; if (s->agent_response && s->agent_responselen >= 5 && s->agent_response[4] == SSH2_AGENT_IDENTITIES_ANSWER) { int keyi; unsigned char *p; p = s->agent_response + 5; | < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < | 7556 7557 7558 7559 7560 7561 7562 7563 7564 7565 7566 7567 7568 7569 7570 7571 7572 7573 7574 7575 7576 7577 7578 7579 7580 7581 7582 7583 7584 7585 7586 7587 7588 7589 7590 7591 7592 7593 7594 7595 7596 | } s->agent_response = (unsigned char *) r; if (s->agent_response && s->agent_responselen >= 5 && s->agent_response[4] == SSH2_AGENT_IDENTITIES_ANSWER) { int keyi; unsigned char *p; p = s->agent_response + 5; s->nkeys = GET_32BIT(p); p += 4; logeventf(ssh, "Pageant has %d SSH-2 keys", s->nkeys); if (s->publickey_blob) { /* See if configured key is in agent. */ for (keyi = 0; keyi < s->nkeys; keyi++) { s->pklen = GET_32BIT(p); if (s->pklen == s->publickey_bloblen && !memcmp(p+4, s->publickey_blob, s->publickey_bloblen)) { logeventf(ssh, "Pageant key #%d matches " "configured key file", keyi); s->keyi = keyi; s->pkblob_in_agent = p; break; } p += 4 + s->pklen; p += GET_32BIT(p) + 4; /* comment */ } if (!s->pkblob_in_agent) { logevent("Configured key file not in Pageant"); s->nkeys = 0; } } } else { logevent("Failed to get reply from Pageant"); } } } /* * We repeat this whole loop, including the username prompt, * until we manage a successful authentication. If the user |
︙ | ︙ | |||
8711 8712 8713 8714 8715 8716 8717 8718 8719 8720 8721 8722 | * - people with a key held in Pageant, who might not have * logged in to a particular machine before; so they want to * type a username, and then _either_ their key will be * accepted, _or_ they will type a password. If they mistype * the username they will want to be able to get back and * retype it! */ s->got_username = FALSE; while (!s->we_are_in) { /* * Get a username. */ | > | | > | > | > | | | 7611 7612 7613 7614 7615 7616 7617 7618 7619 7620 7621 7622 7623 7624 7625 7626 7627 7628 7629 7630 7631 7632 7633 7634 7635 7636 7637 7638 7639 7640 7641 7642 7643 7644 7645 7646 7647 7648 7649 7650 7651 7652 7653 7654 7655 7656 7657 7658 7659 7660 7661 7662 7663 7664 7665 7666 7667 7668 7669 7670 7671 7672 7673 7674 7675 7676 7677 7678 7679 7680 7681 7682 | * - people with a key held in Pageant, who might not have * logged in to a particular machine before; so they want to * type a username, and then _either_ their key will be * accepted, _or_ they will type a password. If they mistype * the username they will want to be able to get back and * retype it! */ s->username[0] = '\0'; s->got_username = FALSE; while (!s->we_are_in) { /* * Get a username. */ if (s->got_username && !ssh->cfg.change_username) { /* * We got a username last time round this loop, and * with change_username turned off we don't try to get * it again. */ } else if (!get_remote_username(&ssh->cfg, s->username, sizeof(s->username))) { int ret; /* need not be kept over crReturn */ s->cur_prompt = new_prompts(ssh->frontend); s->cur_prompt->to_server = TRUE; s->cur_prompt->name = dupstr("SSH login name"); add_prompt(s->cur_prompt, dupstr("login as: "), TRUE, lenof(s->username)); ret = get_userpass_input(s->cur_prompt, NULL, 0); while (ret < 0) { ssh->send_ok = 1; crWaitUntilV(!pktin); ret = get_userpass_input(s->cur_prompt, in, inlen); ssh->send_ok = 0; } if (!ret) { /* * get_userpass_input() failed to get a username. * Terminate. */ free_prompts(s->cur_prompt); ssh_disconnect(ssh, "No username provided", NULL, 0, TRUE); crStopV; } memcpy(s->username, s->cur_prompt->prompts[0]->result, lenof(s->username)); free_prompts(s->cur_prompt); } else { char *stuff; if ((flags & FLAG_VERBOSE) || (flags & FLAG_INTERACTIVE)) { stuff = dupprintf("Using username \"%s\".\r\n", s->username); c_write_str(ssh, stuff); sfree(stuff); } } s->got_username = TRUE; /* * Send an authentication request using method "none": (a) * just in case it succeeds, and (b) so that we know what * authentication methods we can usefully try next. */ ssh->pkt_actx = SSH2_PKTCTX_NOAUTH; s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); ssh2_pkt_addstring(s->pktout, s->username); ssh2_pkt_addstring(s->pktout, "ssh-connection");/* service requested */ ssh2_pkt_addstring(s->pktout, "none"); /* method */ ssh2_pkt_send(ssh, s->pktout); s->type = AUTH_TYPE_NONE; s->gotit = FALSE; s->we_are_in = FALSE; |
︙ | ︙ | |||
8894 8895 8896 8897 8898 8899 8900 | logevent("Keyboard-interactive authentication failed"); c_write_str(ssh, "Access denied\r\n"); } else { assert(s->type == AUTH_TYPE_PASSWORD); logevent("Password authentication failed"); c_write_str(ssh, "Access denied\r\n"); | | > > > > > > | | | | | | | | 7798 7799 7800 7801 7802 7803 7804 7805 7806 7807 7808 7809 7810 7811 7812 7813 7814 7815 7816 7817 7818 7819 7820 7821 7822 7823 7824 7825 7826 7827 7828 7829 7830 7831 7832 7833 7834 7835 7836 7837 7838 7839 7840 7841 7842 7843 7844 7845 7846 7847 7848 7849 7850 7851 7852 7853 7854 7855 7856 7857 7858 7859 7860 7861 7862 7863 7864 7865 7866 7867 7868 7869 7870 7871 7872 | logevent("Keyboard-interactive authentication failed"); c_write_str(ssh, "Access denied\r\n"); } else { assert(s->type == AUTH_TYPE_PASSWORD); logevent("Password authentication failed"); c_write_str(ssh, "Access denied\r\n"); if (ssh->cfg.change_username) { /* XXX perhaps we should allow * keyboard-interactive to do this too? */ s->we_are_in = FALSE; break; } } } else { c_write_str(ssh, "Further authentication required\r\n"); logevent("Further authentication required"); } s->can_pubkey = in_commasep_string("publickey", methods, methlen); /* PuTTY SC start */ s->can_pkcs11= ssh->cfg.try_pkcs11_auth && s->can_pubkey && s->pkcs11_key_loaded; /* PuTTY SC end */ /* PuTTY CAPI start */ s->can_capi= ssh->cfg.try_capi_auth && s->can_pubkey && s->capi_key_loaded; /* PuTTY CAPI end */ s->can_passwd = in_commasep_string("password", methods, methlen); s->can_keyb_inter = ssh->cfg.try_ki_auth && in_commasep_string("keyboard-interactive", methods, methlen); #ifndef NO_GSSAPI if (!ssh->gsslibs) ssh->gsslibs = ssh_gss_setup(&ssh->cfg); s->can_gssapi = ssh->cfg.try_gssapi_auth && in_commasep_string("gssapi-with-mic", methods, methlen) && ssh->gsslibs->nlibraries > 0; #endif } ssh->pkt_actx = SSH2_PKTCTX_NOAUTH; if (s->can_pubkey && !s->done_agent && s->nkeys) { /* * Attempt public-key authentication using a key from Pageant. */ ssh->pkt_actx = SSH2_PKTCTX_PUBLICKEY; logeventf(ssh, "Trying Pageant key #%d", s->keyi); /* Unpack key from agent response */ s->pklen = GET_32BIT(s->agentp); s->agentp += 4; s->pkblob = (char *)s->agentp; s->agentp += s->pklen; s->alglen = GET_32BIT(s->pkblob); s->alg = s->pkblob + 4; s->commentlen = GET_32BIT(s->agentp); s->agentp += 4; s->commentp = (char *)s->agentp; s->agentp += s->commentlen; /* s->agentp now points at next key, if any */ /* See if server will accept it */ s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); ssh2_pkt_addstring(s->pktout, s->username); ssh2_pkt_addstring(s->pktout, "ssh-connection"); /* service requested */ ssh2_pkt_addstring(s->pktout, "publickey"); /* method */ ssh2_pkt_addbool(s->pktout, FALSE); /* no signature included */ ssh2_pkt_addstring_start(s->pktout); ssh2_pkt_addstring_data(s->pktout, s->alg, s->alglen); |
︙ | ︙ | |||
8983 8984 8985 8986 8987 8988 8989 | } /* * Server is willing to accept the key. * Construct a SIGN_REQUEST. */ s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); | | | 7893 7894 7895 7896 7897 7898 7899 7900 7901 7902 7903 7904 7905 7906 7907 | } /* * Server is willing to accept the key. * Construct a SIGN_REQUEST. */ s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); ssh2_pkt_addstring(s->pktout, s->username); ssh2_pkt_addstring(s->pktout, "ssh-connection"); /* service requested */ ssh2_pkt_addstring(s->pktout, "publickey"); /* method */ ssh2_pkt_addbool(s->pktout, TRUE); /* signature included */ ssh2_pkt_addstring_start(s->pktout); ssh2_pkt_addstring_data(s->pktout, s->alg, s->alglen); |
︙ | ︙ | |||
9044 9045 9046 9047 9048 9049 9050 | } while (pktin || inlen > 0); vret = ssh->agent_response; s->retlen = ssh->agent_response_len; } s->ret = vret; sfree(s->agentreq); if (s->ret) { | < | < | 7954 7955 7956 7957 7958 7959 7960 7961 7962 7963 7964 7965 7966 7967 7968 | } while (pktin || inlen > 0); vret = ssh->agent_response; s->retlen = ssh->agent_response_len; } s->ret = vret; sfree(s->agentreq); if (s->ret) { if (s->ret[4] == SSH2_AGENT_SIGN_RESPONSE) { logevent("Sending Pageant's response"); ssh2_add_sigblob(ssh, s->pktout, s->pkblob, s->pklen, s->ret + 9, GET_32BIT(s->ret + 5)); ssh2_pkt_send(ssh, s->pktout); s->type = AUTH_TYPE_PUBLICKEY; |
︙ | ︙ | |||
9072 9073 9074 9075 9076 9077 9078 | s->tried_pubkey_config = TRUE; } else { s->keyi++; if (s->keyi >= s->nkeys) s->done_agent = TRUE; } | > | | > > > > > > > > > > > > > > > > | | 7980 7981 7982 7983 7984 7985 7986 7987 7988 7989 7990 7991 7992 7993 7994 7995 7996 7997 7998 7999 8000 8001 8002 8003 8004 8005 8006 8007 8008 8009 8010 8011 8012 8013 8014 8015 8016 8017 8018 8019 8020 8021 8022 8023 8024 8025 8026 8027 8028 | s->tried_pubkey_config = TRUE; } else { s->keyi++; if (s->keyi >= s->nkeys) s->done_agent = TRUE; } /* PuTTY SC marker */ /* PuTTY CAPI marker */ } else if ((s->can_pubkey && s->publickey_blob && !s->tried_pubkey_config) || (s->can_pkcs11 && s->publickey_blob && !s->tried_pkcs11 && s->pkcs11_key_loaded) || (s->can_capi && s->publickey_blob && !s->tried_capi && s->pkcs11_key_loaded) ) { struct ssh2_userkey *key; /* not live over crReturn */ char *passphrase; /* not live over crReturn */ /* PuTTY SC start */ struct sc_pubkey_blob *key11 = NULL; char passphrase11[512]; if(s->can_pkcs11) { s->tried_pkcs11 = TRUE; } /* PuTTY SC end */ /* PuTTY CAPI start */ if (s->can_capi) s->tried_capi = TRUE; /* PuTTY CAPI end */ ssh->pkt_actx = SSH2_PKTCTX_PUBLICKEY; s->tried_pubkey_config = TRUE; /* * Try the public key supplied in the configuration. * * First, offer the public blob to see if the server is * willing to accept it. */ s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); ssh2_pkt_addstring(s->pktout, s->username); ssh2_pkt_addstring(s->pktout, "ssh-connection"); /* service requested */ ssh2_pkt_addstring(s->pktout, "publickey"); /* method */ ssh2_pkt_addbool(s->pktout, FALSE); /* no signature included */ ssh2_pkt_addstring(s->pktout, s->publickey_algorithm); ssh2_pkt_addstring_start(s->pktout); |
︙ | ︙ | |||
9124 9125 9126 9127 9128 9129 9130 | c_write_str(ssh, "Authenticating with public key \""); c_write_str(ssh, s->publickey_comment); c_write_str(ssh, "\"\r\n"); } key = NULL; while (!key) { const char *error; /* not live over crReturn */ | > | > > > > > > > > | | 8049 8050 8051 8052 8053 8054 8055 8056 8057 8058 8059 8060 8061 8062 8063 8064 8065 8066 8067 8068 8069 8070 8071 8072 8073 8074 8075 8076 8077 8078 8079 8080 8081 8082 8083 | c_write_str(ssh, "Authenticating with public key \""); c_write_str(ssh, s->publickey_comment); c_write_str(ssh, "\"\r\n"); } key = NULL; while (!key) { const char *error; /* not live over crReturn */ /* PuTTY SC marker */ if (s->publickey_encrypted || (s->can_pkcs11 && s->pkcs11_key_loaded)) { /* * Get a passphrase from the user. */ int ret; /* need not be kept over crReturn */ s->cur_prompt = new_prompts(ssh->frontend); s->cur_prompt->to_server = FALSE; s->cur_prompt->name = dupstr("SSH key passphrase"); /* PuTTY SC start */ if(s->can_pkcs11 && s->pkcs11_key_loaded) { add_prompt(s->cur_prompt, dupprintf("Passphrase for smartcard \"%s\": ", ssh->cfg.pkcs11_token_label), FALSE, SSH_MAX_PASSWORD_LEN); } else /* PuTTY SC end */ add_prompt(s->cur_prompt, dupprintf("Passphrase for key \"%.100s\": ", s->publickey_comment), FALSE, SSH_MAX_PASSWORD_LEN); ret = get_userpass_input(s->cur_prompt, NULL, 0); while (ret < 0) { ssh->send_ok = 1; crWaitUntilV(!pktin); ret = get_userpass_input(s->cur_prompt, in, inlen); ssh->send_ok = 0; |
︙ | ︙ | |||
9163 9164 9165 9166 9167 9168 9169 | } else { passphrase = NULL; /* no passphrase needed */ } /* * Try decrypting the key. */ | | > > > > > > > > > > > > > > > > > > > > > > | > | | 8097 8098 8099 8100 8101 8102 8103 8104 8105 8106 8107 8108 8109 8110 8111 8112 8113 8114 8115 8116 8117 8118 8119 8120 8121 8122 8123 8124 8125 8126 8127 8128 8129 8130 8131 8132 8133 8134 8135 8136 8137 8138 | } else { passphrase = NULL; /* no passphrase needed */ } /* * Try decrypting the key. */ /* PuTTY SC start */ if(s->can_pkcs11 && s->pkcs11_key_loaded) { key11 = sc_login_pub(ssh->frontend, ssh->cfg.try_write_syslog, ssh->cfg.sclib, (const char *)&ssh->cfg.pkcs11_token_label, passphrase); key = (struct ssh2_userkey *)key11; if(key11) { strcpy(passphrase11, passphrase); } } else /* PuTTY SC end */ /* PuTTY CAPI start */ if(s->can_capi && s->capi_key_loaded) {/*chained off the else above*/ if (capi_get_key_handle(ssh->frontend, ssh->cfg.capi_certID, &s->capi_keyhandle)) { key = &capi_key_ssh2_userkey; // special flag-struct } else { logeventf(ssh, "capi_get_key_handle(%s) returned false. s->capi_keyhandle=%08x", ssh->cfg.capi_certID, s->capi_keyhandle); error = "Failed to load CAPI key"; } } else /* PuTTY CAPI end */ key = ssh2_load_userkey(&ssh->cfg.keyfile, passphrase, &error); if (passphrase) { /* burn the evidence */ memset(passphrase, 0, strlen(passphrase)); sfree(passphrase); } if (key == SSH2_WRONG_PASSPHRASE || key == NULL) { if (passphrase && (key == SSH2_WRONG_PASSPHRASE)) { c_write_str(ssh, "Wrong passphrase\r\n"); key = NULL; |
︙ | ︙ | |||
9197 9198 9199 9200 9201 9202 9203 | /* * We have loaded the private key and the server * has announced that it's willing to accept it. * Hallelujah. Generate a signature and send it. */ s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); | | > > > > > > > > > > > > > > | 8154 8155 8156 8157 8158 8159 8160 8161 8162 8163 8164 8165 8166 8167 8168 8169 8170 8171 8172 8173 8174 8175 8176 8177 8178 8179 8180 8181 8182 8183 8184 8185 8186 8187 8188 8189 8190 8191 | /* * We have loaded the private key and the server * has announced that it's willing to accept it. * Hallelujah. Generate a signature and send it. */ s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); ssh2_pkt_addstring(s->pktout, s->username); ssh2_pkt_addstring(s->pktout, "ssh-connection"); /* service requested */ ssh2_pkt_addstring(s->pktout, "publickey"); /* method */ ssh2_pkt_addbool(s->pktout, TRUE); /* signature follows */ /* PuTTY SC start */ if((key11 != NULL) && (s->pkcs11_key_loaded)) { ssh2_pkt_addstring(s->pktout, key11->alg); pkblob = calloc(key11->len,1); memcpy(pkblob, key11->data, key11->len); pkblob_len = key11->len; } else /* PuTTY SC end */ /* PuTTY CAPI start */ if (s->capi_keyhandle) { ssh2_pkt_addstring(s->pktout, s->capi_keyhandle->algorithm); pkblob_len = s->capi_keyhandle->pubkey_len; pkblob = calloc(pkblob_len,1); memcpy(pkblob, s->capi_keyhandle->pubkey, pkblob_len); } else { /* PuTTY CAPI end */ ssh2_pkt_addstring(s->pktout, key->alg->name); pkblob = key->alg->public_blob(key->data, &pkblob_len); } ssh2_pkt_addstring_start(s->pktout); ssh2_pkt_addstring_data(s->pktout, (char *)pkblob, pkblob_len); /* * The data to be signed is: * |
︙ | ︙ | |||
9236 9237 9238 9239 9240 9241 9242 9243 9244 9245 9246 9247 9248 9249 9250 9251 9252 9253 9254 9255 9256 9257 9258 9259 9260 | memcpy(sigdata+p, ssh->v2_session_id, ssh->v2_session_id_len); p += ssh->v2_session_id_len; memcpy(sigdata+p, s->pktout->data + 5, s->pktout->length - 5); p += s->pktout->length - 5; assert(p == sigdata_len); sigblob = key->alg->sign(key->data, (char *)sigdata, sigdata_len, &sigblob_len); ssh2_add_sigblob(ssh, s->pktout, pkblob, pkblob_len, sigblob, sigblob_len); sfree(pkblob); sfree(sigblob); sfree(sigdata); ssh2_pkt_send(ssh, s->pktout); logevent("Sent public key signature"); s->type = AUTH_TYPE_PUBLICKEY; key->alg->freekey(key->data); } #ifndef NO_GSSAPI } else if (s->can_gssapi && !s->tried_gssapi) { /* GSSAPI Authentication */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 8207 8208 8209 8210 8211 8212 8213 8214 8215 8216 8217 8218 8219 8220 8221 8222 8223 8224 8225 8226 8227 8228 8229 8230 8231 8232 8233 8234 8235 8236 8237 8238 8239 8240 8241 8242 8243 8244 8245 8246 8247 8248 8249 8250 8251 8252 8253 8254 8255 8256 8257 8258 8259 8260 8261 8262 8263 8264 8265 8266 8267 8268 8269 8270 8271 | memcpy(sigdata+p, ssh->v2_session_id, ssh->v2_session_id_len); p += ssh->v2_session_id_len; memcpy(sigdata+p, s->pktout->data + 5, s->pktout->length - 5); p += s->pktout->length - 5; assert(p == sigdata_len); /* PuTTY SC start */ if((key11 != NULL) && (s->pkcs11_key_loaded)) { sigblob = sc_sig(ssh->frontend, ssh->cfg.try_write_syslog, ssh->cfg.sclib, ssh->cfg.pkcs11_token_label, passphrase11, sigdata, sigdata_len, &sigblob_len); memset(passphrase11, 0, strlen(passphrase11)); } else /* PuTTY SC end */ /* PuTTY CAPI start */ if(s->capi_key_loaded && (s->capi_keyhandle != NULL)) { /* chained off else from above */ if ((sigblob = capi_sig(s->capi_keyhandle, sigdata, sigdata_len, &sigblob_len)) == NULL) { capi_release_key(&s->capi_keyhandle); sfree(pkblob); sfree(sigdata); bombout(("CAPI failed to sign data")); crStopV; } } else /* PuTTY CAPI end */ sigblob = key->alg->sign(key->data, (char *)sigdata, sigdata_len, &sigblob_len); ssh2_add_sigblob(ssh, s->pktout, pkblob, pkblob_len, sigblob, sigblob_len); sfree(pkblob); sfree(sigblob); sfree(sigdata); ssh2_pkt_send(ssh, s->pktout); logevent("Sent public key signature"); s->type = AUTH_TYPE_PUBLICKEY; /* PuTTY SC start */ if((key11 != NULL) && (s->pkcs11_key_loaded)) { sc_free_sclib(ssh->cfg.sclib); ssh->cfg.sclib = NULL; free(key11); key11 = NULL; loaded_pkcs11=0; s->pkcs11_key_loaded = FALSE; } else /* PuTTY SC end */ /* PuTTY CAPI start */ if(s->capi_key_loaded || s->capi_keyhandle) { /* chained off else from above */ capi_release_key(&s->capi_keyhandle); s->capi_key_loaded = FALSE; key = NULL; } else /* PuTTY CAPI end */ key->alg->freekey(key->data); } #ifndef NO_GSSAPI } else if (s->can_gssapi && !s->tried_gssapi) { /* GSSAPI Authentication */ |
︙ | ︙ | |||
9271 9272 9273 9274 9275 9276 9277 | * Pick the highest GSS library on the preference * list. */ { int i, j; s->gsslib = NULL; for (i = 0; i < ngsslibs; i++) { | | < | 8282 8283 8284 8285 8286 8287 8288 8289 8290 8291 8292 8293 8294 8295 8296 | * Pick the highest GSS library on the preference * list. */ { int i, j; s->gsslib = NULL; for (i = 0; i < ngsslibs; i++) { int want_id = ssh->cfg.ssh_gsslist[i]; for (j = 0; j < ssh->gsslibs->nlibraries; j++) if (ssh->gsslibs->libraries[j].id == want_id) { s->gsslib = &ssh->gsslibs->libraries[j]; goto got_gsslib; /* double break */ } } got_gsslib: |
︙ | ︙ | |||
9295 9296 9297 9298 9299 9300 9301 | } if (s->gsslib->gsslogmsg) logevent(s->gsslib->gsslogmsg); /* Sending USERAUTH_REQUEST with "gssapi-with-mic" method */ s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); | | | 8305 8306 8307 8308 8309 8310 8311 8312 8313 8314 8315 8316 8317 8318 8319 | } if (s->gsslib->gsslogmsg) logevent(s->gsslib->gsslogmsg); /* Sending USERAUTH_REQUEST with "gssapi-with-mic" method */ s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); ssh2_pkt_addstring(s->pktout, s->username); ssh2_pkt_addstring(s->pktout, "ssh-connection"); ssh2_pkt_addstring(s->pktout, "gssapi-with-mic"); logevent("Attempting GSSAPI authentication"); /* add mechanism info */ s->gsslib->indicate_mech(s->gsslib, &s->gss_buf); |
︙ | ︙ | |||
9367 9368 9369 9370 9371 9372 9373 | /* now enter the loop */ do { s->gss_stat = s->gsslib->init_sec_context (s->gsslib, &s->gss_ctx, s->gss_srv_name, | | | 8377 8378 8379 8380 8381 8382 8383 8384 8385 8386 8387 8388 8389 8390 8391 | /* now enter the loop */ do { s->gss_stat = s->gsslib->init_sec_context (s->gsslib, &s->gss_ctx, s->gss_srv_name, ssh->cfg.gssapifwd, &s->gss_rcvtok, &s->gss_sndtok); if (s->gss_stat!=SSH_GSS_S_COMPLETE && s->gss_stat!=SSH_GSS_S_CONTINUE_NEEDED) { logevent("GSSAPI authentication initialisation failed"); |
︙ | ︙ | |||
9423 9424 9425 9426 9427 9428 9429 | /* Now send the MIC */ s->pktout = ssh2_pkt_init(0); micoffset = s->pktout->length; ssh_pkt_addstring_start(s->pktout); ssh_pkt_addstring_data(s->pktout, (char *)ssh->v2_session_id, ssh->v2_session_id_len); ssh_pkt_addbyte(s->pktout, SSH2_MSG_USERAUTH_REQUEST); | | | 8433 8434 8435 8436 8437 8438 8439 8440 8441 8442 8443 8444 8445 8446 8447 | /* Now send the MIC */ s->pktout = ssh2_pkt_init(0); micoffset = s->pktout->length; ssh_pkt_addstring_start(s->pktout); ssh_pkt_addstring_data(s->pktout, (char *)ssh->v2_session_id, ssh->v2_session_id_len); ssh_pkt_addbyte(s->pktout, SSH2_MSG_USERAUTH_REQUEST); ssh_pkt_addstring(s->pktout, s->username); ssh_pkt_addstring(s->pktout, "ssh-connection"); ssh_pkt_addstring(s->pktout, "gssapi-with-mic"); s->gss_buf.value = (char *)s->pktout->data + micoffset; s->gss_buf.length = s->pktout->length - micoffset; s->gsslib->get_mic(s->gsslib, s->gss_ctx, &s->gss_buf, &mic); |
︙ | ︙ | |||
9454 9455 9456 9457 9458 9459 9460 | */ s->type = AUTH_TYPE_KEYBOARD_INTERACTIVE; ssh->pkt_actx = SSH2_PKTCTX_KBDINTER; s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); | | | 8464 8465 8466 8467 8468 8469 8470 8471 8472 8473 8474 8475 8476 8477 8478 | */ s->type = AUTH_TYPE_KEYBOARD_INTERACTIVE; ssh->pkt_actx = SSH2_PKTCTX_KBDINTER; s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); ssh2_pkt_addstring(s->pktout, s->username); ssh2_pkt_addstring(s->pktout, "ssh-connection"); /* service requested */ ssh2_pkt_addstring(s->pktout, "keyboard-interactive"); /* method */ ssh2_pkt_addstring(s->pktout, ""); /* lang */ ssh2_pkt_addstring(s->pktout, ""); /* submethods */ ssh2_pkt_send(ssh, s->pktout); |
︙ | ︙ | |||
9515 9516 9517 9518 9519 9520 9521 | echo = ssh2_pkt_getbool(pktin); if (!prompt_len) { prompt = noprompt; prompt_len = lenof(noprompt)-1; } add_prompt(s->cur_prompt, dupprintf("%.*s", prompt_len, prompt), | | | 8525 8526 8527 8528 8529 8530 8531 8532 8533 8534 8535 8536 8537 8538 8539 | echo = ssh2_pkt_getbool(pktin); if (!prompt_len) { prompt = noprompt; prompt_len = lenof(noprompt)-1; } add_prompt(s->cur_prompt, dupprintf("%.*s", prompt_len, prompt), echo, SSH_MAX_PASSWORD_LEN); } if (name_len) { /* FIXME: better prefix to distinguish from * local prompts? */ s->cur_prompt->name = dupprintf("SSH server: %.*s", name_len, name); |
︙ | ︙ | |||
9576 9577 9578 9579 9580 9581 9582 9583 9584 9585 9586 9587 9588 9589 9590 9591 | /* * Send the response(s) to the server. */ s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_INFO_RESPONSE); ssh2_pkt_adduint32(s->pktout, s->num_prompts); for (i=0; i < s->num_prompts; i++) { ssh2_pkt_addstring(s->pktout, s->cur_prompt->prompts[i]->result); } ssh2_pkt_send_with_padding(ssh, s->pktout, 256); /* * Free the prompts structure from this iteration. * If there's another, a new one will be allocated * when we return to the top of this while loop. | > > | 8586 8587 8588 8589 8590 8591 8592 8593 8594 8595 8596 8597 8598 8599 8600 8601 8602 8603 | /* * Send the response(s) to the server. */ s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_INFO_RESPONSE); ssh2_pkt_adduint32(s->pktout, s->num_prompts); for (i=0; i < s->num_prompts; i++) { dont_log_password(ssh, s->pktout, PKTLOG_BLANK); ssh2_pkt_addstring(s->pktout, s->cur_prompt->prompts[i]->result); end_log_omission(ssh, s->pktout); } ssh2_pkt_send_with_padding(ssh, s->pktout, 256); /* * Free the prompts structure from this iteration. * If there's another, a new one will be allocated * when we return to the top of this while loop. |
︙ | ︙ | |||
9614 9615 9616 9617 9618 9619 9620 | int changereq_first_time; /* not live over crReturn */ ssh->pkt_actx = SSH2_PKTCTX_PASSWORD; s->cur_prompt = new_prompts(ssh->frontend); s->cur_prompt->to_server = TRUE; s->cur_prompt->name = dupstr("SSH password"); | | | | | 8626 8627 8628 8629 8630 8631 8632 8633 8634 8635 8636 8637 8638 8639 8640 8641 8642 8643 | int changereq_first_time; /* not live over crReturn */ ssh->pkt_actx = SSH2_PKTCTX_PASSWORD; s->cur_prompt = new_prompts(ssh->frontend); s->cur_prompt->to_server = TRUE; s->cur_prompt->name = dupstr("SSH password"); add_prompt(s->cur_prompt, dupprintf("%.90s@%.90s's password: ", s->username, ssh->savedhost), FALSE, SSH_MAX_PASSWORD_LEN); ret = get_userpass_input(s->cur_prompt, NULL, 0); while (ret < 0) { ssh->send_ok = 1; crWaitUntilV(!pktin); ret = get_userpass_input(s->cur_prompt, in, inlen); ssh->send_ok = 0; |
︙ | ︙ | |||
9655 9656 9657 9658 9659 9660 9661 | * user's password. * * Anyone using a password longer than 256 bytes * probably doesn't have much to worry about from * people who find out how long their password is! */ s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); | | > > | 8667 8668 8669 8670 8671 8672 8673 8674 8675 8676 8677 8678 8679 8680 8681 8682 8683 8684 8685 8686 8687 8688 | * user's password. * * Anyone using a password longer than 256 bytes * probably doesn't have much to worry about from * people who find out how long their password is! */ s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); ssh2_pkt_addstring(s->pktout, s->username); ssh2_pkt_addstring(s->pktout, "ssh-connection"); /* service requested */ ssh2_pkt_addstring(s->pktout, "password"); ssh2_pkt_addbool(s->pktout, FALSE); dont_log_password(ssh, s->pktout, PKTLOG_BLANK); ssh2_pkt_addstring(s->pktout, s->password); end_log_omission(ssh, s->pktout); ssh2_pkt_send_with_padding(ssh, s->pktout, 256); logevent("Sent password"); s->type = AUTH_TYPE_PASSWORD; /* * Wait for next packet, in case it's a password change * request. |
︙ | ︙ | |||
9717 9718 9719 9720 9721 9722 9723 | * reluctantly, we prompt for the old password again. * * (On the other hand, some servers don't even bother * to check this field.) */ add_prompt(s->cur_prompt, dupstr("Current password (blank for previously entered password): "), | | | | | | | 8731 8732 8733 8734 8735 8736 8737 8738 8739 8740 8741 8742 8743 8744 8745 8746 8747 8748 8749 8750 8751 8752 8753 8754 8755 8756 8757 8758 8759 8760 8761 8762 8763 8764 8765 8766 8767 8768 8769 8770 8771 8772 8773 8774 8775 8776 8777 8778 8779 8780 8781 8782 8783 8784 8785 8786 | * reluctantly, we prompt for the old password again. * * (On the other hand, some servers don't even bother * to check this field.) */ add_prompt(s->cur_prompt, dupstr("Current password (blank for previously entered password): "), FALSE, SSH_MAX_PASSWORD_LEN); add_prompt(s->cur_prompt, dupstr("Enter new password: "), FALSE, SSH_MAX_PASSWORD_LEN); add_prompt(s->cur_prompt, dupstr("Confirm new password: "), FALSE, SSH_MAX_PASSWORD_LEN); /* * Loop until the user manages to enter the same * password twice. */ while (!got_new) { ret = get_userpass_input(s->cur_prompt, NULL, 0); while (ret < 0) { ssh->send_ok = 1; crWaitUntilV(!pktin); ret = get_userpass_input(s->cur_prompt, in, inlen); ssh->send_ok = 0; } if (!ret) { /* * Failed to get responses. Terminate. */ /* burn the evidence */ free_prompts(s->cur_prompt); memset(s->password, 0, strlen(s->password)); sfree(s->password); ssh_disconnect(ssh, NULL, "Unable to authenticate", SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER, TRUE); crStopV; } /* * If the user specified a new original password * (IYSWIM), overwrite any previously specified * one. * (A side effect is that the user doesn't have to * re-enter it if they louse up the new password.) */ if (s->cur_prompt->prompts[0]->result[0]) { memset(s->password, 0, strlen(s->password)); /* burn the evidence */ sfree(s->password); s->password = dupstr(s->cur_prompt->prompts[0]->result); } /* |
︙ | ︙ | |||
9782 9783 9784 9785 9786 9787 9788 | } /* * Send the new password (along with the old one). * (see above for padding rationale) */ s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); | | > > | 8796 8797 8798 8799 8800 8801 8802 8803 8804 8805 8806 8807 8808 8809 8810 8811 8812 8813 8814 8815 8816 8817 8818 8819 8820 | } /* * Send the new password (along with the old one). * (see above for padding rationale) */ s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); ssh2_pkt_addstring(s->pktout, s->username); ssh2_pkt_addstring(s->pktout, "ssh-connection"); /* service requested */ ssh2_pkt_addstring(s->pktout, "password"); ssh2_pkt_addbool(s->pktout, TRUE); dont_log_password(ssh, s->pktout, PKTLOG_BLANK); ssh2_pkt_addstring(s->pktout, s->password); ssh2_pkt_addstring(s->pktout, s->cur_prompt->prompts[1]->result); free_prompts(s->cur_prompt); end_log_omission(ssh, s->pktout); ssh2_pkt_send_with_padding(ssh, s->pktout, 256); logevent("Sent new password"); /* * Now see what the server has to say about it. * (If it's CHANGEREQ again, it's not happy with the * new password.) |
︙ | ︙ | |||
9823 9824 9825 9826 9827 9828 9829 | */ s->gotit = TRUE; /* * We don't need the old password any more, in any * case. Burn the evidence. */ | | | 8839 8840 8841 8842 8843 8844 8845 8846 8847 8848 8849 8850 8851 8852 8853 | */ s->gotit = TRUE; /* * We don't need the old password any more, in any * case. Burn the evidence. */ memset(s->password, 0, strlen(s->password)); sfree(s->password); } else { char *str = dupprintf("No supported authentication methods available" " (server sent: %.*s)", methlen, methods); |
︙ | ︙ | |||
9853 9854 9855 9856 9857 9858 9859 | if (s->publickey_blob) { sfree(s->publickey_blob); sfree(s->publickey_comment); } if (s->agent_response) sfree(s->agent_response); | | > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | < < | < | < < < < < | < | < < | | > < < < < < < < < < < | | > | > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < | < < < > | > > > > > > > > | > > | < < > | < < > | < | | < | | < | | | < < < < | > > > > > | > > > > > > > > > > > > | > > > > > > > > | > > > > > > > > > > | | > > > > | < < < < < | < | > > > | | > | < < | | > > > > > > > > < | | | < | < | < | | < > > > > > > > > > | > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | < | | | | | | | | | | < < < > > > > > > > | 8869 8870 8871 8872 8873 8874 8875 8876 8877 8878 8879 8880 8881 8882 8883 8884 8885 8886 8887 8888 8889 8890 8891 8892 8893 8894 8895 8896 8897 8898 8899 8900 8901 8902 8903 8904 8905 8906 8907 8908 8909 8910 8911 8912 8913 8914 8915 8916 8917 8918 8919 8920 8921 8922 8923 8924 8925 8926 8927 8928 8929 8930 8931 8932 8933 8934 8935 8936 8937 8938 8939 8940 8941 8942 8943 8944 8945 8946 8947 8948 8949 8950 8951 8952 8953 8954 8955 8956 8957 8958 8959 8960 8961 8962 8963 8964 8965 8966 8967 8968 8969 8970 8971 8972 8973 8974 8975 8976 8977 8978 8979 8980 8981 8982 8983 8984 8985 8986 8987 8988 8989 8990 8991 8992 8993 8994 8995 8996 8997 8998 8999 9000 9001 9002 9003 9004 9005 9006 9007 9008 9009 9010 9011 9012 9013 9014 9015 9016 9017 9018 9019 9020 9021 9022 9023 9024 9025 9026 9027 9028 9029 9030 9031 9032 9033 9034 9035 9036 9037 9038 9039 9040 9041 9042 9043 9044 9045 9046 9047 9048 9049 9050 9051 9052 9053 9054 9055 9056 9057 9058 9059 9060 9061 9062 9063 9064 9065 9066 9067 9068 9069 9070 9071 9072 9073 9074 9075 9076 9077 9078 9079 9080 9081 9082 9083 9084 9085 9086 9087 9088 9089 9090 9091 9092 9093 9094 9095 9096 9097 9098 9099 9100 9101 9102 9103 9104 9105 9106 9107 9108 9109 9110 9111 9112 9113 9114 9115 9116 9117 9118 9119 9120 9121 9122 9123 9124 9125 9126 9127 9128 9129 9130 9131 9132 9133 9134 9135 9136 9137 9138 9139 9140 9141 9142 9143 9144 9145 9146 9147 9148 9149 9150 9151 9152 9153 9154 9155 9156 9157 9158 9159 9160 9161 9162 9163 9164 9165 9166 9167 9168 9169 9170 9171 9172 9173 9174 9175 9176 9177 9178 9179 9180 9181 9182 9183 9184 9185 9186 9187 9188 9189 9190 9191 9192 9193 9194 9195 9196 9197 9198 9199 9200 9201 9202 9203 9204 9205 9206 9207 9208 9209 9210 9211 9212 9213 9214 9215 9216 9217 9218 9219 9220 9221 9222 9223 9224 9225 9226 9227 9228 9229 9230 9231 9232 9233 9234 9235 9236 9237 9238 9239 9240 9241 9242 9243 9244 9245 9246 9247 9248 9249 9250 9251 9252 9253 9254 9255 9256 9257 9258 9259 9260 9261 9262 9263 9264 9265 9266 9267 9268 9269 9270 9271 9272 9273 9274 9275 9276 9277 9278 9279 9280 9281 9282 9283 9284 | if (s->publickey_blob) { sfree(s->publickey_blob); sfree(s->publickey_comment); } if (s->agent_response) sfree(s->agent_response); if (s->userauth_success) { /* * We've just received USERAUTH_SUCCESS, and we haven't sent any * packets since. Signal the transport layer to consider enacting * delayed compression. * * (Relying on we_are_in is not sufficient, as * draft-miller-secsh-compression-delayed is quite clear that it * triggers on USERAUTH_SUCCESS specifically, and we_are_in can * become set for other reasons.) */ do_ssh2_transport(ssh, "enabling delayed compression", -2, NULL); } /* * Now the connection protocol has started, one way or another. */ ssh->channels = newtree234(ssh_channelcmp); /* * Set up handlers for some connection protocol messages, so we * don't have to handle them repeatedly in this coroutine. */ ssh->packet_dispatch[SSH2_MSG_CHANNEL_WINDOW_ADJUST] = ssh2_msg_channel_window_adjust; ssh->packet_dispatch[SSH2_MSG_GLOBAL_REQUEST] = ssh2_msg_global_request; /* * Create the main session channel. */ if (ssh->cfg.ssh_no_shell) { ssh->mainchan = NULL; } else if (*ssh->cfg.ssh_nc_host) { /* * Just start a direct-tcpip channel and use it as the main * channel. */ ssh->mainchan = snew(struct ssh_channel); ssh->mainchan->ssh = ssh; ssh2_channel_init(ssh->mainchan); logeventf(ssh, "Opening direct-tcpip channel to %s:%d in place of session", ssh->cfg.ssh_nc_host, ssh->cfg.ssh_nc_port); s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN); ssh2_pkt_addstring(s->pktout, "direct-tcpip"); ssh2_pkt_adduint32(s->pktout, ssh->mainchan->localid); ssh2_pkt_adduint32(s->pktout, ssh->mainchan->v.v2.locwindow);/* our window size */ ssh2_pkt_adduint32(s->pktout, OUR_V2_MAXPKT); /* our max pkt size */ ssh2_pkt_addstring(s->pktout, ssh->cfg.ssh_nc_host); ssh2_pkt_adduint32(s->pktout, ssh->cfg.ssh_nc_port); /* * There's nothing meaningful to put in the originator * fields, but some servers insist on syntactically correct * information. */ ssh2_pkt_addstring(s->pktout, "0.0.0.0"); ssh2_pkt_adduint32(s->pktout, 0); ssh2_pkt_send(ssh, s->pktout); crWaitUntilV(pktin); if (pktin->type != SSH2_MSG_CHANNEL_OPEN_CONFIRMATION) { bombout(("Server refused to open a direct-tcpip channel")); crStopV; /* FIXME: error data comes back in FAILURE packet */ } if (ssh_pkt_getuint32(pktin) != ssh->mainchan->localid) { bombout(("Server's channel confirmation cited wrong channel")); crStopV; } ssh->mainchan->remoteid = ssh_pkt_getuint32(pktin); ssh->mainchan->halfopen = FALSE; ssh->mainchan->type = CHAN_MAINSESSION; ssh->mainchan->v.v2.remwindow = ssh_pkt_getuint32(pktin); ssh->mainchan->v.v2.remmaxpkt = ssh_pkt_getuint32(pktin); add234(ssh->channels, ssh->mainchan); update_specials_menu(ssh->frontend); logevent("Opened direct-tcpip channel"); ssh->ncmode = TRUE; } else { ssh->mainchan = snew(struct ssh_channel); ssh->mainchan->ssh = ssh; ssh2_channel_init(ssh->mainchan); s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN); ssh2_pkt_addstring(s->pktout, "session"); ssh2_pkt_adduint32(s->pktout, ssh->mainchan->localid); ssh2_pkt_adduint32(s->pktout, ssh->mainchan->v.v2.locwindow);/* our window size */ ssh2_pkt_adduint32(s->pktout, OUR_V2_MAXPKT); /* our max pkt size */ ssh2_pkt_send(ssh, s->pktout); crWaitUntilV(pktin); if (pktin->type != SSH2_MSG_CHANNEL_OPEN_CONFIRMATION) { bombout(("Server refused to open a session")); crStopV; /* FIXME: error data comes back in FAILURE packet */ } if (ssh_pkt_getuint32(pktin) != ssh->mainchan->localid) { bombout(("Server's channel confirmation cited wrong channel")); crStopV; } ssh->mainchan->remoteid = ssh_pkt_getuint32(pktin); ssh->mainchan->halfopen = FALSE; ssh->mainchan->type = CHAN_MAINSESSION; ssh->mainchan->v.v2.remwindow = ssh_pkt_getuint32(pktin); ssh->mainchan->v.v2.remmaxpkt = ssh_pkt_getuint32(pktin); add234(ssh->channels, ssh->mainchan); update_specials_menu(ssh->frontend); logevent("Opened channel for session"); ssh->ncmode = FALSE; } /* * Now we have a channel, make dispatch table entries for * general channel-based messages. */ ssh->packet_dispatch[SSH2_MSG_CHANNEL_DATA] = ssh->packet_dispatch[SSH2_MSG_CHANNEL_EXTENDED_DATA] = ssh2_msg_channel_data; ssh->packet_dispatch[SSH2_MSG_CHANNEL_EOF] = ssh2_msg_channel_eof; ssh->packet_dispatch[SSH2_MSG_CHANNEL_CLOSE] = ssh2_msg_channel_close; ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN_CONFIRMATION] = ssh2_msg_channel_open_confirmation; ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN_FAILURE] = ssh2_msg_channel_open_failure; ssh->packet_dispatch[SSH2_MSG_CHANNEL_REQUEST] = ssh2_msg_channel_request; ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN] = ssh2_msg_channel_open; if (ssh->mainchan && ssh->cfg.ssh_simple) { /* * This message indicates to the server that we promise * not to try to run any other channel in parallel with * this one, so it's safe for it to advertise a very large * window and leave the flow control to TCP. */ s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST); ssh2_pkt_adduint32(s->pktout, ssh->mainchan->remoteid); ssh2_pkt_addstring(s->pktout, "simple@putty.projects.tartarus.org"); ssh2_pkt_addbool(s->pktout, 0); /* no reply */ ssh2_pkt_send(ssh, s->pktout); } /* * Potentially enable X11 forwarding. */ if (ssh->mainchan && !ssh->ncmode && ssh->cfg.x11_forward && (ssh->x11disp = x11_setup_display(ssh->cfg.x11_display, ssh->cfg.x11_auth, &ssh->cfg))) { logevent("Requesting X11 forwarding"); s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST); ssh2_pkt_adduint32(s->pktout, ssh->mainchan->remoteid); ssh2_pkt_addstring(s->pktout, "x11-req"); ssh2_pkt_addbool(s->pktout, 1); /* want reply */ ssh2_pkt_addbool(s->pktout, 0); /* many connections */ ssh2_pkt_addstring(s->pktout, ssh->x11disp->remoteauthprotoname); /* * Note that while we blank the X authentication data here, we don't * take any special action to blank the start of an X11 channel, * so using MIT-MAGIC-COOKIE-1 and actually opening an X connection * without having session blanking enabled is likely to leak your * cookie into the log. */ dont_log_password(ssh, s->pktout, PKTLOG_BLANK); ssh2_pkt_addstring(s->pktout, ssh->x11disp->remoteauthdatastring); end_log_omission(ssh, s->pktout); ssh2_pkt_adduint32(s->pktout, ssh->x11disp->screennum); ssh2_pkt_send(ssh, s->pktout); crWaitUntilV(pktin); if (pktin->type != SSH2_MSG_CHANNEL_SUCCESS) { if (pktin->type != SSH2_MSG_CHANNEL_FAILURE) { bombout(("Unexpected response to X11 forwarding request:" " packet type %d", pktin->type)); crStopV; } logevent("X11 forwarding refused"); } else { logevent("X11 forwarding enabled"); ssh->X11_fwd_enabled = TRUE; } } /* * Enable port forwardings. */ ssh_setup_portfwd(ssh, &ssh->cfg); /* * Potentially enable agent forwarding. */ if (ssh->mainchan && !ssh->ncmode && ssh->cfg.agentfwd && agent_exists()) { logevent("Requesting OpenSSH-style agent forwarding"); s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST); ssh2_pkt_adduint32(s->pktout, ssh->mainchan->remoteid); ssh2_pkt_addstring(s->pktout, "auth-agent-req@openssh.com"); ssh2_pkt_addbool(s->pktout, 1); /* want reply */ ssh2_pkt_send(ssh, s->pktout); crWaitUntilV(pktin); if (pktin->type != SSH2_MSG_CHANNEL_SUCCESS) { if (pktin->type != SSH2_MSG_CHANNEL_FAILURE) { bombout(("Unexpected response to agent forwarding request:" " packet type %d", pktin->type)); crStopV; } logevent("Agent forwarding refused"); } else { logevent("Agent forwarding enabled"); ssh->agentfwd_enabled = TRUE; } } /* * Now allocate a pty for the session. */ if (ssh->mainchan && !ssh->ncmode && !ssh->cfg.nopty) { /* Unpick the terminal-speed string. */ /* XXX perhaps we should allow no speeds to be sent. */ ssh->ospeed = 38400; ssh->ispeed = 38400; /* last-resort defaults */ sscanf(ssh->cfg.termspeed, "%d,%d", &ssh->ospeed, &ssh->ispeed); /* Build the pty request. */ s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST); ssh2_pkt_adduint32(s->pktout, ssh->mainchan->remoteid); /* recipient channel */ ssh2_pkt_addstring(s->pktout, "pty-req"); ssh2_pkt_addbool(s->pktout, 1); /* want reply */ ssh2_pkt_addstring(s->pktout, ssh->cfg.termtype); ssh2_pkt_adduint32(s->pktout, ssh->term_width); ssh2_pkt_adduint32(s->pktout, ssh->term_height); ssh2_pkt_adduint32(s->pktout, 0); /* pixel width */ ssh2_pkt_adduint32(s->pktout, 0); /* pixel height */ ssh2_pkt_addstring_start(s->pktout); parse_ttymodes(ssh, ssh->cfg.ttymodes, ssh2_send_ttymode, (void *)s->pktout); ssh2_pkt_addbyte(s->pktout, SSH2_TTY_OP_ISPEED); ssh2_pkt_adduint32(s->pktout, ssh->ispeed); ssh2_pkt_addbyte(s->pktout, SSH2_TTY_OP_OSPEED); ssh2_pkt_adduint32(s->pktout, ssh->ospeed); ssh2_pkt_addstring_data(s->pktout, "\0", 1); /* TTY_OP_END */ ssh2_pkt_send(ssh, s->pktout); ssh->state = SSH_STATE_INTERMED; crWaitUntilV(pktin); if (pktin->type != SSH2_MSG_CHANNEL_SUCCESS) { if (pktin->type != SSH2_MSG_CHANNEL_FAILURE) { bombout(("Unexpected response to pty request:" " packet type %d", pktin->type)); crStopV; } c_write_str(ssh, "Server refused to allocate pty\r\n"); ssh->editing = ssh->echoing = 1; } else { logeventf(ssh, "Allocated pty (ospeed %dbps, ispeed %dbps)", ssh->ospeed, ssh->ispeed); } } else { ssh->editing = ssh->echoing = 1; } /* * Send environment variables. * * Simplest thing here is to send all the requests at once, and * then wait for a whole bunch of successes or failures. */ if (ssh->mainchan && !ssh->ncmode && *ssh->cfg.environmt) { char *e = ssh->cfg.environmt; char *var, *varend, *val; s->num_env = 0; while (*e) { var = e; while (*e && *e != '\t') e++; varend = e; if (*e == '\t') e++; val = e; while (*e) e++; e++; s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST); ssh2_pkt_adduint32(s->pktout, ssh->mainchan->remoteid); ssh2_pkt_addstring(s->pktout, "env"); ssh2_pkt_addbool(s->pktout, 1); /* want reply */ ssh2_pkt_addstring_start(s->pktout); ssh2_pkt_addstring_data(s->pktout, var, varend-var); ssh2_pkt_addstring(s->pktout, val); ssh2_pkt_send(ssh, s->pktout); s->num_env++; } logeventf(ssh, "Sent %d environment variables", s->num_env); s->env_ok = 0; s->env_left = s->num_env; while (s->env_left > 0) { crWaitUntilV(pktin); if (pktin->type != SSH2_MSG_CHANNEL_SUCCESS) { if (pktin->type != SSH2_MSG_CHANNEL_FAILURE) { bombout(("Unexpected response to environment request:" " packet type %d", pktin->type)); crStopV; } } else { s->env_ok++; } s->env_left--; } if (s->env_ok == s->num_env) { logevent("All environment variables successfully set"); } else if (s->env_ok == 0) { logevent("All environment variables refused"); c_write_str(ssh, "Server refused to set environment variables\r\n"); } else { logeventf(ssh, "%d environment variables refused", s->num_env - s->env_ok); c_write_str(ssh, "Server refused to set all environment variables\r\n"); } } /* * Start a shell or a remote command. We may have to attempt * this twice if the config data has provided a second choice * of command. */ if (ssh->mainchan && !ssh->ncmode) while (1) { int subsys; char *cmd; if (ssh->fallback_cmd) { subsys = ssh->cfg.ssh_subsys2; cmd = ssh->cfg.remote_cmd_ptr2; } else { subsys = ssh->cfg.ssh_subsys; cmd = ssh->cfg.remote_cmd_ptr; if (!cmd) cmd = ssh->cfg.remote_cmd; } s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST); ssh2_pkt_adduint32(s->pktout, ssh->mainchan->remoteid); /* recipient channel */ if (subsys) { ssh2_pkt_addstring(s->pktout, "subsystem"); ssh2_pkt_addbool(s->pktout, 1); /* want reply */ ssh2_pkt_addstring(s->pktout, cmd); } else if (*cmd) { ssh2_pkt_addstring(s->pktout, "exec"); ssh2_pkt_addbool(s->pktout, 1); /* want reply */ ssh2_pkt_addstring(s->pktout, cmd); } else { ssh2_pkt_addstring(s->pktout, "shell"); ssh2_pkt_addbool(s->pktout, 1); /* want reply */ } ssh2_pkt_send(ssh, s->pktout); crWaitUntilV(pktin); if (pktin->type != SSH2_MSG_CHANNEL_SUCCESS) { if (pktin->type != SSH2_MSG_CHANNEL_FAILURE) { bombout(("Unexpected response to shell/command request:" " packet type %d", pktin->type)); crStopV; } /* * We failed to start the command. If this is the * fallback command, we really are finished; if it's * not, and if the fallback command exists, try falling * back to it before complaining. */ if (!ssh->fallback_cmd && ssh->cfg.remote_cmd_ptr2 != NULL) { logevent("Primary command failed; attempting fallback"); ssh->fallback_cmd = TRUE; continue; } bombout(("Server refused to start a shell/command")); crStopV; } else { logevent("Started a shell/command"); } break; } ssh->state = SSH_STATE_SESSION; if (ssh->size_needed) ssh_size(ssh, ssh->term_width, ssh->term_height); if (ssh->eof_needed) ssh_special(ssh, TS_EOF); /* * All the initial channel requests are done, so install the default * failure handler. */ ssh->packet_dispatch[SSH2_MSG_CHANNEL_SUCCESS] = ssh2_msg_channel_success; ssh->packet_dispatch[SSH2_MSG_CHANNEL_FAILURE] = ssh2_msg_channel_failure; /* * Transfer data! */ if (ssh->ldisc) ldisc_send(ssh->ldisc, NULL, 0, 0);/* cause ldisc to notice changes */ if (ssh->mainchan) ssh->send_ok = 1; |
︙ | ︙ | |||
10160 10161 10162 10163 10164 10165 10166 | /* XXX maybe we should actually take notice of the return value */ ssh2_pkt_getbool(pktin); ssh_pkt_getstring(pktin, &msg, &msglen); logeventf(ssh, "Remote debug message: %.*s", msglen, msg); } | < < < < < < < < < < < < < < < < < < < | 9357 9358 9359 9360 9361 9362 9363 9364 9365 9366 9367 9368 9369 9370 | /* XXX maybe we should actually take notice of the return value */ ssh2_pkt_getbool(pktin); ssh_pkt_getstring(pktin, &msg, &msglen); logeventf(ssh, "Remote debug message: %.*s", msglen, msg); } static void ssh2_msg_something_unimplemented(Ssh ssh, struct Packet *pktin) { struct Packet *pktout; pktout = ssh2_pkt_init(SSH2_MSG_UNIMPLEMENTED); ssh2_pkt_adduint32(pktout, pktin->sequence); /* * UNIMPLEMENTED messages MUST appear in the same order as the |
︙ | ︙ | |||
10205 10206 10207 10208 10209 10210 10211 | /* * Most messages cause SSH2_MSG_UNIMPLEMENTED. */ for (i = 0; i < 256; i++) ssh->packet_dispatch[i] = ssh2_msg_something_unimplemented; /* | | | < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < | | > > > | > | | > > > > | | < < < < < < < < < < | | | < < < < > | | | < < < < | > > > < < < < < < | | | < < | 9383 9384 9385 9386 9387 9388 9389 9390 9391 9392 9393 9394 9395 9396 9397 9398 9399 9400 9401 9402 9403 9404 9405 9406 9407 9408 9409 9410 9411 9412 9413 9414 9415 9416 9417 9418 9419 9420 9421 9422 9423 9424 9425 9426 9427 9428 9429 9430 9431 9432 9433 9434 9435 9436 9437 9438 9439 9440 9441 9442 9443 9444 9445 9446 9447 9448 9449 9450 9451 9452 9453 9454 9455 9456 9457 9458 9459 9460 9461 9462 9463 9464 9465 9466 9467 9468 9469 9470 9471 9472 9473 9474 9475 9476 9477 9478 9479 9480 9481 9482 9483 9484 9485 9486 9487 9488 9489 9490 9491 9492 9493 9494 9495 9496 9497 9498 9499 9500 9501 9502 9503 9504 9505 9506 9507 9508 9509 9510 9511 9512 9513 9514 9515 9516 9517 9518 9519 9520 9521 9522 9523 9524 9525 9526 9527 9528 9529 9530 9531 9532 9533 9534 9535 9536 9537 9538 9539 9540 9541 9542 9543 9544 9545 9546 9547 9548 9549 9550 9551 9552 9553 9554 9555 9556 9557 9558 9559 9560 9561 9562 9563 9564 9565 9566 9567 9568 9569 9570 9571 9572 9573 9574 9575 9576 9577 9578 9579 9580 9581 9582 9583 9584 9585 9586 9587 9588 9589 9590 9591 9592 9593 9594 9595 9596 9597 9598 9599 9600 9601 9602 9603 9604 9605 9606 9607 9608 9609 9610 9611 9612 9613 9614 9615 9616 9617 | /* * Most messages cause SSH2_MSG_UNIMPLEMENTED. */ for (i = 0; i < 256; i++) ssh->packet_dispatch[i] = ssh2_msg_something_unimplemented; /* * Any message we actually understand, we set to NULL so that * the coroutines will get it. */ ssh->packet_dispatch[SSH2_MSG_UNIMPLEMENTED] = NULL; ssh->packet_dispatch[SSH2_MSG_SERVICE_REQUEST] = NULL; ssh->packet_dispatch[SSH2_MSG_SERVICE_ACCEPT] = NULL; ssh->packet_dispatch[SSH2_MSG_KEXINIT] = NULL; ssh->packet_dispatch[SSH2_MSG_NEWKEYS] = NULL; ssh->packet_dispatch[SSH2_MSG_KEXDH_INIT] = NULL; ssh->packet_dispatch[SSH2_MSG_KEXDH_REPLY] = NULL; /* ssh->packet_dispatch[SSH2_MSG_KEX_DH_GEX_REQUEST] = NULL; duplicate case value */ /* ssh->packet_dispatch[SSH2_MSG_KEX_DH_GEX_GROUP] = NULL; duplicate case value */ ssh->packet_dispatch[SSH2_MSG_KEX_DH_GEX_INIT] = NULL; ssh->packet_dispatch[SSH2_MSG_KEX_DH_GEX_REPLY] = NULL; ssh->packet_dispatch[SSH2_MSG_USERAUTH_REQUEST] = NULL; ssh->packet_dispatch[SSH2_MSG_USERAUTH_FAILURE] = NULL; ssh->packet_dispatch[SSH2_MSG_USERAUTH_SUCCESS] = NULL; ssh->packet_dispatch[SSH2_MSG_USERAUTH_BANNER] = NULL; ssh->packet_dispatch[SSH2_MSG_USERAUTH_PK_OK] = NULL; /* ssh->packet_dispatch[SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ] = NULL; duplicate case value */ /* ssh->packet_dispatch[SSH2_MSG_USERAUTH_INFO_REQUEST] = NULL; duplicate case value */ ssh->packet_dispatch[SSH2_MSG_USERAUTH_INFO_RESPONSE] = NULL; ssh->packet_dispatch[SSH2_MSG_GLOBAL_REQUEST] = NULL; ssh->packet_dispatch[SSH2_MSG_REQUEST_SUCCESS] = NULL; ssh->packet_dispatch[SSH2_MSG_REQUEST_FAILURE] = NULL; ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN] = NULL; ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN_CONFIRMATION] = NULL; ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN_FAILURE] = NULL; ssh->packet_dispatch[SSH2_MSG_CHANNEL_WINDOW_ADJUST] = NULL; ssh->packet_dispatch[SSH2_MSG_CHANNEL_DATA] = NULL; ssh->packet_dispatch[SSH2_MSG_CHANNEL_EXTENDED_DATA] = NULL; ssh->packet_dispatch[SSH2_MSG_CHANNEL_EOF] = NULL; ssh->packet_dispatch[SSH2_MSG_CHANNEL_CLOSE] = NULL; ssh->packet_dispatch[SSH2_MSG_CHANNEL_REQUEST] = NULL; ssh->packet_dispatch[SSH2_MSG_CHANNEL_SUCCESS] = NULL; ssh->packet_dispatch[SSH2_MSG_CHANNEL_FAILURE] = NULL; /* * These special message types we install handlers for. */ ssh->packet_dispatch[SSH2_MSG_DISCONNECT] = ssh2_msg_disconnect; ssh->packet_dispatch[SSH2_MSG_IGNORE] = ssh_msg_ignore; /* shared with SSH-1 */ ssh->packet_dispatch[SSH2_MSG_DEBUG] = ssh2_msg_debug; } static void ssh2_timer(void *ctx, long now) { Ssh ssh = (Ssh)ctx; if (ssh->state == SSH_STATE_CLOSED) return; if (!ssh->kex_in_progress && ssh->cfg.ssh_rekey_time != 0 && now - ssh->next_rekey >= 0) { do_ssh2_transport(ssh, "timeout", -1, NULL); } } static void ssh2_protocol(Ssh ssh, void *vin, int inlen, struct Packet *pktin) { unsigned char *in = (unsigned char *)vin; if (ssh->state == SSH_STATE_CLOSED) return; if (pktin) { ssh->incoming_data_size += pktin->encrypted_len; if (!ssh->kex_in_progress && ssh->max_data_size != 0 && ssh->incoming_data_size > ssh->max_data_size) do_ssh2_transport(ssh, "too much data received", -1, NULL); } if (pktin && ssh->packet_dispatch[pktin->type]) { ssh->packet_dispatch[pktin->type](ssh, pktin); return; } if (!ssh->protocol_initial_phase_done || (pktin && pktin->type >= 20 && pktin->type < 50)) { if (do_ssh2_transport(ssh, in, inlen, pktin) && !ssh->protocol_initial_phase_done) { ssh->protocol_initial_phase_done = TRUE; /* * Allow authconn to initialise itself. */ do_ssh2_authconn(ssh, NULL, 0, NULL); } } else { do_ssh2_authconn(ssh, in, inlen, pktin); } } /* * Called to set up the connection. * * Returns an error message, or NULL on success. */ static const char *ssh_init(void *frontend_handle, void **backend_handle, Config *cfg, char *host, int port, char **realhost, int nodelay, int keepalive) { const char *p; Ssh ssh; ssh = snew(struct ssh_tag); ssh->cfg = *cfg; /* STRUCTURE COPY */ ssh->version = 0; /* when not ready yet */ ssh->s = NULL; ssh->cipher = NULL; ssh->v1_cipher_ctx = NULL; ssh->crcda_ctx = NULL; ssh->cscipher = NULL; ssh->cs_cipher_ctx = NULL; ssh->sccipher = NULL; ssh->sc_cipher_ctx = NULL; ssh->csmac = NULL; ssh->cs_mac_ctx = NULL; ssh->scmac = NULL; ssh->sc_mac_ctx = NULL; ssh->cscomp = NULL; ssh->cs_comp_ctx = NULL; ssh->sccomp = NULL; ssh->sc_comp_ctx = NULL; ssh->kex = NULL; ssh->kex_ctx = NULL; ssh->hostkey = NULL; ssh->exitcode = -1; ssh->close_expected = FALSE; ssh->clean_exit = FALSE; ssh->state = SSH_STATE_PREPACKET; ssh->size_needed = FALSE; ssh->eof_needed = FALSE; ssh->ldisc = NULL; ssh->logctx = NULL; ssh->deferred_send_data = NULL; ssh->deferred_len = 0; ssh->deferred_size = 0; ssh->fallback_cmd = 0; ssh->pkt_kctx = SSH2_PKTCTX_NOKEX; ssh->pkt_actx = SSH2_PKTCTX_NOAUTH; ssh->x11disp = NULL; ssh->v1_compressing = FALSE; ssh->v2_outgoing_sequence = 0; ssh->ssh1_rdpkt_crstate = 0; ssh->ssh2_rdpkt_crstate = 0; ssh->do_ssh_init_crstate = 0; ssh->ssh_gotdata_crstate = 0; ssh->do_ssh1_connection_crstate = 0; ssh->do_ssh1_login_crstate = 0; ssh->do_ssh2_transport_crstate = 0; ssh->do_ssh2_authconn_crstate = 0; ssh->do_ssh_init_state = NULL; ssh->do_ssh1_login_state = NULL; ssh->do_ssh2_transport_state = NULL; ssh->do_ssh2_authconn_state = NULL; ssh->v_c = NULL; ssh->v_s = NULL; ssh->mainchan = NULL; ssh->throttled_all = 0; ssh->v1_stdout_throttling = 0; ssh->queue = NULL; ssh->queuelen = ssh->queuesize = 0; ssh->queueing = FALSE; ssh->qhead = ssh->qtail = NULL; ssh->deferred_rekey_reason = NULL; bufchain_init(&ssh->queued_incoming_data); ssh->frozen = FALSE; *backend_handle = ssh; #ifdef MSCRYPTOAPI if (crypto_startup() == 0) return "Microsoft high encryption pack not installed!"; #endif ssh->frontend = frontend_handle; ssh->term_width = ssh->cfg.width; ssh->term_height = ssh->cfg.height; ssh->channels = NULL; ssh->rportfwds = NULL; ssh->portfwds = NULL; ssh->send_ok = 0; ssh->editing = 0; ssh->echoing = 0; ssh->conn_throttle_count = 0; ssh->overall_bufsize = 0; ssh->fallback_cmd = 0; ssh->protocol = NULL; ssh->protocol_initial_phase_done = FALSE; ssh->pinger = NULL; ssh->incoming_data_size = ssh->outgoing_data_size = ssh->deferred_data_size = 0L; ssh->max_data_size = parse_blocksize(ssh->cfg.ssh_rekey_data); ssh->kex_in_progress = FALSE; #ifndef NO_GSSAPI ssh->gsslibs = NULL; #endif p = connect_to_host(ssh, host, port, realhost, nodelay, keepalive); if (p != NULL) return p; random_ref(); return NULL; } static void ssh_free(void *handle) { Ssh ssh = (Ssh) handle; struct ssh_channel *c; struct ssh_rportfwd *pf; if (ssh->v1_cipher_ctx) ssh->cipher->free_context(ssh->v1_cipher_ctx); if (ssh->cs_cipher_ctx) ssh->cscipher->free_context(ssh->cs_cipher_ctx); if (ssh->sc_cipher_ctx) ssh->sccipher->free_context(ssh->sc_cipher_ctx); |
︙ | ︙ | |||
10519 10520 10521 10522 10523 10524 10525 | while (ssh->queuelen-- > 0) ssh_free_packet(ssh->queue[ssh->queuelen]); sfree(ssh->queue); while (ssh->qhead) { struct queued_handler *qh = ssh->qhead; ssh->qhead = qh->next; | | | | | | < < < < < < < < < < < < < < < < < < < < | < | | < | | | | | | < < | < | | | < < < < | < < | | 9638 9639 9640 9641 9642 9643 9644 9645 9646 9647 9648 9649 9650 9651 9652 9653 9654 9655 9656 9657 9658 9659 9660 9661 9662 9663 9664 9665 9666 9667 9668 9669 9670 9671 9672 9673 9674 9675 9676 9677 9678 9679 9680 9681 9682 9683 9684 9685 9686 9687 9688 9689 9690 9691 9692 9693 9694 9695 9696 9697 9698 9699 9700 9701 9702 9703 9704 9705 9706 9707 9708 9709 9710 9711 9712 9713 9714 9715 9716 9717 9718 9719 9720 9721 9722 9723 9724 9725 9726 9727 9728 9729 9730 9731 9732 9733 9734 9735 9736 9737 9738 9739 9740 9741 9742 9743 9744 9745 9746 9747 9748 9749 9750 9751 9752 9753 9754 9755 9756 9757 9758 | while (ssh->queuelen-- > 0) ssh_free_packet(ssh->queue[ssh->queuelen]); sfree(ssh->queue); while (ssh->qhead) { struct queued_handler *qh = ssh->qhead; ssh->qhead = qh->next; sfree(ssh->qhead); } ssh->qhead = ssh->qtail = NULL; if (ssh->channels) { while ((c = delpos234(ssh->channels, 0)) != NULL) { switch (c->type) { case CHAN_X11: if (c->u.x11.s != NULL) x11_close(c->u.x11.s); break; case CHAN_SOCKDATA: case CHAN_SOCKDATA_DORMANT: if (c->u.pfd.s != NULL) pfd_close(c->u.pfd.s); break; } sfree(c); } freetree234(ssh->channels); ssh->channels = NULL; } if (ssh->rportfwds) { while ((pf = delpos234(ssh->rportfwds, 0)) != NULL) free_rportfwd(pf); freetree234(ssh->rportfwds); ssh->rportfwds = NULL; } sfree(ssh->deferred_send_data); if (ssh->x11disp) x11_free_display(ssh->x11disp); sfree(ssh->do_ssh_init_state); sfree(ssh->do_ssh1_login_state); sfree(ssh->do_ssh2_transport_state); sfree(ssh->do_ssh2_authconn_state); sfree(ssh->v_c); sfree(ssh->v_s); sfree(ssh->fullhostname); if (ssh->crcda_ctx) { crcda_free_context(ssh->crcda_ctx); ssh->crcda_ctx = NULL; } if (ssh->s) ssh_do_close(ssh, TRUE); expire_timer_context(ssh); if (ssh->pinger) pinger_free(ssh->pinger); bufchain_clear(&ssh->queued_incoming_data); #ifndef NO_GSSAPI if (ssh->gsslibs) ssh_gss_cleanup(ssh->gsslibs); #endif sfree(ssh); random_unref(); } /* * Reconfigure the SSH backend. */ static void ssh_reconfig(void *handle, Config *cfg) { Ssh ssh = (Ssh) handle; char *rekeying = NULL, rekey_mandatory = FALSE; unsigned long old_max_data_size; pinger_reconfig(ssh->pinger, &ssh->cfg, cfg); if (ssh->portfwds) ssh_setup_portfwd(ssh, cfg); if (ssh->cfg.ssh_rekey_time != cfg->ssh_rekey_time && cfg->ssh_rekey_time != 0) { long new_next = ssh->last_rekey + cfg->ssh_rekey_time*60*TICKSPERSEC; long now = GETTICKCOUNT(); if (new_next - now < 0) { rekeying = "timeout shortened"; } else { ssh->next_rekey = schedule_timer(new_next - now, ssh2_timer, ssh); } } old_max_data_size = ssh->max_data_size; ssh->max_data_size = parse_blocksize(cfg->ssh_rekey_data); if (old_max_data_size != ssh->max_data_size && ssh->max_data_size != 0) { if (ssh->outgoing_data_size > ssh->max_data_size || ssh->incoming_data_size > ssh->max_data_size) rekeying = "data limit lowered"; } if (ssh->cfg.compression != cfg->compression) { rekeying = "compression setting changed"; rekey_mandatory = TRUE; } if (ssh->cfg.ssh2_des_cbc != cfg->ssh2_des_cbc || memcmp(ssh->cfg.ssh_cipherlist, cfg->ssh_cipherlist, sizeof(ssh->cfg.ssh_cipherlist))) { rekeying = "cipher settings changed"; rekey_mandatory = TRUE; } ssh->cfg = *cfg; /* STRUCTURE COPY */ if (rekeying) { if (!ssh->kex_in_progress) { do_ssh2_transport(ssh, rekeying, -1, NULL); } else if (rekey_mandatory) { ssh->deferred_rekey_reason = rekeying; } } } |
︙ | ︙ | |||
10702 10703 10704 10705 10706 10707 10708 | override_value = 0; if (ssh->throttled_all) override_value = ssh->overall_bufsize; if (ssh->version == 1) { return override_value; } else if (ssh->version == 2) { | | | 9790 9791 9792 9793 9794 9795 9796 9797 9798 9799 9800 9801 9802 9803 9804 | override_value = 0; if (ssh->throttled_all) override_value = ssh->overall_bufsize; if (ssh->version == 1) { return override_value; } else if (ssh->version == 2) { if (!ssh->mainchan || ssh->mainchan->closes > 0) return override_value; else return (override_value + bufchain_size(&ssh->mainchan->v.v2.outbuffer)); } return 0; |
︙ | ︙ | |||
10732 10733 10734 10735 10736 10737 10738 | case SSH_STATE_PREPACKET: case SSH_STATE_CLOSED: break; /* do nothing */ case SSH_STATE_INTERMED: ssh->size_needed = TRUE; /* buffer for later */ break; case SSH_STATE_SESSION: | | > > | | | 9820 9821 9822 9823 9824 9825 9826 9827 9828 9829 9830 9831 9832 9833 9834 9835 9836 9837 9838 9839 9840 9841 9842 9843 9844 | case SSH_STATE_PREPACKET: case SSH_STATE_CLOSED: break; /* do nothing */ case SSH_STATE_INTERMED: ssh->size_needed = TRUE; /* buffer for later */ break; case SSH_STATE_SESSION: if (!ssh->cfg.nopty) { if (ssh->version == 1) { send_packet(ssh, SSH1_CMSG_WINDOW_SIZE, PKT_INT, ssh->term_height, PKT_INT, ssh->term_width, PKT_INT, 0, PKT_INT, 0, PKT_END); } else if (ssh->mainchan) { pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST); ssh2_pkt_adduint32(pktout, ssh->mainchan->remoteid); ssh2_pkt_addstring(pktout, "window-change"); ssh2_pkt_addbool(pktout, 0); ssh2_pkt_adduint32(pktout, ssh->term_width); ssh2_pkt_adduint32(pktout, ssh->term_height); ssh2_pkt_adduint32(pktout, 0); ssh2_pkt_adduint32(pktout, 0); ssh2_pkt_send(ssh, pktout); } } |
︙ | ︙ | |||
10811 10812 10813 10814 10815 10816 10817 | * won't cope with it, since we wouldn't bother sending it if * asked anyway. */ if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH1_IGNORE)) ADD_SPECIALS(ssh1_ignore_special); } else if (ssh->version == 2) { if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE)) ADD_SPECIALS(ssh2_ignore_special); | | | 9901 9902 9903 9904 9905 9906 9907 9908 9909 9910 9911 9912 9913 9914 9915 | * won't cope with it, since we wouldn't bother sending it if * asked anyway. */ if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH1_IGNORE)) ADD_SPECIALS(ssh1_ignore_special); } else if (ssh->version == 2) { if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE)) ADD_SPECIALS(ssh2_ignore_special); if (!(ssh->remote_bugs & BUG_SSH2_REKEY)) ADD_SPECIALS(ssh2_rekey_special); if (ssh->mainchan) ADD_SPECIALS(ssh2_session_specials); } /* else we're not ready yet */ if (i) { ADD_SPECIALS(specials_end); |
︙ | ︙ | |||
10849 10850 10851 10852 10853 10854 10855 | if (code == TS_EOF) ssh->eof_needed = TRUE; return; } if (ssh->version == 1) { send_packet(ssh, SSH1_CMSG_EOF, PKT_END); } else if (ssh->mainchan) { | > | > | < | > > > | 9939 9940 9941 9942 9943 9944 9945 9946 9947 9948 9949 9950 9951 9952 9953 9954 9955 9956 9957 9958 9959 9960 9961 9962 9963 9964 9965 9966 9967 9968 9969 9970 9971 9972 9973 9974 9975 9976 9977 9978 9979 9980 9981 9982 9983 9984 9985 | if (code == TS_EOF) ssh->eof_needed = TRUE; return; } if (ssh->version == 1) { send_packet(ssh, SSH1_CMSG_EOF, PKT_END); } else if (ssh->mainchan) { struct Packet *pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_EOF); ssh2_pkt_adduint32(pktout, ssh->mainchan->remoteid); ssh2_pkt_send(ssh, pktout); ssh->send_ok = 0; /* now stop trying to read from stdin */ } logevent("Sent EOF message"); } else if (code == TS_PING || code == TS_NOP) { if (ssh->state == SSH_STATE_CLOSED || ssh->state == SSH_STATE_PREPACKET) return; if (ssh->version == 1) { if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH1_IGNORE)) send_packet(ssh, SSH1_MSG_IGNORE, PKT_STR, "", PKT_END); } else { if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE)) { pktout = ssh2_pkt_init(SSH2_MSG_IGNORE); ssh2_pkt_addstring_start(pktout); ssh2_pkt_send_noqueue(ssh, pktout); } } } else if (code == TS_REKEY) { if (!ssh->kex_in_progress && ssh->version == 2) { do_ssh2_transport(ssh, "at user request", -1, NULL); } } else if (code == TS_BRK) { if (ssh->state == SSH_STATE_CLOSED || ssh->state == SSH_STATE_PREPACKET) return; if (ssh->version == 1) { logevent("Unable to send BREAK signal in SSH-1"); } else if (ssh->mainchan) { pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST); ssh2_pkt_adduint32(pktout, ssh->mainchan->remoteid); ssh2_pkt_addstring(pktout, "break"); ssh2_pkt_addbool(pktout, 0); ssh2_pkt_adduint32(pktout, 0); /* default break length */ ssh2_pkt_send(ssh, pktout); } } else { /* Is is a POSIX signal? */ char *signame = NULL; if (code == TS_SIGABRT) signame = "ABRT"; |
︙ | ︙ | |||
10902 10903 10904 10905 10906 10907 10908 | if (code == TS_SIGUSR1) signame = "USR1"; if (code == TS_SIGUSR2) signame = "USR2"; /* The SSH-2 protocol does in principle support arbitrary named * signals, including signame@domain, but we don't support those. */ if (signame) { /* It's a signal. */ if (ssh->version == 2 && ssh->mainchan) { | | > > > | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < | > | > > > | 9996 9997 9998 9999 10000 10001 10002 10003 10004 10005 10006 10007 10008 10009 10010 10011 10012 10013 10014 10015 10016 10017 10018 10019 10020 10021 10022 10023 10024 10025 10026 10027 10028 10029 10030 10031 10032 10033 10034 10035 10036 10037 10038 10039 10040 10041 10042 10043 10044 10045 10046 10047 10048 10049 10050 10051 10052 10053 10054 10055 10056 10057 10058 10059 10060 10061 10062 10063 10064 10065 10066 10067 10068 10069 10070 10071 10072 10073 10074 10075 10076 10077 10078 10079 10080 10081 10082 10083 10084 10085 10086 10087 10088 10089 10090 | if (code == TS_SIGUSR1) signame = "USR1"; if (code == TS_SIGUSR2) signame = "USR2"; /* The SSH-2 protocol does in principle support arbitrary named * signals, including signame@domain, but we don't support those. */ if (signame) { /* It's a signal. */ if (ssh->version == 2 && ssh->mainchan) { pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST); ssh2_pkt_adduint32(pktout, ssh->mainchan->remoteid); ssh2_pkt_addstring(pktout, "signal"); ssh2_pkt_addbool(pktout, 0); ssh2_pkt_addstring(pktout, signame); ssh2_pkt_send(ssh, pktout); logeventf(ssh, "Sent signal SIG%s", signame); } } else { /* Never heard of it. Do nothing */ } } } void *new_sock_channel(void *handle, Socket s) { Ssh ssh = (Ssh) handle; struct ssh_channel *c; c = snew(struct ssh_channel); c->ssh = ssh; ssh2_channel_init(c); c->halfopen = TRUE; c->type = CHAN_SOCKDATA_DORMANT;/* identify channel type */ c->u.pfd.s = s; add234(ssh->channels, c); return c; } /* * This is called when stdout/stderr (the entity to which * from_backend sends data) manages to clear some backlog. */ static void ssh_unthrottle(void *handle, int bufsize) { Ssh ssh = (Ssh) handle; int buflimit; if (ssh->version == 1) { if (ssh->v1_stdout_throttling && bufsize < SSH1_BUFFER_LIMIT) { ssh->v1_stdout_throttling = 0; ssh_throttle_conn(ssh, -1); } } else { if (ssh->mainchan) { ssh2_set_window(ssh->mainchan, bufsize < ssh->mainchan->v.v2.locmaxwin ? ssh->mainchan->v.v2.locmaxwin - bufsize : 0); if (ssh->cfg.ssh_simple) buflimit = 0; else buflimit = ssh->mainchan->v.v2.locmaxwin; if (ssh->mainchan->throttling_conn && bufsize <= buflimit) { ssh->mainchan->throttling_conn = 0; ssh_throttle_conn(ssh, -1); } } } } void ssh_send_port_open(void *channel, char *hostname, int port, char *org) { struct ssh_channel *c = (struct ssh_channel *)channel; Ssh ssh = c->ssh; struct Packet *pktout; logeventf(ssh, "Opening forwarded connection to %s:%d", hostname, port); if (ssh->version == 1) { send_packet(ssh, SSH1_MSG_PORT_OPEN, PKT_INT, c->localid, PKT_STR, hostname, PKT_INT, port, /* PKT_STR, <org:orgport>, */ PKT_END); } else { pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN); ssh2_pkt_addstring(pktout, "direct-tcpip"); ssh2_pkt_adduint32(pktout, c->localid); ssh2_pkt_adduint32(pktout, c->v.v2.locwindow);/* our window size */ ssh2_pkt_adduint32(pktout, OUR_V2_MAXPKT); /* our max pkt size */ ssh2_pkt_addstring(pktout, hostname); ssh2_pkt_adduint32(pktout, port); /* * We make up values for the originator data; partly it's * too much hassle to keep track, and partly I'm not * convinced the server should be told details like that * about my local network configuration. |
︙ | ︙ |
Changes to ssh.h.
1 2 3 4 5 6 7 8 9 10 | #include <stdio.h> #include <string.h> #include "puttymem.h" #include "tree234.h" #include "network.h" #include "int64.h" #include "misc.h" struct ssh_channel; | > > > > < > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | #include <stdio.h> #include <string.h> #include "puttymem.h" #include "tree234.h" #include "network.h" #include "int64.h" #include "misc.h" /* PuTTY SC start */ #include "pkcs11.h" /* PuTTY SC end */ struct ssh_channel; extern void sshfwd_close(struct ssh_channel *c); extern int sshfwd_write(struct ssh_channel *c, char *, int); extern void sshfwd_unthrottle(struct ssh_channel *c, int bufsize); /* * Useful thing. */ #ifndef lenof #define lenof(x) ( (sizeof((x))) / (sizeof(*(x)))) #endif |
︙ | ︙ | |||
171 172 173 174 175 176 177 | typedef struct { uint32 h[5]; unsigned char block[64]; int blkused; uint32 lenhi, lenlo; } SHA_State; void SHA_Init(SHA_State * s); | | | | 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | typedef struct { uint32 h[5]; unsigned char block[64]; int blkused; uint32 lenhi, lenlo; } SHA_State; void SHA_Init(SHA_State * s); void SHA_Bytes(SHA_State * s, void *p, int len); void SHA_Final(SHA_State * s, unsigned char *output); void SHA_Simple(void *p, int len, unsigned char *output); void hmac_sha1_simple(void *key, int keylen, void *data, int datalen, unsigned char *output); typedef struct { uint32 h[8]; unsigned char block[64]; int blkused; |
︙ | ︙ | |||
335 336 337 338 339 340 341 | extern const struct ssh_signkey ssh_dss; extern const struct ssh_signkey ssh_rsa; extern const struct ssh_mac ssh_hmac_md5; extern const struct ssh_mac ssh_hmac_sha1; extern const struct ssh_mac ssh_hmac_sha1_buggy; extern const struct ssh_mac ssh_hmac_sha1_96; extern const struct ssh_mac ssh_hmac_sha1_96_buggy; | < | 296 297 298 299 300 301 302 303 304 305 306 307 308 309 | extern const struct ssh_signkey ssh_dss; extern const struct ssh_signkey ssh_rsa; extern const struct ssh_mac ssh_hmac_md5; extern const struct ssh_mac ssh_hmac_sha1; extern const struct ssh_mac ssh_hmac_sha1_buggy; extern const struct ssh_mac ssh_hmac_sha1_96; extern const struct ssh_mac ssh_hmac_sha1_96_buggy; void *aes_make_context(void); void aes_free_context(void *handle); void aes128_key(void *handle, unsigned char *key); void aes192_key(void *handle, unsigned char *key); void aes256_key(void *handle, unsigned char *key); void aes_iv(void *handle, unsigned char *iv); |
︙ | ︙ | |||
368 369 370 371 372 373 374 | int random_byte(void); void random_add_noise(void *noise, int length); void random_add_heavynoise(void *noise, int length); void logevent(void *, const char *); | < < | | > | > > > > > | > | < | | | < < < < < < > > > > > > > < < < < < < < < < < < < < < < < < < < < < < < < | > | < < | | | < | | | > | 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 | int random_byte(void); void random_add_noise(void *noise, int length); void random_add_heavynoise(void *noise, int length); void logevent(void *, const char *); /* Allocate and register a new channel for port forwarding */ void *new_sock_channel(void *handle, Socket s); void ssh_send_port_open(void *channel, char *hostname, int port, char *org); /* Exports from portfwd.c */ extern const char *pfd_newconnect(Socket * s, char *hostname, int port, void *c, const Config *cfg, int addressfamily); /* desthost == NULL indicates dynamic (SOCKS) port forwarding */ extern const char *pfd_addforward(char *desthost, int destport, char *srcaddr, int port, void *backhandle, const Config *cfg, void **sockdata, int address_family); extern void pfd_close(Socket s); extern void pfd_terminate(void *sockdata); extern int pfd_send(Socket s, char *data, int len); extern void pfd_confirm(Socket s); extern void pfd_unthrottle(Socket s); extern void pfd_override_throttle(Socket s, int enable); /* Exports from x11fwd.c */ enum { X11_TRANS_IPV4 = 0, X11_TRANS_IPV6 = 6, X11_TRANS_UNIX = 256 }; struct X11Display { /* Broken-down components of the display name itself */ int unixdomain; char *hostname; int displaynum; int screennum; /* OSX sometimes replaces all the above with a full Unix-socket pathname */ char *unixsocketpath; /* PuTTY networking SockAddr to connect to the display, and associated * gubbins */ SockAddr addr; int port; char *realhost; /* Auth details we invented for the virtual display on the SSH server. */ int remoteauthproto; unsigned char *remoteauthdata; int remoteauthdatalen; char *remoteauthprotoname; char *remoteauthdatastring; /* Our local auth details for talking to the real X display. */ int localauthproto; unsigned char *localauthdata; int localauthdatalen; /* * Used inside x11fwd.c to remember recently seen * XDM-AUTHORIZATION-1 strings, to avoid replay attacks. */ tree234 *xdmseen; }; /* * x11_setup_display() parses the display variable and fills in an * X11Display structure. Some remote auth details are invented; * the supplied authtype parameter configures the preferred * authorisation protocol to use at the remote end. The local auth * details are looked up by calling platform_get_x11_auth. */ extern struct X11Display *x11_setup_display(char *display, int authtype, const Config *); void x11_free_display(struct X11Display *disp); extern const char *x11_init(Socket *, struct X11Display *, void *, const char *, int, const Config *); extern void x11_close(Socket); extern int x11_send(Socket, char *, int); extern void x11_unthrottle(Socket s); extern void x11_override_throttle(Socket s, int enable); char *x11_display(const char *display); /* Platform-dependent X11 functions */ extern void platform_get_x11_auth(struct X11Display *display, const Config *); /* examine a mostly-filled-in X11Display and fill in localauth* */ extern const int platform_uses_x11_unix_by_default; /* choose default X transport in the absence of a specified one */ SockAddr platform_get_x11_unix_address(const char *path, int displaynum); /* make up a SockAddr naming the address for displaynum */ char *platform_get_x_display(void); /* allocated local X display string, if any */ |
︙ | ︙ | |||
488 489 490 491 492 493 494 | * platform_get_x11_auth() will work by finding their system's * .Xauthority file, adjusting the display details if necessary * for local oddities like Unix-domain socket transport, and * calling this function to do the rest of the work. */ void x11_get_auth_from_authfile(struct X11Display *display, const char *authfilename); | < < | 428 429 430 431 432 433 434 435 436 437 438 439 440 441 | * platform_get_x11_auth() will work by finding their system's * .Xauthority file, adjusting the display details if necessary * for local oddities like Unix-domain socket transport, and * calling this function to do the rest of the work. */ void x11_get_auth_from_authfile(struct X11Display *display, const char *authfilename); Bignum copybn(Bignum b); Bignum bn_power_2(int n); void bn_restore_invariant(Bignum b); Bignum bignum_from_long(unsigned long n); void freebn(Bignum b); Bignum modpow(Bignum base, Bignum exp, Bignum mod); |
︙ | ︙ | |||
593 594 595 596 597 598 599 | void des3_encrypt_pubkey_ossh(unsigned char *key, unsigned char *iv, unsigned char *blk, int len); void aes256_encrypt_pubkey(unsigned char *key, unsigned char *blk, int len); void aes256_decrypt_pubkey(unsigned char *key, unsigned char *blk, int len); | < | < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 | void des3_encrypt_pubkey_ossh(unsigned char *key, unsigned char *iv, unsigned char *blk, int len); void aes256_encrypt_pubkey(unsigned char *key, unsigned char *blk, int len); void aes256_decrypt_pubkey(unsigned char *key, unsigned char *blk, int len); void des_encrypt_xdmauth(unsigned char *key, unsigned char *blk, int len); void des_decrypt_xdmauth(unsigned char *key, unsigned char *blk, int len); /* * For progress updates in the key generation utility. */ #define PROGFN_INITIALISE 1 #define PROGFN_LIN_PHASE 2 #define PROGFN_EXP_PHASE 3 #define PROGFN_PHASE_EXTENT 4 #define PROGFN_READY 5 #define PROGFN_PROGRESS 6 typedef void (*progfn_t) (void *param, int action, int phase, int progress); int rsa_generate(struct RSAKey *key, int bits, progfn_t pfn, void *pfnparam); int dsa_generate(struct dss_key *key, int bits, progfn_t pfn, void *pfnparam); Bignum primegen(int bits, int modulus, int residue, Bignum factor, int phase, progfn_t pfn, void *pfnparam); /* * zlib compression. */ void *zlib_compress_init(void); void zlib_compress_cleanup(void *); void *zlib_decompress_init(void); void zlib_decompress_cleanup(void *); int zlib_compress_block(void *, unsigned char *block, int len, unsigned char **outblock, int *outlen); int zlib_decompress_block(void *, unsigned char *block, int len, unsigned char **outblock, int *outlen); /* * SSH-1 agent messages. */ #define SSH1_AGENTC_REQUEST_RSA_IDENTITIES 1 #define SSH1_AGENT_RSA_IDENTITIES_ANSWER 2 #define SSH1_AGENTC_RSA_CHALLENGE 3 #define SSH1_AGENT_RSA_RESPONSE 4 |
︙ | ︙ | |||
779 780 781 782 783 784 785 | #define SSH2_AGENT_IDENTITIES_ANSWER 12 #define SSH2_AGENTC_SIGN_REQUEST 13 #define SSH2_AGENT_SIGN_RESPONSE 14 #define SSH2_AGENTC_ADD_IDENTITY 17 #define SSH2_AGENTC_REMOVE_IDENTITY 18 #define SSH2_AGENTC_REMOVE_ALL_IDENTITIES 19 | < < < < < < < < < < < < < < < < < < < < < < < < < < | 593 594 595 596 597 598 599 600 601 602 603 604 | #define SSH2_AGENT_IDENTITIES_ANSWER 12 #define SSH2_AGENTC_SIGN_REQUEST 13 #define SSH2_AGENT_SIGN_RESPONSE 14 #define SSH2_AGENTC_ADD_IDENTITY 17 #define SSH2_AGENTC_REMOVE_IDENTITY 18 #define SSH2_AGENTC_REMOVE_ALL_IDENTITIES 19 /* * Need this to warn about support for the original SSH-2 keyfile * format. */ void old_keyfile_warning(void); |
Changes to sshaes.c.
︙ | ︙ | |||
1153 1154 1155 1156 1157 1158 1159 | void aes256_encrypt_pubkey(unsigned char *key, unsigned char *blk, int len) { AESContext ctx; aes_setup(&ctx, 16, key, 32); memset(ctx.iv, 0, sizeof(ctx.iv)); aes_encrypt_cbc(blk, len, &ctx); | | | | 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 | void aes256_encrypt_pubkey(unsigned char *key, unsigned char *blk, int len) { AESContext ctx; aes_setup(&ctx, 16, key, 32); memset(ctx.iv, 0, sizeof(ctx.iv)); aes_encrypt_cbc(blk, len, &ctx); memset(&ctx, 0, sizeof(ctx)); } void aes256_decrypt_pubkey(unsigned char *key, unsigned char *blk, int len) { AESContext ctx; aes_setup(&ctx, 16, key, 32); memset(ctx.iv, 0, sizeof(ctx.iv)); aes_decrypt_cbc(blk, len, &ctx); memset(&ctx, 0, sizeof(ctx)); } static const struct ssh2_cipher ssh_aes128_ctr = { aes_make_context, aes_free_context, aes_iv, aes128_key, aes_ssh2_sdctr, aes_ssh2_sdctr, "aes128-ctr", 16, 128, 0, "AES-128 SDCTR" |
︙ | ︙ |
Changes to ssharcf.c.
︙ | ︙ | |||
71 72 73 74 75 76 77 | } static void arcfour_stir(ArcfourContext *ctx) { unsigned char *junk = snewn(1536, unsigned char); memset(junk, 0, 1536); arcfour_block(ctx, junk, 1536); | | | 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | } static void arcfour_stir(ArcfourContext *ctx) { unsigned char *junk = snewn(1536, unsigned char); memset(junk, 0, 1536); arcfour_block(ctx, junk, 1536); memset(junk, 0, 1536); sfree(junk); } static void arcfour128_key(void *handle, unsigned char *key) { ArcfourContext *ctx = (ArcfourContext *)handle; arcfour_setkey(ctx, key, 16); |
︙ | ︙ |
Changes to sshbn.c.
1 2 3 4 5 6 7 8 | /* * Bignum routines for RSA and DH and stuff. */ #include <stdio.h> #include <assert.h> #include <stdlib.h> #include <string.h> | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | /* * Bignum routines for RSA and DH and stuff. */ #include <stdio.h> #include <assert.h> #include <stdlib.h> #include <string.h> #include "misc.h" /* * Usage notes: * * Do not call the DIVMOD_WORD macro with expressions such as array * subscripts, as some implementations object to this (see below). |
︙ | ︙ | |||
117 118 119 120 121 122 123 | * nonzero. */ Bignum Zero = bnZero, One = bnOne; static Bignum newbn(int length) { | < < < < | | 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | * nonzero. */ Bignum Zero = bnZero, One = bnOne; static Bignum newbn(int length) { Bignum b = snewn(length + 1, BignumInt); if (!b) abort(); /* FIXME */ memset(b, 0, (length + 1) * sizeof(*b)); b[0] = length; return b; } |
︙ | ︙ | |||
149 150 151 152 153 154 155 | } void freebn(Bignum b) { /* * Burn the evidence, just in case. */ | | < < < < | | 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | } void freebn(Bignum b) { /* * Burn the evidence, just in case. */ memset(b, 0, sizeof(b[0]) * (b[0] + 1)); sfree(b); } Bignum bn_power_2(int n) { Bignum ret = newbn(n / BIGNUM_INT_BITS + 1); bignum_set_bit(ret, n, 1); return ret; } /* * Internal addition. Sets c = a - b, where 'a', 'b' and 'c' are all * big-endian arrays of 'len' BignumInts. Returns a BignumInt carried |
︙ | ︙ | |||
603 604 605 606 607 608 609 | int word = 1 + (shift / BIGNUM_INT_BITS); int bshift = shift % BIGNUM_INT_BITS; BignumDblInt addend; addend = (BignumDblInt)n << bshift; while (addend) { | < | 594 595 596 597 598 599 600 601 602 603 604 605 606 607 | int word = 1 + (shift / BIGNUM_INT_BITS); int bshift = shift % BIGNUM_INT_BITS; BignumDblInt addend; addend = (BignumDblInt)n << bshift; while (addend) { addend += number[word]; number[word] = (BignumInt) addend & BIGNUM_INT_MASK; addend >>= BIGNUM_INT_BITS; word++; } } |
︙ | ︙ | |||
630 631 632 633 634 635 636 | BignumInt *quot, int qshift) { BignumInt m0, m1; unsigned int h; int i, k; m0 = m[0]; | < | 620 621 622 623 624 625 626 627 628 629 630 631 632 633 | BignumInt *quot, int qshift) { BignumInt m0, m1; unsigned int h; int i, k; m0 = m[0]; if (mlen > 1) m1 = m[1]; else m1 = 0; for (i = 0; i <= alen - mlen; i++) { BignumDblInt t; |
︙ | ︙ | |||
822 823 824 825 826 827 828 | result = newbn(mod[0]); for (i = 0; i < mlen; i++) result[result[0] - i] = a[i + mlen]; while (result[0] > 1 && result[result[0]] == 0) result[0]--; /* Free temporary arrays */ | | > | > | > | > | > | 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 | result = newbn(mod[0]); for (i = 0; i < mlen; i++) result[result[0] - i] = a[i + mlen]; while (result[0] > 1 && result[result[0]] == 0) result[0]--; /* Free temporary arrays */ for (i = 0; i < 2 * mlen; i++) a[i] = 0; sfree(a); for (i = 0; i < scratchlen; i++) scratch[i] = 0; sfree(scratch); for (i = 0; i < 2 * mlen; i++) b[i] = 0; sfree(b); for (i = 0; i < mlen; i++) m[i] = 0; sfree(m); for (i = 0; i < mlen; i++) n[i] = 0; sfree(n); freebn(base); return result; } |
︙ | ︙ | |||
875 876 877 878 879 880 881 | * Compute the inverse of n mod r, for monty_reduce. (In fact we * want the inverse of _minus_ n mod r, but we'll sort that out * below.) */ len = mod[0]; r = bn_power_2(BIGNUM_INT_BITS * len); inv = modinv(mod, r); | < | 869 870 871 872 873 874 875 876 877 878 879 880 881 882 | * Compute the inverse of n mod r, for monty_reduce. (In fact we * want the inverse of _minus_ n mod r, but we'll sort that out * below.) */ len = mod[0]; r = bn_power_2(BIGNUM_INT_BITS * len); inv = modinv(mod, r); /* * Multiply the base by r mod n, to get it into Montgomery * representation. */ base2 = modmul(base, r, mod); freebn(base); |
︙ | ︙ | |||
968 969 970 971 972 973 974 | result = newbn(mod[0]); for (i = 0; i < len; i++) result[result[0] - i] = a[i + len]; while (result[0] > 1 && result[result[0]] == 0) result[0]--; /* Free temporary arrays */ | | > | > | > > | | > | > < < < < < < < < < < < < < | 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 | result = newbn(mod[0]); for (i = 0; i < len; i++) result[result[0] - i] = a[i + len]; while (result[0] > 1 && result[result[0]] == 0) result[0]--; /* Free temporary arrays */ for (i = 0; i < scratchlen; i++) scratch[i] = 0; sfree(scratch); for (i = 0; i < 2 * len; i++) a[i] = 0; sfree(a); for (i = 0; i < 2 * len; i++) b[i] = 0; sfree(b); for (i = 0; i < len; i++) mninv[i] = 0; sfree(mninv); for (i = 0; i < len; i++) n[i] = 0; sfree(n); for (i = 0; i < len; i++) x[i] = 0; sfree(x); return result; } /* * Compute (p * q) % mod. * The most significant word of mod MUST be non-zero. * We assume that the result array is the same size as the mod array. */ Bignum modmul(Bignum p, Bignum q, Bignum mod) { BignumInt *a, *n, *m, *o, *scratch; int mshift, scratchlen; int pqlen, mlen, rlen, i, j; Bignum result; /* Allocate m of size mlen, copy mod to m */ /* We use big endian internally */ mlen = mod[0]; m = snewn(mlen, BignumInt); for (j = 0; j < mlen; j++) m[j] = mod[mod[0] - j]; /* Shift m left to make msb bit set */ for (mshift = 0; mshift < BIGNUM_INT_BITS-1; mshift++) if ((m[0] << mshift) & BIGNUM_TOP_BIT) break; if (mshift) { for (i = 0; i < mlen - 1; i++) m[i] = (m[i] << mshift) | (m[i + 1] >> (BIGNUM_INT_BITS - mshift)); m[mlen - 1] = m[mlen - 1] << mshift; } pqlen = (p[0] > q[0] ? p[0] : q[0]); /* Allocate n of size pqlen, copy p to n */ n = snewn(pqlen, BignumInt); i = pqlen - p[0]; for (j = 0; j < i; j++) n[j] = 0; for (j = 0; j < (int)p[0]; j++) n[i + j] = p[p[0] - j]; |
︙ | ︙ | |||
1074 1075 1076 1077 1078 1079 1080 | result = newbn(rlen); for (i = 0; i < rlen; i++) result[result[0] - i] = a[i + 2 * pqlen - rlen]; while (result[0] > 1 && result[result[0]] == 0) result[0]--; /* Free temporary arrays */ | | > | > | > | > | > < < < < < < | 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 | result = newbn(rlen); for (i = 0; i < rlen; i++) result[result[0] - i] = a[i + 2 * pqlen - rlen]; while (result[0] > 1 && result[result[0]] == 0) result[0]--; /* Free temporary arrays */ for (i = 0; i < scratchlen; i++) scratch[i] = 0; sfree(scratch); for (i = 0; i < 2 * pqlen; i++) a[i] = 0; sfree(a); for (i = 0; i < mlen; i++) m[i] = 0; sfree(m); for (i = 0; i < pqlen; i++) n[i] = 0; sfree(n); for (i = 0; i < pqlen; i++) o[i] = 0; sfree(o); return result; } /* * Compute p % mod. * The most significant word of mod MUST be non-zero. * We assume that the result array is the same size as the mod array. * We optionally write out a quotient if `quotient' is non-NULL. * We can avoid writing out the result if `result' is NULL. */ static void bigdivmod(Bignum p, Bignum mod, Bignum result, Bignum quotient) { BignumInt *n, *m; int mshift; int plen, mlen, i, j; /* Allocate m of size mlen, copy mod to m */ /* We use big endian internally */ mlen = mod[0]; m = snewn(mlen, BignumInt); for (j = 0; j < mlen; j++) m[j] = mod[mod[0] - j]; |
︙ | ︙ | |||
1158 1159 1160 1161 1162 1163 1164 | for (i = 1; i <= (int)result[0]; i++) { int j = plen - i; result[i] = j >= 0 ? n[j] : 0; } } /* Free temporary arrays */ | | > | > < < | 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 | for (i = 1; i <= (int)result[0]; i++) { int j = plen - i; result[i] = j >= 0 ? n[j] : 0; } } /* Free temporary arrays */ for (i = 0; i < mlen; i++) m[i] = 0; sfree(m); for (i = 0; i < plen; i++) n[i] = 0; sfree(n); } /* * Decrement a number. */ void decbn(Bignum bn) { int i = 1; while (i < (int)bn[0] && bn[i] == 0) bn[i++] = BIGNUM_INT_MASK; bn[i]--; } Bignum bignum_from_bytes(const unsigned char *data, int nbytes) { Bignum result; int w, i; w = (nbytes + BIGNUM_INT_BYTES - 1) / BIGNUM_INT_BYTES; /* bytes->words */ result = newbn(w); for (i = 1; i <= w; i++) result[i] = 0; for (i = nbytes; i--;) { unsigned char byte = *data++; |
︙ | ︙ | |||
1258 1259 1260 1261 1262 1263 1264 | } /* * Return a byte from a bignum; 0 is least significant, etc. */ int bignum_byte(Bignum bn, int i) { | | | | | 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 | } /* * Return a byte from a bignum; 0 is least significant, etc. */ int bignum_byte(Bignum bn, int i) { if (i >= (int)(BIGNUM_INT_BYTES * bn[0])) return 0; /* beyond the end */ else return (bn[i / BIGNUM_INT_BYTES + 1] >> ((i % BIGNUM_INT_BYTES)*8)) & 0xFF; } /* * Return a bit from a bignum; 0 is least significant, etc. */ int bignum_bit(Bignum bn, int i) { if (i >= (int)(BIGNUM_INT_BITS * bn[0])) return 0; /* beyond the end */ else return (bn[i / BIGNUM_INT_BITS + 1] >> (i % BIGNUM_INT_BITS)) & 1; } /* * Set a bit in a bignum; 0 is least significant, etc. */ void bignum_set_bit(Bignum bn, int bitnum, int value) { if (bitnum >= (int)(BIGNUM_INT_BITS * bn[0])) abort(); /* beyond the end */ else { int v = bitnum / BIGNUM_INT_BITS + 1; int mask = 1 << (bitnum % BIGNUM_INT_BITS); if (value) bn[v] |= mask; else |
︙ | ︙ | |||
1317 1318 1319 1320 1321 1322 1323 | /* * Compare two bignums. Returns like strcmp. */ int bignum_cmp(Bignum a, Bignum b) { int amax = a[0], bmax = b[0]; | < < < < < < < < < < < | | 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 | /* * Compare two bignums. Returns like strcmp. */ int bignum_cmp(Bignum a, Bignum b) { int amax = a[0], bmax = b[0]; int i = (amax > bmax ? amax : bmax); while (i) { BignumInt aval = (i > amax ? 0 : a[i]); BignumInt bval = (i > bmax ? 0 : b[i]); if (aval < bval) return -1; if (aval > bval) return +1; |
︙ | ︙ | |||
1350 1351 1352 1353 1354 1355 1356 | */ Bignum bignum_rshift(Bignum a, int shift) { Bignum ret; int i, shiftw, shiftb, shiftbb, bits; BignumInt ai, ai1; | < < | 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 | */ Bignum bignum_rshift(Bignum a, int shift) { Bignum ret; int i, shiftw, shiftb, shiftbb, bits; BignumInt ai, ai1; bits = bignum_bitcount(a) - shift; ret = newbn((bits + BIGNUM_INT_BITS - 1) / BIGNUM_INT_BITS); if (ret) { shiftw = shift / BIGNUM_INT_BITS; shiftb = shift % BIGNUM_INT_BITS; shiftbb = BIGNUM_INT_BITS - shiftb; |
︙ | ︙ | |||
1422 1423 1424 1425 1426 1427 1428 | carry >>= BIGNUM_INT_BITS; if (ret[i] != 0 && i > maxspot) maxspot = i; } } ret[0] = maxspot; | > | | 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 | carry >>= BIGNUM_INT_BITS; if (ret[i] != 0 && i > maxspot) maxspot = i; } } ret[0] = maxspot; for (i = 0; i < wslen; i++) workspace[i] = 0; sfree(workspace); return ret; } /* * Non-modular multiplication. */ |
︙ | ︙ | |||
1652 1653 1654 1655 1656 1657 1658 | { Bignum a = copybn(modulus); Bignum b = copybn(number); Bignum xp = copybn(Zero); Bignum x = copybn(One); int sign = +1; | < < < < < < < < < < < < < < < < < | | | 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 | { Bignum a = copybn(modulus); Bignum b = copybn(number); Bignum xp = copybn(Zero); Bignum x = copybn(One); int sign = +1; while (bignum_cmp(b, One) != 0) { Bignum t = newbn(b[0]); Bignum q = newbn(a[0]); bigdivmod(a, b, t, q); while (t[0] > 1 && t[t[0]] == 0) t[0]--; freebn(a); a = b; b = t; t = xp; |
︙ | ︙ | |||
1790 1791 1792 1793 1794 1795 1796 | */ if (ndigit > 0) memmove(ret, ret + ndigit, ndigits - ndigit); /* * Done. */ | < | | 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 | */ if (ndigit > 0) memmove(ret, ret + ndigit, ndigits - ndigit); /* * Done. */ sfree(workspace); return ret; } #ifdef TESTBN #include <stdio.h> #include <stdlib.h> #include <ctype.h> /* * gcc -g -O0 -DTESTBN -o testbn sshbn.c misc.c -I unix -I charset * * Then feed to this program's standard input the output of * testdata/bignum.py . */ void modalfatalbox(char *p, ...) { |
︙ | ︙ | |||
1876 1877 1878 1879 1880 1881 1882 | ptrs[ptrnum] = q; } if (!strcmp(buf, "mul")) { Bignum a, b, c, p; if (ptrnum != 3) { | | | 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 | ptrs[ptrnum] = q; } if (!strcmp(buf, "mul")) { Bignum a, b, c, p; if (ptrnum != 3) { printf("%d: mul with %d parameters, expected 3\n", line); exit(1); } a = bignum_from_bytes(ptrs[0], ptrs[1]-ptrs[0]); b = bignum_from_bytes(ptrs[1], ptrs[2]-ptrs[1]); c = bignum_from_bytes(ptrs[2], ptrs[3]-ptrs[2]); p = bigmul(a, b); |
︙ | ︙ | |||
1904 1905 1906 1907 1908 1909 1910 1911 | sfree(bs); sfree(cs); sfree(ps); } freebn(a); freebn(b); freebn(c); freebn(p); | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 | sfree(bs); sfree(cs); sfree(ps); } freebn(a); freebn(b); freebn(c); freebn(p); } else if (!strcmp(buf, "pow")) { Bignum base, expt, modulus, expected, answer; if (ptrnum != 4) { printf("%d: mul with %d parameters, expected 3\n", line); exit(1); } base = bignum_from_bytes(ptrs[0], ptrs[1]-ptrs[0]); expt = bignum_from_bytes(ptrs[1], ptrs[2]-ptrs[1]); modulus = bignum_from_bytes(ptrs[2], ptrs[3]-ptrs[2]); expected = bignum_from_bytes(ptrs[3], ptrs[4]-ptrs[3]); |
︙ | ︙ |
Changes to sshdes.c.
︙ | ︙ | |||
854 855 856 857 858 859 860 | des_key_setup(GET_32BIT_MSB_FIRST(key), GET_32BIT_MSB_FIRST(key + 4), &ourkeys[0]); des_key_setup(GET_32BIT_MSB_FIRST(key + 8), GET_32BIT_MSB_FIRST(key + 12), &ourkeys[1]); des_key_setup(GET_32BIT_MSB_FIRST(key), GET_32BIT_MSB_FIRST(key + 4), &ourkeys[2]); des_3cbc_decrypt(blk, len, ourkeys); | | | | | | | 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 | des_key_setup(GET_32BIT_MSB_FIRST(key), GET_32BIT_MSB_FIRST(key + 4), &ourkeys[0]); des_key_setup(GET_32BIT_MSB_FIRST(key + 8), GET_32BIT_MSB_FIRST(key + 12), &ourkeys[1]); des_key_setup(GET_32BIT_MSB_FIRST(key), GET_32BIT_MSB_FIRST(key + 4), &ourkeys[2]); des_3cbc_decrypt(blk, len, ourkeys); memset(ourkeys, 0, sizeof(ourkeys)); } void des3_encrypt_pubkey(unsigned char *key, unsigned char *blk, int len) { DESContext ourkeys[3]; des_key_setup(GET_32BIT_MSB_FIRST(key), GET_32BIT_MSB_FIRST(key + 4), &ourkeys[0]); des_key_setup(GET_32BIT_MSB_FIRST(key + 8), GET_32BIT_MSB_FIRST(key + 12), &ourkeys[1]); des_key_setup(GET_32BIT_MSB_FIRST(key), GET_32BIT_MSB_FIRST(key + 4), &ourkeys[2]); des_3cbc_encrypt(blk, len, ourkeys); memset(ourkeys, 0, sizeof(ourkeys)); } void des3_decrypt_pubkey_ossh(unsigned char *key, unsigned char *iv, unsigned char *blk, int len) { DESContext ourkeys[3]; des_key_setup(GET_32BIT_MSB_FIRST(key), GET_32BIT_MSB_FIRST(key + 4), &ourkeys[0]); des_key_setup(GET_32BIT_MSB_FIRST(key + 8), GET_32BIT_MSB_FIRST(key + 12), &ourkeys[1]); des_key_setup(GET_32BIT_MSB_FIRST(key + 16), GET_32BIT_MSB_FIRST(key + 20), &ourkeys[2]); ourkeys[0].iv0 = GET_32BIT_MSB_FIRST(iv); ourkeys[0].iv1 = GET_32BIT_MSB_FIRST(iv+4); des_cbc3_decrypt(blk, len, ourkeys); memset(ourkeys, 0, sizeof(ourkeys)); } void des3_encrypt_pubkey_ossh(unsigned char *key, unsigned char *iv, unsigned char *blk, int len) { DESContext ourkeys[3]; des_key_setup(GET_32BIT_MSB_FIRST(key), GET_32BIT_MSB_FIRST(key + 4), &ourkeys[0]); des_key_setup(GET_32BIT_MSB_FIRST(key + 8), GET_32BIT_MSB_FIRST(key + 12), &ourkeys[1]); des_key_setup(GET_32BIT_MSB_FIRST(key + 16), GET_32BIT_MSB_FIRST(key + 20), &ourkeys[2]); ourkeys[0].iv0 = GET_32BIT_MSB_FIRST(iv); ourkeys[0].iv1 = GET_32BIT_MSB_FIRST(iv+4); des_cbc3_encrypt(blk, len, ourkeys); memset(ourkeys, 0, sizeof(ourkeys)); } static void des_keysetup_xdmauth(unsigned char *keydata, DESContext *dc) { unsigned char key[8]; int i, nbits, j; unsigned int bits; bits = 0; nbits = 0; |
︙ | ︙ | |||
925 926 927 928 929 930 931 | bits &= ~(0x7F << (nbits - 7)); nbits -= 7; } des_key_setup(GET_32BIT_MSB_FIRST(key), GET_32BIT_MSB_FIRST(key + 4), dc); } | < | | < | | | 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 | bits &= ~(0x7F << (nbits - 7)); nbits -= 7; } des_key_setup(GET_32BIT_MSB_FIRST(key), GET_32BIT_MSB_FIRST(key + 4), dc); } void des_encrypt_xdmauth(unsigned char *keydata, unsigned char *blk, int len) { DESContext dc; des_keysetup_xdmauth(keydata, &dc); des_cbc_encrypt(blk, 24, &dc); } void des_decrypt_xdmauth(unsigned char *keydata, unsigned char *blk, int len) { DESContext dc; des_keysetup_xdmauth(keydata, &dc); des_cbc_decrypt(blk, 24, &dc); } static const struct ssh2_cipher ssh_3des_ssh2 = { des3_make_context, des3_free_context, des3_iv, des3_key, des3_ssh2_encrypt_blk, des3_ssh2_decrypt_blk, "3des-cbc", 8, 168, SSH_CIPHER_IS_CBC, "triple-DES CBC" |
︙ | ︙ | |||
1027 1028 1029 1030 1031 1032 1033 | } const struct ssh_cipher ssh_des = { des_ssh1_make_context, des3_free_context, des_sesskey, des_encrypt_blk, des_decrypt_blk, 8, "single-DES CBC" }; | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1025 1026 1027 1028 1029 1030 1031 | } const struct ssh_cipher ssh_des = { des_ssh1_make_context, des3_free_context, des_sesskey, des_encrypt_blk, des_decrypt_blk, 8, "single-DES CBC" }; |
Changes to sshdss.c.
︙ | ︙ | |||
16 17 18 19 20 21 22 | len = (bignum_bitcount(b) + 8) / 8; PUT_32BIT(lenbuf, len); SHA_Bytes(s, lenbuf, 4); while (len-- > 0) { lenbuf[0] = bignum_byte(b, len); SHA_Bytes(s, lenbuf, 1); } | | | | < < | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | len = (bignum_bitcount(b) + 8) / 8; PUT_32BIT(lenbuf, len); SHA_Bytes(s, lenbuf, 4); while (len-- > 0) { lenbuf[0] = bignum_byte(b, len); SHA_Bytes(s, lenbuf, 1); } memset(lenbuf, 0, sizeof(lenbuf)); } static void sha512_mpint(SHA512_State * s, Bignum b) { unsigned char lenbuf[4]; int len; len = (bignum_bitcount(b) + 8) / 8; PUT_32BIT(lenbuf, len); SHA512_Bytes(s, lenbuf, 4); while (len-- > 0) { lenbuf[0] = bignum_byte(b, len); SHA512_Bytes(s, lenbuf, 1); } memset(lenbuf, 0, sizeof(lenbuf)); } static void getstring(char **data, int *datalen, char **p, int *length) { *p = NULL; if (*datalen < 4) return; *length = GET_32BIT(*data); *datalen -= 4; *data += 4; if (*datalen < *length) return; *p = *data; *data += *length; *datalen -= *length; |
︙ | ︙ | |||
68 69 70 71 72 73 74 | return b; } static Bignum get160(char **data, int *datalen) { Bignum b; | < < < < < > > | < < < < < < < < < | < | < | < | < < | 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | return b; } static Bignum get160(char **data, int *datalen) { Bignum b; b = bignum_from_bytes((unsigned char *)*data, 20); *data += 20; *datalen -= 20; return b; } static void *dss_newkey(char *data, int len) { char *p; int slen; struct dss_key *dss; dss = snew(struct dss_key); if (!dss) return NULL; getstring(&data, &len, &p, &slen); #ifdef DEBUG_DSS { int i; printf("key:"); for (i = 0; i < len; i++) printf(" %02x", (unsigned char) (data[i])); printf("\n"); } #endif if (!p || memcmp(p, "ssh-dss", 7)) { sfree(dss); return NULL; } dss->p = getmp(&data, &len); dss->q = getmp(&data, &len); dss->g = getmp(&data, &len); dss->y = getmp(&data, &len); return dss; } static void dss_freekey(void *key) { struct dss_key *dss = (struct dss_key *) key; freebn(dss->p); freebn(dss->q); freebn(dss->g); freebn(dss->y); sfree(dss); } static char *dss_fmtkey(void *key) { struct dss_key *dss = (struct dss_key *) key; char *p; |
︙ | ︙ | |||
264 265 266 267 268 269 270 | if (!p || slen != 7 || memcmp(p, "ssh-dss", 7)) { return 0; } sig += 4, siglen -= 4; /* skip yet another length field */ } r = get160(&sig, &siglen); s = get160(&sig, &siglen); | | < < < < < < < < < < < < < < < < | 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 | if (!p || slen != 7 || memcmp(p, "ssh-dss", 7)) { return 0; } sig += 4, siglen -= 4; /* skip yet another length field */ } r = get160(&sig, &siglen); s = get160(&sig, &siglen); if (!r || !s) return 0; /* * Step 1. w <- s^-1 mod q. */ w = modinv(s, dss->q); /* * Step 2. u1 <- SHA(message) * w mod q. */ SHA_Simple(data, datalen, (unsigned char *)hash); p = hash; slen = 20; |
︙ | ︙ | |||
318 319 320 321 322 323 324 | * Step 5. v should now be equal to r. */ ret = !bignum_cmp(v, r); freebn(w); freebn(sha); | < < | 283 284 285 286 287 288 289 290 291 292 293 294 295 296 | * Step 5. v should now be equal to r. */ ret = !bignum_cmp(v, r); freebn(w); freebn(sha); freebn(gu1p); freebn(yu2p); freebn(gu1yu2p); freebn(v); freebn(r); freebn(s); |
︙ | ︙ | |||
410 411 412 413 414 415 416 | char *hash; int hashlen; SHA_State s; unsigned char digest[20]; Bignum ytest; dss = dss_newkey((char *) pub_blob, pub_len); | < < < < < < | 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 | char *hash; int hashlen; SHA_State s; unsigned char digest[20]; Bignum ytest; dss = dss_newkey((char *) pub_blob, pub_len); dss->x = getmp(&pb, &priv_len); /* * Check the obsolete hash in the old DSS key format. */ hashlen = -1; getstring(&pb, &priv_len, &hash, &hashlen); if (hashlen == 20) { |
︙ | ︙ | |||
441 442 443 444 445 446 447 | /* * Now ensure g^x mod p really is y. */ ytest = modpow(dss->g, dss->x, dss->p); if (0 != bignum_cmp(ytest, dss->y)) { dss_freekey(dss); | < > > | | | > > > | | | 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 | /* * Now ensure g^x mod p really is y. */ ytest = modpow(dss->g, dss->x, dss->p); if (0 != bignum_cmp(ytest, dss->y)) { dss_freekey(dss); return NULL; } freebn(ytest); return dss; } static void *dss_openssh_createkey(unsigned char **blob, int *len) { char **b = (char **) blob; struct dss_key *dss; dss = snew(struct dss_key); if (!dss) return NULL; dss->p = getmp(b, len); dss->q = getmp(b, len); dss->g = getmp(b, len); dss->y = getmp(b, len); dss->x = getmp(b, len); if (!dss->p || !dss->q || !dss->g || !dss->y || !dss->x) { sfree(dss->p); sfree(dss->q); sfree(dss->g); sfree(dss->y); sfree(dss->x); sfree(dss); return NULL; } return dss; } static int dss_openssh_fmtkey(void *key, unsigned char *blob, int len) { |
︙ | ︙ | |||
506 507 508 509 510 511 512 | static int dss_pubkey_bits(void *blob, int len) { struct dss_key *dss; int ret; dss = dss_newkey((char *) blob, len); | < < | 467 468 469 470 471 472 473 474 475 476 477 478 479 480 | static int dss_pubkey_bits(void *blob, int len) { struct dss_key *dss; int ret; dss = dss_newkey((char *) blob, len); ret = bignum_bitcount(dss->p); dss_freekey(dss); return ret; } static unsigned char *dss_sign(void *key, char *data, int datalen, int *siglen) |
︙ | ︙ | |||
610 611 612 613 614 615 616 | /* * Now hash that digest plus the message hash. */ SHA512_Init(&ss); SHA512_Bytes(&ss, digest512, sizeof(digest512)); SHA512_Bytes(&ss, digest, sizeof(digest)); | < < < | | | | | | | | < < < < < < < | < < < < < < | > < | 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 | /* * Now hash that digest plus the message hash. */ SHA512_Init(&ss); SHA512_Bytes(&ss, digest512, sizeof(digest512)); SHA512_Bytes(&ss, digest, sizeof(digest)); SHA512_Final(&ss, digest512); memset(&ss, 0, sizeof(ss)); /* * Now convert the result into a bignum, and reduce it mod q. */ proto_k = bignum_from_bytes(digest512, 64); k = bigmod(proto_k, dss->q); freebn(proto_k); memset(digest512, 0, sizeof(digest512)); /* * Now we have k, so just go ahead and compute the signature. */ gkp = modpow(dss->g, k, dss->p); /* g^k mod p */ r = bigmod(gkp, dss->q); /* r = (g^k mod p) mod q */ freebn(gkp); hash = bignum_from_bytes(digest, 20); kinv = modinv(k, dss->q); /* k^-1 mod q */ hxr = bigmuladd(dss->x, r, hash); /* hash + x*r */ s = modmul(kinv, hxr, dss->q); /* s = k^-1 * (hash + x*r) mod q */ freebn(hxr); freebn(kinv); freebn(hash); /* * Signature blob is * * string "ssh-dss" * string two 20-byte numbers r and s, end to end |
︙ | ︙ |
Changes to sshdssg.c.
1 2 3 4 5 6 7 8 9 10 11 | /* * DSS key generation. */ #include "misc.h" #include "ssh.h" int dsa_generate(struct dss_key *key, int bits, progfn_t pfn, void *pfnparam) { Bignum qm1, power, g, h, tmp; | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | /* * DSS key generation. */ #include "misc.h" #include "ssh.h" int dsa_generate(struct dss_key *key, int bits, progfn_t pfn, void *pfnparam) { Bignum qm1, power, g, h, tmp; int progress; /* * Set up the phase limits for the progress report. We do this * by passing minus the phase number. * * For prime generation: our initial filter finds things |
︙ | ︙ | |||
67 68 69 70 71 72 73 | * _after_ generating q, we'll just set it to 0.75. */ pfn(pfnparam, PROGFN_PHASE_EXTENT, 4, 0x2000); pfn(pfnparam, PROGFN_EXP_PHASE, 4, -49152); pfn(pfnparam, PROGFN_READY, 0, 0); | < | | | 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | * _after_ generating q, we'll just set it to 0.75. */ pfn(pfnparam, PROGFN_PHASE_EXTENT, 4, 0x2000); pfn(pfnparam, PROGFN_EXP_PHASE, 4, -49152); pfn(pfnparam, PROGFN_READY, 0, 0); /* * Generate q: a prime of length 160. */ key->q = primegen(160, 2, 2, NULL, 1, pfn, pfnparam); /* * Now generate p: a prime of length `bits', such that p-1 is * divisible by q. */ key->p = primegen(bits-160, 2, 2, key->q, 2, pfn, pfnparam); /* * Next we need g. Raise 2 to the power (p-1)/q modulo p, and * if that comes out to one then try 3, then 4 and so on. As * soon as we hit a non-unit (and non-zero!) one, that'll do * for g. */ |
︙ | ︙ |
Changes to sshgss.h.
︙ | ︙ | |||
43 44 45 46 47 48 49 | * The free function cleans up the structure, and its associated * libraries (if any). */ struct ssh_gss_liblist { struct ssh_gss_library *libraries; int nlibraries; }; | | | 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | * The free function cleans up the structure, and its associated * libraries (if any). */ struct ssh_gss_liblist { struct ssh_gss_library *libraries; int nlibraries; }; struct ssh_gss_liblist *ssh_gss_setup(const Config *cfg); void ssh_gss_cleanup(struct ssh_gss_liblist *list); /* * Fills in buf with a string describing the GSSAPI mechanism in * use. buf->data is not dynamically allocated. */ typedef Ssh_gss_stat (*t_ssh_gss_indicate_mech)(struct ssh_gss_library *lib, |
︙ | ︙ |
Changes to sshmd5.c.
︙ | ︙ | |||
245 246 247 248 249 250 251 | memset(foo, 0x5C, 64); for (i = 0; i < len && i < 64; i++) foo[i] ^= key[i]; MD5Init(&keys[1]); MD5Update(&keys[1], foo, 64); | | | 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 | memset(foo, 0x5C, 64); for (i = 0; i < len && i < 64; i++) foo[i] ^= key[i]; MD5Init(&keys[1]); MD5Update(&keys[1], foo, 64); memset(foo, 0, 64); /* burn the evidence */ } static void hmacmd5_key_16(void *handle, unsigned char *key) { hmacmd5_key(handle, key, 16); } |
︙ | ︙ | |||
308 309 310 311 312 313 314 | } static void hmacmd5_do_hmac_ssh(void *handle, unsigned char const *blk, int len, unsigned long seq, unsigned char *hmac) { unsigned char seqbuf[16]; | > > > > | | 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 | } static void hmacmd5_do_hmac_ssh(void *handle, unsigned char const *blk, int len, unsigned long seq, unsigned char *hmac) { unsigned char seqbuf[16]; seqbuf[0] = (unsigned char) ((seq >> 24) & 0xFF); seqbuf[1] = (unsigned char) ((seq >> 16) & 0xFF); seqbuf[2] = (unsigned char) ((seq >> 8) & 0xFF); seqbuf[3] = (unsigned char) ((seq) & 0xFF); hmacmd5_do_hmac_internal(handle, seqbuf, 4, blk, len, hmac); } static void hmacmd5_generate(void *handle, unsigned char *blk, int len, unsigned long seq) { hmacmd5_do_hmac_ssh(handle, blk, len, seq, blk + len); |
︙ | ︙ |
Changes to sshnogss.c.
1 2 3 4 5 | #include "putty.h" #ifndef NO_GSSAPI /* For platforms not supporting GSSAPI */ | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 | #include "putty.h" #ifndef NO_GSSAPI /* For platforms not supporting GSSAPI */ struct ssh_gss_liblist *ssh_gss_setup(const Config *cfg) { struct ssh_gss_liblist *list = snew(struct ssh_gss_liblist *); list->libraries = NULL; list->nlibraries = 0; return list; } |
︙ | ︙ |
Changes to sshprime.c.
︙ | ︙ | |||
119 120 121 122 123 124 125 | * list.append(i) * for j in range(i,n,i): z[j] = 0 * return list * list = sieve(65535) * for i in list[1:]: sys.stdout.write("%d," % i) */ static const unsigned short primes[] = { | | | | > | | > | | > | | | > | > | | | > | > | > | | | > | > | > | | | > | > | | | > | > | > | | | > | > | > | | | > | > | | | > | > | > | | | > | > | > | | | > | > | | | > | > | > | | | > | > | > | | | > | > | | | > | > | > | | | > | > | > | | | > | > | | | > | > | > | | | > | > | | | > | > | > | | | > | > | > | | | > | > | | | > | > > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | > | | | > | | | > | > | | | > | > | | | > | > | > | | | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | > | | | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | > | | | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | > | | | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | > | | | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | > | | | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | > | | | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | > | > | | | < < < < < < < < | | < < < < | < < | | 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 | * list.append(i) * for j in range(i,n,i): z[j] = 0 * return list * list = sieve(65535) * for i in list[1:]: sys.stdout.write("%d," % i) */ static const unsigned short primes[] = { 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, 3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413, 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821, 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139, 4153, 4157, 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297, 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409, 4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831, 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009, 5011, 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087, 5099, 5101, 5107, 5113, 5119, 5147, 5153, 5167, 5171, 5179, 5189, 5197, 5209, 5227, 5231, 5233, 5237, 5261, 5273, 5279, 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381, 5387, 5393, 5399, 5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443, 5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521, 5527, 5531, 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639, 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, 5689, 5693, 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, 5791, 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, 5857, 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, 5953, 5981, 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073, 6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133, 6143, 6151, 6163, 6173, 6197, 6199, 6203, 6211, 6217, 6221, 6229, 6247, 6257, 6263, 6269, 6271, 6277, 6287, 6299, 6301, 6311, 6317, 6323, 6329, 6337, 6343, 6353, 6359, 6361, 6367, 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, 6473, 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571, 6577, 6581, 6599, 6607, 6619, 6637, 6653, 6659, 6661, 6673, 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, 6761, 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833, 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, 6947, 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997, 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, 7109, 7121, 7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, 7219, 7229, 7237, 7243, 7247, 7253, 7283, 7297, 7307, 7309, 7321, 7331, 7333, 7349, 7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, 7489, 7499, 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, 7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621, 7639, 7643, 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723, 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829, 7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919, 7927, 7933, 7937, 7949, 7951, 7963, 7993, 8009, 8011, 8017, 8039, 8053, 8059, 8069, 8081, 8087, 8089, 8093, 8101, 8111, 8117, 8123, 8147, 8161, 8167, 8171, 8179, 8191, 8209, 8219, 8221, 8231, 8233, 8237, 8243, 8263, 8269, 8273, 8287, 8291, 8293, 8297, 8311, 8317, 8329, 8353, 8363, 8369, 8377, 8387, 8389, 8419, 8423, 8429, 8431, 8443, 8447, 8461, 8467, 8501, 8513, 8521, 8527, 8537, 8539, 8543, 8563, 8573, 8581, 8597, 8599, 8609, 8623, 8627, 8629, 8641, 8647, 8663, 8669, 8677, 8681, 8689, 8693, 8699, 8707, 8713, 8719, 8731, 8737, 8741, 8747, 8753, 8761, 8779, 8783, 8803, 8807, 8819, 8821, 8831, 8837, 8839, 8849, 8861, 8863, 8867, 8887, 8893, 8923, 8929, 8933, 8941, 8951, 8963, 8969, 8971, 8999, 9001, 9007, 9011, 9013, 9029, 9041, 9043, 9049, 9059, 9067, 9091, 9103, 9109, 9127, 9133, 9137, 9151, 9157, 9161, 9173, 9181, 9187, 9199, 9203, 9209, 9221, 9227, 9239, 9241, 9257, 9277, 9281, 9283, 9293, 9311, 9319, 9323, 9337, 9341, 9343, 9349, 9371, 9377, 9391, 9397, 9403, 9413, 9419, 9421, 9431, 9433, 9437, 9439, 9461, 9463, 9467, 9473, 9479, 9491, 9497, 9511, 9521, 9533, 9539, 9547, 9551, 9587, 9601, 9613, 9619, 9623, 9629, 9631, 9643, 9649, 9661, 9677, 9679, 9689, 9697, 9719, 9721, 9733, 9739, 9743, 9749, 9767, 9769, 9781, 9787, 9791, 9803, 9811, 9817, 9829, 9833, 9839, 9851, 9857, 9859, 9871, 9883, 9887, 9901, 9907, 9923, 9929, 9931, 9941, 9949, 9967, 9973, 10007, 10009, 10037, 10039, 10061, 10067, 10069, 10079, 10091, 10093, 10099, 10103, 10111, 10133, 10139, 10141, 10151, 10159, 10163, 10169, 10177, 10181, 10193, 10211, 10223, 10243, 10247, 10253, 10259, 10267, 10271, 10273, 10289, 10301, 10303, 10313, 10321, 10331, 10333, 10337, 10343, 10357, 10369, 10391, 10399, 10427, 10429, 10433, 10453, 10457, 10459, 10463, 10477, 10487, 10499, 10501, 10513, 10529, 10531, 10559, 10567, 10589, 10597, 10601, 10607, 10613, 10627, 10631, 10639, 10651, 10657, 10663, 10667, 10687, 10691, 10709, 10711, 10723, 10729, 10733, 10739, 10753, 10771, 10781, 10789, 10799, 10831, 10837, 10847, 10853, 10859, 10861, 10867, 10883, 10889, 10891, 10903, 10909, 10937, 10939, 10949, 10957, 10973, 10979, 10987, 10993, 11003, 11027, 11047, 11057, 11059, 11069, 11071, 11083, 11087, 11093, 11113, 11117, 11119, 11131, 11149, 11159, 11161, 11171, 11173, 11177, 11197, 11213, 11239, 11243, 11251, 11257, 11261, 11273, 11279, 11287, 11299, 11311, 11317, 11321, 11329, 11351, 11353, 11369, 11383, 11393, 11399, 11411, 11423, 11437, 11443, 11447, 11467, 11471, 11483, 11489, 11491, 11497, 11503, 11519, 11527, 11549, 11551, 11579, 11587, 11593, 11597, 11617, 11621, 11633, 11657, 11677, 11681, 11689, 11699, 11701, 11717, 11719, 11731, 11743, 11777, 11779, 11783, 11789, 11801, 11807, 11813, 11821, 11827, 11831, 11833, 11839, 11863, 11867, 11887, 11897, 11903, 11909, 11923, 11927, 11933, 11939, 11941, 11953, 11959, 11969, 11971, 11981, 11987, 12007, 12011, 12037, 12041, 12043, 12049, 12071, 12073, 12097, 12101, 12107, 12109, 12113, 12119, 12143, 12149, 12157, 12161, 12163, 12197, 12203, 12211, 12227, 12239, 12241, 12251, 12253, 12263, 12269, 12277, 12281, 12289, 12301, 12323, 12329, 12343, 12347, 12373, 12377, 12379, 12391, 12401, 12409, 12413, 12421, 12433, 12437, 12451, 12457, 12473, 12479, 12487, 12491, 12497, 12503, 12511, 12517, 12527, 12539, 12541, 12547, 12553, 12569, 12577, 12583, 12589, 12601, 12611, 12613, 12619, 12637, 12641, 12647, 12653, 12659, 12671, 12689, 12697, 12703, 12713, 12721, 12739, 12743, 12757, 12763, 12781, 12791, 12799, 12809, 12821, 12823, 12829, 12841, 12853, 12889, 12893, 12899, 12907, 12911, 12917, 12919, 12923, 12941, 12953, 12959, 12967, 12973, 12979, 12983, 13001, 13003, 13007, 13009, 13033, 13037, 13043, 13049, 13063, 13093, 13099, 13103, 13109, 13121, 13127, 13147, 13151, 13159, 13163, 13171, 13177, 13183, 13187, 13217, 13219, 13229, 13241, 13249, 13259, 13267, 13291, 13297, 13309, 13313, 13327, 13331, 13337, 13339, 13367, 13381, 13397, 13399, 13411, 13417, 13421, 13441, 13451, 13457, 13463, 13469, 13477, 13487, 13499, 13513, 13523, 13537, 13553, 13567, 13577, 13591, 13597, 13613, 13619, 13627, 13633, 13649, 13669, 13679, 13681, 13687, 13691, 13693, 13697, 13709, 13711, 13721, 13723, 13729, 13751, 13757, 13759, 13763, 13781, 13789, 13799, 13807, 13829, 13831, 13841, 13859, 13873, 13877, 13879, 13883, 13901, 13903, 13907, 13913, 13921, 13931, 13933, 13963, 13967, 13997, 13999, 14009, 14011, 14029, 14033, 14051, 14057, 14071, 14081, 14083, 14087, 14107, 14143, 14149, 14153, 14159, 14173, 14177, 14197, 14207, 14221, 14243, 14249, 14251, 14281, 14293, 14303, 14321, 14323, 14327, 14341, 14347, 14369, 14387, 14389, 14401, 14407, 14411, 14419, 14423, 14431, 14437, 14447, 14449, 14461, 14479, 14489, 14503, 14519, 14533, 14537, 14543, 14549, 14551, 14557, 14561, 14563, 14591, 14593, 14621, 14627, 14629, 14633, 14639, 14653, 14657, 14669, 14683, 14699, 14713, 14717, 14723, 14731, 14737, 14741, 14747, 14753, 14759, 14767, 14771, 14779, 14783, 14797, 14813, 14821, 14827, 14831, 14843, 14851, 14867, 14869, 14879, 14887, 14891, 14897, 14923, 14929, 14939, 14947, 14951, 14957, 14969, 14983, 15013, 15017, 15031, 15053, 15061, 15073, 15077, 15083, 15091, 15101, 15107, 15121, 15131, 15137, 15139, 15149, 15161, 15173, 15187, 15193, 15199, 15217, 15227, 15233, 15241, 15259, 15263, 15269, 15271, 15277, 15287, 15289, 15299, 15307, 15313, 15319, 15329, 15331, 15349, 15359, 15361, 15373, 15377, 15383, 15391, 15401, 15413, 15427, 15439, 15443, 15451, 15461, 15467, 15473, 15493, 15497, 15511, 15527, 15541, 15551, 15559, 15569, 15581, 15583, 15601, 15607, 15619, 15629, 15641, 15643, 15647, 15649, 15661, 15667, 15671, 15679, 15683, 15727, 15731, 15733, 15737, 15739, 15749, 15761, 15767, 15773, 15787, 15791, 15797, 15803, 15809, 15817, 15823, 15859, 15877, 15881, 15887, 15889, 15901, 15907, 15913, 15919, 15923, 15937, 15959, 15971, 15973, 15991, 16001, 16007, 16033, 16057, 16061, 16063, 16067, 16069, 16073, 16087, 16091, 16097, 16103, 16111, 16127, 16139, 16141, 16183, 16187, 16189, 16193, 16217, 16223, 16229, 16231, 16249, 16253, 16267, 16273, 16301, 16319, 16333, 16339, 16349, 16361, 16363, 16369, 16381, 16411, 16417, 16421, 16427, 16433, 16447, 16451, 16453, 16477, 16481, 16487, 16493, 16519, 16529, 16547, 16553, 16561, 16567, 16573, 16603, 16607, 16619, 16631, 16633, 16649, 16651, 16657, 16661, 16673, 16691, 16693, 16699, 16703, 16729, 16741, 16747, 16759, 16763, 16787, 16811, 16823, 16829, 16831, 16843, 16871, 16879, 16883, 16889, 16901, 16903, 16921, 16927, 16931, 16937, 16943, 16963, 16979, 16981, 16987, 16993, 17011, 17021, 17027, 17029, 17033, 17041, 17047, 17053, 17077, 17093, 17099, 17107, 17117, 17123, 17137, 17159, 17167, 17183, 17189, 17191, 17203, 17207, 17209, 17231, 17239, 17257, 17291, 17293, 17299, 17317, 17321, 17327, 17333, 17341, 17351, 17359, 17377, 17383, 17387, 17389, 17393, 17401, 17417, 17419, 17431, 17443, 17449, 17467, 17471, 17477, 17483, 17489, 17491, 17497, 17509, 17519, 17539, 17551, 17569, 17573, 17579, 17581, 17597, 17599, 17609, 17623, 17627, 17657, 17659, 17669, 17681, 17683, 17707, 17713, 17729, 17737, 17747, 17749, 17761, 17783, 17789, 17791, 17807, 17827, 17837, 17839, 17851, 17863, 17881, 17891, 17903, 17909, 17911, 17921, 17923, 17929, 17939, 17957, 17959, 17971, 17977, 17981, 17987, 17989, 18013, 18041, 18043, 18047, 18049, 18059, 18061, 18077, 18089, 18097, 18119, 18121, 18127, 18131, 18133, 18143, 18149, 18169, 18181, 18191, 18199, 18211, 18217, 18223, 18229, 18233, 18251, 18253, 18257, 18269, 18287, 18289, 18301, 18307, 18311, 18313, 18329, 18341, 18353, 18367, 18371, 18379, 18397, 18401, 18413, 18427, 18433, 18439, 18443, 18451, 18457, 18461, 18481, 18493, 18503, 18517, 18521, 18523, 18539, 18541, 18553, 18583, 18587, 18593, 18617, 18637, 18661, 18671, 18679, 18691, 18701, 18713, 18719, 18731, 18743, 18749, 18757, 18773, 18787, 18793, 18797, 18803, 18839, 18859, 18869, 18899, 18911, 18913, 18917, 18919, 18947, 18959, 18973, 18979, 19001, 19009, 19013, 19031, 19037, 19051, 19069, 19073, 19079, 19081, 19087, 19121, 19139, 19141, 19157, 19163, 19181, 19183, 19207, 19211, 19213, 19219, 19231, 19237, 19249, 19259, 19267, 19273, 19289, 19301, 19309, 19319, 19333, 19373, 19379, 19381, 19387, 19391, 19403, 19417, 19421, 19423, 19427, 19429, 19433, 19441, 19447, 19457, 19463, 19469, 19471, 19477, 19483, 19489, 19501, 19507, 19531, 19541, 19543, 19553, 19559, 19571, 19577, 19583, 19597, 19603, 19609, 19661, 19681, 19687, 19697, 19699, 19709, 19717, 19727, 19739, 19751, 19753, 19759, 19763, 19777, 19793, 19801, 19813, 19819, 19841, 19843, 19853, 19861, 19867, 19889, 19891, 19913, 19919, 19927, 19937, 19949, 19961, 19963, 19973, 19979, 19991, 19993, 19997, 20011, 20021, 20023, 20029, 20047, 20051, 20063, 20071, 20089, 20101, 20107, 20113, 20117, 20123, 20129, 20143, 20147, 20149, 20161, 20173, 20177, 20183, 20201, 20219, 20231, 20233, 20249, 20261, 20269, 20287, 20297, 20323, 20327, 20333, 20341, 20347, 20353, 20357, 20359, 20369, 20389, 20393, 20399, 20407, 20411, 20431, 20441, 20443, 20477, 20479, 20483, 20507, 20509, 20521, 20533, 20543, 20549, 20551, 20563, 20593, 20599, 20611, 20627, 20639, 20641, 20663, 20681, 20693, 20707, 20717, 20719, 20731, 20743, 20747, 20749, 20753, 20759, 20771, 20773, 20789, 20807, 20809, 20849, 20857, 20873, 20879, 20887, 20897, 20899, 20903, 20921, 20929, 20939, 20947, 20959, 20963, 20981, 20983, 21001, 21011, 21013, 21017, 21019, 21023, 21031, 21059, 21061, 21067, 21089, 21101, 21107, 21121, 21139, 21143, 21149, 21157, 21163, 21169, 21179, 21187, 21191, 21193, 21211, 21221, 21227, 21247, 21269, 21277, 21283, 21313, 21317, 21319, 21323, 21341, 21347, 21377, 21379, 21383, 21391, 21397, 21401, 21407, 21419, 21433, 21467, 21481, 21487, 21491, 21493, 21499, 21503, 21517, 21521, 21523, 21529, 21557, 21559, 21563, 21569, 21577, 21587, 21589, 21599, 21601, 21611, 21613, 21617, 21647, 21649, 21661, 21673, 21683, 21701, 21713, 21727, 21737, 21739, 21751, 21757, 21767, 21773, 21787, 21799, 21803, 21817, 21821, 21839, 21841, 21851, 21859, 21863, 21871, 21881, 21893, 21911, 21929, 21937, 21943, 21961, 21977, 21991, 21997, 22003, 22013, 22027, 22031, 22037, 22039, 22051, 22063, 22067, 22073, 22079, 22091, 22093, 22109, 22111, 22123, 22129, 22133, 22147, 22153, 22157, 22159, 22171, 22189, 22193, 22229, 22247, 22259, 22271, 22273, 22277, 22279, 22283, 22291, 22303, 22307, 22343, 22349, 22367, 22369, 22381, 22391, 22397, 22409, 22433, 22441, 22447, 22453, 22469, 22481, 22483, 22501, 22511, 22531, 22541, 22543, 22549, 22567, 22571, 22573, 22613, 22619, 22621, 22637, 22639, 22643, 22651, 22669, 22679, 22691, 22697, 22699, 22709, 22717, 22721, 22727, 22739, 22741, 22751, 22769, 22777, 22783, 22787, 22807, 22811, 22817, 22853, 22859, 22861, 22871, 22877, 22901, 22907, 22921, 22937, 22943, 22961, 22963, 22973, 22993, 23003, 23011, 23017, 23021, 23027, 23029, 23039, 23041, 23053, 23057, 23059, 23063, 23071, 23081, 23087, 23099, 23117, 23131, 23143, 23159, 23167, 23173, 23189, 23197, 23201, 23203, 23209, 23227, 23251, 23269, 23279, 23291, 23293, 23297, 23311, 23321, 23327, 23333, 23339, 23357, 23369, 23371, 23399, 23417, 23431, 23447, 23459, 23473, 23497, 23509, 23531, 23537, 23539, 23549, 23557, 23561, 23563, 23567, 23581, 23593, 23599, 23603, 23609, 23623, 23627, 23629, 23633, 23663, 23669, 23671, 23677, 23687, 23689, 23719, 23741, 23743, 23747, 23753, 23761, 23767, 23773, 23789, 23801, 23813, 23819, 23827, 23831, 23833, 23857, 23869, 23873, 23879, 23887, 23893, 23899, 23909, 23911, 23917, 23929, 23957, 23971, 23977, 23981, 23993, 24001, 24007, 24019, 24023, 24029, 24043, 24049, 24061, 24071, 24077, 24083, 24091, 24097, 24103, 24107, 24109, 24113, 24121, 24133, 24137, 24151, 24169, 24179, 24181, 24197, 24203, 24223, 24229, 24239, 24247, 24251, 24281, 24317, 24329, 24337, 24359, 24371, 24373, 24379, 24391, 24407, 24413, 24419, 24421, 24439, 24443, 24469, 24473, 24481, 24499, 24509, 24517, 24527, 24533, 24547, 24551, 24571, 24593, 24611, 24623, 24631, 24659, 24671, 24677, 24683, 24691, 24697, 24709, 24733, 24749, 24763, 24767, 24781, 24793, 24799, 24809, 24821, 24841, 24847, 24851, 24859, 24877, 24889, 24907, 24917, 24919, 24923, 24943, 24953, 24967, 24971, 24977, 24979, 24989, 25013, 25031, 25033, 25037, 25057, 25073, 25087, 25097, 25111, 25117, 25121, 25127, 25147, 25153, 25163, 25169, 25171, 25183, 25189, 25219, 25229, 25237, 25243, 25247, 25253, 25261, 25301, 25303, 25307, 25309, 25321, 25339, 25343, 25349, 25357, 25367, 25373, 25391, 25409, 25411, 25423, 25439, 25447, 25453, 25457, 25463, 25469, 25471, 25523, 25537, 25541, 25561, 25577, 25579, 25583, 25589, 25601, 25603, 25609, 25621, 25633, 25639, 25643, 25657, 25667, 25673, 25679, 25693, 25703, 25717, 25733, 25741, 25747, 25759, 25763, 25771, 25793, 25799, 25801, 25819, 25841, 25847, 25849, 25867, 25873, 25889, 25903, 25913, 25919, 25931, 25933, 25939, 25943, 25951, 25969, 25981, 25997, 25999, 26003, 26017, 26021, 26029, 26041, 26053, 26083, 26099, 26107, 26111, 26113, 26119, 26141, 26153, 26161, 26171, 26177, 26183, 26189, 26203, 26209, 26227, 26237, 26249, 26251, 26261, 26263, 26267, 26293, 26297, 26309, 26317, 26321, 26339, 26347, 26357, 26371, 26387, 26393, 26399, 26407, 26417, 26423, 26431, 26437, 26449, 26459, 26479, 26489, 26497, 26501, 26513, 26539, 26557, 26561, 26573, 26591, 26597, 26627, 26633, 26641, 26647, 26669, 26681, 26683, 26687, 26693, 26699, 26701, 26711, 26713, 26717, 26723, 26729, 26731, 26737, 26759, 26777, 26783, 26801, 26813, 26821, 26833, 26839, 26849, 26861, 26863, 26879, 26881, 26891, 26893, 26903, 26921, 26927, 26947, 26951, 26953, 26959, 26981, 26987, 26993, 27011, 27017, 27031, 27043, 27059, 27061, 27067, 27073, 27077, 27091, 27103, 27107, 27109, 27127, 27143, 27179, 27191, 27197, 27211, 27239, 27241, 27253, 27259, 27271, 27277, 27281, 27283, 27299, 27329, 27337, 27361, 27367, 27397, 27407, 27409, 27427, 27431, 27437, 27449, 27457, 27479, 27481, 27487, 27509, 27527, 27529, 27539, 27541, 27551, 27581, 27583, 27611, 27617, 27631, 27647, 27653, 27673, 27689, 27691, 27697, 27701, 27733, 27737, 27739, 27743, 27749, 27751, 27763, 27767, 27773, 27779, 27791, 27793, 27799, 27803, 27809, 27817, 27823, 27827, 27847, 27851, 27883, 27893, 27901, 27917, 27919, 27941, 27943, 27947, 27953, 27961, 27967, 27983, 27997, 28001, 28019, 28027, 28031, 28051, 28057, 28069, 28081, 28087, 28097, 28099, 28109, 28111, 28123, 28151, 28163, 28181, 28183, 28201, 28211, 28219, 28229, 28277, 28279, 28283, 28289, 28297, 28307, 28309, 28319, 28349, 28351, 28387, 28393, 28403, 28409, 28411, 28429, 28433, 28439, 28447, 28463, 28477, 28493, 28499, 28513, 28517, 28537, 28541, 28547, 28549, 28559, 28571, 28573, 28579, 28591, 28597, 28603, 28607, 28619, 28621, 28627, 28631, 28643, 28649, 28657, 28661, 28663, 28669, 28687, 28697, 28703, 28711, 28723, 28729, 28751, 28753, 28759, 28771, 28789, 28793, 28807, 28813, 28817, 28837, 28843, 28859, 28867, 28871, 28879, 28901, 28909, 28921, 28927, 28933, 28949, 28961, 28979, 29009, 29017, 29021, 29023, 29027, 29033, 29059, 29063, 29077, 29101, 29123, 29129, 29131, 29137, 29147, 29153, 29167, 29173, 29179, 29191, 29201, 29207, 29209, 29221, 29231, 29243, 29251, 29269, 29287, 29297, 29303, 29311, 29327, 29333, 29339, 29347, 29363, 29383, 29387, 29389, 29399, 29401, 29411, 29423, 29429, 29437, 29443, 29453, 29473, 29483, 29501, 29527, 29531, 29537, 29567, 29569, 29573, 29581, 29587, 29599, 29611, 29629, 29633, 29641, 29663, 29669, 29671, 29683, 29717, 29723, 29741, 29753, 29759, 29761, 29789, 29803, 29819, 29833, 29837, 29851, 29863, 29867, 29873, 29879, 29881, 29917, 29921, 29927, 29947, 29959, 29983, 29989, 30011, 30013, 30029, 30047, 30059, 30071, 30089, 30091, 30097, 30103, 30109, 30113, 30119, 30133, 30137, 30139, 30161, 30169, 30181, 30187, 30197, 30203, 30211, 30223, 30241, 30253, 30259, 30269, 30271, 30293, 30307, 30313, 30319, 30323, 30341, 30347, 30367, 30389, 30391, 30403, 30427, 30431, 30449, 30467, 30469, 30491, 30493, 30497, 30509, 30517, 30529, 30539, 30553, 30557, 30559, 30577, 30593, 30631, 30637, 30643, 30649, 30661, 30671, 30677, 30689, 30697, 30703, 30707, 30713, 30727, 30757, 30763, 30773, 30781, 30803, 30809, 30817, 30829, 30839, 30841, 30851, 30853, 30859, 30869, 30871, 30881, 30893, 30911, 30931, 30937, 30941, 30949, 30971, 30977, 30983, 31013, 31019, 31033, 31039, 31051, 31063, 31069, 31079, 31081, 31091, 31121, 31123, 31139, 31147, 31151, 31153, 31159, 31177, 31181, 31183, 31189, 31193, 31219, 31223, 31231, 31237, 31247, 31249, 31253, 31259, 31267, 31271, 31277, 31307, 31319, 31321, 31327, 31333, 31337, 31357, 31379, 31387, 31391, 31393, 31397, 31469, 31477, 31481, 31489, 31511, 31513, 31517, 31531, 31541, 31543, 31547, 31567, 31573, 31583, 31601, 31607, 31627, 31643, 31649, 31657, 31663, 31667, 31687, 31699, 31721, 31723, 31727, 31729, 31741, 31751, 31769, 31771, 31793, 31799, 31817, 31847, 31849, 31859, 31873, 31883, 31891, 31907, 31957, 31963, 31973, 31981, 31991, 32003, 32009, 32027, 32029, 32051, 32057, 32059, 32063, 32069, 32077, 32083, 32089, 32099, 32117, 32119, 32141, 32143, 32159, 32173, 32183, 32189, 32191, 32203, 32213, 32233, 32237, 32251, 32257, 32261, 32297, 32299, 32303, 32309, 32321, 32323, 32327, 32341, 32353, 32359, 32363, 32369, 32371, 32377, 32381, 32401, 32411, 32413, 32423, 32429, 32441, 32443, 32467, 32479, 32491, 32497, 32503, 32507, 32531, 32533, 32537, 32561, 32563, 32569, 32573, 32579, 32587, 32603, 32609, 32611, 32621, 32633, 32647, 32653, 32687, 32693, 32707, 32713, 32717, 32719, 32749, 32771, 32779, 32783, 32789, 32797, 32801, 32803, 32831, 32833, 32839, 32843, 32869, 32887, 32909, 32911, 32917, 32933, 32939, 32941, 32957, 32969, 32971, 32983, 32987, 32993, 32999, 33013, 33023, 33029, 33037, 33049, 33053, 33071, 33073, 33083, 33091, 33107, 33113, 33119, 33149, 33151, 33161, 33179, 33181, 33191, 33199, 33203, 33211, 33223, 33247, 33287, 33289, 33301, 33311, 33317, 33329, 33331, 33343, 33347, 33349, 33353, 33359, 33377, 33391, 33403, 33409, 33413, 33427, 33457, 33461, 33469, 33479, 33487, 33493, 33503, 33521, 33529, 33533, 33547, 33563, 33569, 33577, 33581, 33587, 33589, 33599, 33601, 33613, 33617, 33619, 33623, 33629, 33637, 33641, 33647, 33679, 33703, 33713, 33721, 33739, 33749, 33751, 33757, 33767, 33769, 33773, 33791, 33797, 33809, 33811, 33827, 33829, 33851, 33857, 33863, 33871, 33889, 33893, 33911, 33923, 33931, 33937, 33941, 33961, 33967, 33997, 34019, 34031, 34033, 34039, 34057, 34061, 34123, 34127, 34129, 34141, 34147, 34157, 34159, 34171, 34183, 34211, 34213, 34217, 34231, 34253, 34259, 34261, 34267, 34273, 34283, 34297, 34301, 34303, 34313, 34319, 34327, 34337, 34351, 34361, 34367, 34369, 34381, 34403, 34421, 34429, 34439, 34457, 34469, 34471, 34483, 34487, 34499, 34501, 34511, 34513, 34519, 34537, 34543, 34549, 34583, 34589, 34591, 34603, 34607, 34613, 34631, 34649, 34651, 34667, 34673, 34679, 34687, 34693, 34703, 34721, 34729, 34739, 34747, 34757, 34759, 34763, 34781, 34807, 34819, 34841, 34843, 34847, 34849, 34871, 34877, 34883, 34897, 34913, 34919, 34939, 34949, 34961, 34963, 34981, 35023, 35027, 35051, 35053, 35059, 35069, 35081, 35083, 35089, 35099, 35107, 35111, 35117, 35129, 35141, 35149, 35153, 35159, 35171, 35201, 35221, 35227, 35251, 35257, 35267, 35279, 35281, 35291, 35311, 35317, 35323, 35327, 35339, 35353, 35363, 35381, 35393, 35401, 35407, 35419, 35423, 35437, 35447, 35449, 35461, 35491, 35507, 35509, 35521, 35527, 35531, 35533, 35537, 35543, 35569, 35573, 35591, 35593, 35597, 35603, 35617, 35671, 35677, 35729, 35731, 35747, 35753, 35759, 35771, 35797, 35801, 35803, 35809, 35831, 35837, 35839, 35851, 35863, 35869, 35879, 35897, 35899, 35911, 35923, 35933, 35951, 35963, 35969, 35977, 35983, 35993, 35999, 36007, 36011, 36013, 36017, 36037, 36061, 36067, 36073, 36083, 36097, 36107, 36109, 36131, 36137, 36151, 36161, 36187, 36191, 36209, 36217, 36229, 36241, 36251, 36263, 36269, 36277, 36293, 36299, 36307, 36313, 36319, 36341, 36343, 36353, 36373, 36383, 36389, 36433, 36451, 36457, 36467, 36469, 36473, 36479, 36493, 36497, 36523, 36527, 36529, 36541, 36551, 36559, 36563, 36571, 36583, 36587, 36599, 36607, 36629, 36637, 36643, 36653, 36671, 36677, 36683, 36691, 36697, 36709, 36713, 36721, 36739, 36749, 36761, 36767, 36779, 36781, 36787, 36791, 36793, 36809, 36821, 36833, 36847, 36857, 36871, 36877, 36887, 36899, 36901, 36913, 36919, 36923, 36929, 36931, 36943, 36947, 36973, 36979, 36997, 37003, 37013, 37019, 37021, 37039, 37049, 37057, 37061, 37087, 37097, 37117, 37123, 37139, 37159, 37171, 37181, 37189, 37199, 37201, 37217, 37223, 37243, 37253, 37273, 37277, 37307, 37309, 37313, 37321, 37337, 37339, 37357, 37361, 37363, 37369, 37379, 37397, 37409, 37423, 37441, 37447, 37463, 37483, 37489, 37493, 37501, 37507, 37511, 37517, 37529, 37537, 37547, 37549, 37561, 37567, 37571, 37573, 37579, 37589, 37591, 37607, 37619, 37633, 37643, 37649, 37657, 37663, 37691, 37693, 37699, 37717, 37747, 37781, 37783, 37799, 37811, 37813, 37831, 37847, 37853, 37861, 37871, 37879, 37889, 37897, 37907, 37951, 37957, 37963, 37967, 37987, 37991, 37993, 37997, 38011, 38039, 38047, 38053, 38069, 38083, 38113, 38119, 38149, 38153, 38167, 38177, 38183, 38189, 38197, 38201, 38219, 38231, 38237, 38239, 38261, 38273, 38281, 38287, 38299, 38303, 38317, 38321, 38327, 38329, 38333, 38351, 38371, 38377, 38393, 38431, 38447, 38449, 38453, 38459, 38461, 38501, 38543, 38557, 38561, 38567, 38569, 38593, 38603, 38609, 38611, 38629, 38639, 38651, 38653, 38669, 38671, 38677, 38693, 38699, 38707, 38711, 38713, 38723, 38729, 38737, 38747, 38749, 38767, 38783, 38791, 38803, 38821, 38833, 38839, 38851, 38861, 38867, 38873, 38891, 38903, 38917, 38921, 38923, 38933, 38953, 38959, 38971, 38977, 38993, 39019, 39023, 39041, 39043, 39047, 39079, 39089, 39097, 39103, 39107, 39113, 39119, 39133, 39139, 39157, 39161, 39163, 39181, 39191, 39199, 39209, 39217, 39227, 39229, 39233, 39239, 39241, 39251, 39293, 39301, 39313, 39317, 39323, 39341, 39343, 39359, 39367, 39371, 39373, 39383, 39397, 39409, 39419, 39439, 39443, 39451, 39461, 39499, 39503, 39509, 39511, 39521, 39541, 39551, 39563, 39569, 39581, 39607, 39619, 39623, 39631, 39659, 39667, 39671, 39679, 39703, 39709, 39719, 39727, 39733, 39749, 39761, 39769, 39779, 39791, 39799, 39821, 39827, 39829, 39839, 39841, 39847, 39857, 39863, 39869, 39877, 39883, 39887, 39901, 39929, 39937, 39953, 39971, 39979, 39983, 39989, 40009, 40013, 40031, 40037, 40039, 40063, 40087, 40093, 40099, 40111, 40123, 40127, 40129, 40151, 40153, 40163, 40169, 40177, 40189, 40193, 40213, 40231, 40237, 40241, 40253, 40277, 40283, 40289, 40343, 40351, 40357, 40361, 40387, 40423, 40427, 40429, 40433, 40459, 40471, 40483, 40487, 40493, 40499, 40507, 40519, 40529, 40531, 40543, 40559, 40577, 40583, 40591, 40597, 40609, 40627, 40637, 40639, 40693, 40697, 40699, 40709, 40739, 40751, 40759, 40763, 40771, 40787, 40801, 40813, 40819, 40823, 40829, 40841, 40847, 40849, 40853, 40867, 40879, 40883, 40897, 40903, 40927, 40933, 40939, 40949, 40961, 40973, 40993, 41011, 41017, 41023, 41039, 41047, 41051, 41057, 41077, 41081, 41113, 41117, 41131, 41141, 41143, 41149, 41161, 41177, 41179, 41183, 41189, 41201, 41203, 41213, 41221, 41227, 41231, 41233, 41243, 41257, 41263, 41269, 41281, 41299, 41333, 41341, 41351, 41357, 41381, 41387, 41389, 41399, 41411, 41413, 41443, 41453, 41467, 41479, 41491, 41507, 41513, 41519, 41521, 41539, 41543, 41549, 41579, 41593, 41597, 41603, 41609, 41611, 41617, 41621, 41627, 41641, 41647, 41651, 41659, 41669, 41681, 41687, 41719, 41729, 41737, 41759, 41761, 41771, 41777, 41801, 41809, 41813, 41843, 41849, 41851, 41863, 41879, 41887, 41893, 41897, 41903, 41911, 41927, 41941, 41947, 41953, 41957, 41959, 41969, 41981, 41983, 41999, 42013, 42017, 42019, 42023, 42043, 42061, 42071, 42073, 42083, 42089, 42101, 42131, 42139, 42157, 42169, 42179, 42181, 42187, 42193, 42197, 42209, 42221, 42223, 42227, 42239, 42257, 42281, 42283, 42293, 42299, 42307, 42323, 42331, 42337, 42349, 42359, 42373, 42379, 42391, 42397, 42403, 42407, 42409, 42433, 42437, 42443, 42451, 42457, 42461, 42463, 42467, 42473, 42487, 42491, 42499, 42509, 42533, 42557, 42569, 42571, 42577, 42589, 42611, 42641, 42643, 42649, 42667, 42677, 42683, 42689, 42697, 42701, 42703, 42709, 42719, 42727, 42737, 42743, 42751, 42767, 42773, 42787, 42793, 42797, 42821, 42829, 42839, 42841, 42853, 42859, 42863, 42899, 42901, 42923, 42929, 42937, 42943, 42953, 42961, 42967, 42979, 42989, 43003, 43013, 43019, 43037, 43049, 43051, 43063, 43067, 43093, 43103, 43117, 43133, 43151, 43159, 43177, 43189, 43201, 43207, 43223, 43237, 43261, 43271, 43283, 43291, 43313, 43319, 43321, 43331, 43391, 43397, 43399, 43403, 43411, 43427, 43441, 43451, 43457, 43481, 43487, 43499, 43517, 43541, 43543, 43573, 43577, 43579, 43591, 43597, 43607, 43609, 43613, 43627, 43633, 43649, 43651, 43661, 43669, 43691, 43711, 43717, 43721, 43753, 43759, 43777, 43781, 43783, 43787, 43789, 43793, 43801, 43853, 43867, 43889, 43891, 43913, 43933, 43943, 43951, 43961, 43963, 43969, 43973, 43987, 43991, 43997, 44017, 44021, 44027, 44029, 44041, 44053, 44059, 44071, 44087, 44089, 44101, 44111, 44119, 44123, 44129, 44131, 44159, 44171, 44179, 44189, 44201, 44203, 44207, 44221, 44249, 44257, 44263, 44267, 44269, 44273, 44279, 44281, 44293, 44351, 44357, 44371, 44381, 44383, 44389, 44417, 44449, 44453, 44483, 44491, 44497, 44501, 44507, 44519, 44531, 44533, 44537, 44543, 44549, 44563, 44579, 44587, 44617, 44621, 44623, 44633, 44641, 44647, 44651, 44657, 44683, 44687, 44699, 44701, 44711, 44729, 44741, 44753, 44771, 44773, 44777, 44789, 44797, 44809, 44819, 44839, 44843, 44851, 44867, 44879, 44887, 44893, 44909, 44917, 44927, 44939, 44953, 44959, 44963, 44971, 44983, 44987, 45007, 45013, 45053, 45061, 45077, 45083, 45119, 45121, 45127, 45131, 45137, 45139, 45161, 45179, 45181, 45191, 45197, 45233, 45247, 45259, 45263, 45281, 45289, 45293, 45307, 45317, 45319, 45329, 45337, 45341, 45343, 45361, 45377, 45389, 45403, 45413, 45427, 45433, 45439, 45481, 45491, 45497, 45503, 45523, 45533, 45541, 45553, 45557, 45569, 45587, 45589, 45599, 45613, 45631, 45641, 45659, 45667, 45673, 45677, 45691, 45697, 45707, 45737, 45751, 45757, 45763, 45767, 45779, 45817, 45821, 45823, 45827, 45833, 45841, 45853, 45863, 45869, 45887, 45893, 45943, 45949, 45953, 45959, 45971, 45979, 45989, 46021, 46027, 46049, 46051, 46061, 46073, 46091, 46093, 46099, 46103, 46133, 46141, 46147, 46153, 46171, 46181, 46183, 46187, 46199, 46219, 46229, 46237, 46261, 46271, 46273, 46279, 46301, 46307, 46309, 46327, 46337, 46349, 46351, 46381, 46399, 46411, 46439, 46441, 46447, 46451, 46457, 46471, 46477, 46489, 46499, 46507, 46511, 46523, 46549, 46559, 46567, 46573, 46589, 46591, 46601, 46619, 46633, 46639, 46643, 46649, 46663, 46679, 46681, 46687, 46691, 46703, 46723, 46727, 46747, 46751, 46757, 46769, 46771, 46807, 46811, 46817, 46819, 46829, 46831, 46853, 46861, 46867, 46877, 46889, 46901, 46919, 46933, 46957, 46993, 46997, 47017, 47041, 47051, 47057, 47059, 47087, 47093, 47111, 47119, 47123, 47129, 47137, 47143, 47147, 47149, 47161, 47189, 47207, 47221, 47237, 47251, 47269, 47279, 47287, 47293, 47297, 47303, 47309, 47317, 47339, 47351, 47353, 47363, 47381, 47387, 47389, 47407, 47417, 47419, 47431, 47441, 47459, 47491, 47497, 47501, 47507, 47513, 47521, 47527, 47533, 47543, 47563, 47569, 47581, 47591, 47599, 47609, 47623, 47629, 47639, 47653, 47657, 47659, 47681, 47699, 47701, 47711, 47713, 47717, 47737, 47741, 47743, 47777, 47779, 47791, 47797, 47807, 47809, 47819, 47837, 47843, 47857, 47869, 47881, 47903, 47911, 47917, 47933, 47939, 47947, 47951, 47963, 47969, 47977, 47981, 48017, 48023, 48029, 48049, 48073, 48079, 48091, 48109, 48119, 48121, 48131, 48157, 48163, 48179, 48187, 48193, 48197, 48221, 48239, 48247, 48259, 48271, 48281, 48299, 48311, 48313, 48337, 48341, 48353, 48371, 48383, 48397, 48407, 48409, 48413, 48437, 48449, 48463, 48473, 48479, 48481, 48487, 48491, 48497, 48523, 48527, 48533, 48539, 48541, 48563, 48571, 48589, 48593, 48611, 48619, 48623, 48647, 48649, 48661, 48673, 48677, 48679, 48731, 48733, 48751, 48757, 48761, 48767, 48779, 48781, 48787, 48799, 48809, 48817, 48821, 48823, 48847, 48857, 48859, 48869, 48871, 48883, 48889, 48907, 48947, 48953, 48973, 48989, 48991, 49003, 49009, 49019, 49031, 49033, 49037, 49043, 49057, 49069, 49081, 49103, 49109, 49117, 49121, 49123, 49139, 49157, 49169, 49171, 49177, 49193, 49199, 49201, 49207, 49211, 49223, 49253, 49261, 49277, 49279, 49297, 49307, 49331, 49333, 49339, 49363, 49367, 49369, 49391, 49393, 49409, 49411, 49417, 49429, 49433, 49451, 49459, 49463, 49477, 49481, 49499, 49523, 49529, 49531, 49537, 49547, 49549, 49559, 49597, 49603, 49613, 49627, 49633, 49639, 49663, 49667, 49669, 49681, 49697, 49711, 49727, 49739, 49741, 49747, 49757, 49783, 49787, 49789, 49801, 49807, 49811, 49823, 49831, 49843, 49853, 49871, 49877, 49891, 49919, 49921, 49927, 49937, 49939, 49943, 49957, 49991, 49993, 49999, 50021, 50023, 50033, 50047, 50051, 50053, 50069, 50077, 50087, 50093, 50101, 50111, 50119, 50123, 50129, 50131, 50147, 50153, 50159, 50177, 50207, 50221, 50227, 50231, 50261, 50263, 50273, 50287, 50291, 50311, 50321, 50329, 50333, 50341, 50359, 50363, 50377, 50383, 50387, 50411, 50417, 50423, 50441, 50459, 50461, 50497, 50503, 50513, 50527, 50539, 50543, 50549, 50551, 50581, 50587, 50591, 50593, 50599, 50627, 50647, 50651, 50671, 50683, 50707, 50723, 50741, 50753, 50767, 50773, 50777, 50789, 50821, 50833, 50839, 50849, 50857, 50867, 50873, 50891, 50893, 50909, 50923, 50929, 50951, 50957, 50969, 50971, 50989, 50993, 51001, 51031, 51043, 51047, 51059, 51061, 51071, 51109, 51131, 51133, 51137, 51151, 51157, 51169, 51193, 51197, 51199, 51203, 51217, 51229, 51239, 51241, 51257, 51263, 51283, 51287, 51307, 51329, 51341, 51343, 51347, 51349, 51361, 51383, 51407, 51413, 51419, 51421, 51427, 51431, 51437, 51439, 51449, 51461, 51473, 51479, 51481, 51487, 51503, 51511, 51517, 51521, 51539, 51551, 51563, 51577, 51581, 51593, 51599, 51607, 51613, 51631, 51637, 51647, 51659, 51673, 51679, 51683, 51691, 51713, 51719, 51721, 51749, 51767, 51769, 51787, 51797, 51803, 51817, 51827, 51829, 51839, 51853, 51859, 51869, 51871, 51893, 51899, 51907, 51913, 51929, 51941, 51949, 51971, 51973, 51977, 51991, 52009, 52021, 52027, 52051, 52057, 52067, 52069, 52081, 52103, 52121, 52127, 52147, 52153, 52163, 52177, 52181, 52183, 52189, 52201, 52223, 52237, 52249, 52253, 52259, 52267, 52289, 52291, 52301, 52313, 52321, 52361, 52363, 52369, 52379, 52387, 52391, 52433, 52453, 52457, 52489, 52501, 52511, 52517, 52529, 52541, 52543, 52553, 52561, 52567, 52571, 52579, 52583, 52609, 52627, 52631, 52639, 52667, 52673, 52691, 52697, 52709, 52711, 52721, 52727, 52733, 52747, 52757, 52769, 52783, 52807, 52813, 52817, 52837, 52859, 52861, 52879, 52883, 52889, 52901, 52903, 52919, 52937, 52951, 52957, 52963, 52967, 52973, 52981, 52999, 53003, 53017, 53047, 53051, 53069, 53077, 53087, 53089, 53093, 53101, 53113, 53117, 53129, 53147, 53149, 53161, 53171, 53173, 53189, 53197, 53201, 53231, 53233, 53239, 53267, 53269, 53279, 53281, 53299, 53309, 53323, 53327, 53353, 53359, 53377, 53381, 53401, 53407, 53411, 53419, 53437, 53441, 53453, 53479, 53503, 53507, 53527, 53549, 53551, 53569, 53591, 53593, 53597, 53609, 53611, 53617, 53623, 53629, 53633, 53639, 53653, 53657, 53681, 53693, 53699, 53717, 53719, 53731, 53759, 53773, 53777, 53783, 53791, 53813, 53819, 53831, 53849, 53857, 53861, 53881, 53887, 53891, 53897, 53899, 53917, 53923, 53927, 53939, 53951, 53959, 53987, 53993, 54001, 54011, 54013, 54037, 54049, 54059, 54083, 54091, 54101, 54121, 54133, 54139, 54151, 54163, 54167, 54181, 54193, 54217, 54251, 54269, 54277, 54287, 54293, 54311, 54319, 54323, 54331, 54347, 54361, 54367, 54371, 54377, 54401, 54403, 54409, 54413, 54419, 54421, 54437, 54443, 54449, 54469, 54493, 54497, 54499, 54503, 54517, 54521, 54539, 54541, 54547, 54559, 54563, 54577, 54581, 54583, 54601, 54617, 54623, 54629, 54631, 54647, 54667, 54673, 54679, 54709, 54713, 54721, 54727, 54751, 54767, 54773, 54779, 54787, 54799, 54829, 54833, 54851, 54869, 54877, 54881, 54907, 54917, 54919, 54941, 54949, 54959, 54973, 54979, 54983, 55001, 55009, 55021, 55049, 55051, 55057, 55061, 55073, 55079, 55103, 55109, 55117, 55127, 55147, 55163, 55171, 55201, 55207, 55213, 55217, 55219, 55229, 55243, 55249, 55259, 55291, 55313, 55331, 55333, 55337, 55339, 55343, 55351, 55373, 55381, 55399, 55411, 55439, 55441, 55457, 55469, 55487, 55501, 55511, 55529, 55541, 55547, 55579, 55589, 55603, 55609, 55619, 55621, 55631, 55633, 55639, 55661, 55663, 55667, 55673, 55681, 55691, 55697, 55711, 55717, 55721, 55733, 55763, 55787, 55793, 55799, 55807, 55813, 55817, 55819, 55823, 55829, 55837, 55843, 55849, 55871, 55889, 55897, 55901, 55903, 55921, 55927, 55931, 55933, 55949, 55967, 55987, 55997, 56003, 56009, 56039, 56041, 56053, 56081, 56087, 56093, 56099, 56101, 56113, 56123, 56131, 56149, 56167, 56171, 56179, 56197, 56207, 56209, 56237, 56239, 56249, 56263, 56267, 56269, 56299, 56311, 56333, 56359, 56369, 56377, 56383, 56393, 56401, 56417, 56431, 56437, 56443, 56453, 56467, 56473, 56477, 56479, 56489, 56501, 56503, 56509, 56519, 56527, 56531, 56533, 56543, 56569, 56591, 56597, 56599, 56611, 56629, 56633, 56659, 56663, 56671, 56681, 56687, 56701, 56711, 56713, 56731, 56737, 56747, 56767, 56773, 56779, 56783, 56807, 56809, 56813, 56821, 56827, 56843, 56857, 56873, 56891, 56893, 56897, 56909, 56911, 56921, 56923, 56929, 56941, 56951, 56957, 56963, 56983, 56989, 56993, 56999, 57037, 57041, 57047, 57059, 57073, 57077, 57089, 57097, 57107, 57119, 57131, 57139, 57143, 57149, 57163, 57173, 57179, 57191, 57193, 57203, 57221, 57223, 57241, 57251, 57259, 57269, 57271, 57283, 57287, 57301, 57329, 57331, 57347, 57349, 57367, 57373, 57383, 57389, 57397, 57413, 57427, 57457, 57467, 57487, 57493, 57503, 57527, 57529, 57557, 57559, 57571, 57587, 57593, 57601, 57637, 57641, 57649, 57653, 57667, 57679, 57689, 57697, 57709, 57713, 57719, 57727, 57731, 57737, 57751, 57773, 57781, 57787, 57791, 57793, 57803, 57809, 57829, 57839, 57847, 57853, 57859, 57881, 57899, 57901, 57917, 57923, 57943, 57947, 57973, 57977, 57991, 58013, 58027, 58031, 58043, 58049, 58057, 58061, 58067, 58073, 58099, 58109, 58111, 58129, 58147, 58151, 58153, 58169, 58171, 58189, 58193, 58199, 58207, 58211, 58217, 58229, 58231, 58237, 58243, 58271, 58309, 58313, 58321, 58337, 58363, 58367, 58369, 58379, 58391, 58393, 58403, 58411, 58417, 58427, 58439, 58441, 58451, 58453, 58477, 58481, 58511, 58537, 58543, 58549, 58567, 58573, 58579, 58601, 58603, 58613, 58631, 58657, 58661, 58679, 58687, 58693, 58699, 58711, 58727, 58733, 58741, 58757, 58763, 58771, 58787, 58789, 58831, 58889, 58897, 58901, 58907, 58909, 58913, 58921, 58937, 58943, 58963, 58967, 58979, 58991, 58997, 59009, 59011, 59021, 59023, 59029, 59051, 59053, 59063, 59069, 59077, 59083, 59093, 59107, 59113, 59119, 59123, 59141, 59149, 59159, 59167, 59183, 59197, 59207, 59209, 59219, 59221, 59233, 59239, 59243, 59263, 59273, 59281, 59333, 59341, 59351, 59357, 59359, 59369, 59377, 59387, 59393, 59399, 59407, 59417, 59419, 59441, 59443, 59447, 59453, 59467, 59471, 59473, 59497, 59509, 59513, 59539, 59557, 59561, 59567, 59581, 59611, 59617, 59621, 59627, 59629, 59651, 59659, 59663, 59669, 59671, 59693, 59699, 59707, 59723, 59729, 59743, 59747, 59753, 59771, 59779, 59791, 59797, 59809, 59833, 59863, 59879, 59887, 59921, 59929, 59951, 59957, 59971, 59981, 59999, 60013, 60017, 60029, 60037, 60041, 60077, 60083, 60089, 60091, 60101, 60103, 60107, 60127, 60133, 60139, 60149, 60161, 60167, 60169, 60209, 60217, 60223, 60251, 60257, 60259, 60271, 60289, 60293, 60317, 60331, 60337, 60343, 60353, 60373, 60383, 60397, 60413, 60427, 60443, 60449, 60457, 60493, 60497, 60509, 60521, 60527, 60539, 60589, 60601, 60607, 60611, 60617, 60623, 60631, 60637, 60647, 60649, 60659, 60661, 60679, 60689, 60703, 60719, 60727, 60733, 60737, 60757, 60761, 60763, 60773, 60779, 60793, 60811, 60821, 60859, 60869, 60887, 60889, 60899, 60901, 60913, 60917, 60919, 60923, 60937, 60943, 60953, 60961, 61001, 61007, 61027, 61031, 61043, 61051, 61057, 61091, 61099, 61121, 61129, 61141, 61151, 61153, 61169, 61211, 61223, 61231, 61253, 61261, 61283, 61291, 61297, 61331, 61333, 61339, 61343, 61357, 61363, 61379, 61381, 61403, 61409, 61417, 61441, 61463, 61469, 61471, 61483, 61487, 61493, 61507, 61511, 61519, 61543, 61547, 61553, 61559, 61561, 61583, 61603, 61609, 61613, 61627, 61631, 61637, 61643, 61651, 61657, 61667, 61673, 61681, 61687, 61703, 61717, 61723, 61729, 61751, 61757, 61781, 61813, 61819, 61837, 61843, 61861, 61871, 61879, 61909, 61927, 61933, 61949, 61961, 61967, 61979, 61981, 61987, 61991, 62003, 62011, 62017, 62039, 62047, 62053, 62057, 62071, 62081, 62099, 62119, 62129, 62131, 62137, 62141, 62143, 62171, 62189, 62191, 62201, 62207, 62213, 62219, 62233, 62273, 62297, 62299, 62303, 62311, 62323, 62327, 62347, 62351, 62383, 62401, 62417, 62423, 62459, 62467, 62473, 62477, 62483, 62497, 62501, 62507, 62533, 62539, 62549, 62563, 62581, 62591, 62597, 62603, 62617, 62627, 62633, 62639, 62653, 62659, 62683, 62687, 62701, 62723, 62731, 62743, 62753, 62761, 62773, 62791, 62801, 62819, 62827, 62851, 62861, 62869, 62873, 62897, 62903, 62921, 62927, 62929, 62939, 62969, 62971, 62981, 62983, 62987, 62989, 63029, 63031, 63059, 63067, 63073, 63079, 63097, 63103, 63113, 63127, 63131, 63149, 63179, 63197, 63199, 63211, 63241, 63247, 63277, 63281, 63299, 63311, 63313, 63317, 63331, 63337, 63347, 63353, 63361, 63367, 63377, 63389, 63391, 63397, 63409, 63419, 63421, 63439, 63443, 63463, 63467, 63473, 63487, 63493, 63499, 63521, 63527, 63533, 63541, 63559, 63577, 63587, 63589, 63599, 63601, 63607, 63611, 63617, 63629, 63647, 63649, 63659, 63667, 63671, 63689, 63691, 63697, 63703, 63709, 63719, 63727, 63737, 63743, 63761, 63773, 63781, 63793, 63799, 63803, 63809, 63823, 63839, 63841, 63853, 63857, 63863, 63901, 63907, 63913, 63929, 63949, 63977, 63997, 64007, 64013, 64019, 64033, 64037, 64063, 64067, 64081, 64091, 64109, 64123, 64151, 64153, 64157, 64171, 64187, 64189, 64217, 64223, 64231, 64237, 64271, 64279, 64283, 64301, 64303, 64319, 64327, 64333, 64373, 64381, 64399, 64403, 64433, 64439, 64451, 64453, 64483, 64489, 64499, 64513, 64553, 64567, 64577, 64579, 64591, 64601, 64609, 64613, 64621, 64627, 64633, 64661, 64663, 64667, 64679, 64693, 64709, 64717, 64747, 64763, 64781, 64783, 64793, 64811, 64817, 64849, 64853, 64871, 64877, 64879, 64891, 64901, 64919, 64921, 64927, 64937, 64951, 64969, 64997, 65003, 65011, 65027, 65029, 65033, 65053, 65063, 65071, 65089, 65099, 65101, 65111, 65119, 65123, 65129, 65141, 65147, 65167, 65171, 65173, 65179, 65183, 65203, 65213, 65239, 65257, 65267, 65269, 65287, 65293, 65309, 65323, 65327, 65353, 65357, 65371, 65381, 65393, 65407, 65413, 65419, 65423, 65437, 65447, 65449, 65479, 65497, 65519, 65521, }; #define NPRIMES (sizeof(primes) / sizeof(*primes)) /* * Generate a prime. We can deal with various extra properties of * the prime: * * - to speed up use in RSA, we can arrange to select a prime with * the property (prime % modulus) != residue. * * - for use in DSA, we can arrange to select a prime which is one * more than a multiple of a dirty great bignum. In this case * `bits' gives the size of the factor by which we _multiply_ * that bignum, rather than the size of the whole number. */ Bignum primegen(int bits, int modulus, int residue, Bignum factor, int phase, progfn_t pfn, void *pfnparam) { int i, k, v, byte, bitsleft, check, checks; unsigned long delta; unsigned long moduli[NPRIMES + 1]; unsigned long residues[NPRIMES + 1]; unsigned long multipliers[NPRIMES + 1]; Bignum p, pm1, q, wqp, wqp2; int progress = 0; byte = 0; bitsleft = 0; STARTOVER: pfn(pfnparam, PROGFN_PROGRESS, phase, ++progress); /* * Generate a k-bit random number with top and bottom bits set. * Alternatively, if `factor' is nonzero, generate a k-bit * random number with the top bit set and the bottom bit clear, * multiply it by `factor', and add one. */ p = bn_power_2(bits - 1); for (i = 0; i < bits; i++) { if (i == 0 || i == bits - 1) v = (i != 0 || !factor) ? 1 : 0; else { if (bitsleft <= 0) bitsleft = 8, byte = random_byte(); v = byte & 1; byte >>= 1; bitsleft--; } bignum_set_bit(p, i, v); |
︙ | ︙ | |||
1051 1052 1053 1054 1055 1056 1057 | /* * We have a prime! */ freebn(q); freebn(pm1); return p; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1392 1393 1394 1395 1396 1397 1398 | /* * We have a prime! */ freebn(q); freebn(pm1); return p; } |
Changes to sshpubk.c.
︙ | ︙ | |||
63 64 65 66 67 68 69 | if (len - i < 4) goto end; /* reserved field not present */ if (buf[i] != 0 || buf[i + 1] != 0 || buf[i + 2] != 0 || buf[i + 3] != 0) goto end; /* reserved field nonzero, panic! */ i += 4; /* Now the serious stuff. An ordinary SSH-1 public key. */ | | | < | | | 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | if (len - i < 4) goto end; /* reserved field not present */ if (buf[i] != 0 || buf[i + 1] != 0 || buf[i + 2] != 0 || buf[i + 3] != 0) goto end; /* reserved field nonzero, panic! */ i += 4; /* Now the serious stuff. An ordinary SSH-1 public key. */ i += makekey(buf + i, len, key, NULL, 1); if (i < 0) goto end; /* overran */ /* Next, the comment field. */ j = GET_32BIT(buf + i); i += 4; if (len - i < j) goto end; comment = snewn(j + 1, char); if (comment) { memcpy(comment, buf + i, j); comment[j] = '\0'; } i += j; |
︙ | ︙ | |||
105 106 107 108 109 110 111 | * Decrypt remainder of buffer. */ if (ciphertype) { MD5Init(&md5c); MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); MD5Final(keybuf, &md5c); des3_decrypt_pubkey(keybuf, buf + i, (len - i + 7) & ~7); | | | 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | * Decrypt remainder of buffer. */ if (ciphertype) { MD5Init(&md5c); MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); MD5Final(keybuf, &md5c); des3_decrypt_pubkey(keybuf, buf + i, (len - i + 7) & ~7); memset(keybuf, 0, sizeof(keybuf)); /* burn the evidence */ } /* * We are now in the secret part of the key. The first four * bytes should be of the form a, b, a, b. */ if (len - i < 4) |
︙ | ︙ | |||
147 148 149 150 151 152 153 | *error = "rsa_verify failed"; freersakey(key); ret = 0; } else ret = 1; end: | | | | 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | *error = "rsa_verify failed"; freersakey(key); ret = 0; } else ret = 1; end: memset(buf, 0, sizeof(buf)); /* burn the evidence */ return ret; } int loadrsakey(const Filename *filename, struct RSAKey *key, char *passphrase, const char **errorstr) { FILE *fp; char buf[64]; int ret = 0; const char *error = NULL; fp = f_open(*filename, "rb", FALSE); if (!fp) { error = "can't open file"; goto end; } /* * Read the first line of the file and see if it's a v1 private |
︙ | ︙ | |||
200 201 202 203 204 205 206 | * well. */ int rsakey_encrypted(const Filename *filename, char **comment) { FILE *fp; char buf[64]; | | | 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 | * well. */ int rsakey_encrypted(const Filename *filename, char **comment) { FILE *fp; char buf[64]; fp = f_open(*filename, "rb", FALSE); if (!fp) return 0; /* doesn't even exist */ /* * Read the first line of the file and see if it's a v1 private * key file. */ |
︙ | ︙ | |||
238 239 240 241 242 243 244 | const char *error = NULL; /* Default return if we fail. */ *blob = NULL; *bloblen = 0; ret = 0; | | > < | 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 | const char *error = NULL; /* Default return if we fail. */ *blob = NULL; *bloblen = 0; ret = 0; fp = f_open(*filename, "rb", FALSE); if (!fp) { error = "can't open file"; goto end; } /* * Read the first line of the file and see if it's a v1 private * key file. */ if (fgets(buf, sizeof(buf), fp) && !strcmp(buf, rsa_signature)) { memset(&key, 0, sizeof(key)); if (loadrsakey_main(fp, &key, TRUE, commentptr, NULL, &error)) { *blob = rsa_public_blob(&key, bloblen); freersakey(&key); ret = 1; fp = NULL; } } else { error = "not an SSH-1 RSA file"; } end: if (fp) fclose(fp); |
︙ | ︙ | |||
355 356 357 358 359 360 361 | * Now encrypt the encrypted portion. */ if (passphrase) { MD5Init(&md5c); MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); MD5Final(keybuf, &md5c); des3_encrypt_pubkey(keybuf, estart, p - estart); | | | | 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 | * Now encrypt the encrypted portion. */ if (passphrase) { MD5Init(&md5c); MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); MD5Final(keybuf, &md5c); des3_encrypt_pubkey(keybuf, estart, p - estart); memset(keybuf, 0, sizeof(keybuf)); /* burn the evidence */ } /* * Done. Write the result to the file. */ fp = f_open(*filename, "wb", TRUE); if (fp) { int ret = (fwrite(buf, 1, p - buf, fp) == (size_t) (p - buf)); if (fclose(fp)) ret = 0; return ret; } else return 0; |
︙ | ︙ | |||
459 460 461 462 463 464 465 | */ static int read_header(FILE * fp, char *header) { int len = 39; int c; | | | 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 | */ static int read_header(FILE * fp, char *header) { int len = 39; int c; while (len > 0) { c = fgetc(fp); if (c == '\n' || c == '\r' || c == EOF) return 0; /* failure */ if (c == ':') { c = fgetc(fp); if (c != ' ') return 0; |
︙ | ︙ | |||
629 630 631 632 633 634 635 | int passlen = passphrase ? strlen(passphrase) : 0; const char *error = NULL; ret = NULL; /* return NULL for most errors */ encryption = comment = mac = NULL; public_blob = private_blob = NULL; | | < < < < < | 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 | int passlen = passphrase ? strlen(passphrase) : 0; const char *error = NULL; ret = NULL; /* return NULL for most errors */ encryption = comment = mac = NULL; public_blob = private_blob = NULL; fp = f_open(*filename, "rb", FALSE); if (!fp) { error = "can't open file"; goto error; } /* Read the first header line which contains the key type. */ if (!read_header(fp, header)) goto error; if (0 == strcmp(header, "PuTTY-User-Key-File-2")) { old_fmt = 0; } else if (0 == strcmp(header, "PuTTY-User-Key-File-1")) { /* this is an old key file; warn and then continue */ old_keyfile_warning(); old_fmt = 1; } else { error = "not a PuTTY SSH-2 private key"; goto error; } error = "file format error"; if ((b = read_body(fp)) == NULL) goto error; |
︙ | ︙ | |||
676 677 678 679 680 681 682 683 684 685 686 687 688 689 | if (!strcmp(encryption, "aes256-cbc")) { cipher = 1; cipherblk = 16; } else if (!strcmp(encryption, "none")) { cipher = 0; cipherblk = 1; } else { goto error; } /* Read the Comment header line. */ if (!read_header(fp, header) || 0 != strcmp(header, "Comment")) goto error; if ((comment = read_body(fp)) == NULL) | > | 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 | if (!strcmp(encryption, "aes256-cbc")) { cipher = 1; cipherblk = 16; } else if (!strcmp(encryption, "none")) { cipher = 0; cipherblk = 1; } else { sfree(encryption); goto error; } /* Read the Comment header line. */ if (!read_header(fp, header) || 0 != strcmp(header, "Comment")) goto error; if ((comment = read_body(fp)) == NULL) |
︙ | ︙ | |||
795 796 797 798 799 800 801 | SHA_Bytes(&s, header, sizeof(header)-1); if (cipher && passphrase) SHA_Bytes(&s, passphrase, passlen); SHA_Final(&s, mackey); hmac_sha1_simple(mackey, 20, macdata, maclen, binary); | | | | | 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 | SHA_Bytes(&s, header, sizeof(header)-1); if (cipher && passphrase) SHA_Bytes(&s, passphrase, passlen); SHA_Final(&s, mackey); hmac_sha1_simple(mackey, 20, macdata, maclen, binary); memset(mackey, 0, sizeof(mackey)); memset(&s, 0, sizeof(s)); } else { SHA_Simple(macdata, maclen, binary); } if (free_macdata) { memset(macdata, 0, maclen); sfree(macdata); } for (i = 0; i < 20; i++) sprintf(realmac + 2 * i, "%02x", binary[i]); if (strcmp(mac, realmac)) { |
︙ | ︙ | |||
882 883 884 885 886 887 888 | int public_blob_len; int i; const char *error = NULL; char *comment; public_blob = NULL; | | < < < | | 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 | int public_blob_len; int i; const char *error = NULL; char *comment; public_blob = NULL; fp = f_open(*filename, "rb", FALSE); if (!fp) { error = "can't open file"; goto error; } /* Read the first header line which contains the key type. */ if (!read_header(fp, header) || (0 != strcmp(header, "PuTTY-User-Key-File-2") && 0 != strcmp(header, "PuTTY-User-Key-File-1"))) { error = "not a PuTTY SSH-2 private key"; goto error; } error = "file format error"; if ((b = read_body(fp)) == NULL) goto error; /* Select key algorithm structure. */ alg = find_pubkey_alg(b); |
︙ | ︙ | |||
966 967 968 969 970 971 972 | FILE *fp; char header[40], *b, *comment; int ret; if (commentptr) *commentptr = NULL; | | | 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 | FILE *fp; char header[40], *b, *comment; int ret; if (commentptr) *commentptr = NULL; fp = f_open(*filename, "rb", FALSE); if (!fp) return 0; if (!read_header(fp, header) || (0 != strcmp(header, "PuTTY-User-Key-File-2") && 0 != strcmp(header, "PuTTY-User-Key-File-1"))) { fclose(fp); return 0; |
︙ | ︙ | |||
1004 1005 1006 1007 1008 1009 1010 | fclose(fp); sfree(b); return 1; } if (commentptr) *commentptr = comment; | < < | 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 | fclose(fp); sfree(b); return 1; } if (commentptr) *commentptr = comment; fclose(fp); if (!strcmp(b, "aes256-cbc")) ret = 1; else ret = 0; sfree(b); |
︙ | ︙ | |||
1122 1123 1124 1125 1126 1127 1128 | SHA_Init(&s); SHA_Bytes(&s, header, sizeof(header)-1); if (passphrase) SHA_Bytes(&s, passphrase, strlen(passphrase)); SHA_Final(&s, mackey); hmac_sha1_simple(mackey, 20, macdata, maclen, priv_mac); | | | | | | | | | | 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 | SHA_Init(&s); SHA_Bytes(&s, header, sizeof(header)-1); if (passphrase) SHA_Bytes(&s, passphrase, strlen(passphrase)); SHA_Final(&s, mackey); hmac_sha1_simple(mackey, 20, macdata, maclen, priv_mac); memset(macdata, 0, maclen); sfree(macdata); memset(mackey, 0, sizeof(mackey)); memset(&s, 0, sizeof(s)); } if (passphrase) { unsigned char key[40]; SHA_State s; passlen = strlen(passphrase); SHA_Init(&s); SHA_Bytes(&s, "\0\0\0\0", 4); SHA_Bytes(&s, passphrase, passlen); SHA_Final(&s, key + 0); SHA_Init(&s); SHA_Bytes(&s, "\0\0\0\1", 4); SHA_Bytes(&s, passphrase, passlen); SHA_Final(&s, key + 20); aes256_encrypt_pubkey(key, priv_blob_encrypted, priv_encrypted_len); memset(key, 0, sizeof(key)); memset(&s, 0, sizeof(s)); } fp = f_open(*filename, "w", TRUE); if (!fp) return 0; fprintf(fp, "PuTTY-User-Key-File-2: %s\n", key->alg->name); fprintf(fp, "Encryption: %s\n", cipherstr); fprintf(fp, "Comment: %s\n", key->comment); fprintf(fp, "Public-Lines: %d\n", base64_lines(pub_blob_len)); base64_encode(fp, pub_blob, pub_blob_len, 64); fprintf(fp, "Private-Lines: %d\n", base64_lines(priv_encrypted_len)); base64_encode(fp, priv_blob_encrypted, priv_encrypted_len, 64); fprintf(fp, "Private-MAC: "); for (i = 0; i < 20; i++) fprintf(fp, "%02x", priv_mac[i]); fprintf(fp, "\n"); fclose(fp); sfree(pub_blob); memset(priv_blob, 0, priv_blob_len); sfree(priv_blob); sfree(priv_blob_encrypted); return 1; } /* ---------------------------------------------------------------------- * A function to determine the type of a private key file. Returns * 0 on failure, 1 or 2 on success. */ int key_type(const Filename *filename) { FILE *fp; char buf[32]; const char putty2_sig[] = "PuTTY-User-Key-File-"; const char sshcom_sig[] = "---- BEGIN SSH2 ENCRYPTED PRIVAT"; const char openssh_sig[] = "-----BEGIN "; int i; fp = f_open(*filename, "r", FALSE); if (!fp) return SSH_KEYTYPE_UNOPENABLE; i = fread(buf, 1, sizeof(buf), fp); fclose(fp); if (i < 0) return SSH_KEYTYPE_UNOPENABLE; if (i < 32) |
︙ | ︙ |
Changes to sshrand.c.
︙ | ︙ | |||
45 46 47 48 49 50 51 | int stir_pending; }; static struct RandPool pool; int random_active = 0; long next_noise_collection; | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | int stir_pending; }; static struct RandPool pool; int random_active = 0; long next_noise_collection; static void random_stir(void) { word32 block[HASHINPUT / sizeof(word32)]; word32 digest[HASHSIZE / sizeof(word32)]; int i, j, k; /* * noise_get_light will call random_add_noise, which may call * back to here. Prevent recursive stirs. */ if (pool.stir_pending) return; pool.stir_pending = TRUE; noise_get_light(random_add_noise); SHATransform((word32 *) pool.incoming, (word32 *) pool.incomingb); pool.incomingpos = 0; /* * Chunks of this code are blatantly endianness-dependent, but * as it's all random bits anyway, WHO CARES? */ |
︙ | ︙ | |||
140 141 142 143 144 145 146 | /* * Stick the result back into the pool. */ for (k = 0; k < sizeof(digest) / sizeof(*digest); k++) ((word32 *) (pool.pool + j))[k] = digest[k]; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | /* * Stick the result back into the pool. */ for (k = 0; k < sizeof(digest) / sizeof(*digest); k++) ((word32 *) (pool.pool + j))[k] = digest[k]; } } /* * Might as well save this value back into `incoming', just so * there'll be some extra bizarreness there. */ SHATransform(digest, block); memcpy(pool.incoming, digest, sizeof(digest)); pool.poolpos = sizeof(pool.incoming); pool.stir_pending = FALSE; } void random_add_noise(void *noise, int length) { unsigned char *p = noise; int i; |
︙ | ︙ | |||
270 271 272 273 274 275 276 | } for (i = 0; i < length; i++) pool.pool[i] ^= *p++; pool.poolpos = i; } | | | > > | | | | < < < < | 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 | } for (i = 0; i < length; i++) pool.pool[i] ^= *p++; pool.poolpos = i; } static void random_timer(void *ctx, long now) { if (random_active > 0 && now - next_noise_collection >= 0) { noise_regular(); next_noise_collection = schedule_timer(NOISE_REGULAR_INTERVAL, random_timer, &pool); } } void random_ref(void) { if (!random_active) { memset(&pool, 0, sizeof(pool)); /* just to start with */ noise_get_heavy(random_add_heavynoise_bitbybit); random_stir(); next_noise_collection = schedule_timer(NOISE_REGULAR_INTERVAL, random_timer, &pool); } random_active++; } void random_unref(void) { random_active--; assert(random_active >= 0); if (random_active) return; expire_timer_context(&pool); } int random_byte(void) { if (pool.poolpos >= POOLSIZE) random_stir(); return pool.pool[pool.poolpos++]; } void random_get_savedata(void **data, int *len) |
︙ | ︙ |
Changes to sshrsa.c.
︙ | ︙ | |||
106 107 108 109 110 111 112 | len = (bignum_bitcount(b) + 8) / 8; PUT_32BIT(lenbuf, len); SHA512_Bytes(s, lenbuf, 4); while (len-- > 0) { lenbuf[0] = bignum_byte(b, len); SHA512_Bytes(s, lenbuf, 1); } | | | 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | len = (bignum_bitcount(b) + 8) / 8; PUT_32BIT(lenbuf, len); SHA512_Bytes(s, lenbuf, 4); while (len-- > 0) { lenbuf[0] = bignum_byte(b, len); SHA512_Bytes(s, lenbuf, 1); } memset(lenbuf, 0, sizeof(lenbuf)); } /* * Compute (base ^ exp) % mod, provided mod == p * q, with p,q * distinct primes, and iqmp is the multiplicative inverse of q mod p. * Uses Chinese Remainder Theorem to speed computation up over the * obvious implementation of a single big modpow. |
︙ | ︙ | |||
269 270 271 272 273 274 275 | * Now check that this number is strictly greater than * zero, and strictly less than modulus. */ if (bignum_cmp(random, Zero) <= 0 || bignum_cmp(random, key->modulus) >= 0) { freebn(random); continue; | | | < < < < < < < | < < > | 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 | * Now check that this number is strictly greater than * zero, and strictly less than modulus. */ if (bignum_cmp(random, Zero) <= 0 || bignum_cmp(random, key->modulus) >= 0) { freebn(random); continue; } else { break; } } /* * RSA blinding relies on the fact that (xy)^d mod n is equal * to (x^d mod n) * (y^d mod n) mod n. We invent a random pair * y and y^d; then we multiply x by y, raise to the power d mod * n as usual, and divide by y^d to recover x^d. Thus an * attacker can't correlate the timing of the modpow with the * input, because they don't know anything about the number * that was input to the actual modpow. * * The clever bit is that we don't have to do a huge modpow to * get y and y^d; we will use the number we just invented as * _y^d_, and use the _public_ exponent to compute (y^d)^e = y * from it, which is much faster to do. */ random_encrypted = crt_modpow(random, key->exponent, key->modulus, key->p, key->q, key->iqmp); random_inverse = modinv(random, key->modulus); input_blinded = modmul(input, random_encrypted, key->modulus); ret_blinded = crt_modpow(input_blinded, key->private_exponent, key->modulus, key->p, key->q, key->iqmp); ret = modmul(ret_blinded, random_inverse, key->modulus); freebn(ret_blinded); freebn(input_blinded); |
︙ | ︙ | |||
417 418 419 420 421 422 423 | if (cmp != 0) return 0; /* e * d must be congruent to 1, modulo (p-1) and modulo (q-1). */ pm1 = copybn(key->p); decbn(pm1); ed = modmul(key->exponent, key->private_exponent, pm1); | < | < | < < | | 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 | if (cmp != 0) return 0; /* e * d must be congruent to 1, modulo (p-1) and modulo (q-1). */ pm1 = copybn(key->p); decbn(pm1); ed = modmul(key->exponent, key->private_exponent, pm1); cmp = bignum_cmp(ed, One); sfree(ed); if (cmp != 0) return 0; qm1 = copybn(key->q); decbn(qm1); ed = modmul(key->exponent, key->private_exponent, qm1); cmp = bignum_cmp(ed, One); sfree(ed); if (cmp != 0) return 0; /* * Ensure p > q. * * I have seen key blobs in the wild which were generated with * p < q, so instead of rejecting the key in this case we * should instead flip them round into the canonical order of * p > q. This also involves regenerating iqmp. */ if (bignum_cmp(key->p, key->q) <= 0) { Bignum tmp = key->p; key->p = key->q; key->q = tmp; freebn(key->iqmp); key->iqmp = modinv(key->q, key->p); } /* * Ensure iqmp * q is congruent to 1, modulo p. */ n = modmul(key->iqmp, key->q, key->p); cmp = bignum_cmp(n, One); sfree(n); if (cmp != 0) return 0; return 1; } /* Public key blob as used by Pageant: exponent before modulus. */ |
︙ | ︙ | |||
533 534 535 536 537 538 539 | */ static void getstring(char **data, int *datalen, char **p, int *length) { *p = NULL; if (*datalen < 4) return; | | < < | 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 | */ static void getstring(char **data, int *datalen, char **p, int *length) { *p = NULL; if (*datalen < 4) return; *length = GET_32BIT(*data); *datalen -= 4; *data += 4; if (*datalen < *length) return; *p = *data; *data += *length; *datalen -= *length; |
︙ | ︙ | |||
557 558 559 560 561 562 563 | getstring(data, datalen, &p, &length); if (!p) return NULL; b = bignum_from_bytes((unsigned char *)p, length); return b; } | < < > > < < < < < | 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 | getstring(data, datalen, &p, &length); if (!p) return NULL; b = bignum_from_bytes((unsigned char *)p, length); return b; } static void *rsa2_newkey(char *data, int len) { char *p; int slen; struct RSAKey *rsa; rsa = snew(struct RSAKey); if (!rsa) return NULL; getstring(&data, &len, &p, &slen); if (!p || slen != 7 || memcmp(p, "ssh-rsa", 7)) { sfree(rsa); return NULL; } rsa->exponent = getmp(&data, &len); rsa->modulus = getmp(&data, &len); rsa->private_exponent = NULL; rsa->p = rsa->q = rsa->iqmp = NULL; rsa->comment = NULL; return rsa; } static void rsa2_freekey(void *key) { struct RSAKey *rsa = (struct RSAKey *) key; freersakey(rsa); |
︙ | ︙ | |||
705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 | static void *rsa2_openssh_createkey(unsigned char **blob, int *len) { char **b = (char **) blob; struct RSAKey *rsa; rsa = snew(struct RSAKey); rsa->comment = NULL; rsa->modulus = getmp(b, len); rsa->exponent = getmp(b, len); rsa->private_exponent = getmp(b, len); rsa->iqmp = getmp(b, len); rsa->p = getmp(b, len); rsa->q = getmp(b, len); if (!rsa->modulus || !rsa->exponent || !rsa->private_exponent || !rsa->iqmp || !rsa->p || !rsa->q) { | > > | > > | < | | | | 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 | static void *rsa2_openssh_createkey(unsigned char **blob, int *len) { char **b = (char **) blob; struct RSAKey *rsa; rsa = snew(struct RSAKey); if (!rsa) return NULL; rsa->comment = NULL; rsa->modulus = getmp(b, len); rsa->exponent = getmp(b, len); rsa->private_exponent = getmp(b, len); rsa->iqmp = getmp(b, len); rsa->p = getmp(b, len); rsa->q = getmp(b, len); if (!rsa->modulus || !rsa->exponent || !rsa->private_exponent || !rsa->iqmp || !rsa->p || !rsa->q) { sfree(rsa->modulus); sfree(rsa->exponent); sfree(rsa->private_exponent); sfree(rsa->iqmp); sfree(rsa->p); sfree(rsa->q); sfree(rsa); return NULL; } return rsa; } static int rsa2_openssh_fmtkey(void *key, unsigned char *blob, int len) |
︙ | ︙ | |||
850 851 852 853 854 855 856 | unsigned char hash[20]; getstring(&sig, &siglen, &p, &slen); if (!p || slen != 7 || memcmp(p, "ssh-rsa", 7)) { return 0; } in = getmp(&sig, &siglen); | < < | 834 835 836 837 838 839 840 841 842 843 844 845 846 847 | unsigned char hash[20]; getstring(&sig, &siglen, &p, &slen); if (!p || slen != 7 || memcmp(p, "ssh-rsa", 7)) { return 0; } in = getmp(&sig, &siglen); out = modpow(in, rsa->exponent, rsa->modulus); freebn(in); ret = 1; bytes = (bignum_bitcount(rsa->modulus)+7) / 8; /* Top (partial) byte should be zero. */ |
︙ | ︙ |
Changes to sshrsag.c.
1 2 3 4 | /* * RSA key generation. */ | < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* * RSA key generation. */ #include "ssh.h" #define RSA_EXPONENT 37 /* we like this prime */ int rsa_generate(struct RSAKey *key, int bits, progfn_t pfn, void *pfnparam) { Bignum pm1, qm1, phi_n; /* * Set up the phase limits for the progress report. We do this * by passing minus the phase number. * * For prime generation: our initial filter finds things * coprime to everything below 2^16. Computing the product of |
︙ | ︙ | |||
58 59 60 61 62 63 64 | /* * Generate p and q: primes with combined length `bits', not * congruent to 1 modulo e. (Strictly speaking, we wanted (p-1) * and e to be coprime, and (q-1) and e to be coprime, but in * general that's slightly more fiddly to arrange. By choosing * a prime e, we can simplify the criterion.) */ | < | | | 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | /* * Generate p and q: primes with combined length `bits', not * congruent to 1 modulo e. (Strictly speaking, we wanted (p-1) * and e to be coprime, and (q-1) and e to be coprime, but in * general that's slightly more fiddly to arrange. By choosing * a prime e, we can simplify the criterion.) */ key->p = primegen(bits / 2, RSA_EXPONENT, 1, NULL, 1, pfn, pfnparam); key->q = primegen(bits - bits / 2, RSA_EXPONENT, 1, NULL, 2, pfn, pfnparam); /* * Ensure p > q, by swapping them if not. */ if (bignum_cmp(key->p, key->q) < 0) { Bignum t = key->p; key->p = key->q; |
︙ | ︙ | |||
90 91 92 93 94 95 96 | qm1 = copybn(key->q); decbn(qm1); phi_n = bigmul(pm1, qm1); pfn(pfnparam, PROGFN_PROGRESS, 3, 3); freebn(pm1); freebn(qm1); key->private_exponent = modinv(key->exponent, phi_n); | < < | 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | qm1 = copybn(key->q); decbn(qm1); phi_n = bigmul(pm1, qm1); pfn(pfnparam, PROGFN_PROGRESS, 3, 3); freebn(pm1); freebn(qm1); key->private_exponent = modinv(key->exponent, phi_n); pfn(pfnparam, PROGFN_PROGRESS, 3, 4); key->iqmp = modinv(key->q, key->p); pfn(pfnparam, PROGFN_PROGRESS, 3, 5); /* * Clean up temporary numbers. */ freebn(phi_n); return 1; } |
Changes to sshsh256.c.
︙ | ︙ | |||
214 215 216 217 218 219 220 | sfree(s); } const struct ssh_hash ssh_sha256 = { sha256_init, sha256_bytes, sha256_final, 32, "SHA-256" }; | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 214 215 216 217 218 219 220 221 222 223 224 225 226 227 | sfree(s); } const struct ssh_hash ssh_sha256 = { sha256_init, sha256_bytes, sha256_final, 32, "SHA-256" }; #ifdef TEST #include <stdio.h> #include <stdlib.h> #include <assert.h> int main(void) { |
︙ | ︙ |
Changes to sshsha.c.
︙ | ︙ | |||
24 25 26 27 28 29 30 | void SHATransform(word32 * digest, word32 * block) { word32 w[80]; word32 a, b, c, d, e; int t; | < < < < < < < < < < < < < < < | 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | void SHATransform(word32 * digest, word32 * block) { word32 w[80]; word32 a, b, c, d, e; int t; for (t = 0; t < 16; t++) w[t] = block[t]; for (t = 16; t < 80; t++) { word32 tmp = w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16]; w[t] = rol(tmp, 1); } |
︙ | ︙ | |||
94 95 96 97 98 99 100 | } digest[0] += a; digest[1] += b; digest[2] += c; digest[3] += d; digest[4] += e; | < < < < < < < < < < < < < | | | 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | } digest[0] += a; digest[1] += b; digest[2] += c; digest[3] += d; digest[4] += e; } /* ---------------------------------------------------------------------- * Outer SHA algorithm: take an arbitrary length byte string, * convert it into 16-word blocks with the prescribed padding at * the end, and pass those blocks to the core SHA algorithm. */ void SHA_Init(SHA_State * s) { SHA_Core_Init(s->h); s->blkused = 0; s->lenhi = s->lenlo = 0; } void SHA_Bytes(SHA_State * s, void *p, int len) { unsigned char *q = (unsigned char *) p; uint32 wordblock[16]; uint32 lenw = len; int i; /* * Update the length field. */ |
︙ | ︙ | |||
203 204 205 206 207 208 209 | output[i * 4] = (s->h[i] >> 24) & 0xFF; output[i * 4 + 1] = (s->h[i] >> 16) & 0xFF; output[i * 4 + 2] = (s->h[i] >> 8) & 0xFF; output[i * 4 + 3] = (s->h[i]) & 0xFF; } } | | | 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 | output[i * 4] = (s->h[i] >> 24) & 0xFF; output[i * 4 + 1] = (s->h[i] >> 16) & 0xFF; output[i * 4 + 2] = (s->h[i] >> 8) & 0xFF; output[i * 4 + 3] = (s->h[i]) & 0xFF; } } void SHA_Simple(void *p, int len, unsigned char *output) { SHA_State s; SHA_Init(&s); SHA_Bytes(&s, p, len); SHA_Final(&s, output); } |
︙ | ︙ | |||
277 278 279 280 281 282 283 | memset(foo, 0x5C, 64); for (i = 0; i < len && i < 64; i++) foo[i] ^= key[i]; SHA_Init(&keys[1]); SHA_Bytes(&keys[1], foo, 64); | | | 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 | memset(foo, 0x5C, 64); for (i = 0; i < len && i < 64; i++) foo[i] ^= key[i]; SHA_Init(&keys[1]); SHA_Bytes(&keys[1], foo, 64); memset(foo, 0, 64); /* burn the evidence */ } static void sha1_key(void *handle, unsigned char *key) { sha1_key_internal(handle, key, 20); } |
︙ | ︙ | |||
321 322 323 324 325 326 327 | } static void sha1_do_hmac(void *handle, unsigned char *blk, int len, unsigned long seq, unsigned char *hmac) { unsigned char seqbuf[4]; | > > > > | | 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 | } static void sha1_do_hmac(void *handle, unsigned char *blk, int len, unsigned long seq, unsigned char *hmac) { unsigned char seqbuf[4]; seqbuf[0] = (unsigned char) ((seq >> 24) & 0xFF); seqbuf[1] = (unsigned char) ((seq >> 16) & 0xFF); seqbuf[2] = (unsigned char) ((seq >> 8) & 0xFF); seqbuf[3] = (unsigned char) ((seq) & 0xFF); hmacsha1_start(handle); hmacsha1_bytes(handle, seqbuf, 4); hmacsha1_bytes(handle, blk, len); hmacsha1_genresult(handle, hmac); } static void sha1_generate(void *handle, unsigned char *blk, int len, |
︙ | ︙ |
Deleted sshshare.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to sshzlib.c.
︙ | ︙ | |||
34 35 36 37 38 39 40 | * difference of opinion mentioned above has arisen _precisely_ * because there has been only one zlib implementation and * everybody has used it. I don't intend that this should happen * again. */ #include <stdlib.h> | < | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | * difference of opinion mentioned above has arisen _precisely_ * because there has been only one zlib implementation and * everybody has used it. I don't intend that this should happen * again. */ #include <stdlib.h> #include <assert.h> #ifdef ZLIB_STANDALONE /* * This module also makes a handy zlib decoding tool for when * you're picking apart Zip files or PDFs or PNGs. If you compile |
︙ | ︙ |
Changes to storage.h.
1 2 3 4 5 6 7 8 9 10 11 | /* * storage.h: interface defining functions for storage and recovery * of PuTTY's persistent data. */ #ifndef PUTTY_STORAGE_H #define PUTTY_STORAGE_H /* ---------------------------------------------------------------------- * Functions to save and restore PuTTY sessions. Note that this is * only the low-level code to do the reading and writing. The | | | | | | | < < | > > > | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | /* * storage.h: interface defining functions for storage and recovery * of PuTTY's persistent data. */ #ifndef PUTTY_STORAGE_H #define PUTTY_STORAGE_H /* ---------------------------------------------------------------------- * Functions to save and restore PuTTY sessions. Note that this is * only the low-level code to do the reading and writing. The * higher-level code that translates a Config structure into a set * of (key,value) pairs is elsewhere, since it doesn't (mostly) * change between platforms. */ /* * Write a saved session. The caller is expected to call * open_setting_w() to get a `void *' handle, then pass that to a * number of calls to write_setting_s() and write_setting_i(), and * then close it using close_settings_w(). At the end of this call * sequence the settings should have been written to the PuTTY * persistent storage area. * * A given key will be written at most once while saving a session. * Keys may be up to 255 characters long. String values have no length * limit. * * Any returned error message must be freed after use. */ void *open_settings_w(const char *sessionname, char **errmsg); void write_setting_s(void *handle, const char *key, const char *value); void write_setting_i(void *handle, const char *key, int value); void write_setting_filename(void *handle, const char *key, Filename value); void write_setting_fontspec(void *handle, const char *key, FontSpec font); void close_settings_w(void *handle); /* * Read a saved session. The caller is expected to call * open_setting_r() to get a `void *' handle, then pass that to a * number of calls to read_setting_s() and read_setting_i(), and * then close it using close_settings_r(). * * read_setting_s() writes into the provided buffer and returns a * pointer to the same buffer. * * If a particular string setting is not present in the session, * read_setting_s() can return NULL, in which case the caller * should invent a sensible default. If an integer setting is not * present, read_setting_i() returns its provided default. * * read_setting_filename() and read_setting_fontspec() each read into * the provided buffer, and return zero if they failed to. */ void *open_settings_r(const char *sessionname); char *read_setting_s(void *handle, const char *key, char *buffer, int buflen); int read_setting_i(void *handle, const char *key, int defvalue); int read_setting_filename(void *handle, const char *key, Filename *value); int read_setting_fontspec(void *handle, const char *key, FontSpec *font); void close_settings_r(void *handle); /* * Delete a whole saved session. */ void del_settings(const char *sessionname); |
︙ | ︙ |
Changes to telnet.c.
1 2 3 4 5 6 | /* * Telnet backend. */ #include <stdio.h> #include <stdlib.h> | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 | /* * Telnet backend. */ #include <stdio.h> #include <stdlib.h> #include "putty.h" #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE |
︙ | ︙ | |||
178 179 180 181 182 183 184 | }; typedef struct telnet_tag { const struct plug_function_table *fn; /* the above field _must_ be first in the structure */ Socket s; | < | | 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 | }; typedef struct telnet_tag { const struct plug_function_table *fn; /* the above field _must_ be first in the structure */ Socket s; void *frontend; void *ldisc; int term_width, term_height; int opt_states[NUM_OPTS]; int echoing, editing; int activated; int bufsize; int in_synch; int sb_opt, sb_len; unsigned char *sb_buf; int sb_size; enum { TOP_LEVEL, SEENIAC, SEENWILL, SEENWONT, SEENDO, SEENDONT, SEENSB, SUBNEGOT, SUBNEG_IAC, SEENCR } state; Config cfg; Pinger pinger; } *Telnet; #define TELNET_MAX_BACKLOG 4096 #define SB_DELTA 1024 |
︙ | ︙ | |||
361 362 363 364 365 366 367 | */ if (cmd == WILL || cmd == DO) send_opt(telnet, (cmd == WILL ? DONT : WONT), option); } static void process_subneg(Telnet telnet) { | | | | < < | | | < < < | | > | | < | | 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 | */ if (cmd == WILL || cmd == DO) send_opt(telnet, (cmd == WILL ? DONT : WONT), option); } static void process_subneg(Telnet telnet) { unsigned char b[2048], *p, *q; int var, value, n; char *e; switch (telnet->sb_opt) { case TELOPT_TSPEED: if (telnet->sb_len == 1 && telnet->sb_buf[0] == TELQUAL_SEND) { char *logbuf; b[0] = IAC; b[1] = SB; b[2] = TELOPT_TSPEED; b[3] = TELQUAL_IS; strcpy((char *)(b + 4), telnet->cfg.termspeed); n = 4 + strlen(telnet->cfg.termspeed); b[n] = IAC; b[n + 1] = SE; telnet->bufsize = sk_write(telnet->s, (char *)b, n + 2); logevent(telnet->frontend, "server:\tSB TSPEED SEND"); logbuf = dupprintf("client:\tSB TSPEED IS %s", telnet->cfg.termspeed); logevent(telnet->frontend, logbuf); sfree(logbuf); } else logevent(telnet->frontend, "server:\tSB TSPEED <something weird>"); break; case TELOPT_TTYPE: if (telnet->sb_len == 1 && telnet->sb_buf[0] == TELQUAL_SEND) { char *logbuf; b[0] = IAC; b[1] = SB; b[2] = TELOPT_TTYPE; b[3] = TELQUAL_IS; for (n = 0; telnet->cfg.termtype[n]; n++) b[n + 4] = (telnet->cfg.termtype[n] >= 'a' && telnet->cfg.termtype[n] <= 'z' ? telnet->cfg.termtype[n] + 'A' - 'a' : telnet->cfg.termtype[n]); b[n + 4] = IAC; b[n + 5] = SE; telnet->bufsize = sk_write(telnet->s, (char *)b, n + 6); b[n + 4] = 0; logevent(telnet->frontend, "server:\tSB TTYPE SEND"); logbuf = dupprintf("client:\tSB TTYPE IS %s", b + 4); logevent(telnet->frontend, logbuf); sfree(logbuf); } else logevent(telnet->frontend, "server:\tSB TTYPE <something weird>\r\n"); break; case TELOPT_OLD_ENVIRON: case TELOPT_NEW_ENVIRON: p = telnet->sb_buf; q = p + telnet->sb_len; if (p < q && *p == TELQUAL_SEND) { char *logbuf; p++; logbuf = dupprintf("server:\tSB %s SEND", telopt(telnet->sb_opt)); logevent(telnet->frontend, logbuf); sfree(logbuf); if (telnet->sb_opt == TELOPT_OLD_ENVIRON) { if (telnet->cfg.rfc_environ) { value = RFC_VALUE; var = RFC_VAR; } else { value = BSD_VALUE; var = BSD_VAR; } /* |
︙ | ︙ | |||
452 453 454 455 456 457 458 | /* * With NEW_ENVIRON, the sense of VAR and VALUE * isn't in doubt. */ value = RFC_VALUE; var = RFC_VAR; } | < < < < < < < < < < < < < < < | | < > | > > | | > > > > | | | | | | | | > | | | | | < | | < < | < < < < < < < < < < < < < | | > > | | | < < < | 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 | /* * With NEW_ENVIRON, the sense of VAR and VALUE * isn't in doubt. */ value = RFC_VALUE; var = RFC_VAR; } b[0] = IAC; b[1] = SB; b[2] = telnet->sb_opt; b[3] = TELQUAL_IS; n = 4; e = telnet->cfg.environmt; while (*e) { b[n++] = var; while (*e && *e != '\t') b[n++] = *e++; if (*e == '\t') e++; b[n++] = value; while (*e) b[n++] = *e++; e++; } { char user[sizeof(telnet->cfg.username)]; (void) get_remote_username(&telnet->cfg, user, sizeof(user)); if (*user) { b[n++] = var; b[n++] = 'U'; b[n++] = 'S'; b[n++] = 'E'; b[n++] = 'R'; b[n++] = value; e = user; while (*e) b[n++] = *e++; } b[n++] = IAC; b[n++] = SE; telnet->bufsize = sk_write(telnet->s, (char *)b, n); logbuf = dupprintf("client:\tSB %s IS %s%s%s%s", telopt(telnet->sb_opt), *user ? "USER=" : "", user, *user ? " " : "", n == 6 ? "<nothing>" : (*telnet->cfg.environmt ? "<stuff>" : "")); logevent(telnet->frontend, logbuf); sfree(logbuf); } } break; } } static void do_telnet_read(Telnet telnet, char *buf, int len) { |
︙ | ︙ | |||
658 659 660 661 662 663 664 | if (type == 0) msg = dupprintf("Connecting to %s port %d", addrbuf, port); else msg = dupprintf("Failed to connect to %s: %s", addrbuf, error_msg); logevent(telnet->frontend, msg); | < < < < < < < < < | 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 | if (type == 0) msg = dupprintf("Connecting to %s port %d", addrbuf, port); else msg = dupprintf("Failed to connect to %s: %s", addrbuf, error_msg); logevent(telnet->frontend, msg); } static int telnet_closing(Plug plug, const char *error_msg, int error_code, int calling_back) { Telnet telnet = (Telnet) plug; if (telnet->s) { sk_close(telnet->s); telnet->s = NULL; notify_remote_exit(telnet->frontend); } if (error_msg) { logevent(telnet->frontend, error_msg); connection_fatal(telnet->frontend, "%s", error_msg); } /* Otherwise, the remote side closed the connection normally. */ |
︙ | ︙ | |||
711 712 713 714 715 716 717 | * * Returns an error message, or NULL on success. * * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ static const char *telnet_init(void *frontend_handle, void **backend_handle, | > | | < < | < | | < | | | | | | | 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 | * * Returns an error message, or NULL on success. * * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ static const char *telnet_init(void *frontend_handle, void **backend_handle, Config *cfg, char *host, int port, char **realhost, int nodelay, int keepalive) { static const struct plug_function_table fn_table = { telnet_log, telnet_closing, telnet_receive, telnet_sent }; SockAddr addr; const char *err; Telnet telnet; telnet = snew(struct telnet_tag); telnet->fn = &fn_table; telnet->cfg = *cfg; /* STRUCTURE COPY */ telnet->s = NULL; telnet->echoing = TRUE; telnet->editing = TRUE; telnet->activated = FALSE; telnet->sb_buf = NULL; telnet->sb_size = 0; telnet->frontend = frontend_handle; telnet->term_width = telnet->cfg.width; telnet->term_height = telnet->cfg.height; telnet->state = TOP_LEVEL; telnet->ldisc = NULL; telnet->pinger = NULL; *backend_handle = telnet; /* * Try to find host. */ { char *buf; buf = dupprintf("Looking up host \"%s\"%s", host, (cfg->addressfamily == ADDRTYPE_IPV4 ? " (IPv4)" : (cfg->addressfamily == ADDRTYPE_IPV6 ? " (IPv6)" : ""))); logevent(telnet->frontend, buf); sfree(buf); } addr = name_lookup(host, port, realhost, &telnet->cfg, cfg->addressfamily); if ((err = sk_addr_error(addr)) != NULL) { sk_addr_free(addr); return err; } if (port < 0) port = 23; /* default telnet port */ /* * Open socket. */ telnet->s = new_connection(addr, *realhost, port, 0, 1, nodelay, keepalive, (Plug) telnet, &telnet->cfg); if ((err = sk_socket_error(telnet->s)) != NULL) return err; telnet->pinger = pinger_new(&telnet->cfg, &telnet_backend, telnet); /* * Initialise option states. */ if (telnet->cfg.passive_telnet) { const struct Opt *const *o; for (o = opts; *o; o++) telnet->opt_states[(*o)->index] = INACTIVE; } else { const struct Opt *const *o; |
︙ | ︙ | |||
808 809 810 811 812 813 814 | * We can send special commands from the start. */ update_specials_menu(telnet->frontend); /* * loghost overrides realhost, if specified. */ | < | | | 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 | * We can send special commands from the start. */ update_specials_menu(telnet->frontend); /* * loghost overrides realhost, if specified. */ if (*telnet->cfg.loghost) { char *colon; sfree(*realhost); *realhost = dupstr(telnet->cfg.loghost); colon = strrchr(*realhost, ':'); if (colon) { /* * FIXME: if we ever update this aspect of ssh.c for * IPv6 literal management, this should change in line * with it. */ |
︙ | ︙ | |||
837 838 839 840 841 842 843 | Telnet telnet = (Telnet) handle; sfree(telnet->sb_buf); if (telnet->s) sk_close(telnet->s); if (telnet->pinger) pinger_free(telnet->pinger); | < | | | < | 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 | Telnet telnet = (Telnet) handle; sfree(telnet->sb_buf); if (telnet->s) sk_close(telnet->s); if (telnet->pinger) pinger_free(telnet->pinger); sfree(telnet); } /* * Reconfigure the Telnet backend. There's no immediate action * necessary, in this backend: we just save the fresh config for * any subsequent negotiations. */ static void telnet_reconfig(void *handle, Config *cfg) { Telnet telnet = (Telnet) handle; pinger_reconfig(telnet->pinger, &telnet->cfg, cfg); telnet->cfg = *cfg; /* STRUCTURE COPY */ } /* * Called to send data down the Telnet connection. */ static int telnet_send(void *handle, char *buf, int len) { |
︙ | ︙ | |||
1098 1099 1100 1101 1102 1103 1104 | } static int telnet_exitcode(void *handle) { Telnet telnet = (Telnet) handle; if (telnet->s != NULL) return -1; /* still connected */ | < < | 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 | } static int telnet_exitcode(void *handle) { Telnet telnet = (Telnet) handle; if (telnet->s != NULL) return -1; /* still connected */ else /* Telnet doesn't transmit exit codes back to the client */ return 0; } /* * cfg_info for Telnet does nothing at all. |
︙ | ︙ |
Changes to terminal.c.
︙ | ︙ | |||
985 986 987 988 989 990 991 | /* * Get the number of lines in the scrollback. */ static int sblines(Terminal *term) { int sblines = count234(term->scrollback); | | | 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 | /* * Get the number of lines in the scrollback. */ static int sblines(Terminal *term) { int sblines = count234(term->scrollback); if (term->cfg.erase_to_scrollback && term->alt_which && term->alt_screen) { sblines += term->alt_sblines; } return sblines; } /* |
︙ | ︙ | |||
1011 1012 1013 1014 1015 1016 1017 | whichtree = term->screen; treeindex = y; } else { int altlines = 0; assert(!screen); | | | 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 | whichtree = term->screen; treeindex = y; } else { int altlines = 0; assert(!screen); if (term->cfg.erase_to_scrollback && term->alt_which && term->alt_screen) { altlines = term->alt_sblines; } if (y < -altlines) { whichtree = term->scrollback; treeindex = y + altlines + count234(term->scrollback); } else { |
︙ | ︙ | |||
1061 1062 1063 1064 1065 1066 1067 | #define lineptr(x) (lineptr)(term,x,__LINE__,FALSE) #define scrlineptr(x) (lineptr)(term,x,__LINE__,TRUE) static void term_schedule_tblink(Terminal *term); static void term_schedule_cblink(Terminal *term); | | | | | | | 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 | #define lineptr(x) (lineptr)(term,x,__LINE__,FALSE) #define scrlineptr(x) (lineptr)(term,x,__LINE__,TRUE) static void term_schedule_tblink(Terminal *term); static void term_schedule_cblink(Terminal *term); static void term_timer(void *ctx, long now) { Terminal *term = (Terminal *)ctx; int update = FALSE; if (term->tblink_pending && now - term->next_tblink >= 0) { term->tblinker = !term->tblinker; term->tblink_pending = FALSE; term_schedule_tblink(term); update = TRUE; } if (term->cblink_pending && now - term->next_cblink >= 0) { term->cblinker = !term->cblinker; term->cblink_pending = FALSE; term_schedule_cblink(term); update = TRUE; } if (term->in_vbell && now - term->vbell_end >= 0) { term->in_vbell = FALSE; update = TRUE; } if (update || (term->window_update_pending && now - term->next_update >= 0)) term_update(term); } static void term_schedule_update(Terminal *term) { if (!term->window_update_pending) { term->window_update_pending = TRUE; |
︙ | ︙ | |||
1129 1130 1131 1132 1133 1134 1135 | } /* * Likewise with cursor blinks. */ static void term_schedule_cblink(Terminal *term) { | | | 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 | } /* * Likewise with cursor blinks. */ static void term_schedule_cblink(Terminal *term) { if (term->cfg.blink_cur && term->has_focus) { if (!term->cblink_pending) term->next_cblink = schedule_timer(CBLINK_DELAY, term_timer, term); term->cblink_pending = TRUE; } else { term->cblinker = 1; /* reset when not in use */ term->cblink_pending = FALSE; } |
︙ | ︙ | |||
1193 1194 1195 1196 1197 1198 1199 | else term->alt_b = term->marg_b = 0; if (term->cols != -1) { int i; for (i = 0; i < term->cols; i++) term->tabs[i] = (i % 8 == 0 ? TRUE : FALSE); } | | | | | | | < < < | | 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 | else term->alt_b = term->marg_b = 0; if (term->cols != -1) { int i; for (i = 0; i < term->cols; i++) term->tabs[i] = (i % 8 == 0 ? TRUE : FALSE); } term->alt_om = term->dec_om = term->cfg.dec_om; term->alt_ins = term->insert = FALSE; term->alt_wnext = term->wrapnext = term->save_wnext = term->alt_save_wnext = FALSE; term->alt_wrap = term->wrap = term->cfg.wrap_mode; term->alt_cset = term->cset = term->save_cset = term->alt_save_cset = 0; term->alt_utf = term->utf = term->save_utf = term->alt_save_utf = 0; term->utf_state = 0; term->alt_sco_acs = term->sco_acs = term->save_sco_acs = term->alt_save_sco_acs = 0; term->cset_attr[0] = term->cset_attr[1] = term->save_csattr = term->alt_save_csattr = CSET_ASCII; term->rvideo = 0; term->in_vbell = FALSE; term->cursor_on = 1; term->big_cursor = 0; term->default_attr = term->save_attr = term->alt_save_attr = term->curr_attr = ATTR_DEFAULT; term->term_editing = term->term_echoing = FALSE; term->app_cursor_keys = term->cfg.app_cursor; term->app_keypad_keys = term->cfg.app_keypad; term->use_bce = term->cfg.bce; term->blink_is_real = term->cfg.blinktext; term->erase_char = term->basic_erase_char; term->alt_which = 0; term_print_finish(term); term->xterm_mouse = 0; set_raw_mouse_mode(term->frontend, FALSE); { int i; for (i = 0; i < 256; i++) term->wordness[i] = term->cfg.wordness[i]; } if (term->screen) { swap_screen(term, 1, FALSE, FALSE); erase_lots(term, FALSE, TRUE, TRUE); swap_screen(term, 0, FALSE, FALSE); if (clear) erase_lots(term, FALSE, TRUE, TRUE); |
︙ | ︙ | |||
1260 1261 1262 1263 1264 1265 1266 | Context ctx; term->window_update_pending = FALSE; ctx = get_ctx(term->frontend); if (ctx) { int need_sbar_update = term->seen_disp_event; | | | 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 | Context ctx; term->window_update_pending = FALSE; ctx = get_ctx(term->frontend); if (ctx) { int need_sbar_update = term->seen_disp_event; if (term->seen_disp_event && term->cfg.scroll_on_disp) { term->disptop = 0; /* return to main screen */ term->seen_disp_event = 0; need_sbar_update = TRUE; } if (need_sbar_update) update_sbar(term); |
︙ | ︙ | |||
1299 1300 1301 1302 1303 1304 1305 | } term->beeptail = NULL; term->nbeeps = 0; /* * Reset the scrollback on keypress, if we're doing that. */ | | | 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 | } term->beeptail = NULL; term->nbeeps = 0; /* * Reset the scrollback on keypress, if we're doing that. */ if (term->cfg.scroll_on_key) { term->disptop = 0; /* return to main screen */ seen_disp_event(term); } } /* * Same as power_on(), but an external function. |
︙ | ︙ | |||
1326 1327 1328 1329 1330 1331 1332 1333 | { term->erase_char = term->basic_erase_char; if (term->use_bce) term->erase_char.attr = (term->curr_attr & (ATTR_FGMASK | ATTR_BGMASK)); } /* | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < | < | < | < | < | < | | < | < | | | | | | | | | < | | > < < | 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 | { term->erase_char = term->basic_erase_char; if (term->use_bce) term->erase_char.attr = (term->curr_attr & (ATTR_FGMASK | ATTR_BGMASK)); } /* * When the user reconfigures us, we need to check the forbidden- * alternate-screen config option, disable raw mouse mode if the * user has disabled mouse reporting, and abandon a print job if * the user has disabled printing. */ void term_reconfig(Terminal *term, Config *cfg) { /* * Before adopting the new config, check all those terminal * settings which control power-on defaults; and if they've * changed, we will modify the current state as well as the * default one. The full list is: Auto wrap mode, DEC Origin * Mode, BCE, blinking text, character classes. */ int reset_wrap, reset_decom, reset_bce, reset_tblink, reset_charclass; int i; reset_wrap = (term->cfg.wrap_mode != cfg->wrap_mode); reset_decom = (term->cfg.dec_om != cfg->dec_om); reset_bce = (term->cfg.bce != cfg->bce); reset_tblink = (term->cfg.blinktext != cfg->blinktext); reset_charclass = 0; for (i = 0; i < lenof(term->cfg.wordness); i++) if (term->cfg.wordness[i] != cfg->wordness[i]) reset_charclass = 1; /* * If the bidi or shaping settings have changed, flush the bidi * cache completely. */ if (term->cfg.arabicshaping != cfg->arabicshaping || term->cfg.bidi != cfg->bidi) { for (i = 0; i < term->bidi_cache_size; i++) { sfree(term->pre_bidi_cache[i].chars); sfree(term->post_bidi_cache[i].chars); term->pre_bidi_cache[i].width = -1; term->pre_bidi_cache[i].chars = NULL; term->post_bidi_cache[i].width = -1; term->post_bidi_cache[i].chars = NULL; } } term->cfg = *cfg; /* STRUCTURE COPY */ if (reset_wrap) term->alt_wrap = term->wrap = term->cfg.wrap_mode; if (reset_decom) term->alt_om = term->dec_om = term->cfg.dec_om; if (reset_bce) { term->use_bce = term->cfg.bce; set_erase_char(term); } if (reset_tblink) { term->blink_is_real = term->cfg.blinktext; } if (reset_charclass) for (i = 0; i < 256; i++) term->wordness[i] = term->cfg.wordness[i]; if (term->cfg.no_alt_screen) swap_screen(term, 0, FALSE, FALSE); if (term->cfg.no_mouse_rep) { term->xterm_mouse = 0; set_raw_mouse_mode(term->frontend, 0); } if (term->cfg.no_remote_charset) { term->cset_attr[0] = term->cset_attr[1] = CSET_ASCII; term->sco_acs = term->alt_sco_acs = 0; term->utf = 0; } if (!*term->cfg.printer) { term_print_finish(term); } term_schedule_tblink(term); term_schedule_cblink(term); } /* * Clear the scrollback. */ void term_clrsb(Terminal *term) { unsigned char *line; term->disptop = 0; while ((line = delpos234(term->scrollback, 0)) != NULL) { sfree(line); /* this is compressed data, not a termline */ } term->tempsblines = 0; term->alt_sblines = 0; update_sbar(term); } /* * Initialise the terminal. */ Terminal *term_init(Config *mycfg, struct unicode_data *ucsdata, void *frontend) { Terminal *term; /* * Allocate a new Terminal structure and initialise the fields * that need it. */ term = snew(Terminal); term->frontend = frontend; term->ucsdata = ucsdata; term->cfg = *mycfg; /* STRUCTURE COPY */ term->logctx = NULL; term->compatibility_level = TM_PUTTY; strcpy(term->id_string, "\033[?6c"); term->cblink_pending = term->tblink_pending = FALSE; term->paste_buffer = NULL; term->paste_len = 0; term->last_paste = 0; bufchain_init(&term->inbuf); bufchain_init(&term->printer_buf); term->printing = term->only_printing = FALSE; term->print_job = NULL; term->vt52_mode = FALSE; term->cr_lf_return = FALSE; term->seen_disp_event = FALSE; term->mouse_is_down = FALSE; term->reset_132 = FALSE; term->cblinker = term->tblinker = 0; term->has_focus = 1; term->repeat_off = FALSE; term->termstate = TOPLEVEL; term->selstate = NO_SELECTION; term->curstype = 0; term->screen = term->alt_screen = term->scrollback = NULL; term->tempsblines = 0; term->alt_sblines = 0; term->disptop = 0; term->disptext = NULL; term->dispcursx = term->dispcursy = -1; term->tabs = NULL; |
︙ | ︙ | |||
1616 1617 1618 1619 1620 1621 1622 | sfree(term->ltemp); sfree(term->wcFrom); sfree(term->wcTo); for (i = 0; i < term->bidi_cache_size; i++) { sfree(term->pre_bidi_cache[i].chars); sfree(term->post_bidi_cache[i].chars); | < < < < < < | 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 | sfree(term->ltemp); sfree(term->wcFrom); sfree(term->wcTo); for (i = 0; i < term->bidi_cache_size; i++) { sfree(term->pre_bidi_cache[i].chars); sfree(term->post_bidi_cache[i].chars); } sfree(term->pre_bidi_cache); sfree(term->post_bidi_cache); expire_timer_context(term); sfree(term); } /* * Set up the terminal for a given size. */ void term_size(Terminal *term, int newrows, int newcols, int newsavelines) |
︙ | ︙ | |||
1712 1713 1714 1715 1716 1717 1718 | } term->rows += 1; } /* Do this loop to shrink the screen if newrows < rows */ while (term->rows > newrows) { if (term->curs.y < term->rows - 1) { /* delete bottom row, unless it contains the cursor */ | | < | 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 | } term->rows += 1; } /* Do this loop to shrink the screen if newrows < rows */ while (term->rows > newrows) { if (term->curs.y < term->rows - 1) { /* delete bottom row, unless it contains the cursor */ sfree(delpos234(term->screen, term->rows - 1)); } else { /* push top row to scrollback */ line = delpos234(term->screen, 0); addpos234(term->scrollback, compressline(line), sblen++); freeline(line); term->tempsblines += 1; term->curs.y -= 1; |
︙ | ︙ | |||
1975 1976 1977 1978 1979 1980 1981 | * Scroll the screen. (`lines' is +ve for scrolling forward, -ve * for backward.) `sb' is TRUE if the scrolling is permitted to * affect the scrollback buffer. */ static void scroll(Terminal *term, int topline, int botline, int lines, int sb) { termline *line; | | < < < < < < | | 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 | * Scroll the screen. (`lines' is +ve for scrolling forward, -ve * for backward.) `sb' is TRUE if the scrolling is permitted to * affect the scrollback buffer. */ static void scroll(Terminal *term, int topline, int botline, int lines, int sb) { termline *line; int i, seltop; #ifdef OPTIMISE_SCROLL int olddisptop, shift; #endif /* OPTIMISE_SCROLL */ if (topline != 0 || term->alt_which != 0) sb = FALSE; #ifdef OPTIMISE_SCROLL olddisptop = term->disptop; shift = lines; #endif /* OPTIMISE_SCROLL */ if (lines < 0) { while (lines < 0) { line = delpos234(term->screen, botline); resizeline(term, line, term->cols); for (i = 0; i < term->cols; i++) copy_termchar(line, i, &term->erase_char); line->lattr = LATTR_NORM; addpos234(term->screen, line, topline); |
︙ | ︙ | |||
2016 2017 2018 2019 2020 2021 2022 | if (term->selend.y >= topline && term->selend.y <= botline) { term->selend.y++; if (term->selend.y > botline) { term->selend.y = botline + 1; term->selend.x = 0; } } | | > > < < | | 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 | if (term->selend.y >= topline && term->selend.y <= botline) { term->selend.y++; if (term->selend.y > botline) { term->selend.y = botline + 1; term->selend.x = 0; } } lines++; } } else { while (lines > 0) { line = delpos234(term->screen, topline); #ifdef TERM_CC_DIAGS cc_check(line); #endif if (sb && term->savelines > 0) { int sblen = count234(term->scrollback); /* |
︙ | ︙ | |||
2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 | term->selanchor.y--; if (term->selanchor.y < seltop) { term->selanchor.y = seltop; term->selanchor.x = 0; } } } } } #ifdef OPTIMISE_SCROLL shift += term->disptop - olddisptop; if (shift < term->rows && shift > -term->rows && shift != 0) scroll_display(term, topline, botline, shift); #endif /* OPTIMISE_SCROLL */ | > > | 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 | term->selanchor.y--; if (term->selanchor.y < seltop) { term->selanchor.y = seltop; term->selanchor.x = 0; } } } lines--; } } #ifdef OPTIMISE_SCROLL shift += term->disptop - olddisptop; if (shift < term->rows && shift > -term->rows && shift != 0) scroll_display(term, topline, botline, shift); #endif /* OPTIMISE_SCROLL */ |
︙ | ︙ | |||
2333 2334 2335 2336 2337 2338 2339 | term_invalidate(term); /* Lines scrolled away shouldn't be brought back on if the terminal * resizes. */ if (start.y == 0 && start.x == 0 && end.x == 0 && erase_lattr) erasing_lines_from_top = 1; | | | 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 | term_invalidate(term); /* Lines scrolled away shouldn't be brought back on if the terminal * resizes. */ if (start.y == 0 && start.x == 0 && end.x == 0 && erase_lattr) erasing_lines_from_top = 1; if (term->cfg.erase_to_scrollback && erasing_lines_from_top) { /* If it's a whole number of lines, starting at the top, and * we're fully erasing them, erase by scrolling and keep the * lines in the scrollback. */ int scrolllines = end.y; if (end.y == term->rows) { /* Shrink until we find a non-empty row.*/ scrolllines = find_last_nonempty_line(term, term->screen) + 1; |
︙ | ︙ | |||
2424 2425 2426 2427 2428 2429 2430 | break; case 2: /* DECANM: VT52 mode */ term->vt52_mode = !state; if (term->vt52_mode) { term->blink_is_real = FALSE; term->vt52_bold = FALSE; } else { | | | | 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 | break; case 2: /* DECANM: VT52 mode */ term->vt52_mode = !state; if (term->vt52_mode) { term->blink_is_real = FALSE; term->vt52_bold = FALSE; } else { term->blink_is_real = term->cfg.blinktext; } term_schedule_tblink(term); break; case 3: /* DECCOLM: 80/132 columns */ deselect(term); if (!term->cfg.no_remote_resize) request_resize(term->frontend, state ? 132 : 80, term->rows); term->reset_132 = state; term->alt_t = term->marg_t = 0; term->alt_b = term->marg_b = term->rows - 1; move(term, 0, 0, 0); erase_lots(term, FALSE, TRUE, TRUE); break; |
︙ | ︙ | |||
2477 2478 2479 2480 2481 2482 2483 | compatibility2(OTHER, VT220); term->cursor_on = state; seen_disp_event(term); break; case 47: /* alternate screen */ compatibility(OTHER); deselect(term); | | < < < < < < | | | | | < < < | 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 | compatibility2(OTHER, VT220); term->cursor_on = state; seen_disp_event(term); break; case 47: /* alternate screen */ compatibility(OTHER); deselect(term); swap_screen(term, term->cfg.no_alt_screen ? 0 : state, FALSE, FALSE); term->disptop = 0; break; case 1000: /* xterm mouse 1 (normal) */ term->xterm_mouse = state ? 1 : 0; set_raw_mouse_mode(term->frontend, state); break; case 1002: /* xterm mouse 2 (inc. button drags) */ term->xterm_mouse = state ? 2 : 0; set_raw_mouse_mode(term->frontend, state); break; case 1047: /* alternate screen */ compatibility(OTHER); deselect(term); swap_screen(term, term->cfg.no_alt_screen ? 0 : state, TRUE, TRUE); term->disptop = 0; break; case 1048: /* save/restore cursor */ if (!term->cfg.no_alt_screen) save_cursor(term, state); if (!state) seen_disp_event(term); break; case 1049: /* cursor & alternate screen */ if (state && !term->cfg.no_alt_screen) save_cursor(term, state); if (!state) seen_disp_event(term); compatibility(OTHER); deselect(term); swap_screen(term, term->cfg.no_alt_screen ? 0 : state, TRUE, FALSE); if (!state && !term->cfg.no_alt_screen) save_cursor(term, state); term->disptop = 0; break; } else switch (mode) { case 4: /* IRM: set insert mode */ compatibility(VT102); term->insert = state; break; case 12: /* SRM: set echo mode */ |
︙ | ︙ | |||
2553 2554 2555 2556 2557 2558 2559 | term->wordness[(unsigned char) term->osc_string[term->osc_strlen]] = term->esc_args[0]; } else { term->osc_string[term->osc_strlen] = '\0'; switch (term->esc_args[0]) { case 0: case 1: | | | | | | 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 | term->wordness[(unsigned char) term->osc_string[term->osc_strlen]] = term->esc_args[0]; } else { term->osc_string[term->osc_strlen] = '\0'; switch (term->esc_args[0]) { case 0: case 1: if (!term->cfg.no_remote_wintitle) set_icon(term->frontend, term->osc_string); if (term->esc_args[0] == 1) break; /* fall through: parameter 0 means set both */ case 2: case 21: if (!term->cfg.no_remote_wintitle) set_title(term->frontend, term->osc_string); break; } } } /* * ANSI printing routines. */ static void term_print_setup(Terminal *term) { bufchain_clear(&term->printer_buf); term->print_job = printer_start_job(term->cfg.printer); } static void term_print_flush(Terminal *term) { void *data; int len; int size; while ((size = bufchain_size(&term->printer_buf)) > 5) { |
︙ | ︙ | |||
2648 2649 2650 2651 2652 2653 2654 | c = *chars++; nchars--; /* * Optionally log the session traffic to a file. Useful for * debugging and possibly also useful for actual logging. */ | | | 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 | c = *chars++; nchars--; /* * Optionally log the session traffic to a file. Useful for * debugging and possibly also useful for actual logging. */ if (term->cfg.logtype == LGTYP_DEBUG && term->logctx) logtraffic(term->logctx, (unsigned char) c, LGTYP_DEBUG); } else { c = unget; unget = -1; } /* Note only VT220+ are 8-bit VT102 is seven bit, it shouldn't even |
︙ | ︙ | |||
2840 2841 2842 2843 2844 2845 2846 | /* Or the GL control. */ if (c == '\177' && term->termstate < DO_CTRLS && has_compat(OTHER)) { if (term->curs.x && !term->wrapnext) term->curs.x--; term->wrapnext = FALSE; /* destructive backspace might be disabled */ | | > > > > > > > > > > > | | 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 | /* Or the GL control. */ if (c == '\177' && term->termstate < DO_CTRLS && has_compat(OTHER)) { if (term->curs.x && !term->wrapnext) term->curs.x--; term->wrapnext = FALSE; /* destructive backspace might be disabled */ if (!term->cfg.no_dbackspace) { check_boundary(term, term->curs.x, term->curs.y); check_boundary(term, term->curs.x+1, term->curs.y); copy_termchar(scrlineptr(term->curs.y), term->curs.x, &term->erase_char); } } else /* Or normal C0 controls. */ if ((c & ~0x1F) == 0 && term->termstate < DO_CTRLS) { switch (c) { case '\005': /* ENQ: terminal type query */ /* * Strictly speaking this is VT100 but a VT100 defaults to * no response. Other terminals respond at their option. * * Don't put a CR in the default string as this tends to * upset some weird software. */ compatibility(ANSIMIN); if (term->ldisc) { char abuf[lenof(term->cfg.answerback)], *s, *d; for (s = term->cfg.answerback, d = abuf; *s;) { char *n; char c = ctrlparse(s, &n); if (n) { *d++ = c; s = n; } else { *d++ = *s++; } } lpage_send(term->ldisc, DEFAULT_CODEPAGE, abuf, d - abuf, 0); } break; case '\007': /* BEL: Bell */ { struct beeptime *newbeep; unsigned long ticks; |
︙ | ︙ | |||
2888 2889 2890 2891 2892 2893 2894 | } /* * Throw out any beeps that happened more than * t seconds ago. */ while (term->beephead && | | | | | | | | | | 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 | } /* * Throw out any beeps that happened more than * t seconds ago. */ while (term->beephead && term->beephead->ticks < ticks - term->cfg.bellovl_t) { struct beeptime *tmp = term->beephead; term->beephead = tmp->next; sfree(tmp); if (!term->beephead) term->beeptail = NULL; term->nbeeps--; } if (term->cfg.bellovl && term->beep_overloaded && ticks - term->lastbeep >= (unsigned)term->cfg.bellovl_s) { /* * If we're currently overloaded and the * last beep was more than s seconds ago, * leave overload mode. */ term->beep_overloaded = FALSE; } else if (term->cfg.bellovl && !term->beep_overloaded && term->nbeeps >= term->cfg.bellovl_n) { /* * Now, if we have n or more beeps * remaining in the queue, go into overload * mode. */ term->beep_overloaded = TRUE; } term->lastbeep = ticks; /* * Perform an actual beep if we're not overloaded. */ if (!term->cfg.bellovl || !term->beep_overloaded) { do_beep(term->frontend, term->cfg.beep); if (term->cfg.beep == BELL_VISUAL) { term_schedule_vbell(term, FALSE, 0); } } seen_disp_event(term); } break; case '\b': /* BS: Back space */ |
︙ | ︙ | |||
2962 2963 2964 2965 2966 2967 2968 2969 | term->esc_query = FALSE; } break; case '\015': /* CR: Carriage return */ term->curs.x = 0; term->wrapnext = FALSE; seen_disp_event(term); | > | | | | | | | > | 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 | term->esc_query = FALSE; } break; case '\015': /* CR: Carriage return */ term->curs.x = 0; term->wrapnext = FALSE; seen_disp_event(term); term->paste_hold = 0; if (term->cfg.crhaslf) { if (term->curs.y == term->marg_b) scroll(term, term->marg_t, term->marg_b, 1, TRUE); else if (term->curs.y < term->rows - 1) term->curs.y++; } if (term->logctx) logtraffic(term->logctx, (unsigned char) c, LGTYP_ASCII); break; case '\014': /* FF: Form feed */ if (has_compat(SCOANSI)) { move(term, 0, 0, 0); erase_lots(term, FALSE, FALSE, TRUE); term->disptop = 0; term->wrapnext = FALSE; seen_disp_event(term); break; } case '\013': /* VT: Line tabulation */ compatibility(VT100); case '\012': /* LF: Line feed */ if (term->curs.y == term->marg_b) scroll(term, term->marg_t, term->marg_b, 1, TRUE); else if (term->curs.y < term->rows - 1) term->curs.y++; if (term->cfg.lfhascr) term->curs.x = 0; term->wrapnext = FALSE; seen_disp_event(term); term->paste_hold = 0; if (term->logctx) logtraffic(term->logctx, (unsigned char) c, LGTYP_ASCII); break; case '\t': /* HT: Character tabulation */ { pos old_curs = term->curs; termline *ldata = scrlineptr(term->curs.y); |
︙ | ︙ | |||
3029 3030 3031 3032 3033 3034 3035 | * ctrls are stripped above */ { termline *cline = scrlineptr(term->curs.y); int width = 0; if (DIRECT_CHAR(c)) width = 1; if (!width) | | | | | 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 | * ctrls are stripped above */ { termline *cline = scrlineptr(term->curs.y); int width = 0; if (DIRECT_CHAR(c)) width = 1; if (!width) width = (term->cfg.cjk_ambig_wide ? mk_wcwidth_cjk((wchar_t) c) : mk_wcwidth((wchar_t) c)); if (term->wrapnext && term->wrap && width > 0) { cline->lattr |= LATTR_WRAPPED; if (term->curs.y == term->marg_b) scroll(term, term->marg_t, term->marg_b, 1, TRUE); else if (term->curs.y < term->rows - 1) term->curs.y++; |
︙ | ︙ | |||
3252 3253 3254 3255 3256 3257 3258 | break; case 'c': /* RIS: restore power-on settings */ compatibility(VT100); power_on(term, TRUE); if (term->ldisc) /* cause ldisc to notice changes */ ldisc_send(term->ldisc, NULL, 0, 0); if (term->reset_132) { | | | 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 | break; case 'c': /* RIS: restore power-on settings */ compatibility(VT100); power_on(term, TRUE); if (term->ldisc) /* cause ldisc to notice changes */ ldisc_send(term->ldisc, NULL, 0, 0); if (term->reset_132) { if (!term->cfg.no_remote_resize) request_resize(term->frontend, 80, term->rows); term->reset_132 = 0; } term->disptop = 0; seen_disp_event(term); break; case 'H': /* HTS: set a tab */ |
︙ | ︙ | |||
3317 3318 3319 3320 3321 3322 3323 | } scrlineptr(term->curs.y)->lattr = nlattr; } break; /* GZD4: G0 designate 94-set */ case ANSI('A', '('): compatibility(VT100); | | | | | | | | | | | | 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 | } scrlineptr(term->curs.y)->lattr = nlattr; } break; /* GZD4: G0 designate 94-set */ case ANSI('A', '('): compatibility(VT100); if (!term->cfg.no_remote_charset) term->cset_attr[0] = CSET_GBCHR; break; case ANSI('B', '('): compatibility(VT100); if (!term->cfg.no_remote_charset) term->cset_attr[0] = CSET_ASCII; break; case ANSI('0', '('): compatibility(VT100); if (!term->cfg.no_remote_charset) term->cset_attr[0] = CSET_LINEDRW; break; case ANSI('U', '('): compatibility(OTHER); if (!term->cfg.no_remote_charset) term->cset_attr[0] = CSET_SCOACS; break; /* G1D4: G1-designate 94-set */ case ANSI('A', ')'): compatibility(VT100); if (!term->cfg.no_remote_charset) term->cset_attr[1] = CSET_GBCHR; break; case ANSI('B', ')'): compatibility(VT100); if (!term->cfg.no_remote_charset) term->cset_attr[1] = CSET_ASCII; break; case ANSI('0', ')'): compatibility(VT100); if (!term->cfg.no_remote_charset) term->cset_attr[1] = CSET_LINEDRW; break; case ANSI('U', ')'): compatibility(OTHER); if (!term->cfg.no_remote_charset) term->cset_attr[1] = CSET_SCOACS; break; /* DOCS: Designate other coding system */ case ANSI('8', '%'): /* Old Linux code */ case ANSI('G', '%'): compatibility(OTHER); if (!term->cfg.no_remote_charset) term->utf = 1; break; case ANSI('@', '%'): compatibility(OTHER); if (!term->cfg.no_remote_charset) term->utf = 0; break; } break; case SEEN_CSI: term->termstate = TOPLEVEL; /* default */ if (isdigit(c)) { |
︙ | ︙ | |||
3549 3550 3551 3552 3553 3554 3555 | term->esc_query, TRUE); } break; case 'i': /* MC: Media copy */ case ANSI_QUE('i'): compatibility(VT100); { | < | < < | | 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 | term->esc_query, TRUE); } break; case 'i': /* MC: Media copy */ case ANSI_QUE('i'): compatibility(VT100); { if (term->esc_nargs != 1) break; if (term->esc_args[0] == 5 && *term->cfg.printer) { term->printing = TRUE; term->only_printing = !term->esc_query; term->print_state = 0; term_print_setup(term); } else if (term->esc_args[0] == 4 && term->printing) { term_print_finish(term); } } break; case 'l': /* RM: toggle modes to low */ |
︙ | ︙ | |||
3680 3681 3682 3683 3684 3685 3686 | term_schedule_tblink(term); break; case 7: /* enable reverse video */ term->curr_attr |= ATTR_REVERSE; break; case 10: /* SCO acs off */ compatibility(SCOANSI); | | | | | 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 | term_schedule_tblink(term); break; case 7: /* enable reverse video */ term->curr_attr |= ATTR_REVERSE; break; case 10: /* SCO acs off */ compatibility(SCOANSI); if (term->cfg.no_remote_charset) break; term->sco_acs = 0; break; case 11: /* SCO acs on */ compatibility(SCOANSI); if (term->cfg.no_remote_charset) break; term->sco_acs = 1; break; case 12: /* SCO acs on, |0x80 */ compatibility(SCOANSI); if (term->cfg.no_remote_charset) break; term->sco_acs = 2; break; case 22: /* disable bold */ compatibility2(OTHER, VT220); term->curr_attr &= ~ATTR_BOLD; break; case 24: /* disable underline */ compatibility2(OTHER, VT220); |
︙ | ︙ | |||
3811 3812 3813 3814 3815 3816 3817 | * illegal values (eg first arg 1..9) for window changing * and reports. */ if (term->esc_nargs <= 1 && (term->esc_args[0] < 1 || term->esc_args[0] >= 24)) { compatibility(VT340TEXT); | | | | 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 | * illegal values (eg first arg 1..9) for window changing * and reports. */ if (term->esc_nargs <= 1 && (term->esc_args[0] < 1 || term->esc_args[0] >= 24)) { compatibility(VT340TEXT); if (!term->cfg.no_remote_resize) request_resize(term->frontend, term->cols, def(term->esc_args[0], 24)); deselect(term); } else if (term->esc_nargs >= 1 && term->esc_args[0] >= 1 && term->esc_args[0] < 24) { compatibility(OTHER); switch (term->esc_args[0]) { int x, y, len; char buf[80], *p; case 1: set_iconic(term->frontend, FALSE); break; case 2: set_iconic(term->frontend, TRUE); break; case 3: if (term->esc_nargs >= 3) { if (!term->cfg.no_remote_resize) move_window(term->frontend, def(term->esc_args[1], 0), def(term->esc_args[2], 0)); } break; case 4: /* We should resize the window to a given |
︙ | ︙ | |||
3856 3857 3858 3859 3860 3861 3862 | set_zorder(term->frontend, FALSE); break; case 7: refresh_window(term->frontend); break; case 8: if (term->esc_nargs >= 3) { | | | | | 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 | set_zorder(term->frontend, FALSE); break; case 7: refresh_window(term->frontend); break; case 8: if (term->esc_nargs >= 3) { if (!term->cfg.no_remote_resize) request_resize(term->frontend, def(term->esc_args[2], term->cfg.width), def(term->esc_args[1], term->cfg.height)); } break; case 9: if (term->esc_nargs >= 2) set_zoomed(term->frontend, term->esc_args[1] ? TRUE : FALSE); |
︙ | ︙ | |||
3914 3915 3916 3917 3918 3919 3920 | * moment and see if anyone * complains, and then ask them * what they would like it to do. */ break; case 20: if (term->ldisc && | | | | | | 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 | * moment and see if anyone * complains, and then ask them * what they would like it to do. */ break; case 20: if (term->ldisc && term->cfg.remote_qtitle_action != TITLE_NONE) { if(term->cfg.remote_qtitle_action == TITLE_REAL) p = get_window_title(term->frontend, TRUE); else p = EMPTY_WINDOW_TITLE; len = strlen(p); ldisc_send(term->ldisc, "\033]L", 3, 0); ldisc_send(term->ldisc, p, len, 0); ldisc_send(term->ldisc, "\033\\", 2, 0); } break; case 21: if (term->ldisc && term->cfg.remote_qtitle_action != TITLE_NONE) { if(term->cfg.remote_qtitle_action == TITLE_REAL) p = get_window_title(term->frontend, FALSE); else p = EMPTY_WINDOW_TITLE; len = strlen(p); ldisc_send(term->ldisc, "\033]l", 3, 0); ldisc_send(term->ldisc, p, len, 0); ldisc_send(term->ldisc, "\033\\", 2, 0); |
︙ | ︙ | |||
3964 3965 3966 3967 3968 3969 3970 | * Set number of lines on screen * VT420 uses VGA like hardware and can * support any size in reasonable range * (24..49 AIUI) with no default specified. */ compatibility(VT420); if (term->esc_nargs == 1 && term->esc_args[0] > 0) { | | | | | < | 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 | * Set number of lines on screen * VT420 uses VGA like hardware and can * support any size in reasonable range * (24..49 AIUI) with no default specified. */ compatibility(VT420); if (term->esc_nargs == 1 && term->esc_args[0] > 0) { if (!term->cfg.no_remote_resize) request_resize(term->frontend, term->cols, def(term->esc_args[0], term->cfg.height)); deselect(term); } break; case ANSI('|', '$'): /* DECSCPP */ /* * Set number of columns per page * Docs imply range is only 80 or 132, but * I'll allow any. */ compatibility(VT340TEXT); if (term->esc_nargs <= 1) { if (!term->cfg.no_remote_resize) request_resize(term->frontend, def(term->esc_args[0], term->cfg.width), term->rows); deselect(term); } break; case 'X': /* ECH: write N spaces w/o moving cursor */ /* XXX VTTEST says this is vt220, vt510 manual * says vt100 */ compatibility(ANSIMIN); |
︙ | ︙ | |||
4185 4186 4187 4188 4189 4190 4191 | strcat(term->id_string, "c"); } #if 0 /* Is this a good idea ? * Well we should do a soft reset at this point ... */ if (!has_compat(VT420) && has_compat(VT100)) { | | | 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 | strcat(term->id_string, "c"); } #if 0 /* Is this a good idea ? * Well we should do a soft reset at this point ... */ if (!has_compat(VT420) && has_compat(VT100)) { if (!term->cfg.no_remote_resize) { if (term->reset_132) request_resize(132, 24); else request_resize(80, 24); } } #endif |
︙ | ︙ | |||
4420 4421 4422 4423 4424 4425 4426 | break; case '<': /* XXX This should switch to VT100 mode not current or default * VT mode. But this will only have effect in a VT220+ * emulation. */ term->vt52_mode = FALSE; | | | 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 | break; case '<': /* XXX This should switch to VT100 mode not current or default * VT mode. But this will only have effect in a VT220+ * emulation. */ term->vt52_mode = FALSE; term->blink_is_real = term->cfg.blinktext; term_schedule_tblink(term); break; #if 0 case '^': /* XXX Enter auto print mode */ break; case '_': |
︙ | ︙ | |||
4564 4565 4566 4567 4568 4569 4570 | pos cursplus = term->curs; incpos(cursplus); check_selection(term, term->curs, cursplus); } } term_print_flush(term); | | | 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 | pos cursplus = term->curs; incpos(cursplus); check_selection(term, term->curs, cursplus); } } term_print_flush(term); if (term->cfg.logflush) logflush(term->logctx); } /* * To prevent having to run the reasonably tricky bidi algorithm * too many times, we maintain a cache of the last lineful of data * fed to the algorithm on each line of the display. |
︙ | ︙ | |||
4667 4668 4669 4670 4671 4672 4673 | static termchar *term_bidi_line(Terminal *term, struct termline *ldata, int scr_y) { termchar *lchars; int it; /* Do Arabic shaping and bidi. */ | | | | | | | | 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 | static termchar *term_bidi_line(Terminal *term, struct termline *ldata, int scr_y) { termchar *lchars; int it; /* Do Arabic shaping and bidi. */ if(!term->cfg.bidi || !term->cfg.arabicshaping) { if (!term_bidi_cache_hit(term, scr_y, ldata->chars, term->cols)) { if (term->wcFromTo_size < term->cols) { term->wcFromTo_size = term->cols; term->wcFrom = sresize(term->wcFrom, term->wcFromTo_size, bidi_char); term->wcTo = sresize(term->wcTo, term->wcFromTo_size, bidi_char); } for(it=0; it<term->cols ; it++) { unsigned long uc = (ldata->chars[it].chr); switch (uc & CSET_MASK) { case CSET_LINEDRW: if (!term->cfg.rawcnp) { uc = term->ucsdata->unitab_xterm[uc & 0xFF]; break; } case CSET_ASCII: uc = term->ucsdata->unitab_line[uc & 0xFF]; break; case CSET_SCOACS: uc = term->ucsdata->unitab_scoacs[uc&0xFF]; break; } switch (uc & CSET_MASK) { case CSET_ACP: uc = term->ucsdata->unitab_font[uc & 0xFF]; break; case CSET_OEMCP: uc = term->ucsdata->unitab_oemcp[uc & 0xFF]; break; } term->wcFrom[it].origwc = term->wcFrom[it].wc = (wchar_t)uc; term->wcFrom[it].index = it; } if(!term->cfg.bidi) do_bidi(term->wcFrom, term->cols); /* this is saved iff done from inside the shaping */ if(!term->cfg.bidi && term->cfg.arabicshaping) for(it=0; it<term->cols; it++) term->wcTo[it] = term->wcFrom[it]; if(!term->cfg.arabicshaping) do_shape(term->wcFrom, term->wcTo, term->cols); if (term->ltemp_size < ldata->size) { term->ltemp_size = ldata->size; term->ltemp = sresize(term->ltemp, term->ltemp_size, termchar); } |
︙ | ︙ | |||
4780 4781 4782 4783 4784 4785 4786 | newline = snewn(term->cols, termchar); rv = (!term->rvideo ^ !term->in_vbell ? ATTR_REVERSE : 0); /* Depends on: * screen array, disptop, scrtop, * selection, rv, | | | | | 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 | newline = snewn(term->cols, termchar); rv = (!term->rvideo ^ !term->in_vbell ? ATTR_REVERSE : 0); /* Depends on: * screen array, disptop, scrtop, * selection, rv, * cfg.blinkpc, blink_is_real, tblinker, * curs.y, curs.x, cblinker, cfg.blink_cur, cursor_on, has_focus, wrapnext */ /* Has the cursor position or type changed ? */ if (term->cursor_on) { if (term->has_focus) { if (term->cblinker || !term->cfg.blink_cur) cursor = TATTR_ACTCURS; else cursor = 0; } else cursor = TATTR_PASCURS; if (term->wrapnext) cursor |= TATTR_RIGHTCURS; |
︙ | ︙ | |||
4895 4896 4897 4898 4899 4900 4901 | unsigned long tattr, tchar; termchar *d = lchars + j; scrpos.x = backward ? backward[j] : j; tchar = d->chr; tattr = d->attr; | | | | 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 | unsigned long tattr, tchar; termchar *d = lchars + j; scrpos.x = backward ? backward[j] : j; tchar = d->chr; tattr = d->attr; if (!term->cfg.ansi_colour) tattr = (tattr & ~(ATTR_FGMASK | ATTR_BGMASK)) | ATTR_DEFFG | ATTR_DEFBG; if (!term->cfg.xterm_256_colour) { int colour; colour = (tattr & ATTR_FGMASK) >> ATTR_FGSHIFT; if (colour >= 16 && colour < 256) tattr = (tattr &~ ATTR_FGMASK) | ATTR_DEFFG; colour = (tattr & ATTR_BGMASK) >> ATTR_BGSHIFT; if (colour >= 16 && colour < 256) tattr = (tattr &~ ATTR_BGMASK) | ATTR_DEFBG; |
︙ | ︙ | |||
5029 5030 5031 5032 5033 5034 5035 | tchar = newline[j].chr; if ((term->disptext[i]->chars[j].attr ^ tattr) & ATTR_WIDE) dirty_line = TRUE; break_run = ((tattr ^ attr) & term->attr_mask) != 0; | < < | 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 | tchar = newline[j].chr; if ((term->disptext[i]->chars[j].attr ^ tattr) & ATTR_WIDE) dirty_line = TRUE; break_run = ((tattr ^ attr) & term->attr_mask) != 0; /* Special hack for VT100 Linedraw glyphs */ if ((tchar >= 0x23BA && tchar <= 0x23BD) || (j > 0 && (newline[j-1].chr >= 0x23BA && newline[j-1].chr <= 0x23BD))) break_run = TRUE; /* * Separate out sequences of characters that have the * same CSET, if that CSET is a magic one. */ if (CSET_OF(tchar) != cset) break_run = TRUE; |
︙ | ︙ | |||
5083 5084 5085 5086 5087 5088 5089 | do_copy = FALSE; if (!termchars_equal_override(&term->disptext[i]->chars[j], d, tchar, tattr)) { do_copy = TRUE; dirty_run = TRUE; } | | < < < < < < < | 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 | do_copy = FALSE; if (!termchars_equal_override(&term->disptext[i]->chars[j], d, tchar, tattr)) { do_copy = TRUE; dirty_run = TRUE; } if (ccount >= chlen) { chlen = ccount + 256; ch = sresize(ch, chlen, wchar_t); } ch[ccount++] = (wchar_t) tchar; if (d->cc_next) { termchar *dd = d; while (dd->cc_next) { unsigned long schar; |
︙ | ︙ | |||
5117 5118 5119 5120 5121 5122 5123 | schar = term->ucsdata->unitab_xterm[schar & 0xFF]; break; case CSET_SCOACS: schar = term->ucsdata->unitab_scoacs[schar&0xFF]; break; } | | < < < < < < < | 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 | schar = term->ucsdata->unitab_xterm[schar & 0xFF]; break; case CSET_SCOACS: schar = term->ucsdata->unitab_scoacs[schar&0xFF]; break; } if (ccount >= chlen) { chlen = ccount + 256; ch = sresize(ch, chlen, wchar_t); } ch[ccount++] = (wchar_t) schar; } attr |= TATTR_COMBINING; } if (do_copy) { |
︙ | ︙ | |||
5373 5374 5375 5376 5377 5378 5379 | while (1) { int uc = ldata->chars[x].chr; attr = ldata->chars[x].attr; switch (uc & CSET_MASK) { case CSET_LINEDRW: | | | 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 | while (1) { int uc = ldata->chars[x].chr; attr = ldata->chars[x].attr; switch (uc & CSET_MASK) { case CSET_LINEDRW: if (!term->cfg.rawcnp) { uc = term->ucsdata->unitab_xterm[uc & 0xFF]; break; } case CSET_ASCII: uc = term->ucsdata->unitab_line[uc & 0xFF]; break; case CSET_SCOACS: |
︙ | ︙ | |||
5627 5628 5629 5630 5631 5632 5633 | term->cols-1 : term->cols); if (p.x < maxcols-1) { if (wordtype(term, UCSGET(ldata->chars, p.x+1)) == wvalue) p.x++; else break; } else { | < | | 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 | term->cols-1 : term->cols); if (p.x < maxcols-1) { if (wordtype(term, UCSGET(ldata->chars, p.x+1)) == wvalue) p.x++; else break; } else { if (ldata->lattr & LATTR_WRAPPED) { termline *ldata2; ldata2 = lineptr(p.y+1); if (wordtype(term, UCSGET(ldata2->chars, 0)) == wvalue) { p.x = 0; p.y++; unlineptr(ldata); |
︙ | ︙ | |||
5699 5700 5701 5702 5703 5704 5705 | term->selstart = sel_spread_half(term, term->selstart, -1); decpos(term->selend); term->selend = sel_spread_half(term, term->selend, +1); incpos(term->selend); } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < < < < | 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 | term->selstart = sel_spread_half(term, term->selstart, -1); decpos(term->selend); term->selend = sel_spread_half(term, term->selend, +1); incpos(term->selend); } } void term_do_paste(Terminal *term) { wchar_t *data; int len; get_clip(term->frontend, &data, &len); if (data && len > 0) { wchar_t *p, *q; term_seen_key_event(term); /* pasted data counts */ if (term->paste_buffer) sfree(term->paste_buffer); term->paste_pos = term->paste_hold = term->paste_len = 0; term->paste_buffer = snewn(len, wchar_t); p = q = data; while (p < data + len) { while (p < data + len && !(p <= data + len - sel_nl_sz && !memcmp(p, sel_nl, sizeof(sel_nl)))) p++; |
︙ | ︙ | |||
5769 5770 5771 5772 5773 5774 5775 | !memcmp(p, sel_nl, sizeof(sel_nl))) { term->paste_buffer[term->paste_len++] = '\015'; p += sel_nl_sz; } q = p; } | < < < < < < | < < | | | 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 | !memcmp(p, sel_nl, sizeof(sel_nl))) { term->paste_buffer[term->paste_len++] = '\015'; p += sel_nl_sz; } q = p; } /* Assume a small paste will be OK in one go. */ if (term->paste_len < 256) { if (term->ldisc) luni_send(term->ldisc, term->paste_buffer, term->paste_len, 0); if (term->paste_buffer) sfree(term->paste_buffer); term->paste_buffer = 0; term->paste_pos = term->paste_hold = term->paste_len = 0; } } get_clip(term->frontend, NULL, NULL); } void term_mouse(Terminal *term, Mouse_Button braw, Mouse_Button bcooked, Mouse_Action a, int x, int y, int shift, int ctrl, int alt) { pos selpoint; termline *ldata; int raw_mouse = (term->xterm_mouse && !term->cfg.no_mouse_rep && !(term->cfg.mouse_override && shift)); int default_seltype; if (y < 0) { y = 0; if (a == MA_DRAG && !raw_mouse) term_scroll(term, 0, -1); } |
︙ | ︙ | |||
5848 5849 5850 5851 5852 5853 5854 | * This makes use of Shift for selection reliable, and avoids the * host seeing mouse releases for which they never saw corresponding * presses. */ if (raw_mouse && (term->selstate != ABOUT_TO) && (term->selstate != DRAGGING)) { int encstate = 0, r, c; | | < | | | | | < < | | | < < < < < < | < | | | 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743 5744 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 | * This makes use of Shift for selection reliable, and avoids the * host seeing mouse releases for which they never saw corresponding * presses. */ if (raw_mouse && (term->selstate != ABOUT_TO) && (term->selstate != DRAGGING)) { int encstate = 0, r, c; char abuf[16]; if (term->ldisc) { switch (braw) { case MBT_LEFT: encstate = 0x20; /* left button down */ break; case MBT_MIDDLE: encstate = 0x21; break; case MBT_RIGHT: encstate = 0x22; break; case MBT_WHEEL_UP: encstate = 0x60; break; case MBT_WHEEL_DOWN: encstate = 0x61; break; default: break; /* placate gcc warning about enum use */ } switch (a) { case MA_DRAG: if (term->xterm_mouse == 1) return; encstate += 0x20; break; case MA_RELEASE: encstate = 0x23; term->mouse_is_down = 0; break; case MA_CLICK: if (term->mouse_is_down == braw) return; term->mouse_is_down = braw; break; default: break; /* placate gcc warning about enum use */ } if (shift) encstate += 0x04; if (ctrl) encstate += 0x10; r = y + 33; c = x + 33; sprintf(abuf, "\033[M%c%c%c", encstate, c, r); ldisc_send(term->ldisc, abuf, 6, 0); } return; } /* * Set the selection type (rectangular or normal) at the start * of a selection attempt, from the state of Alt. */ if (!alt ^ !term->cfg.rect_select) default_seltype = RECTANGULAR; else default_seltype = LEXICOGRAPHIC; if (term->selstate == NO_SELECTION) { term->seltype = default_seltype; } |
︙ | ︙ | |||
6024 6025 6026 6027 6028 6029 6030 | #if MULTICLICK_ONLY_EVENT || a == MA_2CLK || a == MA_3CLK #endif )) { request_paste(term->frontend); } | < < < < < < < | | 5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 5884 5885 5886 5887 | #if MULTICLICK_ONLY_EVENT || a == MA_2CLK || a == MA_3CLK #endif )) { request_paste(term->frontend); } term_update(term); } int format_arrow_key(char *buf, Terminal *term, int xkey, int ctrl) { char *p = buf; if (term->vt52_mode) p += sprintf((char *) p, "\x1B%c", xkey); else { int app_flg = (term->app_cursor_keys && !term->cfg.no_applic_c); #if 0 /* * RDB: VT100 & VT102 manuals both state the app cursor * keys only work if the app keypad is on. * * SGT: That may well be true, but xterm disagrees and so * does at least one application, so I've #if'ed this out |
︙ | ︙ | |||
6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 | p += sprintf((char *) p, "\x1BO%c", xkey); else p += sprintf((char *) p, "\x1B[%c", xkey); } return p - buf; } void term_nopaste(Terminal *term) { if (term->paste_len == 0) return; sfree(term->paste_buffer); term->paste_buffer = NULL; term->paste_len = 0; } static void deselect(Terminal *term) { term->selstate = NO_SELECTION; term->selstart.x = term->selstart.y = term->selend.x = term->selend.y = 0; } void term_deselect(Terminal *term) { deselect(term); term_update(term); | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < < < < < < < | 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 5996 5997 5998 5999 6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 6043 6044 6045 6046 6047 6048 6049 6050 6051 6052 6053 6054 6055 6056 6057 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097 6098 6099 6100 6101 6102 6103 6104 6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144 6145 6146 6147 6148 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158 6159 6160 6161 6162 6163 6164 6165 6166 6167 6168 6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267 6268 6269 6270 6271 6272 6273 6274 6275 6276 6277 6278 6279 6280 6281 6282 6283 6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317 6318 6319 6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362 6363 6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 6398 6399 6400 6401 6402 | p += sprintf((char *) p, "\x1BO%c", xkey); else p += sprintf((char *) p, "\x1B[%c", xkey); } return p - buf; } void term_key(Terminal *term, Key_Sym keysym, wchar_t *text, size_t tlen, unsigned int modifiers, unsigned int flags) { char output[10]; char *p = output; int prependesc = FALSE; #if 0 int i; fprintf(stderr, "keysym = %d, %d chars:", keysym, tlen); for (i = 0; i < tlen; i++) fprintf(stderr, " %04x", (unsigned)text[i]); fprintf(stderr, "\n"); #endif /* XXX Num Lock */ if ((flags & PKF_REPEAT) && term->repeat_off) return; /* Currently, Meta always just prefixes everything with ESC. */ if (modifiers & PKM_META) prependesc = TRUE; modifiers &= ~PKM_META; /* * Alt is only used for Alt+keypad, which isn't supported yet, so * ignore it. */ modifiers &= ~PKM_ALT; /* Standard local function keys */ switch (modifiers & (PKM_SHIFT | PKM_CONTROL)) { case PKM_SHIFT: if (keysym == PK_PAGEUP) /* scroll up one page */; if (keysym == PK_PAGEDOWN) /* scroll down on page */; if (keysym == PK_INSERT) term_do_paste(term); break; case PKM_CONTROL: if (keysym == PK_PAGEUP) /* scroll up one line */; if (keysym == PK_PAGEDOWN) /* scroll down one line */; /* Control-Numlock for app-keypad mode switch */ if (keysym == PK_PF1) term->app_keypad_keys ^= 1; break; } if (modifiers & PKM_ALT) { /* Alt+F4 (close) */ /* Alt+Return (full screen) */ /* Alt+Space (system menu) */ } if (keysym == PK_NULL && (modifiers & PKM_CONTROL) && tlen == 1 && text[0] >= 0x20 && text[0] <= 0x7e) { /* ASCII chars + Control */ if ((text[0] >= 0x40 && text[0] <= 0x5f) || (text[0] >= 0x61 && text[0] <= 0x7a)) text[0] &= 0x1f; else { /* * Control-2 should return ^@ (0x00), Control-6 should return * ^^ (0x1E), and Control-Minus should return ^_ (0x1F). Since * the DOS keyboard handling did it, and we have nothing better * to do with the key combo in question, we'll also map * Control-Backquote to ^\ (0x1C). */ switch (text[0]) { case ' ': text[0] = 0x00; break; case '-': text[0] = 0x1f; break; case '/': text[0] = 0x1f; break; case '2': text[0] = 0x00; break; case '3': text[0] = 0x1b; break; case '4': text[0] = 0x1c; break; case '5': text[0] = 0x1d; break; case '6': text[0] = 0x1e; break; case '7': text[0] = 0x1f; break; case '8': text[0] = 0x7f; break; case '`': text[0] = 0x1c; break; } } } /* Nethack keypad */ if (term->cfg.nethack_keypad) { char c = 0; switch (keysym) { case PK_KP1: c = 'b'; break; case PK_KP2: c = 'j'; break; case PK_KP3: c = 'n'; break; case PK_KP4: c = 'h'; break; case PK_KP5: c = '.'; break; case PK_KP6: c = 'l'; break; case PK_KP7: c = 'y'; break; case PK_KP8: c = 'k'; break; case PK_KP9: c = 'u'; break; default: break; /* else gcc warns `enum value not used' */ } if (c != 0) { if (c != '.') { if (modifiers & PKM_CONTROL) c &= 0x1f; else if (modifiers & PKM_SHIFT) c = toupper((unsigned char)c); } *p++ = c; goto done; } } /* Numeric Keypad */ if (PK_ISKEYPAD(keysym)) { int xkey = 0; /* * In VT400 mode, PFn always emits an escape sequence. In * Linux and tilde modes, this only happens in app keypad mode. */ if (term->cfg.funky_type == FUNKY_VT400 || ((term->cfg.funky_type == FUNKY_LINUX || term->cfg.funky_type == FUNKY_TILDE) && term->app_keypad_keys && !term->cfg.no_applic_k)) { switch (keysym) { case PK_PF1: xkey = 'P'; break; case PK_PF2: xkey = 'Q'; break; case PK_PF3: xkey = 'R'; break; case PK_PF4: xkey = 'S'; break; default: break; /* else gcc warns `enum value not used' */ } } if (term->app_keypad_keys && !term->cfg.no_applic_k) { switch (keysym) { case PK_KP0: xkey = 'p'; break; case PK_KP1: xkey = 'q'; break; case PK_KP2: xkey = 'r'; break; case PK_KP3: xkey = 's'; break; case PK_KP4: xkey = 't'; break; case PK_KP5: xkey = 'u'; break; case PK_KP6: xkey = 'v'; break; case PK_KP7: xkey = 'w'; break; case PK_KP8: xkey = 'x'; break; case PK_KP9: xkey = 'y'; break; case PK_KPDECIMAL: xkey = 'n'; break; case PK_KPENTER: xkey = 'M'; break; default: break; /* else gcc warns `enum value not used' */ } if (term->cfg.funky_type == FUNKY_XTERM && tlen > 0) { /* * xterm can't see the layout of the keypad, so it has * to rely on the X keysyms returned by the keys. * Hence, we look at the strings here, not the PuTTY * keysyms (which describe the layout). */ switch (text[0]) { case '+': if (modifiers & PKM_SHIFT) xkey = 'l'; else xkey = 'k'; break; case '/': xkey = 'o'; break; case '*': xkey = 'j'; break; case '-': xkey = 'm'; break; } } else { /* * In all other modes, we try to retain the layout of * the DEC keypad in application mode. */ switch (keysym) { case PK_KPBIGPLUS: /* This key covers the '-' and ',' keys on a VT220 */ if (modifiers & PKM_SHIFT) xkey = 'm'; /* VT220 '-' */ else xkey = 'l'; /* VT220 ',' */ break; case PK_KPMINUS: xkey = 'm'; break; case PK_KPCOMMA: xkey = 'l'; break; default: break; /* else gcc warns `enum value not used' */ } } } if (xkey) { if (term->vt52_mode) { if (xkey >= 'P' && xkey <= 'S') p += sprintf((char *) p, "\x1B%c", xkey); else p += sprintf((char *) p, "\x1B?%c", xkey); } else p += sprintf((char *) p, "\x1BO%c", xkey); goto done; } /* Not in application mode -- treat the number pad as arrow keys? */ if ((flags & PKF_NUMLOCK) == 0) { switch (keysym) { case PK_KP0: keysym = PK_INSERT; break; case PK_KP1: keysym = PK_END; break; case PK_KP2: keysym = PK_DOWN; break; case PK_KP3: keysym = PK_PAGEDOWN; break; case PK_KP4: keysym = PK_LEFT; break; case PK_KP5: keysym = PK_REST; break; case PK_KP6: keysym = PK_RIGHT; break; case PK_KP7: keysym = PK_HOME; break; case PK_KP8: keysym = PK_UP; break; case PK_KP9: keysym = PK_PAGEUP; break; default: break; /* else gcc warns `enum value not used' */ } } } /* Miscellaneous keys */ switch (keysym) { case PK_ESCAPE: *p++ = 0x1b; goto done; case PK_BACKSPACE: if (modifiers == 0) *p++ = (term->cfg.bksp_is_delete ? 0x7F : 0x08); else if (modifiers == PKM_SHIFT) /* We do the opposite of what is configured */ *p++ = (term->cfg.bksp_is_delete ? 0x08 : 0x7F); else break; goto done; case PK_TAB: if (modifiers == 0) *p++ = 0x09; else if (modifiers == PKM_SHIFT) *p++ = 0x1B, *p++ = '[', *p++ = 'Z'; else break; goto done; /* XXX window.c has ctrl+shift+space sending 0xa0 */ case PK_PAUSE: if (modifiers == PKM_CONTROL) *p++ = 26; else break; goto done; case PK_RETURN: case PK_KPENTER: /* Odd keypad modes handled above */ if (modifiers == 0) { *p++ = 0x0d; if (term->cr_lf_return) *p++ = 0x0a; goto done; } default: break; /* else gcc warns `enum value not used' */ } /* SCO function keys and editing keys */ if (term->cfg.funky_type == FUNKY_SCO) { if (PK_ISFKEY(keysym) && keysym <= PK_F12) { static char const codes[] = "MNOPQRSTUVWX" "YZabcdefghij" "klmnopqrstuv" "wxyz@[\\]^_`{"; int index = keysym - PK_F1; if (modifiers & PKM_SHIFT) index += 12; if (modifiers & PKM_CONTROL) index += 24; p += sprintf((char *) p, "\x1B[%c", codes[index]); goto done; } if (PK_ISEDITING(keysym)) { int xkey = 0; switch (keysym) { case PK_DELETE: *p++ = 0x7f; goto done; case PK_HOME: xkey = 'H'; break; case PK_INSERT: xkey = 'L'; break; case PK_END: xkey = 'F'; break; case PK_PAGEUP: xkey = 'I'; break; case PK_PAGEDOWN: xkey = 'G'; break; default: break; /* else gcc warns `enum value not used' */ } p += sprintf((char *) p, "\x1B[%c", xkey); } } if (PK_ISEDITING(keysym) && (modifiers & PKM_SHIFT) == 0) { int code; if (term->cfg.funky_type == FUNKY_XTERM) { /* Xterm shuffles these keys, apparently. */ switch (keysym) { case PK_HOME: keysym = PK_INSERT; break; case PK_INSERT: keysym = PK_HOME; break; case PK_DELETE: keysym = PK_END; break; case PK_END: keysym = PK_PAGEUP; break; case PK_PAGEUP: keysym = PK_DELETE; break; case PK_PAGEDOWN: keysym = PK_PAGEDOWN; break; default: break; /* else gcc warns `enum value not used' */ } } /* RXVT Home/End */ if (term->cfg.rxvt_homeend && (keysym == PK_HOME || keysym == PK_END)) { p += sprintf((char *) p, keysym == PK_HOME ? "\x1B[H" : "\x1BOw"); goto done; } if (term->vt52_mode) { int xkey; /* * A real VT52 doesn't have these, and a VT220 doesn't * send anything for them in VT52 mode. */ switch (keysym) { case PK_HOME: xkey = 'H'; break; case PK_INSERT: xkey = 'L'; break; case PK_DELETE: xkey = 'M'; break; case PK_END: xkey = 'E'; break; case PK_PAGEUP: xkey = 'I'; break; case PK_PAGEDOWN: xkey = 'G'; break; default: xkey=0; break; /* else gcc warns `enum value not used'*/ } p += sprintf((char *) p, "\x1B%c", xkey); goto done; } switch (keysym) { case PK_HOME: code = 1; break; case PK_INSERT: code = 2; break; case PK_DELETE: code = 3; break; case PK_END: code = 4; break; case PK_PAGEUP: code = 5; break; case PK_PAGEDOWN: code = 6; break; default: code = 0; break; /* else gcc warns `enum value not used' */ } p += sprintf((char *) p, "\x1B[%d~", code); goto done; } if (PK_ISFKEY(keysym)) { /* Map Shift+F1-F10 to F11-F20 */ if (keysym >= PK_F1 && keysym <= PK_F10 && (modifiers & PKM_SHIFT)) keysym += 10; if ((term->vt52_mode || term->cfg.funky_type == FUNKY_VT100P) && keysym <= PK_F14) { /* XXX This overrides the XTERM/VT52 mode below */ int offt = 0; if (keysym >= PK_F6) offt++; if (keysym >= PK_F12) offt++; p += sprintf((char *) p, term->vt52_mode ? "\x1B%c" : "\x1BO%c", 'P' + keysym - PK_F1 - offt); goto done; } if (term->cfg.funky_type == FUNKY_LINUX && keysym <= PK_F5) { p += sprintf((char *) p, "\x1B[[%c", 'A' + keysym - PK_F1); goto done; } if (term->cfg.funky_type == FUNKY_XTERM && keysym <= PK_F4) { if (term->vt52_mode) p += sprintf((char *) p, "\x1B%c", 'P' + keysym - PK_F1); else p += sprintf((char *) p, "\x1BO%c", 'P' + keysym - PK_F1); goto done; } p += sprintf((char *) p, "\x1B[%d~", 11 + keysym - PK_F1); goto done; } if (PK_ISCURSOR(keysym)) { int xkey; switch (keysym) { case PK_UP: xkey = 'A'; break; case PK_DOWN: xkey = 'B'; break; case PK_RIGHT: xkey = 'C'; break; case PK_LEFT: xkey = 'D'; break; case PK_REST: xkey = 'G'; break; /* centre key on number pad */ default: xkey = 0; break; /* else gcc warns `enum value not used' */ } p += format_arrow_key(p, term, xkey, modifiers == PKM_CONTROL); goto done; } done: if (p > output || tlen > 0) { /* * Interrupt an ongoing paste. I'm not sure * this is sensible, but for the moment it's * preferable to having to faff about buffering * things. */ term_nopaste(term); /* * We need not bother about stdin backlogs * here, because in GUI PuTTY we can't do * anything about it anyway; there's no means * of asking Windows to hold off on KEYDOWN * messages. We _have_ to buffer everything * we're sent. */ term_seen_key_event(term); if (prependesc) { #if 0 fprintf(stderr, "sending ESC\n"); #endif ldisc_send(term->ldisc, "\x1b", 1, 1); } if (p > output) { #if 0 fprintf(stderr, "sending %d bytes:", p - output); for (i = 0; i < p - output; i++) fprintf(stderr, " %02x", output[i]); fprintf(stderr, "\n"); #endif ldisc_send(term->ldisc, output, p - output, 1); } else if (tlen > 0) { #if 0 fprintf(stderr, "sending %d unichars:", tlen); for (i = 0; i < tlen; i++) fprintf(stderr, " %04x", (unsigned) text[i]); fprintf(stderr, "\n"); #endif luni_send(term->ldisc, text, tlen, 1); } } } void term_nopaste(Terminal *term) { if (term->paste_len == 0) return; sfree(term->paste_buffer); term->paste_buffer = NULL; term->paste_len = 0; } int term_paste_pending(Terminal *term) { return term->paste_len != 0; } void term_paste(Terminal *term) { long now, paste_diff; if (term->paste_len == 0) return; /* Don't wait forever to paste */ if (term->paste_hold) { now = GETTICKCOUNT(); paste_diff = now - term->last_paste; if (paste_diff >= 0 && paste_diff < 450) return; } term->paste_hold = 0; while (term->paste_pos < term->paste_len) { int n = 0; while (n + term->paste_pos < term->paste_len) { if (term->paste_buffer[term->paste_pos + n++] == '\015') break; } if (term->ldisc) luni_send(term->ldisc, term->paste_buffer + term->paste_pos, n, 0); term->paste_pos += n; if (term->paste_pos < term->paste_len) { term->paste_hold = 1; return; } } sfree(term->paste_buffer); term->paste_buffer = NULL; term->paste_len = 0; } static void deselect(Terminal *term) { term->selstate = NO_SELECTION; term->selstart.x = term->selstart.y = term->selend.x = term->selend.y = 0; } void term_deselect(Terminal *term) { deselect(term); term_update(term); } int term_ldisc(Terminal *term, int option) { if (option == LD_ECHO) return term->term_echoing; if (option == LD_EDIT) |
︙ | ︙ | |||
6184 6185 6186 6187 6188 6189 6190 | * Provide "auto" settings for remote tty modes, suitable for an * application with a terminal window. */ char *term_get_ttymode(Terminal *term, const char *mode) { char *val = NULL; if (strcmp(mode, "ERASE") == 0) { | | | | 6476 6477 6478 6479 6480 6481 6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 | * Provide "auto" settings for remote tty modes, suitable for an * application with a terminal window. */ char *term_get_ttymode(Terminal *term, const char *mode) { char *val = NULL; if (strcmp(mode, "ERASE") == 0) { val = term->cfg.bksp_is_delete ? "^?" : "^H"; } /* FIXME: perhaps we should set ONLCR based on cfg.lfhascr as well? */ /* FIXME: or ECHO and friends based on local echo state? */ return dupstr(val); } struct term_userpass_state { size_t curr_prompt; int done_prompt; /* printed out prompt yet? */ |
︙ | ︙ | |||
6232 6233 6234 6235 6236 6237 6238 | } /* * Zero all the results, in case we abort half-way through. */ { int i; for (i = 0; i < (int)p->n_prompts; i++) | | | 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533 6534 6535 6536 6537 6538 | } /* * Zero all the results, in case we abort half-way through. */ { int i; for (i = 0; i < (int)p->n_prompts; i++) memset(p->prompts[i]->result, 0, p->prompts[i]->result_len); } } while (s->curr_prompt < p->n_prompts) { prompt_t *pr = p->prompts[s->curr_prompt]; int finished_prompt = 0; |
︙ | ︙ | |||
6259 6260 6261 6262 6263 6264 6265 | while (!finished_prompt && inlen) { char c = *in++; inlen--; switch (c) { case 10: case 13: term_data(term, 0, "\r\n", 2); | < > | 6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566 | while (!finished_prompt && inlen) { char c = *in++; inlen--; switch (c) { case 10: case 13: term_data(term, 0, "\r\n", 2); pr->result[s->pos] = '\0'; pr->result[pr->result_len - 1] = '\0'; /* go to next prompt, if any */ s->curr_prompt++; s->done_prompt = 0; finished_prompt = 1; /* break out */ break; case 8: case 127: |
︙ | ︙ | |||
6295 6296 6297 6298 6299 6300 6301 | return 0; /* user abort */ default: /* * This simplistic check for printability is disabled * when we're doing password input, because some people * have control characters in their passwords. */ | > | | | | 6587 6588 6589 6590 6591 6592 6593 6594 6595 6596 6597 6598 6599 6600 6601 6602 6603 6604 | return 0; /* user abort */ default: /* * This simplistic check for printability is disabled * when we're doing password input, because some people * have control characters in their passwords. */ if ((!pr->echo || (c >= ' ' && c <= '~') || ((unsigned char) c >= 160)) && s->pos < pr->result_len - 1) { pr->result[s->pos++] = c; if (pr->echo) term_data(term, 0, &c, 1); } break; } } |
︙ | ︙ |
Changes to terminal.h.
︙ | ︙ | |||
148 149 150 151 152 153 154 | long vbell_end; int app_cursor_keys, app_keypad_keys, vt52_mode; int repeat_off, cr_lf_return; int seen_disp_event; int big_cursor; int xterm_mouse; /* send mouse messages to host */ | < < < < | 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 | long vbell_end; int app_cursor_keys, app_keypad_keys, vt52_mode; int repeat_off, cr_lf_return; int seen_disp_event; int big_cursor; int xterm_mouse; /* send mouse messages to host */ int mouse_is_down; /* used while tracking mouse buttons */ int cset_attr[2]; /* * Saved settings on the alternate screen. */ int alt_x, alt_y, alt_om, alt_wrap, alt_wnext, alt_ins; int alt_cset, alt_sco_acs, alt_utf; |
︙ | ︙ | |||
218 219 220 221 222 223 224 | short wordness[256]; /* Mask of attributes to pay attention to when painting. */ int attr_mask; wchar_t *paste_buffer; | | > | | | | | | | 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 | short wordness[256]; /* Mask of attributes to pay attention to when painting. */ int attr_mask; wchar_t *paste_buffer; int paste_len, paste_pos, paste_hold; long last_paste; void (*resize_fn)(void *, int, int); void *resize_ctx; void *ldisc; void *frontend; void *logctx; struct unicode_data *ucsdata; /* * We maintain a full _copy_ of a Config structure here, not * merely a pointer to it. That way, when we're passed a new * one for reconfiguration, we can check the differences and * adjust the _current_ setting of (e.g.) auto wrap mode rather * than only the default. */ Config cfg; /* * from_backend calls term_out, but it can also be called from * the ldisc if the ldisc is called _within_ term_out. So we * have to guard against re-entrancy - if from_backend is * called recursively like this, it will simply add data to the * end of the buffer term_out is in the process of working |
︙ | ︙ | |||
272 273 274 275 276 277 278 | */ termchar *ltemp; int ltemp_size; bidi_char *wcFrom, *wcTo; int wcFromTo_size; struct bidi_cache_entry *pre_bidi_cache, *post_bidi_cache; int bidi_cache_size; | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 269 270 271 272 273 274 275 276 277 278 279 280 | */ termchar *ltemp; int ltemp_size; bidi_char *wcFrom, *wcTo; int wcFromTo_size; struct bidi_cache_entry *pre_bidi_cache, *post_bidi_cache; int bidi_cache_size; }; #define in_utf(term) ((term)->utf || (term)->ucsdata->line_codepage==CP_UTF8) #endif |
Changes to testback.c.
|
| | | 1 2 3 4 5 6 7 8 | /* $Id: testback.c 7628 2007-06-30 21:56:44Z jacob $ */ /* * Copyright (c) 1999 Simon Tatham * Copyright (c) 1999 Ben Harris * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation |
︙ | ︙ | |||
29 30 31 32 33 34 35 | /* PuTTY test backends */ #include <stdio.h> #include <stdlib.h> #include "putty.h" | | | | | 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | /* PuTTY test backends */ #include <stdio.h> #include <stdlib.h> #include "putty.h" static const char *null_init(void *, void **, Config *, char *, int, char **, int, int); static const char *loop_init(void *, void **, Config *, char *, int, char **, int, int); static void null_free(void *); static void loop_free(void *); static void null_reconfig(void *, Config *); static int null_send(void *, char *, int); static int loop_send(void *, char *, int); static int null_sendbuffer(void *); static void null_size(void *, int, int); static void null_special(void *, Telnet_Special); static const struct telnet_special *null_get_specials(void *handle); static int null_connected(void *); |
︙ | ︙ | |||
70 71 72 73 74 75 76 | }; struct loop_state { Terminal *term; }; static const char *null_init(void *frontend_handle, void **backend_handle, | | | | | 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | }; struct loop_state { Terminal *term; }; static const char *null_init(void *frontend_handle, void **backend_handle, Config *cfg, char *host, int port, char **realhost, int nodelay, int keepalive) { return NULL; } static const char *loop_init(void *frontend_handle, void **backend_handle, Config *cfg, char *host, int port, char **realhost, int nodelay, int keepalive) { struct loop_state *st = snew(struct loop_state); st->term = frontend_handle; *backend_handle = st; return NULL; } static void null_free(void *handle) { } static void loop_free(void *handle) { sfree(handle); } static void null_reconfig(void *handle, Config *cfg) { } static int null_send(void *handle, char *buf, int len) { return 0; } |
︙ | ︙ |
Changes to testdata/bignum.py.
︙ | ︙ | |||
99 100 101 102 103 104 105 | # carry to the very top of the number. for i in range(1,4200): a, b, p = findprod((1<<i)+1, +1, (i, i*i+1)) print "mul", hexstr(a), hexstr(b), hexstr(p) a, b, p = findprod((1<<i)+1, +1, (i, i+1)) print "mul", hexstr(a), hexstr(b), hexstr(p) | < < < < < < < < < < | 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | # carry to the very top of the number. for i in range(1,4200): a, b, p = findprod((1<<i)+1, +1, (i, i*i+1)) print "mul", hexstr(a), hexstr(b), hexstr(p) a, b, p = findprod((1<<i)+1, +1, (i, i+1)) print "mul", hexstr(a), hexstr(b), hexstr(p) # Simple tests of modpow. for i in range(64, 4097, 63): modulus = sqrt(1<<(2*i-1)) | 1 base = sqrt(3*modulus*modulus) % modulus expt = sqrt(modulus*modulus*2/5) print "pow", hexstr(base), hexstr(expt), hexstr(modulus), hexstr(pow(base, expt, modulus)) if i <= 1024: # Test even moduli, which can't be done by Montgomery. modulus = modulus - 1 print "pow", hexstr(base), hexstr(expt), hexstr(modulus), hexstr(pow(base, expt, modulus)) |
Changes to timing.c.
1 2 3 4 5 6 7 8 9 | /* * timing.c * * This module tracks any timers set up by schedule_timer(). It * keeps all the currently active timers in a list; it informs the * front end of when the next timer is due to go off if that * changes; and, very importantly, it tracks the context pointers * passed to schedule_timer(), so that if a context is freed all * the timers associated with it can be immediately annulled. | < < < < < < < < < < < < < < < < < < | < | | | | > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | /* * timing.c * * This module tracks any timers set up by schedule_timer(). It * keeps all the currently active timers in a list; it informs the * front end of when the next timer is due to go off if that * changes; and, very importantly, it tracks the context pointers * passed to schedule_timer(), so that if a context is freed all * the timers associated with it can be immediately annulled. */ #include <assert.h> #include <stdio.h> #include "putty.h" #include "tree234.h" struct timer { timer_fn_t fn; void *ctx; long now; }; static tree234 *timers = NULL; static tree234 *timer_contexts = NULL; static long now = 0L; static int compare_timers(void *av, void *bv) { struct timer *a = (struct timer *)av; struct timer *b = (struct timer *)bv; long at = a->now - now; long bt = b->now - now; if (at < bt) return -1; else if (at > bt) return +1; /* * Failing that, compare on the other two fields, just so that * we don't get unwanted equality. */ #ifdef __LCC__ /* lcc won't let us compare function pointers. Legal, but annoying. */ { int c = memcmp(&a->fn, &b->fn, sizeof(a->fn)); if (c < 0) return -1; else if (c > 0) return +1; } #else if (a->fn < b->fn) return -1; else if (a->fn > b->fn) return +1; #endif |
︙ | ︙ | |||
102 103 104 105 106 107 108 | if (!timers) { timers = newtree234(compare_timers); timer_contexts = newtree234(compare_timer_contexts); now = GETTICKCOUNT(); } } | | | < | < | 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | if (!timers) { timers = newtree234(compare_timers); timer_contexts = newtree234(compare_timer_contexts); now = GETTICKCOUNT(); } } long schedule_timer(int ticks, timer_fn_t fn, void *ctx) { long when; struct timer *t, *first; init_timers(); when = ticks + GETTICKCOUNT(); /* * Just in case our various defences against timing skew fail * us: if we try to schedule a timer that's already in the * past, we instead schedule it for the immediate future. */ if (when - now <= 0) when = now + 1; t = snew(struct timer); t->fn = fn; t->ctx = ctx; t->now = when; if (t != add234(timers, t)) { sfree(t); /* identical timer already exists */ } else { add234(timer_contexts, t->ctx);/* don't care if this fails */ } |
︙ | ︙ | |||
149 150 151 152 153 154 155 | } /* * Call to run any timers whose time has reached the present. * Returns the time (in ticks) expected until the next timer after * that triggers. */ | | > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < | | 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 | } /* * Call to run any timers whose time has reached the present. * Returns the time (in ticks) expected until the next timer after * that triggers. */ int run_timers(long anow, long *next) { struct timer *first; init_timers(); #ifdef TIMING_SYNC /* * In this ifdef I put some code which deals with the * possibility that `anow' disagrees with GETTICKCOUNT by a * significant margin. Our strategy for dealing with it differs * depending on platform, because on some platforms * GETTICKCOUNT is more likely to be right whereas on others * `anow' is a better gold standard. */ { long tnow = GETTICKCOUNT(); if (tnow + TICKSPERSEC/50 - anow < 0 || anow + TICKSPERSEC/50 - tnow < 0 ) { #if defined TIMING_SYNC_ANOW /* * If anow is accurate and the tick count is wrong, * this is likely to be because the tick count is * derived from the system clock which has changed (as * can occur on Unix). Therefore, we resolve this by * inventing an offset which is used to adjust all * future output from GETTICKCOUNT. * * A platform which defines TIMING_SYNC_ANOW is * expected to have also defined this offset variable * in (its platform-specific adjunct to) putty.h. * Therefore we can simply reference it here and assume * that it will exist. */ tickcount_offset += anow - tnow; #elif defined TIMING_SYNC_TICKCOUNT /* * If the tick count is more likely to be accurate, we * simply use that as our time value, which may mean we * run no timers in this call (because we got called * early), or alternatively it may mean we run lots of * timers in a hurry because we were called late. */ anow = tnow; #else /* * Any platform which defines TIMING_SYNC must also define one of the two * auxiliary symbols TIMING_SYNC_ANOW and TIMING_SYNC_TICKCOUNT, to * indicate which measurement to trust when the two disagree. */ #error TIMING_SYNC definition incomplete #endif } } #endif now = anow; while (1) { first = (struct timer *)index234(timers, 0); if (!first) return FALSE; /* no timers remaining */ if (find234(timer_contexts, first->ctx, NULL) == NULL) { /* * This timer belongs to a context that has been * expired. Delete it without running. */ delpos234(timers, 0); sfree(first); } else if (first->now - now <= 0) { /* * This timer is active and has reached its running * time. Run it. */ delpos234(timers, 0); first->fn(first->ctx, first->now); sfree(first); |
︙ | ︙ |
Changes to tree234.c.
︙ | ︙ | |||
25 26 27 28 29 30 31 32 33 34 35 | * SOFTWARE. */ #include <stdio.h> #include <stdlib.h> #include <assert.h> #include "tree234.h" #ifdef TEST #define LOG(x) (printf x) | > < < < < < < < | 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | * SOFTWARE. */ #include <stdio.h> #include <stdlib.h> #include <assert.h> #include "puttymem.h" #include "tree234.h" #ifdef TEST #define LOG(x) (printf x) #else #define LOG(x) #endif typedef struct node234_Tag node234; struct tree234_Tag { node234 *root; |
︙ | ︙ | |||
222 223 224 225 226 227 228 | LOG((" at %p: %p/%d [%p] %p/%d [%p] %p/%d [%p] %p/%d\n", n, n->kids[0], n->counts[0], n->elems[0], n->kids[1], n->counts[1], n->elems[1], n->kids[2], n->counts[2], n->elems[2], n->kids[3], n->counts[3])); LOG((" need to insert %p/%d [%p] %p/%d at position %d\n", | | | 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 | LOG((" at %p: %p/%d [%p] %p/%d [%p] %p/%d [%p] %p/%d\n", n, n->kids[0], n->counts[0], n->elems[0], n->kids[1], n->counts[1], n->elems[1], n->kids[2], n->counts[2], n->elems[2], n->kids[3], n->counts[3])); LOG((" need to insert %p/%d [%p] %p/%d at position %d\n", left, lcount, e, right, rcount, np - n->kids)); if (n->elems[1] == NULL) { /* * Insert in a 2-node; simple. */ if (np == &n->kids[0]) { LOG((" inserting on left of 2-node\n")); n->kids[2] = n->kids[1]; |
︙ | ︙ | |||
1471 1472 1473 1474 1475 1476 1477 | printf("adding string %s at index %d\n", strings[j], k); addpostest(strings[j], k); } while (count234(tree) > 0) { printf("cleanup: tree size %d\n", count234(tree)); j = randomnumber(&seed); j %= count234(tree); | | < | 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 | printf("adding string %s at index %d\n", strings[j], k); addpostest(strings[j], k); } while (count234(tree) > 0) { printf("cleanup: tree size %d\n", count234(tree)); j = randomnumber(&seed); j %= count234(tree); printf("deleting string %s from index %d\n", array[j], j); delpostest(j); } return 0; } #endif |
Changes to unix/configure.ac.
1 2 3 4 5 6 | # To compile this into a configure script, you need: # * Autoconf 2.50 or newer # * Gtk (for $prefix/share/aclocal/gtk.m4) # * Automake (for aclocal) # If you've got them, running "autoreconf" should work. | < < < | < | < | | < < | < < < < < < < < < < < < < < < < < < < > > | < < < < < < < < < < < < < < < | < | < < < < < | < < | | | < < < < < < < < < | | < < < < < < > | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | # To compile this into a configure script, you need: # * Autoconf 2.50 or newer # * Gtk (for $prefix/share/aclocal/gtk.m4) # * Automake (for aclocal) # If you've got them, running "autoreconf" should work. AC_INIT AC_CONFIG_FILES([Makefile]) AC_CONFIG_HEADERS([uxconfig.h:uxconfig.in]) AC_PROG_INSTALL AC_PROG_CC if test "X$GCC" = Xyes; then PUTTYCFLAGS="-Wall -Werror" else PUTTYCFLAGS="" fi AC_SUBST(PUTTYCFLAGS) AC_ARG_WITH([gssapi], [AS_HELP_STRING([--without-gssapi], [disable GSSAPI support])], [], [with_gssapi=yes]) WITH_GSSAPI= AS_IF([test "x$with_gssapi" != xno], [AC_DEFINE([WITH_GSSAPI], [1], [Define if building with GSSAPI support.])]) AC_CHECK_HEADERS([utmpx.h sys/select.h],,,[ #include <sys/types.h> #include <utmp.h>]) # Look for both GTK 1 and GTK 2. AM_PATH_GTK([1.2.0], [gtk=1], [gtk=none]) AM_PATH_GTK_2_0([2.0.0], [gtk=2], []) if test "$gtk" = "none"; then all_targets="all-cli" else all_targets="all-cli all-gtk" fi if test "$gtk" = "2"; then ac_save_CFLAGS="$CFLAGS" ac_save_LIBS="$LIBS" CFLAGS="$CFLAGS $GTK_CFLAGS" LIBS="$GTK_LIBS $LIBS" AC_CHECK_FUNCS([pango_font_family_is_monospace pango_font_map_list_families]) CFLAGS="$ac_save_CFLAGS" LIBS="$ac_save_LIBS" fi AC_SUBST([all_targets]) AC_SEARCH_LIBS([socket], [xnet]) AS_IF([test "x$with_gssapi" != xno], [AC_SEARCH_LIBS( [dlopen],[dl], [], [AC_DEFINE([NO_LIBDL], [1], [Define if we could not find libdl.]) AC_CHECK_HEADERS([gssapi/gssapi.h]) AC_SEARCH_LIBS( [gss_init_sec_context],[gssapi gssapi_krb5 gss], [], [AC_DEFINE([NO_GSSAPI_LIB], [1], [Define if we could not find a gssapi library])])])]) AC_CHECK_LIB(X11, XOpenDisplay) AC_CHECK_FUNCS([getaddrinfo ptsname setresuid strsignal updwtmpx]) AC_OUTPUT AH_BOTTOM([ /* Convert autoconf definitions to ones that PuTTY wants. */ #ifndef HAVE_GETADDRINFO # define NO_IPV6 #endif #ifndef HAVE_SETRESUID |
︙ | ︙ |
Changes to unix/gtkcfg.c.
︙ | ︙ | |||
38 39 40 41 42 43 44 | * GTK makes it rather easier to put the scrollbar on the left * than Windows does! */ s = ctrl_getset(b, "Window", "scrollback", "Control the scrollback in the window"); ctrl_checkbox(s, "Scrollbar on left", 'l', HELPCTX(no_help), | | | | | 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | * GTK makes it rather easier to put the scrollbar on the left * than Windows does! */ s = ctrl_getset(b, "Window", "scrollback", "Control the scrollback in the window"); ctrl_checkbox(s, "Scrollbar on left", 'l', HELPCTX(no_help), dlg_stdcheckbox_handler, I(offsetof(Config,scrollbar_on_left))); /* * Really this wants to go just after `Display scrollbar'. See * if we can find that control, and do some shuffling. */ for (i = 0; i < s->ncontrols; i++) { c = s->ctrls[i]; if (c->generic.type == CTRL_CHECKBOX && c->generic.context.i == offsetof(Config,scrollbar)) { /* * Control i is the scrollbar checkbox. * Control s->ncontrols-1 is the scrollbar-on-left one. */ if (i < s->ncontrols-2) { c = s->ctrls[s->ncontrols-1]; memmove(s->ctrls+i+2, s->ctrls+i+1, |
︙ | ︙ | |||
85 86 87 88 89 90 91 | } } ctrl_settitle(b, "Window/Fonts", "Options controlling font usage"); s = ctrl_getset(b, "Window/Fonts", "font", "Fonts for displaying non-bold text"); ctrl_fontsel(s, "Font used for ordinary text", 'f', HELPCTX(no_help), | | | | | | | | | | | | | > | 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | } } ctrl_settitle(b, "Window/Fonts", "Options controlling font usage"); s = ctrl_getset(b, "Window/Fonts", "font", "Fonts for displaying non-bold text"); ctrl_fontsel(s, "Font used for ordinary text", 'f', HELPCTX(no_help), dlg_stdfontsel_handler, I(offsetof(Config,font))); ctrl_fontsel(s, "Font used for wide (CJK) text", 'w', HELPCTX(no_help), dlg_stdfontsel_handler, I(offsetof(Config,widefont))); s = ctrl_getset(b, "Window/Fonts", "fontbold", "Fonts for displaying bolded text"); ctrl_fontsel(s, "Font used for bolded text", 'b', HELPCTX(no_help), dlg_stdfontsel_handler, I(offsetof(Config,boldfont))); ctrl_fontsel(s, "Font used for bold wide text", 'i', HELPCTX(no_help), dlg_stdfontsel_handler, I(offsetof(Config,wideboldfont))); ctrl_checkbox(s, "Use shadow bold instead of bold fonts", 'u', HELPCTX(no_help), dlg_stdcheckbox_handler, I(offsetof(Config,shadowbold))); ctrl_text(s, "(Note that bold fonts or shadow bolding are only" " used if you have not requested bolding to be done by" " changing the text colour.)", HELPCTX(no_help)); ctrl_editbox(s, "Horizontal offset for shadow bold:", 'z', 20, HELPCTX(no_help), dlg_stdeditbox_handler, I(offsetof(Config,shadowboldoffset)), I(-1)); /* * Markus Kuhn feels, not totally unreasonably, that it's good * for all applications to shift into UTF-8 mode if they notice * that they've been started with a LANG setting dictating it, * so that people don't have to keep remembering a separate * UTF-8 option for every application they use. Therefore, * here's an override option in the Translation panel. */ s = ctrl_getset(b, "Window/Translation", "trans", "Character set translation on received data"); ctrl_checkbox(s, "Override with UTF-8 if locale says so", 'l', HELPCTX(translation_utf8_override), dlg_stdcheckbox_handler, I(offsetof(Config,utf8_override))); if (!midsession) { /* * Allow the user to specify the window class as part of the saved * configuration, so that they can have their window manager treat * different kinds of PuTTY and pterm differently if they want to. */ s = ctrl_getset(b, "Window/Behaviour", "x11", "X Window System settings"); ctrl_editbox(s, "Window class name:", 'z', 50, HELPCTX(no_help), dlg_stdeditbox_handler, I(offsetof(Config,winclass)), I(sizeof(((Config *)0)->winclass))); } } |
Changes to unix/gtkcols.h.
1 2 3 4 5 6 7 8 9 10 | /* * gtkcols.h - header file for a columns-based widget container * capable of supporting the PuTTY portable dialog box layout * mechanism. */ #ifndef COLUMNS_H #define COLUMNS_H #include <gdk/gdk.h> | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | /* * gtkcols.h - header file for a columns-based widget container * capable of supporting the PuTTY portable dialog box layout * mechanism. */ #ifndef COLUMNS_H #define COLUMNS_H #include <gdk/gdk.h> #include <gtk/gtkcontainer.h> #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #define TYPE_COLUMNS (columns_get_type()) #define COLUMNS(obj) (GTK_CHECK_CAST((obj), TYPE_COLUMNS, Columns)) |
︙ | ︙ |
Changes to unix/gtkdlg.c.
︙ | ︙ | |||
326 327 328 329 330 331 332 | * operations: first delete the previous text leaving the empty * string, then insert the new text. This causes two calls to * the "changed" signal. * * The first call to "changed", if allowed to proceed normally, * will cause an EVENT_VALCHANGE event on the edit box, causing * a call to dlg_editbox_get() which will read the empty string | | | | | > | > | > > | | > > > | > > > | 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 | * operations: first delete the previous text leaving the empty * string, then insert the new text. This causes two calls to * the "changed" signal. * * The first call to "changed", if allowed to proceed normally, * will cause an EVENT_VALCHANGE event on the edit box, causing * a call to dlg_editbox_get() which will read the empty string * out of the GtkEntry - and promptly write it straight into * the Config structure, which is precisely where our `text' * pointer is probably pointing, so the second editing * operation will insert that instead of the string we * originally asked for. * * Hence, we must take our own copy of the text before we do * this. */ tmpstring = dupstr(text); gtk_entry_set_text(GTK_ENTRY(entry), tmpstring); sfree(tmpstring); } void dlg_editbox_get(union control *ctrl, void *dlg, char *buffer, int length) { struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc = dlg_find_byctrl(dp, ctrl); assert(uc->ctrl->generic.type == CTRL_EDITBOX); #if GTK_CHECK_VERSION(2,4,0) if (uc->combo) { #if GTK_CHECK_VERSION(2,6,0) strncpy(buffer, gtk_combo_box_get_active_text(GTK_COMBO_BOX(uc->combo)), length); #else strncpy(buffer, gtk_entry_get_text (GTK_ENTRY(gtk_bin_get_child(GTK_BIN(uc->combo)))), length); #endif buffer[length-1] = '\0'; return; } #endif if (uc->entry) { strncpy(buffer, gtk_entry_get_text(GTK_ENTRY(uc->entry)), length); buffer[length-1] = '\0'; return; } assert(!"We shouldn't get here"); } #if !GTK_CHECK_VERSION(2,4,0) static void container_remove_and_destroy(GtkWidget *w, gpointer data) |
︙ | ︙ | |||
902 903 904 905 906 907 908 | break; default: assert(!"This shouldn't happen"); break; } } | | < < < | < | | > > | < < < | < | | > > | 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 | break; default: assert(!"This shouldn't happen"); break; } } void dlg_filesel_set(union control *ctrl, void *dlg, Filename fn) { struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc = dlg_find_byctrl(dp, ctrl); assert(uc->ctrl->generic.type == CTRL_FILESELECT); assert(uc->entry != NULL); gtk_entry_set_text(GTK_ENTRY(uc->entry), fn.path); } void dlg_filesel_get(union control *ctrl, void *dlg, Filename *fn) { struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc = dlg_find_byctrl(dp, ctrl); assert(uc->ctrl->generic.type == CTRL_FILESELECT); assert(uc->entry != NULL); strncpy(fn->path, gtk_entry_get_text(GTK_ENTRY(uc->entry)), lenof(fn->path)); fn->path[lenof(fn->path)-1] = '\0'; } void dlg_fontsel_set(union control *ctrl, void *dlg, FontSpec fs) { struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc = dlg_find_byctrl(dp, ctrl); assert(uc->ctrl->generic.type == CTRL_FONTSELECT); assert(uc->entry != NULL); gtk_entry_set_text(GTK_ENTRY(uc->entry), fs.name); } void dlg_fontsel_get(union control *ctrl, void *dlg, FontSpec *fs) { struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc = dlg_find_byctrl(dp, ctrl); assert(uc->ctrl->generic.type == CTRL_FONTSELECT); assert(uc->entry != NULL); strncpy(fs->name, gtk_entry_get_text(GTK_ENTRY(uc->entry)), lenof(fs->name)); fs->name[lenof(fs->name)-1] = '\0'; } /* * Bracketing a large set of updates in these two functions will * cause the front end (if possible) to delay updating the screen * until it's all complete, thus avoiding flicker. */ |
︙ | ︙ | |||
2816 2817 2818 2819 2820 2821 2822 | gtk_box_pack_end(GTK_BOX(dlg->vbox), w, FALSE, TRUE, 0); gtk_widget_show(w); gtk_widget_hide(dlg->action_area); gtk_dialog_set_has_separator(dlg, FALSE); #endif } | | | | 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 | gtk_box_pack_end(GTK_BOX(dlg->vbox), w, FALSE, TRUE, 0); gtk_widget_show(w); gtk_widget_hide(dlg->action_area); gtk_dialog_set_has_separator(dlg, FALSE); #endif } int do_config_box(const char *title, Config *cfg, int midsession, int protcfginfo) { GtkWidget *window, *hbox, *vbox, *cols, *label, *tree, *treescroll, *panels, *panelvbox; int index, level; struct controlbox *ctrlbox; char *path; #if GTK_CHECK_VERSION(2,0,0) GtkTreeStore *treestore; GtkCellRenderer *treerenderer; GtkTreeViewColumn *treecolumn; GtkTreeSelection *treeselection; |
︙ | ︙ | |||
2849 2850 2851 2852 2853 2854 2855 | for (index = 0; index < lenof(scs.sc); index++) { scs.sc[index].action = SHORTCUT_EMPTY; } window = gtk_dialog_new(); ctrlbox = ctrl_new_box(); | < | | | 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 | for (index = 0; index < lenof(scs.sc); index++) { scs.sc[index].action = SHORTCUT_EMPTY; } window = gtk_dialog_new(); ctrlbox = ctrl_new_box(); setup_config_box(ctrlbox, midsession, cfg->protocol, protcfginfo); unix_setup_config_box(ctrlbox, midsession, cfg->protocol); gtk_setup_config_box(ctrlbox, midsession, window); gtk_window_set_title(GTK_WINDOW(window), title); hbox = gtk_hbox_new(FALSE, 4); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(window)->vbox), hbox, TRUE, TRUE, 0); gtk_container_set_border_width(GTK_CONTAINER(hbox), 10); gtk_widget_show(hbox); |
︙ | ︙ | |||
3086 3087 3088 3089 3090 3091 3092 | gtk_signal_connect(GTK_OBJECT(selparams[index].treeitem), "select", GTK_SIGNAL_FUNC(treeitem_sel), &selparams[index]); dp.treeitems[index] = selparams[index].treeitem; } #endif | | | 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 | gtk_signal_connect(GTK_OBJECT(selparams[index].treeitem), "select", GTK_SIGNAL_FUNC(treeitem_sel), &selparams[index]); dp.treeitems[index] = selparams[index].treeitem; } #endif dp.data = cfg; dlg_refresh(NULL, &dp); dp.shortcuts = &selparams[0].shortcuts; #if !GTK_CHECK_VERSION(2,0,0) dp.currtreeitem = dp.treeitems[0]; #endif dp.lastfocus = NULL; |
︙ | ︙ | |||
3258 3259 3260 3261 3262 3263 3264 | dlg_cleanup(&dp); ctrl_free_box(ctrlbox); return dp.retval; } | | | 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 | dlg_cleanup(&dp); ctrl_free_box(ctrlbox); return dp.retval; } static int string_width(char *text) { GtkWidget *label = gtk_label_new(text); GtkRequisition req; gtk_widget_size_request(label, &req); gtk_object_sink(GTK_OBJECT(label)); return req.width; } |
︙ | ︙ | |||
3385 3386 3387 3388 3389 3390 3391 | void fatal_message_box(void *window, char *msg) { messagebox(window, "PuTTY Fatal Error", msg, string_width("REASONABLY LONG LINE OF TEXT FOR BASIC SANITY"), "OK", 'o', 1, 1, NULL); } | < < < < < < < < < < < < < < < < < < | | 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 | void fatal_message_box(void *window, char *msg) { messagebox(window, "PuTTY Fatal Error", msg, string_width("REASONABLY LONG LINE OF TEXT FOR BASIC SANITY"), "OK", 'o', 1, 1, NULL); } void fatalbox(char *p, ...) { va_list ap; char *msg; va_start(ap, p); msg = dupvprintf(p, ap); va_end(ap); fatal_message_box(NULL, msg); sfree(msg); cleanup_exit(1); } static GtkWidget *aboutbox = NULL; static void about_close_clicked(GtkButton *button, gpointer data) { gtk_widget_destroy(aboutbox); aboutbox = NULL; } static void licence_clicked(GtkButton *button, gpointer data) { char *title; char *licence = "Copyright 1997-2011 Simon Tatham.\n\n" "Portions copyright Robert de Bath, Joris van Rantwijk, Delian " "Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas " "Barry, Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, " "Markus Kuhn, Colin Watson, and CORE SDI S.A.\n\n" "Permission is hereby granted, free of charge, to any person " |
︙ | ︙ | |||
3509 3510 3511 3512 3513 3514 3515 | gtk_widget_show(w); w = gtk_label_new(ver); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(aboutbox)->vbox), w, FALSE, FALSE, 5); gtk_widget_show(w); | | | 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 | gtk_widget_show(w); w = gtk_label_new(ver); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(aboutbox)->vbox), w, FALSE, FALSE, 5); gtk_widget_show(w); w = gtk_label_new("Copyright 1997-2011 Simon Tatham. All rights reserved"); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(aboutbox)->vbox), w, FALSE, FALSE, 5); gtk_widget_show(w); set_transient_window_pos(GTK_WIDGET(window), aboutbox); gtk_window_set_transient_for(GTK_WINDOW(aboutbox), GTK_WINDOW(window)); |
︙ | ︙ | |||
3761 3762 3763 3764 3765 3766 3767 | strcat(es->events[es->nevents], string); if (es->window) { dlg_listbox_add(es->listctrl, &es->dp, es->events[es->nevents]); } es->nevents++; } | | | | 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 | strcat(es->events[es->nevents], string); if (es->window) { dlg_listbox_add(es->listctrl, &es->dp, es->events[es->nevents]); } es->nevents++; } int askappend(void *frontend, Filename filename, void (*callback)(void *ctx, int result), void *ctx) { static const char msgtemplate[] = "The session log file \"%.*s\" already exists. " "You can overwrite it with a new session log, " "append your session log to the end of it, " "or disable session logging for this session."; char *message; char *mbtitle; int mbret; message = dupprintf(msgtemplate, FILENAME_MAX, filename.path); mbtitle = dupprintf("%s Log to File", appname); mbret = messagebox(get_window(frontend), mbtitle, message, string_width("LINE OF TEXT SUITABLE FOR THE" " ASKAPPEND WIDTH"), "Overwrite", 'o', 1, 2, "Append", 'a', 0, 1, |
︙ | ︙ |
Changes to unix/gtkfont.c.
︙ | ︙ | |||
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | /* * Future work: * * - it would be nice to have a display of the current font name, * and in particular whether it's client- or server-side, * during the progress of the font selector. * * - it would be nice if we could move the processing of * underline and VT100 double width into this module, so that * instead of using the ghastly pixmap-stretching technique * everywhere we could tell the Pango backend to scale its * fonts to double size properly and at full resolution. * However, this requires me to learn how to make Pango stretch * text to an arbitrary aspect ratio (for double-width only * text, which perversely is harder than DW+DH), and right now * I haven't the energy. */ | > > > > > > < < < < < | 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | /* * Future work: * * - it would be nice to have a display of the current font name, * and in particular whether it's client- or server-side, * during the progress of the font selector. * * - all the GDK font functions used in the x11font subclass are * deprecated, so one day they may go away. When this happens - * or before, if I'm feeling proactive - it oughtn't to be too * difficult in principle to convert the whole thing to use * actual Xlib font calls. * * - it would be nice if we could move the processing of * underline and VT100 double width into this module, so that * instead of using the ghastly pixmap-stretching technique * everywhere we could tell the Pango backend to scale its * fonts to double size properly and at full resolution. * However, this requires me to learn how to make Pango stretch * text to an arbitrary aspect ratio (for double-width only * text, which perversely is harder than DW+DH), and right now * I haven't the energy. */ /* * Ad-hoc vtable mechanism to allow font structures to be * polymorphic. * * Any instance of `unifont' used in the vtable functions will * actually be the first element of a larger structure containing * data specific to the subtype. This is permitted by the ISO C |
︙ | ︙ | |||
72 73 74 75 76 77 78 | struct unifont_vtable { /* * `Methods' of the `class'. */ unifont *(*create)(GtkWidget *widget, const char *name, int wide, int bold, int shadowoffset, int shadowalways); | < < < | | < | | 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | struct unifont_vtable { /* * `Methods' of the `class'. */ unifont *(*create)(GtkWidget *widget, const char *name, int wide, int bold, int shadowoffset, int shadowalways); void (*destroy)(unifont *font); void (*draw_text)(GdkDrawable *target, GdkGC *gc, unifont *font, int x, int y, const char *string, int len, int wide, int bold, int cellwidth); void (*enum_fonts)(GtkWidget *widget, fontsel_add_entry callback, void *callback_ctx); char *(*canonify_fontname)(GtkWidget *widget, const char *name, int *size, int *flags, int resolve_aliases); char *(*scale_fontname)(GtkWidget *widget, const char *name, int size); /* * `Static data members' of the `class'. */ const char *prefix; }; /* ---------------------------------------------------------------------- * GDK-based X11 font implementation. */ static void x11font_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font, int x, int y, const char *string, int len, int wide, int bold, int cellwidth); static unifont *x11font_create(GtkWidget *widget, const char *name, int wide, int bold, int shadowoffset, int shadowalways); static void x11font_destroy(unifont *font); static void x11font_enum_fonts(GtkWidget *widget, fontsel_add_entry callback, void *callback_ctx); |
︙ | ︙ | |||
123 124 125 126 127 128 129 | * * The parallel array `allocated' indicates whether we've * tried to fetch a subfont already (thus distinguishing NULL * because we haven't tried yet from NULL because we tried and * failed, so that we don't keep trying and failing * subsequently). */ | | | < < < < < < < < < < | > | | 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | * * The parallel array `allocated' indicates whether we've * tried to fetch a subfont already (thus distinguishing NULL * because we haven't tried yet from NULL because we tried and * failed, so that we don't keep trying and failing * subsequently). */ GdkFont *fonts[4]; int allocated[4]; /* * `sixteen_bit' is true iff the font object is indexed by * values larger than a byte. That is, this flag tells us * whether we use gdk_draw_text_wc() or gdk_draw_text(). */ int sixteen_bit; /* * `variable' is true iff the font is non-fixed-pitch. This * enables some code which takes greater care over character * positioning during text drawing. */ int variable; /* * Data passed in to unifont_create(). */ int wide, bold, shadowoffset, shadowalways; }; static const struct unifont_vtable x11font_vtable = { x11font_create, x11font_destroy, x11font_draw_text, x11font_enum_fonts, x11font_canonify_fontname, x11font_scale_fontname, "server", }; char *x11_guess_derived_font_name(GdkFont *font, int bold, int wide) { XFontStruct *xfs = GDK_FONT_XFONT(font); Display *disp = GDK_FONT_XDISPLAY(font); Atom fontprop = XInternAtom(disp, "FONT", False); unsigned long ret; if (XGetFontProperty(xfs, fontprop, &ret)) { char *name = XGetAtomName(disp, (Atom)ret); if (name && name[0] == '-') { char *strings[13]; char *dupname, *extrafree = NULL, *ret; |
︙ | ︙ | |||
187 188 189 190 191 192 193 | if (*p == '-') { *p = '\0'; strings[nstr++] = p+1; } p++; } | | < < | 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 | if (*p == '-') { *p = '\0'; strings[nstr++] = p+1; } p++; } if (nstr < lenof(strings)) return NULL; /* XLFD was malformed */ if (bold) strings[2] = "bold"; if (wide) { /* 4 is `wideness', which obviously may have changed. */ /* 5 is additional style, which may be e.g. `ja' or `ko'. */ |
︙ | ︙ | |||
216 217 218 219 220 221 222 | return ret; } } return NULL; } | | < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < > | | | > > > | 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 | return ret; } } return NULL; } static int x11_font_width(GdkFont *font, int sixteen_bit) { if (sixteen_bit) { XChar2b space; space.byte1 = 0; space.byte2 = '0'; return gdk_text_width(font, (const gchar *)&space, 2); } else { return gdk_char_width(font, '0'); } } static unifont *x11font_create(GtkWidget *widget, const char *name, int wide, int bold, int shadowoffset, int shadowalways) { struct x11font *xfont; GdkFont *font; XFontStruct *xfs; Display *disp; Atom charset_registry, charset_encoding, spacing; unsigned long registry_ret, encoding_ret, spacing_ret; int pubcs, realcs, sixteen_bit, variable; int i; font = gdk_font_load(name); if (!font) return NULL; xfs = GDK_FONT_XFONT(font); disp = GDK_FONT_XDISPLAY(font); charset_registry = XInternAtom(disp, "CHARSET_REGISTRY", False); charset_encoding = XInternAtom(disp, "CHARSET_ENCODING", False); pubcs = realcs = CS_NONE; sixteen_bit = FALSE; variable = TRUE; |
︙ | ︙ | |||
334 335 336 337 338 339 340 | */ if (!strcasecmp(encoding, "iso10646-1")) { sixteen_bit = TRUE; pubcs = realcs = CS_UTF8; } /* | | | | | > > > > > > | | | | > > | | | | | | < | | < | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | < | | < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < | | | < < | | | < < | > > | > > > > > > > > > > > > > | | | | | > | | > < < < < < < < > | < | 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 | */ if (!strcasecmp(encoding, "iso10646-1")) { sixteen_bit = TRUE; pubcs = realcs = CS_UTF8; } /* * Hack for X line-drawing characters: if the primary * font is encoded as ISO-8859-1, and has valid glyphs * in the first 32 char positions, it is assumed that * those glyphs are the VT100 line-drawing character * set. * * Actually, we'll hack even harder by only checking * position 0x19 (vertical line, VT100 linedrawing * `x'). Then we can check it easily by seeing if the * ascent and descent differ. */ if (pubcs == CS_ISO8859_1) { int lb, rb, wid, asc, desc; gchar text[2]; text[1] = '\0'; text[0] = '\x12'; gdk_string_extents(font, text, &lb, &rb, &wid, &asc, &desc); if (asc != desc) realcs = CS_ISO8859_1_X11; } sfree(encoding); } } spacing = XInternAtom(disp, "SPACING", False); if (XGetFontProperty(xfs, spacing, &spacing_ret)) { char *spc; spc = XGetAtomName(disp, (Atom)spacing_ret); if (spc && strchr("CcMm", spc[0])) variable = FALSE; } xfont = snew(struct x11font); xfont->u.vt = &x11font_vtable; xfont->u.width = x11_font_width(font, sixteen_bit); xfont->u.ascent = font->ascent; xfont->u.descent = font->descent; xfont->u.height = xfont->u.ascent + xfont->u.descent; xfont->u.public_charset = pubcs; xfont->u.real_charset = realcs; xfont->fonts[0] = font; xfont->allocated[0] = TRUE; xfont->sixteen_bit = sixteen_bit; xfont->variable = variable; xfont->wide = wide; xfont->bold = bold; xfont->shadowoffset = shadowoffset; xfont->shadowalways = shadowalways; for (i = 1; i < lenof(xfont->fonts); i++) { xfont->fonts[i] = NULL; xfont->allocated[i] = FALSE; } return (unifont *)xfont; } static void x11font_destroy(unifont *font) { struct x11font *xfont = (struct x11font *)font; int i; for (i = 0; i < lenof(xfont->fonts); i++) if (xfont->fonts[i]) gdk_font_unref(xfont->fonts[i]); sfree(font); } static void x11_alloc_subfont(struct x11font *xfont, int sfid) { char *derived_name = x11_guess_derived_font_name (xfont->fonts[0], sfid & 1, !!(sfid & 2)); xfont->fonts[sfid] = gdk_font_load(derived_name); /* may be NULL */ xfont->allocated[sfid] = TRUE; sfree(derived_name); } static void x11font_really_draw_text(GdkDrawable *target, GdkFont *font, GdkGC *gc, int x, int y, const gchar *string, int clen, int nchars, int shadowbold, int shadowoffset, int fontvariable, int cellwidth) { int step = clen * nchars, nsteps = 1, centre = FALSE; if (fontvariable) { /* * In a variable-pitch font, we draw one character at a * time, and centre it in the character cell. */ step = clen; nsteps = nchars; centre = TRUE; } while (nsteps-- > 0) { int X = x; if (centre) X += (cellwidth - gdk_text_width(font, string, step)) / 2; gdk_draw_text(target, font, gc, X, y, string, step); if (shadowbold) gdk_draw_text(target, font, gc, X + shadowoffset, y, string, step); x += cellwidth; string += step; } } static void x11font_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font, int x, int y, const char *string, int len, int wide, int bold, int cellwidth) { struct x11font *xfont = (struct x11font *)font; int sfid; int shadowbold = FALSE; int mult = (wide ? 2 : 1); wide -= xfont->wide; bold -= xfont->bold; /* * Decide which subfont we're using, and whether we have to * use shadow bold. */ if (xfont->shadowalways && bold) { shadowbold = TRUE; bold = 0; } sfid = 2 * wide + bold; if (!xfont->allocated[sfid]) x11_alloc_subfont(xfont, sfid); if (bold && !xfont->fonts[sfid]) { bold = 0; shadowbold = TRUE; sfid = 2 * wide + bold; if (!xfont->allocated[sfid]) x11_alloc_subfont(xfont, sfid); } if (!xfont->fonts[sfid]) return; /* we've tried our best, but no luck */ if (xfont->sixteen_bit) { /* * This X font has 16-bit character indices, which means * we expect our string to have been passed in UTF-8. */ XChar2b *xcs; wchar_t *wcs; int nchars, maxchars, i; /* * Convert the input string to wide-character Unicode. */ maxchars = 0; for (i = 0; i < len; i++) if ((unsigned char)string[i] <= 0x7F || (unsigned char)string[i] >= 0xC0) maxchars++; wcs = snewn(maxchars+1, wchar_t); nchars = charset_to_unicode((char **)&string, &len, wcs, maxchars, CS_UTF8, NULL, NULL, 0); assert(nchars <= maxchars); wcs[nchars] = L'\0'; xcs = snewn(nchars, XChar2b); for (i = 0; i < nchars; i++) { xcs[i].byte1 = wcs[i] >> 8; xcs[i].byte2 = wcs[i]; } x11font_really_draw_text(target, xfont->fonts[sfid], gc, x, y, (gchar *)xcs, 2, nchars, shadowbold, xfont->shadowoffset, xfont->variable, cellwidth * mult); sfree(xcs); sfree(wcs); } else { x11font_really_draw_text(target, xfont->fonts[sfid], gc, x, y, string, 1, len, shadowbold, xfont->shadowoffset, xfont->variable, cellwidth * mult); } } static void x11font_enum_fonts(GtkWidget *widget, fontsel_add_entry callback, void *callback_ctx) { char **fontnames; |
︙ | ︙ | |||
664 665 666 667 668 669 670 | /* * Style is a mixture of quite a lot of the fields, * with some strange formatting. */ style = p; p += sprintf(p, "%s", components[2][0] ? components[2] : "regular"); | | | | | | | | | | | | | | | | | | | 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 | /* * Style is a mixture of quite a lot of the fields, * with some strange formatting. */ style = p; p += sprintf(p, "%s", components[2][0] ? components[2] : "regular"); if (!g_strcasecmp(components[3], "i")) p += sprintf(p, " italic"); else if (!g_strcasecmp(components[3], "o")) p += sprintf(p, " oblique"); else if (!g_strcasecmp(components[3], "ri")) p += sprintf(p, " reverse italic"); else if (!g_strcasecmp(components[3], "ro")) p += sprintf(p, " reverse oblique"); else if (!g_strcasecmp(components[3], "ot")) p += sprintf(p, " other-slant"); if (components[4][0] && g_strcasecmp(components[4], "normal")) p += sprintf(p, " %s", components[4]); if (!g_strcasecmp(components[10], "m")) p += sprintf(p, " [M]"); if (!g_strcasecmp(components[10], "c")) p += sprintf(p, " [C]"); if (components[5][0]) p += sprintf(p, " %s", components[5]); /* * Style key is the same stuff as above, but with a * couple of transformations done on it to make it * sort more sensibly. */ p++; stylekey = p; if (!g_strcasecmp(components[2], "medium") || !g_strcasecmp(components[2], "regular") || !g_strcasecmp(components[2], "normal") || !g_strcasecmp(components[2], "book")) weightkey = 0; else if (!g_strncasecmp(components[2], "demi", 4) || !g_strncasecmp(components[2], "semi", 4)) weightkey = 1; else weightkey = 2; if (!g_strcasecmp(components[3], "r")) slantkey = 0; else if (!g_strncasecmp(components[3], "r", 1)) slantkey = 2; else slantkey = 1; if (!g_strcasecmp(components[4], "normal")) setwidthkey = 0; else setwidthkey = 1; p += sprintf(p, "%04d%04d%s%04d%04d%s%04d%04d%s%04d%s%04d%s", weightkey, (int)strlen(components[2]), components[2], |
︙ | ︙ | |||
778 779 780 781 782 783 784 785 | * property, which should give its full XLFD even if what we * originally had was a wildcard. * * However, we must carefully avoid canonifying font * _aliases_, unless specifically asked to, because the font * selector treats them as worthwhile in their own right. */ XFontStruct *xfs; | > | < < | > > > > | < | < | < < < | 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 | * property, which should give its full XLFD even if what we * originally had was a wildcard. * * However, we must carefully avoid canonifying font * _aliases_, unless specifically asked to, because the font * selector treats them as worthwhile in their own right. */ GdkFont *font = gdk_font_load(name); XFontStruct *xfs; Display *disp; Atom fontprop, fontprop2; unsigned long ret; if (!font) return NULL; /* didn't make sense to us, sorry */ gdk_font_ref(font); xfs = GDK_FONT_XFONT(font); disp = GDK_FONT_XDISPLAY(font); fontprop = XInternAtom(disp, "FONT", False); if (XGetFontProperty(xfs, fontprop, &ret)) { char *newname = XGetAtomName(disp, (Atom)ret); if (newname) { unsigned long fsize = 12; fontprop2 = XInternAtom(disp, "PIXEL_SIZE", False); if (XGetFontProperty(xfs, fontprop2, &fsize) && fsize > 0) { *size = fsize; gdk_font_unref(font); if (flags) { if (name[0] == '-' || resolve_aliases) *flags = FONTFLAG_SERVERSIDE; else *flags = FONTFLAG_SERVERALIAS; } return dupstr(name[0] == '-' || resolve_aliases ? newname : name); } } } gdk_font_unref(font); return NULL; /* something went wrong */ } static char *x11font_scale_fontname(GtkWidget *widget, const char *name, int size) { return NULL; /* shan't */ } #if GTK_CHECK_VERSION(2,0,0) /* ---------------------------------------------------------------------- * Pango font implementation (for GTK 2 only). */ #if defined PANGO_PRE_1POINT4 && !defined PANGO_PRE_1POINT6 #define PANGO_PRE_1POINT6 /* make life easier for pre-1.4 folk */ #endif static void pangofont_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font, int x, int y, const char *string, int len, int wide, int bold, int cellwidth); static unifont *pangofont_create(GtkWidget *widget, const char *name, int wide, int bold, int shadowoffset, int shadowalways); static void pangofont_destroy(unifont *font); static void pangofont_enum_fonts(GtkWidget *widget, fontsel_add_entry callback, void *callback_ctx); static char *pangofont_canonify_fontname(GtkWidget *widget, const char *name, int *size, int *flags, int resolve_aliases); static char *pangofont_scale_fontname(GtkWidget *widget, const char *name, |
︙ | ︙ | |||
870 871 872 873 874 875 876 | * Data passed in to unifont_create(). */ int bold, shadowoffset, shadowalways; }; static const struct unifont_vtable pangofont_vtable = { pangofont_create, | < < | 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 | * Data passed in to unifont_create(). */ int bold, shadowoffset, shadowalways; }; static const struct unifont_vtable pangofont_vtable = { pangofont_create, pangofont_destroy, pangofont_draw_text, pangofont_enum_fonts, pangofont_canonify_fontname, pangofont_scale_fontname, "client", }; |
︙ | ︙ | |||
918 919 920 921 922 923 924 | pango_font_map_list_families(map, &families, &nfamilies); #else pango_context_list_families(ctx, &families, &nfamilies); #endif matched = FALSE; for (i = 0; i < nfamilies; i++) { | | | | < < | | > > > > > > > > > > > > > > | 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 | pango_font_map_list_families(map, &families, &nfamilies); #else pango_context_list_families(ctx, &families, &nfamilies); #endif matched = FALSE; for (i = 0; i < nfamilies; i++) { if (!g_strcasecmp(pango_font_family_get_name(families[i]), pango_font_description_get_family(desc))) { matched = TRUE; break; } } g_free(families); return matched; } static unifont *pangofont_create(GtkWidget *widget, const char *name, int wide, int bold, int shadowoffset, int shadowalways) { struct pangofont *pfont; PangoContext *ctx; #ifndef PANGO_PRE_1POINT6 PangoFontMap *map; #endif PangoFontDescription *desc; PangoFontset *fset; PangoFontMetrics *metrics; desc = pango_font_description_from_string(name); if (!desc) return NULL; ctx = gtk_widget_get_pango_context(widget); if (!ctx) { pango_font_description_free(desc); return NULL; } if (!pangofont_check_desc_makes_sense(ctx, desc)) { pango_font_description_free(desc); return NULL; } #ifndef PANGO_PRE_1POINT6 map = pango_context_get_font_map(ctx); if (!map) { pango_font_description_free(desc); return NULL; } fset = pango_font_map_load_fontset(map, ctx, desc, |
︙ | ︙ | |||
973 974 975 976 977 978 979 | pfont = snew(struct pangofont); pfont->u.vt = &pangofont_vtable; pfont->u.width = PANGO_PIXELS(pango_font_metrics_get_approximate_digit_width(metrics)); pfont->u.ascent = PANGO_PIXELS(pango_font_metrics_get_ascent(metrics)); pfont->u.descent = PANGO_PIXELS(pango_font_metrics_get_descent(metrics)); pfont->u.height = pfont->u.ascent + pfont->u.descent; | < > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < | | 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 | pfont = snew(struct pangofont); pfont->u.vt = &pangofont_vtable; pfont->u.width = PANGO_PIXELS(pango_font_metrics_get_approximate_digit_width(metrics)); pfont->u.ascent = PANGO_PIXELS(pango_font_metrics_get_ascent(metrics)); pfont->u.descent = PANGO_PIXELS(pango_font_metrics_get_descent(metrics)); pfont->u.height = pfont->u.ascent + pfont->u.descent; /* The Pango API is hardwired to UTF-8 */ pfont->u.public_charset = CS_UTF8; pfont->u.real_charset = CS_UTF8; pfont->desc = desc; pfont->fset = fset; pfont->widget = widget; pfont->bold = bold; pfont->shadowoffset = shadowoffset; pfont->shadowalways = shadowalways; pango_font_metrics_unref(metrics); return (unifont *)pfont; } static void pangofont_destroy(unifont *font) { struct pangofont *pfont = (struct pangofont *)font; pango_font_description_free(pfont->desc); g_object_unref(pfont->fset); sfree(font); } static void pangofont_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font, int x, int y, const char *string, int len, int wide, int bold, int cellwidth) { struct pangofont *pfont = (struct pangofont *)font; PangoLayout *layout; PangoRectangle rect; int shadowbold = FALSE; if (wide) cellwidth *= 2; y -= pfont->u.ascent; layout = pango_layout_new(gtk_widget_get_pango_context(pfont->widget)); pango_layout_set_font_description(layout, pfont->desc); if (bold > pfont->bold) { if (pfont->shadowalways) shadowbold = TRUE; else { PangoFontDescription *desc2 = pango_font_description_copy_static(pfont->desc); pango_font_description_set_weight(desc2, PANGO_WEIGHT_BOLD); pango_layout_set_font_description(layout, desc2); } } while (len > 0) { int clen, n; /* * We want to display every character from this string in * the centre of its own character cell. In the worst case, * this requires a separate text-drawing call for each * character; but in the common case where the font is |
︙ | ︙ | |||
1115 1116 1117 1118 1119 1120 1121 | */ /* * Start by extracting a single UTF-8 character from the * string. */ clen = 1; | | | | | < < < < < < < | | | | | | | | | | | | | | | | | | | | | | | | | | | < | | < | < < | 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 | */ /* * Start by extracting a single UTF-8 character from the * string. */ clen = 1; while (clen < len && (unsigned char)string[clen] >= 0x80 && (unsigned char)string[clen] < 0xC0) clen++; n = 1; /* * See if that character has the width we expect. */ pango_layout_set_text(layout, string, clen); pango_layout_get_pixel_extents(layout, NULL, &rect); if (rect.width == cellwidth) { /* * Try extracting more characters, for as long as they * stay well-behaved. */ while (clen < len) { int oldclen = clen; clen++; /* skip UTF-8 introducer byte */ while (clen < len && (unsigned char)string[clen] >= 0x80 && (unsigned char)string[clen] < 0xC0) clen++; n++; pango_layout_set_text(layout, string, clen); pango_layout_get_pixel_extents(layout, NULL, &rect); if (rect.width != n * cellwidth) { clen = oldclen; n--; break; } } } pango_layout_set_text(layout, string, clen); pango_layout_get_pixel_extents(layout, NULL, &rect); gdk_draw_layout(target, gc, x + (n*cellwidth - rect.width)/2, y + (pfont->u.height - rect.height)/2, layout); if (shadowbold) gdk_draw_layout(target, gc, x + (n*cellwidth - rect.width)/2 + pfont->shadowoffset, y + (pfont->u.height - rect.height)/2, layout); len -= clen; string += clen; x += n * cellwidth; } g_object_unref(layout); } /* * Dummy size value to be used when converting a * PangoFontDescription of a scalable font to a string for * internal use. |
︙ | ︙ | |||
1436 1437 1438 1439 1440 1441 1442 | /* * Complete list of font-type subclasses. Listed in preference * order for unifont_create(). (That is, in the extremely unlikely * event that the same font name is valid as both a Pango and an * X11 font, it will be interpreted as the former in the absence * of an explicit type-disambiguating prefix.) | < < | 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 | /* * Complete list of font-type subclasses. Listed in preference * order for unifont_create(). (That is, in the extremely unlikely * event that the same font name is valid as both a Pango and an * X11 font, it will be interpreted as the former in the absence * of an explicit type-disambiguating prefix.) */ static const struct unifont_vtable *unifont_types[] = { #if GTK_CHECK_VERSION(2,0,0) &pangofont_vtable, #endif &x11font_vtable, }; |
︙ | ︙ | |||
1514 1515 1516 1517 1518 1519 1520 | void unifont_destroy(unifont *font) { font->vt->destroy(font); } void unifont_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font, | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 | void unifont_destroy(unifont *font) { font->vt->destroy(font); } void unifont_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font, int x, int y, const char *string, int len, int wide, int bold, int cellwidth) { font->vt->draw_text(target, gc, font, x, y, string, len, wide, bold, cellwidth); } #if GTK_CHECK_VERSION(2,0,0) /* ---------------------------------------------------------------------- * Implementation of a unified font selector. Used on GTK 2 only; * for GTK 1 we still use the standard font selector. */ |
︙ | ︙ | |||
1716 1717 1718 1719 1720 1721 1722 | */ if (!a) return 0; /* * Otherwise, ordinary strcasecmp. */ | | | 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 | */ if (!a) return 0; /* * Otherwise, ordinary strcasecmp. */ return g_strcasecmp(a, b); } static int fontinfo_realname_compare(void *av, void *bv) { fontinfo *a = (fontinfo *)av; fontinfo *b = (fontinfo *)bv; int i; |
︙ | ︙ | |||
2015 2016 2017 2018 2019 2020 2021 | * that they find out the problems with using * proportional fonts in terminal windows here than * that they go to the effort of selecting their font * and _then_ realise it was a mistake. */ info->fontclass->draw_text(fs->preview_pixmap, gc, font, 0, font->ascent, | | | | | 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 | * that they find out the problems with using * proportional fonts in terminal windows here than * that they go to the effort of selecting their font * and _then_ realise it was a mistake. */ info->fontclass->draw_text(fs->preview_pixmap, gc, font, 0, font->ascent, "bankrupt jilted showmen quiz convex fogey", 41, FALSE, FALSE, font->width); info->fontclass->draw_text(fs->preview_pixmap, gc, font, 0, font->ascent + font->height, "BANKRUPT JILTED SHOWMEN QUIZ CONVEX FOGEY", 41, FALSE, FALSE, font->width); /* * The ordering of punctuation here is also selected * with some specific aims in mind. I put ` and ' * together because some software (and people) still * use them as matched quotes no matter what Unicode * might say on the matter, so people can quickly * check whether they look silly in a candidate font. * The sequence #_@ is there to let people judge the * suitability of the underscore as an effectively * alphabetic character (since that's how it's often * used in practice, at least by programmers). */ info->fontclass->draw_text(fs->preview_pixmap, gc, font, 0, font->ascent + font->height * 2, "0123456789!?,.:;<>()[]{}\\/`'\"+*-=~#_@|%&^$", 42, FALSE, FALSE, font->width); } gdk_gc_unref(gc); gdk_window_invalidate_rect(fs->preview_area->window, NULL, FALSE); } if (font) info->fontclass->destroy(font); |
︙ | ︙ | |||
2286 2287 2288 2289 2290 2291 2292 | /* * Search in the tree to find the fontinfo structure which * best approximates the size the user last requested. */ below = findrelpos234(fs->fonts_by_selorder, &info2, NULL, REL234_LE, &pos); | < < | | 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 | /* * Search in the tree to find the fontinfo structure which * best approximates the size the user last requested. */ below = findrelpos234(fs->fonts_by_selorder, &info2, NULL, REL234_LE, &pos); above = index234(fs->fonts_by_selorder, pos+1); /* * See if we've found it exactly, which is an easy special * case. If we have, it'll be in `below' and not `above', * because we did a REL234_LE rather than REL234_LT search. */ if (!fontinfo_selorder_compare(&info2, below)) return below; /* * Now we've either found two suitable fonts, one smaller and * one larger, or we're at one or other extreme end of the * scale. Find out which, by NULLing out either of below and * above if it differs from this one in any respect but size |
︙ | ︙ |
Changes to unix/gtkfont.h.
︙ | ︙ | |||
17 18 19 20 21 22 23 24 | * `Non-static data members' of the `class', accessible to * external code. */ /* * public_charset is the charset used when the user asks for * `Use font encoding'. */ | > > > > > > | < < < < < < < < | < < < < < < < < < < < < | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | * `Non-static data members' of the `class', accessible to * external code. */ /* * public_charset is the charset used when the user asks for * `Use font encoding'. * * real_charset is the charset used when translating text into * a form suitable for sending to unifont_draw_text(). * * They can differ. For example, public_charset might be * CS_ISO8859_1 while real_charset is CS_ISO8859_1_X11. */ int public_charset, real_charset; /* * Font dimensions needed by clients. */ int width, height, ascent, descent; } unifont; unifont *unifont_create(GtkWidget *widget, const char *name, int wide, int bold, int shadowoffset, int shadowalways); void unifont_destroy(unifont *font); void unifont_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font, int x, int y, const char *string, int len, int wide, int bold, int cellwidth); /* * Unified font selector dialog. I can't be bothered to do a * proper GTK subclassing today, so this will just be an ordinary * data structure with some useful members. * * (Of course, these aren't the only members; this structure is * contained within a bigger one which holds data visible only to |
︙ | ︙ |
Changes to unix/gtkwin.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | #include <assert.h> #include <stdlib.h> #include <string.h> #include <signal.h> #include <stdio.h> #include <time.h> #include <errno.h> | < < < < < < < > | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | #include <assert.h> #include <stdlib.h> #include <string.h> #include <signal.h> #include <stdio.h> #include <time.h> #include <errno.h> #include <fcntl.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <gtk/gtk.h> #include <gdk/gdkkeysyms.h> #include <gdk/gdkx.h> #include <X11/Xlib.h> #include <X11/Xutil.h> #include <X11/Xatom.h> #define PUTTY_DO_GLOBALS /* actually _define_ globals */ #include "putty.h" #include "terminal.h" #include "gtkfont.h" #define CAT2(x,y) x ## y #define CAT(x,y) CAT2(x,y) #define ASSERT(x) enum {CAT(assertion_,__LINE__) = 1 / (x)} #if GTK_CHECK_VERSION(2,0,0) ASSERT(sizeof(long) <= sizeof(gsize)); #define LONG_TO_GPOINTER(l) GSIZE_TO_POINTER(l) #define GPOINTER_TO_LONG(p) GPOINTER_TO_SIZE(p) #else /* Gtk 1.2 */ ASSERT(sizeof(long) <= sizeof(gpointer)); #define LONG_TO_GPOINTER(l) ((gpointer)(long)(l)) #define GPOINTER_TO_LONG(p) ((long)(p)) #endif /* Colours come in two flavours: configurable, and xterm-extended. */ #define NCFGCOLOURS (lenof(((Config *)0)->colours)) #define NEXTCOLOURS 240 /* 216 colour-cube plus 24 shades of grey */ #define NALLCOLOURS (NCFGCOLOURS + NEXTCOLOURS) GdkAtom compound_text_atom, utf8_string_atom; extern char **pty_argv; /* declared in pty.c */ extern int use_pty_argv; |
︙ | ︙ | |||
71 72 73 74 75 76 77 | GtkWidget *window, *area, *sbar; GtkBox *hbox; GtkAdjustment *sbar_adjust; GtkWidget *menu, *specialsmenu, *specialsitem1, *specialsitem2, *restartitem; GtkWidget *sessionsmenu; GdkPixmap *pixmap; | < < < | > | | | < < < < < < < < < < < < > | | | > | > | | > | > | | 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 | GtkWidget *window, *area, *sbar; GtkBox *hbox; GtkAdjustment *sbar_adjust; GtkWidget *menu, *specialsmenu, *specialsitem1, *specialsitem2, *restartitem; GtkWidget *sessionsmenu; GdkPixmap *pixmap; unifont *fonts[4]; /* normal, bold, wide, widebold */ int xpos, ypos, gotpos, gravity; GdkCursor *rawcursor, *textcursor, *blankcursor, *waitcursor, *currcursor; GdkColor cols[NALLCOLOURS]; GdkColormap *colmap; wchar_t *pastein_data; int direct_to_font; int pastein_data_len; char *pasteout_data, *pasteout_data_ctext, *pasteout_data_utf8; int pasteout_data_len, pasteout_data_ctext_len, pasteout_data_utf8_len; int font_width, font_height; int width, height; int ignore_sbar; int mouseptr_visible; int busy_status; guint term_paste_idle_id; guint term_exit_idle_id; int alt_keycode; int alt_digits; char wintitle[sizeof(((Config *)0)->wintitle)]; char icontitle[sizeof(((Config *)0)->wintitle)]; int master_fd, master_func_id; void *ldisc; Backend *back; void *backhandle; Terminal *term; void *logctx; int exited; struct unicode_data ucsdata; Config cfg; void *eventlogstuff; char *progname, **gtkargvstart; int ngtkargs; guint32 input_event_time; /* Timestamp of the most recent input event. */ int reconfiguring; }; struct draw_ctx { GdkGC *gc; struct gui_data *inst; }; static int send_raw_mouse; static char *app_name = "pterm"; static void start_backend(struct gui_data *inst); char *x_get_default(const char *key) { return XGetDefault(GDK_DISPLAY(), app_name, key); } void connection_fatal(void *frontend, char *p, ...) { struct gui_data *inst = (struct gui_data *)frontend; va_list ap; char *msg; va_start(ap, p); msg = dupvprintf(p, ap); va_end(ap); inst->exited = TRUE; fatal_message_box(inst->window, msg); sfree(msg); if (inst->cfg.close_on_exit == FORCE_ON) cleanup_exit(1); } /* * Default settings that are specific to pterm. */ FontSpec platform_default_fontspec(const char *name) { FontSpec ret; if (!strcmp(name, "Font")) strcpy(ret.name, "server:fixed"); else *ret.name = '\0'; return ret; } Filename platform_default_filename(const char *name) { Filename ret; if (!strcmp(name, "LogFileName")) strcpy(ret.path, "putty.log"); else *ret.path = '\0'; return ret; } char *platform_default_s(const char *name) { if (!strcmp(name, "SerialLine")) return dupstr("/dev/ttyS0"); return NULL; |
︙ | ︙ | |||
211 212 213 214 215 216 217 | int from_backend_untrusted(void *frontend, const char *data, int len) { struct gui_data *inst = (struct gui_data *)frontend; return term_data_untrusted(inst->term, data, len); } | < < < < < | 196 197 198 199 200 201 202 203 204 205 206 207 208 209 | int from_backend_untrusted(void *frontend, const char *data, int len) { struct gui_data *inst = (struct gui_data *)frontend; return term_data_untrusted(inst->term, data, len); } int get_userpass_input(prompts_t *p, unsigned char *in, int inlen) { struct gui_data *inst = (struct gui_data *)p->frontend; int ret; ret = cmdline_get_passwd_input(p, in, inlen); if (ret == -1) ret = term_get_userpass_input(inst->term, p, in, inlen); |
︙ | ︙ | |||
410 411 412 413 414 415 416 | struct gui_data *inst = (struct gui_data *)frontend; return icon ? inst->icontitle : inst->wintitle; } gint delete_window(GtkWidget *widget, GdkEvent *event, gpointer data) { struct gui_data *inst = (struct gui_data *)data; | | | 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 | struct gui_data *inst = (struct gui_data *)frontend; return icon ? inst->icontitle : inst->wintitle; } gint delete_window(GtkWidget *widget, GdkEvent *event, gpointer data) { struct gui_data *inst = (struct gui_data *)data; if (!inst->exited && inst->cfg.warn_on_close) { if (!reallyclose(inst)) return TRUE; } return FALSE; } static void update_mouseptr(struct gui_data *inst) |
︙ | ︙ | |||
441 442 443 444 445 446 447 | default: assert(0); } } static void show_mouseptr(struct gui_data *inst, int show) { | | | | | | | | < < | > | > | < < < < | 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 | default: assert(0); } } static void show_mouseptr(struct gui_data *inst, int show) { if (!inst->cfg.hide_mouseptr) show = 1; inst->mouseptr_visible = show; update_mouseptr(inst); } void draw_backing_rect(struct gui_data *inst) { GdkGC *gc = gdk_gc_new(inst->area->window); gdk_gc_set_foreground(gc, &inst->cols[258]); /* default background */ gdk_draw_rectangle(inst->pixmap, gc, 1, 0, 0, inst->cfg.width * inst->font_width + 2*inst->cfg.window_border, inst->cfg.height * inst->font_height + 2*inst->cfg.window_border); gdk_gc_unref(gc); } gint configure_area(GtkWidget *widget, GdkEventConfigure *event, gpointer data) { struct gui_data *inst = (struct gui_data *)data; int w, h, need_size = 0; /* * See if the terminal size has changed, in which case we must * let the terminal know. */ w = (event->width - 2*inst->cfg.window_border) / inst->font_width; h = (event->height - 2*inst->cfg.window_border) / inst->font_height; if (w != inst->width || h != inst->height) { inst->cfg.width = inst->width = w; inst->cfg.height = inst->height = h; need_size = 1; } if (inst->pixmap) { gdk_pixmap_unref(inst->pixmap); inst->pixmap = NULL; } inst->pixmap = gdk_pixmap_new(widget->window, (inst->cfg.width * inst->font_width + 2*inst->cfg.window_border), (inst->cfg.height * inst->font_height + 2*inst->cfg.window_border), -1); draw_backing_rect(inst); if (need_size && inst->term) { term_size(inst->term, h, w, inst->cfg.savelines); } if (inst->term) term_invalidate(inst->term); return TRUE; } gint expose_area(GtkWidget *widget, GdkEventExpose *event, gpointer data) { struct gui_data *inst = (struct gui_data *)data; |
︙ | ︙ | |||
529 530 531 532 533 534 535 | gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) { struct gui_data *inst = (struct gui_data *)data; char output[256]; wchar_t ucsoutput[2]; int ucsval, start, end, special, output_charset, use_ucsoutput; | < | | | | | | | | | | | | | < < < < < | 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 | gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) { struct gui_data *inst = (struct gui_data *)data; char output[256]; wchar_t ucsoutput[2]; int ucsval, start, end, special, output_charset, use_ucsoutput; /* Remember the timestamp. */ inst->input_event_time = event->time; /* By default, nothing is generated. */ end = start = 0; special = use_ucsoutput = FALSE; output_charset = CS_ISO8859_1; /* * If Alt is being released after typing an Alt+numberpad * sequence, we should generate the code that was typed. * * Note that we only do this if more than one key was actually * pressed - I don't think Alt+NumPad4 should be ^D or that * Alt+NumPad3 should be ^C, for example. There's no serious * inconvenience in having to type a zero before a single-digit * character code. */ if (event->type == GDK_KEY_RELEASE && (event->keyval == GDK_Meta_L || event->keyval == GDK_Alt_L || event->keyval == GDK_Meta_R || event->keyval == GDK_Alt_R) && inst->alt_keycode >= 0 && inst->alt_digits > 1) { #ifdef KEY_DEBUGGING printf("Alt key up, keycode = %d\n", inst->alt_keycode); #endif /* * FIXME: we might usefully try to do something clever here * about interpreting the generated key code in a way that's * appropriate to the line code page. */ output[0] = inst->alt_keycode; end = 1; goto done; } if (event->type == GDK_KEY_PRESS) { #ifdef KEY_DEBUGGING { int i; printf("keypress: keyval = %04x, state = %08x; string =", |
︙ | ︙ | |||
644 645 646 647 648 649 650 | } /* * Shift-PgUp and Shift-PgDn don't even generate keystrokes * at all. */ if (event->keyval == GDK_Page_Up && (event->state & GDK_SHIFT_MASK)) { | | | < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > > > | < | 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 | } /* * Shift-PgUp and Shift-PgDn don't even generate keystrokes * at all. */ if (event->keyval == GDK_Page_Up && (event->state & GDK_SHIFT_MASK)) { term_scroll(inst->term, 0, -inst->cfg.height/2); return TRUE; } if (event->keyval == GDK_Page_Up && (event->state & GDK_CONTROL_MASK)) { term_scroll(inst->term, 0, -1); return TRUE; } if (event->keyval == GDK_Page_Down && (event->state & GDK_SHIFT_MASK)) { term_scroll(inst->term, 0, +inst->cfg.height/2); return TRUE; } if (event->keyval == GDK_Page_Down && (event->state & GDK_CONTROL_MASK)) { term_scroll(inst->term, 0, +1); return TRUE; } /* * Neither does Shift-Ins. */ if (event->keyval == GDK_Insert && (event->state & GDK_SHIFT_MASK)) { request_paste(inst); return TRUE; } special = FALSE; use_ucsoutput = FALSE; /* ALT+things gives leading Escape. */ output[0] = '\033'; #if !GTK_CHECK_VERSION(2,0,0) /* * In vanilla X, and hence also GDK 1.2, the string received * as part of a keyboard event is assumed to be in * ISO-8859-1. (Seems woefully shortsighted in i18n terms, * but it's true: see the man page for XLookupString(3) for * confirmation.) */ output_charset = CS_ISO8859_1; strncpy(output+1, event->string, lenof(output)-1); #else /* * GDK 2.0 arranges to have done some translation for us: in * GDK 2.0, event->string is encoded in the current locale. * * (However, it's also deprecated; we really ought to be * using a GTKIMContext.) * * So we use the standard C library function mbstowcs() to * convert from the current locale into Unicode; from there * we can convert to whatever PuTTY is currently working in. * (In fact I convert straight back to UTF-8 from * wide-character Unicode, for the sake of simplicity: that * way we can still use exactly the same code to manipulate * the string, such as prefixing ESC.) */ output_charset = CS_UTF8; { wchar_t widedata[32], *wp; int wlen; int ulen; wlen = mb_to_wc(DEFAULT_CODEPAGE, 0, event->string, strlen(event->string), widedata, lenof(widedata)-1); |
︙ | ︙ | |||
846 847 848 849 850 851 852 | use_ucsoutput = FALSE; end = 2; } /* We don't let GTK tell us what Backspace is! We know better. */ if (event->keyval == GDK_BackSpace && !(event->state & GDK_SHIFT_MASK)) { | < | < | | 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 | use_ucsoutput = FALSE; end = 2; } /* We don't let GTK tell us what Backspace is! We know better. */ if (event->keyval == GDK_BackSpace && !(event->state & GDK_SHIFT_MASK)) { output[1] = inst->cfg.bksp_is_delete ? '\x7F' : '\x08'; use_ucsoutput = FALSE; end = 2; special = TRUE; } /* For Shift Backspace, do opposite of what is configured. */ if (event->keyval == GDK_BackSpace && (event->state & GDK_SHIFT_MASK)) { output[1] = inst->cfg.bksp_is_delete ? '\x08' : '\x7F'; use_ucsoutput = FALSE; end = 2; special = TRUE; } /* Shift-Tab is ESC [ Z */ if (event->keyval == GDK_ISO_Left_Tab || |
︙ | ︙ | |||
879 880 881 882 883 884 885 | output[1] = '\t'; end = 2; } /* * NetHack keypad mode. */ | | | 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 | output[1] = '\t'; end = 2; } /* * NetHack keypad mode. */ if (inst->cfg.nethack_keypad) { char *keys = NULL; switch (event->keyval) { case GDK_KP_1: case GDK_KP_End: keys = "bB\002"; break; case GDK_KP_2: case GDK_KP_Down: keys = "jJ\012"; break; case GDK_KP_3: case GDK_KP_Page_Down: keys = "nN\016"; break; case GDK_KP_4: case GDK_KP_Left: keys = "hH\010"; break; case GDK_KP_5: case GDK_KP_Begin: keys = "..."; break; |
︙ | ︙ | |||
908 909 910 911 912 913 914 | goto done; } } /* * Application keypad mode. */ | | | | 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 | goto done; } } /* * Application keypad mode. */ if (inst->term->app_keypad_keys && !inst->cfg.no_applic_k) { int xkey = 0; switch (event->keyval) { case GDK_Num_Lock: xkey = 'P'; break; case GDK_KP_Divide: xkey = 'Q'; break; case GDK_KP_Multiply: xkey = 'R'; break; case GDK_KP_Subtract: xkey = 'S'; break; /* * Keypad + is tricky. It covers a space that would * be taken up on the VT100 by _two_ keys; so we * let Shift select between the two. Worse still, * in xterm function key mode we change which two... */ case GDK_KP_Add: if (inst->cfg.funky_type == FUNKY_XTERM) { if (event->state & GDK_SHIFT_MASK) xkey = 'l'; else xkey = 'k'; } else if (event->state & GDK_SHIFT_MASK) xkey = 'm'; else |
︙ | ︙ | |||
969 970 971 972 973 974 975 | * We also deal with the weird ones here. Linux VCs replace F1 * to F5 by ESC [ [ A to ESC [ [ E. rxvt doesn't do _that_, but * does replace Home and End (1~ and 4~) by ESC [ H and ESC O w * respectively. */ { int code = 0; | < | 872 873 874 875 876 877 878 879 880 881 882 883 884 885 | * We also deal with the weird ones here. Linux VCs replace F1 * to F5 by ESC [ [ A to ESC [ [ E. rxvt doesn't do _that_, but * does replace Home and End (1~ and 4~) by ESC [ H and ESC O w * respectively. */ { int code = 0; switch (event->keyval) { case GDK_F1: code = (event->state & GDK_SHIFT_MASK ? 23 : 11); break; case GDK_F2: code = (event->state & GDK_SHIFT_MASK ? 24 : 12); break; |
︙ | ︙ | |||
1053 1054 1055 1056 1057 1058 1059 | code = 5; break; case GDK_Page_Down: case GDK_KP_Page_Down: code = 6; break; } /* Reorder edit keys to physical order */ | | | | 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 | code = 5; break; case GDK_Page_Down: case GDK_KP_Page_Down: code = 6; break; } /* Reorder edit keys to physical order */ if (inst->cfg.funky_type == FUNKY_VT400 && code <= 6) code = "\0\2\1\4\5\3\6"[code]; if (inst->term->vt52_mode && code > 0 && code <= 6) { end = 1 + sprintf(output+1, "\x1B%c", " HLMEIG"[code]); use_ucsoutput = FALSE; goto done; } if (inst->cfg.funky_type == FUNKY_SCO && /* SCO function keys */ code >= 11 && code <= 34) { char codes[] = "MNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@[\\]^_`{"; int index = 0; switch (event->keyval) { case GDK_F1: index = 0; break; case GDK_F2: index = 1; break; case GDK_F3: index = 2; break; |
︙ | ︙ | |||
1086 1087 1088 1089 1090 1091 1092 | } if (event->state & GDK_SHIFT_MASK) index += 12; if (event->state & GDK_CONTROL_MASK) index += 24; end = 1 + sprintf(output+1, "\x1B[%c", codes[index]); use_ucsoutput = FALSE; goto done; } | | | | | | < | 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 | } if (event->state & GDK_SHIFT_MASK) index += 12; if (event->state & GDK_CONTROL_MASK) index += 24; end = 1 + sprintf(output+1, "\x1B[%c", codes[index]); use_ucsoutput = FALSE; goto done; } if (inst->cfg.funky_type == FUNKY_SCO && /* SCO small keypad */ code >= 1 && code <= 6) { char codes[] = "HL.FIG"; if (code == 3) { output[1] = '\x7F'; end = 2; } else { end = 1 + sprintf(output+1, "\x1B[%c", codes[code-1]); } use_ucsoutput = FALSE; goto done; } if ((inst->term->vt52_mode || inst->cfg.funky_type == FUNKY_VT100P) && code >= 11 && code <= 24) { int offt = 0; if (code > 15) offt++; if (code > 21) offt++; if (inst->term->vt52_mode) end = 1 + sprintf(output+1, "\x1B%c", code + 'P' - 11 - offt); else end = 1 + sprintf(output+1, "\x1BO%c", code + 'P' - 11 - offt); use_ucsoutput = FALSE; goto done; } if (inst->cfg.funky_type == FUNKY_LINUX && code >= 11 && code <= 15) { end = 1 + sprintf(output+1, "\x1B[[%c", code + 'A' - 11); use_ucsoutput = FALSE; goto done; } if (inst->cfg.funky_type == FUNKY_XTERM && code >= 11 && code <= 14) { if (inst->term->vt52_mode) end = 1 + sprintf(output+1, "\x1B%c", code + 'P' - 11); else end = 1 + sprintf(output+1, "\x1BO%c", code + 'P' - 11); use_ucsoutput = FALSE; goto done; } if (inst->cfg.rxvt_homeend && (code == 1 || code == 4)) { end = 1 + sprintf(output+1, code == 1 ? "\x1B[H" : "\x1BOw"); use_ucsoutput = FALSE; goto done; } if (code) { end = 1 + sprintf(output+1, "\x1B[%d~", code); use_ucsoutput = FALSE; |
︙ | ︙ | |||
1214 1215 1216 1217 1218 1219 1220 | show_mouseptr(inst, 0); term_seen_key_event(inst->term); } return TRUE; } | < < < < < < < < < < < | 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 | show_mouseptr(inst, 0); term_seen_key_event(inst->term); } return TRUE; } gboolean button_internal(struct gui_data *inst, guint32 timestamp, GdkEventType type, guint ebutton, guint state, gdouble ex, gdouble ey) { int shift, ctrl, alt, x, y, button, act; /* Remember the timestamp. */ |
︙ | ︙ | |||
1272 1273 1274 1275 1276 1277 1278 | case GDK_BUTTON_PRESS: act = MA_CLICK; break; case GDK_BUTTON_RELEASE: act = MA_RELEASE; break; case GDK_2BUTTON_PRESS: act = MA_2CLK; break; case GDK_3BUTTON_PRESS: act = MA_3CLK; break; default: return FALSE; /* don't know this event type */ } | | < | | | 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 | case GDK_BUTTON_PRESS: act = MA_CLICK; break; case GDK_BUTTON_RELEASE: act = MA_RELEASE; break; case GDK_2BUTTON_PRESS: act = MA_2CLK; break; case GDK_3BUTTON_PRESS: act = MA_3CLK; break; default: return FALSE; /* don't know this event type */ } if (send_raw_mouse && !(inst->cfg.mouse_override && shift) && act != MA_CLICK && act != MA_RELEASE) return TRUE; /* we ignore these in raw mouse mode */ x = (ex - inst->cfg.window_border) / inst->font_width; y = (ey - inst->cfg.window_border) / inst->font_height; term_mouse(inst->term, button, translate_button(button), act, x, y, shift, ctrl, alt); return TRUE; } |
︙ | ︙ | |||
1338 1339 1340 1341 1342 1343 1344 | else if (event->state & GDK_BUTTON2_MASK) button = MBT_MIDDLE; else if (event->state & GDK_BUTTON3_MASK) button = MBT_RIGHT; else return FALSE; /* don't even know what button! */ | | | | | | | < | | > | | | | | > > > > < < | < | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < < < < | | | | 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 | else if (event->state & GDK_BUTTON2_MASK) button = MBT_MIDDLE; else if (event->state & GDK_BUTTON3_MASK) button = MBT_RIGHT; else return FALSE; /* don't even know what button! */ x = (event->x - inst->cfg.window_border) / inst->font_width; y = (event->y - inst->cfg.window_border) / inst->font_height; term_mouse(inst->term, button, translate_button(button), MA_DRAG, x, y, shift, ctrl, alt); return TRUE; } void frontend_keypress(void *handle) { struct gui_data *inst = (struct gui_data *)handle; /* * If our child process has exited but not closed, terminate on * any keypress. */ if (inst->exited) exit(0); } static gint idle_exit_func(gpointer data) { struct gui_data *inst = (struct gui_data *)data; int exitcode; if (!inst->exited && (exitcode = inst->back->exitcode(inst->backhandle)) >= 0) { inst->exited = TRUE; if (inst->cfg.close_on_exit == FORCE_ON || (inst->cfg.close_on_exit == AUTO && exitcode == 0)) gtk_main_quit(); /* just go */ if (inst->ldisc) { ldisc_free(inst->ldisc); inst->ldisc = NULL; } if (inst->back) { inst->back->free(inst->backhandle); inst->backhandle = NULL; inst->back = NULL; term_provide_resize_fn(inst->term, NULL, NULL); update_specials_menu(inst); } gtk_widget_set_sensitive(inst->restartitem, TRUE); } gtk_idle_remove(inst->term_exit_idle_id); return TRUE; } void notify_remote_exit(void *frontend) { struct gui_data *inst = (struct gui_data *)frontend; inst->term_exit_idle_id = gtk_idle_add(idle_exit_func, inst); } static gint timer_trigger(gpointer data) { long now = GPOINTER_TO_LONG(data); long next; long ticks; if (run_timers(now, &next)) { ticks = next - GETTICKCOUNT(); timer_id = gtk_timeout_add(ticks > 0 ? ticks : 1, timer_trigger, LONG_TO_GPOINTER(next)); } /* * Never let a timer resume. If we need another one, we've * asked for it explicitly above. */ return FALSE; } void timer_change_notify(long next) { long ticks; if (timer_id) gtk_timeout_remove(timer_id); ticks = next - GETTICKCOUNT(); |
︙ | ︙ | |||
1513 1514 1515 1516 1517 1518 1519 | /* * set or clear the "raw mouse message" mode */ void set_raw_mouse_mode(void *frontend, int activate) { struct gui_data *inst = (struct gui_data *)frontend; | | | 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 | /* * set or clear the "raw mouse message" mode */ void set_raw_mouse_mode(void *frontend, int activate) { struct gui_data *inst = (struct gui_data *)frontend; activate = activate && !inst->cfg.no_mouse_rep; send_raw_mouse = activate; update_mouseptr(inst); } void request_resize(void *frontend, int w, int h) { struct gui_data *inst = (struct gui_data *)frontend; |
︙ | ︙ | |||
1561 1562 1563 1564 1565 1566 1567 | #endif gtk_widget_size_request(inst->area, &inner); gtk_widget_size_request(inst->window, &outer); offset_x = outer.width - inner.width; offset_y = outer.height - inner.height; | | | | 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 | #endif gtk_widget_size_request(inst->area, &inner); gtk_widget_size_request(inst->window, &outer); offset_x = outer.width - inner.width; offset_y = outer.height - inner.height; area_x = inst->font_width * w + 2*inst->cfg.window_border; area_y = inst->font_height * h + 2*inst->cfg.window_border; /* * Now we must set the size request on the drawing area back to * something sensible before we commit the real resize. Best * way to do this, I think, is to set it to what the size is * really going to end up being. */ |
︙ | ︙ | |||
1629 1630 1631 1632 1633 1634 1635 | } void palette_set(void *frontend, int n, int r, int g, int b) { struct gui_data *inst = (struct gui_data *)frontend; if (n >= 16) n += 256 - 16; | | | | < | < | < | 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 | } void palette_set(void *frontend, int n, int r, int g, int b) { struct gui_data *inst = (struct gui_data *)frontend; if (n >= 16) n += 256 - 16; if (n > NALLCOLOURS) return; real_palette_set(inst, n, r, g, b); if (n == 258) { /* Default Background changed. Ensure space between text area and * window border is redrawn */ set_window_background(inst); draw_backing_rect(inst); gtk_widget_queue_draw(inst->area); } } void palette_reset(void *frontend) { struct gui_data *inst = (struct gui_data *)frontend; /* This maps colour indices in inst->cfg to those used in inst->cols. */ static const int ww[] = { 256, 257, 258, 259, 260, 261, 0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15 }; gboolean success[NALLCOLOURS]; int i; assert(lenof(ww) == NCFGCOLOURS); if (!inst->colmap) { inst->colmap = gdk_colormap_get_system(); } else { gdk_colormap_free_colors(inst->colmap, inst->cols, NALLCOLOURS); } for (i = 0; i < NCFGCOLOURS; i++) { inst->cols[ww[i]].red = inst->cfg.colours[i][0] * 0x0101; inst->cols[ww[i]].green = inst->cfg.colours[i][1] * 0x0101; inst->cols[ww[i]].blue = inst->cfg.colours[i][2] * 0x0101; } for (i = 0; i < NEXTCOLOURS; i++) { if (i < 216) { int r = i / 36, g = (i / 6) % 6, b = i % 6; inst->cols[i+16].red = r ? r * 0x2828 + 0x3737 : 0; inst->cols[i+16].green = g ? g * 0x2828 + 0x3737 : 0; |
︙ | ︙ | |||
1689 1690 1691 1692 1693 1694 1695 | } gdk_colormap_alloc_colors(inst->colmap, inst->cols, NALLCOLOURS, FALSE, TRUE, success); for (i = 0; i < NALLCOLOURS; i++) { if (!success[i]) g_error("%s: couldn't allocate colour %d (#%02x%02x%02x)\n", | | | < < | 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 | } gdk_colormap_alloc_colors(inst->colmap, inst->cols, NALLCOLOURS, FALSE, TRUE, success); for (i = 0; i < NALLCOLOURS; i++) { if (!success[i]) g_error("%s: couldn't allocate colour %d (#%02x%02x%02x)\n", appname, i, inst->cfg.colours[i][0], inst->cfg.colours[i][1], inst->cfg.colours[i][2]); } /* Since Default Background may have changed, ensure that space * between text area and window border is refreshed. */ set_window_background(inst); if (inst->area && inst->area->window) { draw_backing_rect(inst); |
︙ | ︙ | |||
1765 1766 1767 1768 1769 1770 1771 | sfree(inst->pasteout_data_utf8); /* * Set up UTF-8 and compound text paste data. This only happens * if we aren't in direct-to-font mode using the D800 hack. */ if (!inst->direct_to_font) { | | | 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 | sfree(inst->pasteout_data_utf8); /* * Set up UTF-8 and compound text paste data. This only happens * if we aren't in direct-to-font mode using the D800 hack. */ if (!inst->direct_to_font) { wchar_t *tmp = data; int tmplen = len; XTextProperty tp; char *list[1]; inst->pasteout_data_utf8 = snewn(len*6, char); inst->pasteout_data_utf8_len = len*6; inst->pasteout_data_utf8_len = |
︙ | ︙ | |||
2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 | inst->pastein_data_len = length; inst->pastein_data_len = mb_to_wc(charset, 0, text, length, inst->pastein_data, inst->pastein_data_len); term_do_paste(inst->term); if (free_list_required) XFreeStringList(list); if (free_required) XFree(text); } void get_clip(void *frontend, wchar_t ** p, int *len) { struct gui_data *inst = (struct gui_data *)frontend; if (p) { *p = inst->pastein_data; *len = inst->pastein_data_len; } } static void set_window_titles(struct gui_data *inst) { /* * We must always call set_icon_name after calling set_title, * since set_title will write both names. Irritating, but such * is life. */ gtk_window_set_title(GTK_WINDOW(inst->window), inst->wintitle); | > > > > > > > > > > > > > > > > | | | | < < < < < < < < < | < | | | 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 | inst->pastein_data_len = length; inst->pastein_data_len = mb_to_wc(charset, 0, text, length, inst->pastein_data, inst->pastein_data_len); term_do_paste(inst->term); if (term_paste_pending(inst->term)) inst->term_paste_idle_id = gtk_idle_add(idle_paste_func, inst); if (free_list_required) XFreeStringList(list); if (free_required) XFree(text); } gint idle_paste_func(gpointer data) { struct gui_data *inst = (struct gui_data *)data; if (term_paste_pending(inst->term)) term_paste(inst->term); else gtk_idle_remove(inst->term_paste_idle_id); return TRUE; } void get_clip(void *frontend, wchar_t ** p, int *len) { struct gui_data *inst = (struct gui_data *)frontend; if (p) { *p = inst->pastein_data; *len = inst->pastein_data_len; } } static void set_window_titles(struct gui_data *inst) { /* * We must always call set_icon_name after calling set_title, * since set_title will write both names. Irritating, but such * is life. */ gtk_window_set_title(GTK_WINDOW(inst->window), inst->wintitle); if (!inst->cfg.win_name_always) gdk_window_set_icon_name(inst->window->window, inst->icontitle); } void set_title(void *frontend, char *title) { struct gui_data *inst = (struct gui_data *)frontend; strncpy(inst->wintitle, title, lenof(inst->wintitle)); inst->wintitle[lenof(inst->wintitle)-1] = '\0'; set_window_titles(inst); } void set_icon(void *frontend, char *title) { struct gui_data *inst = (struct gui_data *)frontend; strncpy(inst->icontitle, title, lenof(inst->icontitle)); inst->icontitle[lenof(inst->icontitle)-1] = '\0'; set_window_titles(inst); } void set_sbar(void *frontend, int total, int start, int page) { struct gui_data *inst = (struct gui_data *)frontend; if (!inst->cfg.scrollbar) return; inst->sbar_adjust->lower = 0; inst->sbar_adjust->upper = total; inst->sbar_adjust->value = start; inst->sbar_adjust->page_size = page; inst->sbar_adjust->step_increment = 1; inst->sbar_adjust->page_increment = page/2; inst->ignore_sbar = TRUE; gtk_adjustment_changed(inst->sbar_adjust); inst->ignore_sbar = FALSE; } void scrollbar_moved(GtkAdjustment *adj, gpointer data) { struct gui_data *inst = (struct gui_data *)data; if (!inst->cfg.scrollbar) return; if (!inst->ignore_sbar) term_scroll(inst->term, 1, (int)adj->value); } void sys_cursor(void *frontend, int x, int y) { |
︙ | ︙ | |||
2175 2176 2177 2178 2179 2180 2181 | nfg = ((monochrome ? ATTR_DEFFG : (attr & ATTR_FGMASK)) >> ATTR_FGSHIFT); nbg = ((monochrome ? ATTR_DEFBG : (attr & ATTR_BGMASK)) >> ATTR_BGSHIFT); if (!!(attr & ATTR_REVERSE) ^ (monochrome && (attr & TATTR_ACTCURS))) { t = nfg; nfg = nbg; nbg = t; } | | | | | 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 | nfg = ((monochrome ? ATTR_DEFFG : (attr & ATTR_FGMASK)) >> ATTR_FGSHIFT); nbg = ((monochrome ? ATTR_DEFBG : (attr & ATTR_BGMASK)) >> ATTR_BGSHIFT); if (!!(attr & ATTR_REVERSE) ^ (monochrome && (attr & TATTR_ACTCURS))) { t = nfg; nfg = nbg; nbg = t; } if (inst->cfg.bold_colour && (attr & ATTR_BOLD)) { if (nfg < 16) nfg |= 8; else if (nfg >= 256) nfg |= 1; } if (inst->cfg.bold_colour && (attr & ATTR_BLINK)) { if (nbg < 16) nbg |= 8; else if (nbg >= 256) nbg |= 1; } if ((attr & TATTR_ACTCURS) && !monochrome) { nfg = 260; nbg = 261; } fontid = shadow = 0; if (attr & ATTR_WIDE) { widefactor = 2; fontid |= 2; } else { widefactor = 1; } if ((attr & ATTR_BOLD) && !inst->cfg.bold_colour) { bold = 1; fontid |= 1; } else { bold = 0; } if (!inst->fonts[fontid]) { |
︙ | ︙ | |||
2234 2235 2236 2237 2238 2239 2240 | rlen = len * 2; } else rlen = len; { GdkRectangle r; | | | | | > > > > > > > > > > > | > > > | | | | > | > | | | | | | | | | | | | | 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 | rlen = len * 2; } else rlen = len; { GdkRectangle r; r.x = x*inst->font_width+inst->cfg.window_border; r.y = y*inst->font_height+inst->cfg.window_border; r.width = rlen*widefactor*inst->font_width; r.height = inst->font_height; gdk_gc_set_clip_rectangle(gc, &r); } gdk_gc_set_foreground(gc, &inst->cols[nbg]); gdk_draw_rectangle(inst->pixmap, gc, 1, x*inst->font_width+inst->cfg.window_border, y*inst->font_height+inst->cfg.window_border, rlen*widefactor*inst->font_width, inst->font_height); gdk_gc_set_foreground(gc, &inst->cols[nfg]); { gchar *gcs; /* * FIXME: this length is hardwired on the assumption that * conversions from wide to multibyte characters will * never generate more than 10 bytes for a single wide * character. */ gcs = snewn(len*10+1, gchar); for (combining = 0; combining < ncombining; combining++) { int mblen = wc_to_mb(inst->fonts[fontid]->real_charset, 0, text + combining, len, gcs, len*10+1, ".", NULL, NULL); unifont_draw_text(inst->pixmap, gc, inst->fonts[fontid], x*inst->font_width+inst->cfg.window_border, y*inst->font_height+inst->cfg.window_border+inst->fonts[0]->ascent, gcs, mblen, widefactor > 1, bold, inst->font_width); } sfree(gcs); } if (attr & ATTR_UNDER) { int uheight = inst->fonts[0]->ascent + 1; if (uheight >= inst->font_height) uheight = inst->font_height - 1; gdk_draw_line(inst->pixmap, gc, x*inst->font_width+inst->cfg.window_border, y*inst->font_height + uheight + inst->cfg.window_border, (x+len)*widefactor*inst->font_width-1+inst->cfg.window_border, y*inst->font_height + uheight + inst->cfg.window_border); } if ((lattr & LATTR_MODE) != LATTR_NORM) { /* * I can't find any plausible StretchBlt equivalent in the * X server, so I'm going to do this the slow and painful * way. This will involve repeated calls to * gdk_draw_pixmap() to stretch the text horizontally. It's * O(N^2) in time and O(N) in network bandwidth, but you * try thinking of a better way. :-( */ int i; for (i = 0; i < len * widefactor * inst->font_width; i++) { gdk_draw_pixmap(inst->pixmap, gc, inst->pixmap, x*inst->font_width+inst->cfg.window_border + 2*i, y*inst->font_height+inst->cfg.window_border, x*inst->font_width+inst->cfg.window_border + 2*i+1, y*inst->font_height+inst->cfg.window_border, len * widefactor * inst->font_width - i, inst->font_height); } len *= 2; if ((lattr & LATTR_MODE) != LATTR_WIDE) { int dt, db; /* Now stretch vertically, in the same way. */ if ((lattr & LATTR_MODE) == LATTR_BOT) dt = 0, db = 1; else dt = 1, db = 0; for (i = 0; i < inst->font_height; i+=2) { gdk_draw_pixmap(inst->pixmap, gc, inst->pixmap, x*inst->font_width+inst->cfg.window_border, y*inst->font_height+inst->cfg.window_border+dt*i+db, x*inst->font_width+inst->cfg.window_border, y*inst->font_height+inst->cfg.window_border+dt*(i+1), len * widefactor * inst->font_width, inst->font_height-i-1); } } } } void do_text(Context ctx, int x, int y, wchar_t *text, int len, |
︙ | ︙ | |||
2330 2331 2332 2333 2334 2335 2336 | return; if (x + len*2*widefactor > inst->term->cols) len = (inst->term->cols-x)/2/widefactor;/* trim to LH half */ len *= 2; } gdk_draw_pixmap(inst->area->window, gc, inst->pixmap, | | | | | | | 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 | return; if (x + len*2*widefactor > inst->term->cols) len = (inst->term->cols-x)/2/widefactor;/* trim to LH half */ len *= 2; } gdk_draw_pixmap(inst->area->window, gc, inst->pixmap, x*inst->font_width+inst->cfg.window_border, y*inst->font_height+inst->cfg.window_border, x*inst->font_width+inst->cfg.window_border, y*inst->font_height+inst->cfg.window_border, len*widefactor*inst->font_width, inst->font_height); } void do_cursor(Context ctx, int x, int y, wchar_t *text, int len, unsigned long attr, int lattr) { struct draw_ctx *dctx = (struct draw_ctx *)ctx; struct gui_data *inst = dctx->inst; GdkGC *gc = dctx->gc; int active, passive, widefactor; if (attr & TATTR_PASCURS) { attr &= ~TATTR_PASCURS; passive = 1; } else passive = 0; if ((attr & TATTR_ACTCURS) && inst->cfg.cursor_type != 0) { attr &= ~TATTR_ACTCURS; active = 1; } else active = 0; do_text_internal(ctx, x, y, text, len, attr, lattr); if (attr & TATTR_COMBINING) |
︙ | ︙ | |||
2376 2377 2378 2379 2380 2381 2382 | if (x >= inst->term->cols) return; if (x + len*2*widefactor > inst->term->cols) len = (inst->term->cols-x)/2/widefactor;/* trim to LH half */ len *= 2; } | | | | | | | | | | 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 | if (x >= inst->term->cols) return; if (x + len*2*widefactor > inst->term->cols) len = (inst->term->cols-x)/2/widefactor;/* trim to LH half */ len *= 2; } if (inst->cfg.cursor_type == 0) { /* * An active block cursor will already have been done by * the above do_text call, so we only need to do anything * if it's passive. */ if (passive) { gdk_gc_set_foreground(gc, &inst->cols[261]); gdk_draw_rectangle(inst->pixmap, gc, 0, x*inst->font_width+inst->cfg.window_border, y*inst->font_height+inst->cfg.window_border, len*widefactor*inst->font_width-1, inst->font_height-1); } } else { int uheight; int startx, starty, dx, dy, length, i; int char_width; if ((attr & ATTR_WIDE) || (lattr & LATTR_MODE) != LATTR_NORM) char_width = 2*inst->font_width; else char_width = inst->font_width; if (inst->cfg.cursor_type == 1) { uheight = inst->fonts[0]->ascent + 1; if (uheight >= inst->font_height) uheight = inst->font_height - 1; startx = x * inst->font_width + inst->cfg.window_border; starty = y * inst->font_height + inst->cfg.window_border + uheight; dx = 1; dy = 0; length = len * widefactor * char_width; } else { int xadjust = 0; if (attr & TATTR_RIGHTCURS) xadjust = char_width - 1; startx = x * inst->font_width + inst->cfg.window_border + xadjust; starty = y * inst->font_height + inst->cfg.window_border; dx = 0; dy = 1; length = inst->font_height; } gdk_gc_set_foreground(gc, &inst->cols[261]); if (passive) { |
︙ | ︙ | |||
2437 2438 2439 2440 2441 2442 2443 | } else if (active) { gdk_draw_line(inst->pixmap, gc, startx, starty, startx + (length-1) * dx, starty + (length-1) * dy); } /* else no cursor (e.g., blinked off) */ } gdk_draw_pixmap(inst->area->window, gc, inst->pixmap, | | | | | < < < < < < < < < < < | 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 | } else if (active) { gdk_draw_line(inst->pixmap, gc, startx, starty, startx + (length-1) * dx, starty + (length-1) * dy); } /* else no cursor (e.g., blinked off) */ } gdk_draw_pixmap(inst->area->window, gc, inst->pixmap, x*inst->font_width+inst->cfg.window_border, y*inst->font_height+inst->cfg.window_border, x*inst->font_width+inst->cfg.window_border, y*inst->font_height+inst->cfg.window_border, len*widefactor*inst->font_width, inst->font_height); } GdkCursor *make_mouse_ptr(struct gui_data *inst, int cursor_val) { /* * Truly hideous hack: GTK doesn't allow us to set the mouse * cursor foreground and background colours unless we've _also_ |
︙ | ︙ | |||
2610 2611 2612 2613 2614 2615 2616 | " -e COMMAND [ARGS...] Execute command (consumes all remaining args)\n" ) < 0 || fflush(fp) < 0) { perror("output error"); exit(1); } } | < < < < < < < | | 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 | " -e COMMAND [ARGS...] Execute command (consumes all remaining args)\n" ) < 0 || fflush(fp) < 0) { perror("output error"); exit(1); } } int do_cmdline(int argc, char **argv, int do_everything, int *allow_launch, struct gui_data *inst, Config *cfg) { int err = 0; char *val; /* * Macros to make argument handling easier. Note that because * they need to call `continue', they cannot be contained in |
︙ | ︙ | |||
2657 2658 2659 2660 2661 2662 2663 | * only, we convert -T into -title. */ if ((cmdline_tooltype & TOOLTYPE_NONNETWORK) && !strcmp(p, "-T")) p = "-title"; ret = cmdline_process_param(p, (argc > 1 ? argv[1] : NULL), | | < | < | < | | < < | | < < < | | | > | | | | 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 | * only, we convert -T into -title. */ if ((cmdline_tooltype & TOOLTYPE_NONNETWORK) && !strcmp(p, "-T")) p = "-title"; ret = cmdline_process_param(p, (argc > 1 ? argv[1] : NULL), do_everything ? 1 : -1, cfg); if (ret == -2) { cmdline_error("option \"%s\" requires an argument", p); } else if (ret == 2) { --argc, ++argv; /* skip next argument */ continue; } else if (ret == 1) { continue; } if (!strcmp(p, "-fn") || !strcmp(p, "-font")) { EXPECTS_ARG; SECOND_PASS_ONLY; strncpy(cfg->font.name, val, sizeof(cfg->font.name)); cfg->font.name[sizeof(cfg->font.name)-1] = '\0'; } else if (!strcmp(p, "-fb")) { EXPECTS_ARG; SECOND_PASS_ONLY; strncpy(cfg->boldfont.name, val, sizeof(cfg->boldfont.name)); cfg->boldfont.name[sizeof(cfg->boldfont.name)-1] = '\0'; } else if (!strcmp(p, "-fw")) { EXPECTS_ARG; SECOND_PASS_ONLY; strncpy(cfg->widefont.name, val, sizeof(cfg->widefont.name)); cfg->widefont.name[sizeof(cfg->widefont.name)-1] = '\0'; } else if (!strcmp(p, "-fwb")) { EXPECTS_ARG; SECOND_PASS_ONLY; strncpy(cfg->wideboldfont.name, val, sizeof(cfg->wideboldfont.name)); cfg->wideboldfont.name[sizeof(cfg->wideboldfont.name)-1] = '\0'; } else if (!strcmp(p, "-cs")) { EXPECTS_ARG; SECOND_PASS_ONLY; strncpy(cfg->line_codepage, val, sizeof(cfg->line_codepage)); cfg->line_codepage[sizeof(cfg->line_codepage)-1] = '\0'; } else if (!strcmp(p, "-geometry")) { int flags, x, y; unsigned int w, h; EXPECTS_ARG; SECOND_PASS_ONLY; flags = XParseGeometry(val, &x, &y, &w, &h); if (flags & WidthValue) cfg->width = (int)w; if (flags & HeightValue) cfg->height = (int)h; if (flags & (XValue | YValue)) { inst->xpos = x; inst->ypos = y; inst->gotpos = TRUE; inst->gravity = ((flags & XNegative ? 1 : 0) | (flags & YNegative ? 2 : 0)); } } else if (!strcmp(p, "-sl")) { EXPECTS_ARG; SECOND_PASS_ONLY; cfg->savelines = atoi(val); } else if (!strcmp(p, "-fg") || !strcmp(p, "-bg") || !strcmp(p, "-bfg") || !strcmp(p, "-bbg") || !strcmp(p, "-cfg") || !strcmp(p, "-cbg")) { GdkColor col; EXPECTS_ARG; |
︙ | ︙ | |||
2750 2751 2752 2753 2754 2755 2756 | index = (!strcmp(p, "-fg") ? 0 : !strcmp(p, "-bg") ? 2 : !strcmp(p, "-bfg") ? 1 : !strcmp(p, "-bbg") ? 3 : !strcmp(p, "-cfg") ? 4 : !strcmp(p, "-cbg") ? 5 : -1); assert(index != -1); | | | | | 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 | index = (!strcmp(p, "-fg") ? 0 : !strcmp(p, "-bg") ? 2 : !strcmp(p, "-bfg") ? 1 : !strcmp(p, "-bbg") ? 3 : !strcmp(p, "-cfg") ? 4 : !strcmp(p, "-cbg") ? 5 : -1); assert(index != -1); cfg->colours[index][0] = col.red / 256; cfg->colours[index][1] = col.green / 256; cfg->colours[index][2] = col.blue / 256; } } else if (use_pty_argv && !strcmp(p, "-e")) { /* This option swallows all further arguments. */ if (!do_everything) break; |
︙ | ︙ | |||
2775 2776 2777 2778 2779 2780 2781 | } else err = 1, fprintf(stderr, "%s: -e expects an argument\n", appname); } else if (!strcmp(p, "-title")) { EXPECTS_ARG; SECOND_PASS_ONLY; | | > < | | | < | | | | | | | < < < < | | 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 | } else err = 1, fprintf(stderr, "%s: -e expects an argument\n", appname); } else if (!strcmp(p, "-title")) { EXPECTS_ARG; SECOND_PASS_ONLY; strncpy(cfg->wintitle, val, sizeof(cfg->wintitle)); cfg->wintitle[sizeof(cfg->wintitle)-1] = '\0'; } else if (!strcmp(p, "-log")) { EXPECTS_ARG; SECOND_PASS_ONLY; strncpy(cfg->logfilename.path, val, sizeof(cfg->logfilename.path)); cfg->logfilename.path[sizeof(cfg->logfilename.path)-1] = '\0'; cfg->logtype = LGTYP_DEBUG; } else if (!strcmp(p, "-ut-") || !strcmp(p, "+ut")) { SECOND_PASS_ONLY; cfg->stamp_utmp = 0; } else if (!strcmp(p, "-ut")) { SECOND_PASS_ONLY; cfg->stamp_utmp = 1; } else if (!strcmp(p, "-ls-") || !strcmp(p, "+ls")) { SECOND_PASS_ONLY; cfg->login_shell = 0; } else if (!strcmp(p, "-ls")) { SECOND_PASS_ONLY; cfg->login_shell = 1; } else if (!strcmp(p, "-nethack")) { SECOND_PASS_ONLY; cfg->nethack_keypad = 1; } else if (!strcmp(p, "-sb-") || !strcmp(p, "+sb")) { SECOND_PASS_ONLY; cfg->scrollbar = 0; } else if (!strcmp(p, "-sb")) { SECOND_PASS_ONLY; cfg->scrollbar = 0; } else if (!strcmp(p, "-name")) { EXPECTS_ARG; app_name = val; } else if (!strcmp(p, "-xrm")) { EXPECTS_ARG; provide_xrm_string(val); } else if(!strcmp(p, "-help") || !strcmp(p, "--help")) { help(stdout); exit(0); } else if (!strcmp(p, "-pgpfp")) { pgp_fingerprints(); exit(1); } else if(p[0] != '-' && (!do_everything || process_nonoption_arg(p, cfg, allow_launch))) { /* do nothing */ } else { err = 1; fprintf(stderr, "%s: unrecognized option '%s'\n", appname, p); } |
︙ | ︙ | |||
2861 2862 2863 2864 2865 2866 2867 | return gdk_input_add(fd, flags, fd_input_func, NULL); } void uxsel_input_remove(int id) { gdk_input_remove(id); } | | | > | > | | | > | | | > | | > > < | | > | | > | < < | > > < | > | | > | < < < | > > | < | | | > | > | < < < | < < | < < < < > | < < < < | < | < | < | | | | | 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 | return gdk_input_add(fd, flags, fd_input_func, NULL); } void uxsel_input_remove(int id) { gdk_input_remove(id); } void setup_fonts_ucs(struct gui_data *inst) { if (inst->fonts[0]) unifont_destroy(inst->fonts[0]); if (inst->fonts[1]) unifont_destroy(inst->fonts[1]); if (inst->fonts[2]) unifont_destroy(inst->fonts[2]); if (inst->fonts[3]) unifont_destroy(inst->fonts[3]); inst->fonts[0] = unifont_create(inst->area, inst->cfg.font.name, FALSE, FALSE, inst->cfg.shadowboldoffset, inst->cfg.shadowbold); if (!inst->fonts[0]) { fprintf(stderr, "%s: unable to load font \"%s\"\n", appname, inst->cfg.font.name); exit(1); } if (inst->cfg.shadowbold || !inst->cfg.boldfont.name[0]) { inst->fonts[1] = NULL; } else { inst->fonts[1] = unifont_create(inst->area, inst->cfg.boldfont.name, FALSE, TRUE, inst->cfg.shadowboldoffset, inst->cfg.shadowbold); if (!inst->fonts[1]) { fprintf(stderr, "%s: unable to load bold font \"%s\"\n", appname, inst->cfg.boldfont.name); exit(1); } } if (inst->cfg.widefont.name[0]) { inst->fonts[2] = unifont_create(inst->area, inst->cfg.widefont.name, TRUE, FALSE, inst->cfg.shadowboldoffset, inst->cfg.shadowbold); if (!inst->fonts[2]) { fprintf(stderr, "%s: unable to load wide font \"%s\"\n", appname, inst->cfg.widefont.name); exit(1); } } else { inst->fonts[2] = NULL; } if (inst->cfg.shadowbold || !inst->cfg.wideboldfont.name[0]) { inst->fonts[3] = NULL; } else { inst->fonts[3] = unifont_create(inst->area, inst->cfg.wideboldfont.name, TRUE, TRUE, inst->cfg.shadowboldoffset, inst->cfg.shadowbold); if (!inst->fonts[3]) { fprintf(stderr, "%s: unable to load wide bold font \"%s\"\n", appname, inst->cfg.boldfont.name); exit(1); } } inst->font_width = inst->fonts[0]->width; inst->font_height = inst->fonts[0]->height; inst->direct_to_font = init_ucs(&inst->ucsdata, inst->cfg.line_codepage, inst->cfg.utf8_override, inst->fonts[0]->public_charset, inst->cfg.vtmode); } void set_geom_hints(struct gui_data *inst) { GdkGeometry geom; geom.min_width = inst->font_width + 2*inst->cfg.window_border; geom.min_height = inst->font_height + 2*inst->cfg.window_border; geom.max_width = geom.max_height = -1; geom.base_width = 2*inst->cfg.window_border; geom.base_height = 2*inst->cfg.window_border; geom.width_inc = inst->font_width; geom.height_inc = inst->font_height; geom.min_aspect = geom.max_aspect = 0; gtk_window_set_geometry_hints(GTK_WINDOW(inst->window), inst->area, &geom, GDK_HINT_MIN_SIZE | GDK_HINT_BASE_SIZE | GDK_HINT_RESIZE_INC); } |
︙ | ︙ | |||
3000 3001 3002 3003 3004 3005 3006 | { struct gui_data *inst = (struct gui_data *)data; showeventlog(inst->eventlogstuff, inst->window); } void change_settings_menuitem(GtkMenuItem *item, gpointer data) { | | | | | < | < < | | > > | | < < | | < < | | | | < | | < | | | | < | | | < | < | < | < | < | < | < | < | < < | < < | < | < < < | < < < < < < < < < | | | < < < < < | < < | | < < | | < < < < | 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 | { struct gui_data *inst = (struct gui_data *)data; showeventlog(inst->eventlogstuff, inst->window); } void change_settings_menuitem(GtkMenuItem *item, gpointer data) { /* This maps colour indices in inst->cfg to those used in inst->cols. */ static const int ww[] = { 256, 257, 258, 259, 260, 261, 0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15 }; struct gui_data *inst = (struct gui_data *)data; char *title = dupcat(appname, " Reconfiguration", NULL); Config cfg2, oldcfg; int i, need_size; assert(lenof(ww) == NCFGCOLOURS); if (inst->reconfiguring) return; else inst->reconfiguring = TRUE; cfg2 = inst->cfg; /* structure copy */ if (do_config_box(title, &cfg2, 1, inst->back?inst->back->cfg_info(inst->backhandle):0)) { oldcfg = inst->cfg; /* structure copy */ inst->cfg = cfg2; /* structure copy */ /* Pass new config data to the logging module */ log_reconfig(inst->logctx, &cfg2); /* * Flush the line discipline's edit buffer in the case * where local editing has just been disabled. */ if (inst->ldisc) ldisc_send(inst->ldisc, NULL, 0, 0); /* Pass new config data to the terminal */ term_reconfig(inst->term, &cfg2); /* Pass new config data to the back end */ if (inst->back) inst->back->reconfig(inst->backhandle, &cfg2); /* * Just setting inst->cfg is sufficient to cause colour * setting changes to appear on the next ESC]R palette * reset. But we should also check whether any colour * settings have been changed, and revert the ones that * have to the new default, on the assumption that the user * is most likely to want an immediate update. */ for (i = 0; i < NCFGCOLOURS; i++) { if (oldcfg.colours[i][0] != cfg2.colours[i][0] || oldcfg.colours[i][1] != cfg2.colours[i][1] || oldcfg.colours[i][2] != cfg2.colours[i][2]) { real_palette_set(inst, ww[i], cfg2.colours[i][0], cfg2.colours[i][1], cfg2.colours[i][2]); /* * If the default background has changed, we must * repaint the space in between the window border * and the text area. */ if (i == 258) { set_window_background(inst); draw_backing_rect(inst); } } } /* * If the scrollbar needs to be shown, hidden, or moved * from one end to the other of the window, do so now. */ if (oldcfg.scrollbar != cfg2.scrollbar) { if (cfg2.scrollbar) gtk_widget_show(inst->sbar); else gtk_widget_hide(inst->sbar); } if (oldcfg.scrollbar_on_left != cfg2.scrollbar_on_left) { gtk_box_reorder_child(inst->hbox, inst->sbar, cfg2.scrollbar_on_left ? 0 : 1); } /* * Change the window title, if required. */ if (strcmp(oldcfg.wintitle, cfg2.wintitle)) set_title(inst, cfg2.wintitle); set_window_titles(inst); /* * Redo the whole tangled fonts and Unicode mess if * necessary. */ if (strcmp(oldcfg.font.name, cfg2.font.name) || strcmp(oldcfg.boldfont.name, cfg2.boldfont.name) || strcmp(oldcfg.widefont.name, cfg2.widefont.name) || strcmp(oldcfg.wideboldfont.name, cfg2.wideboldfont.name) || strcmp(oldcfg.line_codepage, cfg2.line_codepage) || oldcfg.vtmode != cfg2.vtmode || oldcfg.shadowbold != cfg2.shadowbold) { setup_fonts_ucs(inst); need_size = 1; } else need_size = 0; /* * Resize the window. */ if (oldcfg.width != cfg2.width || oldcfg.height != cfg2.height || oldcfg.window_border != cfg2.window_border || need_size) { set_geom_hints(inst); request_resize(inst, cfg2.width, cfg2.height); } else { /* * The above will have caused a call to term_size() for * us if it happened. If the user has fiddled with only * the scrollback size, the above will not have * happened and we will need an explicit term_size() * here. */ if (oldcfg.savelines != cfg2.savelines) term_size(inst->term, inst->term->rows, inst->term->cols, cfg2.savelines); } term_invalidate(inst->term); /* * We do an explicit full redraw here to ensure the window * border has been redrawn as well as the text area. */ gtk_widget_queue_draw(inst->area); } sfree(title); inst->reconfiguring = FALSE; } void fork_and_exec_self(struct gui_data *inst, int fd_to_close, ...) { |
︙ | ︙ | |||
3229 3230 3231 3232 3233 3234 3235 | /* * Do the double fork. */ pid = fork(); if (pid < 0) { perror("fork"); | < | 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 | /* * Do the double fork. */ pid = fork(); if (pid < 0) { perror("fork"); return; } if (pid == 0) { int pid2 = fork(); if (pid2 < 0) { perror("fork"); |
︙ | ︙ | |||
3263 3264 3265 3266 3267 3268 3269 | execv("/proc/self/exe", args); execvp(inst->progname, args); perror("exec"); _exit(127); } else { int status; | < | | | | | | | | | | | | < < | 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 | execv("/proc/self/exe", args); execvp(inst->progname, args); perror("exec"); _exit(127); } else { int status; waitpid(pid, &status, 0); } } void dup_session_menuitem(GtkMenuItem *item, gpointer gdata) { struct gui_data *inst = (struct gui_data *)gdata; /* * For this feature we must marshal cfg and (possibly) pty_argv * into a byte stream, create a pipe, and send this byte stream * to the child through the pipe. */ int i, ret, size; char *data; char option[80]; int pipefd[2]; if (pipe(pipefd) < 0) { perror("pipe"); return; } size = sizeof(inst->cfg); if (use_pty_argv && pty_argv) { for (i = 0; pty_argv[i]; i++) size += strlen(pty_argv[i]) + 1; } data = snewn(size, char); memcpy(data, &inst->cfg, sizeof(inst->cfg)); if (use_pty_argv && pty_argv) { int p = sizeof(inst->cfg); for (i = 0; pty_argv[i]; i++) { strcpy(data + p, pty_argv[i]); p += strlen(pty_argv[i]) + 1; } assert(p == size); } sprintf(option, "---[%d,%d]", pipefd[0], size); fcntl(pipefd[0], F_SETFD, 0); fork_and_exec_self(inst, pipefd[1], option, NULL); close(pipefd[0]); i = ret = 0; while (i < size && (ret = write(pipefd[1], data + i, size - i)) > 0) i += ret; if (ret < 0) perror("write to pipe"); close(pipefd[1]); sfree(data); } int read_dupsession_data(struct gui_data *inst, Config *cfg, char *arg) { int fd, i, ret, size; char *data; if (sscanf(arg, "---[%d,%d]", &fd, &size) != 2) { fprintf(stderr, "%s: malformed magic argument `%s'\n", appname, arg); exit(1); } data = snewn(size, char); i = ret = 0; while (i < size && (ret = read(fd, data + i, size - i)) > 0) i += ret; if (ret < 0) { perror("read from pipe"); exit(1); } else if (i < size) { fprintf(stderr, "%s: unexpected EOF in Duplicate Session data\n", appname); exit(1); } memcpy(cfg, data, sizeof(Config)); if (use_pty_argv && size > sizeof(Config)) { int n = 0; i = sizeof(Config); while (i < size) { while (i < size && data[i]) i++; if (i >= size) { fprintf(stderr, "%s: malformed Duplicate Session data\n", appname); exit(1); } i++; n++; } pty_argv = snewn(n+1, char *); pty_argv[n] = NULL; n = 0; i = sizeof(Config); while (i < size) { char *p = data + i; while (i < size && data[i]) i++; assert(i < size); i++; pty_argv[n++] = dupstr(p); } } return 0; } void new_session_menuitem(GtkMenuItem *item, gpointer data) { struct gui_data *inst = (struct gui_data *)data; |
︙ | ︙ | |||
3539 3540 3541 3542 3543 3544 3545 | gtk_widget_hide(inst->specialsitem1); gtk_widget_hide(inst->specialsitem2); } } static void start_backend(struct gui_data *inst) { | | < | | < < | < | | < | > | > | | | < < < < | 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 | gtk_widget_hide(inst->specialsitem1); gtk_widget_hide(inst->specialsitem2); } } static void start_backend(struct gui_data *inst) { extern Backend *select_backend(Config *cfg); char *realhost; const char *error; inst->back = select_backend(&inst->cfg); error = inst->back->init((void *)inst, &inst->backhandle, &inst->cfg, inst->cfg.host, inst->cfg.port, &realhost, inst->cfg.tcp_nodelay, inst->cfg.tcp_keepalives); if (error) { char *msg = dupprintf("Unable to open connection to %s:\n%s", inst->cfg.host, error); inst->exited = TRUE; fatal_message_box(inst->window, msg); sfree(msg); exit(0); } if (inst->cfg.wintitle[0]) { set_title(inst, inst->cfg.wintitle); set_icon(inst, inst->cfg.wintitle); } else { char *title = make_default_wintitle(realhost); set_title(inst, title); set_icon(inst, title); sfree(title); } sfree(realhost); inst->back->provide_logctx(inst->backhandle, inst->logctx); term_provide_resize_fn(inst->term, inst->back->size, inst->backhandle); inst->ldisc = ldisc_create(&inst->cfg, inst->term, inst->back, inst->backhandle, inst); gtk_widget_set_sensitive(inst->restartitem, FALSE); } int pt_main(int argc, char **argv) { extern int cfgbox(Config *cfg); struct gui_data *inst; /* * Create an instance structure and initialise to zeroes */ inst = snew(struct gui_data); memset(inst, 0, sizeof(*inst)); inst->alt_keycode = -1; /* this one needs _not_ to be zero */ inst->busy_status = BUSY_NOT; /* defer any child exit handling until we're ready to deal with * it */ block_signal(SIGCHLD, 1); inst->progname = argv[0]; /* |
︙ | ︙ | |||
3621 3622 3623 3624 3625 3626 3627 | inst->gtkargvstart[i-1] = dupstr(argv[i]); oldargc = argc; gtk_init(&argc, &argv); inst->ngtkargs = oldargc - argc; } if (argc > 1 && !strncmp(argv[1], "---", 3)) { | | | | | | | | | < < < < < | < < < < < < < | | | < | | < | | | | | | 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 | inst->gtkargvstart[i-1] = dupstr(argv[i]); oldargc = argc; gtk_init(&argc, &argv); inst->ngtkargs = oldargc - argc; } if (argc > 1 && !strncmp(argv[1], "---", 3)) { read_dupsession_data(inst, &inst->cfg, argv[1]); /* Splatter this argument so it doesn't clutter a ps listing */ memset(argv[1], 0, strlen(argv[1])); } else { /* By default, we bring up the config dialog, rather than launching * a session. This gets set to TRUE if something happens to change * that (e.g., a hostname is specified on the command-line). */ int allow_launch = FALSE; if (do_cmdline(argc, argv, 0, &allow_launch, inst, &inst->cfg)) exit(1); /* pre-defaults pass to get -class */ do_defaults(NULL, &inst->cfg); if (do_cmdline(argc, argv, 1, &allow_launch, inst, &inst->cfg)) exit(1); /* post-defaults, do everything */ cmdline_run_saved(&inst->cfg); if (loaded_session) allow_launch = TRUE; if ((!allow_launch || !cfg_launchable(&inst->cfg)) && !cfgbox(&inst->cfg)) exit(0); /* config box hit Cancel */ } if (!compound_text_atom) compound_text_atom = gdk_atom_intern("COMPOUND_TEXT", FALSE); if (!utf8_string_atom) utf8_string_atom = gdk_atom_intern("UTF8_STRING", FALSE); inst->area = gtk_drawing_area_new(); setup_fonts_ucs(inst); init_cutbuffers(); inst->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); if (inst->cfg.winclass[0]) gtk_window_set_wmclass(GTK_WINDOW(inst->window), inst->cfg.winclass, inst->cfg.winclass); /* * Set up the colour map. */ palette_reset(inst); inst->width = inst->cfg.width; inst->height = inst->cfg.height; gtk_drawing_area_size(GTK_DRAWING_AREA(inst->area), inst->font_width * inst->cfg.width + 2*inst->cfg.window_border, inst->font_height * inst->cfg.height + 2*inst->cfg.window_border); inst->sbar_adjust = GTK_ADJUSTMENT(gtk_adjustment_new(0,0,0,0,0,0)); inst->sbar = gtk_vscrollbar_new(inst->sbar_adjust); inst->hbox = GTK_BOX(gtk_hbox_new(FALSE, 0)); /* * We always create the scrollbar; it remains invisible if * unwanted, so we can pop it up quickly if it suddenly becomes * desirable. */ if (inst->cfg.scrollbar_on_left) gtk_box_pack_start(inst->hbox, inst->sbar, FALSE, FALSE, 0); gtk_box_pack_start(inst->hbox, inst->area, TRUE, TRUE, 0); if (!inst->cfg.scrollbar_on_left) gtk_box_pack_start(inst->hbox, inst->sbar, FALSE, FALSE, 0); gtk_container_add(GTK_CONTAINER(inst->window), GTK_WIDGET(inst->hbox)); set_geom_hints(inst); gtk_widget_show(inst->area); if (inst->cfg.scrollbar) gtk_widget_show(inst->sbar); else gtk_widget_hide(inst->sbar); gtk_widget_show(GTK_WIDGET(inst->hbox)); if (inst->gotpos) { int x = inst->xpos, y = inst->ypos; |
︙ | ︙ | |||
3752 3753 3754 3755 3756 3757 3758 | GTK_SIGNAL_FUNC(motion_event), inst); gtk_signal_connect(GTK_OBJECT(inst->area), "selection_received", GTK_SIGNAL_FUNC(selection_received), inst); gtk_signal_connect(GTK_OBJECT(inst->area), "selection_get", GTK_SIGNAL_FUNC(selection_get), inst); gtk_signal_connect(GTK_OBJECT(inst->area), "selection_clear_event", GTK_SIGNAL_FUNC(selection_clear), inst); | < < < < | | 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 | GTK_SIGNAL_FUNC(motion_event), inst); gtk_signal_connect(GTK_OBJECT(inst->area), "selection_received", GTK_SIGNAL_FUNC(selection_received), inst); gtk_signal_connect(GTK_OBJECT(inst->area), "selection_get", GTK_SIGNAL_FUNC(selection_get), inst); gtk_signal_connect(GTK_OBJECT(inst->area), "selection_clear_event", GTK_SIGNAL_FUNC(selection_clear), inst); if (inst->cfg.scrollbar) gtk_signal_connect(GTK_OBJECT(inst->sbar_adjust), "value_changed", GTK_SIGNAL_FUNC(scrollbar_moved), inst); gtk_widget_add_events(GTK_WIDGET(inst->area), GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_BUTTON_MOTION_MASK); |
︙ | ︙ | |||
3856 3857 3858 3859 3860 3861 3862 | inst->blankcursor = make_mouse_ptr(inst, -1); make_mouse_ptr(inst, -2); /* clean up cursor font */ inst->currcursor = inst->textcursor; show_mouseptr(inst, 1); inst->eventlogstuff = eventlogstuff_new(); | < < | | | < | 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 | inst->blankcursor = make_mouse_ptr(inst, -1); make_mouse_ptr(inst, -2); /* clean up cursor font */ inst->currcursor = inst->textcursor; show_mouseptr(inst, 1); inst->eventlogstuff = eventlogstuff_new(); inst->term = term_init(&inst->cfg, &inst->ucsdata, inst); inst->logctx = log_init(inst, &inst->cfg); term_provide_logctx(inst->term, inst->logctx); uxsel_init(); term_size(inst->term, inst->cfg.height, inst->cfg.width, inst->cfg.savelines); start_backend(inst); ldisc_send(inst->ldisc, NULL, 0, 0);/* cause ldisc to notice changes */ /* now we're reday to deal with the child exit handler being * called */ |
︙ | ︙ |
Changes to unix/unix.h.
︙ | ︙ | |||
9 10 11 12 13 14 15 | #include <stdint.h> /* C99 int types */ #ifndef NO_LIBDL #include <dlfcn.h> /* Dynamic library loading */ #endif /* NO_LIBDL */ #include "charset.h" struct Filename { | | | | < > > > | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | #include <stdint.h> /* C99 int types */ #ifndef NO_LIBDL #include <dlfcn.h> /* Dynamic library loading */ #endif /* NO_LIBDL */ #include "charset.h" struct Filename { char path[FILENAME_MAX]; }; FILE *f_open(struct Filename, char const *, int); struct FontSpec { char name[256]; }; typedef void *Context; /* FIXME: probably needs changing */ typedef int OSSocket; #define OSSOCKET_DEFINED /* stop network.h using its default */ extern Backend pty_backend; typedef uint32_t uint32; /* C99: uint32_t defined in stdint.h */ #define PUTTY_UINT32_DEFINED /* * Under GTK, we send MA_CLICK _and_ MA_2CLK, or MA_CLICK _and_ |
︙ | ︙ | |||
53 54 55 56 57 58 59 60 61 62 63 64 65 66 | #define SEL_NL { 10 } /* Simple wraparound timer function */ unsigned long getticks(void); /* based on gettimeofday(2) */ #define GETTICKCOUNT getticks #define TICKSPERSEC 1000 /* we choose to use milliseconds */ #define CURSORBLINK 450 /* no standard way to set this */ #define WCHAR wchar_t #define BYTE unsigned char /* * Unix-specific global flag * | > > > > > | 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | #define SEL_NL { 10 } /* Simple wraparound timer function */ unsigned long getticks(void); /* based on gettimeofday(2) */ #define GETTICKCOUNT getticks #define TICKSPERSEC 1000 /* we choose to use milliseconds */ #define CURSORBLINK 450 /* no standard way to set this */ /* getticks() works using gettimeofday(), so it's vulnerable to system clock * changes causing chaos. Therefore, we provide a compensation mechanism. */ #define TIMING_SYNC #define TIMING_SYNC_ANOW extern long tickcount_offset; #define WCHAR wchar_t #define BYTE unsigned char /* * Unix-specific global flag * |
︙ | ︙ | |||
78 79 80 81 82 83 84 | int font_dimension(void *frontend, int which);/* 0 for width, 1 for height */ long get_windowid(void *frontend); /* Things gtkdlg.c needs from pterm.c */ void *get_window(void *frontend); /* void * to avoid depending on gtk.h */ /* Things pterm.c needs from gtkdlg.c */ | | < < < < < | | 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | int font_dimension(void *frontend, int which);/* 0 for width, 1 for height */ long get_windowid(void *frontend); /* Things gtkdlg.c needs from pterm.c */ void *get_window(void *frontend); /* void * to avoid depending on gtk.h */ /* Things pterm.c needs from gtkdlg.c */ int do_config_box(const char *title, Config *cfg, int midsession, int protcfginfo); void fatal_message_box(void *window, char *msg); void about_box(void *window); void *eventlogstuff_new(void); void showeventlog(void *estuff, void *parentwin); void logevent_dlg(void *estuff, const char *string); int reallyclose(void *frontend); /* Things pterm.c needs from {ptermm,uxputty}.c */ char *make_default_wintitle(char *hostname); int process_nonoption_arg(char *arg, Config *cfg, int *allow_launch); /* pterm.c needs this special function in xkeysym.c */ int keysym_to_unicode(int keysym); /* Things uxstore.c needs from pterm.c */ char *x_get_default(const char *key); |
︙ | ︙ | |||
149 150 151 152 153 154 155 | #define stricmp strcasecmp /* BSD-semantics version of signal(), and another helpful function */ void (*putty_signal(int sig, void (*func)(int)))(int); void block_signal(int sig, int block_it); /* uxmisc.c */ | | < < < | 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | #define stricmp strcasecmp /* BSD-semantics version of signal(), and another helpful function */ void (*putty_signal(int sig, void (*func)(int)))(int); void block_signal(int sig, int block_it); /* uxmisc.c */ int cloexec(int); /* * Exports from unicode.c. */ struct unicode_data; int init_ucs(struct unicode_data *ucsdata, char *line_codepage, int utf8_override, int font_charset, int vtmode); |
︙ | ︙ |
Changes to unix/ux_x11.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | #include <stdlib.h> #include <errno.h> #include "putty.h" #include "ssh.h" #include "network.h" | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | #include <stdlib.h> #include <errno.h> #include "putty.h" #include "ssh.h" #include "network.h" void platform_get_x11_auth(struct X11Display *disp, const Config *cfg) { char *xauthfile; int needs_free; /* * Find the .Xauthority file. */ |
︙ | ︙ |
Changes to unix/uxagentc.c.
︙ | ︙ | |||
13 14 15 16 17 18 19 | #include "putty.h" #include "misc.h" #include "tree234.h" #include "puttymem.h" int agent_exists(void) { | | < | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | #include "putty.h" #include "misc.h" #include "tree234.h" #include "puttymem.h" int agent_exists(void) { if (getenv("SSH_AUTH_SOCK") != NULL) return TRUE; return FALSE; } static tree234 *agent_connections; struct agent_connection { int fd; |
︙ | ︙ | |||
71 72 73 74 75 76 77 | if (conn->retbuf != conn->sizebuf) sfree(conn->retbuf); conn->retbuf = NULL; conn->retlen = 0; goto done; } conn->retlen += ret; if (conn->retsize == 4 && conn->retlen == 4) { | | > | 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | if (conn->retbuf != conn->sizebuf) sfree(conn->retbuf); conn->retbuf = NULL; conn->retlen = 0; goto done; } conn->retlen += ret; if (conn->retsize == 4 && conn->retlen == 4) { conn->retsize = GET_32BIT(conn->retbuf); if (conn->retsize <= 0) { conn->retbuf = NULL; conn->retlen = 0; goto done; } conn->retsize += 4; assert(conn->retbuf == conn->sizebuf); conn->retbuf = snewn(conn->retsize, char); memcpy(conn->retbuf, conn->sizebuf, 4); } if (conn->retlen < conn->retsize) return 0; /* more data to come */ |
︙ | ︙ |
Changes to unix/uxcfg.c.
︙ | ︙ | |||
12 13 14 15 16 17 18 | void unix_setup_config_box(struct controlbox *b, int midsession, int protocol) { struct controlset *s; union control *c; /* | | | | | | | | | > | | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | void unix_setup_config_box(struct controlbox *b, int midsession, int protocol) { struct controlset *s; union control *c; /* * The Config structure contains two Unix-specific elements * which are not configured in here: stamp_utmp and * login_shell. This is because pterm does not put up a * configuration box right at the start, which is the only time * when these elements would be useful to configure. */ /* * On Unix, we don't have a drop-down list for the printer * control. */ s = ctrl_getset(b, "Terminal", "printing", "Remote-controlled printing"); assert(s->ncontrols == 1 && s->ctrls[0]->generic.type == CTRL_EDITBOX); s->ctrls[0]->editbox.has_list = 0; /* * Unix supports a local-command proxy. This also means we must * adjust the text on the `Telnet command' control. */ if (!midsession) { int i; s = ctrl_getset(b, "Connection/Proxy", "basics", NULL); for (i = 0; i < s->ncontrols; i++) { c = s->ctrls[i]; if (c->generic.type == CTRL_RADIO && c->generic.context.i == offsetof(Config, proxy_type)) { assert(c->generic.handler == dlg_stdradiobutton_handler); c->radio.nbuttons++; c->radio.buttons = sresize(c->radio.buttons, c->radio.nbuttons, char *); c->radio.buttons[c->radio.nbuttons-1] = dupstr("Local"); c->radio.buttondata = sresize(c->radio.buttondata, c->radio.nbuttons, intorptr); c->radio.buttondata[c->radio.nbuttons-1] = I(PROXY_CMD); break; } } for (i = 0; i < s->ncontrols; i++) { c = s->ctrls[i]; if (c->generic.type == CTRL_EDITBOX && c->generic.context.i == offsetof(Config, proxy_telnet_command)) { assert(c->generic.handler == dlg_stdeditbox_handler); sfree(c->generic.label); c->generic.label = dupstr("Telnet command, or local" " proxy command"); break; } } } |
︙ | ︙ |
Changes to unix/uxcons.c.
1 2 3 4 5 6 7 8 9 | /* * uxcons.c: various interactive-prompt routines shared between the * Unix console PuTTY tools */ #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <assert.h> | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | /* * uxcons.c: various interactive-prompt routines shared between the * Unix console PuTTY tools */ #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <assert.h> #include <termios.h> #include <unistd.h> #include "putty.h" #include "storage.h" #include "ssh.h" int console_batch_mode = FALSE; |
︙ | ︙ | |||
66 67 68 69 70 71 72 | { } void notify_remote_exit(void *frontend) { } | | | 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | { } void notify_remote_exit(void *frontend) { } void timer_change_notify(long next) { } int verify_ssh_host_key(void *frontend, char *host, int port, char *keytype, char *keystr, char *fingerprint, void (*callback)(void *ctx, int result), void *ctx) { |
︙ | ︙ | |||
231 232 233 234 235 236 237 | } } /* * Ask whether to wipe a session log file before writing to it. * Returns 2 for wipe, 1 for append, 0 for cancel (don't log). */ | | | | | 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 | } } /* * Ask whether to wipe a session log file before writing to it. * Returns 2 for wipe, 1 for append, 0 for cancel (don't log). */ int askappend(void *frontend, Filename filename, void (*callback)(void *ctx, int result), void *ctx) { static const char msgtemplate[] = "The session log file \"%.*s\" already exists.\n" "You can overwrite it with a new session log,\n" "append your session log to the end of it,\n" "or disable session logging for this session.\n" "Enter \"y\" to wipe the file, \"n\" to append to it,\n" "or just press Return to disable logging.\n" "Wipe the log file? (y/n, Return cancels logging) "; static const char msgtemplate_batch[] = "The session log file \"%.*s\" already exists.\n" "Logging will not be enabled.\n"; char line[32]; struct termios cf; premsg(&cf); if (console_batch_mode) { fprintf(stderr, msgtemplate_batch, FILENAME_MAX, filename.path); fflush(stderr); return 0; } fprintf(stderr, msgtemplate, FILENAME_MAX, filename.path); fflush(stderr); { struct termios oldmode, newmode; tcgetattr(0, &oldmode); newmode = oldmode; newmode.c_lflag |= ECHO | ISIG | ICANON; |
︙ | ︙ | |||
317 318 319 320 321 322 323 | { console_logctx = logctx; } void logevent(void *frontend, const char *string) { struct termios cf; | < | < | | | | | | > | < < < < | < < < < < < < < < < | | | < | < < | | | | | | | | | < < < < < < < > | < | | < < < | < | < < < | < < | | | 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 | { console_logctx = logctx; } void logevent(void *frontend, const char *string) { struct termios cf; premsg(&cf); if (console_logctx) log_eventlog(console_logctx, string); postmsg(&cf); } /* * Special function to print text to the console for password * prompts and the like. Uses /dev/tty or stderr, in that order of * preference; also sanitises escape sequences out of the text, on * the basis that it might have been sent by a hostile SSH server * doing malicious keyboard-interactive. */ static void console_prompt_text(FILE **confp, const char *data, int len) { int i; if (!*confp) { if ((*confp = fopen("/dev/tty", "w")) == NULL) *confp = stderr; } for (i = 0; i < len; i++) if ((data[i] & 0x60) || (data[i] == '\n')) fputc(data[i], *confp); fflush(*confp); } int console_get_userpass_input(prompts_t *p, unsigned char *in, int inlen) { size_t curr_prompt; FILE *confp = NULL; /* * Zero all the results, in case we abort half-way through. */ { int i; for (i = 0; i < p->n_prompts; i++) memset(p->prompts[i]->result, 0, p->prompts[i]->result_len); } if (p->n_prompts && console_batch_mode) return 0; /* * Preamble. */ /* We only print the `name' caption if we have to... */ if (p->name_reqd && p->name) { size_t l = strlen(p->name); console_prompt_text(&confp, p->name, l); if (p->name[l-1] != '\n') console_prompt_text(&confp, "\n", 1); } /* ...but we always print any `instruction'. */ if (p->instruction) { size_t l = strlen(p->instruction); console_prompt_text(&confp, p->instruction, l); if (p->instruction[l-1] != '\n') console_prompt_text(&confp, "\n", 1); } for (curr_prompt = 0; curr_prompt < p->n_prompts; curr_prompt++) { struct termios oldmode, newmode; int i; prompt_t *pr = p->prompts[curr_prompt]; tcgetattr(0, &oldmode); newmode = oldmode; newmode.c_lflag |= ISIG | ICANON; if (!pr->echo) newmode.c_lflag &= ~ECHO; else newmode.c_lflag |= ECHO; tcsetattr(0, TCSANOW, &newmode); console_prompt_text(&confp, pr->prompt, strlen(pr->prompt)); i = read(0, pr->result, pr->result_len - 1); tcsetattr(0, TCSANOW, &oldmode); if (i > 0 && pr->result[i-1] == '\n') i--; pr->result[i] = '\0'; if (!pr->echo) console_prompt_text(&confp, "\n", 1); } if (confp && confp != stderr) fclose(confp); return 1; /* success */ } void frontend_keypress(void *handle) { /* |
︙ | ︙ |
Changes to unix/uxgen.c.
︙ | ︙ | |||
22 23 24 25 26 27 28 | } ngot = 0; while (ngot < len) { ret = read(fd, buf+ngot, len-ngot); if (ret < 0) { close(fd); | < | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | } ngot = 0; while (ngot < len) { ret = read(fd, buf+ngot, len-ngot); if (ret < 0) { close(fd); perror("puttygen: unable to read /dev/random"); return NULL; } ngot += ret; } close(fd); |
︙ | ︙ |
Changes to unix/uxgss.c.
︙ | ︙ | |||
49 50 51 52 53 54 55 | #undef BIND_GSS_FN ssh_gssapi_bind_fns(lib); } /* Dynamically load gssapi libs. */ | | < | 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | #undef BIND_GSS_FN ssh_gssapi_bind_fns(lib); } /* Dynamically load gssapi libs. */ struct ssh_gss_liblist *ssh_gss_setup(const Config *cfg) { void *gsslib; struct ssh_gss_liblist *list = snew(struct ssh_gss_liblist); list->libraries = snewn(4, struct ssh_gss_library); list->nlibraries = 0; /* Heimdal's GSSAPI Library */ if ((gsslib = dlopen("libgssapi.so.2", RTLD_LAZY)) != NULL) |
︙ | ︙ | |||
74 75 76 77 78 79 80 | /* Sun's GSSAPI Library */ if ((gsslib = dlopen("libgss.so.1", RTLD_LAZY)) != NULL) gss_init(&list->libraries[list->nlibraries++], gsslib, 2, "Using GSSAPI from libgss.so.1"); /* User-specified GSSAPI library */ | | | | | 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | /* Sun's GSSAPI Library */ if ((gsslib = dlopen("libgss.so.1", RTLD_LAZY)) != NULL) gss_init(&list->libraries[list->nlibraries++], gsslib, 2, "Using GSSAPI from libgss.so.1"); /* User-specified GSSAPI library */ if (cfg->ssh_gss_custom.path[0] && (gsslib = dlopen(cfg->ssh_gss_custom.path, RTLD_LAZY)) != NULL) gss_init(&list->libraries[list->nlibraries++], gsslib, 3, dupprintf("Using GSSAPI from user-specified" " library '%s'", cfg->ssh_gss_custom.path)); return list; } void ssh_gss_cleanup(struct ssh_gss_liblist *list) { int i; |
︙ | ︙ | |||
126 127 128 129 130 131 132 | * library structure containing pointers to the functions we linked * against. */ #include <gssapi/gssapi.h> /* Dynamically load gssapi libs. */ | | | 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | * library structure containing pointers to the functions we linked * against. */ #include <gssapi/gssapi.h> /* Dynamically load gssapi libs. */ struct ssh_gss_liblist *ssh_gss_setup(const Config *cfg) { struct ssh_gss_liblist *list = snew(struct ssh_gss_liblist); list->libraries = snew(struct ssh_gss_library); list->nlibraries = 1; list->libraries[0].gsslogmsg = "Using statically linked GSSAPI"; |
︙ | ︙ |
Changes to unix/uxmisc.c.
1 2 3 4 5 6 7 8 | /* * PuTTY miscellaneous Unix stuff */ #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <assert.h> | < < > > > > | < | | < < < < < < < < < < < < < | | | < | | > | < < < < < | | | < < < < < < < < < < < < < < < < | < < < < < < < < < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | /* * PuTTY miscellaneous Unix stuff */ #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <assert.h> #include <unistd.h> #include <sys/time.h> #include <sys/types.h> #include <pwd.h> #include "putty.h" long tickcount_offset = 0; unsigned long getticks(void) { struct timeval tv; gettimeofday(&tv, NULL); /* * We want to use milliseconds rather than microseconds, * because we need a decent number of them to fit into a 32-bit * word so it can be used for keepalives. */ return tv.tv_sec * 1000 + tv.tv_usec / 1000 + tickcount_offset; } Filename filename_from_str(const char *str) { Filename ret; strncpy(ret.path, str, sizeof(ret.path)); ret.path[sizeof(ret.path)-1] = '\0'; return ret; } const char *filename_to_str(const Filename *fn) { return fn->path; } int filename_equal(Filename f1, Filename f2) { return !strcmp(f1.path, f2.path); } int filename_is_null(Filename fn) { return !*fn.path; } #ifdef DEBUG static FILE *debug_fp = NULL; void dputs(char *buf) { |
︙ | ︙ | |||
165 166 167 168 169 170 171 | "PuTTY Master Key (RSA), 1024-bit:\n" " " PGP_RSA_MASTER_KEY_FP "\n" "PuTTY Master Key (DSA), 1024-bit:\n" " " PGP_DSA_MASTER_KEY_FP "\n", stdout); } /* | | < < < < < < < | | < < < | < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | "PuTTY Master Key (RSA), 1024-bit:\n" " " PGP_RSA_MASTER_KEY_FP "\n" "PuTTY Master Key (DSA), 1024-bit:\n" " " PGP_DSA_MASTER_KEY_FP "\n", stdout); } /* * Set FD_CLOEXEC on a file descriptor */ int cloexec(int fd) { int fdflags; fdflags = fcntl(fd, F_GETFD); if (fdflags == -1) return -1; return fcntl(fd, F_SETFD, fdflags | FD_CLOEXEC); } FILE *f_open(struct Filename filename, char const *mode, int is_private) { if (!is_private) { return fopen(filename.path, mode); } else { int fd; assert(mode[0] == 'w'); /* is_private is meaningless for read, and tricky for append */ fd = open(filename.path, O_WRONLY | O_CREAT | O_TRUNC, 0700); if (fd < 0) return NULL; return fdopen(fd, mode); } } |
Changes to unix/uxnet.c.
︙ | ︙ | |||
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | struct Socket_tag { struct socket_function_table *fn; /* the above variable absolutely *must* be the first in this structure */ const char *error; int s; Plug plug; bufchain output_data; int connected; /* irrelevant for listening sockets */ int writable; int frozen; /* this causes readability notifications to be ignored */ int localhost_only; /* for listening sockets */ char oobdata[1]; int sending_oob; int oobpending; /* is there OOB data available to read? */ int oobinline; | > > > < < | 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | struct Socket_tag { struct socket_function_table *fn; /* the above variable absolutely *must* be the first in this structure */ const char *error; int s; Plug plug; void *private_ptr; bufchain output_data; int connected; /* irrelevant for listening sockets */ int writable; int frozen; /* this causes readability notifications to be ignored */ int frozen_readable; /* this means we missed at least one readability * notification while we were frozen */ int localhost_only; /* for listening sockets */ char oobdata[1]; int sending_oob; int oobpending; /* is there OOB data available to read? */ int oobinline; int pending_error; /* in case send() returns error */ int listener; int nodelay, keepalive; /* for connect()-type sockets */ int privport, port; /* and again */ SockAddr addr; SockAddrStep step; /* |
︙ | ︙ | |||
311 312 313 314 315 316 317 | return FALSE; } #endif } void sk_getaddr(SockAddr addr, char *buf, int buflen) { | > > > | | 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 | return FALSE; } #endif } void sk_getaddr(SockAddr addr, char *buf, int buflen) { /* XXX not clear what we should return for Unix-domain sockets; let's * hope the question never arises */ assert(addr->superfamily != UNIX); if (addr->superfamily == UNRESOLVED) { strncpy(buf, addr->hostname, buflen); buf[buflen-1] = '\0'; } else { #ifndef NO_IPV6 if (getnameinfo(addr->ais->ai_addr, addr->ais->ai_addrlen, buf, buflen, NULL, 0, NI_NUMERICHOST) != 0) { buf[0] = '\0'; |
︙ | ︙ | |||
333 334 335 336 337 338 339 | a.s_addr = htonl(addr->addresses[0]); strncpy(buf, inet_ntoa(a), buflen); buf[buflen-1] = '\0'; #endif } } | < < < < < < < < < | | 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 | a.s_addr = htonl(addr->addresses[0]); strncpy(buf, inet_ntoa(a), buflen); buf[buflen-1] = '\0'; #endif } } int sk_hostname_is_local(char *name) { return !strcmp(name, "localhost") || !strcmp(name, "::1") || !strncmp(name, "127.", 4); } #define ipv4_is_loopback(addr) \ |
︙ | ︙ | |||
389 390 391 392 393 394 395 | assert(SOCKADDR_FAMILY(addr, step) == AF_INET); a.s_addr = htonl(addr->addresses[0]); return ipv4_is_loopback(a); #endif } } | < < < < < | 384 385 386 387 388 389 390 391 392 393 394 395 396 397 | assert(SOCKADDR_FAMILY(addr, step) == AF_INET); a.s_addr = htonl(addr->addresses[0]); return ipv4_is_loopback(a); #endif } } int sk_addrtype(SockAddr addr) { SockAddrStep step; int family; START_STEP(addr, step); family = SOCKADDR_FAMILY(addr, step); |
︙ | ︙ | |||
472 473 474 475 476 477 478 | * so we don't need to do anything here. :-) */ } static void sk_tcp_close(Socket s); static int sk_tcp_write(Socket s, const char *data, int len); static int sk_tcp_write_oob(Socket s, const char *data, int len); | | > | | > | < > < < | 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 | * so we don't need to do anything here. :-) */ } static void sk_tcp_close(Socket s); static int sk_tcp_write(Socket s, const char *data, int len); static int sk_tcp_write_oob(Socket s, const char *data, int len); static void sk_tcp_set_private_ptr(Socket s, void *ptr); static void *sk_tcp_get_private_ptr(Socket s); static void sk_tcp_set_frozen(Socket s, int is_frozen); static const char *sk_tcp_socket_error(Socket s); static struct socket_function_table tcp_fn_table = { sk_tcp_plug, sk_tcp_close, sk_tcp_write, sk_tcp_write_oob, sk_tcp_flush, sk_tcp_set_private_ptr, sk_tcp_get_private_ptr, sk_tcp_set_frozen, sk_tcp_socket_error }; Socket sk_register(OSSocket sockfd, Plug plug) { Actual_Socket ret; /* * Create Socket structure. */ ret = snew(struct Socket_tag); ret->fn = &tcp_fn_table; ret->error = NULL; ret->plug = plug; bufchain_init(&ret->output_data); ret->writable = 1; /* to start with */ ret->sending_oob = 0; ret->frozen = 1; ret->frozen_readable = 0; ret->localhost_only = 0; /* unused, but best init anyway */ ret->pending_error = 0; ret->oobpending = FALSE; ret->listener = 0; ret->parent = ret->child = NULL; ret->addr = NULL; ret->connected = 1; ret->s = sockfd; |
︙ | ︙ | |||
535 536 537 538 539 540 541 | static int try_connect(Actual_Socket sock) { int s; union sockaddr_union u; const union sockaddr_union *sa; int err = 0; short localport; | | | 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 | static int try_connect(Actual_Socket sock) { int s; union sockaddr_union u; const union sockaddr_union *sa; int err = 0; short localport; int fl, salen, family; /* * Remove the socket from the tree before we overwrite its * internal socket id, because that forms part of the tree's * sorting criterion. We'll add it back before exiting this * function, whether we changed anything or not. */ |
︙ | ︙ | |||
567 568 569 570 571 572 573 | goto ret; } cloexec(s); if (sock->oobinline) { int b = TRUE; | | < < < < < | < < < < < | < < < < < | 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 | goto ret; } cloexec(s); if (sock->oobinline) { int b = TRUE; setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (void *) &b, sizeof(b)); } if (sock->nodelay) { int b = TRUE; setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (void *) &b, sizeof(b)); } if (sock->keepalive) { int b = TRUE; setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (void *) &b, sizeof(b)); } /* * Bind to local address. */ if (sock->privport) localport = 1023; /* count from 1023 downwards */ |
︙ | ︙ | |||
690 691 692 693 694 695 696 | break; default: assert(0 && "unknown address family"); exit(1); /* XXX: GCC doesn't understand assert() on some systems. */ } | | > > | 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 | break; default: assert(0 && "unknown address family"); exit(1); /* XXX: GCC doesn't understand assert() on some systems. */ } fl = fcntl(s, F_GETFL); if (fl != -1) fcntl(s, F_SETFL, fl | O_NONBLOCK); if ((connect(s, &(sa->sa), salen)) < 0) { if ( errno != EINPROGRESS ) { err = errno; goto ret; } } else { |
︙ | ︙ | |||
738 739 740 741 742 743 744 745 746 747 748 | ret->error = NULL; ret->plug = plug; bufchain_init(&ret->output_data); ret->connected = 0; /* to start with */ ret->writable = 0; /* to start with */ ret->sending_oob = 0; ret->frozen = 0; ret->localhost_only = 0; /* unused, but best init anyway */ ret->pending_error = 0; ret->parent = ret->child = NULL; ret->oobpending = FALSE; | > < < | 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 | ret->error = NULL; ret->plug = plug; bufchain_init(&ret->output_data); ret->connected = 0; /* to start with */ ret->writable = 0; /* to start with */ ret->sending_oob = 0; ret->frozen = 0; ret->frozen_readable = 0; ret->localhost_only = 0; /* unused, but best init anyway */ ret->pending_error = 0; ret->parent = ret->child = NULL; ret->oobpending = FALSE; ret->listener = 0; ret->addr = addr; START_STEP(ret->addr, ret->step); ret->s = -1; ret->oobinline = oobinline; ret->nodelay = nodelay; ret->keepalive = keepalive; |
︙ | ︙ | |||
791 792 793 794 795 796 797 798 799 800 801 | ret->fn = &tcp_fn_table; ret->error = NULL; ret->plug = plug; bufchain_init(&ret->output_data); ret->writable = 0; /* to start with */ ret->sending_oob = 0; ret->frozen = 0; ret->localhost_only = local_host_only; ret->pending_error = 0; ret->parent = ret->child = NULL; ret->oobpending = FALSE; | > < < < | 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 | ret->fn = &tcp_fn_table; ret->error = NULL; ret->plug = plug; bufchain_init(&ret->output_data); ret->writable = 0; /* to start with */ ret->sending_oob = 0; ret->frozen = 0; ret->frozen_readable = 0; ret->localhost_only = local_host_only; ret->pending_error = 0; ret->parent = ret->child = NULL; ret->oobpending = FALSE; ret->listener = 1; ret->addr = NULL; /* * Translate address_family from platform-independent constants * into local reality. */ address_family = (orig_address_family == ADDRTYPE_IPV4 ? AF_INET : #ifndef NO_IPV6 |
︙ | ︙ | |||
842 843 844 845 846 847 848 | return (Socket) ret; } cloexec(s); ret->oobinline = 0; | | < < < < < | 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 | return (Socket) ret; } cloexec(s); ret->oobinline = 0; setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on)); retcode = -1; addr = NULL; addrlen = -1; /* placate optimiser */ if (srcaddr != NULL) { #ifndef NO_IPV6 hints.ai_flags = AI_NUMERICHOST; |
︙ | ︙ | |||
1024 1025 1026 1027 1028 1029 1030 | default: return NULL; } return buf; } | < < < < < < < < < < < < < < < < < < < < | 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 | default: return NULL; } return buf; } /* * The function which tries to send on a socket once it's deemed * writable. */ void try_send(Actual_Socket s) { while (s->sending_oob || bufchain_size(&s->output_data) > 0) { |
︙ | ︙ | |||
1085 1086 1087 1088 1089 1090 1091 | * _in_ a call from the code we'd be calling back * to, so we'd have to make half the SSH code * reentrant. Instead we flag a pending error on * the socket, to be dealt with (by calling * plug_closing()) at some suitable future moment. */ s->pending_error = err; | < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 | * _in_ a call from the code we'd be calling back * to, so we'd have to make half the SSH code * reentrant. Instead we flag a pending error on * the socket, to be dealt with (by calling * plug_closing()) at some suitable future moment. */ s->pending_error = err; return; } } else { if (s->sending_oob) { if (nsent < len) { memmove(s->oobdata, s->oobdata+nsent, len-nsent); s->sending_oob = len - nsent; } else { s->sending_oob = 0; } } else { bufchain_consume(&s->output_data, nsent); } } } uxsel_tell(s); } static int sk_tcp_write(Socket sock, const char *buf, int len) { Actual_Socket s = (Actual_Socket) sock; /* * Add the data to the buffer list on the socket. */ bufchain_add(&s->output_data, buf, len); /* * Now try sending from the start of the buffer list. |
︙ | ︙ | |||
1158 1159 1160 1161 1162 1163 1164 | return bufchain_size(&s->output_data); } static int sk_tcp_write_oob(Socket sock, const char *buf, int len) { Actual_Socket s = (Actual_Socket) sock; | < < | 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 | return bufchain_size(&s->output_data); } static int sk_tcp_write_oob(Socket sock, const char *buf, int len) { Actual_Socket s = (Actual_Socket) sock; /* * Replace the buffer list on the socket with the data. */ bufchain_clear(&s->output_data); assert(len <= sizeof(s->oobdata)); memcpy(s->oobdata, buf, len); s->sending_oob = len; |
︙ | ︙ | |||
1183 1184 1185 1186 1187 1188 1189 | * not we should be selecting for write. */ uxsel_tell(s); return s->sending_oob; } | < < < < < < < < < < < < < < < < < < < < < < < < | 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 | * not we should be selecting for write. */ uxsel_tell(s); return s->sending_oob; } static int net_select_result(int fd, int event) { int ret; char buf[20480]; /* nice big buffer for plenty of speed */ Actual_Socket s; u_long atmark; |
︙ | ︙ | |||
1267 1268 1269 1270 1271 1272 1273 | if (s->listener) { /* * On a listening socket, the readability event means a * connection is ready to be accepted. */ union sockaddr_union su; socklen_t addrlen = sizeof(su); | < > | | > | | | | > > | 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 | if (s->listener) { /* * On a listening socket, the readability event means a * connection is ready to be accepted. */ union sockaddr_union su; socklen_t addrlen = sizeof(su); int t; /* socket of connection */ int fl; memset(&su, 0, addrlen); t = accept(s->s, &su.sa, &addrlen); if (t < 0) { break; } fl = fcntl(t, F_GETFL); if (fl != -1) fcntl(t, F_SETFL, fl | O_NONBLOCK); if (s->localhost_only && !sockaddr_is_loopback(&su.sa)) { close(t); /* someone let nonlocal through?! */ } else if (plug_accepting(s->plug, t)) { close(t); /* denied or error */ } break; } /* * If we reach here, this is not a listening socket, so * readability really means readability. */ /* In the case the socket is still frozen, we don't even bother */ if (s->frozen) { s->frozen_readable = 1; break; } /* * We have received data on the socket. For an oobinline * socket, this might be data _before_ an urgent pointer, * in which case we send it to the back end with type==1 * (data prior to urgent). */ |
︙ | ︙ | |||
1334 1335 1336 1337 1338 1339 1340 | while (s->addr && sk_nextaddr(s->addr, &s->step)) { err = try_connect(s); } } if (err != 0) return plug_closing(s->plug, strerror(err), err, 0); } else if (0 == ret) { | < < | 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 | while (s->addr && sk_nextaddr(s->addr, &s->step)) { err = try_connect(s); } } if (err != 0) return plug_closing(s->plug, strerror(err), err, 0); } else if (0 == ret) { return plug_closing(s->plug, NULL, 0, 0); } else { /* * Receiving actual data on a socket means we can * stop falling back through the candidate * addresses to connect to. */ |
︙ | ︙ | |||
1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 | plug_sent(s->plug, bufsize_after); } break; } return 1; } /* * Special error values are returned from sk_namelookup and sk_new * if there's a problem. These functions extract an error message, * or return NULL if there's no problem. */ const char *sk_addr_error(SockAddr addr) | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 | plug_sent(s->plug, bufsize_after); } break; } return 1; } /* * Deal with socket errors detected in try_send(). */ void net_pending_errors(void) { int i; Actual_Socket s; /* * This might be a fiddly business, because it's just possible * that handling a pending error on one socket might cause * others to be closed. (I can't think of any reason this might * happen in current SSH implementation, but to maintain * generality of this network layer I'll assume the worst.) * * So what we'll do is search the socket list for _one_ socket * with a pending error, and then handle it, and then search * the list again _from the beginning_. Repeat until we make a * pass with no socket errors present. That way we are * protected against the socket list changing under our feet. */ do { for (i = 0; (s = index234(sktree, i)) != NULL; i++) { if (s->pending_error) { /* * An error has occurred on this socket. Pass it to the * plug. */ plug_closing(s->plug, strerror(s->pending_error), s->pending_error, 0); break; } } } while (s); } /* * Each socket abstraction contains a `void *' private field in * which the client can keep state. */ static void sk_tcp_set_private_ptr(Socket sock, void *ptr) { Actual_Socket s = (Actual_Socket) sock; s->private_ptr = ptr; } static void *sk_tcp_get_private_ptr(Socket sock) { Actual_Socket s = (Actual_Socket) sock; return s->private_ptr; } /* * Special error values are returned from sk_namelookup and sk_new * if there's a problem. These functions extract an error message, * or return NULL if there's no problem. */ const char *sk_addr_error(SockAddr addr) |
︙ | ︙ | |||
1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 | static void sk_tcp_set_frozen(Socket sock, int is_frozen) { Actual_Socket s = (Actual_Socket) sock; if (s->frozen == is_frozen) return; s->frozen = is_frozen; uxsel_tell(s); } static void uxsel_tell(Actual_Socket s) { int rwx = 0; | > > > > > < | | | | | | | | | < | 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 | static void sk_tcp_set_frozen(Socket sock, int is_frozen) { Actual_Socket s = (Actual_Socket) sock; if (s->frozen == is_frozen) return; s->frozen = is_frozen; if (!is_frozen && s->frozen_readable) { char c; recv(s->s, &c, 1, MSG_PEEK); } s->frozen_readable = 0; uxsel_tell(s); } static void uxsel_tell(Actual_Socket s) { int rwx = 0; if (s->listener) { rwx |= 1; /* read == accept */ } else { if (!s->connected) rwx |= 2; /* write == connect */ if (s->connected && !s->frozen) rwx |= 1 | 4; /* read, except */ if (bufchain_size(&s->output_data)) rwx |= 2; /* write */ } uxsel_set(s->s, rwx, net_select_result); } int net_service_lookup(char *service) { struct servent *se; |
︙ | ︙ | |||
1476 1477 1478 1479 1480 1481 1482 | #else ret->addresses = NULL; ret->naddresses = 0; #endif ret->refcount = 1; return ret; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1429 1430 1431 1432 1433 1434 1435 | #else ret->addresses = NULL; ret->naddresses = 0; #endif ret->refcount = 1; return ret; } |
Changes to unix/uxplink.c.
︙ | ︙ | |||
59 60 61 62 63 64 65 | postmsg(&cf); if (logctx) { log_free(logctx); logctx = NULL; } cleanup_exit(1); } | < < < < < < < < < < < < | 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | postmsg(&cf); if (logctx) { log_free(logctx); logctx = NULL; } cleanup_exit(1); } void connection_fatal(void *frontend, char *p, ...) { struct termios cf; va_list ap; premsg(&cf); fprintf(stderr, "FATAL ERROR: "); va_start(ap, p); |
︙ | ︙ | |||
106 107 108 109 110 111 112 | exit(1); } static int local_tty = FALSE; /* do we have a local tty? */ static Backend *back; static void *backhandle; | | > > > > > > | > > | | > | > | | 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | exit(1); } static int local_tty = FALSE; /* do we have a local tty? */ static Backend *back; static void *backhandle; static Config cfg; /* * Default settings that are specific to pterm. */ char *platform_default_s(const char *name) { if (!strcmp(name, "TermType")) return dupstr(getenv("TERM")); if (!strcmp(name, "UserName")) return get_username(); if (!strcmp(name, "SerialLine")) return dupstr("/dev/ttyS0"); return NULL; } int platform_default_i(const char *name, int def) { if (!strcmp(name, "TermWidth") || !strcmp(name, "TermHeight")) { struct winsize size; if (ioctl(STDIN_FILENO, TIOCGWINSZ, (void *)&size) >= 0) return (!strcmp(name, "TermWidth") ? size.ws_col : size.ws_row); } return def; } FontSpec platform_default_fontspec(const char *name) { FontSpec ret; *ret.name = '\0'; return ret; } Filename platform_default_filename(const char *name) { Filename ret; if (!strcmp(name, "LogFileName")) strcpy(ret.path, "putty.log"); else *ret.path = '\0'; return ret; } char *x_get_default(const char *key) { return NULL; /* this is a stub */ } int term_ldisc(Terminal *term, int mode) |
︙ | ︙ | |||
200 201 202 203 204 205 206 | /* Helper function to extract a special character from a termios. */ static char *get_ttychar(struct termios *t, int index) { cc_t c = t->c_cc[index]; #if defined(_POSIX_VDISABLE) if (c == _POSIX_VDISABLE) | | | 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 | /* Helper function to extract a special character from a termios. */ static char *get_ttychar(struct termios *t, int index) { cc_t c = t->c_cc[index]; #if defined(_POSIX_VDISABLE) if (c == _POSIX_VDISABLE) return dupprintf(""); #endif return dupprintf("^<%d>", c); } char *get_ttymode(void *frontend, const char *mode) { /* |
︙ | ︙ | |||
381 382 383 384 385 386 387 | void cleanup_termios(void) { if (local_tty) tcsetattr(STDIN_FILENO, TCSANOW, &orig_termios); } bufchain stdout_data, stderr_data; | < | | > | > > > | | | | | | | | | | | < < < < < < < < < < < < < < | 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 | void cleanup_termios(void) { if (local_tty) tcsetattr(STDIN_FILENO, TCSANOW, &orig_termios); } bufchain stdout_data, stderr_data; int try_output(int is_stderr) { bufchain *chain = (is_stderr ? &stderr_data : &stdout_data); int fd = (is_stderr ? STDERR_FILENO : STDOUT_FILENO); void *senddata; int sendlen, ret, fl; if (bufchain_size(chain) == 0) return bufchain_size(&stdout_data) + bufchain_size(&stderr_data); fl = fcntl(fd, F_GETFL); if (fl != -1 && !(fl & O_NONBLOCK)) fcntl(fd, F_SETFL, fl | O_NONBLOCK); do { bufchain_prefix(chain, &senddata, &sendlen); ret = write(fd, senddata, sendlen); if (ret > 0) bufchain_consume(chain, ret); } while (ret == sendlen && bufchain_size(chain) != 0); if (fl != -1 && !(fl & O_NONBLOCK)) fcntl(fd, F_SETFL, fl); if (ret < 0 && errno != EAGAIN) { perror(is_stderr ? "stderr: write" : "stdout: write"); exit(1); } return bufchain_size(&stdout_data) + bufchain_size(&stderr_data); } int from_backend(void *frontend_handle, int is_stderr, const char *data, int len) { if (is_stderr) { bufchain_add(&stderr_data, data, len); return try_output(TRUE); } else { bufchain_add(&stdout_data, data, len); return try_output(FALSE); } } int from_backend_untrusted(void *frontend_handle, const char *data, int len) { /* * No "untrusted" output should get here (the way the code is * currently, it's all diverted by FLAG_STDERR). */ assert(!"Unexpected call to from_backend_untrusted()"); return 0; /* not reached */ } int get_userpass_input(prompts_t *p, unsigned char *in, int inlen) { int ret; ret = cmdline_get_passwd_input(p, in, inlen); if (ret == -1) ret = console_get_userpass_input(p, in, inlen); return ret; |
︙ | ︙ | |||
585 586 587 588 589 590 591 | static void version(void) { printf("plink: %s\n", ver); exit(1); } | < < < < < | < < < < < < | | | | | < < | | | < < < | | | | | > < < | | 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 | static void version(void) { printf("plink: %s\n", ver); exit(1); } int main(int argc, char **argv) { int sending; int portnumber = -1; int *fdlist; int fd; int i, fdcount, fdsize, fdstate; int connopen; int exitcode; int errors; int use_subsystem = 0; int got_host = FALSE; long now; fdlist = NULL; fdcount = fdsize = 0; /* * Initialise port and protocol to sensible defaults. (These * will be overridden by more or less anything.) */ default_protocol = PROT_SSH; default_port = 22; flags = FLAG_STDERR | FLAG_STDERR_TTY; stderr_tty_init(); /* * Process the command line. */ do_defaults(NULL, &cfg); loaded_session = FALSE; default_protocol = cfg.protocol; default_port = cfg.port; errors = 0; { /* * Override the default protocol if PLINK_PROTOCOL is set. */ char *p = getenv("PLINK_PROTOCOL"); if (p) { const Backend *b = backend_from_name(p); if (b) { default_protocol = cfg.protocol = b->protocol; default_port = cfg.port = b->default_port; } } } while (--argc) { char *p = *++argv; if (*p == '-') { int ret = cmdline_process_param(p, (argc > 1 ? argv[1] : NULL), 1, &cfg); if (ret == -2) { fprintf(stderr, "plink: option \"%s\" requires an argument\n", p); errors = 1; } else if (ret == 2) { --argc, ++argv; } else if (ret == 1) { continue; } else if (!strcmp(p, "-batch")) { console_batch_mode = 1; } else if (!strcmp(p, "-s")) { /* Save status to write to cfg later. */ use_subsystem = 1; } else if (!strcmp(p, "-V")) { version(); } else if (!strcmp(p, "-pgpfp")) { pgp_fingerprints(); exit(1); } else if (!strcmp(p, "-o")) { if (argc <= 1) { fprintf(stderr, "plink: option \"-o\" requires an argument\n"); errors = 1; } else { --argc; provide_xrm_string(*++argv); } } else { fprintf(stderr, "plink: unknown option \"%s\"\n", p); errors = 1; } } else if (*p) { if (!cfg_launchable(&cfg) || !(got_host || loaded_session)) { char *q = p; /* * If the hostname starts with "telnet:", set the * protocol to Telnet and process the string as a * Telnet URL. */ if (!strncmp(q, "telnet:", 7)) { char c; q += 7; if (q[0] == '/' && q[1] == '/') q += 2; cfg.protocol = PROT_TELNET; p = q; while (*p && *p != ':' && *p != '/') p++; c = *p; if (*p) *p++ = '\0'; if (c == ':') cfg.port = atoi(p); else cfg.port = -1; strncpy(cfg.host, q, sizeof(cfg.host) - 1); cfg.host[sizeof(cfg.host) - 1] = '\0'; got_host = TRUE; } else { char *r, *user, *host; /* * Before we process the [user@]host string, we * first check for the presence of a protocol * prefix (a protocol name followed by ","). */ r = strchr(p, ','); if (r) { const Backend *b; *r = '\0'; b = backend_from_name(p); if (b) { default_protocol = cfg.protocol = b->protocol; portnumber = b->default_port; } p = r + 1; } /* * A nonzero length string followed by an @ is treated |
︙ | ︙ | |||
754 755 756 757 758 759 760 | } /* * Now attempt to load a saved session with the * same name as the hostname. */ { | | | | | > | | < | > > | 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 | } /* * Now attempt to load a saved session with the * same name as the hostname. */ { Config cfg2; do_defaults(host, &cfg2); if (loaded_session || !cfg_launchable(&cfg2)) { /* No settings for this host; use defaults */ /* (or session was already loaded with -load) */ strncpy(cfg.host, host, sizeof(cfg.host) - 1); cfg.host[sizeof(cfg.host) - 1] = '\0'; cfg.port = default_port; got_host = TRUE; } else { cfg = cfg2; loaded_session = TRUE; } } if (user) { /* Patch in specified username. */ strncpy(cfg.username, user, sizeof(cfg.username) - 1); cfg.username[sizeof(cfg.username) - 1] = '\0'; } } } else { char *command; int cmdlen, cmdsize; cmdlen = cmdsize = 0; |
︙ | ︙ | |||
798 799 800 801 802 803 804 | command = sresize(command, cmdsize, char); } command[cmdlen++]=' '; /* always add trailing space */ if (--argc) p = *++argv; } if (cmdlen) command[--cmdlen]='\0'; /* change trailing blank to NUL */ | | | | | | | | < | < < < < < | < < | | > | | | | < | < < < < | < < < < < < < < < < < < < < | | > > > > | > > > > > > > > > > > > > > | | | < | < < < < < < < < < < < < < < | < < | < | | | | < < | < | < | 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 | command = sresize(command, cmdsize, char); } command[cmdlen++]=' '; /* always add trailing space */ if (--argc) p = *++argv; } if (cmdlen) command[--cmdlen]='\0'; /* change trailing blank to NUL */ cfg.remote_cmd_ptr = command; cfg.remote_cmd_ptr2 = NULL; cfg.nopty = TRUE; /* command => no terminal */ break; /* done with cmdline */ } } } if (errors) return 1; if (!cfg_launchable(&cfg) || !(got_host || loaded_session)) { usage(); } /* * Trim leading whitespace off the hostname if it's there. */ { int space = strspn(cfg.host, " \t"); memmove(cfg.host, cfg.host+space, 1+strlen(cfg.host)-space); } /* See if host is of the form user@host */ if (cfg.host[0] != '\0') { char *atsign = strrchr(cfg.host, '@'); /* Make sure we're not overflowing the user field */ if (atsign) { if (atsign - cfg.host < sizeof cfg.username) { strncpy(cfg.username, cfg.host, atsign - cfg.host); cfg.username[atsign - cfg.host] = '\0'; } memmove(cfg.host, atsign + 1, 1 + strlen(atsign + 1)); } } /* * Perform command-line overrides on session configuration. */ cmdline_run_saved(&cfg); /* * Apply subsystem status. */ if (use_subsystem) cfg.ssh_subsys = TRUE; /* * Trim a colon suffix off the hostname if it's there. */ cfg.host[strcspn(cfg.host, ":")] = '\0'; /* * Remove any remaining whitespace from the hostname. */ { int p1 = 0, p2 = 0; while (cfg.host[p2] != '\0') { if (cfg.host[p2] != ' ' && cfg.host[p2] != '\t') { cfg.host[p1] = cfg.host[p2]; p1++; } p2++; } cfg.host[p1] = '\0'; } if (!cfg.remote_cmd_ptr && !*cfg.remote_cmd && !*cfg.ssh_nc_host) flags |= FLAG_INTERACTIVE; /* * Select protocol. This is farmed out into a table in a * separate file to enable an ssh-free variant. */ back = backend_from_proto(cfg.protocol); if (back == NULL) { fprintf(stderr, "Internal fault: Unsupported protocol found\n"); return 1; } /* * Select port. */ if (portnumber != -1) cfg.port = portnumber; /* * Set up the pipe we'll use to tell us about SIGWINCH. */ if (pipe(signalpipe) < 0) { perror("pipe"); exit(1); } putty_signal(SIGWINCH, sigwinch); sk_init(); uxsel_init(); /* * Unix Plink doesn't provide any way to add forwardings after the * connection is set up, so if there are none now, we can safely set * the "simple" flag. */ if (cfg.protocol == PROT_SSH && !cfg.x11_forward && !cfg.agentfwd && cfg.portfwd[0] == '\0' && cfg.portfwd[1] == '\0') cfg.ssh_simple = TRUE; /* * Start up the connection. */ logctx = log_init(NULL, &cfg); console_provide_logctx(logctx); { const char *error; char *realhost; /* nodelay is only useful if stdin is a terminal device */ int nodelay = cfg.tcp_nodelay && isatty(0); error = back->init(NULL, &backhandle, &cfg, cfg.host, cfg.port, &realhost, nodelay, cfg.tcp_keepalives); if (error) { fprintf(stderr, "Unable to open connection:\n%s\n", error); return 1; } back->provide_logctx(backhandle, logctx); ldisc_create(&cfg, NULL, back, backhandle, NULL); sfree(realhost); } connopen = 1; /* * Set up the initial console mode. We don't care if this call * fails, because we know we aren't necessarily running in a * console. */ local_tty = (tcgetattr(STDIN_FILENO, &orig_termios) == 0); atexit(cleanup_termios); ldisc_update(NULL, 1, 1); sending = FALSE; now = GETTICKCOUNT(); while (1) { fd_set rset, wset, xset; int maxfd; int rwx; int ret; FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&xset); maxfd = 0; FD_SET_MAX(signalpipe[0], maxfd, rset); |
︙ | ︙ | |||
1028 1029 1030 1031 1032 1033 1034 | FD_SET_MAX(fd, maxfd, rset); if (rwx & 2) FD_SET_MAX(fd, maxfd, wset); if (rwx & 4) FD_SET_MAX(fd, maxfd, xset); } | < < < < < < | < | | | | < | < < > > > > | | | | | > > > > > > > > > > > > > > | | | | > > | 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 | FD_SET_MAX(fd, maxfd, rset); if (rwx & 2) FD_SET_MAX(fd, maxfd, wset); if (rwx & 4) FD_SET_MAX(fd, maxfd, xset); } do { long next, ticks; struct timeval tv, *ptv; if (run_timers(now, &next)) { ticks = next - GETTICKCOUNT(); if (ticks < 0) ticks = 0; /* just in case */ tv.tv_sec = ticks / 1000; tv.tv_usec = ticks % 1000 * 1000; ptv = &tv; } else { ptv = NULL; } ret = select(maxfd, &rset, &wset, &xset, ptv); if (ret == 0) now = next; else { long newnow = GETTICKCOUNT(); /* * Check to see whether the system clock has * changed massively during the select. */ if (newnow - now < 0 || newnow - now > next - now) { /* * If so, look at the elapsed time in the * select and use it to compute a new * tickcount_offset. */ long othernow = now + tv.tv_sec * 1000 + tv.tv_usec / 1000; /* So we'd like GETTICKCOUNT to have returned othernow, * but instead it return newnow. Hence ... */ tickcount_offset += othernow - newnow; now = othernow; } else { now = newnow; } } } while (ret < 0 && errno == EINTR); if (ret < 0) { perror("select"); exit(1); } for (i = 0; i < fdcount; i++) { |
︙ | ︙ | |||
1083 1084 1085 1086 1087 1088 1089 | if (FD_ISSET(signalpipe[0], &rset)) { char c[1]; struct winsize size; if (read(signalpipe[0], c, 1) <= 0) /* ignore error */; /* ignore its value; it'll be `x' */ | | | 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 | if (FD_ISSET(signalpipe[0], &rset)) { char c[1]; struct winsize size; if (read(signalpipe[0], c, 1) <= 0) /* ignore error */; /* ignore its value; it'll be `x' */ if (ioctl(0, TIOCGWINSZ, (void *)&size) >= 0) back->size(backhandle, size.ws_col, size.ws_row); } if (FD_ISSET(STDIN_FILENO, &rset)) { char buf[4096]; int ret; |
︙ | ︙ | |||
1116 1117 1118 1119 1120 1121 1122 | back->unthrottle(backhandle, try_output(FALSE)); } if (FD_ISSET(STDERR_FILENO, &wset)) { back->unthrottle(backhandle, try_output(TRUE)); } | < < | 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 | back->unthrottle(backhandle, try_output(FALSE)); } if (FD_ISSET(STDERR_FILENO, &wset)) { back->unthrottle(backhandle, try_output(TRUE)); } if ((!connopen || !back->connected(backhandle)) && bufchain_size(&stdout_data) == 0 && bufchain_size(&stderr_data) == 0) break; /* we closed the connection */ } exitcode = back->exitcode(backhandle); if (exitcode < 0) { fprintf(stderr, "Remote process exit code unavailable\n"); exitcode = 1; /* this is an error condition */ } cleanup_exit(exitcode); return exitcode; /* shouldn't happen, but placates gcc */ } |
Changes to unix/uxproxy.c.
︙ | ︙ | |||
25 26 27 28 29 30 31 | char *error; Plug plug; bufchain pending_output_data; bufchain pending_input_data; | | > | 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | char *error; Plug plug; bufchain pending_output_data; bufchain pending_input_data; void *privptr; }; static int localproxy_select_result(int fd, int event); /* * Trees to look up the pipe fds in. */ |
︙ | ︙ | |||
90 91 92 93 94 95 96 | return ret; } static void sk_localproxy_close (Socket s) { Local_Proxy_Socket ps = (Local_Proxy_Socket) s; | | | < < | | < > | 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | return ret; } static void sk_localproxy_close (Socket s) { Local_Proxy_Socket ps = (Local_Proxy_Socket) s; del234(localproxy_by_fromfd, ps); del234(localproxy_by_tofd, ps); uxsel_del(ps->to_cmd); uxsel_del(ps->from_cmd); close(ps->to_cmd); close(ps->from_cmd); sfree(ps); } static int localproxy_try_send(Local_Proxy_Socket ps) { |
︙ | ︙ | |||
126 127 128 129 130 131 132 | break; } else { bufchain_consume(&ps->pending_output_data, ret); sent += ret; } } | < < < < < < < < < < < < < < < < < < < < > > > > > > > > > > > > | 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | break; } else { bufchain_consume(&ps->pending_output_data, ret); sent += ret; } } if (bufchain_size(&ps->pending_output_data) == 0) uxsel_del(ps->to_cmd); else uxsel_set(ps->to_cmd, 2, localproxy_select_result); return sent; } static int sk_localproxy_write (Socket s, const char *data, int len) { Local_Proxy_Socket ps = (Local_Proxy_Socket) s; bufchain_add(&ps->pending_output_data, data, len); localproxy_try_send(ps); return bufchain_size(&ps->pending_output_data); } static int sk_localproxy_write_oob (Socket s, const char *data, int len) { /* * oob data is treated as inband; nasty, but nothing really * better we can do */ return sk_localproxy_write(s, data, len); } static void sk_localproxy_flush (Socket s) { /* Local_Proxy_Socket ps = (Local_Proxy_Socket) s; */ /* do nothing */ } static void sk_localproxy_set_private_ptr (Socket s, void *ptr) { Local_Proxy_Socket ps = (Local_Proxy_Socket) s; ps->privptr = ptr; } static void * sk_localproxy_get_private_ptr (Socket s) { Local_Proxy_Socket ps = (Local_Proxy_Socket) s; return ps->privptr; } static void sk_localproxy_set_frozen (Socket s, int is_frozen) { Local_Proxy_Socket ps = (Local_Proxy_Socket) s; if (is_frozen) uxsel_del(ps->from_cmd); |
︙ | ︙ | |||
229 230 231 232 233 234 235 | return 1; } Socket platform_new_connection(SockAddr addr, char *hostname, int port, int privport, int oobinline, int nodelay, int keepalive, | | | | > | | < < < | | | 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 | return 1; } Socket platform_new_connection(SockAddr addr, char *hostname, int port, int privport, int oobinline, int nodelay, int keepalive, Plug plug, const Config *cfg) { char *cmd; static const struct socket_function_table socket_fn_table = { sk_localproxy_plug, sk_localproxy_close, sk_localproxy_write, sk_localproxy_write_oob, sk_localproxy_flush, sk_localproxy_set_private_ptr, sk_localproxy_get_private_ptr, sk_localproxy_set_frozen, sk_localproxy_socket_error }; Local_Proxy_Socket ret; int to_cmd_pipe[2], from_cmd_pipe[2], pid; if (cfg->proxy_type != PROXY_CMD) return NULL; cmd = format_telnet_command(addr, port, cfg); ret = snew(struct Socket_localproxy_tag); ret->fn = &socket_fn_table; ret->plug = plug; ret->error = NULL; bufchain_init(&ret->pending_input_data); bufchain_init(&ret->pending_output_data); /* * Create the pipes to the proxy command, and spawn the proxy * command process. */ if (pipe(to_cmd_pipe) < 0 || pipe(from_cmd_pipe) < 0) { ret->error = dupprintf("pipe: %s", strerror(errno)); return (Socket)ret; } cloexec(to_cmd_pipe[1]); cloexec(from_cmd_pipe[0]); pid = fork(); if (pid < 0) { ret->error = dupprintf("fork: %s", strerror(errno)); return (Socket)ret; } else if (pid == 0) { close(0); close(1); dup2(to_cmd_pipe[0], 0); dup2(from_cmd_pipe[1], 1); close(to_cmd_pipe[0]); close(from_cmd_pipe[1]); fcntl(0, F_SETFD, 0); fcntl(1, F_SETFD, 0); execl("/bin/sh", "sh", "-c", cmd, (void *)NULL); _exit(255); } sfree(cmd); close(to_cmd_pipe[0]); |
︙ | ︙ |
Changes to unix/uxpterm.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | #include "putty.h" const char *const appname = "pterm"; const int use_event_log = 0; /* pterm doesn't need it */ const int new_session = 0, saved_sessions = 0; /* or these */ const int use_pty_argv = TRUE; | | | | | < | < < | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | #include "putty.h" const char *const appname = "pterm"; const int use_event_log = 0; /* pterm doesn't need it */ const int new_session = 0, saved_sessions = 0; /* or these */ const int use_pty_argv = TRUE; Backend *select_backend(Config *cfg) { return &pty_backend; } int cfgbox(Config *cfg) { /* * This is a no-op in pterm, except that we'll ensure the * protocol is set to -1 to inhibit the useless Connection * panel in the config box. */ cfg->protocol = -1; return 1; } void cleanup_exit(int code) { exit(code); } int process_nonoption_arg(char *arg, Config *cfg, int *allow_launch) { return 0; /* pterm doesn't have any. */ } char *make_default_wintitle(char *hostname) { return dupstr("pterm"); } int main(int argc, char **argv) { extern int pt_main(int argc, char **argv); extern void pty_pre_init(void); /* declared in pty.c */ cmdline_tooltype = TOOLTYPE_NONNETWORK; default_protocol = -1; pty_pre_init(); return pt_main(argc, argv); } |
Changes to unix/uxpty.c.
︙ | ︙ | |||
72 73 74 75 76 77 78 | /* * The pty_signal_pipe, along with the SIGCHLD handler, must be * process-global rather than session-specific. */ static int pty_signal_pipe[2] = { -1, -1 }; /* obviously bogus initial val */ struct pty_tag { | | | 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | /* * The pty_signal_pipe, along with the SIGCHLD handler, must be * process-global rather than session-specific. */ static int pty_signal_pipe[2] = { -1, -1 }; /* obviously bogus initial val */ struct pty_tag { Config cfg; int master_fd, slave_fd; void *frontend; char name[FILENAME_MAX]; pid_t child_pid; int term_width, term_height; int child_dead, finished; int exit_code; |
︙ | ︙ | |||
163 164 165 166 167 168 169 | * Likewise, since utmp is only used via pty_pre_init, it too must * be single-instance, so we can declare utmp-related variables * here. */ static Pty single_pty = NULL; #ifndef OMIT_UTMP | | | | 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 | * Likewise, since utmp is only used via pty_pre_init, it too must * be single-instance, so we can declare utmp-related variables * here. */ static Pty single_pty = NULL; #ifndef OMIT_UTMP static pid_t pty_utmp_helper_pid; static int pty_utmp_helper_pipe; static int pty_stamped_utmp; static struct utmpx utmp_entry; #endif /* * pty_argv is a grievous hack to allow a proper argv to be passed * through from the Unix command line. Again, it doesn't really |
︙ | ︙ | |||
266 267 268 269 270 271 272 273 274 275 276 277 278 279 | } #ifndef OMIT_UTMP static void fatal_sig_handler(int signum) { putty_signal(signum, SIG_DFL); cleanup_utmp(); raise(signum); } #endif static int pty_open_slave(Pty pty) { if (pty->slave_fd < 0) { | > | 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 | } #ifndef OMIT_UTMP static void fatal_sig_handler(int signum) { putty_signal(signum, SIG_DFL); cleanup_utmp(); setuid(getuid()); raise(signum); } #endif static int pty_open_slave(Pty pty) { if (pty->slave_fd < 0) { |
︙ | ︙ | |||
330 331 332 333 334 335 336 | got_one: /* We need to chown/chmod the /dev/ttyXX device. */ gp = getgrnam("tty"); chown(pty->name, getuid(), gp ? gp->gr_gid : -1); chmod(pty->name, 0600); #else | < < < < < < < < < < < < < < < | < > > > > > | > > > | 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 | got_one: /* We need to chown/chmod the /dev/ttyXX device. */ gp = getgrnam("tty"); chown(pty->name, getuid(), gp ? gp->gr_gid : -1); chmod(pty->name, 0600); #else pty->master_fd = open("/dev/ptmx", O_RDWR); if (pty->master_fd < 0) { perror("/dev/ptmx: open"); exit(1); } if (grantpt(pty->master_fd) < 0) { perror("grantpt"); exit(1); } if (unlockpt(pty->master_fd) < 0) { perror("unlockpt"); exit(1); } cloexec(pty->master_fd); pty->name[FILENAME_MAX-1] = '\0'; strncpy(pty->name, ptsname(pty->master_fd), FILENAME_MAX-1); #endif { /* * Set the pty master into non-blocking mode. */ int fl; fl = fcntl(pty->master_fd, F_GETFL); if (fl != -1 && !(fl & O_NONBLOCK)) fcntl(pty->master_fd, F_SETFL, fl | O_NONBLOCK); } if (!ptys_by_fd) ptys_by_fd = newtree234(pty_compare_by_fd); add234(ptys_by_fd, pty); } /* |
︙ | ︙ | |||
399 400 401 402 403 404 405 | #ifndef OMIT_UTMP pid_t pid; int pipefd[2]; #endif pty = single_pty = snew(struct pty_tag); | < > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | < < < | < < < | < < < | < < < | 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 | #ifndef OMIT_UTMP pid_t pid; int pipefd[2]; #endif pty = single_pty = snew(struct pty_tag); bufchain_init(&pty->output_data); /* set the child signal handler straight away; it needs to be set * before we ever fork. */ putty_signal(SIGCHLD, sigchld_handler); pty->master_fd = pty->slave_fd = -1; #ifndef OMIT_UTMP pty_stamped_utmp = FALSE; #endif if (geteuid() != getuid() || getegid() != getgid()) { pty_open_master(pty); } #ifndef OMIT_UTMP /* * Fork off the utmp helper. */ if (pipe(pipefd) < 0) { perror("pterm: pipe"); exit(1); } cloexec(pipefd[0]); cloexec(pipefd[1]); pid = fork(); if (pid < 0) { perror("pterm: fork"); exit(1); } else if (pid == 0) { char display[128], buffer[128]; int dlen, ret; close(pipefd[1]); /* * Now sit here until we receive a display name from the * other end of the pipe, and then stamp utmp. Unstamp utmp * again, and exit, when the pipe closes. */ dlen = 0; while (1) { ret = read(pipefd[0], buffer, lenof(buffer)); if (ret <= 0) { cleanup_utmp(); _exit(0); } else if (!pty_stamped_utmp) { if (dlen < lenof(display)) memcpy(display+dlen, buffer, min(ret, lenof(display)-dlen)); if (buffer[ret-1] == '\0') { /* * Now we have a display name. NUL-terminate * it, and stamp utmp. */ display[lenof(display)-1] = '\0'; /* * Trap as many fatal signals as we can in the * hope of having the best possible chance to * clean up utmp before termination. We are * unfortunately unprotected against SIGKILL, * but that's life. */ putty_signal(SIGHUP, fatal_sig_handler); putty_signal(SIGINT, fatal_sig_handler); putty_signal(SIGQUIT, fatal_sig_handler); putty_signal(SIGILL, fatal_sig_handler); putty_signal(SIGABRT, fatal_sig_handler); putty_signal(SIGFPE, fatal_sig_handler); putty_signal(SIGPIPE, fatal_sig_handler); putty_signal(SIGALRM, fatal_sig_handler); putty_signal(SIGTERM, fatal_sig_handler); putty_signal(SIGSEGV, fatal_sig_handler); putty_signal(SIGUSR1, fatal_sig_handler); putty_signal(SIGUSR2, fatal_sig_handler); #ifdef SIGBUS putty_signal(SIGBUS, fatal_sig_handler); #endif #ifdef SIGPOLL putty_signal(SIGPOLL, fatal_sig_handler); #endif #ifdef SIGPROF putty_signal(SIGPROF, fatal_sig_handler); #endif #ifdef SIGSYS putty_signal(SIGSYS, fatal_sig_handler); #endif #ifdef SIGTRAP putty_signal(SIGTRAP, fatal_sig_handler); #endif #ifdef SIGVTALRM putty_signal(SIGVTALRM, fatal_sig_handler); #endif #ifdef SIGXCPU putty_signal(SIGXCPU, fatal_sig_handler); #endif #ifdef SIGXFSZ putty_signal(SIGXFSZ, fatal_sig_handler); #endif #ifdef SIGIO putty_signal(SIGIO, fatal_sig_handler); #endif setup_utmp(pty->name, display); } } } } else { close(pipefd[0]); pty_utmp_helper_pid = pid; pty_utmp_helper_pipe = pipefd[1]; } #endif /* Drop privs. */ { #ifndef HAVE_NO_SETRESUID int gid = getgid(), uid = getuid(); int setresgid(gid_t, gid_t, gid_t); int setresuid(uid_t, uid_t, uid_t); setresgid(gid, gid, gid); setresuid(uid, uid, uid); #else setgid(getgid()); setuid(getuid()); #endif } } int pty_real_select_result(Pty pty, int event, int status) { char buf[4096]; |
︙ | ︙ | |||
604 605 606 607 608 609 610 | * Attempt to send data down the pty. */ pty_try_write(pty); } } if (finished && !pty->finished) { | < < < | | < | 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 | * Attempt to send data down the pty. */ pty_try_write(pty); } } if (finished && !pty->finished) { uxsel_del(pty->master_fd); pty_close(pty); pty->master_fd = -1; pty->finished = TRUE; /* * This is a slight layering-violation sort of hack: only * if we're not closing on exit (COE is set to Never, or to * Only On Clean and it wasn't a clean exit) do we output a * `terminated' message. */ if (pty->cfg.close_on_exit == FORCE_OFF || (pty->cfg.close_on_exit == AUTO && pty->exit_code != 0)) { char message[512]; if (WIFEXITED(pty->exit_code)) sprintf(message, "\r\n[pterm: process terminated with exit" " code %d]\r\n", WEXITSTATUS(pty->exit_code)); else if (WIFSIGNALED(pty->exit_code)) #ifdef HAVE_NO_STRSIGNAL sprintf(message, "\r\n[pterm: process terminated on signal" " %d]\r\n", WTERMSIG(pty->exit_code)); |
︙ | ︙ | |||
701 702 703 704 705 706 707 | * Called to set up the pty. * * Returns an error message, or NULL on success. * * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ | | < | | | < | < | | | | | | | | | | | | | | | < | 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 | * Called to set up the pty. * * Returns an error message, or NULL on success. * * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ static const char *pty_init(void *frontend, void **backend_handle, Config *cfg, char *host, int port, char **realhost, int nodelay, int keepalive) { int slavefd; pid_t pid, pgrp; #ifndef NOT_X_WINDOWS /* for Mac OS X native compilation */ long windowid; #endif Pty pty; if (single_pty) { pty = single_pty; } else { pty = snew(struct pty_tag); pty->master_fd = pty->slave_fd = -1; #ifndef OMIT_UTMP pty_stamped_utmp = FALSE; #endif } pty->frontend = frontend; *backend_handle = NULL; /* we can't sensibly use this, sadly */ pty->cfg = *cfg; /* structure copy */ pty->term_width = cfg->width; pty->term_height = cfg->height; if (pty->master_fd < 0) pty_open_master(pty); /* * Set the backspace character to be whichever of ^H and ^? is * specified by bksp_is_delete. */ { struct termios attrs; tcgetattr(pty->master_fd, &attrs); attrs.c_cc[VERASE] = cfg->bksp_is_delete ? '\177' : '\010'; tcsetattr(pty->master_fd, TCSANOW, &attrs); } #ifndef OMIT_UTMP /* * Stamp utmp (that is, tell the utmp helper process to do so), * or not. */ if (!cfg->stamp_utmp) { close(pty_utmp_helper_pipe); /* just let the child process die */ pty_utmp_helper_pipe = -1; } else { char *location = get_x_display(pty->frontend); int len = strlen(location)+1, pos = 0; /* +1 to include NUL */ while (pos < len) { int ret = write(pty_utmp_helper_pipe, location+pos, len - pos); if (ret < 0) { perror("pterm: writing to utmp helper process"); close(pty_utmp_helper_pipe); /* arrgh, just give up */ pty_utmp_helper_pipe = -1; break; } pos += ret; } } #endif #ifndef NOT_X_WINDOWS /* for Mac OS X native compilation */ windowid = get_windowid(pty->frontend); #endif |
︙ | ︙ | |||
796 797 798 799 800 801 802 | slavefd = pty_open_slave(pty); if (slavefd < 0) { perror("slave pty: open"); _exit(1); } close(pty->master_fd); | | < | < < < | < | | | > > > > | > > | | | 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 | slavefd = pty_open_slave(pty); if (slavefd < 0) { perror("slave pty: open"); _exit(1); } close(pty->master_fd); fcntl(slavefd, F_SETFD, 0); /* don't close on exec */ dup2(slavefd, 0); dup2(slavefd, 1); dup2(slavefd, 2); close(slavefd); setsid(); #ifdef TIOCSCTTY ioctl(0, TIOCSCTTY, 1); #endif pgrp = getpid(); tcsetpgrp(0, pgrp); setpgid(pgrp, pgrp); close(open(pty->name, O_WRONLY, 0)); setpgid(pgrp, pgrp); { char *term_env_var = dupprintf("TERM=%s", cfg->termtype); putenv(term_env_var); /* We mustn't free term_env_var, as putenv links it into the * environment in place. */ } #ifndef NOT_X_WINDOWS /* for Mac OS X native compilation */ { char *windowid_env_var = dupprintf("WINDOWID=%ld", windowid); putenv(windowid_env_var); /* We mustn't free windowid_env_var, as putenv links it into the * environment in place. */ } #endif { char *e = cfg->environmt; char *var, *varend, *val, *varval; while (*e) { var = e; while (*e && *e != '\t') e++; varend = e; if (*e == '\t') e++; val = e; while (*e) e++; e++; varval = dupprintf("%.*s=%s", varend-var, var, val); putenv(varval); /* * We must not free varval, since putenv links it * into the environment _in place_. Weird, but * there we go. Memory usage will be rationalised * as soon as we exec anyway. */ |
︙ | ︙ | |||
859 860 861 862 863 864 865 | * blocked during pt_main() startup. Reverse all this for our * child process. */ putty_signal(SIGINT, SIG_DFL); putty_signal(SIGQUIT, SIG_DFL); putty_signal(SIGPIPE, SIG_DFL); block_signal(SIGCHLD, 0); | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 | * blocked during pt_main() startup. Reverse all this for our * child process. */ putty_signal(SIGINT, SIG_DFL); putty_signal(SIGQUIT, SIG_DFL); putty_signal(SIGPIPE, SIG_DFL); block_signal(SIGCHLD, 0); if (pty_argv) execvp(pty_argv[0], pty_argv); else { char *shell = getenv("SHELL"); char *shellname; if (cfg->login_shell) { char *p = strrchr(shell, '/'); shellname = snewn(2+strlen(shell), char); p = p ? p+1 : shell; sprintf(shellname, "-%s", p); } else shellname = shell; execl(getenv("SHELL"), shellname, (void *)NULL); |
︙ | ︙ | |||
934 935 936 937 938 939 940 | cloexec(pty_signal_pipe[0]); cloexec(pty_signal_pipe[1]); } pty_uxsel_setup(pty); *backend_handle = pty; | | | | < < < < < < < < < | < | 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 | cloexec(pty_signal_pipe[0]); cloexec(pty_signal_pipe[1]); } pty_uxsel_setup(pty); *backend_handle = pty; *realhost = dupprintf("\0"); return NULL; } static void pty_reconfig(void *handle, Config *cfg) { Pty pty = (Pty)handle; /* * We don't have much need to reconfigure this backend, but * unfortunately we do need to pick up the setting of Close On * Exit so we know whether to give a `terminated' message. */ pty->cfg = *cfg; /* structure copy */ } /* * Stub routine (never called in pterm). */ static void pty_free(void *handle) { Pty pty = (Pty)handle; /* Either of these may fail `not found'. That's fine with us. */ del234(ptys_by_pid, pty); del234(ptys_by_fd, pty); sfree(pty); } static void pty_try_write(Pty pty) { void *data; int len, ret; |
︙ | ︙ |
Changes to unix/uxputty.c.
︙ | ︙ | |||
27 28 29 30 31 32 33 | * Clean up. */ sk_cleanup(); random_save_seed(); exit(code); } | | | | | | | | | | | > | > | 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | * Clean up. */ sk_cleanup(); random_save_seed(); exit(code); } Backend *select_backend(Config *cfg) { Backend *back = backend_from_proto(cfg->protocol); assert(back != NULL); return back; } int cfgbox(Config *cfg) { char *title = dupcat(appname, " Configuration", NULL); int ret = do_config_box(title, cfg, 0, 0); sfree(title); return ret; } static int got_host = 0; const int use_event_log = 1, new_session = 1, saved_sessions = 1; int process_nonoption_arg(char *arg, Config *cfg, int *allow_launch) { char *p, *q = arg; if (got_host) { /* * If we already have a host name, treat this argument as a * port number. NB we have to treat this as a saved -P * argument, so that it will be deferred until it's a good * moment to run it. */ int ret = cmdline_process_param("-P", arg, 1, cfg); assert(ret == 2); } else if (!strncmp(q, "telnet:", 7)) { /* * If the hostname starts with "telnet:", * set the protocol to Telnet and process * the string as a Telnet URL. */ char c; q += 7; if (q[0] == '/' && q[1] == '/') q += 2; cfg->protocol = PROT_TELNET; p = q; while (*p && *p != ':' && *p != '/') p++; c = *p; if (*p) *p++ = '\0'; if (c == ':') cfg->port = atoi(p); else cfg->port = -1; strncpy(cfg->host, q, sizeof(cfg->host) - 1); cfg->host[sizeof(cfg->host) - 1] = '\0'; got_host = 1; } else { /* * Otherwise, treat this argument as a host name. */ p = arg; while (*p && !isspace((unsigned char)*p)) p++; if (*p) *p++ = '\0'; strncpy(cfg->host, q, sizeof(cfg->host) - 1); cfg->host[sizeof(cfg->host) - 1] = '\0'; got_host = 1; } if (got_host) *allow_launch = TRUE; return 1; } |
︙ | ︙ | |||
118 119 120 121 122 123 124 | /* Try to take account of --display and what have you. */ if (!(display = gdk_get_display())) /* fall back to traditional method */ display = getenv("DISPLAY"); return dupstr(display); } | < < < < < | < < | 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | /* Try to take account of --display and what have you. */ if (!(display = gdk_get_display())) /* fall back to traditional method */ display = getenv("DISPLAY"); return dupstr(display); } int main(int argc, char **argv) { extern int pt_main(int argc, char **argv); sk_init(); flags = FLAG_VERBOSE | FLAG_INTERACTIVE; default_protocol = be_default_protocol; /* Find the appropriate default port. */ { Backend *b = backend_from_proto(default_protocol); default_port = 0; /* illegal */ if (b) default_port = b->default_port; } return pt_main(argc, argv); } |
Changes to unix/uxser.c.
︙ | ︙ | |||
56 57 58 59 60 61 62 | static tree234 *serial_by_fd = NULL; static int serial_select_result(int fd, int event); static void serial_uxsel_setup(Serial serial); static void serial_try_write(Serial serial); | | | < | | 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | static tree234 *serial_by_fd = NULL; static int serial_select_result(int fd, int event); static void serial_uxsel_setup(Serial serial); static void serial_try_write(Serial serial); static const char *serial_configure(Serial serial, Config *cfg) { struct termios options; int bflag, bval; const char *str; char *msg; if (serial->fd < 0) return "Unable to reconfigure already-closed serial connection"; tcgetattr(serial->fd, &options); /* * Find the appropriate baud rate flag. */ #define SETBAUD(x) (bflag = B ## x, bval = x) #define CHECKBAUD(x) do { if (cfg->serspeed >= x) SETBAUD(x); } while (0) SETBAUD(50); #ifdef B75 CHECKBAUD(75); #endif #ifdef B110 CHECKBAUD(110); #endif |
︙ | ︙ | |||
180 181 182 183 184 185 186 | cfsetispeed(&options, bflag); cfsetospeed(&options, bflag); msg = dupprintf("Configuring baud rate %d", bval); logevent(serial->frontend, msg); sfree(msg); options.c_cflag &= ~CSIZE; | | | < | < | | < | | | 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 | cfsetispeed(&options, bflag); cfsetospeed(&options, bflag); msg = dupprintf("Configuring baud rate %d", bval); logevent(serial->frontend, msg); sfree(msg); options.c_cflag &= ~CSIZE; switch (cfg->serdatabits) { case 5: options.c_cflag |= CS5; break; case 6: options.c_cflag |= CS6; break; case 7: options.c_cflag |= CS7; break; case 8: options.c_cflag |= CS8; break; default: return "Invalid number of data bits (need 5, 6, 7 or 8)"; } msg = dupprintf("Configuring %d data bits", cfg->serdatabits); logevent(serial->frontend, msg); sfree(msg); if (cfg->serstopbits >= 4) { options.c_cflag |= CSTOPB; } else { options.c_cflag &= ~CSTOPB; } msg = dupprintf("Configuring %d stop bits", (options.c_cflag & CSTOPB ? 2 : 1)); logevent(serial->frontend, msg); sfree(msg); options.c_iflag &= ~(IXON|IXOFF); #ifdef CRTSCTS options.c_cflag &= ~CRTSCTS; #endif #ifdef CNEW_RTSCTS options.c_cflag &= ~CNEW_RTSCTS; #endif if (cfg->serflow == SER_FLOW_XONXOFF) { options.c_iflag |= IXON | IXOFF; str = "XON/XOFF"; } else if (cfg->serflow == SER_FLOW_RTSCTS) { #ifdef CRTSCTS options.c_cflag |= CRTSCTS; #endif #ifdef CNEW_RTSCTS options.c_cflag |= CNEW_RTSCTS; #endif str = "RTS/CTS"; } else str = "no"; msg = dupprintf("Configuring %s flow control", str); logevent(serial->frontend, msg); sfree(msg); /* Parity */ if (cfg->serparity == SER_PAR_ODD) { options.c_cflag |= PARENB; options.c_cflag |= PARODD; str = "odd"; } else if (cfg->serparity == SER_PAR_EVEN) { options.c_cflag |= PARENB; options.c_cflag &= ~PARODD; str = "even"; } else { options.c_cflag &= ~PARENB; str = "no"; } |
︙ | ︙ | |||
284 285 286 287 288 289 290 | * * Returns an error message, or NULL on success. * * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ static const char *serial_init(void *frontend_handle, void **backend_handle, | | < < | < | | | | 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 | * * Returns an error message, or NULL on success. * * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ static const char *serial_init(void *frontend_handle, void **backend_handle, Config *cfg, char *host, int port, char **realhost, int nodelay, int keepalive) { Serial serial; const char *err; serial = snew(struct serial_backend_data); *backend_handle = serial; serial->frontend = frontend_handle; serial->finished = FALSE; serial->inbufsize = 0; bufchain_init(&serial->output_data); { char *msg = dupprintf("Opening serial device %s", cfg->serline); logevent(serial->frontend, msg); } serial->fd = open(cfg->serline, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK); if (serial->fd < 0) return "Unable to open serial port"; cloexec(serial->fd); err = serial_configure(serial, cfg); if (err) return err; *realhost = dupstr(cfg->serline); if (!serial_by_fd) serial_by_fd = newtree234(serial_compare_by_fd); add234(serial_by_fd, serial); serial_uxsel_setup(serial); |
︙ | ︙ | |||
352 353 354 355 356 357 358 | serial_close(serial); bufchain_clear(&serial->output_data); sfree(serial); } | | | | 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 | serial_close(serial); bufchain_clear(&serial->output_data); sfree(serial); } static void serial_reconfig(void *handle, Config *cfg) { Serial serial = (Serial) handle; /* * FIXME: what should we do if this returns an error? */ serial_configure(serial, cfg); } static int serial_select_result(int fd, int event) { Serial serial; char buf[4096]; int ret; |
︙ | ︙ |
Changes to unix/uxsftp.c.
︙ | ︙ | |||
30 31 32 33 34 35 36 | void uxsel_input_remove(int id) { } char *x_get_default(const char *key) { return NULL; /* this is a stub */ } | | | > > | | > | > | | 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | void uxsel_input_remove(int id) { } char *x_get_default(const char *key) { return NULL; /* this is a stub */ } void platform_get_x11_auth(struct X11Display *display, const Config *cfg) { /* Do nothing, therefore no auth. */ } const int platform_uses_x11_unix_by_default = TRUE; /* * Default settings that are specific to PSFTP. */ char *platform_default_s(const char *name) { return NULL; } int platform_default_i(const char *name, int def) { return def; } FontSpec platform_default_fontspec(const char *name) { FontSpec ret; *ret.name = '\0'; return ret; } Filename platform_default_filename(const char *name) { Filename ret; if (!strcmp(name, "LogFileName")) strcpy(ret.path, "putty.log"); else *ret.path = '\0'; return ret; } char *get_ttymode(void *frontend, const char *mode) { return NULL; } int get_userpass_input(prompts_t *p, unsigned char *in, int inlen) { int ret; |
︙ | ︙ | |||
117 118 119 120 121 122 123 | } struct RFile { int fd; }; RFile *open_existing_file(char *name, uint64 *size, | | < | < < < | 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | } struct RFile { int fd; }; RFile *open_existing_file(char *name, uint64 *size, unsigned long *mtime, unsigned long *atime) { int fd; RFile *ret; fd = open(name, O_RDONLY); if (fd < 0) return NULL; ret = snew(RFile); ret->fd = fd; if (size || mtime || atime) { struct stat statbuf; if (fstat(fd, &statbuf) < 0) { fprintf(stderr, "%s: stat: %s\n", name, strerror(errno)); memset(&statbuf, 0, sizeof(statbuf)); } if (size) *size = uint64_make((statbuf.st_size >> 16) >> 16, statbuf.st_size); if (mtime) *mtime = statbuf.st_mtime; if (atime) *atime = statbuf.st_atime; } return ret; } int read_from_file(RFile *f, void *buffer, int length) { |
︙ | ︙ | |||
170 171 172 173 174 175 176 | } struct WFile { int fd; char *name; }; | | | < | 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 | } struct WFile { int fd; char *name; }; WFile *open_new_file(char *name) { int fd; WFile *ret; fd = open(name, O_CREAT | O_TRUNC | O_WRONLY, 0666); if (fd < 0) return NULL; ret = snew(WFile); ret->fd = fd; ret->name = dupstr(name); |
︙ | ︙ | |||
439 440 441 442 443 444 445 | * optionally stdin. */ static int ssh_sftp_do_select(int include_stdin, int no_fds_ok) { fd_set rset, wset, xset; int i, fdcount, fdsize, *fdlist; int fd, fdstate, rwx, ret, maxfd; | | < | 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 | * optionally stdin. */ static int ssh_sftp_do_select(int include_stdin, int no_fds_ok) { fd_set rset, wset, xset; int i, fdcount, fdsize, *fdlist; int fd, fdstate, rwx, ret, maxfd; long now = GETTICKCOUNT(); fdlist = NULL; fdcount = fdsize = 0; do { /* Count the currently active fds. */ |
︙ | ︙ | |||
485 486 487 488 489 490 491 | if (rwx & 4) FD_SET_MAX(fd, maxfd, xset); } if (include_stdin) FD_SET_MAX(0, maxfd, rset); | < < < < < < < < | < | | | | < | < | > > > > | | | | | > > > > > > > > > > > > > > | | | | > > | 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 | if (rwx & 4) FD_SET_MAX(fd, maxfd, xset); } if (include_stdin) FD_SET_MAX(0, maxfd, rset); do { long next, ticks; struct timeval tv, *ptv; if (run_timers(now, &next)) { ticks = next - GETTICKCOUNT(); if (ticks <= 0) ticks = 1; /* just in case */ tv.tv_sec = ticks / 1000; tv.tv_usec = ticks % 1000 * 1000; ptv = &tv; } else { ptv = NULL; } ret = select(maxfd, &rset, &wset, &xset, ptv); if (ret == 0) now = next; else { long newnow = GETTICKCOUNT(); /* * Check to see whether the system clock has * changed massively during the select. */ if (newnow - now < 0 || newnow - now > next - now) { /* * If so, look at the elapsed time in the * select and use it to compute a new * tickcount_offset. */ long othernow = now + tv.tv_sec * 1000 + tv.tv_usec / 1000; /* So we'd like GETTICKCOUNT to have returned othernow, * but instead it return newnow. Hence ... */ tickcount_offset += othernow - newnow; now = othernow; } else { now = newnow; } } } while (ret < 0 && errno != EINTR); } while (ret == 0); if (ret < 0) { perror("select"); exit(1); } |
︙ | ︙ | |||
539 540 541 542 543 544 545 | select_result(fd, 1); if (FD_ISSET(fd, &wset)) select_result(fd, 2); } sfree(fdlist); | < < | 546 547 548 549 550 551 552 553 554 555 556 557 558 559 | select_result(fd, 1); if (FD_ISSET(fd, &wset)) select_result(fd, 2); } sfree(fdlist); return FD_ISSET(0, &rset) ? 1 : 0; } /* * Wait for some network data and process it. */ int ssh_sftp_loop_iteration(void) |
︙ | ︙ | |||
570 571 572 573 574 575 576 | buf = NULL; buflen = bufsize = 0; while (1) { ret = ssh_sftp_do_select(TRUE, no_fds_ok); if (ret < 0) { printf("connection died\n"); | < < < < < | 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 | buf = NULL; buflen = bufsize = 0; while (1) { ret = ssh_sftp_do_select(TRUE, no_fds_ok); if (ret < 0) { printf("connection died\n"); return NULL; /* woop woop */ } if (ret > 0) { if (buflen >= bufsize) { bufsize = buflen + 512; buf = sresize(buf, bufsize, char); } ret = read(0, buf+buflen, 1); if (ret < 0) { perror("read"); return NULL; } if (ret == 0) { /* eof on stdin; no error, but no answer either */ return NULL; } if (buf[buflen++] == '\n') { /* we have a full line */ return buf; } } } } /* * Main program: do platform-specific initialisation and then call * psftp_main(). */ int main(int argc, char *argv[]) { uxsel_init(); return psftp_main(argc, argv); } |
Deleted unix/uxshare.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to unix/uxstore.c.
︙ | ︙ | |||
162 163 164 165 166 167 168 | char *filename; FILE *fp; *errmsg = NULL; /* * Start by making sure the .putty directory and its sessions | | > > > | | < | | < < | < < | < < < < | | | 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 | char *filename; FILE *fp; *errmsg = NULL; /* * Start by making sure the .putty directory and its sessions * subdir actually exist. Ignore error returns from mkdir since * they're perfectly likely to be `already exists', and any * other error will trip us up later on so there's no real need * to catch it now. */ filename = make_filename(INDEX_SESSIONDIR, NULL); if (mkdir(filename, 0700) != 0) { char *filename2 = make_filename(INDEX_DIR, NULL); mkdir(filename2, 0700); sfree(filename2); mkdir(filename, 0700); } sfree(filename); filename = make_filename(INDEX_SESSION, sessionname); fp = fopen(filename, "w"); if (!fp) { *errmsg = dupprintf("Unable to create %s: %s", filename, strerror(errno)); sfree(filename); return NULL; /* can't open */ } sfree(filename); return fp; } |
︙ | ︙ | |||
301 302 303 304 305 306 307 | ret = newtree234(keycmp); while ( (line = fgetline(fp)) ) { char *value = strchr(line, '='); struct skeyval *kv; | | < < | | > > | > | 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 | ret = newtree234(keycmp); while ( (line = fgetline(fp)) ) { char *value = strchr(line, '='); struct skeyval *kv; if (!value) continue; *value++ = '\0'; value[strcspn(value, "\r\n")] = '\0'; /* trim trailing NL */ kv = snew(struct skeyval); kv->key = dupstr(line); kv->value = dupstr(value); add234(ret, kv); sfree(line); } fclose(fp); return ret; } char *read_setting_s(void *handle, const char *key, char *buffer, int buflen) { tree234 *tree = (tree234 *)handle; const char *val; struct skeyval tmp, *kv; tmp.key = key; if (tree != NULL && (kv = find234(tree, &tmp, NULL)) != NULL) { val = kv->value; assert(val != NULL); } else val = get_setting(key); if (!val) return NULL; else { strncpy(buffer, val, buflen); buffer[buflen-1] = '\0'; return buffer; } } int read_setting_i(void *handle, const char *key, int defvalue) { tree234 *tree = (tree234 *)handle; const char *val; struct skeyval tmp, *kv; |
︙ | ︙ | |||
361 362 363 364 365 366 367 | if (!val) return defvalue; else return atoi(val); } | | < < | < < | > | < | < | | | < | | | < < < < < < | | | | | 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 | if (!val) return defvalue; else return atoi(val); } int read_setting_fontspec(void *handle, const char *name, FontSpec *result) { /* * In GTK1-only PuTTY, we used to store font names simply as a * valid X font description string (logical or alias), under a * bare key such as "Font". * * In GTK2 PuTTY, we have a prefix system where "client:" * indicates a Pango font and "server:" an X one; existing * configuration needs to be reinterpreted as having the * "server:" prefix, so we change the storage key from the * provided name string (e.g. "Font") to a suffixed one * ("FontName"). */ char *suffname = dupcat(name, "Name", NULL); if (read_setting_s(handle, suffname, result->name, sizeof(result->name))) { sfree(suffname); return TRUE; /* got new-style name */ } sfree(suffname); /* Fall back to old-style name. */ memcpy(result->name, "server:", 7); if (!read_setting_s(handle, name, result->name + 7, sizeof(result->name) - 7) || !result->name[7]) { result->name[0] = '\0'; return FALSE; } else { return TRUE; } } int read_setting_filename(void *handle, const char *name, Filename *result) { return !!read_setting_s(handle, name, result->path, sizeof(result->path)); } void write_setting_fontspec(void *handle, const char *name, FontSpec result) { /* * read_setting_fontspec had to handle two cases, but when * writing our settings back out we simply always generate the * new-style name. */ char *suffname = dupcat(name, "Name", NULL); write_setting_s(handle, suffname, result.name); sfree(suffname); } void write_setting_filename(void *handle, const char *name, Filename result) { write_setting_s(handle, name, result.path); } void close_settings_r(void *handle) { tree234 *tree = (tree234 *)handle; struct skeyval *kv; |
︙ | ︙ | |||
593 594 595 596 597 598 599 600 601 602 603 604 | const char *keytype, const char *key) { FILE *rfp, *wfp; char *newtext, *line; int headerlen; char *filename, *tmpfilename; /* * Open both the old file and a new file. */ tmpfilename = make_filename(INDEX_HOSTKEYS_TMP, NULL); wfp = fopen(tmpfilename, "w"); | > > > | | < < < < < < < < < < | | < < < < | < < < < < | 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 | const char *keytype, const char *key) { FILE *rfp, *wfp; char *newtext, *line; int headerlen; char *filename, *tmpfilename; newtext = dupprintf("%s@%d:%s %s\n", keytype, port, hostname, key); headerlen = 1 + strcspn(newtext, " "); /* count the space too */ /* * Open both the old file and a new file. */ tmpfilename = make_filename(INDEX_HOSTKEYS_TMP, NULL); wfp = fopen(tmpfilename, "w"); if (!wfp) { char *dir; dir = make_filename(INDEX_DIR, NULL); mkdir(dir, 0700); sfree(dir); wfp = fopen(tmpfilename, "w"); } if (!wfp) { sfree(tmpfilename); return; } filename = make_filename(INDEX_HOSTKEYS, NULL); rfp = fopen(filename, "r"); /* * Copy all lines from the old file to the new one that _don't_ * involve the same host key identifier as the one we're adding. */ if (rfp) { while ( (line = fgetline(rfp)) ) { if (strncmp(line, newtext, headerlen)) fputs(line, wfp); } fclose(rfp); } /* * Now add the new line at the end. */ fputs(newtext, wfp); fclose(wfp); rename(tmpfilename, filename); sfree(tmpfilename); sfree(filename); sfree(newtext); } void read_random_seed(noise_consumer_t consumer) |
︙ | ︙ | |||
689 690 691 692 693 694 695 | /* * Don't truncate the random seed file if it already exists; if * something goes wrong half way through writing it, it would * be better to leave the old data there than to leave it empty. */ fd = open(fname, O_CREAT | O_WRONLY, 0600); if (fd < 0) { | < < < < < < < < | < < < < < < < < < < < < < < < < | < < < < < < | 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 | /* * Don't truncate the random seed file if it already exists; if * something goes wrong half way through writing it, it would * be better to leave the old data there than to leave it empty. */ fd = open(fname, O_CREAT | O_WRONLY, 0600); if (fd < 0) { char *dir; dir = make_filename(INDEX_DIR, NULL); mkdir(dir, 0700); sfree(dir); fd = open(fname, O_CREAT | O_WRONLY, 0600); } while (len > 0) { int ret = write(fd, data, len); if (ret <= 0) break; len -= ret; data = (char *)data + len; } close(fd); sfree(fname); } void cleanup_all(void) { } |
Changes to unix/uxucs.c.
︙ | ︙ | |||
17 18 19 20 21 22 23 | */ int is_dbcs_leadbyte(int codepage, char byte) { return 0; /* we don't do DBCS */ } | | > > > | > > > | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | */ int is_dbcs_leadbyte(int codepage, char byte) { return 0; /* we don't do DBCS */ } int mb_to_wc(int codepage, int flags, char *mbstr, int mblen, wchar_t *wcstr, int wclen) { if (codepage == DEFAULT_CODEPAGE) { int n = 0; mbstate_t state; memset(&state, 0, sizeof state); setlocale(LC_CTYPE, ""); while (mblen > 0) { size_t i = mbrtowc(wcstr+n, mbstr, (size_t)mblen, &state); if (i == (size_t)-1 || i == (size_t)-2) break; n++; mbstr += i; mblen -= i; } setlocale(LC_CTYPE, "C"); return n; } else if (codepage == CS_NONE) { int n = 0; while (mblen > 0) { wcstr[n] = 0xD800 | (mbstr[0] & 0xFF); n++; mbstr++; mblen--; } return n; } else return charset_to_unicode(&mbstr, &mblen, wcstr, wclen, codepage, NULL, NULL, 0); } int wc_to_mb(int codepage, int flags, wchar_t *wcstr, int wclen, char *mbstr, int mblen, char *defchr, int *defused, struct unicode_data *ucsdata) { /* FIXME: we should remove the defused param completely... */ if (defused) *defused = 0; if (codepage == DEFAULT_CODEPAGE) { char output[MB_LEN_MAX]; mbstate_t state; int n = 0; memset(&state, 0, sizeof state); setlocale(LC_CTYPE, ""); while (wclen > 0) { int i = wcrtomb(output, wcstr[0], &state); if (i == (size_t)-1 || i > n - mblen) break; memcpy(mbstr+n, output, i); n += i; wcstr++; wclen--; } setlocale(LC_CTYPE, "C"); return n; } else if (codepage == CS_NONE) { int n = 0; while (wclen > 0 && n < mblen) { if (*wcstr >= 0xD800 && *wcstr < 0xD900) mbstr[n++] = (*wcstr & 0xFF); |
︙ | ︙ | |||
129 130 131 132 133 134 135 | if (strstr(s, "UTF-8")) ucsdata->line_codepage = CS_UTF8; } } /* * Failing that, line_codepage should be decoded from the | | | 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | if (strstr(s, "UTF-8")) ucsdata->line_codepage = CS_UTF8; } } /* * Failing that, line_codepage should be decoded from the * specification in cfg. */ if (ucsdata->line_codepage == CS_NONE) ucsdata->line_codepage = decode_codepage(linecharset); /* * If line_codepage is _still_ CS_NONE, we assume we're using * the font's own encoding. This has been passed in to us, so |
︙ | ︙ | |||
152 153 154 155 156 157 158 | ret = 1; /* * Set up unitab_line, by translating each individual character * in the line codepage into Unicode. */ for (i = 0; i < 256; i++) { | | < | 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | ret = 1; /* * Set up unitab_line, by translating each individual character * in the line codepage into Unicode. */ for (i = 0; i < 256; i++) { char c[1], *p; wchar_t wc[1]; int len; c[0] = i; p = c; len = 1; if (ucsdata->line_codepage == CS_NONE) ucsdata->unitab_line[i] = 0xD800 | i; |
︙ | ︙ | |||
207 208 209 210 211 212 213 | } /* * Set up unitab_scoacs. The SCO Alternate Character Set is * simply CP437. */ for (i = 0; i < 256; i++) { | | < | 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 | } /* * Set up unitab_scoacs. The SCO Alternate Character Set is * simply CP437. */ for (i = 0; i < 256; i++) { char c[1], *p; wchar_t wc[1]; int len; c[0] = i; p = c; len = 1; if (1 == charset_to_unicode(&p, &len, wc, 1, CS_CP437, NULL, L"", 0)) ucsdata->unitab_scoacs[i] = wc[0]; |
︙ | ︙ | |||
249 250 251 252 253 254 255 | return "Use font encoding"; return charset_to_localenc(codepage); } const char *cp_enumerate(int index) { int charset; | > > | | < < < < | | | 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 | return "Use font encoding"; return charset_to_localenc(codepage); } const char *cp_enumerate(int index) { int charset; if (index == 0) return "Use font encoding"; charset = charset_localenc_nth(index-1); if (charset == CS_NONE) return NULL; return charset_to_localenc(charset); } int decode_codepage(char *cp_name) { if (!*cp_name) return CS_NONE; /* use font encoding */ return charset_from_localenc(cp_name); } |
Changes to version.c.
1 2 3 4 5 6 7 | /* * PuTTY version numbering */ #define STR1(x) #x #define STR(x) STR1(x) | < < < < < < < < < < < < < < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | /* * PuTTY version numbering */ #define STR1(x) #x #define STR(x) STR1(x) #if defined SNAPSHOT #if defined SVN_REV #define SNAPSHOT_TEXT STR(SNAPSHOT) ":r" STR(SVN_REV) #else #define SNAPSHOT_TEXT STR(SNAPSHOT) #endif |
︙ | ︙ |
Changes to wcwidth.c.
︙ | ︙ | |||
46 47 48 49 50 51 52 | * up a proper standard for the behavior of UTF-8 character terminals * will require a careful analysis not only of each Unicode character, * but also of each presentation form, something the author of these * routines has avoided to do so far. * * http://www.unicode.org/unicode/reports/tr11/ * | | | | | | 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | * up a proper standard for the behavior of UTF-8 character terminals * will require a careful analysis not only of each Unicode character, * but also of each presentation form, something the author of these * routines has avoided to do so far. * * http://www.unicode.org/unicode/reports/tr11/ * * Markus Kuhn -- 2003-05-20 (Unicode 4.0) * * Permission to use, copy, modify, and distribute this software * for any purpose and without fee is hereby granted. The author * disclaims all warranties with regard to this software. * * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c */ #include <wchar.h> #include "putty.h" /* for prototypes */ struct interval { int first; int last; }; /* auxiliary function for binary search in interval table */ static int bisearch(wchar_t ucs, const struct interval *table, int max) { int min = 0; int mid; if (ucs < table[0].first || ucs > table[max].last) return 0; while (max >= min) { mid = (min + max) / 2; |
︙ | ︙ | |||
117 118 119 120 121 122 123 | * ISO 8859-1 and WGL4 characters, Unicode control characters, * etc.) have a column width of 1. * * This implementation assumes that wchar_t characters are encoded * in ISO 10646. */ | | | > | | | | | < | | | | | | | | | | | | | | | | | | | | < < < | | < | | < < | < | 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | * ISO 8859-1 and WGL4 characters, Unicode control characters, * etc.) have a column width of 1. * * This implementation assumes that wchar_t characters are encoded * in ISO 10646. */ int mk_wcwidth(wchar_t ucs) { /* sorted list of non-overlapping intervals of non-spacing characters */ /* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */ static const struct interval combining[] = { { 0x0300, 0x0357 }, { 0x035D, 0x036F }, { 0x0483, 0x0486 }, { 0x0488, 0x0489 }, { 0x0591, 0x05A1 }, { 0x05A3, 0x05B9 }, { 0x05BB, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 }, { 0x05C4, 0x05C4 }, { 0x0600, 0x0603 }, { 0x0610, 0x0615 }, { 0x064B, 0x0658 }, { 0x0670, 0x0670 }, { 0x06D6, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED }, { 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A }, { 0x07A6, 0x07B0 }, { 0x0901, 0x0902 }, { 0x093C, 0x093C }, { 0x0941, 0x0948 }, { 0x094D, 0x094D }, { 0x0951, 0x0954 }, { 0x0962, 0x0963 }, { 0x0981, 0x0981 }, { 0x09BC, 0x09BC }, { 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD }, { 0x09E2, 0x09E3 }, { 0x0A01, 0x0A02 }, { 0x0A3C, 0x0A3C }, { 0x0A41, 0x0A42 }, { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D }, { 0x0A70, 0x0A71 }, { 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC }, { 0x0AC1, 0x0AC5 }, { 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD }, { 0x0AE2, 0x0AE3 }, { 0x0B01, 0x0B01 }, { 0x0B3C, 0x0B3C }, { 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 }, { 0x0B4D, 0x0B4D }, { 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 }, { 0x0BC0, 0x0BC0 }, { 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 }, { 0x0C46, 0x0C48 }, { 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 }, { 0x0CBC, 0x0CBC }, { 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD }, { 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D }, { 0x0DCA, 0x0DCA }, { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 }, { 0x0E31, 0x0E31 }, { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E }, { 0x0EB1, 0x0EB1 }, { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC }, { 0x0EC8, 0x0ECD }, { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 }, { 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E }, { 0x0F80, 0x0F84 }, { 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 }, { 0x0F99, 0x0FBC }, { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 }, { 0x1032, 0x1032 }, { 0x1036, 0x1037 }, { 0x1039, 0x1039 }, { 0x1058, 0x1059 }, { 0x1160, 0x11FF }, { 0x1712, 0x1714 }, { 0x1732, 0x1734 }, { 0x1752, 0x1753 }, { 0x1772, 0x1773 }, { 0x17B4, 0x17B5 }, { 0x17B7, 0x17BD }, { 0x17C6, 0x17C6 }, { 0x17C9, 0x17D3 }, { 0x17DD, 0x17DD }, { 0x180B, 0x180D }, { 0x18A9, 0x18A9 }, { 0x1920, 0x1922 }, { 0x1927, 0x1928 }, { 0x1932, 0x1932 }, { 0x1939, 0x193B }, { 0x200B, 0x200F }, { 0x202A, 0x202E }, { 0x2060, 0x2063 }, { 0x206A, 0x206F }, { 0x20D0, 0x20EA }, { 0x302A, 0x302F }, { 0x3099, 0x309A }, { 0xFB1E, 0xFB1E }, { 0xFE00, 0xFE0F }, { 0xFE20, 0xFE23 }, { 0xFEFF, 0xFEFF }, { 0xFFF9, 0xFFFB }, { 0x1D167, 0x1D169 }, { 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD }, { 0xE0001, 0xE0001 }, { 0xE0020, 0xE007F }, { 0xE0100, 0xE01EF } }; /* test for 8-bit control characters */ if (ucs == 0) return 0; if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0)) return -1; |
︙ | ︙ | |||
193 194 195 196 197 198 199 | (ucs >= 0x1100 && (ucs <= 0x115f || /* Hangul Jamo init. consonants */ ucs == 0x2329 || ucs == 0x232a || (ucs >= 0x2e80 && ucs <= 0xa4cf && ucs != 0x303f) || /* CJK ... Yi */ (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */ (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */ | < | | | | 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 | (ucs >= 0x1100 && (ucs <= 0x115f || /* Hangul Jamo init. consonants */ ucs == 0x2329 || ucs == 0x232a || (ucs >= 0x2e80 && ucs <= 0xa4cf && ucs != 0x303f) || /* CJK ... Yi */ (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */ (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */ (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */ (ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */ (ucs >= 0xffe0 && ucs <= 0xffe6) || (ucs >= 0x20000 && ucs <= 0x2fffd) || (ucs >= 0x30000 && ucs <= 0x3fffd))); } int mk_wcswidth(const wchar_t *pwcs, size_t n) { int w, width = 0; for (;*pwcs && n-- > 0; pwcs++) if ((w = mk_wcwidth(*pwcs)) < 0) return -1; else width += w; return width; } /* * The following functions are the same as mk_wcwidth() and * mk_wcwidth_cjk(), except that spacing characters in the East Asian * Ambiguous (A) category as defined in Unicode Technical Report #11 * have a column width of 2. This variant might be useful for users of * CJK legacy encodings who want to migrate to UCS without changing * the traditional terminal character-width behaviour. It is not * otherwise recommended for general use. */ int mk_wcwidth_cjk(wchar_t ucs) { /* sorted list of non-overlapping intervals of East Asian Ambiguous * characters, generated by "uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf c" */ static const struct interval ambiguous[] = { { 0x00A1, 0x00A1 }, { 0x00A4, 0x00A4 }, { 0x00A7, 0x00A8 }, { 0x00AA, 0x00AA }, { 0x00AE, 0x00AE }, { 0x00B0, 0x00B4 }, { 0x00B6, 0x00BA }, { 0x00BC, 0x00BF }, { 0x00C6, 0x00C6 }, |
︙ | ︙ | |||
293 294 295 296 297 298 299 | sizeof(ambiguous) / sizeof(struct interval) - 1)) return 2; return mk_wcwidth(ucs); } | | | 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 | sizeof(ambiguous) / sizeof(struct interval) - 1)) return 2; return mk_wcwidth(ucs); } int mk_wcswidth_cjk(const wchar_t *pwcs, size_t n) { int w, width = 0; for (;*pwcs && n-- > 0; pwcs++) if ((w = mk_wcwidth_cjk(*pwcs)) < 0) return -1; else width += w; return width; } |
Changes to wildcard.c.
︙ | ︙ | |||
322 323 324 325 326 327 328 | return 0; /* it's a wildcard! */ } else { if (output) *output++ = *wildcard; wildcard++; } } | < | | 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 | return 0; /* it's a wildcard! */ } else { if (output) *output++ = *wildcard; wildcard++; } } *output = '\0'; return 1; /* it's clean */ } #ifdef TESTMODE struct test { const char *wildcard; |
︙ | ︙ |
Changes to windows/pageant.rc.
︙ | ︙ | |||
24 25 26 27 28 29 30 | 211 DIALOG DISCARDABLE 0, 0, 330, 200 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Pageant Key List" FONT 8, "MS Shell Dlg" BEGIN LISTBOX 100, 10, 10, 310, 155, | | > > | | | | 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | 211 DIALOG DISCARDABLE 0, 0, 330, 200 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Pageant Key List" FONT 8, "MS Shell Dlg" BEGIN LISTBOX 100, 10, 10, 310, 155, LBS_NOTIFY | LBS_EXTENDEDSEL | LBS_HASSTRINGS | LBS_USETABSTOPS | WS_VSCROLL | WS_TABSTOP PUSHBUTTON "&Add Key", 101, 75, 162, 60, 14 PUSHBUTTON "&Remove Key", 102, 195, 162, 60, 14 PUSHBUTTON "&Help", 103, 10, 182, 50, 14 // id x y w h PUSHBUTTON "Add CAPI Cert", 110, 130, 182, 70, 14 DEFPUSHBUTTON "&Close", IDOK, 270, 182, 50, 14 END /* Accelerators used: cl */ 213 DIALOG DISCARDABLE 140, 40, 136, 70 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "About Pageant" FONT 8, "MS Shell Dlg" BEGIN DEFPUSHBUTTON "&Close", IDOK, 82, 52, 48, 14 PUSHBUTTON "View &Licence", 101, 6, 52, 70, 14 CTEXT "Pageant", 102, 10, 6, 120, 8 CTEXT "", 100, 10, 16, 120, 16 CTEXT "\251 1997-2011 Simon Tatham. All rights reserved.", 103, 10, 34, 120, 16 END /* No accelerators used */ 214 DIALOG DISCARDABLE 50, 50, 226, 263 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "PuTTY Licence" FONT 8, "MS Shell Dlg" BEGIN DEFPUSHBUTTON "OK", IDOK, 98, 243, 44, 14 LTEXT "Copyright \251 1997-2011 Simon Tatham", 1000, 10, 10, 206, 8 LTEXT "Portions copyright Robert de Bath, Joris van Rantwijk, Delian", 1001, 10, 26, 206, 8 LTEXT "Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas", 1002, 10, 34, 206, 8 LTEXT "Barry, Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa,", 1003, 10, 42, 206, 8 LTEXT "Markus Kuhn, Pascal Buchbinder, Daniel Risacher, Colin Watson, and CORE SDI S.A.", 1004, 10, 50, 206, 8 LTEXT "Permission is hereby granted, free of charge, to any person", 1005, 10, 66, 206, 8 LTEXT "obtaining a copy of this software and associated documentation", 1006, 10, 74, 206, 8 LTEXT "files (the ""Software""), to deal in the Software without restriction,", 1007, 10, 82, 206, 8 LTEXT "including without limitation the rights to use, copy, modify, merge,", 1008, 10, 90, 206, 8 LTEXT "publish, distribute, sublicense, and/or sell copies of the Software,", 1009, 10, 98, 206, 8 LTEXT "and to permit persons to whom the Software is furnished to do so,", 1010, 10, 106, 206, 8 |
︙ | ︙ | |||
89 90 91 92 93 94 95 | END #include "version.rc2" #ifndef NO_MANIFESTS 1 RT_MANIFEST "pageant.mft" #endif /* NO_MANIFESTS */ | > > > > > > > > > > > > | 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | END #include "version.rc2" #ifndef NO_MANIFESTS 1 RT_MANIFEST "pageant.mft" #endif /* NO_MANIFESTS */ 215 DIALOG DISCARDABLE 0, 0, 140, 60 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Pageant: Enter Passphrase" FONT 8, "MS Shell Dlg" BEGIN CTEXT "Enter passphrase for key", 100, 10, 6, 120, 8 CTEXT "", 101, 10, 16, 120, 8 EDITTEXT 102, 10, 26, 120, 12, ES_PASSWORD | ES_AUTOHSCROLL DEFPUSHBUTTON "O&K", IDOK, 20, 42, 40, 14 PUSHBUTTON "Save", IDCANCEL, 80, 42, 40, 14 END |
Changes to windows/putty.iss.
1 | ; -*- no -*- | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | ; -*- no -*- ; $Id: putty.iss 9366 2011-12-10 12:08:09Z simon $ ; ; -- Inno Setup installer script for PuTTY and its related tools. ; Last tested with Inno Setup 5.0.8. ; ; TODO for future releases: ; ; - It might be nice to have an option to add PSCP, Plink and PSFTP to ; the PATH. See wish `installer-addpath'. ; ; - Maybe a "custom" installation might be useful? Hassle with ; UninstallDisplayIcon, though. [Setup] AppName=PuTTY AppVerName=PuTTY version 0.62 VersionInfoTextVersion=Release 0.62 AppVersion=0.62 VersionInfoVersion=0.62.0.0 AppPublisher=Simon Tatham AppPublisherURL=http://www.chiark.greenend.org.uk/~sgtatham/putty/ AppReadmeFile={app}\README.txt DefaultDirName={pf}\PuTTY DefaultGroupName=PuTTY SetupIconFile=puttyins.ico UninstallDisplayIcon={app}\putty.exe |
︙ | ︙ |
Changes to windows/puttygen.rc.
︙ | ︙ | |||
34 35 36 37 38 39 40 | CAPTION "About PuTTYgen" FONT 8, "MS Shell Dlg" BEGIN DEFPUSHBUTTON "&Close", IDOK, 82, 52, 48, 14 PUSHBUTTON "View &Licence", 101, 6, 52, 70, 14 CTEXT "PuTTYgen", 102, 10, 6, 120, 8 CTEXT "", 100, 10, 16, 120, 16 | | | | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | CAPTION "About PuTTYgen" FONT 8, "MS Shell Dlg" BEGIN DEFPUSHBUTTON "&Close", IDOK, 82, 52, 48, 14 PUSHBUTTON "View &Licence", 101, 6, 52, 70, 14 CTEXT "PuTTYgen", 102, 10, 6, 120, 8 CTEXT "", 100, 10, 16, 120, 16 CTEXT "\251 1997-2011 Simon Tatham. All rights reserved.", 103, 10, 34, 120, 16 END /* No accelerators used */ 214 DIALOG DISCARDABLE 50, 50, 226, 263 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "PuTTY Licence" FONT 8, "MS Shell Dlg" BEGIN DEFPUSHBUTTON "OK", IDOK, 98, 243, 44, 14 LTEXT "Copyright \251 1997-2011 Simon Tatham", 1000, 10, 10, 206, 8 LTEXT "Portions copyright Robert de Bath, Joris van Rantwijk, Delian", 1001, 10, 26, 206, 8 LTEXT "Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas", 1002, 10, 34, 206, 8 LTEXT "Barry, Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa,", 1003, 10, 42, 206, 8 LTEXT "Markus Kuhn, Colin Watson, and CORE SDI S.A.", 1004, 10, 50, 206, 8 LTEXT "Permission is hereby granted, free of charge, to any person", 1005, 10, 66, 206, 8 |
︙ | ︙ |
Changes to windows/version.rc2.
︙ | ︙ | |||
35 36 37 38 39 40 41 | */ #define STR1(x) #x #define STR(x) STR1(x) /* We keep this around even for snapshots, for monotonicity of version * numbering. It needs to be kept up to date. NB _comma_-separated. */ | | | 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | */ #define STR1(x) #x #define STR(x) STR1(x) /* We keep this around even for snapshots, for monotonicity of version * numbering. It needs to be kept up to date. NB _comma_-separated. */ #define BASE_VERSION 0,62 #if defined SNAPSHOT /* Make SVN_REV mandatory for snapshots, to avoid issuing binary * version numbers that look like full releases. */ #ifndef SVN_REV #error SVN_REV not defined/nonzero for snapshot build |
︙ | ︙ | |||
109 110 111 112 113 114 115 | /* (On Win98SE and Win2K, we can see most of this on the Version tab * in the file properties in Explorer.) */ BLOCK "StringFileInfo" BEGIN /* "lang-charset" LLLLCCCC = (UK English, Unicode) */ BLOCK "080904B0" BEGIN | | | | | 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | /* (On Win98SE and Win2K, we can see most of this on the Version tab * in the file properties in Explorer.) */ BLOCK "StringFileInfo" BEGIN /* "lang-charset" LLLLCCCC = (UK English, Unicode) */ BLOCK "080904B0" BEGIN VALUE "CompanyName", "Daniel Risacher" /* required :/ */ VALUE "ProductName", "PuTTY-CAC suite" VALUE "FileDescription", APPDESC VALUE "InternalName", APPNAME VALUE "OriginalFilename", APPNAME VALUE "FileVersion", VERSION_TEXT VALUE "ProductVersion", VERSION_TEXT VALUE "LegalCopyright", "Copyright \251 1997-2011 Simon Tatham." #if (!defined SNAPSHOT) && (!defined RELEASE) /* Only if VS_FF_PRIVATEBUILD. */ VALUE "PrivateBuild", VERSION_TEXT /* NBI */ #endif END END BLOCK "VarFileInfo" |
︙ | ︙ |
Changes to windows/win_res.rc2.
︙ | ︙ | |||
14 15 16 17 18 19 20 | IDI_MAINICON ICON "putty.ico" IDI_CFGICON ICON "puttycfg.ico" /* Accelerators used: clw */ IDD_ABOUTBOX DIALOG DISCARDABLE 140, 40, 214, 70 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | | | | | | | | | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | IDI_MAINICON ICON "putty.ico" IDI_CFGICON ICON "puttycfg.ico" /* Accelerators used: clw */ IDD_ABOUTBOX DIALOG DISCARDABLE 140, 40, 214, 70 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "About PuTTY-CAC" FONT 8, "MS Shell Dlg" BEGIN DEFPUSHBUTTON "&Close", IDOK, 160, 52, 48, 14 PUSHBUTTON "View &Licence", IDA_LICENCE, 6, 52, 70, 14 PUSHBUTTON "Visit &Web Site", IDA_WEB, 84, 52, 70, 14 CTEXT "PuTTY-CAC", IDA_TEXT1, 10, 6, 194, 8 CTEXT "", IDA_VERSION, 10, 16, 194, 16 CTEXT "\251 1997-2012 Dan Risacher, Simon Tatham, and others.", IDA_TEXT2, 10, 34, 194, 16 END /* Accelerators used: aco */ IDD_MAINBOX DIALOG DISCARDABLE 0, 0, 300, 252 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "PuTTY CAC Configuration" FONT 8, "MS Shell Dlg" CLASS "PuTTYConfigBox" BEGIN END /* Accelerators used: co */ IDD_LOGBOX DIALOG DISCARDABLE 100, 20, 300, 119 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "PuTTY CAC Event Log" FONT 8, "MS Shell Dlg" BEGIN DEFPUSHBUTTON "&Close", IDOK, 135, 102, 44, 14 PUSHBUTTON "C&opy", IDN_COPY, 81, 102, 44, 14 LISTBOX IDN_LIST, 3, 3, 294, 95, LBS_HASSTRINGS | LBS_USETABSTOPS | WS_VSCROLL | LBS_EXTENDEDSEL END /* No accelerators used */ IDD_LICENCEBOX DIALOG DISCARDABLE 50, 50, 226, 263 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "PuTTY Licence" FONT 8, "MS Shell Dlg" BEGIN DEFPUSHBUTTON "OK", IDOK, 98, 243, 44, 14 LTEXT "Copyright \251 1997-2011 Dan Risacher, Simon Tatham", 1000, 10, 10, 206, 8 LTEXT "Portions copyright Robert de Bath, Joris van Rantwijk, Delian", 1001, 10, 26, 206, 8 LTEXT "Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas", 1002, 10, 34, 206, 8 LTEXT "Barry, Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa,", 1003, 10, 42, 206, 8 LTEXT "Markus Kuhn, Pascal Buchbinder, Colin Watson, and CORE SDI S.A.", 1004, 10, 50, 206, 8 LTEXT "Permission is hereby granted, free of charge, to any person", 1005, 10, 66, 206, 8 LTEXT "obtaining a copy of this software and associated documentation", 1006, 10, 74, 206, 8 LTEXT "files (the ""Software""), to deal in the Software without restriction,", 1007, 10, 82, 206, 8 LTEXT "including without limitation the rights to use, copy, modify, merge,", 1008, 10, 90, 206, 8 LTEXT "publish, distribute, sublicense, and/or sell copies of the Software,", 1009, 10, 98, 206, 8 LTEXT "and to permit persons to whom the Software is furnished to do so,", 1010, 10, 106, 206, 8 |
︙ | ︙ |
Changes to windows/wincfg.c.
︙ | ︙ | |||
66 67 68 69 70 71 72 | * Full-screen mode is a Windows peculiarity; hence * scrollbar_in_fullscreen is as well. */ s = ctrl_getset(b, "Window", "scrollback", "Control the scrollback in the window"); ctrl_checkbox(s, "Display scrollbar in full screen mode", 'i', HELPCTX(window_scrollback), | | | | | 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | * Full-screen mode is a Windows peculiarity; hence * scrollbar_in_fullscreen is as well. */ s = ctrl_getset(b, "Window", "scrollback", "Control the scrollback in the window"); ctrl_checkbox(s, "Display scrollbar in full screen mode", 'i', HELPCTX(window_scrollback), dlg_stdcheckbox_handler, I(offsetof(Config,scrollbar_in_fullscreen))); /* * Really this wants to go just after `Display scrollbar'. See * if we can find that control, and do some shuffling. */ { int i; for (i = 0; i < s->ncontrols; i++) { c = s->ctrls[i]; if (c->generic.type == CTRL_CHECKBOX && c->generic.context.i == offsetof(Config,scrollbar)) { /* * Control i is the scrollbar checkbox. * Control s->ncontrols-1 is the scrollbar-in-FS one. */ if (i < s->ncontrols-2) { c = s->ctrls[s->ncontrols-1]; memmove(s->ctrls+i+2, s->ctrls+i+1, |
︙ | ︙ | |||
101 102 103 104 105 106 107 | * Windows has the AltGr key, which has various Windows- * specific options. */ s = ctrl_getset(b, "Terminal/Keyboard", "features", "Enable extra keyboard features:"); ctrl_checkbox(s, "AltGr acts as Compose key", 't', HELPCTX(keyboard_compose), | | | | 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | * Windows has the AltGr key, which has various Windows- * specific options. */ s = ctrl_getset(b, "Terminal/Keyboard", "features", "Enable extra keyboard features:"); ctrl_checkbox(s, "AltGr acts as Compose key", 't', HELPCTX(keyboard_compose), dlg_stdcheckbox_handler, I(offsetof(Config,compose_key))); ctrl_checkbox(s, "Control-Alt is different from AltGr", 'd', HELPCTX(keyboard_ctrlalt), dlg_stdcheckbox_handler, I(offsetof(Config,ctrlaltkeys))); /* * Windows allows an arbitrary .WAV to be played as a bell, and * also the use of the PC speaker. For this we must search the * existing controlset for the radio-button set controlling the * `beep' option, and add extra buttons to it. * |
︙ | ︙ | |||
129 130 131 132 133 134 135 | */ s = ctrl_getset(b, "Terminal/Bell", "style", "Set the style of bell"); { int i; for (i = 0; i < s->ncontrols; i++) { c = s->ctrls[i]; if (c->generic.type == CTRL_RADIO && | | | | 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | */ s = ctrl_getset(b, "Terminal/Bell", "style", "Set the style of bell"); { int i; for (i = 0; i < s->ncontrols; i++) { c = s->ctrls[i]; if (c->generic.type == CTRL_RADIO && c->generic.context.i == offsetof(Config, beep)) { assert(c->generic.handler == dlg_stdradiobutton_handler); c->radio.nbuttons += 2; c->radio.buttons = sresize(c->radio.buttons, c->radio.nbuttons, char *); c->radio.buttons[c->radio.nbuttons-1] = dupstr("Play a custom sound file"); c->radio.buttons[c->radio.nbuttons-2] = dupstr("Beep using the PC speaker"); |
︙ | ︙ | |||
155 156 157 158 159 160 161 | break; } } } ctrl_filesel(s, "Custom sound file to play as a bell:", NO_SHORTCUT, FILTER_WAVE_FILES, FALSE, "Select bell sound file", HELPCTX(bell_style), | | | | | | | | | | 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 | break; } } } ctrl_filesel(s, "Custom sound file to play as a bell:", NO_SHORTCUT, FILTER_WAVE_FILES, FALSE, "Select bell sound file", HELPCTX(bell_style), dlg_stdfilesel_handler, I(offsetof(Config, bell_wavefile))); /* * While we've got this box open, taskbar flashing on a bell is * also Windows-specific. */ ctrl_radiobuttons(s, "Taskbar/caption indication on bell:", 'i', 3, HELPCTX(bell_taskbar), dlg_stdradiobutton_handler, I(offsetof(Config, beep_ind)), "Disabled", I(B_IND_DISABLED), "Flashing", I(B_IND_FLASH), "Steady", I(B_IND_STEADY), NULL); /* * The sunken-edge border is a Windows GUI feature. */ s = ctrl_getset(b, "Window/Appearance", "border", "Adjust the window border"); ctrl_checkbox(s, "Sunken-edge border (slightly thicker)", 's', HELPCTX(appearance_border), dlg_stdcheckbox_handler, I(offsetof(Config,sunken_edge))); /* * Configurable font quality settings for Windows. */ s = ctrl_getset(b, "Window/Appearance", "font", "Font settings"); ctrl_checkbox(s, "Allow selection of variable-pitch fonts", NO_SHORTCUT, HELPCTX(appearance_font), variable_pitch_handler, I(0)); ctrl_radiobuttons(s, "Font quality:", 'q', 2, HELPCTX(appearance_font), dlg_stdradiobutton_handler, I(offsetof(Config, font_quality)), "Antialiased", I(FQ_ANTIALIASED), "Non-Antialiased", I(FQ_NONANTIALIASED), "ClearType", I(FQ_CLEARTYPE), "Default", I(FQ_DEFAULT), NULL); /* * Cyrillic Lock is a horrid misfeature even on Windows, and * the least we can do is ensure it never makes it to any other * platform (at least unless someone fixes it!). */ s = ctrl_getset(b, "Window/Translation", "tweaks", NULL); ctrl_checkbox(s, "Caps Lock acts as Cyrillic switch", 's', HELPCTX(translation_cyrillic), dlg_stdcheckbox_handler, I(offsetof(Config,xlat_capslockcyr))); /* * On Windows we can use but not enumerate translation tables * from the operating system. Briefly document this. */ s = ctrl_getset(b, "Window/Translation", "trans", "Character set translation on received data"); |
︙ | ︙ | |||
228 229 230 231 232 233 234 | s = ctrl_getset(b, "Window/Translation", "linedraw", str); sfree(str); { int i; for (i = 0; i < s->ncontrols; i++) { c = s->ctrls[i]; if (c->generic.type == CTRL_RADIO && | | | | 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 | s = ctrl_getset(b, "Window/Translation", "linedraw", str); sfree(str); { int i; for (i = 0; i < s->ncontrols; i++) { c = s->ctrls[i]; if (c->generic.type == CTRL_RADIO && c->generic.context.i == offsetof(Config, vtmode)) { assert(c->generic.handler == dlg_stdradiobutton_handler); c->radio.nbuttons += 3; c->radio.buttons = sresize(c->radio.buttons, c->radio.nbuttons, char *); c->radio.buttons[c->radio.nbuttons-3] = dupstr("Font has XWindows encoding"); c->radio.buttons[c->radio.nbuttons-2] = dupstr("Use font in both ANSI and OEM modes"); |
︙ | ︙ | |||
268 269 270 271 272 273 274 | /* * RTF paste is Windows-specific. */ s = ctrl_getset(b, "Window/Selection", "format", "Formatting of pasted characters"); ctrl_checkbox(s, "Paste to clipboard in RTF as well as plain text", 'f', HELPCTX(selection_rtf), | | | | | | | | | | | | | | | | | > | | 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 | /* * RTF paste is Windows-specific. */ s = ctrl_getset(b, "Window/Selection", "format", "Formatting of pasted characters"); ctrl_checkbox(s, "Paste to clipboard in RTF as well as plain text", 'f', HELPCTX(selection_rtf), dlg_stdcheckbox_handler, I(offsetof(Config,rtf_paste))); /* * Windows often has no middle button, so we supply a selection * mode in which the more critical Paste action is available on * the right button instead. */ s = ctrl_getset(b, "Window/Selection", "mouse", "Control use of mouse"); ctrl_radiobuttons(s, "Action of mouse buttons:", 'm', 1, HELPCTX(selection_buttons), dlg_stdradiobutton_handler, I(offsetof(Config, mouse_is_xterm)), "Windows (Middle extends, Right brings up menu)", I(2), "Compromise (Middle extends, Right pastes)", I(0), "xterm (Right extends, Middle pastes)", I(1), NULL); /* * This really ought to go at the _top_ of its box, not the * bottom, so we'll just do some shuffling now we've set it * up... */ c = s->ctrls[s->ncontrols-1]; /* this should be the new control */ memmove(s->ctrls+1, s->ctrls, (s->ncontrols-1)*sizeof(union control *)); s->ctrls[0] = c; /* * Logical palettes don't even make sense anywhere except Windows. */ s = ctrl_getset(b, "Window/Colours", "general", "General options for colour usage"); ctrl_checkbox(s, "Attempt to use logical palettes", 'l', HELPCTX(colours_logpal), dlg_stdcheckbox_handler, I(offsetof(Config,try_palette))); ctrl_checkbox(s, "Use system colours", 's', HELPCTX(colours_system), dlg_stdcheckbox_handler, I(offsetof(Config,system_colour))); /* * Resize-by-changing-font is a Windows insanity. */ s = ctrl_getset(b, "Window", "size", "Set the size of the window"); ctrl_radiobuttons(s, "When window is resized:", 'z', 1, HELPCTX(window_resize), dlg_stdradiobutton_handler, I(offsetof(Config, resize_action)), "Change the number of rows and columns", I(RESIZE_TERM), "Change the size of the font", I(RESIZE_FONT), "Change font size only when maximised", I(RESIZE_EITHER), "Forbid resizing completely", I(RESIZE_DISABLED), NULL); /* * Most of the Window/Behaviour stuff is there to mimic Windows * conventions which PuTTY can optionally disregard. Hence, * most of these options are Windows-specific. */ s = ctrl_getset(b, "Window/Behaviour", "main", NULL); ctrl_checkbox(s, "Window closes on ALT-F4", '4', HELPCTX(behaviour_altf4), dlg_stdcheckbox_handler, I(offsetof(Config,alt_f4))); ctrl_checkbox(s, "System menu appears on ALT-Space", 'y', HELPCTX(behaviour_altspace), dlg_stdcheckbox_handler, I(offsetof(Config,alt_space))); ctrl_checkbox(s, "System menu appears on ALT alone", 'l', HELPCTX(behaviour_altonly), dlg_stdcheckbox_handler, I(offsetof(Config,alt_only))); ctrl_checkbox(s, "Ensure window is always on top", 'e', HELPCTX(behaviour_alwaysontop), dlg_stdcheckbox_handler, I(offsetof(Config,alwaysontop))); ctrl_checkbox(s, "Full screen on Alt-Enter", 'f', HELPCTX(behaviour_altenter), dlg_stdcheckbox_handler, I(offsetof(Config,fullscreenonaltenter))); /* * Windows supports a local-command proxy. This also means we * must adjust the text on the `Telnet command' control. */ if (!midsession) { int i; s = ctrl_getset(b, "Connection/Proxy", "basics", NULL); for (i = 0; i < s->ncontrols; i++) { c = s->ctrls[i]; if (c->generic.type == CTRL_RADIO && c->generic.context.i == offsetof(Config, proxy_type)) { assert(c->generic.handler == dlg_stdradiobutton_handler); c->radio.nbuttons++; c->radio.buttons = sresize(c->radio.buttons, c->radio.nbuttons, char *); c->radio.buttons[c->radio.nbuttons-1] = dupstr("Local"); c->radio.buttondata = sresize(c->radio.buttondata, c->radio.nbuttons, intorptr); c->radio.buttondata[c->radio.nbuttons-1] = I(PROXY_CMD); break; } } for (i = 0; i < s->ncontrols; i++) { c = s->ctrls[i]; if (c->generic.type == CTRL_EDITBOX && c->generic.context.i == offsetof(Config, proxy_telnet_command)) { assert(c->generic.handler == dlg_stdeditbox_handler); sfree(c->generic.label); c->generic.label = dupstr("Telnet command, or local" " proxy command"); break; } } } |
︙ | ︙ | |||
394 395 396 397 398 399 400 | * means to override it. */ if (!midsession && backend_from_proto(PROT_SSH)) { s = ctrl_getset(b, "Connection/SSH/X11", "x11", "X11 forwarding"); ctrl_filesel(s, "X authority file for local display", 't', NULL, FALSE, "Select X authority file", HELPCTX(ssh_tunnels_xauthority), | | | 395 396 397 398 399 400 401 402 403 404 | * means to override it. */ if (!midsession && backend_from_proto(PROT_SSH)) { s = ctrl_getset(b, "Connection/SSH/X11", "x11", "X11 forwarding"); ctrl_filesel(s, "X authority file for local display", 't', NULL, FALSE, "Select X authority file", HELPCTX(ssh_tunnels_xauthority), dlg_stdfilesel_handler, I(offsetof(Config, xauthfile))); } } |
Changes to windows/wincons.c.
︙ | ︙ | |||
37 38 39 40 41 42 43 | { } void notify_remote_exit(void *frontend) { } | | | 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | { } void notify_remote_exit(void *frontend) { } void timer_change_notify(long next) { } int verify_ssh_host_key(void *frontend, char *host, int port, char *keytype, char *keystr, char *fingerprint, void (*callback)(void *ctx, int result), void *ctx) { |
︙ | ︙ | |||
197 198 199 200 201 202 203 | } } /* * Ask whether to wipe a session log file before writing to it. * Returns 2 for wipe, 1 for append, 0 for cancel (don't log). */ | | | 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 | } } /* * Ask whether to wipe a session log file before writing to it. * Returns 2 for wipe, 1 for append, 0 for cancel (don't log). */ int askappend(void *frontend, Filename filename, void (*callback)(void *ctx, int result), void *ctx) { HANDLE hin; DWORD savemode, i; static const char msgtemplate[] = "The session log file \"%.*s\" already exists.\n" |
︙ | ︙ | |||
219 220 221 222 223 224 225 | static const char msgtemplate_batch[] = "The session log file \"%.*s\" already exists.\n" "Logging will not be enabled.\n"; char line[32]; if (console_batch_mode) { | | | | 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 | static const char msgtemplate_batch[] = "The session log file \"%.*s\" already exists.\n" "Logging will not be enabled.\n"; char line[32]; if (console_batch_mode) { fprintf(stderr, msgtemplate_batch, FILENAME_MAX, filename.path); fflush(stderr); return 0; } fprintf(stderr, msgtemplate, FILENAME_MAX, filename.path); fflush(stderr); hin = GetStdHandle(STD_INPUT_HANDLE); GetConsoleMode(hin, &savemode); SetConsoleMode(hin, (savemode | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT)); ReadFile(hin, line, sizeof(line) - 1, &i, NULL); |
︙ | ︙ | |||
311 312 313 314 315 316 317 | /* * Zero all the results, in case we abort half-way through. */ { int i; for (i = 0; i < (int)p->n_prompts; i++) | | | 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 | /* * Zero all the results, in case we abort half-way through. */ { int i; for (i = 0; i < (int)p->n_prompts; i++) memset(p->prompts[i]->result, 0, p->prompts[i]->result_len); } /* * The prompts_t might contain a message to be displayed but no * actual prompt. More usually, though, it will contain * questions that the user needs to answer, in which case we * need to ensure that we're able to get the answers. |
︙ | ︙ | |||
361 362 363 364 365 366 367 | console_data_untrusted(hout, p->instruction, l); if (p->instruction[l-1] != '\n') console_data_untrusted(hout, "\n", 1); } for (curr_prompt = 0; curr_prompt < p->n_prompts; curr_prompt++) { | | < > < < < < | < < < | < < < | < | < | | < < < | < > < < < < < > | 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 | console_data_untrusted(hout, p->instruction, l); if (p->instruction[l-1] != '\n') console_data_untrusted(hout, "\n", 1); } for (curr_prompt = 0; curr_prompt < p->n_prompts; curr_prompt++) { DWORD savemode, newmode, i = 0; prompt_t *pr = p->prompts[curr_prompt]; BOOL r; GetConsoleMode(hin, &savemode); newmode = savemode | ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT; if (!pr->echo) newmode &= ~ENABLE_ECHO_INPUT; else newmode |= ENABLE_ECHO_INPUT; SetConsoleMode(hin, newmode); console_data_untrusted(hout, pr->prompt, strlen(pr->prompt)); r = ReadFile(hin, pr->result, pr->result_len - 1, &i, NULL); SetConsoleMode(hin, savemode); if ((int) i > pr->result_len) i = pr->result_len - 1; else i = i - 2; pr->result[i] = '\0'; if (!pr->echo) { DWORD dummy; WriteFile(hout, "\r\n", 2, &dummy, NULL); } } return 1; /* success */ } void frontend_keypress(void *handle) { /* * This is nothing but a stub, in console code. */ return; } |
Changes to windows/winctrls.c.
︙ | ︙ | |||
444 445 446 447 448 449 450 | } SelectObject(hdc, oldfont); ReleaseDC(cp->hwnd, hdc); if (lines) *lines = nlines; | < < | 444 445 446 447 448 449 450 451 452 453 454 455 456 457 | } SelectObject(hdc, oldfont); ReleaseDC(cp->hwnd, hdc); if (lines) *lines = nlines; return ret; } /* * A single standalone static text control. */ void statictext(struct ctlpos *cp, char *text, int lines, int id) |
︙ | ︙ | |||
1637 1638 1639 1640 1641 1642 1643 | case CTRL_FONTSELECT: num_ids = 3; escaped = shortcut_escape(ctrl->fontselect.label, ctrl->fontselect.shortcut); shortcuts[nshortcuts++] = ctrl->fontselect.shortcut; statictext(&pos, escaped, 1, base_id); staticbtn(&pos, "", base_id+1, "Change...", base_id+2); | < > | 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 | case CTRL_FONTSELECT: num_ids = 3; escaped = shortcut_escape(ctrl->fontselect.label, ctrl->fontselect.shortcut); shortcuts[nshortcuts++] = ctrl->fontselect.shortcut; statictext(&pos, escaped, 1, base_id); staticbtn(&pos, "", base_id+1, "Change...", base_id+2); sfree(escaped); data = snew(FontSpec); break; default: assert(!"Can't happen"); num_ids = 0; /* placate gcc */ break; } |
︙ | ︙ | |||
1663 1664 1665 1666 1667 1668 1669 | c->num_ids = num_ids; c->data = data; memcpy(c->shortcuts, shortcuts, sizeof(shortcuts)); winctrl_add(wc, c); winctrl_add_shortcuts(dp, c); if (actual_base_id == base_id) base_id += num_ids; | < < | | 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 | c->num_ids = num_ids; c->data = data; memcpy(c->shortcuts, shortcuts, sizeof(shortcuts)); winctrl_add(wc, c); winctrl_add_shortcuts(dp, c); if (actual_base_id == base_id) base_id += num_ids; } if (colstart >= 0) { /* * Update the ypos in all columns crossed by this * control. */ int i; |
︙ | ︙ | |||
1934 1935 1936 1937 1938 1939 1940 | if (id == 2 && (msg == WM_COMMAND && (HIWORD(wParam) == BN_CLICKED || HIWORD(wParam) == BN_DOUBLECLICKED))) { CHOOSEFONT cf; LOGFONT lf; HDC hdc; | | | | | | | > > > | > | < < | 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 | if (id == 2 && (msg == WM_COMMAND && (HIWORD(wParam) == BN_CLICKED || HIWORD(wParam) == BN_DOUBLECLICKED))) { CHOOSEFONT cf; LOGFONT lf; HDC hdc; FontSpec fs = *(FontSpec *)c->data; hdc = GetDC(0); lf.lfHeight = -MulDiv(fs.height, GetDeviceCaps(hdc, LOGPIXELSY), 72); ReleaseDC(0, hdc); lf.lfWidth = lf.lfEscapement = lf.lfOrientation = 0; lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = 0; lf.lfWeight = (fs.isbold ? FW_BOLD : 0); lf.lfCharSet = fs.charset; lf.lfOutPrecision = OUT_DEFAULT_PRECIS; lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; lf.lfQuality = DEFAULT_QUALITY; lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE; strncpy(lf.lfFaceName, fs.name, sizeof(lf.lfFaceName) - 1); lf.lfFaceName[sizeof(lf.lfFaceName) - 1] = '\0'; cf.lStructSize = sizeof(cf); cf.hwndOwner = dp->hwnd; cf.lpLogFont = &lf; cf.Flags = (dp->fixed_pitch_fonts ? CF_FIXEDPITCHONLY : 0) | CF_FORCEFONTEXIST | CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS; if (ChooseFont(&cf)) { strncpy(fs.name, lf.lfFaceName, sizeof(fs.name) - 1); fs.name[sizeof(fs.name) - 1] = '\0'; fs.isbold = (lf.lfWeight == FW_BOLD); fs.charset = lf.lfCharSet; fs.height = cf.iPointSize / 10; dlg_fontsel_set(ctrl, dp, fs); ctrl->generic.handler(ctrl, dp, dp->data, EVENT_VALCHANGE); } } break; } /* |
︙ | ︙ | |||
2098 2099 2100 2101 2102 2103 2104 | { struct dlgparam *dp = (struct dlgparam *)dlg; struct winctrl *c = dlg_findbyctrl(dp, ctrl); assert(c && c->ctrl->generic.type == CTRL_EDITBOX); SetDlgItemText(dp->hwnd, c->base_id+1, text); } | | | > | 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 | { struct dlgparam *dp = (struct dlgparam *)dlg; struct winctrl *c = dlg_findbyctrl(dp, ctrl); assert(c && c->ctrl->generic.type == CTRL_EDITBOX); SetDlgItemText(dp->hwnd, c->base_id+1, text); } void dlg_editbox_get(union control *ctrl, void *dlg, char *buffer, int length) { struct dlgparam *dp = (struct dlgparam *)dlg; struct winctrl *c = dlg_findbyctrl(dp, ctrl); assert(c && c->ctrl->generic.type == CTRL_EDITBOX); GetDlgItemText(dp->hwnd, c->base_id+1, buffer, length); buffer[length-1] = '\0'; } /* The `listbox' functions can also apply to combo boxes. */ void dlg_listbox_clear(union control *ctrl, void *dlg) { struct dlgparam *dp = (struct dlgparam *)dlg; struct winctrl *c = dlg_findbyctrl(dp, ctrl); |
︙ | ︙ | |||
2283 2284 2285 2286 2287 2288 2289 | } if (escaped) { SetDlgItemText(dp->hwnd, id, escaped); sfree(escaped); } } | | | | < < | < < < > | | < | | | | | | | | | 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 | } if (escaped) { SetDlgItemText(dp->hwnd, id, escaped); sfree(escaped); } } void dlg_filesel_set(union control *ctrl, void *dlg, Filename fn) { struct dlgparam *dp = (struct dlgparam *)dlg; struct winctrl *c = dlg_findbyctrl(dp, ctrl); assert(c && c->ctrl->generic.type == CTRL_FILESELECT); SetDlgItemText(dp->hwnd, c->base_id+1, fn.path); } void dlg_filesel_get(union control *ctrl, void *dlg, Filename *fn) { struct dlgparam *dp = (struct dlgparam *)dlg; struct winctrl *c = dlg_findbyctrl(dp, ctrl); assert(c && c->ctrl->generic.type == CTRL_FILESELECT); GetDlgItemText(dp->hwnd, c->base_id+1, fn->path, lenof(fn->path)); fn->path[lenof(fn->path)-1] = '\0'; } void dlg_fontsel_set(union control *ctrl, void *dlg, FontSpec fs) { char *buf, *boldstr; struct dlgparam *dp = (struct dlgparam *)dlg; struct winctrl *c = dlg_findbyctrl(dp, ctrl); assert(c && c->ctrl->generic.type == CTRL_FONTSELECT); *(FontSpec *)c->data = fs; /* structure copy */ boldstr = (fs.isbold ? "bold, " : ""); if (fs.height == 0) buf = dupprintf("Font: %s, %sdefault height", fs.name, boldstr); else buf = dupprintf("Font: %s, %s%d-%s", fs.name, boldstr, (fs.height < 0 ? -fs.height : fs.height), (fs.height < 0 ? "pixel" : "point")); SetDlgItemText(dp->hwnd, c->base_id+1, buf); sfree(buf); dlg_auto_set_fixed_pitch_flag(dp); } void dlg_fontsel_get(union control *ctrl, void *dlg, FontSpec *fs) { struct dlgparam *dp = (struct dlgparam *)dlg; struct winctrl *c = dlg_findbyctrl(dp, ctrl); assert(c && c->ctrl->generic.type == CTRL_FONTSELECT); *fs = *(FontSpec *)c->data; /* structure copy */ } /* * Bracketing a large set of updates in these two functions will * cause the front end (if possible) to delay updating the screen * until it's all complete, thus avoiding flicker. */ |
︙ | ︙ | |||
2366 2367 2368 2369 2370 2371 2372 | void dlg_set_focus(union control *ctrl, void *dlg) { struct dlgparam *dp = (struct dlgparam *)dlg; struct winctrl *c = dlg_findbyctrl(dp, ctrl); int id; HWND ctl; | < < | 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 | void dlg_set_focus(union control *ctrl, void *dlg) { struct dlgparam *dp = (struct dlgparam *)dlg; struct winctrl *c = dlg_findbyctrl(dp, ctrl); int id; HWND ctl; switch (ctrl->generic.type) { case CTRL_EDITBOX: id = c->base_id + 1; break; case CTRL_RADIO: for (id = c->base_id + ctrl->radio.nbuttons; id > 1; id--) if (IsDlgButtonChecked(dp->hwnd, id)) break; /* |
︙ | ︙ | |||
2475 2476 2477 2478 2479 2480 2481 | } else return 0; } void dlg_auto_set_fixed_pitch_flag(void *dlg) { struct dlgparam *dp = (struct dlgparam *)dlg; | | < < | | < < < | | | | | | | | 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 | } else return 0; } void dlg_auto_set_fixed_pitch_flag(void *dlg) { struct dlgparam *dp = (struct dlgparam *)dlg; Config *cfg = (Config *)dp->data; HFONT font; HDC hdc; TEXTMETRIC tm; int is_var; /* * Attempt to load the current font, and see if it's * variable-pitch. If so, start off the fixed-pitch flag for the * dialog box as false. * * We assume here that any client of the dlg_* mechanism which is * using font selectors at all is also using a normal 'Config *' * as dp->data. */ font = CreateFont(0, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, FONT_QUALITY(cfg->font_quality), FIXED_PITCH | FF_DONTCARE, cfg->font.name); hdc = GetDC(NULL); if (font && hdc && SelectObject(hdc, font) && GetTextMetrics(hdc, &tm)) { /* Note that the TMPF_FIXED_PITCH bit is defined upside down :-( */ is_var = (tm.tmPitchAndFamily & TMPF_FIXED_PITCH); } else { is_var = FALSE; /* assume it's basically normal */ } if (hdc) ReleaseDC(NULL, hdc); if (font) DeleteObject(font); if (is_var) dp->fixed_pitch_fonts = FALSE; } int dlg_get_fixed_pitch_flag(void *dlg) { |
︙ | ︙ |
Changes to windows/windefs.c.
1 2 3 4 5 6 7 8 | /* * windefs.c: default settings that are specific to Windows. */ #include "putty.h" #include <commctrl.h> | | > | | > > > | > > | | > | > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | /* * windefs.c: default settings that are specific to Windows. */ #include "putty.h" #include <commctrl.h> FontSpec platform_default_fontspec(const char *name) { FontSpec ret; if (!strcmp(name, "Font")) { strcpy(ret.name, "Courier New"); ret.isbold = 0; ret.charset = ANSI_CHARSET; ret.height = 10; } else { ret.name[0] = '\0'; } return ret; } Filename platform_default_filename(const char *name) { Filename ret; if (!strcmp(name, "LogFileName")) strcpy(ret.path, "putty.log"); else *ret.path = '\0'; return ret; } char *platform_default_s(const char *name) { if (!strcmp(name, "SerialLine")) return dupstr("COM1"); return NULL; |
︙ | ︙ |
Changes to windows/windlg.c.
︙ | ︙ | |||
40 41 42 43 44 45 46 | */ static struct winctrls ctrls_base, ctrls_panel; static struct dlgparam dp; static char **events = NULL; static int nevents = 0, negsize = 0; | | | 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | */ static struct winctrls ctrls_base, ctrls_panel; static struct dlgparam dp; static char **events = NULL; static int nevents = 0, negsize = 0; extern Config cfg; /* defined in window.c */ #define PRINTER_DISABLED_STRING "None (printing disabled)" void force_normal(HWND hwnd) { static int recurse = 0; |
︙ | ︙ | |||
213 214 215 216 217 218 219 | EnableWindow(hwnd, 1); SetActiveWindow(hwnd); return 0; case IDA_WEB: /* Load web browser */ ShellExecute(hwnd, "open", | | | 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 | EnableWindow(hwnd, 1); SetActiveWindow(hwnd); return 0; case IDA_WEB: /* Load web browser */ ShellExecute(hwnd, "open", "http://www.risacher.org/putty-cac/", 0, 0, SW_SHOWDEFAULT); return 0; } return 0; case WM_CLOSE: EndDialog(hwnd, TRUE); return 0; |
︙ | ︙ | |||
644 645 646 647 648 649 650 | dp_init(&dp); winctrl_init(&ctrls_base); winctrl_init(&ctrls_panel); dp_add_tree(&dp, &ctrls_base); dp_add_tree(&dp, &ctrls_panel); dp.wintitle = dupprintf("%s Configuration", appname); dp.errtitle = dupprintf("%s Error", appname); | | | | | < | | > | < | < | 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 | dp_init(&dp); winctrl_init(&ctrls_base); winctrl_init(&ctrls_panel); dp_add_tree(&dp, &ctrls_base); dp_add_tree(&dp, &ctrls_panel); dp.wintitle = dupprintf("%s Configuration", appname); dp.errtitle = dupprintf("%s Error", appname); dp.data = &cfg; dlg_auto_set_fixed_pitch_flag(&dp); dp.shortcuts['g'] = TRUE; /* the treeview: `Cate&gory' */ ret = SaneDialogBox(hinst, MAKEINTRESOURCE(IDD_MAINBOX), NULL, GenericMainDlgProc); ctrl_free_box(ctrlbox); winctrl_cleanup(&ctrls_panel); winctrl_cleanup(&ctrls_base); dp_cleanup(&dp); return ret; } int do_reconfig(HWND hwnd, int protcfginfo) { Config backup_cfg; int ret; backup_cfg = cfg; /* structure copy */ ctrlbox = ctrl_new_box(); setup_config_box(ctrlbox, TRUE, cfg.protocol, protcfginfo); win_setup_config_box(ctrlbox, &dp.hwnd, has_help(), TRUE, cfg.protocol); dp_init(&dp); winctrl_init(&ctrls_base); winctrl_init(&ctrls_panel); dp_add_tree(&dp, &ctrls_base); dp_add_tree(&dp, &ctrls_panel); dp.wintitle = dupprintf("%s Reconfiguration", appname); dp.errtitle = dupprintf("%s Error", appname); dp.data = &cfg; dlg_auto_set_fixed_pitch_flag(&dp); dp.shortcuts['g'] = TRUE; /* the treeview: `Cate&gory' */ ret = SaneDialogBox(hinst, MAKEINTRESOURCE(IDD_MAINBOX), NULL, GenericMainDlgProc); ctrl_free_box(ctrlbox); winctrl_cleanup(&ctrls_base); winctrl_cleanup(&ctrls_panel); dp_cleanup(&dp); if (!ret) cfg = backup_cfg; /* structure copy */ return ret; } void logevent(void *frontend, const char *string) { char timebuf[40]; |
︙ | ︙ | |||
854 855 856 857 858 859 860 | return 0; } /* * Ask whether to wipe a session log file before writing to it. * Returns 2 for wipe, 1 for append, 0 for cancel (don't log). */ | | | | 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 | return 0; } /* * Ask whether to wipe a session log file before writing to it. * Returns 2 for wipe, 1 for append, 0 for cancel (don't log). */ int askappend(void *frontend, Filename filename, void (*callback)(void *ctx, int result), void *ctx) { static const char msgtemplate[] = "The session log file \"%.*s\" already exists.\n" "You can overwrite it with a new session log,\n" "append your session log to the end of it,\n" "or disable session logging for this session.\n" "Hit Yes to wipe the file, No to append to it,\n" "or Cancel to disable logging."; char *message; char *mbtitle; int mbret; message = dupprintf(msgtemplate, FILENAME_MAX, filename.path); mbtitle = dupprintf("%s Log to File", appname); mbret = MessageBox(NULL, message, mbtitle, MB_ICONQUESTION | MB_YESNOCANCEL | MB_DEFBUTTON3); socket_reselect_all(); |
︙ | ︙ |
Changes to windows/window.c.
︙ | ︙ | |||
76 77 78 79 80 81 82 | #define WHEEL_DELTA 120 #endif static Mouse_Button translate_button(Mouse_Button button); static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, unsigned char *output); | | | > > > > | < < < < < < | < < < < | 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | #define WHEEL_DELTA 120 #endif static Mouse_Button translate_button(Mouse_Button button); static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, unsigned char *output); static void cfgtopalette(void); static void systopalette(void); static void init_palette(void); static void init_fonts(int, int); static void another_font(int); static void deinit_fonts(void); static void set_input_locale(HKL); static void update_savedsess_menu(void); static void init_flashwindow(void); static int is_full_screen(void); static void make_full_screen(void); static void clear_full_screen(void); static void flip_full_screen(void); static int process_clipdata(HGLOBAL clipdata, int unicode); /* Window layout information */ static void reset_window(int); static int extra_width, extra_height; static int font_width, font_height, font_dualwidth, font_varpitch; static int offset_width, offset_height; static int was_zoomed = 0; static int prev_rows, prev_cols; static int pending_netevent = 0; static WPARAM pend_netevent_wParam = 0; static LPARAM pend_netevent_lParam = 0; static void enact_pending_netevent(void); static void flash_window(int mode); static void sys_cursor_update(void); static int get_fullscreen_rect(RECT * ss); static int caret_x = -1, caret_y = -1; static int kbd_codepage; static void *ldisc; static Backend *back; static void *backhandle; static struct unicode_data ucsdata; static int must_close_session, session_closed; static int reconfiguring = FALSE; static const struct telnet_special *specials = NULL; static HMENU specials_menu = NULL; static int n_specials = 0; static wchar_t *clipboard_contents; static size_t clipboard_length; #define TIMING_TIMER_ID 1234 static long timing_next_time; static struct { HMENU menu; } popup_menus[2]; enum { SYSMENU, CTXMENU }; static HMENU savedsess_menu; Config cfg; /* exported to windlg.c */ static struct sesslist sesslist; /* for saved-session menu */ struct agent_callback { void (*callback)(void *, void *, int); void *callback_ctx; void *data; |
︙ | ︙ | |||
166 167 168 169 170 171 172 | #define FONT_NARROW 0x10 #define FONT_OEM 0x20 #define FONT_OEMBOLD 0x21 #define FONT_OEMUND 0x22 #define FONT_OEMBOLDUND 0x23 | | | | < | 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 | #define FONT_NARROW 0x10 #define FONT_OEM 0x20 #define FONT_OEMBOLD 0x21 #define FONT_OEMUND 0x22 #define FONT_OEMBOLDUND 0x23 #define FONT_MAXNO 0x2F #define FONT_SHIFT 5 static HFONT fonts[FONT_MAXNO]; static LOGFONT lfont; static int fontflag[FONT_MAXNO]; static enum { BOLD_COLOURS, BOLD_SHADOW, BOLD_FONT } bold_mode; static enum { UND_LINE, UND_FONT } und_mode; static int descent; #define NCFGCOLOURS 22 #define NEXTCOLOURS 240 |
︙ | ︙ | |||
205 206 207 208 209 210 211 | static char *window_name, *icon_name; static int compose_state = 0; static UINT wm_mousewheel = WM_MOUSEWHEEL; | < < < < < < < < < | 198 199 200 201 202 203 204 205 206 207 208 209 210 211 | static char *window_name, *icon_name; static int compose_state = 0; static UINT wm_mousewheel = WM_MOUSEWHEEL; /* Dummy routine, only required in plink. */ void ldisc_update(void *frontend, int echo, int edit) { } char *get_ttymode(void *frontend, const char *mode) { |
︙ | ︙ | |||
235 236 237 238 239 240 241 | char *realhost; int i; /* * Select protocol. This is farmed out into a table in a * separate file to enable an ssh-free variant. */ | | | < < | < | | | | > | > | | 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 | char *realhost; int i; /* * Select protocol. This is farmed out into a table in a * separate file to enable an ssh-free variant. */ back = backend_from_proto(cfg.protocol); if (back == NULL) { char *str = dupprintf("%s Internal Error", appname); MessageBox(NULL, "Unsupported protocol number found", str, MB_OK | MB_ICONEXCLAMATION); sfree(str); cleanup_exit(1); } error = back->init(NULL, &backhandle, &cfg, cfg.host, cfg.port, &realhost, cfg.tcp_nodelay, cfg.tcp_keepalives); back->provide_logctx(backhandle, logctx); if (error) { char *str = dupprintf("%s Error", appname); sprintf(msg, "Unable to open connection to\n" "%.800s\n" "%s", cfg_dest(&cfg), error); MessageBox(NULL, msg, str, MB_ICONERROR | MB_OK); sfree(str); exit(0); } window_name = icon_name = NULL; if (*cfg.wintitle) { title = cfg.wintitle; } else { sprintf(msg, "%s - %s", realhost, appname); title = msg; } sfree(realhost); set_title(NULL, title); set_icon(NULL, title); /* * Connect the terminal to the backend for resize purposes. */ term_provide_resize_fn(term, back->size, backhandle); /* * Set up a line discipline. */ ldisc = ldisc_create(&cfg, term, back, backhandle, NULL); /* * Destroy the Restart Session menu item. (This will return * failure if it's already absent, as it will be the very first * time we call this function. We ignore that, because as long * as the menu item ends up not being there, we don't care * whether it was us who removed it or not!) */ for (i = 0; i < lenof(popup_menus); i++) { DeleteMenu(popup_menus[i].menu, IDM_RESTART, MF_BYCOMMAND); } must_close_session = FALSE; session_closed = FALSE; } static void close_session(void) { char morestuff[100]; int i; session_closed = TRUE; sprintf(morestuff, "%.70s (inactive)", appname); set_icon(NULL, morestuff); |
︙ | ︙ | |||
324 325 326 327 328 329 330 331 332 333 334 335 336 337 | * delete first to ensure we never end up with more than one. */ for (i = 0; i < lenof(popup_menus); i++) { DeleteMenu(popup_menus[i].menu, IDM_RESTART, MF_BYCOMMAND); InsertMenu(popup_menus[i].menu, IDM_DUPSESS, MF_BYCOMMAND | MF_ENABLED, IDM_RESTART, "&Restart Session"); } } int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { WNDCLASS wndclass; MSG msg; HRESULT hr; | > > > > > > > > > | 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 | * delete first to ensure we never end up with more than one. */ for (i = 0; i < lenof(popup_menus); i++) { DeleteMenu(popup_menus[i].menu, IDM_RESTART, MF_BYCOMMAND); InsertMenu(popup_menus[i].menu, IDM_DUPSESS, MF_BYCOMMAND | MF_ENABLED, IDM_RESTART, "&Restart Session"); } /* * Unset the 'must_close_session' flag, or else we'll come * straight back here the next time we go round the main message * loop - which, worse still, will be immediately (without * blocking) because we've just triggered a WM_SETTEXT by the * window title change above. */ must_close_session = FALSE; } int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { WNDCLASS wndclass; MSG msg; HRESULT hr; |
︙ | ︙ | |||
366 367 368 369 370 371 372 | if (osVersion.dwMajorVersion < 4 || (osVersion.dwMajorVersion == 4 && osVersion.dwPlatformId != VER_PLATFORM_WIN32_NT)) wm_mousewheel = RegisterWindowMessage("MSWHEEL_ROLLMSG"); init_help(); | < | < | 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 | if (osVersion.dwMajorVersion < 4 || (osVersion.dwMajorVersion == 4 && osVersion.dwPlatformId != VER_PLATFORM_WIN32_NT)) wm_mousewheel = RegisterWindowMessage("MSWHEEL_ROLLMSG"); init_help(); init_flashwindow(); /* * Initialize COM. */ hr = CoInitialize(NULL); if (hr != S_OK && hr != S_FALSE) { char *str = dupprintf("%s Fatal Error", appname); |
︙ | ︙ | |||
401 402 403 404 405 406 407 | /* Find the appropriate default port. */ { Backend *b = backend_from_proto(default_protocol); default_port = 0; /* illegal */ if (b) default_port = b->default_port; } | | | | 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 | /* Find the appropriate default port. */ { Backend *b = backend_from_proto(default_protocol); default_port = 0; /* illegal */ if (b) default_port = b->default_port; } cfg.logtype = LGTYP_NONE; do_defaults(NULL, &cfg); p = cmdline; /* * Process a couple of command-line options which are more * easily dealt with before the line is broken up into words. * These are the old-fashioned but convenient @sessionname and |
︙ | ︙ | |||
428 429 430 431 432 433 434 | * very convenient means of automated saved-session * launching, via IDM_SAVEDSESS or Windows 7 jump lists. */ int i = strlen(p); while (i > 1 && isspace(p[i - 1])) i--; p[i] = '\0'; | | | | | | < | | < > | 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 | * very convenient means of automated saved-session * launching, via IDM_SAVEDSESS or Windows 7 jump lists. */ int i = strlen(p); while (i > 1 && isspace(p[i - 1])) i--; p[i] = '\0'; do_defaults(p + 1, &cfg); if (!cfg_launchable(&cfg) && !do_config()) { cleanup_exit(0); } allow_launch = TRUE; /* allow it to be launched directly */ } else if (*p == '&') { /* * An initial & means we've been given a command line * containing the hex value of a HANDLE for a file * mapping object, which we must then extract as a * config. */ HANDLE filemap; Config *cp; if (sscanf(p + 1, "%p", &filemap) == 1 && (cp = MapViewOfFile(filemap, FILE_MAP_READ, 0, 0, sizeof(Config))) != NULL) { cfg = *cp; UnmapViewOfFile(cp); CloseHandle(filemap); } else if (!do_config()) { cleanup_exit(0); } allow_launch = TRUE; } else { |
︙ | ︙ | |||
468 469 470 471 472 473 474 | split_into_argv(cmdline, &argc, &argv, NULL); for (i = 0; i < argc; i++) { char *p = argv[i]; int ret; ret = cmdline_process_param(p, i+1<argc?argv[i+1]:NULL, | | | 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 | split_into_argv(cmdline, &argc, &argv, NULL); for (i = 0; i < argc; i++) { char *p = argv[i]; int ret; ret = cmdline_process_param(p, i+1<argc?argv[i+1]:NULL, 1, &cfg); if (ret == -2) { cmdline_error("option \"%s\" requires an argument", p); } else if (ret == 2) { i++; /* skip next argument */ } else if (ret == 1) { continue; /* nothing further needs doing */ } else if (!strcmp(p, "-cleanup") || |
︙ | ︙ | |||
529 530 531 532 533 534 535 | /* * If we already have a host name, treat * this argument as a port number. NB we * have to treat this as a saved -P * argument, so that it will be deferred * until it's a good moment to run it. */ | | | | | | > | > | | | | | < | < < < < < | < < | | > | | | > > | | | | | | | | | | | | | | | | | | | | | < > | | | | | | | | < | < < | | | | | | | < < < < < < | | | | < > > > > > | | 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 | /* * If we already have a host name, treat * this argument as a port number. NB we * have to treat this as a saved -P * argument, so that it will be deferred * until it's a good moment to run it. */ int ret = cmdline_process_param("-P", p, 1, &cfg); assert(ret == 2); } else if (!strncmp(q, "telnet:", 7)) { /* * If the hostname starts with "telnet:", * set the protocol to Telnet and process * the string as a Telnet URL. */ char c; q += 7; if (q[0] == '/' && q[1] == '/') q += 2; cfg.protocol = PROT_TELNET; p = q; while (*p && *p != ':' && *p != '/') p++; c = *p; if (*p) *p++ = '\0'; if (c == ':') cfg.port = atoi(p); else cfg.port = -1; strncpy(cfg.host, q, sizeof(cfg.host) - 1); cfg.host[sizeof(cfg.host) - 1] = '\0'; got_host = 1; } else { /* * Otherwise, treat this argument as a host * name. */ while (*p && !isspace(*p)) p++; if (*p) *p++ = '\0'; strncpy(cfg.host, q, sizeof(cfg.host) - 1); cfg.host[sizeof(cfg.host) - 1] = '\0'; got_host = 1; } } else { cmdline_error("unknown option \"%s\"", p); } } } cmdline_run_saved(&cfg); if (loaded_session || got_host) allow_launch = TRUE; if ((!allow_launch || !cfg_launchable(&cfg)) && !do_config()) { cleanup_exit(0); } /* * Trim leading whitespace off the hostname if it's there. */ { int space = strspn(cfg.host, " \t"); memmove(cfg.host, cfg.host+space, 1+strlen(cfg.host)-space); } /* See if host is of the form user@host */ if (cfg.host[0] != '\0') { char *atsign = strrchr(cfg.host, '@'); /* Make sure we're not overflowing the user field */ if (atsign) { if (atsign - cfg.host < sizeof cfg.username) { strncpy(cfg.username, cfg.host, atsign - cfg.host); cfg.username[atsign - cfg.host] = '\0'; } memmove(cfg.host, atsign + 1, 1 + strlen(atsign + 1)); } } /* * Trim a colon suffix off the hostname if it's there. In * order to protect IPv6 address literals against this * treatment, we do not do this if there's _more_ than one * colon. */ { char *c = strchr(cfg.host, ':'); if (c) { char *d = strchr(c+1, ':'); if (!d) *c = '\0'; } } /* * Remove any remaining whitespace from the hostname. */ { int p1 = 0, p2 = 0; while (cfg.host[p2] != '\0') { if (cfg.host[p2] != ' ' && cfg.host[p2] != '\t') { cfg.host[p1] = cfg.host[p2]; p1++; } p2++; } cfg.host[p1] = '\0'; } } if (!prev) { wndclass.style = 0; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = inst; wndclass.hIcon = LoadIcon(inst, MAKEINTRESOURCE(IDI_MAINICON)); wndclass.hCursor = LoadCursor(NULL, IDC_IBEAM); wndclass.hbrBackground = NULL; wndclass.lpszMenuName = NULL; wndclass.lpszClassName = appname; RegisterClass(&wndclass); } memset(&ucsdata, 0, sizeof(ucsdata)); cfgtopalette(); /* * Guess some defaults for the window size. This all gets * updated later, so we don't really care too much. However, we * do want the font width/height guesses to correspond to a * large font rather than a small one... */ font_width = 10; font_height = 20; extra_width = 25; extra_height = 28; guess_width = extra_width + font_width * cfg.width; guess_height = extra_height + font_height * cfg.height; { RECT r; get_fullscreen_rect(&r); if (guess_width > r.right - r.left) guess_width = r.right - r.left; if (guess_height > r.bottom - r.top) guess_height = r.bottom - r.top; } { int winmode = WS_OVERLAPPEDWINDOW | WS_VSCROLL; int exwinmode = 0; if (!cfg.scrollbar) winmode &= ~(WS_VSCROLL); if (cfg.resize_action == RESIZE_DISABLED) winmode &= ~(WS_THICKFRAME | WS_MAXIMIZEBOX); if (cfg.alwaysontop) exwinmode |= WS_EX_TOPMOST; if (cfg.sunken_edge) exwinmode |= WS_EX_CLIENTEDGE; hwnd = CreateWindowEx(exwinmode, appname, appname, winmode, CW_USEDEFAULT, CW_USEDEFAULT, guess_width, guess_height, NULL, NULL, inst, NULL); } /* * Initialise the terminal. (We have to do this _after_ * creating the window, since the terminal is the first thing * which will call schedule_timer(), which will in turn call * timer_change_notify() which will expect hwnd to exist.) */ term = term_init(&cfg, &ucsdata, NULL); logctx = log_init(NULL, &cfg); term_provide_logctx(term, logctx); term_size(term, cfg.height, cfg.width, cfg.savelines); /* * Initialise the fonts, simultaneously correcting the guesses * for font_{width,height}. */ init_fonts(0,0); /* * Correct the guesses for extra_{width,height}. */ { RECT cr, wr; GetWindowRect(hwnd, &wr); GetClientRect(hwnd, &cr); offset_width = offset_height = cfg.window_border; extra_width = wr.right - wr.left - cr.right + cr.left + offset_width*2; extra_height = wr.bottom - wr.top - cr.bottom + cr.top +offset_height*2; } /* * Resize the window, now we know what size we _really_ want it * to be. |
︙ | ︙ | |||
808 809 810 811 812 813 814 | "Sa&ved Sessions"); AppendMenu(m, MF_ENABLED, IDM_RECONF, "Chan&ge Settings..."); AppendMenu(m, MF_SEPARATOR, 0, 0); AppendMenu(m, MF_ENABLED, IDM_COPYALL, "C&opy All to Clipboard"); AppendMenu(m, MF_ENABLED, IDM_CLRSB, "C&lear Scrollback"); AppendMenu(m, MF_ENABLED, IDM_RESET, "Rese&t Terminal"); AppendMenu(m, MF_SEPARATOR, 0, 0); | < | | | 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 | "Sa&ved Sessions"); AppendMenu(m, MF_ENABLED, IDM_RECONF, "Chan&ge Settings..."); AppendMenu(m, MF_SEPARATOR, 0, 0); AppendMenu(m, MF_ENABLED, IDM_COPYALL, "C&opy All to Clipboard"); AppendMenu(m, MF_ENABLED, IDM_CLRSB, "C&lear Scrollback"); AppendMenu(m, MF_ENABLED, IDM_RESET, "Rese&t Terminal"); AppendMenu(m, MF_SEPARATOR, 0, 0); AppendMenu(m, (cfg.resize_action == RESIZE_DISABLED) ? MF_GRAYED : MF_ENABLED, IDM_FULLSCREEN, "&Full Screen"); AppendMenu(m, MF_SEPARATOR, 0, 0); if (has_help()) AppendMenu(m, MF_ENABLED, IDM_HELP, "&Help"); str = dupprintf("&About %s", appname); AppendMenu(m, MF_ENABLED, IDM_ABOUT, str); sfree(str); } |
︙ | ︙ | |||
846 847 848 849 850 851 852 | term_set_focus(term, GetForegroundWindow() == hwnd); UpdateWindow(hwnd); while (1) { HANDLE *handles; int nhandles, n; | < < < < < < < < < < < < < < < < < < < < < < < < < < < | | > > | > > > > > > > > > > | > > > > | 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 | term_set_focus(term, GetForegroundWindow() == hwnd); UpdateWindow(hwnd); while (1) { HANDLE *handles; int nhandles, n; handles = handle_get_events(&nhandles); n = MsgWaitForMultipleObjects(nhandles, handles, FALSE, INFINITE, QS_ALLINPUT); if ((unsigned)(n - WAIT_OBJECT_0) < (unsigned)nhandles) { handle_got_event(handles[n - WAIT_OBJECT_0]); sfree(handles); if (must_close_session) close_session(); } else sfree(handles); while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) goto finished; /* two-level break */ if (!(IsWindow(logbox) && IsDialogMessage(logbox, &msg))) DispatchMessage(&msg); /* Send the paste buffer if there's anything to send */ term_paste(term); /* If there's nothing new in the queue then we can do everything * we've delayed, reading the socket, writing, and repainting * the window. */ if (must_close_session) close_session(); } /* The messages seem unreliable; especially if we're being tricky */ term_set_focus(term, GetForegroundWindow() == hwnd); if (pending_netevent) enact_pending_netevent(); net_pending_errors(); } finished: cleanup_exit(msg.wParam); /* this doesn't return... */ return msg.wParam; /* ... but optimiser doesn't know */ } |
︙ | ︙ | |||
915 916 917 918 919 920 921 | */ deinit_fonts(); sfree(logpal); if (pal) DeleteObject(pal); sk_cleanup(); | | | 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 | */ deinit_fonts(); sfree(logpal); if (pal) DeleteObject(pal); sk_cleanup(); if (cfg.protocol == PROT_SSH) { random_save_seed(); #ifdef MSCRYPTOAPI crypto_wrapup(); #endif } shutdown_help(); |
︙ | ︙ | |||
1093 1094 1095 1096 1097 1098 1099 | } /* * set or clear the "raw mouse message" mode */ void set_raw_mouse_mode(void *frontend, int activate) { | | | | | 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 | } /* * set or clear the "raw mouse message" mode */ void set_raw_mouse_mode(void *frontend, int activate) { activate = activate && !cfg.no_mouse_rep; send_raw_mouse = activate; update_mouse_pointer(); } /* * Print a message box and close the connection. */ void connection_fatal(void *frontend, char *fmt, ...) { va_list ap; char *stuff, morestuff[100]; va_start(ap, fmt); stuff = dupvprintf(fmt, ap); va_end(ap); sprintf(morestuff, "%.70s Fatal Error", appname); MessageBox(hwnd, stuff, morestuff, MB_ICONERROR | MB_OK); sfree(stuff); if (cfg.close_on_exit == FORCE_ON) PostQuitMessage(1); else { must_close_session = TRUE; } } /* * Report an error at the command-line parsing stage. */ void cmdline_error(char *fmt, ...) |
︙ | ︙ | |||
1140 1141 1142 1143 1144 1145 1146 | sfree(stuff); exit(1); } /* * Actually do the job requested by a WM_NETEVENT */ | | > > | > > | > | > > > | | | | | | 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 | sfree(stuff); exit(1); } /* * Actually do the job requested by a WM_NETEVENT */ static void enact_pending_netevent(void) { static int reentering = 0; extern int select_result(WPARAM, LPARAM); if (reentering) return; /* don't unpend the pending */ pending_netevent = FALSE; reentering = 1; select_result(pend_netevent_wParam, pend_netevent_lParam); reentering = 0; } /* * Copy the colour palette from the configuration data into defpal. * This is non-trivial because the colour indices are different. */ static void cfgtopalette(void) { int i; static const int ww[] = { 256, 257, 258, 259, 260, 261, 0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15 }; for (i = 0; i < 22; i++) { int w = ww[i]; defpal[w].rgbtRed = cfg.colours[i][0]; defpal[w].rgbtGreen = cfg.colours[i][1]; defpal[w].rgbtBlue = cfg.colours[i][2]; } for (i = 0; i < NEXTCOLOURS; i++) { if (i < 216) { int r = i / 36, g = (i / 6) % 6, b = i % 6; defpal[i+16].rgbtRed = r ? r * 40 + 55 : 0; defpal[i+16].rgbtGreen = g ? g * 40 + 55 : 0; defpal[i+16].rgbtBlue = b ? b * 40 + 55 : 0; } else { int shade = i - 216; shade = shade * 10 + 8; defpal[i+16].rgbtRed = defpal[i+16].rgbtGreen = defpal[i+16].rgbtBlue = shade; } } /* Override with system colours if appropriate */ if (cfg.system_colour) systopalette(); } /* * Override bit of defpal with colours from the system. * (NB that this takes a copy the system colours at the time this is called, * so subsequent colour scheme changes don't take effect. To fix that we'd |
︙ | ︙ | |||
1221 1222 1223 1224 1225 1226 1227 | * Set up the colour palette. */ static void init_palette(void) { int i; HDC hdc = GetDC(hwnd); if (hdc) { | < | | 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 | * Set up the colour palette. */ static void init_palette(void) { int i; HDC hdc = GetDC(hwnd); if (hdc) { if (cfg.try_palette && GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) { /* * This is a genuine case where we must use smalloc * because the snew macros can't cope. */ logpal = smalloc(sizeof(*logpal) - sizeof(logpal->palPalEntry) + NALLCOLOURS * sizeof(PALETTEENTRY)); |
︙ | ︙ | |||
1405 1406 1407 1408 1409 1410 1411 | * ordinary one (manual underlining by means of line drawing can * be done in a pinch). */ static void init_fonts(int pick_width, int pick_height) { TEXTMETRIC tm; CPINFO cpinfo; | < < < | < < | | < | | | | 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 | * ordinary one (manual underlining by means of line drawing can * be done in a pinch). */ static void init_fonts(int pick_width, int pick_height) { TEXTMETRIC tm; CPINFO cpinfo; int fontsize[3]; int i; HDC hdc; int fw_dontcare, fw_bold; for (i = 0; i < FONT_MAXNO; i++) fonts[i] = NULL; bold_mode = cfg.bold_colour ? BOLD_COLOURS : BOLD_FONT; und_mode = UND_FONT; if (cfg.font.isbold) { fw_dontcare = FW_BOLD; fw_bold = FW_HEAVY; } else { fw_dontcare = FW_DONTCARE; fw_bold = FW_BOLD; } hdc = GetDC(hwnd); if (pick_height) font_height = pick_height; else { font_height = cfg.font.height; if (font_height > 0) { font_height = -MulDiv(font_height, GetDeviceCaps(hdc, LOGPIXELSY), 72); } } font_width = pick_width; #define f(i,c,w,u) \ fonts[i] = CreateFont (font_height, font_width, 0, 0, w, FALSE, u, FALSE, \ c, OUT_DEFAULT_PRECIS, \ CLIP_DEFAULT_PRECIS, FONT_QUALITY(cfg.font_quality), \ FIXED_PITCH | FF_DONTCARE, cfg.font.name) f(FONT_NORMAL, cfg.font.charset, fw_dontcare, FALSE); SelectObject(hdc, fonts[FONT_NORMAL]); GetTextMetrics(hdc, &tm); GetObject(fonts[FONT_NORMAL], sizeof(LOGFONT), &lfont); /* Note that the TMPF_FIXED_PITCH bit is defined upside down :-( */ |
︙ | ︙ | |||
1492 1493 1494 1495 1496 1497 1498 | else ucsdata.font_codepage = -1; GetCPInfo(ucsdata.font_codepage, &cpinfo); ucsdata.dbcs_screenfont = (cpinfo.MaxCharSize > 1); } | | | 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 | else ucsdata.font_codepage = -1; GetCPInfo(ucsdata.font_codepage, &cpinfo); ucsdata.dbcs_screenfont = (cpinfo.MaxCharSize > 1); } f(FONT_UNDERLINE, cfg.font.charset, fw_dontcare, TRUE); /* * Some fonts, e.g. 9-pt Courier, draw their underlines * outside their character cell. We successfully prevent * screen corruption by clipping the text output, but then * we lose the underline completely. Here we try to work * out whether this is such a font, and if it is, we set a |
︙ | ︙ | |||
1542 1543 1544 1545 1546 1547 1548 | if (!gotit) { und_mode = UND_LINE; DeleteObject(fonts[FONT_UNDERLINE]); fonts[FONT_UNDERLINE] = 0; } } | | | | 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 | if (!gotit) { und_mode = UND_LINE; DeleteObject(fonts[FONT_UNDERLINE]); fonts[FONT_UNDERLINE] = 0; } } if (bold_mode == BOLD_FONT) { f(FONT_BOLD, cfg.font.charset, fw_bold, FALSE); } #undef f descent = tm.tmAscent + 1; if (descent >= font_height) descent = font_height - 1; |
︙ | ︙ | |||
1569 1570 1571 1572 1573 1574 1575 | if (fontsize[FONT_UNDERLINE] != fontsize[FONT_NORMAL]) { und_mode = UND_LINE; DeleteObject(fonts[FONT_UNDERLINE]); fonts[FONT_UNDERLINE] = 0; } | | | | | < < < | | | < < | | 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 | if (fontsize[FONT_UNDERLINE] != fontsize[FONT_NORMAL]) { und_mode = UND_LINE; DeleteObject(fonts[FONT_UNDERLINE]); fonts[FONT_UNDERLINE] = 0; } if (bold_mode == BOLD_FONT && fontsize[FONT_BOLD] != fontsize[FONT_NORMAL]) { bold_mode = BOLD_SHADOW; DeleteObject(fonts[FONT_BOLD]); fonts[FONT_BOLD] = 0; } fontflag[0] = fontflag[1] = fontflag[2] = 1; init_ucs(&cfg, &ucsdata); } static void another_font(int fontno) { int basefont; int fw_dontcare, fw_bold; int c, u, w, x; char *s; if (fontno < 0 || fontno >= FONT_MAXNO || fontflag[fontno]) return; basefont = (fontno & ~(FONT_BOLDUND)); if (basefont != fontno && !fontflag[basefont]) another_font(basefont); if (cfg.font.isbold) { fw_dontcare = FW_BOLD; fw_bold = FW_HEAVY; } else { fw_dontcare = FW_DONTCARE; fw_bold = FW_BOLD; } c = cfg.font.charset; w = fw_dontcare; u = FALSE; s = cfg.font.name; x = font_width; if (fontno & FONT_WIDE) x *= 2; if (fontno & FONT_NARROW) x = (x+1)/2; if (fontno & FONT_OEM) c = OEM_CHARSET; if (fontno & FONT_BOLD) w = fw_bold; if (fontno & FONT_UNDERLINE) u = TRUE; fonts[fontno] = CreateFont(font_height * (1 + !!(fontno & FONT_HIGH)), x, 0, 0, w, FALSE, u, FALSE, c, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, FONT_QUALITY(cfg.font_quality), DEFAULT_PITCH | FF_DONTCARE, s); fontflag[fontno] = 1; } static void deinit_fonts(void) { |
︙ | ︙ | |||
1650 1651 1652 1653 1654 1655 1656 | void request_resize(void *frontend, int w, int h) { int width, height; /* If the window is maximized supress resizing attempts */ if (IsZoomed(hwnd)) { | | | | 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 | void request_resize(void *frontend, int w, int h) { int width, height; /* If the window is maximized supress resizing attempts */ if (IsZoomed(hwnd)) { if (cfg.resize_action == RESIZE_TERM) return; } if (cfg.resize_action == RESIZE_DISABLED) return; if (h == term->rows && w == term->cols) return; /* Sanity checks ... */ { static int first_time = 1; static RECT ss; |
︙ | ︙ | |||
1685 1686 1687 1688 1689 1690 1691 | if (w < 15) w = 15; if (h < 1) h = 1; } } | | < | | < < < | < | 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 | if (w < 15) w = 15; if (h < 1) h = 1; } } term_size(term, h, w, cfg.savelines); if (cfg.resize_action != RESIZE_FONT && !IsZoomed(hwnd)) { width = extra_width + font_width * w; height = extra_height + font_height * h; SetWindowPos(hwnd, NULL, 0, 0, width, height, SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOZORDER); } else reset_window(0); InvalidateRect(hwnd, NULL, TRUE); } static void reset_window(int reinit) { /* * This function decides how to resize or redraw when the * user changes something. * * This function doesn't like to change the terminal size but if the * font size is locked that may be it's only soluion. */ int win_width, win_height; RECT cr, wr; #ifdef RDB_DEBUG_PATCH debug((27, "reset_window()")); #endif /* Current window sizes ... */ GetWindowRect(hwnd, &wr); GetClientRect(hwnd, &cr); win_width = cr.right - cr.left; win_height = cr.bottom - cr.top; if (cfg.resize_action == RESIZE_DISABLED) reinit = 2; /* Are we being forced to reload the fonts ? */ if (reinit>1) { #ifdef RDB_DEBUG_PATCH debug((27, "reset_window() -- Forced deinit")); #endif deinit_fonts(); |
︙ | ︙ | |||
1762 1763 1764 1765 1766 1767 1768 | /* We're fullscreen, this means we must not change the size of * the window so it's the font size or the terminal itself. */ extra_width = wr.right - wr.left - cr.right + cr.left; extra_height = wr.bottom - wr.top - cr.bottom + cr.top; | | | | | | | | | 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 | /* We're fullscreen, this means we must not change the size of * the window so it's the font size or the terminal itself. */ extra_width = wr.right - wr.left - cr.right + cr.left; extra_height = wr.bottom - wr.top - cr.bottom + cr.top; if (cfg.resize_action != RESIZE_TERM) { if ( font_width != win_width/term->cols || font_height != win_height/term->rows) { deinit_fonts(); init_fonts(win_width/term->cols, win_height/term->rows); offset_width = (win_width-font_width*term->cols)/2; offset_height = (win_height-font_height*term->rows)/2; InvalidateRect(hwnd, NULL, TRUE); #ifdef RDB_DEBUG_PATCH debug((25, "reset_window() -> Z font resize to (%d, %d)", font_width, font_height)); #endif } } else { if ( font_width * term->cols != win_width || font_height * term->rows != win_height) { /* Our only choice at this point is to change the * size of the terminal; Oh well. */ term_size(term, win_height/font_height, win_width/font_width, cfg.savelines); offset_width = (win_width-font_width*term->cols)/2; offset_height = (win_height-font_height*term->rows)/2; InvalidateRect(hwnd, NULL, TRUE); #ifdef RDB_DEBUG_PATCH debug((27, "reset_window() -> Zoomed term_size")); #endif } } return; } /* Hmm, a force re-init means we should ignore the current window * so we resize to the default font size. */ if (reinit>0) { #ifdef RDB_DEBUG_PATCH debug((27, "reset_window() -> Forced re-init")); #endif offset_width = offset_height = cfg.window_border; extra_width = wr.right - wr.left - cr.right + cr.left + offset_width*2; extra_height = wr.bottom - wr.top - cr.bottom + cr.top +offset_height*2; if (win_width != font_width*term->cols + offset_width*2 || win_height != font_height*term->rows + offset_height*2) { /* If this is too large windows will resize it to the maximum |
︙ | ︙ | |||
1827 1828 1829 1830 1831 1832 1833 | return; } /* Okay the user doesn't want us to change the font so we try the * window. But that may be too big for the screen which forces us * to change the terminal. */ | | | | | | < | 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 | return; } /* Okay the user doesn't want us to change the font so we try the * window. But that may be too big for the screen which forces us * to change the terminal. */ if ((cfg.resize_action == RESIZE_TERM && reinit<=0) || (cfg.resize_action == RESIZE_EITHER && reinit<0) || reinit>0) { offset_width = offset_height = cfg.window_border; extra_width = wr.right - wr.left - cr.right + cr.left + offset_width*2; extra_height = wr.bottom - wr.top - cr.bottom + cr.top +offset_height*2; if (win_width != font_width*term->cols + offset_width*2 || win_height != font_height*term->rows + offset_height*2) { static RECT ss; int width, height; get_fullscreen_rect(&ss); width = (ss.right - ss.left - extra_width) / font_width; height = (ss.bottom - ss.top - extra_height) / font_height; /* Grrr too big */ if ( term->rows > height || term->cols > width ) { if (cfg.resize_action == RESIZE_EITHER) { /* Make the font the biggest we can */ if (term->cols > width) font_width = (ss.right - ss.left - extra_width) / term->cols; if (term->rows > height) font_height = (ss.bottom - ss.top - extra_height) / term->rows; deinit_fonts(); init_fonts(font_width, font_height); width = (ss.right - ss.left - extra_width) / font_width; height = (ss.bottom - ss.top - extra_height) / font_height; } else { if ( height > term->rows ) height = term->rows; if ( width > term->cols ) width = term->cols; term_size(term, height, width, cfg.savelines); #ifdef RDB_DEBUG_PATCH debug((27, "reset_window() -> term resize to (%d,%d)", height, width)); #endif } } |
︙ | ︙ | |||
1890 1891 1892 1893 1894 1895 1896 | #endif } return; } /* We're allowed to or must change the font but do we want to ? */ | | | | | | 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 | #endif } return; } /* We're allowed to or must change the font but do we want to ? */ if (font_width != (win_width-cfg.window_border*2)/term->cols || font_height != (win_height-cfg.window_border*2)/term->rows) { deinit_fonts(); init_fonts((win_width-cfg.window_border*2)/term->cols, (win_height-cfg.window_border*2)/term->rows); offset_width = (win_width-font_width*term->cols)/2; offset_height = (win_height-font_height*term->rows)/2; extra_width = wr.right - wr.left - cr.right + cr.left +offset_width*2; extra_height = wr.bottom - wr.top - cr.bottom + cr.top+offset_height*2; InvalidateRect(hwnd, NULL, TRUE); |
︙ | ︙ | |||
1924 1925 1926 1927 1928 1929 1930 | kbd_codepage = atoi(lbuf); } static void click(Mouse_Button b, int x, int y, int shift, int ctrl, int alt) { int thistime = GetMessageTime(); | | < | 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 | kbd_codepage = atoi(lbuf); } static void click(Mouse_Button b, int x, int y, int shift, int ctrl, int alt) { int thistime = GetMessageTime(); if (send_raw_mouse && !(cfg.mouse_override && shift)) { lastbtn = MBT_NOTHING; term_mouse(term, b, translate_button(b), MA_CLICK, x, y, shift, ctrl, alt); return; } if (lastbtn == b && thistime - lasttime < dbltime) { |
︙ | ︙ | |||
1955 1956 1957 1958 1959 1960 1961 | * into a cooked one (SELECT, EXTEND, PASTE). */ static Mouse_Button translate_button(Mouse_Button button) { if (button == MBT_LEFT) return MBT_SELECT; if (button == MBT_MIDDLE) | < | < | < | > | 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 | * into a cooked one (SELECT, EXTEND, PASTE). */ static Mouse_Button translate_button(Mouse_Button button) { if (button == MBT_LEFT) return MBT_SELECT; if (button == MBT_MIDDLE) return cfg.mouse_is_xterm == 1 ? MBT_PASTE : MBT_EXTEND; if (button == MBT_RIGHT) return cfg.mouse_is_xterm == 1 ? MBT_EXTEND : MBT_PASTE; return 0; /* shouldn't happen */ } static void show_mouseptr(int show) { /* NB that the counter in ShowCursor() is also frobbed by * update_mouse_pointer() */ static int cursor_visible = 1; if (!cfg.hide_mouseptr) /* override if this feature disabled */ show = 1; if (cursor_visible && !show) ShowCursor(FALSE); else if (!cursor_visible && show) ShowCursor(TRUE); cursor_visible = show; } |
︙ | ︙ | |||
1994 1995 1996 1997 1998 1999 2000 | return FALSE; } static int resizing; void notify_remote_exit(void *fe) { | | < | | | | < | < | < < < < < < < < < < | | | 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 | return FALSE; } static int resizing; void notify_remote_exit(void *fe) { int exitcode; if (!session_closed && (exitcode = back->exitcode(backhandle)) >= 0) { /* Abnormal exits will already have set session_closed and taken * appropriate action. */ if (cfg.close_on_exit == FORCE_ON || (cfg.close_on_exit == AUTO && exitcode != INT_MAX)) { PostQuitMessage(0); } else { must_close_session = TRUE; session_closed = TRUE; /* exitcode == INT_MAX indicates that the connection was closed * by a fatal error, so an error box will be coming our way and * we should not generate this informational one. */ if (exitcode != INT_MAX) MessageBox(hwnd, "Connection closed by remote host", appname, MB_OK | MB_ICONINFORMATION); } } } void timer_change_notify(long next) { long ticks = next - GETTICKCOUNT(); if (ticks <= 0) ticks = 1; /* just in case */ KillTimer(hwnd, TIMING_TIMER_ID); SetTimer(hwnd, TIMING_TIMER_ID, ticks, NULL); timing_next_time = next; } static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; static int ignore_clip = FALSE; static int need_backend_resize = FALSE; static int fullscr_on_max = FALSE; static int processed_resize = FALSE; static UINT last_mousemove = 0; switch (message) { case WM_TIMER: if ((UINT_PTR)wParam == TIMING_TIMER_ID) { long next; KillTimer(hwnd, TIMING_TIMER_ID); if (run_timers(timing_next_time, &next)) { timer_change_notify(next); } else { } } return 0; case WM_CREATE: break; case WM_CLOSE: { char *str; show_mouseptr(1); str = dupprintf("%s Exit Confirmation", appname); if (!cfg.warn_on_close || session_closed || MessageBox(hwnd, "Are you sure you want to close this session?", str, MB_ICONWARNING | MB_OKCANCEL | MB_DEFBUTTON1) == IDOK) DestroyWindow(hwnd); sfree(str); } |
︙ | ︙ | |||
2114 2115 2116 2117 2118 2119 2120 | if (wParam == IDM_DUPSESS) { /* * Allocate a file-mapping memory chunk for the * config structure. */ SECURITY_ATTRIBUTES sa; | | < < < | | > > < > | | 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 | if (wParam == IDM_DUPSESS) { /* * Allocate a file-mapping memory chunk for the * config structure. */ SECURITY_ATTRIBUTES sa; Config *p; sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; filemap = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0, sizeof(Config), NULL); if (filemap && filemap != INVALID_HANDLE_VALUE) { p = (Config *) MapViewOfFile(filemap, FILE_MAP_WRITE, 0, 0, sizeof(Config)); if (p) { *p = cfg; /* structure copy */ UnmapViewOfFile(p); } } inherit_handles = TRUE; sprintf(c, "putty &%p", filemap); cl = c; } else if (wParam == IDM_SAVEDSESS) { unsigned int sessno = ((lParam - IDM_SAVED_MIN) / MENU_SAVED_STEP) + 1; if (sessno < (unsigned)sesslist.nsessions) { char *session = sesslist.sessions[sessno]; cl = dupprintf("putty @%s", session); |
︙ | ︙ | |||
2161 2162 2163 2164 2165 2166 2167 | si.lpDesktop = NULL; si.lpTitle = NULL; si.dwFlags = 0; si.cbReserved2 = 0; si.lpReserved2 = NULL; CreateProcess(b, cl, NULL, NULL, inherit_handles, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi); | < < | < < < < < < < | | | < | < < < < | | > > | < | | | | | < < | < | | | | < < | < | | | | < | | | | | | < < < < | < | < | | | | < | | < < | | | < | | < | < | 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 | si.lpDesktop = NULL; si.lpTitle = NULL; si.dwFlags = 0; si.cbReserved2 = 0; si.lpReserved2 = NULL; CreateProcess(b, cl, NULL, NULL, inherit_handles, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi); if (filemap) CloseHandle(filemap); if (freecl) sfree(cl); } break; case IDM_RESTART: if (!back) { logevent(NULL, "----- Session restarted -----"); term_pwron(term, FALSE); start_backend(); } break; case IDM_RECONF: { Config prev_cfg; int init_lvl = 1; int reconfig_result; if (reconfiguring) break; else reconfiguring = TRUE; GetWindowText(hwnd, cfg.wintitle, sizeof(cfg.wintitle)); prev_cfg = cfg; reconfig_result = do_reconfig(hwnd, back ? back->cfg_info(backhandle) : 0); reconfiguring = FALSE; if (!reconfig_result) break; { /* Disable full-screen if resizing forbidden */ int i; for (i = 0; i < lenof(popup_menus); i++) EnableMenuItem(popup_menus[i].menu, IDM_FULLSCREEN, MF_BYCOMMAND | (cfg.resize_action == RESIZE_DISABLED) ? MF_GRAYED : MF_ENABLED); /* Gracefully unzoom if necessary */ if (IsZoomed(hwnd) && (cfg.resize_action == RESIZE_DISABLED)) { ShowWindow(hwnd, SW_RESTORE); } } /* Pass new config data to the logging module */ log_reconfig(logctx, &cfg); sfree(logpal); /* * Flush the line discipline's edit buffer in the * case where local editing has just been disabled. */ if (ldisc) ldisc_send(ldisc, NULL, 0, 0); if (pal) DeleteObject(pal); logpal = NULL; pal = NULL; cfgtopalette(); init_palette(); /* Pass new config data to the terminal */ term_reconfig(term, &cfg); /* Pass new config data to the back end */ if (back) back->reconfig(backhandle, &cfg); /* Screen size changed ? */ if (cfg.height != prev_cfg.height || cfg.width != prev_cfg.width || cfg.savelines != prev_cfg.savelines || cfg.resize_action == RESIZE_FONT || (cfg.resize_action == RESIZE_EITHER && IsZoomed(hwnd)) || cfg.resize_action == RESIZE_DISABLED) term_size(term, cfg.height, cfg.width, cfg.savelines); /* Enable or disable the scroll bar, etc */ { LONG nflg, flag = GetWindowLongPtr(hwnd, GWL_STYLE); LONG nexflag, exflag = GetWindowLongPtr(hwnd, GWL_EXSTYLE); nexflag = exflag; if (cfg.alwaysontop != prev_cfg.alwaysontop) { if (cfg.alwaysontop) { nexflag |= WS_EX_TOPMOST; SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); } else { nexflag &= ~(WS_EX_TOPMOST); SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); } } if (cfg.sunken_edge) nexflag |= WS_EX_CLIENTEDGE; else nexflag &= ~(WS_EX_CLIENTEDGE); nflg = flag; if (is_full_screen() ? cfg.scrollbar_in_fullscreen : cfg.scrollbar) nflg |= WS_VSCROLL; else nflg &= ~WS_VSCROLL; if (cfg.resize_action == RESIZE_DISABLED || is_full_screen()) nflg &= ~WS_THICKFRAME; else nflg |= WS_THICKFRAME; if (cfg.resize_action == RESIZE_DISABLED) nflg &= ~WS_MAXIMIZEBOX; else nflg |= WS_MAXIMIZEBOX; if (nflg != flag || nexflag != exflag) { if (nflg != flag) SetWindowLongPtr(hwnd, GWL_STYLE, nflg); if (nexflag != exflag) SetWindowLongPtr(hwnd, GWL_EXSTYLE, nexflag); SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); init_lvl = 2; } } /* Oops */ if (cfg.resize_action == RESIZE_DISABLED && IsZoomed(hwnd)) { force_normal(hwnd); init_lvl = 2; } set_title(NULL, cfg.wintitle); if (IsIconic(hwnd)) { SetWindowText(hwnd, cfg.win_name_always ? window_name : icon_name); } if (strcmp(cfg.font.name, prev_cfg.font.name) != 0 || strcmp(cfg.line_codepage, prev_cfg.line_codepage) != 0 || cfg.font.isbold != prev_cfg.font.isbold || cfg.font.height != prev_cfg.font.height || cfg.font.charset != prev_cfg.font.charset || cfg.font_quality != prev_cfg.font_quality || cfg.vtmode != prev_cfg.vtmode || cfg.bold_colour != prev_cfg.bold_colour || cfg.resize_action == RESIZE_DISABLED || cfg.resize_action == RESIZE_EITHER || (cfg.resize_action != prev_cfg.resize_action)) init_lvl = 2; InvalidateRect(hwnd, NULL, TRUE); reset_window(init_lvl); net_pending_errors(); } break; case IDM_COPYALL: term_copyall(term); break; case IDM_PASTE: request_paste(NULL); |
︙ | ︙ | |||
2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 | * which would cause us to reference invalid memory * and crash. Perhaps I'm just too paranoid here. */ if (i >= n_specials) break; if (back) back->special(backhandle, specials[i].code); } } break; #define X_POS(l) ((int)(short)LOWORD(l)) #define Y_POS(l) ((int)(short)HIWORD(l)) #define TO_CHR_X(x) ((((x)<0 ? (x)-font_width+1 : (x))-offset_width) / font_width) #define TO_CHR_Y(y) ((((y)<0 ? (y)-font_height+1: (y))-offset_height) / font_height) case WM_LBUTTONDOWN: case WM_MBUTTONDOWN: case WM_RBUTTONDOWN: case WM_LBUTTONUP: case WM_MBUTTONUP: case WM_RBUTTONUP: if (message == WM_RBUTTONDOWN && | > | < | 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 | * which would cause us to reference invalid memory * and crash. Perhaps I'm just too paranoid here. */ if (i >= n_specials) break; if (back) back->special(backhandle, specials[i].code); net_pending_errors(); } } break; #define X_POS(l) ((int)(short)LOWORD(l)) #define Y_POS(l) ((int)(short)HIWORD(l)) #define TO_CHR_X(x) ((((x)<0 ? (x)-font_width+1 : (x))-offset_width) / font_width) #define TO_CHR_Y(y) ((((y)<0 ? (y)-font_height+1: (y))-offset_height) / font_height) case WM_LBUTTONDOWN: case WM_MBUTTONDOWN: case WM_RBUTTONDOWN: case WM_LBUTTONUP: case WM_MBUTTONUP: case WM_RBUTTONUP: if (message == WM_RBUTTONDOWN && ((wParam & MK_CONTROL) || (cfg.mouse_is_xterm == 2))) { POINT cursorpos; show_mouseptr(1); /* make sure pointer is visible */ GetCursorPos(&cursorpos); TrackPopupMenu(popup_menus[CTXMENU].menu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RIGHTBUTTON, cursorpos.x, cursorpos.y, |
︙ | ︙ | |||
2700 2701 2702 2703 2704 2705 2706 | SelectObject(hdc, GetStockObject(SYSTEM_FONT)); SelectObject(hdc, GetStockObject(WHITE_PEN)); EndPaint(hwnd, &p); ShowCaret(hwnd); } return 0; case WM_NETEVENT: | < > | | < < < < | | > | > | | > | | > | 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 | SelectObject(hdc, GetStockObject(SYSTEM_FONT)); SelectObject(hdc, GetStockObject(WHITE_PEN)); EndPaint(hwnd, &p); ShowCaret(hwnd); } return 0; case WM_NETEVENT: /* Notice we can get multiple netevents, FD_READ, FD_WRITE etc * but the only one that's likely to try to overload us is FD_READ. * This means buffering just one is fine. */ if (pending_netevent) enact_pending_netevent(); pending_netevent = TRUE; pend_netevent_wParam = wParam; pend_netevent_lParam = lParam; if (WSAGETSELECTEVENT(lParam) != FD_READ) enact_pending_netevent(); net_pending_errors(); return 0; case WM_SETFOCUS: term_set_focus(term, TRUE); CreateCaret(hwnd, caretbm, font_width, font_height); ShowCaret(hwnd); flash_window(0); /* stop */ compose_state = 0; |
︙ | ︙ | |||
2745 2746 2747 2748 2749 2750 2751 | case WM_EXITSIZEMOVE: EnableSizeTip(0); resizing = FALSE; #ifdef RDB_DEBUG_PATCH debug((27, "WM_EXITSIZEMOVE")); #endif if (need_backend_resize) { | | < < < | | | | < > > > | < | 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 | case WM_EXITSIZEMOVE: EnableSizeTip(0); resizing = FALSE; #ifdef RDB_DEBUG_PATCH debug((27, "WM_EXITSIZEMOVE")); #endif if (need_backend_resize) { term_size(term, cfg.height, cfg.width, cfg.savelines); InvalidateRect(hwnd, NULL, TRUE); } break; case WM_SIZING: /* * This does two jobs: * 1) Keep the sizetip uptodate * 2) Make sure the window size is _stepped_ in units of the font size. */ if (cfg.resize_action == RESIZE_TERM || (cfg.resize_action == RESIZE_EITHER && !is_alt_pressed())) { int width, height, w, h, ew, eh; LPRECT r = (LPRECT) lParam; if ( !need_backend_resize && cfg.resize_action == RESIZE_EITHER && (cfg.height != term->rows || cfg.width != term->cols )) { /* * Great! It seems that both the terminal size and the * font size have been changed and the user is now dragging. * * It will now be difficult to get back to the configured * font size! * * This would be easier but it seems to be too confusing. term_size(term, cfg.height, cfg.width, cfg.savelines); reset_window(2); */ cfg.height=term->rows; cfg.width=term->cols; InvalidateRect(hwnd, NULL, TRUE); need_backend_resize = TRUE; } width = r->right - r->left - extra_width; height = r->bottom - r->top - extra_height; |
︙ | ︙ | |||
2813 2814 2815 2816 2817 2818 2819 | } if (ew || eh) return 1; else return 0; } else { int width, height, w, h, rv = 0; | < | | | 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 | } if (ew || eh) return 1; else return 0; } else { int width, height, w, h, rv = 0; int ex_width = extra_width + (cfg.window_border - offset_width) * 2; int ex_height = extra_height + (cfg.window_border - offset_height) * 2; LPRECT r = (LPRECT) lParam; width = r->right - r->left - ex_width; height = r->bottom - r->top - ex_height; w = (width + term->cols/2)/term->cols; h = (height + term->rows/2)/term->rows; |
︙ | ︙ | |||
2851 2852 2853 2854 2855 2856 2857 | case WM_FULLSCR_ON_MAX: fullscr_on_max = TRUE; break; case WM_MOVE: sys_cursor_update(); break; case WM_SIZE: | < < | | 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 | case WM_FULLSCR_ON_MAX: fullscr_on_max = TRUE; break; case WM_MOVE: sys_cursor_update(); break; case WM_SIZE: #ifdef RDB_DEBUG_PATCH debug((27, "WM_SIZE %s (%d,%d)", (wParam == SIZE_MINIMIZED) ? "SIZE_MINIMIZED": (wParam == SIZE_MAXIMIZED) ? "SIZE_MAXIMIZED": (wParam == SIZE_RESTORED && resizing) ? "to": (wParam == SIZE_RESTORED) ? "SIZE_RESTORED": "...", LOWORD(lParam), HIWORD(lParam))); #endif if (wParam == SIZE_MINIMIZED) SetWindowText(hwnd, cfg.win_name_always ? window_name : icon_name); if (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED) SetWindowText(hwnd, window_name); if (wParam == SIZE_RESTORED) { processed_resize = FALSE; clear_full_screen(); if (processed_resize) { /* |
︙ | ︙ | |||
2897 2898 2899 2900 2901 2902 2903 | */ return 0; } } processed_resize = TRUE; | | < | < < < < < < < < < < < < | < < | | | | | | | | | | | | | 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 | */ return 0; } } processed_resize = TRUE; if (cfg.resize_action == RESIZE_DISABLED) { /* A resize, well it better be a minimize. */ reset_window(-1); } else { int width, height, w, h; width = LOWORD(lParam); height = HIWORD(lParam); if (wParam == SIZE_MAXIMIZED && !was_zoomed) { was_zoomed = 1; prev_rows = term->rows; prev_cols = term->cols; if (cfg.resize_action == RESIZE_TERM) { w = width / font_width; if (w < 1) w = 1; h = height / font_height; if (h < 1) h = 1; term_size(term, h, w, cfg.savelines); } reset_window(0); } else if (wParam == SIZE_RESTORED && was_zoomed) { was_zoomed = 0; if (cfg.resize_action == RESIZE_TERM) { w = (width-cfg.window_border*2) / font_width; if (w < 1) w = 1; h = (height-cfg.window_border*2) / font_height; if (h < 1) h = 1; term_size(term, h, w, cfg.savelines); reset_window(2); } else if (cfg.resize_action != RESIZE_FONT) reset_window(2); else reset_window(0); } else if (wParam == SIZE_MINIMIZED) { /* do nothing */ } else if (cfg.resize_action == RESIZE_TERM || (cfg.resize_action == RESIZE_EITHER && !is_alt_pressed())) { w = (width-cfg.window_border*2) / font_width; if (w < 1) w = 1; h = (height-cfg.window_border*2) / font_height; if (h < 1) h = 1; if (resizing) { /* * Don't call back->size in mid-resize. (To * prevent massive numbers of resize events * getting sent down the connection during an NT * opaque drag.) */ need_backend_resize = TRUE; cfg.height = h; cfg.width = w; } else { term_size(term, h, w, cfg.savelines); } } else { reset_window(0); } } sys_cursor_update(); return 0; |
︙ | ︙ | |||
2999 3000 3001 3002 3003 3004 3005 | term_scroll(term, 0, +term->rows / 2); break; case SB_PAGEUP: term_scroll(term, 0, -term->rows / 2); break; case SB_THUMBPOSITION: case SB_THUMBTRACK: | < < < < < < < < < < < | < | 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 | term_scroll(term, 0, +term->rows / 2); break; case SB_PAGEUP: term_scroll(term, 0, -term->rows / 2); break; case SB_THUMBPOSITION: case SB_THUMBTRACK: term_scroll(term, 1, HIWORD(wParam)); break; } break; case WM_PALETTECHANGED: if ((HWND) wParam != hwnd && pal != NULL) { HDC hdc = get_ctx(NULL); if (hdc) { |
︙ | ︙ | |||
3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 | } else break; /* pass to Windows for default processing */ } else { len = TranslateKey(message, wParam, lParam, buf); if (len == -1) return DefWindowProc(hwnd, message, wParam, lParam); if (len != 0) { /* * We need not bother about stdin backlogs * here, because in GUI PuTTY we can't do * anything about it anyway; there's no means * of asking Windows to hold off on KEYDOWN * messages. We _have_ to buffer everything * we're sent. */ term_seen_key_event(term); if (ldisc) ldisc_send(ldisc, buf, len, 1); show_mouseptr(0); } } } return 0; case WM_INPUTLANGCHANGE: /* wParam == Font number */ /* lParam == Locale */ set_input_locale((HKL)lParam); sys_cursor_update(); break; | > > > > > > > > > | 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 | } else break; /* pass to Windows for default processing */ } else { len = TranslateKey(message, wParam, lParam, buf); if (len == -1) return DefWindowProc(hwnd, message, wParam, lParam); if (len != 0) { /* * Interrupt an ongoing paste. I'm not sure * this is sensible, but for the moment it's * preferable to having to faff about buffering * things. */ term_nopaste(term); /* * We need not bother about stdin backlogs * here, because in GUI PuTTY we can't do * anything about it anyway; there's no means * of asking Windows to hold off on KEYDOWN * messages. We _have_ to buffer everything * we're sent. */ term_seen_key_event(term); if (ldisc) ldisc_send(ldisc, buf, len, 1); show_mouseptr(0); } } } net_pending_errors(); return 0; case WM_INPUTLANGCHANGE: /* wParam == Font number */ /* lParam == Locale */ set_input_locale((HKL)lParam); sys_cursor_update(); break; |
︙ | ︙ | |||
3127 3128 3129 3130 3131 3132 3133 | /* * Jaeyoun Chung reports that Korean character * input doesn't work correctly if we do a single * luni_send() covering the whole of buff. So * instead we luni_send the characters one by one. */ term_seen_key_event(term); | < < | < < < | < < < < < < | 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 | /* * Jaeyoun Chung reports that Korean character * input doesn't work correctly if we do a single * luni_send() covering the whole of buff. So * instead we luni_send the characters one by one. */ term_seen_key_event(term); for (i = 0; i < n; i += 2) { if (ldisc) luni_send(ldisc, (unsigned short *)(buff+i), 1, 1); } free(buff); } ImmReleaseContext(hwnd, hIMC); return 1; } |
︙ | ︙ | |||
3180 3181 3182 3183 3184 3185 3186 | char c = (unsigned char)wParam; term_seen_key_event(term); if (ldisc) lpage_send(ldisc, CP_ACP, &c, 1, 1); } return 0; case WM_SYSCOLORCHANGE: | | | 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 | char c = (unsigned char)wParam; term_seen_key_event(term); if (ldisc) lpage_send(ldisc, CP_ACP, &c, 1, 1); } return 0; case WM_SYSCOLORCHANGE: if (cfg.system_colour) { /* Refresh palette from system colours. */ /* XXX actually this zaps the entire palette. */ systopalette(); init_palette(); /* Force a repaint of the terminal window. */ term_invalidate(term); } |
︙ | ︙ | |||
3232 3233 3234 3235 3236 3237 3238 | } else if (wheel_accumulator < 0) { b = MBT_WHEEL_DOWN; wheel_accumulator += WHEEL_DELTA; } else break; if (send_raw_mouse && | < | | 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 | } else if (wheel_accumulator < 0) { b = MBT_WHEEL_DOWN; wheel_accumulator += WHEEL_DELTA; } else break; if (send_raw_mouse && !(cfg.mouse_override && shift_pressed)) { /* Mouse wheel position is in screen coordinates for * some reason */ POINT p; p.x = X_POS(lParam); p.y = Y_POS(lParam); if (ScreenToClient(hwnd, &p)) { /* send a mouse-down followed by a mouse up */ term_mouse(term, b, translate_button(b), |
︙ | ︙ | |||
3340 3341 3342 3343 3344 3345 3346 | HDC hdc = ctx; RECT line_box; int force_manual_underline = 0; int fnt_width, char_width; int text_adjust = 0; int xoffset = 0; int maxlen, remaining, opaque; | < < | > > > < | < | 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 | HDC hdc = ctx; RECT line_box; int force_manual_underline = 0; int fnt_width, char_width; int text_adjust = 0; int xoffset = 0; int maxlen, remaining, opaque; static int *lpDx = NULL; static int lpDx_len = 0; int *lpDx_maybe; lattr &= LATTR_MODE; char_width = fnt_width = font_width * (1 + (lattr != LATTR_NORM)); if (attr & ATTR_WIDE) char_width *= 2; /* Only want the left half of double width lines */ if (lattr != LATTR_NORM && x*2 >= term->cols) return; x *= fnt_width; y *= font_height; x += offset_width; y += offset_height; if ((attr & TATTR_ACTCURS) && (cfg.cursor_type == 0 || term->big_cursor)) { attr &= ~(ATTR_REVERSE|ATTR_BLINK|ATTR_COLOURS); if (bold_mode == BOLD_COLOURS) attr &= ~ATTR_BOLD; /* cursor fg and bg */ attr |= (260 << ATTR_FGSHIFT) | (261 << ATTR_BGSHIFT); } nfont = 0; if (cfg.vtmode == VT_POORMAN && lattr != LATTR_NORM) { /* Assume a poorman font is borken in other ways too. */ lattr = LATTR_WIDE; } else switch (lattr) { case LATTR_NORM: break; case LATTR_WIDE: nfont |= FONT_WIDE; break; default: nfont |= FONT_WIDE + FONT_HIGH; break; } if (attr & ATTR_NARROW) nfont |= FONT_NARROW; /* Special hack for the VT100 linedraw glyphs. */ if (text[0] >= 0x23BA && text[0] <= 0x23BD) { switch ((unsigned char) (text[0])) { case 0xBA: text_adjust = -2 * font_height / 5; break; case 0xBB: |
︙ | ︙ | |||
3412 3413 3414 3415 3416 3417 3418 | text_adjust *= 2; text[0] = ucsdata.unitab_xterm['q']; if (attr & ATTR_UNDER) { attr &= ~ATTR_UNDER; force_manual_underline = 1; } } | < | < | | | < < < < < < < < < < < < < < < < < < | 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 | text_adjust *= 2; text[0] = ucsdata.unitab_xterm['q']; if (attr & ATTR_UNDER) { attr &= ~ATTR_UNDER; force_manual_underline = 1; } } /* Anything left as an original character set is unprintable. */ if (DIRECT_CHAR(text[0])) { int i; for (i = 0; i < len; i++) text[i] = 0xFFFD; } /* OEM CP */ if ((text[0] & CSET_MASK) == CSET_OEMCP) nfont |= FONT_OEM; nfg = ((attr & ATTR_FGMASK) >> ATTR_FGSHIFT); nbg = ((attr & ATTR_BGMASK) >> ATTR_BGSHIFT); if (bold_mode == BOLD_FONT && (attr & ATTR_BOLD)) nfont |= FONT_BOLD; if (und_mode == UND_FONT && (attr & ATTR_UNDER)) nfont |= FONT_UNDERLINE; another_font(nfont); if (!fonts[nfont]) { if (nfont & FONT_UNDERLINE) force_manual_underline = 1; /* Don't do the same for manual bold, it could be bad news. */ nfont &= ~(FONT_BOLD | FONT_UNDERLINE); } another_font(nfont); if (!fonts[nfont]) nfont = FONT_NORMAL; if (attr & ATTR_REVERSE) { t = nfg; nfg = nbg; nbg = t; } if (bold_mode == BOLD_COLOURS && (attr & ATTR_BOLD)) { if (nfg < 16) nfg |= 8; else if (nfg >= 256) nfg |= 1; } if (bold_mode == BOLD_COLOURS && (attr & ATTR_BLINK)) { if (nbg < 16) nbg |= 8; else if (nbg >= 256) nbg |= 1; } fg = colours[nfg]; bg = colours[nbg]; SelectObject(hdc, fonts[nfont]); SetTextColor(hdc, fg); SetBkColor(hdc, bg); if (attr & TATTR_COMBINING) SetBkMode(hdc, TRANSPARENT); else SetBkMode(hdc, OPAQUE); line_box.left = x; line_box.top = y; line_box.right = x + char_width * len; line_box.bottom = y + font_height; /* Only want the left half of double width lines */ if (line_box.right > font_width*term->cols+offset_width) line_box.right = font_width*term->cols+offset_width; if (font_varpitch) { /* |
︙ | ︙ | |||
3517 3518 3519 3520 3521 3522 3523 | SetTextAlign(hdc, TA_TOP | TA_LEFT | TA_NOUPDATECP); lpDx_maybe = lpDx; maxlen = len; } opaque = TRUE; /* start by erasing the rectangle */ for (remaining = len; remaining > 0; | | < < < < < < < < < < | | | | | | < | | < < < | < < < < < < < < < < < < < < | 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 | SetTextAlign(hdc, TA_TOP | TA_LEFT | TA_NOUPDATECP); lpDx_maybe = lpDx; maxlen = len; } opaque = TRUE; /* start by erasing the rectangle */ for (remaining = len; remaining > 0; text += len, remaining -= len, x += char_width * len) { len = (maxlen < remaining ? maxlen : remaining); if (len > lpDx_len) { if (len > lpDx_len) { lpDx_len = len * 9 / 8 + 16; lpDx = sresize(lpDx, lpDx_len, int); } } { int i; for (i = 0; i < len; i++) lpDx[i] = char_width; } /* We're using a private area for direct to font. (512 chars.) */ if (ucsdata.dbcs_screenfont && (text[0] & CSET_MASK) == CSET_ACP) { /* Ho Hum, dbcs fonts are a PITA! */ /* To display on W9x I have to convert to UCS */ static wchar_t *uni_buf = 0; |
︙ | ︙ | |||
3602 3603 3604 3605 3606 3607 3608 | return; /* Eeek! */ ExtTextOutW(hdc, x + xoffset, y - font_height * (lattr == LATTR_BOT) + text_adjust, ETO_CLIPPED | (opaque ? ETO_OPAQUE : 0), &line_box, uni_buf, nlen, lpDx_maybe); | | | 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 | return; /* Eeek! */ ExtTextOutW(hdc, x + xoffset, y - font_height * (lattr == LATTR_BOT) + text_adjust, ETO_CLIPPED | (opaque ? ETO_OPAQUE : 0), &line_box, uni_buf, nlen, lpDx_maybe); if (bold_mode == BOLD_SHADOW && (attr & ATTR_BOLD)) { SetBkMode(hdc, TRANSPARENT); ExtTextOutW(hdc, x + xoffset - 1, y - font_height * (lattr == LATTR_BOT) + text_adjust, ETO_CLIPPED, &line_box, uni_buf, nlen, lpDx_maybe); } |
︙ | ︙ | |||
3627 3628 3629 3630 3631 3632 3633 | for (i = 0; i < len; i++) directbuf[i] = text[i] & 0xFF; ExtTextOut(hdc, x + xoffset, y - font_height * (lattr == LATTR_BOT) + text_adjust, ETO_CLIPPED | (opaque ? ETO_OPAQUE : 0), &line_box, directbuf, len, lpDx_maybe); | | | 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 | for (i = 0; i < len; i++) directbuf[i] = text[i] & 0xFF; ExtTextOut(hdc, x + xoffset, y - font_height * (lattr == LATTR_BOT) + text_adjust, ETO_CLIPPED | (opaque ? ETO_OPAQUE : 0), &line_box, directbuf, len, lpDx_maybe); if (bold_mode == BOLD_SHADOW && (attr & ATTR_BOLD)) { SetBkMode(hdc, TRANSPARENT); /* GRR: This draws the character outside its box and * can leave 'droppings' even with the clip box! I * suppose I could loop it one character at a time ... * yuk. * |
︙ | ︙ | |||
3666 3667 3668 3669 3670 3671 3672 | /* print Glyphs as they are, without Windows' Shaping*/ general_textout(hdc, x + xoffset, y - font_height * (lattr==LATTR_BOT) + text_adjust, &line_box, wbuf, len, lpDx, opaque && !(attr & TATTR_COMBINING)); /* And the shadow bold hack. */ | | | 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 | /* print Glyphs as they are, without Windows' Shaping*/ general_textout(hdc, x + xoffset, y - font_height * (lattr==LATTR_BOT) + text_adjust, &line_box, wbuf, len, lpDx, opaque && !(attr & TATTR_COMBINING)); /* And the shadow bold hack. */ if (bold_mode == BOLD_SHADOW && (attr & ATTR_BOLD)) { SetBkMode(hdc, TRANSPARENT); ExtTextOutW(hdc, x + xoffset - 1, y - font_height * (lattr == LATTR_BOT) + text_adjust, ETO_CLIPPED, &line_box, wbuf, len, lpDx_maybe); } } |
︙ | ︙ | |||
3706 3707 3708 3709 3710 3711 3712 | * Wrapper that handles combining characters. */ void do_text(Context ctx, int x, int y, wchar_t *text, int len, unsigned long attr, int lattr) { if (attr & TATTR_COMBINING) { unsigned long a = 0; | < < < < < | < < < < < < < < < < < < < < < < < < < | < < | | 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 | * Wrapper that handles combining characters. */ void do_text(Context ctx, int x, int y, wchar_t *text, int len, unsigned long attr, int lattr) { if (attr & TATTR_COMBINING) { unsigned long a = 0; attr &= ~TATTR_COMBINING; while (len--) { do_text_internal(ctx, x, y, text, 1, attr | a, lattr); text++; a = TATTR_COMBINING; } } else do_text_internal(ctx, x, y, text, len, attr, lattr); } void do_cursor(Context ctx, int x, int y, wchar_t *text, int len, unsigned long attr, int lattr) { int fnt_width; int char_width; HDC hdc = ctx; int ctype = cfg.cursor_type; lattr &= LATTR_MODE; if ((attr & TATTR_ACTCURS) && (ctype == 0 || term->big_cursor)) { if (*text != UCSWIDE) { do_text(ctx, x, y, text, len, attr, lattr); return; |
︙ | ︙ | |||
3880 3881 3882 3883 3884 3885 3886 | ibuf += font_width / 2 -1; ibuf /= font_width; return ibuf; } | < < < < < < < < < < < < < < < > | | | 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 | ibuf += font_width / 2 -1; ibuf /= font_width; return ibuf; } /* * Translate a WM_(SYS)?KEY(UP|DOWN) message into a string of ASCII * codes. Returns number of bytes used, zero to drop the message, * -1 to forward the message to Windows, or another negative number * to indicate a NUL-terminated "special" string. */ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, unsigned char *output) { BYTE keystate[256]; int scan, left_alt = 0, key_down, shift_state; int r, i, code; unsigned char *p = output; static int alt_sum = 0; HKL kbd_layout = GetKeyboardLayout(0); /* keys is for ToAsciiEx. There's some ick here, see below. */ static WORD keys[3]; static int compose_char = 0; static WPARAM compose_key = 0; r = GetKeyboardState(keystate); if (!r) memset(keystate, 0, sizeof(keystate)); else { #if 0 #define SHOW_TOASCII_RESULT |
︙ | ︙ | |||
3964 3965 3966 3967 3968 3969 3970 | ch = MapVirtualKeyEx(wParam, 2, kbd_layout); if (ch >= ' ' && ch <= '~') debug((", '%c'", ch)); else if (ch) debug((", $%02x", ch)); | | | | | | | | 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 | ch = MapVirtualKeyEx(wParam, 2, kbd_layout); if (ch >= ' ' && ch <= '~') debug((", '%c'", ch)); else if (ch) debug((", $%02x", ch)); if (keys[0]) debug((", KB0=%02x", keys[0])); if (keys[1]) debug((", KB1=%02x", keys[1])); if (keys[2]) debug((", KB2=%02x", keys[2])); if ((keystate[VK_SHIFT] & 0x80) != 0) debug((", S")); if ((keystate[VK_CONTROL] & 0x80) != 0) debug((", C")); if ((HIWORD(lParam) & KF_EXTENDED)) debug((", E")); |
︙ | ︙ | |||
4001 4002 4003 4004 4005 4006 4007 | if (wParam == VK_MENU && (HIWORD(lParam) & KF_EXTENDED)) { keystate[VK_RMENU] = keystate[VK_MENU]; } /* Nastyness with NUMLock - Shift-NUMLock is left alone though */ | | | | | 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 | if (wParam == VK_MENU && (HIWORD(lParam) & KF_EXTENDED)) { keystate[VK_RMENU] = keystate[VK_MENU]; } /* Nastyness with NUMLock - Shift-NUMLock is left alone though */ if ((cfg.funky_type == FUNKY_VT400 || (cfg.funky_type <= FUNKY_LINUX && term->app_keypad_keys && !cfg.no_applic_k)) && wParam == VK_NUMLOCK && !(keystate[VK_SHIFT] & 0x80)) { wParam = VK_EXECUTE; /* UnToggle NUMLock */ if ((HIWORD(lParam) & (KF_UP | KF_REPEAT)) == 0) keystate[VK_NUMLOCK] ^= 1; |
︙ | ︙ | |||
4029 4030 4031 4032 4033 4034 4035 | if ((HIWORD(lParam) & KF_ALTDOWN) && (keystate[VK_RMENU] & 0x80) == 0) left_alt = 1; key_down = ((HIWORD(lParam) & KF_UP) == 0); /* Make sure Ctrl-ALT is not the same as AltGr for ToAscii unless told. */ if (left_alt && (keystate[VK_CONTROL] & 0x80)) { | | | | | | | | | | | 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 | if ((HIWORD(lParam) & KF_ALTDOWN) && (keystate[VK_RMENU] & 0x80) == 0) left_alt = 1; key_down = ((HIWORD(lParam) & KF_UP) == 0); /* Make sure Ctrl-ALT is not the same as AltGr for ToAscii unless told. */ if (left_alt && (keystate[VK_CONTROL] & 0x80)) { if (cfg.ctrlaltkeys) keystate[VK_MENU] = 0; else { keystate[VK_RMENU] = 0x80; left_alt = 0; } } scan = (HIWORD(lParam) & (KF_UP | KF_EXTENDED | 0xFF)); shift_state = ((keystate[VK_SHIFT] & 0x80) != 0) + ((keystate[VK_CONTROL] & 0x80) != 0) * 2; /* Note if AltGr was pressed and if it was used as a compose key */ if (!compose_state) { compose_key = 0x100; if (cfg.compose_key) { if (wParam == VK_MENU && (HIWORD(lParam) & KF_EXTENDED)) compose_key = wParam; } if (wParam == VK_APPS) compose_key = wParam; } if (wParam == compose_key) { if (compose_state == 0 && (HIWORD(lParam) & (KF_UP | KF_REPEAT)) == 0) compose_state = 1; else if (compose_state == 1 && (HIWORD(lParam) & KF_UP)) compose_state = 2; else compose_state = 0; } else if (compose_state == 1 && wParam != VK_CONTROL) compose_state = 0; if (compose_state > 1 && left_alt) compose_state = 0; /* Sanitize the number pad if not using a PC NumPad */ if (left_alt || (term->app_keypad_keys && !cfg.no_applic_k && cfg.funky_type != FUNKY_XTERM) || cfg.funky_type == FUNKY_VT400 || cfg.nethack_keypad || compose_state) { if ((HIWORD(lParam) & KF_EXTENDED) == 0) { int nParam = 0; switch (wParam) { case VK_INSERT: nParam = VK_NUMPAD0; break; case VK_END: |
︙ | ︙ | |||
4146 4147 4148 4149 4150 4151 4152 | term_scroll_to_selection(term, (wParam == VK_PRIOR ? 0 : 1)); return 0; } if (wParam == VK_INSERT && shift_state == 1) { request_paste(NULL); return 0; } | | | < | < | | | 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 | term_scroll_to_selection(term, (wParam == VK_PRIOR ? 0 : 1)); return 0; } if (wParam == VK_INSERT && shift_state == 1) { request_paste(NULL); return 0; } if (left_alt && wParam == VK_F4 && cfg.alt_f4) { return -1; } if (left_alt && wParam == VK_SPACE && cfg.alt_space) { SendMessage(hwnd, WM_SYSCOMMAND, SC_KEYMENU, 0); return -1; } if (left_alt && wParam == VK_RETURN && cfg.fullscreenonaltenter && (cfg.resize_action != RESIZE_DISABLED)) { if ((HIWORD(lParam) & (KF_UP | KF_REPEAT)) != KF_REPEAT) flip_full_screen(); return -1; } /* Control-Numlock for app-keypad mode switch */ if (wParam == VK_PAUSE && shift_state == 2) { term->app_keypad_keys ^= 1; return 0; } /* Nethack keypad */ if (cfg.nethack_keypad && !left_alt) { switch (wParam) { case VK_NUMPAD1: *p++ = "bB\002\002"[shift_state & 3]; return p - output; case VK_NUMPAD2: *p++ = "jJ\012\012"[shift_state & 3]; return p - output; |
︙ | ︙ | |||
4204 4205 4206 4207 4208 4209 4210 | } } /* Application Keypad */ if (!left_alt) { int xkey = 0; | | | | | | 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 | } } /* Application Keypad */ if (!left_alt) { int xkey = 0; if (cfg.funky_type == FUNKY_VT400 || (cfg.funky_type <= FUNKY_LINUX && term->app_keypad_keys && !cfg.no_applic_k)) switch (wParam) { case VK_EXECUTE: xkey = 'P'; break; case VK_DIVIDE: xkey = 'Q'; break; case VK_MULTIPLY: xkey = 'R'; break; case VK_SUBTRACT: xkey = 'S'; break; } if (term->app_keypad_keys && !cfg.no_applic_k) switch (wParam) { case VK_NUMPAD0: xkey = 'p'; break; case VK_NUMPAD1: xkey = 'q'; break; |
︙ | ︙ | |||
4257 4258 4259 4260 4261 4262 4263 | xkey = 'y'; break; case VK_DECIMAL: xkey = 'n'; break; case VK_ADD: | | | | | | 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 | xkey = 'y'; break; case VK_DECIMAL: xkey = 'n'; break; case VK_ADD: if (cfg.funky_type == FUNKY_XTERM) { if (shift_state) xkey = 'l'; else xkey = 'k'; } else if (shift_state) xkey = 'm'; else xkey = 'l'; break; case VK_DIVIDE: if (cfg.funky_type == FUNKY_XTERM) xkey = 'o'; break; case VK_MULTIPLY: if (cfg.funky_type == FUNKY_XTERM) xkey = 'j'; break; case VK_SUBTRACT: if (cfg.funky_type == FUNKY_XTERM) xkey = 'm'; break; case VK_RETURN: if (HIWORD(lParam) & KF_EXTENDED) xkey = 'M'; break; |
︙ | ︙ | |||
4299 4300 4301 4302 4303 4304 4305 | } else p += sprintf((char *) p, "\x1BO%c", xkey); return p - output; } } if (wParam == VK_BACK && shift_state == 0) { /* Backspace */ | | | | 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 | } else p += sprintf((char *) p, "\x1BO%c", xkey); return p - output; } } if (wParam == VK_BACK && shift_state == 0) { /* Backspace */ *p++ = (cfg.bksp_is_delete ? 0x7F : 0x08); *p++ = 0; return -2; } if (wParam == VK_BACK && shift_state == 1) { /* Shift Backspace */ /* We do the opposite of what is configured */ *p++ = (cfg.bksp_is_delete ? 0x08 : 0x7F); *p++ = 0; return -2; } if (wParam == VK_TAB && shift_state == 1) { /* Shift tab */ *p++ = 0x1B; *p++ = '['; *p++ = 'Z'; |
︙ | ︙ | |||
4449 4450 4451 4452 4453 4454 4455 | code = 5; break; case VK_NEXT: code = 6; break; } /* Reorder edit keys to physical order */ | | > | < | 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 | code = 5; break; case VK_NEXT: code = 6; break; } /* Reorder edit keys to physical order */ if (cfg.funky_type == FUNKY_VT400 && code <= 6) code = "\0\2\1\4\5\3\6"[code]; if (term->vt52_mode && code > 0 && code <= 6) { p += sprintf((char *) p, "\x1B%c", " HLMEIG"[code]); return p - output; } if (cfg.funky_type == FUNKY_SCO && /* SCO function keys */ code >= 11 && code <= 34) { char codes[] = "MNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@[\\]^_`{"; int index = 0; switch (wParam) { case VK_F1: index = 0; break; case VK_F2: index = 1; break; case VK_F3: index = 2; break; case VK_F4: index = 3; break; |
︙ | ︙ | |||
4480 4481 4482 4483 4484 4485 4486 | case VK_F12: index = 11; break; } if (keystate[VK_SHIFT] & 0x80) index += 12; if (keystate[VK_CONTROL] & 0x80) index += 24; p += sprintf((char *) p, "\x1B[%c", codes[index]); return p - output; } | | | | | | < | 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 | case VK_F12: index = 11; break; } if (keystate[VK_SHIFT] & 0x80) index += 12; if (keystate[VK_CONTROL] & 0x80) index += 24; p += sprintf((char *) p, "\x1B[%c", codes[index]); return p - output; } if (cfg.funky_type == FUNKY_SCO && /* SCO small keypad */ code >= 1 && code <= 6) { char codes[] = "HL.FIG"; if (code == 3) { *p++ = '\x7F'; } else { p += sprintf((char *) p, "\x1B[%c", codes[code-1]); } return p - output; } if ((term->vt52_mode || cfg.funky_type == FUNKY_VT100P) && code >= 11 && code <= 24) { int offt = 0; if (code > 15) offt++; if (code > 21) offt++; if (term->vt52_mode) p += sprintf((char *) p, "\x1B%c", code + 'P' - 11 - offt); else p += sprintf((char *) p, "\x1BO%c", code + 'P' - 11 - offt); return p - output; } if (cfg.funky_type == FUNKY_LINUX && code >= 11 && code <= 15) { p += sprintf((char *) p, "\x1B[[%c", code + 'A' - 11); return p - output; } if (cfg.funky_type == FUNKY_XTERM && code >= 11 && code <= 14) { if (term->vt52_mode) p += sprintf((char *) p, "\x1B%c", code + 'P' - 11); else p += sprintf((char *) p, "\x1BO%c", code + 'P' - 11); return p - output; } if (cfg.rxvt_homeend && (code == 1 || code == 4)) { p += sprintf((char *) p, code == 1 ? "\x1B[H" : "\x1BOw"); return p - output; } if (code) { p += sprintf((char *) p, "\x1B[%d~", code); return p - output; } |
︙ | ︙ | |||
4575 4576 4577 4578 4579 4580 4581 | /* Okay we've done everything interesting; let windows deal with * the boring stuff */ { BOOL capsOn=0; /* helg: clear CAPS LOCK state if caps lock switches to cyrillic */ | | < | < < < > < < | < < | | < < < > | | > > > > > > > | | | | | | | | | | | > | | | | | | | | < | | 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 | /* Okay we've done everything interesting; let windows deal with * the boring stuff */ { BOOL capsOn=0; /* helg: clear CAPS LOCK state if caps lock switches to cyrillic */ if(cfg.xlat_capslockcyr && keystate[VK_CAPITAL] != 0) { capsOn= !left_alt; keystate[VK_CAPITAL] = 0; } /* XXX how do we know what the max size of the keys array should * be is? There's indication on MS' website of an Inquire/InquireEx * functioning returning a KBINFO structure which tells us. */ if (osVersion.dwPlatformId == VER_PLATFORM_WIN32_NT) { /* XXX 'keys' parameter is declared in MSDN documentation as * 'LPWORD lpChar'. * The experience of a French user indicates that on * Win98, WORD[] should be passed in, but on Win2K, it should * be BYTE[]. German WinXP and my Win2K with "US International" * driver corroborate this. * Experimentally I've conditionalised the behaviour on the * Win9x/NT split, but I suspect it's worse than that. * See wishlist item `win-dead-keys' for more horrible detail * and speculations. */ BYTE keybs[3]; int i; r = ToAsciiEx(wParam, scan, keystate, (LPWORD)keybs, 0, kbd_layout); for (i=0; i<3; i++) keys[i] = keybs[i]; } else { r = ToAsciiEx(wParam, scan, keystate, keys, 0, kbd_layout); } #ifdef SHOW_TOASCII_RESULT if (r == 1 && !key_down) { if (alt_sum) { if (in_utf(term) || ucsdata.dbcs_screenfont) debug((", (U+%04x)", alt_sum)); else debug((", LCH(%d)", alt_sum)); } else { debug((", ACH(%d)", keys[0])); } } else if (r > 0) { int r1; debug((", ASC(")); for (r1 = 0; r1 < r; r1++) { debug(("%s%d", r1 ? "," : "", keys[r1])); } debug((")")); } #endif if (r > 0) { WCHAR keybuf; /* * Interrupt an ongoing paste. I'm not sure this is * sensible, but for the moment it's preferable to * having to faff about buffering things. */ term_nopaste(term); p = output; for (i = 0; i < r; i++) { unsigned char ch = (unsigned char) keys[i]; if (compose_state == 2 && (ch & 0x80) == 0 && ch > ' ') { compose_char = ch; compose_state++; continue; } if (compose_state == 3 && (ch & 0x80) == 0 && ch > ' ') { int nc; compose_state = 0; if ((nc = check_compose(compose_char, ch)) == -1) { MessageBeep(MB_ICONHAND); return 0; } keybuf = nc; term_seen_key_event(term); if (ldisc) luni_send(ldisc, &keybuf, 1, 1); continue; } compose_state = 0; if (!key_down) { if (alt_sum) { if (in_utf(term) || ucsdata.dbcs_screenfont) { keybuf = alt_sum; term_seen_key_event(term); if (ldisc) luni_send(ldisc, &keybuf, 1, 1); } else { ch = (char) alt_sum; /* * We need not bother about stdin * backlogs here, because in GUI PuTTY * we can't do anything about it * anyway; there's no means of asking * Windows to hold off on KEYDOWN * messages. We _have_ to buffer * everything we're sent. */ term_seen_key_event(term); if (ldisc) ldisc_send(ldisc, &ch, 1, 1); } alt_sum = 0; } else { term_seen_key_event(term); if (ldisc) lpage_send(ldisc, kbd_codepage, &ch, 1, 1); } } else { if(capsOn && ch < 0x80) { WCHAR cbuf[2]; cbuf[0] = 27; cbuf[1] = xlat_uskbd2cyrllic(ch); term_seen_key_event(term); if (ldisc) luni_send(ldisc, cbuf+!left_alt, 1+!!left_alt, 1); } else { char cbuf[2]; cbuf[0] = '\033'; cbuf[1] = ch; term_seen_key_event(term); if (ldisc) lpage_send(ldisc, kbd_codepage, cbuf+!left_alt, 1+!!left_alt, 1); } } show_mouseptr(0); } /* This is so the ALT-Numpad and dead keys work correctly. */ keys[0] = 0; return p - output; } /* If we're definitly not building up an ALT-54321 then clear it */ if (!left_alt) keys[0] = 0; /* If we will be using alt_sum fix the 256s */ else if (keys[0] && (in_utf(term) || ucsdata.dbcs_screenfont)) keys[0] = 10; } /* * ALT alone may or may not want to bring up the System menu. * If it's not meant to, we return 0 on presses or releases of * ALT, to show that we've swallowed the keystroke. Otherwise * we return -1, which means Windows will give the keystroke * its default handling (i.e. bring up the System menu). */ if (wParam == VK_MENU && !cfg.alt_only) return 0; return -1; } void set_title(void *frontend, char *title) { sfree(window_name); window_name = snewn(1 + strlen(title), char); strcpy(window_name, title); if (cfg.win_name_always || !IsIconic(hwnd)) SetWindowText(hwnd, title); } void set_icon(void *frontend, char *title) { sfree(icon_name); icon_name = snewn(1 + strlen(title), char); strcpy(icon_name, title); if (!cfg.win_name_always && IsIconic(hwnd)) SetWindowText(hwnd, title); } void set_sbar(void *frontend, int total, int start, int page) { SCROLLINFO si; if (is_full_screen() ? !cfg.scrollbar_in_fullscreen : !cfg.scrollbar) return; si.cbSize = sizeof(si); si.fMask = SIF_ALL | SIF_DISABLENOSCROLL; si.nMin = 0; si.nMax = total - 1; si.nPage = page; |
︙ | ︙ | |||
4803 4804 4805 4806 4807 4808 4809 | colours[n] = RGB(r, g, b); } void palette_set(void *frontend, int n, int r, int g, int b) { if (n >= 16) n += 256 - 16; | | | 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 | colours[n] = RGB(r, g, b); } void palette_set(void *frontend, int n, int r, int g, int b) { if (n >= 16) n += 256 - 16; if (n > NALLCOLOURS) return; real_palette_set(n, r, g, b); if (pal) { HDC hdc = get_ctx(frontend); UnrealizeObject(pal); RealizePalette(hdc); free_ctx(hdc); |
︙ | ︙ | |||
4903 4904 4905 4906 4907 4908 4909 | if (!clipdata || !clipdata2) { if (clipdata) GlobalFree(clipdata); if (clipdata2) GlobalFree(clipdata2); return; } | | < < < | < < < < | < | | | 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 | if (!clipdata || !clipdata2) { if (clipdata) GlobalFree(clipdata); if (clipdata2) GlobalFree(clipdata2); return; } if (!(lock = GlobalLock(clipdata))) return; if (!(lock2 = GlobalLock(clipdata2))) return; memcpy(lock, data, len * sizeof(wchar_t)); WideCharToMultiByte(CP_ACP, 0, data, len, lock2, len2, NULL, NULL); if (cfg.rtf_paste) { wchar_t unitab[256]; char *rtf = NULL; unsigned char *tdata = (unsigned char *)lock2; wchar_t *udata = (wchar_t *)lock; int rtflen = 0, uindex = 0, tindex = 0; int rtfsize = 0; int multilen, blen, alen, totallen, i; char before[16], after[4]; int fgcolour, lastfgcolour = 0; int bgcolour, lastbgcolour = 0; int attrBold, lastAttrBold = 0; int attrUnder, lastAttrUnder = 0; int palette[NALLCOLOURS]; int numcolours; get_unitab(CP_ACP, unitab, 0); rtfsize = 100 + strlen(cfg.font.name); rtf = snewn(rtfsize, char); rtflen = sprintf(rtf, "{\\rtf1\\ansi\\deff0{\\fonttbl\\f0\\fmodern %s;}\\f0\\fs%d", cfg.font.name, cfg.font.height*2); /* * Add colour palette * {\colortbl ;\red255\green0\blue0;\red0\green0\blue128;} */ /* |
︙ | ︙ | |||
4963 4964 4965 4966 4967 4968 4969 | if (attr[i] & ATTR_REVERSE) { int tmpcolour = fgcolour; /* Swap foreground and background */ fgcolour = bgcolour; bgcolour = tmpcolour; } | | | 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 | if (attr[i] & ATTR_REVERSE) { int tmpcolour = fgcolour; /* Swap foreground and background */ fgcolour = bgcolour; bgcolour = tmpcolour; } if (bold_mode == BOLD_COLOURS && (attr[i] & ATTR_BOLD)) { if (fgcolour < 8) /* ANSI colours */ fgcolour += 8; else if (fgcolour >= 256) /* Default colours */ fgcolour ++; } if (attr[i] & ATTR_BLINK) { |
︙ | ︙ | |||
5054 5055 5056 5057 5058 5059 5060 | if (attr[tindex] & ATTR_REVERSE) { int tmpcolour = fgcolour; /* Swap foreground and background */ fgcolour = bgcolour; bgcolour = tmpcolour; } | | | | | 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 | if (attr[tindex] & ATTR_REVERSE) { int tmpcolour = fgcolour; /* Swap foreground and background */ fgcolour = bgcolour; bgcolour = tmpcolour; } if (bold_mode == BOLD_COLOURS && (attr[tindex] & ATTR_BOLD)) { if (fgcolour < 8) /* ANSI colours */ fgcolour += 8; else if (fgcolour >= 256) /* Default colours */ fgcolour ++; } if (attr[tindex] & ATTR_BLINK) { if (bgcolour < 8) /* ANSI colours */ bgcolour += 8; else if (bgcolour >= 256) /* Default colours */ bgcolour ++; } /* * Collect other attributes */ if (bold_mode != BOLD_COLOURS) attrBold = attr[tindex] & ATTR_BOLD; else attrBold = 0; attrUnder = attr[tindex] & ATTR_UNDER; /* * Reverse video * o If video isn't reversed, ignore colour attributes for default foregound * or background. * o Special case where bolded text is displayed using the default foregound * and background colours - force to bolded RTF. */ if (!(attr[tindex] & ATTR_REVERSE)) { if (bgcolour >= 256) /* Default color */ bgcolour = -1; /* No coloring */ if (fgcolour >= 256) { /* Default colour */ if (bold_mode == BOLD_COLOURS && (fgcolour & 1) && bgcolour == -1) attrBold = ATTR_BOLD; /* Emphasize text with bold attribute */ fgcolour = -1; /* No coloring */ } } /* |
︙ | ︙ | |||
5355 5356 5357 5358 5359 5360 5361 | sprintf(morestuff, "%.70s Fatal Error", appname); MessageBox(hwnd, stuff, morestuff, MB_SYSTEMMODAL | MB_ICONERROR | MB_OK); sfree(stuff); cleanup_exit(1); } | < < < < > | < < > | < < < < < < > > | 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 | sprintf(morestuff, "%.70s Fatal Error", appname); MessageBox(hwnd, stuff, morestuff, MB_SYSTEMMODAL | MB_ICONERROR | MB_OK); sfree(stuff); cleanup_exit(1); } DECL_WINDOWS_FUNCTION(static, BOOL, FlashWindowEx, (PFLASHWINFO)); static void init_flashwindow(void) { HMODULE user32_module = load_system32_dll("user32.dll"); GET_WINDOWS_FUNCTION(user32_module, FlashWindowEx); } static BOOL flash_window_ex(DWORD dwFlags, UINT uCount, DWORD dwTimeout) { if (p_FlashWindowEx) { FLASHWINFO fi; fi.cbSize = sizeof(fi); |
︙ | ︙ | |||
5394 5395 5396 5397 5398 5399 5400 | static long next_flash; static int flashing = 0; /* * Timer for platforms where we must maintain window flashing manually * (e.g., Win95). */ | | | < | | 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 | static long next_flash; static int flashing = 0; /* * Timer for platforms where we must maintain window flashing manually * (e.g., Win95). */ static void flash_window_timer(void *ctx, long now) { if (flashing && now - next_flash >= 0) { flash_window(1); } } /* * Manage window caption / taskbar flashing, if enabled. * 0 = stop, 1 = maintain, 2 = start */ static void flash_window(int mode) { if ((mode == 0) || (cfg.beep_ind == B_IND_DISABLED)) { /* stop */ if (flashing) { flashing = 0; if (p_FlashWindowEx) flash_window_ex(FLASHW_STOP, 0, 0); else FlashWindow(hwnd, FALSE); |
︙ | ︙ | |||
5430 5431 5432 5433 5434 5435 5436 | /* For so-called "steady" mode, we use uCount=2, which * seems to be the traditional number of flashes used * by user notifications (e.g., by Explorer). * uCount=0 appears to enable continuous flashing, per * "flashing" mode, although I haven't seen this * documented. */ flash_window_ex(FLASHW_ALL | FLASHW_TIMER, | | | | 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 | /* For so-called "steady" mode, we use uCount=2, which * seems to be the traditional number of flashes used * by user notifications (e.g., by Explorer). * uCount=0 appears to enable continuous flashing, per * "flashing" mode, although I haven't seen this * documented. */ flash_window_ex(FLASHW_ALL | FLASHW_TIMER, (cfg.beep_ind == B_IND_FLASH ? 0 : 2), 0 /* system cursor blink rate */); /* No need to schedule timer */ } else { FlashWindow(hwnd, TRUE); next_flash = schedule_timer(450, flash_window_timer, hwnd); } } } else if ((mode == 1) && (cfg.beep_ind == B_IND_FLASH)) { /* maintain */ if (flashing && !p_FlashWindowEx) { FlashWindow(hwnd, TRUE); /* toggle */ next_flash = schedule_timer(450, flash_window_timer, hwnd); } } } |
︙ | ︙ | |||
5473 5474 5475 5476 5477 5478 5479 | MessageBeep(MB_OK); /* * The above MessageBeep call takes time, so we record the * time _after_ it finishes rather than before it starts. */ lastbeep = GetTickCount(); } else if (mode == BELL_WAVEFILE) { | < | | | | | 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 | MessageBeep(MB_OK); /* * The above MessageBeep call takes time, so we record the * time _after_ it finishes rather than before it starts. */ lastbeep = GetTickCount(); } else if (mode == BELL_WAVEFILE) { if (!PlaySound(cfg.bell_wavefile.path, NULL, SND_ASYNC | SND_FILENAME)) { char buf[sizeof(cfg.bell_wavefile.path) + 80]; char otherbuf[100]; sprintf(buf, "Unable to play sound file\n%s\n" "Using default sound instead", cfg.bell_wavefile.path); sprintf(otherbuf, "%.70s Sound Error", appname); MessageBox(hwnd, buf, otherbuf, MB_OK | MB_ICONEXCLAMATION); cfg.beep = BELL_DEFAULT; } } else if (mode == BELL_PCSPEAKER) { static long lastbeep = 0; long beepdiff; beepdiff = GetTickCount() - lastbeep; if (beepdiff >= 0 && beepdiff < 50) |
︙ | ︙ | |||
5529 5530 5531 5532 5533 5534 5535 | } /* * Move the window in response to a server-side request. */ void move_window(void *frontend, int x, int y) { | < | | | | 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 | } /* * Move the window in response to a server-side request. */ void move_window(void *frontend, int x, int y) { if (cfg.resize_action == RESIZE_DISABLED || cfg.resize_action == RESIZE_FONT || IsZoomed(hwnd)) return; SetWindowPos(hwnd, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); } /* * Move the window to the top or bottom of the z-order in response * to a server-side request. */ void set_zorder(void *frontend, int top) { if (cfg.alwaysontop) return; /* ignore */ SetWindowPos(hwnd, top ? HWND_TOP : HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); } /* * Refresh the window in response to a server-side request. |
︙ | ︙ | |||
5666 5667 5668 5669 5670 5671 5672 | if (is_full_screen()) return; /* Remove the window furniture. */ style = GetWindowLongPtr(hwnd, GWL_STYLE); style &= ~(WS_CAPTION | WS_BORDER | WS_THICKFRAME); | | | 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 | if (is_full_screen()) return; /* Remove the window furniture. */ style = GetWindowLongPtr(hwnd, GWL_STYLE); style &= ~(WS_CAPTION | WS_BORDER | WS_THICKFRAME); if (cfg.scrollbar_in_fullscreen) style |= WS_VSCROLL; else style &= ~WS_VSCROLL; SetWindowLongPtr(hwnd, GWL_STYLE, style); /* Resize ourselves to exactly cover the nearest monitor. */ get_fullscreen_rect(&ss); |
︙ | ︙ | |||
5701 5702 5703 5704 5705 5706 5707 | static void clear_full_screen() { DWORD oldstyle, style; /* Reinstate the window furniture. */ style = oldstyle = GetWindowLongPtr(hwnd, GWL_STYLE); style |= WS_CAPTION | WS_BORDER; | | | | 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 | static void clear_full_screen() { DWORD oldstyle, style; /* Reinstate the window furniture. */ style = oldstyle = GetWindowLongPtr(hwnd, GWL_STYLE); style |= WS_CAPTION | WS_BORDER; if (cfg.resize_action == RESIZE_DISABLED) style &= ~WS_THICKFRAME; else style |= WS_THICKFRAME; if (cfg.scrollbar) style |= WS_VSCROLL; else style &= ~WS_VSCROLL; if (style != oldstyle) { SetWindowLongPtr(hwnd, GWL_STYLE, style); SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | |
︙ | ︙ | |||
5760 5761 5762 5763 5764 5765 5766 | } int from_backend_untrusted(void *frontend, const char *data, int len) { return term_data_untrusted(term, data, len); } | < < < < < | 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 | } int from_backend_untrusted(void *frontend, const char *data, int len) { return term_data_untrusted(term, data, len); } int get_userpass_input(prompts_t *p, unsigned char *in, int inlen) { int ret; ret = cmdline_get_passwd_input(p, in, inlen); if (ret == -1) ret = term_get_userpass_input(term, p, in, inlen); return ret; |
︙ | ︙ |
Changes to windows/wingss.c.
︙ | ︙ | |||
61 62 63 64 65 66 67 | const Ssh_gss_buf gss_mech_krb5={9,"\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"}; const char *gsslogmsg = NULL; static void ssh_sspi_bind_fns(struct ssh_gss_library *lib); | | < | 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | const Ssh_gss_buf gss_mech_krb5={9,"\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"}; const char *gsslogmsg = NULL; static void ssh_sspi_bind_fns(struct ssh_gss_library *lib); struct ssh_gss_liblist *ssh_gss_setup(const Config *cfg) { HMODULE module; HKEY regkey; struct ssh_gss_liblist *list = snew(struct ssh_gss_liblist); list->libraries = snewn(3, struct ssh_gss_library); list->nlibraries = 0; /* MIT Kerberos GSSAPI implementation */ /* TODO: For 64-bit builds, check for gssapi64.dll */ module = NULL; |
︙ | ︙ | |||
145 146 147 148 149 150 151 | ssh_sspi_bind_fns(lib); } /* * Custom GSSAPI DLL. */ module = NULL; | | < | | | 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | ssh_sspi_bind_fns(lib); } /* * Custom GSSAPI DLL. */ module = NULL; if (cfg->ssh_gss_custom.path[0]) { module = LoadLibrary(cfg->ssh_gss_custom.path); } if (module) { struct ssh_gss_library *lib = &list->libraries[list->nlibraries++]; lib->id = 2; lib->gsslogmsg = dupprintf("Using GSSAPI from user-specified" " library '%s'", cfg->ssh_gss_custom.path); lib->handle = (void *)module; #define BIND_GSS_FN(name) \ lib->u.gssapi.name = (t_gss_##name) GetProcAddress(module, "gss_" #name) BIND_GSS_FN(delete_sec_context); BIND_GSS_FN(display_status); |
︙ | ︙ |
Changes to windows/winhandl.c.
︙ | ︙ | |||
61 62 63 64 65 66 67 | int moribund; /* are we going to kill this soon? */ int done; /* request subthread to terminate */ int defunct; /* has the subthread already gone? */ int busy; /* operation currently in progress? */ void *privdata; /* for client to remember who they are */ }; | < < | 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | int moribund; /* are we going to kill this soon? */ int done; /* request subthread to terminate */ int defunct; /* has the subthread already gone? */ int busy; /* operation currently in progress? */ void *privdata; /* for client to remember who they are */ }; /* ---------------------------------------------------------------------- * Input threads. */ /* * Data required by an input thread. */ |
︙ | ︙ | |||
248 249 250 251 252 253 254 | DWORD lenwritten; /* how much data we actually wrote */ int writeerr; /* return value from WriteFile */ /* * Data only ever read or written by the main thread. */ bufchain queued_data; /* data still waiting to be written */ | < | 246 247 248 249 250 251 252 253 254 255 256 257 258 259 | DWORD lenwritten; /* how much data we actually wrote */ int writeerr; /* return value from WriteFile */ /* * Data only ever read or written by the main thread. */ bufchain queued_data; /* data still waiting to be written */ /* * Callback function called when the backlog in the bufchain * drops. */ handle_outputfn_t sentdata; }; |
︙ | ︙ | |||
319 320 321 322 323 324 325 | if (!ctx->busy && bufchain_size(&ctx->queued_data)) { bufchain_prefix(&ctx->queued_data, &senddata, &sendlen); ctx->buffer = senddata; ctx->len = sendlen; SetEvent(ctx->ev_from_main); ctx->busy = TRUE; | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 | if (!ctx->busy && bufchain_size(&ctx->queued_data)) { bufchain_prefix(&ctx->queued_data, &senddata, &sendlen); ctx->buffer = senddata; ctx->len = sendlen; SetEvent(ctx->ev_from_main); ctx->busy = TRUE; } } /* ---------------------------------------------------------------------- * Unified code handling both input and output threads. */ struct handle { int output; union { struct handle_generic g; struct handle_input i; struct handle_output o; } u; }; static tree234 *handles_by_evtomain; static int handle_cmp_evtomain(void *av, void *bv) { |
︙ | ︙ | |||
402 403 404 405 406 407 408 | struct handle *handle_input_new(HANDLE handle, handle_inputfn_t gotdata, void *privdata, int flags) { struct handle *h = snew(struct handle); DWORD in_threadid; /* required for Win9x */ | | | 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 | struct handle *handle_input_new(HANDLE handle, handle_inputfn_t gotdata, void *privdata, int flags) { struct handle *h = snew(struct handle); DWORD in_threadid; /* required for Win9x */ h->output = FALSE; h->u.i.h = handle; h->u.i.ev_to_main = CreateEvent(NULL, FALSE, FALSE, NULL); h->u.i.ev_from_main = CreateEvent(NULL, FALSE, FALSE, NULL); h->u.i.gotdata = gotdata; h->u.i.defunct = FALSE; h->u.i.moribund = FALSE; h->u.i.done = FALSE; |
︙ | ︙ | |||
430 431 432 433 434 435 436 | struct handle *handle_output_new(HANDLE handle, handle_outputfn_t sentdata, void *privdata, int flags) { struct handle *h = snew(struct handle); DWORD out_threadid; /* required for Win9x */ | | < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < | 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 | struct handle *handle_output_new(HANDLE handle, handle_outputfn_t sentdata, void *privdata, int flags) { struct handle *h = snew(struct handle); DWORD out_threadid; /* required for Win9x */ h->output = TRUE; h->u.o.h = handle; h->u.o.ev_to_main = CreateEvent(NULL, FALSE, FALSE, NULL); h->u.o.ev_from_main = CreateEvent(NULL, FALSE, FALSE, NULL); h->u.o.busy = FALSE; h->u.o.defunct = FALSE; h->u.o.moribund = FALSE; h->u.o.done = FALSE; h->u.o.privdata = privdata; bufchain_init(&h->u.o.queued_data); h->u.o.sentdata = sentdata; h->u.o.flags = flags; if (!handles_by_evtomain) handles_by_evtomain = newtree234(handle_cmp_evtomain); add234(handles_by_evtomain, h); CreateThread(NULL, 0, handle_output_threadfunc, &h->u.o, 0, &out_threadid); return h; } int handle_write(struct handle *h, const void *data, int len) { assert(h->output); bufchain_add(&h->u.o.queued_data, data, len); handle_try_output(&h->u.o); return bufchain_size(&h->u.o.queued_data); } HANDLE *handle_get_events(int *nevents) { HANDLE *ret; struct handle *h; int i, n, size; /* |
︙ | ︙ | |||
533 534 535 536 537 538 539 | *nevents = n; return ret; } static void handle_destroy(struct handle *h) { | | | 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 | *nevents = n; return ret; } static void handle_destroy(struct handle *h) { if (h->output) bufchain_clear(&h->u.o.queued_data); CloseHandle(h->u.g.ev_from_main); CloseHandle(h->u.g.ev_to_main); del234(handles_by_evtomain, h); sfree(h); } |
︙ | ︙ | |||
610 611 612 613 614 615 616 | h->u.g.done = TRUE; h->u.g.busy = TRUE; SetEvent(h->u.g.ev_from_main); } return; } | | < < | < < < < < < < | | | 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 | h->u.g.done = TRUE; h->u.g.busy = TRUE; SetEvent(h->u.g.ev_from_main); } return; } if (!h->output) { int backlog; h->u.i.busy = FALSE; /* * A signal on an input handle means data has arrived. */ if (h->u.i.len == 0) { /* * EOF, or (nearly equivalently) read error. */ h->u.i.gotdata(h, NULL, -h->u.i.readerr); h->u.i.defunct = TRUE; } else { backlog = h->u.i.gotdata(h, h->u.i.buffer, h->u.i.len); handle_throttle(&h->u.i, backlog); } } else { h->u.o.busy = FALSE; /* * A signal on an output handle means we have completed a * write. Call the callback to indicate that the output * buffer size has decreased, or to indicate an error. */ if (h->u.o.writeerr) { /* * Write error. Send a negative value to the callback, * and mark the thread as defunct (because the output * thread is terminating by now). */ h->u.o.sentdata(h, -h->u.o.writeerr); h->u.o.defunct = TRUE; } else { bufchain_consume(&h->u.o.queued_data, h->u.o.lenwritten); h->u.o.sentdata(h, bufchain_size(&h->u.o.queued_data)); handle_try_output(&h->u.o); } } } void handle_unthrottle(struct handle *h, int backlog) { assert(!h->output); handle_throttle(&h->u.i, backlog); } int handle_backlog(struct handle *h) { assert(h->output); return bufchain_size(&h->u.o.queued_data); } void *handle_get_privdata(struct handle *h) { return h->u.g.privdata; } |
Changes to windows/winhelp.c.
︙ | ︙ | |||
77 78 79 80 81 82 83 | { /* * FIXME: it would be nice here to disregard help_path on * platforms that didn't have WINHLP32. But that's probably * unrealistic, since even Vista will have it if the user * specifically downloads it. */ | | | 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | { /* * FIXME: it would be nice here to disregard help_path on * platforms that didn't have WINHLP32. But that's probably * unrealistic, since even Vista will have it if the user * specifically downloads it. */ return (help_path #ifndef NO_HTMLHELP || chm_path #endif /* NO_HTMLHELP */ ); } void launch_help(HWND hwnd, const char *topic) |
︙ | ︙ |
Changes to windows/winhelp.h.
︙ | ︙ | |||
95 96 97 98 99 100 101 | #define WINHELP_CTX_ssh_nopty "ssh.nopty:config-ssh-pty" #define WINHELP_CTX_ssh_ttymodes "ssh.ttymodes:config-ttymodes" #define WINHELP_CTX_ssh_noshell "ssh.noshell:config-ssh-noshell" #define WINHELP_CTX_ssh_ciphers "ssh.ciphers:config-ssh-encryption" #define WINHELP_CTX_ssh_protocol "ssh.protocol:config-ssh-prot" #define WINHELP_CTX_ssh_command "ssh.command:config-command" #define WINHELP_CTX_ssh_compress "ssh.compress:config-ssh-comp" | < | 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | #define WINHELP_CTX_ssh_nopty "ssh.nopty:config-ssh-pty" #define WINHELP_CTX_ssh_ttymodes "ssh.ttymodes:config-ttymodes" #define WINHELP_CTX_ssh_noshell "ssh.noshell:config-ssh-noshell" #define WINHELP_CTX_ssh_ciphers "ssh.ciphers:config-ssh-encryption" #define WINHELP_CTX_ssh_protocol "ssh.protocol:config-ssh-prot" #define WINHELP_CTX_ssh_command "ssh.command:config-command" #define WINHELP_CTX_ssh_compress "ssh.compress:config-ssh-comp" #define WINHELP_CTX_ssh_kexlist "ssh.kex.order:config-ssh-kex-order" #define WINHELP_CTX_ssh_kex_repeat "ssh.kex.repeat:config-ssh-kex-rekey" #define WINHELP_CTX_ssh_auth_bypass "ssh.auth.bypass:config-ssh-noauth" #define WINHELP_CTX_ssh_auth_banner "ssh.auth.banner:config-ssh-banner" #define WINHELP_CTX_ssh_auth_privkey "ssh.auth.privkey:config-ssh-privkey" #define WINHELP_CTX_ssh_auth_agentfwd "ssh.auth.agentfwd:config-ssh-agentfwd" #define WINHELP_CTX_ssh_auth_changeuser "ssh.auth.changeuser:config-ssh-changeuser" |
︙ | ︙ | |||
141 142 143 144 145 146 147 | #define WINHELP_CTX_ssh_bugs_ignore2 "ssh.bugs.ignore2:config-ssh-bug-ignore2" #define WINHELP_CTX_ssh_bugs_hmac2 "ssh.bugs.hmac2:config-ssh-bug-hmac2" #define WINHELP_CTX_ssh_bugs_derivekey2 "ssh.bugs.derivekey2:config-ssh-bug-derivekey2" #define WINHELP_CTX_ssh_bugs_rsapad2 "ssh.bugs.rsapad2:config-ssh-bug-sig" #define WINHELP_CTX_ssh_bugs_pksessid2 "ssh.bugs.pksessid2:config-ssh-bug-pksessid2" #define WINHELP_CTX_ssh_bugs_rekey2 "ssh.bugs.rekey2:config-ssh-bug-rekey" #define WINHELP_CTX_ssh_bugs_maxpkt2 "ssh.bugs.maxpkt2:config-ssh-bug-maxpkt2" | < | 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | #define WINHELP_CTX_ssh_bugs_ignore2 "ssh.bugs.ignore2:config-ssh-bug-ignore2" #define WINHELP_CTX_ssh_bugs_hmac2 "ssh.bugs.hmac2:config-ssh-bug-hmac2" #define WINHELP_CTX_ssh_bugs_derivekey2 "ssh.bugs.derivekey2:config-ssh-bug-derivekey2" #define WINHELP_CTX_ssh_bugs_rsapad2 "ssh.bugs.rsapad2:config-ssh-bug-sig" #define WINHELP_CTX_ssh_bugs_pksessid2 "ssh.bugs.pksessid2:config-ssh-bug-pksessid2" #define WINHELP_CTX_ssh_bugs_rekey2 "ssh.bugs.rekey2:config-ssh-bug-rekey" #define WINHELP_CTX_ssh_bugs_maxpkt2 "ssh.bugs.maxpkt2:config-ssh-bug-maxpkt2" #define WINHELP_CTX_serial_line "serial.line:config-serial-line" #define WINHELP_CTX_serial_speed "serial.speed:config-serial-speed" #define WINHELP_CTX_serial_databits "serial.databits:config-serial-databits" #define WINHELP_CTX_serial_stopbits "serial.stopbits:config-serial-stopbits" #define WINHELP_CTX_serial_parity "serial.parity:config-serial-parity" #define WINHELP_CTX_serial_flow "serial.flow:config-serial-flow" |
︙ | ︙ | |||
166 167 168 169 170 171 172 173 174 175 176 177 178 179 | #define WINHELP_CTX_puttygen_comment "puttygen.comment:puttygen-comment" #define WINHELP_CTX_puttygen_passphrase "puttygen.passphrase:puttygen-passphrase" #define WINHELP_CTX_puttygen_savepriv "puttygen.savepriv:puttygen-savepriv" #define WINHELP_CTX_puttygen_savepub "puttygen.savepub:puttygen-savepub" #define WINHELP_CTX_puttygen_pastekey "puttygen.pastekey:puttygen-pastekey" #define WINHELP_CTX_puttygen_load "puttygen.load:puttygen-load" #define WINHELP_CTX_puttygen_conversions "puttygen.conversions:puttygen-conversions" /* These are used in Windows-specific bits of the frontend. * We (ab)use "help context identifiers" (dwContextId) to identify them. */ #define HELPCTXID(x) WINHELP_CTXID_ ## x #define WINHELP_CTXID_no_help 0 | > > > > > > > > > > > > > | 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 | #define WINHELP_CTX_puttygen_comment "puttygen.comment:puttygen-comment" #define WINHELP_CTX_puttygen_passphrase "puttygen.passphrase:puttygen-passphrase" #define WINHELP_CTX_puttygen_savepriv "puttygen.savepriv:puttygen-savepriv" #define WINHELP_CTX_puttygen_savepub "puttygen.savepub:puttygen-savepub" #define WINHELP_CTX_puttygen_pastekey "puttygen.pastekey:puttygen-pastekey" #define WINHELP_CTX_puttygen_load "puttygen.load:puttygen-load" #define WINHELP_CTX_puttygen_conversions "puttygen.conversions:puttygen-conversions" /* PuTTY SC start */ #define WINHELP_CTX_ssh_write_syslog "ssh.write.syslog" #define WINHELP_CTX_ssh_auth_pkcs11 "ssh.auth.pkcs11" #define WINHELP_CTX_ssh_auth_pkcs11_libfile "ssh.auth.pkcs11libfile" #define WINHELP_CTX_ssh_auth_pkcs11_token_label "ssh.auth.pkcs11tokenlabel" #define WINHELP_CTX_ssh_auth_pkcs11_cert_label "ssh.auth.pkcs11certlabel" /* PuTTY SC end */ /* PuTTY CAPI start */ #ifdef _WINDOWS #define WINHELP_CTX_ssh_auth_capi "ssh.auth.capi" #define WINHELP_CTX_ssh_auth_capi_certstore_label "ssh.auth.capicertstorelabel" #endif /* PuTTY CAPI end */ /* These are used in Windows-specific bits of the frontend. * We (ab)use "help context identifiers" (dwContextId) to identify them. */ #define HELPCTXID(x) WINHELP_CTXID_ ## x #define WINHELP_CTXID_no_help 0 |
︙ | ︙ |
Deleted windows/winhsock.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to windows/winjump.c.
︙ | ︙ | |||
349 350 351 352 353 354 355 | 0x886d8eeb, 0x8cf2, 0x4446, {0x8d,0x02,0xcd,0xba,0x1d,0xbd,0xcf,0x99} }; static const PROPERTYKEY PKEY_Title = { {0xf29f85e0, 0x4ff9, 0x1068, {0xab,0x91,0x08,0x00,0x2b,0x27,0xb3,0xd9}}, 0x00000002 }; | | > | < < > | | 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 | 0x886d8eeb, 0x8cf2, 0x4446, {0x8d,0x02,0xcd,0xba,0x1d,0xbd,0xcf,0x99} }; static const PROPERTYKEY PKEY_Title = { {0xf29f85e0, 0x4ff9, 0x1068, {0xab,0x91,0x08,0x00,0x2b,0x27,0xb3,0xd9}}, 0x00000002 }; /* Type-checking macro to provide arguments for CoCreateInstance() etc. * The pointer arithmetic is a compile-time pointer type check that 'obj' * really is a 'type **', but is intended to have no effect at runtime. */ #define COMPTR(type, obj) &IID_##type, \ (void **)(void *)((obj) + (sizeof((obj)-(type **)(obj))) \ - (sizeof((obj)-(type **)(obj)))) static char putty_path[2048]; /* * Function to make an IShellLink describing a particular PuTTY * command. If 'appname' is null, the command run will be the one * returned by GetModuleFileName, i.e. our own executable; if it's |
︙ | ︙ | |||
406 407 408 409 410 411 412 | } else { app_path = dupstr(putty_path); } /* Check if this is a valid session, otherwise don't add. */ if (sessionname) { psettings_tmp = open_settings_r(sessionname); | | < < | < < | 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 | } else { app_path = dupstr(putty_path); } /* Check if this is a valid session, otherwise don't add. */ if (sessionname) { psettings_tmp = open_settings_r(sessionname); if (!psettings_tmp) return NULL; close_settings_r(psettings_tmp); } /* Create the new item. */ if (!SUCCEEDED(CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, COMPTR(IShellLink, &ret)))) return NULL; /* Set path, parameters, icon and description. */ ret->lpVtbl->SetPath(ret, app_path); if (sessionname) { param_string = dupcat("@", sessionname, NULL); } else { |
︙ | ︙ |
Changes to windows/winmisc.c.
︙ | ︙ | |||
10 11 12 13 14 15 16 | OSVERSIONINFO osVersion; char *platform_get_x_display(void) { /* We may as well check for DISPLAY in case it's useful. */ return dupstr(getenv("DISPLAY")); } | | | > | < < < < < | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | OSVERSIONINFO osVersion; char *platform_get_x_display(void) { /* We may as well check for DISPLAY in case it's useful. */ return dupstr(getenv("DISPLAY")); } Filename filename_from_str(const char *str) { Filename ret; strncpy(ret.path, str, sizeof(ret.path)); ret.path[sizeof(ret.path)-1] = '\0'; return ret; } const char *filename_to_str(const Filename *fn) { return fn->path; } int filename_equal(Filename f1, Filename f2) { return !strcmp(f1.path, f2.path); } int filename_is_null(Filename fn) { return !*fn.path; } char *get_username(void) { DWORD namelen; char *user; int got_username = FALSE; DECL_WINDOWS_FUNCTION(static, BOOLEAN, GetUserNameExA, |
︙ | ︙ | |||
169 170 171 172 173 174 175 | fullpath = dupcat(sysdir, "\\", libname, NULL); ret = LoadLibrary(fullpath); sfree(fullpath); return ret; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | fullpath = dupcat(sysdir, "\\", libname, NULL); ret = LoadLibrary(fullpath); sfree(fullpath); return ret; } #ifdef DEBUG static FILE *debug_fp = NULL; static HANDLE debug_hdl = INVALID_HANDLE_VALUE; static int debug_got_console = 0; void dputs(char *buf) { |
︙ | ︙ | |||
477 478 479 480 481 482 483 | oldsize = minefield_get_size(p); memcpy(q, p, (oldsize < size ? oldsize : size)); minefield_free(p); return q; } #endif /* MINEFIELD */ | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 375 376 377 378 379 380 381 | oldsize = minefield_get_size(p); memcpy(q, p, (oldsize < size ? oldsize : size)); minefield_free(p); return q; } #endif /* MINEFIELD */ |
Changes to windows/winnet.c.
︙ | ︙ | |||
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | struct Socket_tag { const struct socket_function_table *fn; /* the above variable absolutely *must* be the first in this structure */ char *error; SOCKET s; Plug plug; bufchain output_data; int connected; int writable; int frozen; /* this causes readability notifications to be ignored */ int frozen_readable; /* this means we missed at least one readability * notification while we were frozen */ int localhost_only; /* for listening sockets */ char oobdata[1]; int sending_oob; int oobinline, nodelay, keepalive, privport; | > < < < | 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | struct Socket_tag { const struct socket_function_table *fn; /* the above variable absolutely *must* be the first in this structure */ char *error; SOCKET s; Plug plug; void *private_ptr; bufchain output_data; int connected; int writable; int frozen; /* this causes readability notifications to be ignored */ int frozen_readable; /* this means we missed at least one readability * notification while we were frozen */ int localhost_only; /* for listening sockets */ char oobdata[1]; int sending_oob; int oobinline, nodelay, keepalive, privport; SockAddr addr; SockAddrStep step; int port; int pending_error; /* in case send() returns error */ /* * We sometimes need pairs of Socket structures to be linked: * if we are listening on the same IPv6 and v4 port, for * example. So here we define `parent' and `child' pointers to * track this link. */ Actual_Socket parent, child; }; struct SockAddr_tag { int refcount; char *error; int resolved; #ifndef NO_IPV6 struct addrinfo *ais; /* Addresses IPv6 style. */ #endif unsigned long *addresses; /* Addresses IPv4 style. */ int naddresses; char hostname[512]; /* Store an unresolved host name. */ }; |
︙ | ︙ | |||
165 166 167 168 169 170 171 | DECL_WINDOWS_FUNCTION(static, int, bind, (SOCKET, const struct sockaddr FAR *, int)); DECL_WINDOWS_FUNCTION(static, int, setsockopt, (SOCKET, int, int, const char FAR *, int)); DECL_WINDOWS_FUNCTION(static, SOCKET, socket, (int, int, int)); DECL_WINDOWS_FUNCTION(static, int, listen, (SOCKET, int)); DECL_WINDOWS_FUNCTION(static, int, send, (SOCKET, const char FAR *, int, int)); | < | 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | DECL_WINDOWS_FUNCTION(static, int, bind, (SOCKET, const struct sockaddr FAR *, int)); DECL_WINDOWS_FUNCTION(static, int, setsockopt, (SOCKET, int, int, const char FAR *, int)); DECL_WINDOWS_FUNCTION(static, SOCKET, socket, (int, int, int)); DECL_WINDOWS_FUNCTION(static, int, listen, (SOCKET, int)); DECL_WINDOWS_FUNCTION(static, int, send, (SOCKET, const char FAR *, int, int)); DECL_WINDOWS_FUNCTION(static, int, ioctlsocket, (SOCKET, long, u_long FAR *)); DECL_WINDOWS_FUNCTION(static, SOCKET, accept, (SOCKET, struct sockaddr FAR *, int FAR *)); DECL_WINDOWS_FUNCTION(static, int, recv, (SOCKET, char FAR *, int, int)); DECL_WINDOWS_FUNCTION(static, int, WSAIoctl, (SOCKET, DWORD, LPVOID, DWORD, LPVOID, DWORD, |
︙ | ︙ | |||
290 291 292 293 294 295 296 | GET_WINDOWS_FUNCTION(winsock_module, inet_ntoa); GET_WINDOWS_FUNCTION(winsock_module, connect); GET_WINDOWS_FUNCTION(winsock_module, bind); GET_WINDOWS_FUNCTION(winsock_module, setsockopt); GET_WINDOWS_FUNCTION(winsock_module, socket); GET_WINDOWS_FUNCTION(winsock_module, listen); GET_WINDOWS_FUNCTION(winsock_module, send); | < | 287 288 289 290 291 292 293 294 295 296 297 298 299 300 | GET_WINDOWS_FUNCTION(winsock_module, inet_ntoa); GET_WINDOWS_FUNCTION(winsock_module, connect); GET_WINDOWS_FUNCTION(winsock_module, bind); GET_WINDOWS_FUNCTION(winsock_module, setsockopt); GET_WINDOWS_FUNCTION(winsock_module, socket); GET_WINDOWS_FUNCTION(winsock_module, listen); GET_WINDOWS_FUNCTION(winsock_module, send); GET_WINDOWS_FUNCTION(winsock_module, ioctlsocket); GET_WINDOWS_FUNCTION(winsock_module, accept); GET_WINDOWS_FUNCTION(winsock_module, recv); GET_WINDOWS_FUNCTION(winsock_module, WSAIoctl); /* Try to get the best WinSock version we can get */ if (!sk_startup(2,2) && |
︙ | ︙ | |||
329 330 331 332 333 334 335 | FreeLibrary(winsock_module); #ifndef NO_IPV6 if (wship6_module) FreeLibrary(wship6_module); #endif } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 | FreeLibrary(winsock_module); #ifndef NO_IPV6 if (wship6_module) FreeLibrary(wship6_module); #endif } char *winsock_error_string(int error) { switch (error) { case WSAEACCES: return "Network error: Permission denied"; case WSAEADDRINUSE: return "Network error: Address already in use"; case WSAEADDRNOTAVAIL: return "Network error: Cannot assign requested address"; |
︙ | ︙ | |||
433 434 435 436 437 438 439 | return "Network error: Socket type not supported"; case WSAETIMEDOUT: return "Network error: Connection timed out"; case WSAEWOULDBLOCK: return "Network error: Resource temporarily unavailable"; case WSAEDISCON: return "Network error: Graceful shutdown in progress"; | < | < < < < < < < < < < < < | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 | return "Network error: Socket type not supported"; case WSAETIMEDOUT: return "Network error: Connection timed out"; case WSAEWOULDBLOCK: return "Network error: Resource temporarily unavailable"; case WSAEDISCON: return "Network error: Graceful shutdown in progress"; default: return "Unknown network error"; } } SockAddr sk_namelookup(const char *host, char **canonicalname, int address_family) { SockAddr ret = snew(struct SockAddr_tag); unsigned long a; |
︙ | ︙ | |||
502 503 504 505 506 507 508 | AF_UNSPEC); /* Clear the structure and default to IPv4. */ memset(ret, 0, sizeof(struct SockAddr_tag)); #ifndef NO_IPV6 ret->ais = NULL; #endif | < | 424 425 426 427 428 429 430 431 432 433 434 435 436 437 | AF_UNSPEC); /* Clear the structure and default to IPv4. */ memset(ret, 0, sizeof(struct SockAddr_tag)); #ifndef NO_IPV6 ret->ais = NULL; #endif ret->addresses = NULL; ret->resolved = FALSE; ret->refcount = 1; *realhost = '\0'; if ((a = p_inet_addr(host)) == (unsigned long) INADDR_NONE) { struct hostent *h = NULL; |
︙ | ︙ | |||
609 610 611 612 613 614 615 | { SockAddr ret = snew(struct SockAddr_tag); ret->error = NULL; ret->resolved = FALSE; #ifndef NO_IPV6 ret->ais = NULL; #endif | < < < < < < < < < < < < < < < < < < | 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 | { SockAddr ret = snew(struct SockAddr_tag); ret->error = NULL; ret->resolved = FALSE; #ifndef NO_IPV6 ret->ais = NULL; #endif ret->addresses = NULL; ret->naddresses = 0; ret->refcount = 1; strncpy(ret->hostname, host, lenof(ret->hostname)); ret->hostname[lenof(ret->hostname)-1] = '\0'; return ret; } int sk_nextaddr(SockAddr addr, SockAddrStep *step) { #ifndef NO_IPV6 if (step->ai) { if (step->ai->ai_next) { step->ai = step->ai->ai_next; return TRUE; |
︙ | ︙ | |||
688 689 690 691 692 693 694 | buf[buflen-1] = '\0'; } else { strncpy(buf, addr->hostname, buflen); buf[buflen-1] = '\0'; } } | < < < < < | | 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 | buf[buflen-1] = '\0'; } else { strncpy(buf, addr->hostname, buflen); buf[buflen-1] = '\0'; } } int sk_hostname_is_local(char *name) { return !strcmp(name, "localhost") || !strcmp(name, "::1") || !strncmp(name, "127.", 4); } static INTERFACE_INFO local_interfaces[16]; |
︙ | ︙ | |||
740 741 742 743 744 745 746 | SockAddrStep step; int family; START_STEP(addr, step); family = SOCKADDR_FAMILY(addr, step); #ifndef NO_IPV6 if (family == AF_INET6) { | | | 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 | SockAddrStep step; int family; START_STEP(addr, step); family = SOCKADDR_FAMILY(addr, step); #ifndef NO_IPV6 if (family == AF_INET6) { return IN6_IS_ADDR_LOOPBACK((const struct in6_addr *)step.ai->ai_addr); } else #endif if (family == AF_INET) { #ifndef NO_IPV6 if (step.ai) { return ipv4_is_local_addr(((struct sockaddr_in *)step.ai->ai_addr) ->sin_addr); |
︙ | ︙ | |||
762 763 764 765 766 767 768 | } } else { assert(family == AF_UNSPEC); return 0; /* we don't know; assume not */ } } | < < < < < | 660 661 662 663 664 665 666 667 668 669 670 671 672 673 | } } else { assert(family == AF_UNSPEC); return 0; /* we don't know; assume not */ } } int sk_addrtype(SockAddr addr) { SockAddrStep step; int family; START_STEP(addr, step); family = SOCKADDR_FAMILY(addr, step); |
︙ | ︙ | |||
848 849 850 851 852 853 854 | * so we don't need to do anything here. :-) */ } static void sk_tcp_close(Socket s); static int sk_tcp_write(Socket s, const char *data, int len); static int sk_tcp_write_oob(Socket s, const char *data, int len); | | > | | | > < | | 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 | * so we don't need to do anything here. :-) */ } static void sk_tcp_close(Socket s); static int sk_tcp_write(Socket s, const char *data, int len); static int sk_tcp_write_oob(Socket s, const char *data, int len); static void sk_tcp_set_private_ptr(Socket s, void *ptr); static void *sk_tcp_get_private_ptr(Socket s); static void sk_tcp_set_frozen(Socket s, int is_frozen); static const char *sk_tcp_socket_error(Socket s); extern char *do_select(SOCKET skt, int startup); Socket sk_register(void *sock, Plug plug) { static const struct socket_function_table fn_table = { sk_tcp_plug, sk_tcp_close, sk_tcp_write, sk_tcp_write_oob, sk_tcp_flush, sk_tcp_set_private_ptr, sk_tcp_get_private_ptr, sk_tcp_set_frozen, sk_tcp_socket_error }; DWORD err; char *errstr; Actual_Socket ret; /* * Create Socket structure. */ ret = snew(struct Socket_tag); ret->fn = &fn_table; ret->error = NULL; ret->plug = plug; bufchain_init(&ret->output_data); ret->writable = 1; /* to start with */ ret->sending_oob = 0; ret->frozen = 1; ret->frozen_readable = 0; ret->localhost_only = 0; /* unused, but best init anyway */ ret->pending_error = 0; ret->parent = ret->child = NULL; ret->addr = NULL; ret->s = (SOCKET)sock; if (ret->s == INVALID_SOCKET) { err = p_WSAGetLastError(); ret->error = winsock_error_string(err); return (Socket) ret; } |
︙ | ︙ | |||
1109 1110 1111 1112 1113 1114 1115 | int nodelay, int keepalive, Plug plug) { static const struct socket_function_table fn_table = { sk_tcp_plug, sk_tcp_close, sk_tcp_write, sk_tcp_write_oob, | | | > < | 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 | int nodelay, int keepalive, Plug plug) { static const struct socket_function_table fn_table = { sk_tcp_plug, sk_tcp_close, sk_tcp_write, sk_tcp_write_oob, sk_tcp_flush, sk_tcp_set_private_ptr, sk_tcp_get_private_ptr, sk_tcp_set_frozen, sk_tcp_socket_error }; Actual_Socket ret; DWORD err; /* * Create Socket structure. */ ret = snew(struct Socket_tag); ret->fn = &fn_table; ret->error = NULL; ret->plug = plug; bufchain_init(&ret->output_data); ret->connected = 0; /* to start with */ ret->writable = 0; /* to start with */ ret->sending_oob = 0; ret->frozen = 0; ret->frozen_readable = 0; ret->localhost_only = 0; /* unused, but best init anyway */ ret->pending_error = 0; ret->parent = ret->child = NULL; ret->oobinline = oobinline; ret->nodelay = nodelay; |
︙ | ︙ | |||
1160 1161 1162 1163 1164 1165 1166 | int orig_address_family) { static const struct socket_function_table fn_table = { sk_tcp_plug, sk_tcp_close, sk_tcp_write, sk_tcp_write_oob, | | | > | 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 | int orig_address_family) { static const struct socket_function_table fn_table = { sk_tcp_plug, sk_tcp_close, sk_tcp_write, sk_tcp_write_oob, sk_tcp_flush, sk_tcp_set_private_ptr, sk_tcp_get_private_ptr, sk_tcp_set_frozen, sk_tcp_socket_error }; SOCKET s; #ifndef NO_IPV6 SOCKADDR_IN6 a6; |
︙ | ︙ | |||
1190 1191 1192 1193 1194 1195 1196 | ret = snew(struct Socket_tag); ret->fn = &fn_table; ret->error = NULL; ret->plug = plug; bufchain_init(&ret->output_data); ret->writable = 0; /* to start with */ ret->sending_oob = 0; | < | 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 | ret = snew(struct Socket_tag); ret->fn = &fn_table; ret->error = NULL; ret->plug = plug; bufchain_init(&ret->output_data); ret->writable = 0; /* to start with */ ret->sending_oob = 0; ret->frozen = 0; ret->frozen_readable = 0; ret->localhost_only = local_host_only; ret->pending_error = 0; ret->parent = ret->child = NULL; ret->addr = NULL; |
︙ | ︙ | |||
1302 1303 1304 1305 1306 1307 1308 | ret->error = winsock_error_string(err); return (Socket) ret; } if (p_listen(s, SOMAXCONN) == SOCKET_ERROR) { p_closesocket(s); | | | 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 | ret->error = winsock_error_string(err); return (Socket) ret; } if (p_listen(s, SOMAXCONN) == SOCKET_ERROR) { p_closesocket(s); ret->error = winsock_error_string(err); return (Socket) ret; } /* Set up a select mechanism. This could be an AsyncSelect on a * window, or an EventSelect on an event object. */ errstr = do_select(s, 1); if (errstr) { |
︙ | ︙ | |||
1358 1359 1360 1361 1362 1363 1364 | do_select(s->s, 0); p_closesocket(s->s); if (s->addr) sk_addr_free(s->addr); sfree(s); } | < < < < < < < < < < < < < < < < < < < < < | 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 | do_select(s->s, 0); p_closesocket(s->s); if (s->addr) sk_addr_free(s->addr); sfree(s); } /* * The function which tries to send on a socket once it's deemed * writable. */ void try_send(Actual_Socket s) { while (s->sending_oob || bufchain_size(&s->output_data) > 0) { |
︙ | ︙ | |||
1428 1429 1430 1431 1432 1433 1434 | * _in_ a call from the code we'd be calling back * to, so we'd have to make half the SSH code * reentrant. Instead we flag a pending error on * the socket, to be dealt with (by calling * plug_closing()) at some suitable future moment. */ s->pending_error = err; | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 | * _in_ a call from the code we'd be calling back * to, so we'd have to make half the SSH code * reentrant. Instead we flag a pending error on * the socket, to be dealt with (by calling * plug_closing()) at some suitable future moment. */ s->pending_error = err; return; } else { /* We're inside the Windows frontend here, so we know * that the frontend handle is unnecessary. */ logevent(NULL, winsock_error_string(err)); fatalbox("%s", winsock_error_string(err)); } } else { if (s->sending_oob) { if (nsent < len) { memmove(s->oobdata, s->oobdata+nsent, len-nsent); s->sending_oob = len - nsent; } else { s->sending_oob = 0; } } else { bufchain_consume(&s->output_data, nsent); } } } } static int sk_tcp_write(Socket sock, const char *buf, int len) { Actual_Socket s = (Actual_Socket) sock; /* * Add the data to the buffer list on the socket. */ bufchain_add(&s->output_data, buf, len); /* * Now try sending from the start of the buffer list. */ if (s->writable) try_send(s); return bufchain_size(&s->output_data); } static int sk_tcp_write_oob(Socket sock, const char *buf, int len) { Actual_Socket s = (Actual_Socket) sock; /* * Replace the buffer list on the socket with the data. */ bufchain_clear(&s->output_data); assert(len <= sizeof(s->oobdata)); memcpy(s->oobdata, buf, len); s->sending_oob = len; /* * Now try sending from the start of the buffer list. */ if (s->writable) try_send(s); return s->sending_oob; } int select_result(WPARAM wParam, LPARAM lParam) { int ret, open; DWORD err; char buf[20480]; /* nice big buffer for plenty of speed */ Actual_Socket s; u_long atmark; |
︙ | ︙ | |||
1673 1674 1675 1676 1677 1678 1679 | #ifdef NO_IPV6 struct sockaddr_in isa; #else struct sockaddr_storage isa; #endif int addrlen = sizeof(isa); SOCKET t; /* socket of connection */ | < < < < | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 | #ifdef NO_IPV6 struct sockaddr_in isa; #else struct sockaddr_storage isa; #endif int addrlen = sizeof(isa); SOCKET t; /* socket of connection */ memset(&isa, 0, sizeof(isa)); err = 0; t = p_accept(s->s,(struct sockaddr *)&isa,&addrlen); if (t == INVALID_SOCKET) { err = p_WSAGetLastError(); if (err == WSATRY_AGAIN) break; } #ifndef NO_IPV6 if (isa.ss_family == AF_INET && s->localhost_only && !ipv4_is_local_addr(((struct sockaddr_in *)&isa)->sin_addr)) #else if (s->localhost_only && !ipv4_is_local_addr(isa.sin_addr)) #endif { p_closesocket(t); /* dodgy WinSock let nonlocal through */ } else if (plug_accepting(s->plug, (void*)t)) { p_closesocket(t); /* denied or error */ } } } return 1; } /* * Deal with socket errors detected in try_send(). */ void net_pending_errors(void) { int i; Actual_Socket s; /* * This might be a fiddly business, because it's just possible * that handling a pending error on one socket might cause * others to be closed. (I can't think of any reason this might * happen in current SSH implementation, but to maintain * generality of this network layer I'll assume the worst.) * * So what we'll do is search the socket list for _one_ socket * with a pending error, and then handle it, and then search * the list again _from the beginning_. Repeat until we make a * pass with no socket errors present. That way we are * protected against the socket list changing under our feet. */ do { for (i = 0; (s = index234(sktree, i)) != NULL; i++) { if (s->pending_error) { /* * An error has occurred on this socket. Pass it to the * plug. */ plug_closing(s->plug, winsock_error_string(s->pending_error), s->pending_error, 0); break; } } } while (s); } /* * Each socket abstraction contains a `void *' private field in * which the client can keep state. */ static void sk_tcp_set_private_ptr(Socket sock, void *ptr) { Actual_Socket s = (Actual_Socket) sock; s->private_ptr = ptr; } static void *sk_tcp_get_private_ptr(Socket sock) { Actual_Socket s = (Actual_Socket) sock; return s->private_ptr; } /* * Special error values are returned from sk_namelookup and sk_new * if there's a problem. These functions extract an error message, * or return NULL if there's no problem. */ const char *sk_addr_error(SockAddr addr) |
︙ | ︙ |
Changes to windows/winnoise.c.
1 2 3 4 5 6 7 8 9 10 11 | /* * Noise generation for PuTTY's cryptographic random number * generator. */ #include <stdio.h> #include "putty.h" #include "ssh.h" #include "storage.h" | < < < < < < < < < < | > > < < < < < < < < < < < < < < < < < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | /* * Noise generation for PuTTY's cryptographic random number * generator. */ #include <stdio.h> #include "putty.h" #include "ssh.h" #include "storage.h" /* * This function is called once, at PuTTY startup, and will do some * seriously silly things like listing directories and getting disk * free space and a process snapshot. */ void noise_get_heavy(void (*func) (void *, int)) { HANDLE srch; WIN32_FIND_DATA finddata; DWORD pid; char winpath[MAX_PATH + 3]; GetWindowsDirectory(winpath, sizeof(winpath)); strcat(winpath, "\\*"); srch = FindFirstFile(winpath, &finddata); if (srch != INVALID_HANDLE_VALUE) { do { func(&finddata, sizeof(finddata)); } while (FindNextFile(srch, &finddata)); FindClose(srch); } pid = GetCurrentProcessId(); func(&pid, sizeof(pid)); read_random_seed(func); /* Update the seed immediately, in case another instance uses it. */ random_save_seed(); } void random_save_seed(void) { |
︙ | ︙ |
Deleted windows/winnpc.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted windows/winnps.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to windows/winpgen.c.
1 2 3 4 5 6 7 | /* * PuTTY key generation front end (Windows). */ #include <time.h> #include <stdio.h> #include <stdlib.h> | < | < < < < < < < < < < < < < < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | /* * PuTTY key generation front end (Windows). */ #include <time.h> #include <stdio.h> #include <stdlib.h> #define PUTTY_DO_GLOBALS #include "putty.h" #include "ssh.h" #include <commctrl.h> #ifdef MSVC4 #define ICON_BIG 1 #endif #define WM_DONEKEY (WM_APP + 1) #define DEFAULT_KEYSIZE 1024 static char *cmdline_keyfile = NULL; /* * Print a modal (Really Bad) message box and perform a fatal exit. */ void modalfatalbox(char *fmt, ...) { va_list ap; char *stuff; va_start(ap, fmt); stuff = dupvprintf(fmt, ap); va_end(ap); MessageBox(NULL, stuff, "PuTTYgen Fatal Error", MB_SYSTEMMODAL | MB_ICONERROR | MB_OK); sfree(stuff); exit(1); } /* ---------------------------------------------------------------------- * Progress report code. This is really horrible :-) */ #define PROGRESSRANGE 65535 #define MAXPHASE 5 struct progress { int nphases; |
︙ | ︙ | |||
129 130 131 132 133 134 135 136 | SendMessage(p->progbar, PBM_SETPOS, position / p->divisor, 0); break; } } extern char ver[]; struct PassphraseProcStruct { | > > | | | 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | SendMessage(p->progbar, PBM_SETPOS, position / p->divisor, 0); break; } } extern char ver[]; #define PASSPHRASE_MAXLEN 512 struct PassphraseProcStruct { char *passphrase; char *comment; }; /* * Dialog-box function for the passphrase box. */ static int CALLBACK PassphraseProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { static char *passphrase = NULL; struct PassphraseProcStruct *p; switch (msg) { case WM_INITDIALOG: SetForegroundWindow(hwnd); SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); |
︙ | ︙ | |||
168 169 170 171 172 173 174 | rd.right - rd.left, rd.bottom - rd.top, TRUE); } p = (struct PassphraseProcStruct *) lParam; passphrase = p->passphrase; if (p->comment) SetDlgItemText(hwnd, 101, p->comment); | < | | | > | | 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | rd.right - rd.left, rd.bottom - rd.top, TRUE); } p = (struct PassphraseProcStruct *) lParam; passphrase = p->passphrase; if (p->comment) SetDlgItemText(hwnd, 101, p->comment); *passphrase = 0; SetDlgItemText(hwnd, 102, passphrase); return 0; case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: if (*passphrase) EndDialog(hwnd, 1); else MessageBeep(0); return 0; case IDCANCEL: EndDialog(hwnd, 0); return 0; case 102: /* edit box */ if ((HIWORD(wParam) == EN_CHANGE) && passphrase) { GetDlgItemText(hwnd, 102, passphrase, PASSPHRASE_MAXLEN - 1); passphrase[PASSPHRASE_MAXLEN - 1] = '\0'; } return 0; } return 0; case WM_CLOSE: EndDialog(hwnd, 0); return 0; |
︙ | ︙ | |||
416 417 418 419 420 421 422 423 424 425 | } static int save_ssh1_pubkey(char *filename, struct RSAKey *key) { char *dec1, *dec2; FILE *fp; fp = fopen(filename, "wb"); if (!fp) return 0; | > > < < | 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 | } static int save_ssh1_pubkey(char *filename, struct RSAKey *key) { char *dec1, *dec2; FILE *fp; dec1 = bignum_decimal(key->exponent); dec2 = bignum_decimal(key->modulus); fp = fopen(filename, "wb"); if (!fp) return 0; fprintf(fp, "%d %s %s %s\n", bignum_bitcount(key->modulus), dec1, dec2, key->comment); fclose(fp); sfree(dec1); sfree(dec2); return 1; } |
︙ | ︙ | |||
626 627 628 629 630 631 632 | do_export_menuitem(IDC_EXPORT_SSHCOM, SSH_KEYTYPE_SSHCOM); #undef do_export_menuitem break; } } void load_key_file(HWND hwnd, struct MainDlgState *state, | | | > | < | | > | | | | | < < < < | > | | | | > | > | 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 | do_export_menuitem(IDC_EXPORT_SSHCOM, SSH_KEYTYPE_SSHCOM); #undef do_export_menuitem break; } } void load_key_file(HWND hwnd, struct MainDlgState *state, Filename filename, int was_import_cmd) { char passphrase[PASSPHRASE_MAXLEN]; int needs_pass; int type, realtype; int ret; const char *errmsg = NULL; char *comment; struct PassphraseProcStruct pps; struct RSAKey newkey1; struct ssh2_userkey *newkey2 = NULL; type = realtype = key_type(&filename); if (type != SSH_KEYTYPE_SSH1 && type != SSH_KEYTYPE_SSH2 && !import_possible(type)) { char *msg = dupprintf("Couldn't load private key (%s)", key_type_to_str(type)); message_box(msg, "PuTTYgen Error", MB_OK | MB_ICONERROR, HELPCTXID(errors_cantloadkey)); sfree(msg); return; } if (type != SSH_KEYTYPE_SSH1 && type != SSH_KEYTYPE_SSH2) { realtype = type; type = import_target_type(type); } comment = NULL; if (realtype == SSH_KEYTYPE_SSH1) needs_pass = rsakey_encrypted(&filename, &comment); else if (realtype == SSH_KEYTYPE_SSH2) needs_pass = ssh2_userkey_encrypted(&filename, &comment); else needs_pass = import_encrypted(&filename, realtype, &comment); pps.passphrase = passphrase; pps.comment = comment; do { if (needs_pass) { int dlgret; dlgret = DialogBoxParam(hinst, MAKEINTRESOURCE(210), NULL, PassphraseProc, (LPARAM) &pps); if (!dlgret) { ret = -2; break; } } else *passphrase = '\0'; if (type == SSH_KEYTYPE_SSH1) { if (realtype == type) ret = loadrsakey(&filename, &newkey1, passphrase, &errmsg); else ret = import_ssh1(&filename, realtype, &newkey1, passphrase, &errmsg); } else { if (realtype == type) newkey2 = ssh2_load_userkey(&filename, passphrase, &errmsg); else newkey2 = import_ssh2(&filename, realtype, passphrase, &errmsg); if (newkey2 == SSH2_WRONG_PASSPHRASE) ret = -1; else if (!newkey2) ret = 0; else ret = 1; } |
︙ | ︙ | |||
795 796 797 798 799 800 801 | "use the \"Save private key\" command to\n" "save it in PuTTY's own format.", key_type_to_str(realtype)); MessageBox(NULL, msg, "PuTTYgen Notice", MB_OK | MB_ICONINFORMATION); } } | < | 780 781 782 783 784 785 786 787 788 789 790 791 792 793 | "use the \"Save private key\" command to\n" "save it in PuTTY's own format.", key_type_to_str(realtype)); MessageBox(NULL, msg, "PuTTYgen Notice", MB_OK | MB_ICONINFORMATION); } } } /* * Dialog-box function for the main PuTTYgen dialog box. */ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) |
︙ | ︙ | |||
950 951 952 953 954 955 956 | * anything. */ ui_set_state(hwnd, state, 0); /* * Load a key file if one was provided on the command line. */ | | < | < < | | 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 | * anything. */ ui_set_state(hwnd, state, 0); /* * Load a key file if one was provided on the command line. */ if (cmdline_keyfile) load_key_file(hwnd, state, filename_from_str(cmdline_keyfile), 0); return 1; case WM_MOUSEMOVE: state = (struct MainDlgState *) GetWindowLongPtr(hwnd, GWLP_USERDATA); if (state->collecting_entropy && state->entropy && state->entropy_got < state->entropy_required) { state->entropy[state->entropy_got++] = lParam; state->entropy[state->entropy_got++] = GetMessageTime(); SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, state->entropy_got, 0); if (state->entropy_got >= state->entropy_required) { struct rsa_key_thread_params *params; DWORD threadid; /* * Seed the entropy pool */ random_add_heavynoise(state->entropy, state->entropy_size); memset(state->entropy, 0, state->entropy_size); sfree(state->entropy); state->collecting_entropy = FALSE; SetDlgItemText(hwnd, IDC_GENERATING, generating_msg); SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETRANGE, 0, MAKELPARAM(0, PROGRESSRANGE)); SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, 0, 0); |
︙ | ︙ | |||
1117 1118 1119 1120 1121 1122 1123 | case IDC_EXPORT_SSHCOM: if (HIWORD(wParam) != BN_CLICKED) break; state = (struct MainDlgState *) GetWindowLongPtr(hwnd, GWLP_USERDATA); if (state->key_exists) { char filename[FILENAME_MAX]; | > | | 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 | case IDC_EXPORT_SSHCOM: if (HIWORD(wParam) != BN_CLICKED) break; state = (struct MainDlgState *) GetWindowLongPtr(hwnd, GWLP_USERDATA); if (state->key_exists) { char filename[FILENAME_MAX]; char passphrase[PASSPHRASE_MAXLEN]; char passphrase2[PASSPHRASE_MAXLEN]; int type, realtype; if (state->ssh2) realtype = SSH_KEYTYPE_SSH2; else realtype = SSH_KEYTYPE_SSH1; |
︙ | ︙ | |||
1143 1144 1145 1146 1147 1148 1149 | " format", (state->ssh2 ? 2 : 1), (state->ssh2 ? 1 : 2)); MessageBox(hwnd, msg, "PuTTYgen Error", MB_OK | MB_ICONERROR); break; } | | > | > < < < | < | < | < < | | | < | | | < < | 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 | " format", (state->ssh2 ? 2 : 1), (state->ssh2 ? 1 : 2)); MessageBox(hwnd, msg, "PuTTYgen Error", MB_OK | MB_ICONERROR); break; } GetDlgItemText(hwnd, IDC_PASSPHRASE1EDIT, passphrase, sizeof(passphrase)); GetDlgItemText(hwnd, IDC_PASSPHRASE2EDIT, passphrase2, sizeof(passphrase2)); if (strcmp(passphrase, passphrase2)) { MessageBox(hwnd, "The two passphrases given do not match.", "PuTTYgen Error", MB_OK | MB_ICONERROR); break; } if (!*passphrase) { int ret; ret = MessageBox(hwnd, "Are you sure you want to save this key\n" "without a passphrase to protect it?", "PuTTYgen Warning", MB_YESNO | MB_ICONWARNING); if (ret != IDYES) break; } if (prompt_keyfile(hwnd, "Save private key as:", filename, 1, (type == realtype))) { int ret; FILE *fp = fopen(filename, "r"); if (fp) { char *buffer; fclose(fp); buffer = dupprintf("Overwrite existing file\n%s?", filename); ret = MessageBox(hwnd, buffer, "PuTTYgen Warning", MB_YESNO | MB_ICONWARNING); sfree(buffer); if (ret != IDYES) break; } if (state->ssh2) { Filename fn = filename_from_str(filename); if (type != realtype) ret = export_ssh2(&fn, type, &state->ssh2key, *passphrase ? passphrase : NULL); else ret = ssh2_save_userkey(&fn, &state->ssh2key, *passphrase ? passphrase : NULL); } else { Filename fn = filename_from_str(filename); if (type != realtype) ret = export_ssh1(&fn, type, &state->key, *passphrase ? passphrase : NULL); else ret = saversakey(&fn, &state->key, *passphrase ? passphrase : NULL); } if (ret <= 0) { MessageBox(hwnd, "Unable to save key file", "PuTTYgen Error", MB_OK | MB_ICONERROR); } } } break; case IDC_SAVEPUB: if (HIWORD(wParam) != BN_CLICKED) break; state = (struct MainDlgState *) GetWindowLongPtr(hwnd, GWLP_USERDATA); |
︙ | ︙ | |||
1255 1256 1257 1258 1259 1260 1261 | if (HIWORD(wParam) != BN_CLICKED) break; state = (struct MainDlgState *) GetWindowLongPtr(hwnd, GWLP_USERDATA); if (!state->generation_thread_exists) { char filename[FILENAME_MAX]; if (prompt_keyfile(hwnd, "Load private key:", | | | | < < | 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 | if (HIWORD(wParam) != BN_CLICKED) break; state = (struct MainDlgState *) GetWindowLongPtr(hwnd, GWLP_USERDATA); if (!state->generation_thread_exists) { char filename[FILENAME_MAX]; if (prompt_keyfile(hwnd, "Load private key:", filename, 0, LOWORD(wParam)==IDC_LOAD)) load_key_file(hwnd, state, filename_from_str(filename), LOWORD(wParam) != IDC_LOAD); } break; } return 0; case WM_DONEKEY: state = (struct MainDlgState *) GetWindowLongPtr(hwnd, GWLP_USERDATA); state->generation_thread_exists = FALSE; |
︙ | ︙ |
Changes to windows/winpgnt.c.
︙ | ︙ | |||
10 11 12 13 14 15 16 | #define PUTTY_DO_GLOBALS #include "putty.h" #include "ssh.h" #include "misc.h" #include "tree234.h" | > > > > > > | > > > | > > > > > | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | #define PUTTY_DO_GLOBALS #include "putty.h" #include "ssh.h" #include "misc.h" #include "tree234.h" #include <shellapi.h> /* PuTTY SC start */ #include <windows.h> #include "storage.h" #include "sc.h" /* PuTTY SC end */ /* PuTTY CAPI start */ #ifdef _WINDOWS #include <specstrings.h> #include <Wincrypt.h> #include <CryptDlg.h> #include "capi.h" #endif /* PuTTY CAPI end */ #ifndef NO_SECURITY #include <aclapi.h> #ifdef DEBUG_IPC #define _WIN32_WINNT 0x0500 /* for ConvertSidToStringSid */ #include <sddl.h> #endif |
︙ | ︙ | |||
110 111 112 113 114 115 116 | return; } } *out = '\0'; return; } | | > > > > > > | 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | return; } } *out = '\0'; return; } static tree234 *rsakeys, *ssh2keys, *capikeys; static int has_security; #ifndef NO_SECURITY DECL_WINDOWS_FUNCTION(extern, DWORD, GetSecurityInfo, (HANDLE, SE_OBJECT_TYPE, SECURITY_INFORMATION, PSID *, PSID *, PACL *, PACL *, PSECURITY_DESCRIPTOR *)); #endif /* * Forward references */ static void *make_keylist1(int *length); static void *make_keylist2(int *length); static void *get_keylist1(int *length); |
︙ | ︙ | |||
150 151 152 153 154 155 156 157 | */ struct blob { unsigned char *blob; int len; }; static int cmpkeys_ssh2_asymm(void *av, void *bv); struct PassphraseProcStruct { | > > | | | 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 | */ struct blob { unsigned char *blob; int len; }; static int cmpkeys_ssh2_asymm(void *av, void *bv); #define PASSPHRASE_MAXLEN 512 struct PassphraseProcStruct { char *passphrase; char *comment; }; static tree234 *passphrases = NULL; /* * After processing a list of filenames, we want to forget the * passphrases. */ static void forget_passphrases(void) { while (count234(passphrases) > 0) { char *pp = index234(passphrases, 0); memset(pp, 0, strlen(pp)); delpos234(passphrases, 0); free(pp); } } /* * Dialog-box function for the Licence box. |
︙ | ︙ | |||
230 231 232 233 234 235 236 | return 0; } return 0; } static HWND passphrase_box; | > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 | return 0; } return 0; } static HWND passphrase_box; /* PuTTY SC start */ sc_lib *sclib = NULL; char pkcs11_token_label[70]; char pkcs11_cert_label[70]; char sc_save_passphrase[PASSPHRASE_MAXLEN]; int sc_activate_pwd_cache = 0; void logevent(void *f, const char *msg) { } static int CALLBACK sc_PassphraseProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { static char *passphrase = NULL; struct PassphraseProcStruct *p; switch (msg) { case WM_INITDIALOG: passphrase_box = hwnd; /* * Centre the window. */ { /* centre the window */ RECT rs, rd; HWND hw; hw = GetDesktopWindow(); if (GetWindowRect(hw, &rs) && GetWindowRect(hwnd, &rd)) MoveWindow(hwnd, (rs.right + rs.left + rd.left - rd.right) / 2, (rs.bottom + rs.top + rd.top - rd.bottom) / 2, rd.right - rd.left, rd.bottom - rd.top, TRUE); } SetForegroundWindow(hwnd); SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); p = (struct PassphraseProcStruct *) lParam; passphrase = p->passphrase; if (p->comment) SetDlgItemText(hwnd, 101, p->comment); *passphrase = 0; SetDlgItemText(hwnd, 102, passphrase); return 0; case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: if (*passphrase) EndDialog(hwnd, 1); else MessageBeep(0); return 0; case IDCANCEL: sc_activate_pwd_cache = 1; EndDialog(hwnd, 0); return 0; case 102: /* edit box */ if ((HIWORD(wParam) == EN_CHANGE) && passphrase) { GetDlgItemText(hwnd, 102, passphrase, PASSPHRASE_MAXLEN - 1); passphrase[PASSPHRASE_MAXLEN - 1] = '\0'; } return 0; } return 0; case WM_CLOSE: EndDialog(hwnd, 0); return 0; } return 0; } /* PuTTY SC end */ /* * Dialog-box function for the passphrase box. */ static int CALLBACK PassphraseProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { static char *passphrase = NULL; struct PassphraseProcStruct *p; switch (msg) { case WM_INITDIALOG: passphrase_box = hwnd; /* * Centre the window. |
︙ | ︙ | |||
264 265 266 267 268 269 270 | SetForegroundWindow(hwnd); SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); p = (struct PassphraseProcStruct *) lParam; passphrase = p->passphrase; if (p->comment) SetDlgItemText(hwnd, 101, p->comment); | < | | | > | | 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 | SetForegroundWindow(hwnd); SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); p = (struct PassphraseProcStruct *) lParam; passphrase = p->passphrase; if (p->comment) SetDlgItemText(hwnd, 101, p->comment); *passphrase = 0; SetDlgItemText(hwnd, 102, passphrase); return 0; case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: if (*passphrase) EndDialog(hwnd, 1); else MessageBeep(0); return 0; case IDCANCEL: EndDialog(hwnd, 0); return 0; case 102: /* edit box */ if ((HIWORD(wParam) == EN_CHANGE) && passphrase) { GetDlgItemText(hwnd, 102, passphrase, PASSPHRASE_MAXLEN - 1); passphrase[PASSPHRASE_MAXLEN - 1] = '\0'; } return 0; } return 0; case WM_CLOSE: EndDialog(hwnd, 0); return 0; |
︙ | ︙ | |||
322 323 324 325 326 327 328 329 330 331 332 333 334 335 | * Update the visible key list. */ static void keylist_update(void) { struct RSAKey *rkey; struct ssh2_userkey *skey; int i; if (keylist) { SendDlgItemMessage(keylist, 100, LB_RESETCONTENT, 0, 0); for (i = 0; NULL != (rkey = index234(rsakeys, i)); i++) { char listentry[512], *p; /* * Replace two spaces in the fingerprint with tabs, for | > > > | 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 | * Update the visible key list. */ static void keylist_update(void) { struct RSAKey *rkey; struct ssh2_userkey *skey; int i; /* PuTTY CAPI start */ struct CAPI_userkey *ckey; /* PuTTY CAPI end */ if (keylist) { SendDlgItemMessage(keylist, 100, LB_RESETCONTENT, 0, 0); for (i = 0; NULL != (rkey = index234(rsakeys, i)); i++) { char listentry[512], *p; /* * Replace two spaces in the fingerprint with tabs, for |
︙ | ︙ | |||
344 345 346 347 348 349 350 | p = strchr(listentry, ' '); if (p) *p = '\t'; SendDlgItemMessage(keylist, 100, LB_ADDSTRING, 0, (LPARAM) listentry); } for (i = 0; NULL != (skey = index234(ssh2keys, i)); i++) { | | | < < < | | | > > > > > | > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > | > > > > > > > > > > > > > > | > > > | > > > > > > | > > > > > > > > > > > > | < < < < < | 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 | p = strchr(listentry, ' '); if (p) *p = '\t'; SendDlgItemMessage(keylist, 100, LB_ADDSTRING, 0, (LPARAM) listentry); } for (i = 0; NULL != (skey = index234(ssh2keys, i)); i++) { char listentry[512], *p; int len; /* * Replace two spaces in the fingerprint with tabs, for * nice alignment in the box. */ p = skey->alg->fingerprint(skey->data); strncpy(listentry, p, sizeof(listentry)); p = strchr(listentry, ' '); if (p) *p = '\t'; p = strchr(listentry, ' '); if (p) *p = '\t'; len = strlen(listentry); if (len < sizeof(listentry) - 2) { listentry[len] = '\t'; strncpy(listentry + len + 1, skey->comment, sizeof(listentry) - len - 1); } SendDlgItemMessage(keylist, 100, LB_ADDSTRING, 0, (LPARAM) listentry); } /* PuTTY CAPI start */ for (i = 0; NULL != (ckey = index234(capikeys, i)); i++) { char listentry[512]; memset(listentry, 0, sizeof(listentry)); _snprintf(listentry, sizeof(listentry)-1, "CAPI\t%s", ckey->certID); SendDlgItemMessage(keylist, 100, LB_ADDSTRING, 0, (LPARAM) listentry); } /* PuTTY CAPI end */ SendDlgItemMessage(keylist, 100, LB_SETCURSEL, (WPARAM) - 1, 0); } } /* PuTTY CAPI start */ typedef BOOL (WINAPI *PCertSelectCertificateA)( __inout PCERT_SELECT_STRUCT_A pCertSelectInfo ); static void prompt_add_CAPIkey(HWND hwnd) { HCERTSTORE hStore = NULL; CERT_SELECT_STRUCT_A* css = NULL; CERT_CONTEXT** acc = NULL; unsigned int tmpSHA1size = 0, dwCertStoreUser; unsigned char tmpSHA1[20]; char tmpSHA1hex[41] = ""; char tmpCertID[100] = ""; char* tmpCertID_alloced = NULL; HMODULE hCertDlgDLL = NULL; PCertSelectCertificateA f_csca = NULL; int i = 0; // TODO: Let the user choose this struct CAPI_userkey* ckey = NULL; if ((hCertDlgDLL = LoadLibrary("CryptDlg.dll")) == NULL) goto cleanup; if ((f_csca = (PCertSelectCertificateA) GetProcAddress(hCertDlgDLL, "CertSelectCertificateA")) == NULL) goto cleanup; dwCertStoreUser = CERT_SYSTEM_STORE_CURRENT_USER; if (i == 1) dwCertStoreUser = CERT_SYSTEM_STORE_LOCAL_MACHINE; if ((hStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, 0 /*hCryptProv*/, dwCertStoreUser | CERT_STORE_READONLY_FLAG | CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_ENUM_ARCHIVED_FLAG, "MY")) == NULL) goto cleanup; acc = (CERT_CONTEXT**) malloc(sizeof(CERT_CONTEXT*)); acc[0] = NULL; css = (CERT_SELECT_STRUCT_A*) malloc(sizeof(CERT_SELECT_STRUCT_A)); memset(css, 0, sizeof(CERT_SELECT_STRUCT_A)); css->dwSize = sizeof(CERT_SELECT_STRUCT_A); css->hwndParent = hwnd; css->hInstance = NULL; css->pTemplateName = NULL; css->dwFlags = 0; css->szTitle = "PuTTY: Select Certificate for CAPI Auth"; css->cCertStore = 1; css->arrayCertStore = &hStore; css->szPurposeOid = szOID_PKIX_KP_CLIENT_AUTH; css->cCertContext = 1; // count of arrayCertContext indexes allocated css->arrayCertContext = acc; if (!f_csca(css)) // GetProcAddress(hCertDlgDLL, "CertSelectCertificateA") goto cleanup; if (css->cCertContext != 1) goto cleanup; if (acc[0] == NULL) goto cleanup; tmpSHA1size = sizeof(tmpSHA1); if (!CertGetCertificateContextProperty(acc[0], CERT_HASH_PROP_ID, tmpSHA1, &tmpSHA1size)) memset(tmpSHA1, 0, sizeof(tmpSHA1)); _snprintf(tmpSHA1hex, sizeof(tmpSHA1hex)-1, "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", tmpSHA1[0], tmpSHA1[1], tmpSHA1[2], tmpSHA1[3], tmpSHA1[4], tmpSHA1[5], tmpSHA1[6], tmpSHA1[7], tmpSHA1[8], tmpSHA1[9], tmpSHA1[10], tmpSHA1[11], tmpSHA1[12], tmpSHA1[13], tmpSHA1[14], tmpSHA1[15], tmpSHA1[16], tmpSHA1[17], tmpSHA1[18], tmpSHA1[19]); tmpSHA1hex[sizeof(tmpSHA1hex)-1] = '\0'; _snprintf(tmpCertID, sizeof(tmpCertID)-1, "%s\\%s", i == 1 ? "Machine\\MY" : "User\\MY", tmpSHA1hex); tmpCertID[sizeof(tmpCertID)-1] = '\0'; if ((ckey = Create_CAPI_userkey(tmpCertID, acc[0])) == NULL) goto cleanup; if (add234(capikeys, ckey) != ckey) Free_CAPI_userkey(ckey); keylist_update(); cleanup: if (hCertDlgDLL) { FreeLibrary(hCertDlgDLL); f_csca = NULL; hCertDlgDLL = NULL; } if (acc) { if (acc[0]) CertFreeCertificateContext(acc[0]); acc[0] = NULL; free(acc); acc = NULL; } if (css) free(css); css = NULL; if (hStore) CertCloseStore(hStore, 0); hStore = NULL; return; } // Key comparison function for the 2-3-4 tree of CAPI keys (struct CAPI_userkey). int cmpkeys_capi(void *av, void *bv) { struct CAPI_userkey *a, *b; a = (struct CAPI_userkey *) av; b = (struct CAPI_userkey *) bv; return strcmp(a->certID, b->certID); } // Key comparison function for the 2-3-4 tree of CAPI keys (struct CAPI_userkey) where the first argument is a blob. static int cmpkeys_capi_blob(void *av, void *bv) { struct blob *a = (struct blob *) av; struct CAPI_userkey *b = (struct CAPI_userkey *) bv; int i; int c; // Compare purely by public blob. c = 0; for (i = 0; i < a->len && i < b->bloblen; i++) { if (a->blob[i] < b->blob[i]) { c = -1; break; } else if (a->blob[i] > b->blob[i]) { c = +1; break; } } if (c == 0 && i < a->len) c = +1; /* a is longer */ if (c == 0 && i < b->bloblen) c = -1; /* b is longer */ return c; } /* PuTTY CAPI end */ /* * This function loads a key from a file and adds it. */ static void add_keyfile(Filename filename) { char passphrase[PASSPHRASE_MAXLEN]; struct RSAKey *rkey = NULL; struct ssh2_userkey *skey = NULL; int needs_pass; int ret; int attempts; char *comment; const char *error = NULL; struct PassphraseProcStruct pps; int type; int original_pass; /* PuTTY CAPI start */ BOOL CAPI_KEY = FALSE; struct CAPI_userkey *ckey = NULL; if (strnicmp(filename_to_str(&filename), "CAPI:", 5) == 0) { const char *fn = filename_to_str(&filename); const char *certID = &fn[5]; CAPI_KEY = TRUE; type = SSH_KEYTYPE_SSH2; if ((ckey = Create_CAPI_userkey(certID, NULL)) == NULL) { char *msg = dupprintf("Couldn't load CAPI certificate/key: %s", certID); message_box(msg, APPNAME, MB_OK | MB_ICONERROR, HELPCTXID(errors_cantloadkey)); sfree(msg); return; } } else { /* PuTTY CAPI end */ type = key_type(&filename); if (type != SSH_KEYTYPE_SSH1 && type != SSH_KEYTYPE_SSH2) { char *msg = dupprintf("Couldn't load this key (%s)", key_type_to_str(type)); message_box(msg, APPNAME, MB_OK | MB_ICONERROR, HELPCTXID(errors_cantloadkey)); sfree(msg); return; } /* PuTTY CAPI start */ } /* PuTTY CAPI end */ /* * See if the key is already loaded (in the primary Pageant, * which may or may not be us). */ { void *blob; unsigned char *keylist, *p; int i, nkeys, bloblen, keylistlen; if (type == SSH_KEYTYPE_SSH1) { if (!rsakey_pubblob(&filename, &blob, &bloblen, NULL, &error)) { char *msg = dupprintf("Couldn't load private key (%s)", error); message_box(msg, APPNAME, MB_OK | MB_ICONERROR, HELPCTXID(errors_cantloadkey)); sfree(msg); return; } keylist = get_keylist1(&keylistlen); } else { unsigned char *blob2; /* PuTTY CAPI start */ if (CAPI_KEY) { bloblen = ckey->bloblen; } else { /* PuTTY CAPI end */ blob = ssh2_userkey_loadpub(&filename, NULL, &bloblen, NULL, &error); if (!blob) { char *msg = dupprintf("Couldn't load private key (%s)", error); message_box(msg, APPNAME, MB_OK | MB_ICONERROR, HELPCTXID(errors_cantloadkey)); sfree(msg); return; } /* PuTTY CAPI start */ } /* PuTTY CAPI end */ /* For our purposes we want the blob prefixed with its length */ blob2 = snewn(bloblen+4, unsigned char); PUT_32BIT(blob2, bloblen); /* PuTTY CAPI start */ if (CAPI_KEY) { memcpy(blob2 + 4, ckey->blob, ckey->bloblen); } else { /* PuTTY CAPI end */ memcpy(blob2 + 4, blob, bloblen); sfree(blob); /* PuTTY CAPI start */ } /* PuTTY CAPI end */ blob = blob2; keylist = get_keylist2(&keylistlen); } if (keylist) { if (keylistlen < 4) { MessageBox(NULL, "Received broken key list?!", APPNAME, MB_OK | MB_ICONERROR); return; } nkeys = GET_32BIT(keylist); p = keylist + 4; keylistlen -= 4; for (i = 0; i < nkeys; i++) { if (!memcmp(blob, p, bloblen)) { /* Key is already present; we can now leave. */ sfree(keylist); |
︙ | ︙ | |||
473 474 475 476 477 478 479 | } else { int n; if (keylistlen < 4) { MessageBox(NULL, "Received broken key list?!", APPNAME, MB_OK | MB_ICONERROR); return; } | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | > < < < | < < < < < | < < | < | | > | | < < < < | 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 | } else { int n; if (keylistlen < 4) { MessageBox(NULL, "Received broken key list?!", APPNAME, MB_OK | MB_ICONERROR); return; } n = 4 + GET_32BIT(p); if (keylistlen < n) { MessageBox(NULL, "Received broken key list?!", APPNAME, MB_OK | MB_ICONERROR); return; } p += n; keylistlen -= n; } /* Now skip over comment field */ { int n; if (keylistlen < 4) { MessageBox(NULL, "Received broken key list?!", APPNAME, MB_OK | MB_ICONERROR); return; } n = 4 + GET_32BIT(p); if (keylistlen < n) { MessageBox(NULL, "Received broken key list?!", APPNAME, MB_OK | MB_ICONERROR); return; } p += n; keylistlen -= n; } } sfree(keylist); } sfree(blob); } /* PuTTY CAPI start */ // if we've reached this far, the key is not already loaded.... if (CAPI_KEY) { if (already_running) { // need to comm with the main pageant... unsigned char *request, *response, *p; int reqlen, resplen, ret; reqlen = 4 + 1 + // length, message type 4 + 4 + // length, "CAPI" 4 + strlen(ckey->certID); // length + certID string p = request = snewn(reqlen, unsigned char); PUT_32BIT(p, reqlen - 4); p[4] = SSH2_AGENTC_ADD_IDENTITY; p += 5; PUT_32BIT(p, 4); p += 4; memcpy(p, "CAPI", 4); p += 4; PUT_32BIT(p, strlen(ckey->certID)); p += 4; memcpy(p, ckey->certID, strlen(ckey->certID)); p += strlen(ckey->certID); ret = agent_query(request, reqlen, &response, &resplen, NULL, NULL); assert(ret == 1); if (resplen < 5 || response[4] != SSH_AGENT_SUCCESS) MessageBox(NULL, "The already running Pageant refused to add the capi cert/key.", APPNAME, MB_OK | MB_ICONERROR); sfree(request); sfree(response); } else { // we are the main pageant if (add234(capikeys, ckey) != ckey) { Free_CAPI_userkey(ckey); /* already present, don't waste RAM */ } } return; } /* PuTTY CAPI end */ error = NULL; if (type == SSH_KEYTYPE_SSH1) needs_pass = rsakey_encrypted(&filename, &comment); else needs_pass = ssh2_userkey_encrypted(&filename, &comment); attempts = 0; if (type == SSH_KEYTYPE_SSH1) rkey = snew(struct RSAKey); pps.passphrase = passphrase; pps.comment = comment; original_pass = 0; do { if (needs_pass) { /* try all the remembered passphrases first */ char *pp = index234(passphrases, attempts); if(pp) { strcpy(passphrase, pp); } else { int dlgret; original_pass = 1; dlgret = DialogBoxParam(hinst, MAKEINTRESOURCE(210), NULL, PassphraseProc, (LPARAM) &pps); passphrase_box = NULL; if (!dlgret) { if (comment) sfree(comment); if (type == SSH_KEYTYPE_SSH1) sfree(rkey); return; /* operation cancelled */ } } } else *passphrase = '\0'; if (type == SSH_KEYTYPE_SSH1) ret = loadrsakey(&filename, rkey, passphrase, &error); else { skey = ssh2_load_userkey(&filename, passphrase, &error); if (skey == SSH2_WRONG_PASSPHRASE) ret = -1; else if (!skey) ret = 0; else ret = 1; } attempts++; } while (ret == -1); /* if they typed in an ok passphrase, remember it */ if(original_pass && ret) { char *pp = dupstr(passphrase); addpos234(passphrases, pp, 0); } if (comment) sfree(comment); if (ret == 0) { char *msg = dupprintf("Couldn't load private key (%s)", error); message_box(msg, APPNAME, MB_OK | MB_ICONERROR, HELPCTXID(errors_cantloadkey)); |
︙ | ︙ | |||
738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 | /* * Create an SSH-2 key list in a malloc'ed buffer; return its * length. */ static void *make_keylist2(int *length) { struct ssh2_userkey *key; int i, len, nkeys; unsigned char *blob, *p, *ret; int bloblen; /* * Count up the number and length of keys we hold. */ len = 4; nkeys = 0; for (i = 0; NULL != (key = index234(ssh2keys, i)); i++) { nkeys++; len += 4; /* length field */ blob = key->alg->public_blob(key->data, &bloblen); len += bloblen; sfree(blob); len += 4 + strlen(key->comment); } /* Allocate the buffer. */ p = ret = snewn(len, unsigned char); if (length) *length = len; /* * Packet header is the obvious five bytes, plus four | > > > > > > > > > > > > > | 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 | /* * Create an SSH-2 key list in a malloc'ed buffer; return its * length. */ static void *make_keylist2(int *length) { /* PuTTY CAPI start */ struct CAPI_userkey *ckey; char *comment; /* PuTTY CAPI end */ struct ssh2_userkey *key; int i, len, nkeys; unsigned char *blob, *p, *ret; int bloblen; /* * Count up the number and length of keys we hold. */ len = 4; nkeys = 0; for (i = 0; NULL != (key = index234(ssh2keys, i)); i++) { nkeys++; len += 4; /* length field */ blob = key->alg->public_blob(key->data, &bloblen); len += bloblen; sfree(blob); len += 4 + strlen(key->comment); } /* PuTTY CAPI start */ for (i = 0; NULL != (ckey = index234(capikeys, i)); i++) { nkeys++; len += 4; /* length field */ len += ckey->bloblen; len += 4 + CAPI_userkey_Comment_Length(ckey); } /* PuTTY CAPI end */ /* Allocate the buffer. */ p = ret = snewn(len, unsigned char); if (length) *length = len; /* * Packet header is the obvious five bytes, plus four |
︙ | ︙ | |||
778 779 780 781 782 783 784 785 786 787 788 789 790 791 | memcpy(p, blob, bloblen); p += bloblen; sfree(blob); PUT_32BIT(p, strlen(key->comment)); memcpy(p + 4, key->comment, strlen(key->comment)); p += 4 + strlen(key->comment); } assert(p - ret == len); return ret; } /* * Acquire a keylist1 from the primary Pageant; this means either | > > > > > > > > > > > > > | 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 | memcpy(p, blob, bloblen); p += bloblen; sfree(blob); PUT_32BIT(p, strlen(key->comment)); memcpy(p + 4, key->comment, strlen(key->comment)); p += 4 + strlen(key->comment); } /* PuTTY CAPI start */ for (i = 0; NULL != (ckey = index234(capikeys, i)); i++) { PUT_32BIT(p, ckey->bloblen); p += 4; memcpy(p, ckey->blob, ckey->bloblen); p += ckey->bloblen; comment = CAPI_userkey_GetComment(ckey); PUT_32BIT(p, strlen(comment)); memcpy(p + 4, comment, strlen(comment)); p += 4 + strlen(comment); free(comment); } /* PuTTY CAPI end */ assert(p - ret == len); return ret; } /* * Acquire a keylist1 from the primary Pageant; this means either |
︙ | ︙ | |||
802 803 804 805 806 807 808 | int resplen, retval; request[4] = SSH1_AGENTC_REQUEST_RSA_IDENTITIES; PUT_32BIT(request, 4); retval = agent_query(request, 5, &vresponse, &resplen, NULL, NULL); assert(retval == 1); response = vresponse; | | < < | 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 | int resplen, retval; request[4] = SSH1_AGENTC_REQUEST_RSA_IDENTITIES; PUT_32BIT(request, 4); retval = agent_query(request, 5, &vresponse, &resplen, NULL, NULL); assert(retval == 1); response = vresponse; if (resplen < 5 || response[4] != SSH1_AGENT_RSA_IDENTITIES_ANSWER) return NULL; ret = snewn(resplen-5, unsigned char); memcpy(ret, response+5, resplen-5); sfree(response); if (length) *length = resplen-5; |
︙ | ︙ | |||
839 840 841 842 843 844 845 | request[4] = SSH2_AGENTC_REQUEST_IDENTITIES; PUT_32BIT(request, 4); retval = agent_query(request, 5, &vresponse, &resplen, NULL, NULL); assert(retval == 1); response = vresponse; | | < < | 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 | request[4] = SSH2_AGENTC_REQUEST_IDENTITIES; PUT_32BIT(request, 4); retval = agent_query(request, 5, &vresponse, &resplen, NULL, NULL); assert(retval == 1); response = vresponse; if (resplen < 5 || response[4] != SSH2_AGENT_IDENTITIES_ANSWER) return NULL; ret = snewn(resplen-5, unsigned char); memcpy(ret, response+5, resplen-5); sfree(response); if (length) *length = resplen-5; |
︙ | ︙ | |||
937 938 939 940 941 942 943 | p += 4; i = ssh1_read_bignum(p, msgend - p, &reqkey.exponent); if (i < 0) goto failure; p += i; i = ssh1_read_bignum(p, msgend - p, &reqkey.modulus); | | < < | < < < | 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 | p += 4; i = ssh1_read_bignum(p, msgend - p, &reqkey.exponent); if (i < 0) goto failure; p += i; i = ssh1_read_bignum(p, msgend - p, &reqkey.modulus); if (i < 0) goto failure; p += i; i = ssh1_read_bignum(p, msgend - p, &challenge); if (i < 0) goto failure; p += i; if (msgend < p+16) { freebn(reqkey.exponent); freebn(reqkey.modulus); freebn(challenge); goto failure; } |
︙ | ︙ | |||
972 973 974 975 976 977 978 | response = rsadecrypt(challenge, key); for (i = 0; i < 32; i++) response_source[i] = bignum_byte(response, 31 - i); MD5Init(&md5c); MD5Update(&md5c, response_source, 48); MD5Final(response_md5, &md5c); | | | 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 | response = rsadecrypt(challenge, key); for (i = 0; i < 32; i++) response_source[i] = bignum_byte(response, 31 - i); MD5Init(&md5c); MD5Update(&md5c, response_source, 48); MD5Final(response_md5, &md5c); memset(response_source, 0, 48); /* burn the evidence */ freebn(response); /* and that evidence */ freebn(challenge); /* yes, and that evidence */ freebn(reqkey.exponent); /* and free some memory ... */ freebn(reqkey.modulus); /* ... while we're at it. */ /* * Packet is the obvious five byte header, plus sixteen |
︙ | ︙ | |||
995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 | case SSH2_AGENTC_SIGN_REQUEST: /* * Reply with either SSH2_AGENT_SIGN_RESPONSE or * SSH_AGENT_FAILURE, depending on whether we have that key * or not. */ { struct ssh2_userkey *key; struct blob b; unsigned char *data, *signature; int datalen, siglen, len; if (msgend < p+4) goto failure; | > > > | > | | < | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 | case SSH2_AGENTC_SIGN_REQUEST: /* * Reply with either SSH2_AGENT_SIGN_RESPONSE or * SSH_AGENT_FAILURE, depending on whether we have that key * or not. */ { /* PuTTY CAPI start */ struct CAPI_userkey *ckey; /* PuTTY CAPI end */ struct ssh2_userkey *key; struct blob b; unsigned char *data, *signature; int datalen, siglen, len; if (msgend < p+4) goto failure; b.len = GET_32BIT(p); p += 4; if (msgend < p+b.len) goto failure; b.blob = p; p += b.len; if (msgend < p+4) goto failure; datalen = GET_32BIT(p); p += 4; if (msgend < p+datalen) goto failure; data = p; /* PuTTY CAPI start */ ckey = find234(capikeys, &b, cmpkeys_capi_blob); if (ckey) { if ((signature = capi_sig_certID(ckey->certID, data, datalen, &siglen)) == NULL) goto failure; } else { /* PuTTY CAPI end */ key = find234(ssh2keys, &b, cmpkeys_ssh2_asymm); if (!key) goto failure; /* PuTTY SC start */ if((sclib != NULL) && (strcmp(key->comment, pkcs11_cert_label) == 0)) { char passphrase[PASSPHRASE_MAXLEN]; struct PassphraseProcStruct pps1; pps1.passphrase = passphrase; pps1.comment = key->comment; if(strlen(sc_save_passphrase) == 0) { /* password not in cache */ sc_activate_pwd_cache = 0; DialogBoxParam(hinst, MAKEINTRESOURCE(215), NULL, sc_PassphraseProc, (LPARAM) &pps1); } else { /* re-use existing pwd */ strcpy(pps1.passphrase, sc_save_passphrase); } signature = sc_sig(NULL, 0, sclib, pkcs11_token_label, pps1.passphrase, data, datalen, &siglen); if(siglen > 1 && sc_activate_pwd_cache) { /* store password in cache (if requested and valid) */ strcpy(sc_save_passphrase, pps1.passphrase); } memset(pps1.passphrase, 0, PASSPHRASE_MAXLEN); } else /* PuTTY SC end */ signature = key->alg->sign(key->data, data, datalen, &siglen); /* PuTTY CAPI start */ } /* PuTTY CAPI end */ len = 5 + 4 + siglen; PUT_32BIT(ret, len - 4); ret[4] = SSH2_AGENT_SIGN_RESPONSE; PUT_32BIT(ret + 5, siglen); memcpy(ret + 5 + 4, signature, siglen); sfree(signature); } |
︙ | ︙ | |||
1085 1086 1087 1088 1089 1090 1091 | p += n; if (msgend < p+4) { freersakey(key); sfree(key); goto failure; } | | | | 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 | p += n; if (msgend < p+4) { freersakey(key); sfree(key); goto failure; } commentlen = GET_32BIT(p); if (msgend < p+commentlen) { freersakey(key); sfree(key); goto failure; } comment = snewn(commentlen+1, char); if (comment) { |
︙ | ︙ | |||
1124 1125 1126 1127 1128 1129 1130 | char *comment, *alg; int alglen, commlen; int bloblen; if (msgend < p+4) goto failure; | | | > > > > > > > > > > > > > > > > > > > > > > > > > > | 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 | char *comment, *alg; int alglen, commlen; int bloblen; if (msgend < p+4) goto failure; alglen = GET_32BIT(p); p += 4; if (msgend < p+alglen) goto failure; alg = p; p += alglen; /* PuTTY CAPI start */ if (alglen == 4 && memcmp(alg, "CAPI", 4) == 0) { struct CAPI_userkey *ckey; char *certID; int certIDlen; if (msgend < p+4) goto failure; certIDlen = GET_32BIT(p); p += 4; if (msgend < p+certIDlen) goto failure; certID = p; if ((ckey = Create_CAPI_userkey(certID, NULL)) == NULL) goto failure; if (add234(capikeys, ckey) != ckey) Free_CAPI_userkey(ckey); // already loaded, free our (unused) copy PUT_32BIT(ret, 1); ret[4] = SSH_AGENT_SUCCESS; keylist_update(); break; } /* PuTTY CAPI end */ key = snew(struct ssh2_userkey); /* Add further algorithm names here. */ if (alglen == 7 && !memcmp(alg, "ssh-rsa", 7)) key->alg = &ssh_rsa; else if (alglen == 7 && !memcmp(alg, "ssh-dss", 7)) key->alg = &ssh_dss; else { |
︙ | ︙ | |||
1160 1161 1162 1163 1164 1165 1166 | assert(p <= msgend); if (msgend < p+4) { key->alg->freekey(key->data); sfree(key); goto failure; } | | | | 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 | assert(p <= msgend); if (msgend < p+4) { key->alg->freekey(key->data); sfree(key); goto failure; } commlen = GET_32BIT(p); p += 4; if (msgend < p+commlen) { key->alg->freekey(key->data); sfree(key); goto failure; } comment = snewn(commlen + 1, char); if (comment) { memcpy(comment, p, commlen); |
︙ | ︙ | |||
1227 1228 1229 1230 1231 1232 1233 | */ { struct ssh2_userkey *key; struct blob b; if (msgend < p+4) goto failure; | | | | 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 | */ { struct ssh2_userkey *key; struct blob b; if (msgend < p+4) goto failure; b.len = GET_32BIT(p); p += 4; if (msgend < p+b.len) goto failure; b.blob = p; p += b.len; key = find234(ssh2keys, &b, cmpkeys_ssh2_asymm); if (!key) goto failure; |
︙ | ︙ | |||
1437 1438 1439 1440 1441 1442 1443 | of.lpstrFile = filelist; *filelist = '\0'; of.nMaxFile = 8192; of.lpstrFileTitle = NULL; of.lpstrTitle = "Select Private Key File"; of.Flags = OFN_ALLOWMULTISELECT | OFN_EXPLORER; if (request_file(keypath, &of, TRUE, FALSE)) { | | < | < | < | < > > > | 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 | of.lpstrFile = filelist; *filelist = '\0'; of.nMaxFile = 8192; of.lpstrFileTitle = NULL; of.lpstrTitle = "Select Private Key File"; of.Flags = OFN_ALLOWMULTISELECT | OFN_EXPLORER; if (request_file(keypath, &of, TRUE, FALSE)) { if(strlen(filelist) > of.nFileOffset) /* Only one filename returned? */ add_keyfile(filename_from_str(filelist)); else { /* we are returned a bunch of strings, end to * end. first string is the directory, the * rest the filenames. terminated with an * empty string. */ char *dir = filelist; char *filewalker = filelist + strlen(dir) + 1; while (*filewalker != '\0') { char *filename = dupcat(dir, "\\", filewalker, NULL); add_keyfile(filename_from_str(filename)); sfree(filename); filewalker += strlen(filewalker) + 1; } } keylist_update(); forget_passphrases(); } sfree(filelist); } /* * Dialog-box function for the key list box. */ static int CALLBACK KeyListProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { struct RSAKey *rkey; struct ssh2_userkey *skey; /* PuTTY CAPI start */ struct CAPI_userkey *ckey; /* PuTTY CAPI end */ switch (msg) { case WM_INITDIALOG: /* * Centre the window. */ { /* centre the window */ |
︙ | ︙ | |||
1533 1534 1535 1536 1537 1538 1539 | prompt_add_keyfile(); } return 0; case 102: /* remove key */ if (HIWORD(wParam) == BN_CLICKED || HIWORD(wParam) == BN_DOUBLECLICKED) { int i; | | | 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 | prompt_add_keyfile(); } return 0; case 102: /* remove key */ if (HIWORD(wParam) == BN_CLICKED || HIWORD(wParam) == BN_DOUBLECLICKED) { int i; int rCount, sCount, cCount; /* PuTTY CAPI marker */ int *selectedArray; /* our counter within the array of selected items */ int itemNum; /* get the number of items selected in the list */ int numSelected = |
︙ | ︙ | |||
1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 | selectedArray = snewn(numSelected, int); SendDlgItemMessage(hwnd, 100, LB_GETSELITEMS, numSelected, (WPARAM)selectedArray); itemNum = numSelected - 1; rCount = count234(rsakeys); sCount = count234(ssh2keys); /* go through the non-rsakeys until we've covered them all, * and/or we're out of selected items to check. note that * we go *backwards*, to avoid complications from deleting * things hence altering the offset of subsequent items */ for (i = sCount - 1; (itemNum >= 0) && (i >= 0); i--) { skey = index234(ssh2keys, i); if (selectedArray[itemNum] == rCount + i) { del234(ssh2keys, skey); skey->alg->freekey(skey->data); sfree(skey); | > > > > > > > > > > > > > > | 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 | selectedArray = snewn(numSelected, int); SendDlgItemMessage(hwnd, 100, LB_GETSELITEMS, numSelected, (WPARAM)selectedArray); itemNum = numSelected - 1; rCount = count234(rsakeys); sCount = count234(ssh2keys); /* PuTTY CAPI start */ cCount = count234(capikeys); /* PuTTY CAPI end */ /* go through the non-rsakeys until we've covered them all, * and/or we're out of selected items to check. note that * we go *backwards*, to avoid complications from deleting * things hence altering the offset of subsequent items */ /* PuTTY CAPI start */ for (i = cCount - 1; (itemNum >= 0) && (i >= 0); i--) { ckey = index234(capikeys, i); if (selectedArray[itemNum] == rCount + sCount + i) { del234(capikeys, ckey); Free_CAPI_userkey(ckey); itemNum--; } } /* PuTTY CAPI end */ for (i = sCount - 1; (itemNum >= 0) && (i >= 0); i--) { skey = index234(ssh2keys, i); if (selectedArray[itemNum] == rCount + i) { del234(ssh2keys, skey); skey->alg->freekey(skey->data); sfree(skey); |
︙ | ︙ | |||
1596 1597 1598 1599 1600 1601 1602 | return 0; case 103: /* help */ if (HIWORD(wParam) == BN_CLICKED || HIWORD(wParam) == BN_DOUBLECLICKED) { launch_help(hwnd, WINHELP_CTX_pageant_general); } return 0; | > > > > > > | > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > | 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 | return 0; case 103: /* help */ if (HIWORD(wParam) == BN_CLICKED || HIWORD(wParam) == BN_DOUBLECLICKED) { launch_help(hwnd, WINHELP_CTX_pageant_general); } return 0; /* PuTTY CAPI start */ case 100: { // listbox if (HIWORD(wParam) == LBN_DBLCLK) { int i, rCount, sCount, cCount; int selected; int numSelected; numSelected = SendDlgItemMessage(hwnd, 100, LB_GETSELCOUNT, 0, 0); if (numSelected != 1) break; SendDlgItemMessage(hwnd, 100, LB_GETSELITEMS, numSelected, (WPARAM) &selected); rCount = count234(rsakeys); sCount = count234(ssh2keys); cCount = count234(capikeys); // since numSelected is garunteed to be 1, we can skip a few checks... for (i = cCount - 1; i >= 0; i--) { if (selected == rCount + sCount + i) { PCCERT_CONTEXT pCertContext = NULL; ckey = index234(capikeys, i); //BOOL capi_get_pubkey_int(void *f /*frontend*/, char* certID, unsigned char** pubkey, char **algorithm, int *blob_len, PCCERT_CONTEXT* oCertContext) { capi_display_cert_ui(hwnd, ckey->certID, L"Pageant Certificate"); } } } return 0; } case 110: { if (HIWORD(wParam) == BN_CLICKED || HIWORD(wParam) == BN_DOUBLECLICKED) { if (passphrase_box) { MessageBeep(MB_ICONERROR); SetForegroundWindow(passphrase_box); break; } prompt_add_CAPIkey(hwnd); } return 0; } /* PuTTY CAPI end */ } case WM_HELP: { int id = ((LPHELPINFO)lParam)->iCtrlId; char *topic = NULL; switch (id) { case 100: topic = WINHELP_CTX_pageant_keylist; break; case 101: topic = WINHELP_CTX_pageant_addkey; break; |
︙ | ︙ | |||
1640 1641 1642 1643 1644 1645 1646 | tnid.cbSize = sizeof(NOTIFYICONDATA); tnid.hWnd = hwnd; tnid.uID = 1; /* unique within this systray use */ tnid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; tnid.uCallbackMessage = WM_SYSTRAY; tnid.hIcon = hicon = LoadIcon(hinst, MAKEINTRESOURCE(201)); | | | 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 | tnid.cbSize = sizeof(NOTIFYICONDATA); tnid.hWnd = hwnd; tnid.uID = 1; /* unique within this systray use */ tnid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; tnid.uCallbackMessage = WM_SYSTRAY; tnid.hIcon = hicon = LoadIcon(hinst, MAKEINTRESOURCE(201)); strcpy(tnid.szTip, "Pageant (PuTTY SC authentication agent)"); res = Shell_NotifyIcon(NIM_ADD, &tnid); if (hicon) DestroyIcon(hicon); return res; } |
︙ | ︙ | |||
1912 1913 1914 1915 1916 1917 1918 | #ifndef NO_SECURITY int rc; if (has_security) { if ((ourself = get_user_sid()) == NULL) { #ifdef DEBUG_IPC debug(("couldn't get user SID\n")); #endif | < < < < < < < < < | 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 | #ifndef NO_SECURITY int rc; if (has_security) { if ((ourself = get_user_sid()) == NULL) { #ifdef DEBUG_IPC debug(("couldn't get user SID\n")); #endif return 0; } if ((ourself2 = get_default_sid()) == NULL) { #ifdef DEBUG_IPC debug(("couldn't get default SID\n")); #endif return 0; } if ((rc = p_GetSecurityInfo(filemap, SE_KERNEL_OBJECT, OWNER_SECURITY_INFORMATION, &mapowner, NULL, NULL, NULL, &psd) != ERROR_SUCCESS)) { #ifdef DEBUG_IPC debug(("couldn't get owner info for filemap: %d\n", rc)); #endif return 0; } #ifdef DEBUG_IPC { LPTSTR ours, ours2, theirs; ConvertSidToStringSid(mapowner, &theirs); ConvertSidToStringSid(ourself, &ours); ConvertSidToStringSid(ourself2, &ours2); debug(("got sids:\n oursnew=%s\n oursold=%s\n" " theirs=%s\n", ours, ours2, theirs)); LocalFree(ours); LocalFree(ours2); LocalFree(theirs); } #endif if (!EqualSid(mapowner, ourself) && !EqualSid(mapowner, ourself2)) { CloseHandle(filemap); return 0; /* security ID mismatch! */ } #ifdef DEBUG_IPC debug(("security stuff matched\n")); #endif LocalFree(psd); sfree(ourself); |
︙ | ︙ | |||
2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 | int flags = FLAG_SYNCAGENT; int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { WNDCLASS wndclass; MSG msg; char *command = NULL; int added_keys = 0; int argc, i; char **argv, **argstart; hinst = inst; hwnd = NULL; /* * Determine whether we're an NT system (should have security * APIs) or a non-NT system (don't do security). */ | > > > > > | 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 | int flags = FLAG_SYNCAGENT; int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { WNDCLASS wndclass; MSG msg; HMODULE advapi; char *command = NULL; int added_keys = 0; int argc, i; char **argv, **argstart; /* PuTTY SC start */ HKEY hkey; /* PuTTY SC end */ hinst = inst; hwnd = NULL; /* * Determine whether we're an NT system (should have security * APIs) or a non-NT system (don't do security). */ |
︙ | ︙ | |||
2056 2057 2058 2059 2060 2061 2062 | has_security = FALSE; if (has_security) { #ifndef NO_SECURITY /* * Attempt to get the security API we need. */ | | | > | 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 | has_security = FALSE; if (has_security) { #ifndef NO_SECURITY /* * Attempt to get the security API we need. */ if (!init_advapi()) { MessageBox(NULL, "Unable to access security APIs. Pageant will\n" "not run, in case it causes a security breach.", "Pageant Fatal Error", MB_ICONERROR | MB_OK); return 1; } #else MessageBox(NULL, "This program has been compiled for Win9X and will\n" "not run on NT, in case it causes a security breach.", "Pageant Fatal Error", MB_ICONERROR | MB_OK); return 1; #endif } else advapi = NULL; /* * See if we can find our Help file. */ init_help(); /* |
︙ | ︙ | |||
2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 | /* * Initialise storage for RSA keys. */ if (!already_running) { rsakeys = newtree234(cmpkeys_rsa); ssh2keys = newtree234(cmpkeys_ssh2); } /* * Initialise storage for short-term passphrase cache. */ passphrases = newtree234(NULL); /* * Process the command line and add keys as listed on it. */ split_into_argv(cmdline, &argc, &argv, &argstart); for (i = 0; i < argc; i++) { if (!strcmp(argv[i], "-pgpfp")) { pgp_fingerprints(); return 1; } else if (!strcmp(argv[i], "-c")) { /* * If we see `-c', then the rest of the * command line should be treated as a * command to be spawned. */ if (i < argc-1) command = argstart[i+1]; else command = ""; break; } else { | > > > > > < | < | 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 | /* * Initialise storage for RSA keys. */ if (!already_running) { rsakeys = newtree234(cmpkeys_rsa); ssh2keys = newtree234(cmpkeys_ssh2); /* PuTTY CAPI start */ capikeys = newtree234(cmpkeys_capi); /* PuTTY CAPI end */ } /* * Initialise storage for short-term passphrase cache. */ passphrases = newtree234(NULL); /* * Process the command line and add keys as listed on it. */ split_into_argv(cmdline, &argc, &argv, &argstart); for (i = 0; i < argc; i++) { if (!strcmp(argv[i], "-pgpfp")) { pgp_fingerprints(); if (advapi) FreeLibrary(advapi); return 1; } else if (!strcmp(argv[i], "-c")) { /* * If we see `-c', then the rest of the * command line should be treated as a * command to be spawned. */ if (i < argc-1) command = argstart[i+1]; else command = ""; break; } else { add_keyfile(filename_from_str(argv[i])); added_keys = TRUE; } } /* * Forget any passphrase that we retained while going over * command line keyfiles. |
︙ | ︙ | |||
2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 | * keys), complain. */ if (already_running) { if (!command && !added_keys) { MessageBox(NULL, "Pageant is already running", "Pageant Error", MB_ICONERROR | MB_OK); } return 0; } if (!prev) { wndclass.style = 0; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = inst; wndclass.hIcon = LoadIcon(inst, MAKEINTRESOURCE(IDI_MAINICON)); wndclass.hCursor = LoadCursor(NULL, IDC_IBEAM); wndclass.hbrBackground = GetStockObject(BLACK_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = APPNAME; RegisterClass(&wndclass); } keylist = NULL; hwnd = CreateWindow(APPNAME, APPNAME, WS_OVERLAPPEDWINDOW | WS_VSCROLL, CW_USEDEFAULT, CW_USEDEFAULT, 100, 100, NULL, NULL, inst, NULL); /* Set up a system tray icon */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 | * keys), complain. */ if (already_running) { if (!command && !added_keys) { MessageBox(NULL, "Pageant is already running", "Pageant Error", MB_ICONERROR | MB_OK); } if (advapi) FreeLibrary(advapi); return 0; } if (!prev) { wndclass.style = 0; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = inst; wndclass.hIcon = LoadIcon(inst, MAKEINTRESOURCE(IDI_MAINICON)); wndclass.hCursor = LoadCursor(NULL, IDC_IBEAM); wndclass.hbrBackground = GetStockObject(BLACK_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = APPNAME; RegisterClass(&wndclass); } keylist = NULL; /* PuTTY SC start */ if(ERROR_SUCCESS == RegOpenKey(HKEY_CURRENT_USER, PUTTY_REGKEY, &hkey)) { TCHAR buf[MAX_PATH + 1]; int index_key = 0; memset(sc_save_passphrase, 0, PASSPHRASE_MAXLEN); while(ERROR_SUCCESS == RegEnumKey(hkey, index_key, buf, MAX_PATH)) { char kn[1024]; HKEY sesskey; sprintf(kn, "%s\\%s", PUTTY_REGKEY, buf); if(ERROR_SUCCESS == RegOpenKey(HKEY_CURRENT_USER, kn, &sesskey)) { Filename pkcs11_libfile; int ln = sizeof(pkcs11_token_label); if(read_setting_s(sesskey, "PKCS11CertLabel", pkcs11_cert_label, ln)) { if(strlen(pkcs11_cert_label) > 0) { read_setting_filename(sesskey, "PKCS11LibFile", &pkcs11_libfile); read_setting_s(sesskey, "PKCS11TokenLabel", pkcs11_token_label, ln); { sclib = calloc(sizeof(sc_lib), 1); if(sc_init_library(NULL, 1, sclib, &pkcs11_libfile)) { int bloblen; char *algorithm; unsigned char *blob = (unsigned char *)sc_get_pub(NULL, 0, sclib, pkcs11_token_label, pkcs11_cert_label, &algorithm, &bloblen); if(blob == NULL) { sc_free_sclib(sclib); sclib = NULL; } else { struct RSAKey *rkey = snew(struct RSAKey); struct ssh2_userkey *newKey = snew(struct ssh2_userkey); rkey->exponent = sclib->rsakey->exponent; rkey->modulus = sclib->rsakey->modulus; newKey->data = rkey; newKey->comment = pkcs11_cert_label; newKey->alg = find_pubkey_alg("ssh-rsa"); if(add234(ssh2keys, newKey) != newKey) { MessageBox(NULL, "Failed to add token key", "Pageant Error", MB_ICONERROR | MB_OK); } break; // todo support multiple keys // -------------------- } } } RegCloseKey(sesskey); } } RegCloseKey(sesskey); } index_key++; } RegCloseKey(hkey); } /* PuTTY SC end */ hwnd = CreateWindow(APPNAME, APPNAME, WS_OVERLAPPEDWINDOW | WS_VSCROLL, CW_USEDEFAULT, CW_USEDEFAULT, 100, 100, NULL, NULL, inst, NULL); /* Set up a system tray icon */ |
︙ | ︙ | |||
2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 | Shell_NotifyIcon(NIM_DELETE, &tnid); DestroyMenu(systray_menu); } if (keypath) filereq_free(keypath); cleanup_exit(msg.wParam); return msg.wParam; /* just in case optimiser complains */ } | > > > | 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 | Shell_NotifyIcon(NIM_DELETE, &tnid); DestroyMenu(systray_menu); } if (keypath) filereq_free(keypath); if (advapi) FreeLibrary(advapi); cleanup_exit(msg.wParam); return msg.wParam; /* just in case optimiser complains */ } |
Changes to windows/winpgntc.c.
1 2 3 4 5 6 7 8 9 10 | /* * Pageant client code. */ #include <stdio.h> #include <stdlib.h> #include "putty.h" #ifndef NO_SECURITY | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | /* * Pageant client code. */ #include <stdio.h> #include <stdlib.h> #include "putty.h" #ifndef NO_SECURITY #include <aclapi.h> #endif #define AGENT_COPYDATA_ID 0x804e50ba /* random goop */ #define AGENT_MAX_MSGLEN 8192 int agent_exists(void) { |
︙ | ︙ | |||
66 67 68 69 70 71 72 73 74 75 76 77 78 79 | agent_schedule_callback(data->callback, data->callback_ctx, ret, retlen); return 0; } #endif int agent_query(void *in, int inlen, void **out, int *outlen, void (*callback)(void *, void *, int), void *callback_ctx) { HWND hwnd; char *mapname; HANDLE filemap; unsigned char *p, *ret; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | agent_schedule_callback(data->callback, data->callback_ctx, ret, retlen); return 0; } #endif /* * Dynamically load advapi32.dll for SID manipulation. In its absence, * we degrade gracefully. */ #ifndef NO_SECURITY int advapi_initialised = FALSE; static HMODULE advapi; DECL_WINDOWS_FUNCTION(static, BOOL, OpenProcessToken, (HANDLE, DWORD, PHANDLE)); DECL_WINDOWS_FUNCTION(static, BOOL, GetTokenInformation, (HANDLE, TOKEN_INFORMATION_CLASS, LPVOID, DWORD, PDWORD)); DECL_WINDOWS_FUNCTION(static, BOOL, InitializeSecurityDescriptor, (PSECURITY_DESCRIPTOR, DWORD)); DECL_WINDOWS_FUNCTION(static, BOOL, SetSecurityDescriptorOwner, (PSECURITY_DESCRIPTOR, PSID, BOOL)); DECL_WINDOWS_FUNCTION(, DWORD, GetSecurityInfo, (HANDLE, SE_OBJECT_TYPE, SECURITY_INFORMATION, PSID *, PSID *, PACL *, PACL *, PSECURITY_DESCRIPTOR *)); int init_advapi(void) { advapi = load_system32_dll("advapi32.dll"); return advapi && GET_WINDOWS_FUNCTION(advapi, GetSecurityInfo) && GET_WINDOWS_FUNCTION(advapi, OpenProcessToken) && GET_WINDOWS_FUNCTION(advapi, GetTokenInformation) && GET_WINDOWS_FUNCTION(advapi, InitializeSecurityDescriptor) && GET_WINDOWS_FUNCTION(advapi, SetSecurityDescriptorOwner); } PSID get_user_sid(void) { HANDLE proc = NULL, tok = NULL; TOKEN_USER *user = NULL; DWORD toklen, sidlen; PSID sid = NULL, ret = NULL; if ((proc = OpenProcess(MAXIMUM_ALLOWED, FALSE, GetCurrentProcessId())) == NULL) goto cleanup; if (!p_OpenProcessToken(proc, TOKEN_QUERY, &tok)) goto cleanup; if (!p_GetTokenInformation(tok, TokenUser, NULL, 0, &toklen) && GetLastError() != ERROR_INSUFFICIENT_BUFFER) goto cleanup; if ((user = (TOKEN_USER *)LocalAlloc(LPTR, toklen)) == NULL) goto cleanup; if (!p_GetTokenInformation(tok, TokenUser, user, toklen, &toklen)) goto cleanup; sidlen = GetLengthSid(user->User.Sid); sid = (PSID)smalloc(sidlen); if (!CopySid(sidlen, sid, user->User.Sid)) goto cleanup; /* Success. Move sid into the return value slot, and null it out * to stop the cleanup code freeing it. */ ret = sid; sid = NULL; cleanup: if (proc != NULL) CloseHandle(proc); if (tok != NULL) CloseHandle(tok); if (user != NULL) LocalFree(user); if (sid != NULL) sfree(sid); return ret; } #endif int agent_query(void *in, int inlen, void **out, int *outlen, void (*callback)(void *, void *, int), void *callback_ctx) { HWND hwnd; char *mapname; HANDLE filemap; unsigned char *p, *ret; |
︙ | ︙ | |||
87 88 89 90 91 92 93 | *outlen = 0; hwnd = FindWindow("Pageant", "Pageant"); if (!hwnd) return 1; /* *out == NULL, so failure */ mapname = dupprintf("PageantRequest%08x", (unsigned)GetCurrentThreadId()); | < | > | 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 | *outlen = 0; hwnd = FindWindow("Pageant", "Pageant"); if (!hwnd) return 1; /* *out == NULL, so failure */ mapname = dupprintf("PageantRequest%08x", (unsigned)GetCurrentThreadId()); #ifndef NO_SECURITY if (advapi_initialised || init_advapi()) { /* * Make the file mapping we create for communication with * Pageant owned by the user SID rather than the default. This * should make communication between processes with slightly * different contexts more reliable: in particular, command * prompts launched as administrator should still be able to * run PSFTPs which refer back to the owning user's * unprivileged Pageant. */ usersid = get_user_sid(); psa = NULL; if (usersid) { psd = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH); if (psd) { if (p_InitializeSecurityDescriptor (psd, SECURITY_DESCRIPTOR_REVISION) && p_SetSecurityDescriptorOwner(psd, usersid, FALSE)) { |
︙ | ︙ | |||
123 124 125 126 127 128 129 | } } } #endif /* NO_SECURITY */ filemap = CreateFileMapping(INVALID_HANDLE_VALUE, psa, PAGE_READWRITE, 0, AGENT_MAX_MSGLEN, mapname); | | < < | 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 | } } } #endif /* NO_SECURITY */ filemap = CreateFileMapping(INVALID_HANDLE_VALUE, psa, PAGE_READWRITE, 0, AGENT_MAX_MSGLEN, mapname); if (filemap == NULL || filemap == INVALID_HANDLE_VALUE) return 1; /* *out == NULL, so failure */ p = MapViewOfFile(filemap, FILE_MAP_WRITE, 0, 0, 0); memcpy(p, in, inlen); cds.dwData = AGENT_COPYDATA_ID; cds.cbData = 1 + strlen(mapname); cds.lpData = mapname; #ifdef WINDOWS_ASYNC_AGENT if (callback != NULL && !(flags & FLAG_SYNCAGENT)) { |
︙ | ︙ | |||
153 154 155 156 157 158 159 | data->mapname = mapname; data->callback = callback; data->callback_ctx = callback_ctx; data->cds = cds; /* structure copy */ data->hwnd = hwnd; if (CreateThread(NULL, 0, agent_query_thread, data, 0, &threadid)) return 0; | < | 233 234 235 236 237 238 239 240 241 242 243 244 245 246 | data->mapname = mapname; data->callback = callback; data->callback_ctx = callback_ctx; data->cds = cds; /* structure copy */ data->hwnd = hwnd; if (CreateThread(NULL, 0, agent_query_thread, data, 0, &threadid)) return 0; sfree(data); } #endif /* * The user either passed a null callback (indicating that the * query is required to be synchronous) or CreateThread failed. |
︙ | ︙ | |||
175 176 177 178 179 180 181 | memcpy(ret, p, retlen); *out = ret; *outlen = retlen; } } UnmapViewOfFile(p); CloseHandle(filemap); | < | 254 255 256 257 258 259 260 261 262 263 264 265 | memcpy(ret, p, retlen); *out = ret; *outlen = retlen; } } UnmapViewOfFile(p); CloseHandle(filemap); if (psd) LocalFree(psd); sfree(usersid); return 1; } |
Changes to windows/winplink.c.
︙ | ︙ | |||
45 46 47 48 49 50 51 | fputc('\n', stderr); if (logctx) { log_free(logctx); logctx = NULL; } cleanup_exit(1); } | < < < < < < < < < | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | fputc('\n', stderr); if (logctx) { log_free(logctx); logctx = NULL; } cleanup_exit(1); } void connection_fatal(void *frontend, char *p, ...) { va_list ap; fprintf(stderr, "FATAL ERROR: "); va_start(ap, p); vfprintf(stderr, p, ap); va_end(ap); |
︙ | ︙ | |||
88 89 90 91 92 93 94 | DWORD orig_console_mode; int connopen; WSAEVENT netevent; static Backend *back; static void *backhandle; | | | 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | DWORD orig_console_mode; int connopen; WSAEVENT netevent; static Backend *back; static void *backhandle; static Config cfg; int term_ldisc(Terminal *term, int mode) { return FALSE; } void ldisc_update(void *frontend, int echo, int edit) { |
︙ | ︙ | |||
135 136 137 138 139 140 141 | * No "untrusted" output should get here (the way the code is * currently, it's all diverted by FLAG_STDERR). */ assert(!"Unexpected call to from_backend_untrusted()"); return 0; /* not reached */ } | < < < < < < | 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | * No "untrusted" output should get here (the way the code is * currently, it's all diverted by FLAG_STDERR). */ assert(!"Unexpected call to from_backend_untrusted()"); return 0; /* not reached */ } int get_userpass_input(prompts_t *p, unsigned char *in, int inlen) { int ret; ret = cmdline_get_passwd_input(p, in, inlen); if (ret == -1) ret = console_get_userpass_input(p, in, inlen); return ret; |
︙ | ︙ | |||
284 285 286 287 288 289 290 | } if (connopen && back->connected(backhandle)) { back->unthrottle(backhandle, (handle_backlog(stdout_handle) + handle_backlog(stderr_handle))); } } | < < < | < | | | | | < < | | | < < | | | | | > < < | | 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 | } if (connopen && back->connected(backhandle)) { back->unthrottle(backhandle, (handle_backlog(stdout_handle) + handle_backlog(stderr_handle))); } } int main(int argc, char **argv) { int sending; int portnumber = -1; SOCKET *sklist; int skcount, sksize; int exitcode; int errors; int got_host = FALSE; int use_subsystem = 0; long now, next; sklist = NULL; skcount = sksize = 0; /* * Initialise port and protocol to sensible defaults. (These * will be overridden by more or less anything.) */ default_protocol = PROT_SSH; default_port = 22; flags = FLAG_STDERR; /* * Process the command line. */ do_defaults(NULL, &cfg); loaded_session = FALSE; default_protocol = cfg.protocol; default_port = cfg.port; errors = 0; { /* * Override the default protocol if PLINK_PROTOCOL is set. */ char *p = getenv("PLINK_PROTOCOL"); if (p) { const Backend *b = backend_from_name(p); if (b) { default_protocol = cfg.protocol = b->protocol; default_port = cfg.port = b->default_port; } } } while (--argc) { char *p = *++argv; if (*p == '-') { int ret = cmdline_process_param(p, (argc > 1 ? argv[1] : NULL), 1, &cfg); if (ret == -2) { fprintf(stderr, "plink: option \"%s\" requires an argument\n", p); errors = 1; } else if (ret == 2) { --argc, ++argv; } else if (ret == 1) { continue; } else if (!strcmp(p, "-batch")) { console_batch_mode = 1; } else if (!strcmp(p, "-s")) { /* Save status to write to cfg later. */ use_subsystem = 1; } else if (!strcmp(p, "-V")) { version(); } else if (!strcmp(p, "-pgpfp")) { pgp_fingerprints(); exit(1); } else { fprintf(stderr, "plink: unknown option \"%s\"\n", p); errors = 1; } } else if (*p) { if (!cfg_launchable(&cfg) || !(got_host || loaded_session)) { char *q = p; /* * If the hostname starts with "telnet:", set the * protocol to Telnet and process the string as a * Telnet URL. */ if (!strncmp(q, "telnet:", 7)) { char c; q += 7; if (q[0] == '/' && q[1] == '/') q += 2; cfg.protocol = PROT_TELNET; p = q; while (*p && *p != ':' && *p != '/') p++; c = *p; if (*p) *p++ = '\0'; if (c == ':') cfg.port = atoi(p); else cfg.port = -1; strncpy(cfg.host, q, sizeof(cfg.host) - 1); cfg.host[sizeof(cfg.host) - 1] = '\0'; got_host = TRUE; } else { char *r, *user, *host; /* * Before we process the [user@]host string, we * first check for the presence of a protocol * prefix (a protocol name followed by ","). */ r = strchr(p, ','); if (r) { const Backend *b; *r = '\0'; b = backend_from_name(p); if (b) { default_protocol = cfg.protocol = b->protocol; portnumber = b->default_port; } p = r + 1; } /* * A nonzero length string followed by an @ is treated |
︙ | ︙ | |||
431 432 433 434 435 436 437 | } /* * Now attempt to load a saved session with the * same name as the hostname. */ { | | | | | > | | < | > > | 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 | } /* * Now attempt to load a saved session with the * same name as the hostname. */ { Config cfg2; do_defaults(host, &cfg2); if (loaded_session || !cfg_launchable(&cfg2)) { /* No settings for this host; use defaults */ /* (or session was already loaded with -load) */ strncpy(cfg.host, host, sizeof(cfg.host) - 1); cfg.host[sizeof(cfg.host) - 1] = '\0'; cfg.port = default_port; got_host = TRUE; } else { cfg = cfg2; loaded_session = TRUE; } } if (user) { /* Patch in specified username. */ strncpy(cfg.username, user, sizeof(cfg.username) - 1); cfg.username[sizeof(cfg.username) - 1] = '\0'; } } } else { char *command; int cmdlen, cmdsize; cmdlen = cmdsize = 0; |
︙ | ︙ | |||
475 476 477 478 479 480 481 | command = sresize(command, cmdsize, char); } command[cmdlen++]=' '; /* always add trailing space */ if (--argc) p = *++argv; } if (cmdlen) command[--cmdlen]='\0'; /* change trailing blank to NUL */ | | | | | | | | < | < < < < < | < < | | > | | | | < | < < < < | < < < < < < < < < < < < < < | | > > > > | > > > > > > > > > > > > > > | | | | | | | < < | < | 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 | command = sresize(command, cmdsize, char); } command[cmdlen++]=' '; /* always add trailing space */ if (--argc) p = *++argv; } if (cmdlen) command[--cmdlen]='\0'; /* change trailing blank to NUL */ cfg.remote_cmd_ptr = command; cfg.remote_cmd_ptr2 = NULL; cfg.nopty = TRUE; /* command => no terminal */ break; /* done with cmdline */ } } } if (errors) return 1; if (!cfg_launchable(&cfg) || !(got_host || loaded_session)) { usage(); } /* * Trim leading whitespace off the hostname if it's there. */ { int space = strspn(cfg.host, " \t"); memmove(cfg.host, cfg.host+space, 1+strlen(cfg.host)-space); } /* See if host is of the form user@host */ if (cfg_launchable(&cfg)) { char *atsign = strrchr(cfg.host, '@'); /* Make sure we're not overflowing the user field */ if (atsign) { if (atsign - cfg.host < sizeof cfg.username) { strncpy(cfg.username, cfg.host, atsign - cfg.host); cfg.username[atsign - cfg.host] = '\0'; } memmove(cfg.host, atsign + 1, 1 + strlen(atsign + 1)); } } /* * Perform command-line overrides on session configuration. */ cmdline_run_saved(&cfg); /* * Apply subsystem status. */ if (use_subsystem) cfg.ssh_subsys = TRUE; /* * Trim a colon suffix off the hostname if it's there. */ cfg.host[strcspn(cfg.host, ":")] = '\0'; /* * Remove any remaining whitespace from the hostname. */ { int p1 = 0, p2 = 0; while (cfg.host[p2] != '\0') { if (cfg.host[p2] != ' ' && cfg.host[p2] != '\t') { cfg.host[p1] = cfg.host[p2]; p1++; } p2++; } cfg.host[p1] = '\0'; } if (!cfg.remote_cmd_ptr && !*cfg.remote_cmd && !*cfg.ssh_nc_host) flags |= FLAG_INTERACTIVE; /* * Select protocol. This is farmed out into a table in a * separate file to enable an ssh-free variant. */ back = backend_from_proto(cfg.protocol); if (back == NULL) { fprintf(stderr, "Internal fault: Unsupported protocol found\n"); return 1; } /* * Select port. */ if (portnumber != -1) cfg.port = portnumber; sk_init(); if (p_WSAEventSelect == NULL) { fprintf(stderr, "Plink requires WinSock 2\n"); return 1; } logctx = log_init(NULL, &cfg); console_provide_logctx(logctx); /* * Start up the connection. */ netevent = CreateEvent(NULL, FALSE, FALSE, NULL); { const char *error; char *realhost; /* nodelay is only useful if stdin is a character device (console) */ int nodelay = cfg.tcp_nodelay && (GetFileType(GetStdHandle(STD_INPUT_HANDLE)) == FILE_TYPE_CHAR); error = back->init(NULL, &backhandle, &cfg, cfg.host, cfg.port, &realhost, nodelay, cfg.tcp_keepalives); if (error) { fprintf(stderr, "Unable to open connection:\n%s", error); return 1; } back->provide_logctx(backhandle, logctx); sfree(realhost); } |
︙ | ︙ | |||
643 644 645 646 647 648 649 | if (!sending && back->sendok(backhandle)) { stdin_handle = handle_input_new(inhandle, stdin_gotdata, NULL, 0); sending = TRUE; } | < < | < | < | < < | 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 | if (!sending && back->sendok(backhandle)) { stdin_handle = handle_input_new(inhandle, stdin_gotdata, NULL, 0); sending = TRUE; } if (run_timers(now, &next)) { ticks = next - GETTICKCOUNT(); if (ticks < 0) ticks = 0; /* just in case */ } else { ticks = INFINITE; } handles = handle_get_events(&nhandles); handles = sresize(handles, nhandles+1, HANDLE); handles[nhandles] = netevent; |
︙ | ︙ | |||
735 736 737 738 739 740 741 | PM_REMOVE)) { struct agent_callback *c = (struct agent_callback *)msg.lParam; c->callback(c->callback_ctx, c->data, c->len); sfree(c); } } | < < | 696 697 698 699 700 701 702 703 704 705 706 707 708 709 | PM_REMOVE)) { struct agent_callback *c = (struct agent_callback *)msg.lParam; c->callback(c->callback_ctx, c->data, c->len); sfree(c); } } if (n == WAIT_TIMEOUT) { now = next; } else { now = GETTICKCOUNT(); } sfree(handles); |
︙ | ︙ |
Changes to windows/winprint.c.
︙ | ︙ | |||
14 15 16 17 18 19 20 | } info; }; struct printer_job_tag { HANDLE hprinter; }; | | | | | | | | | | | | > > > | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | } info; }; struct printer_job_tag { HANDLE hprinter; }; static char *printer_add_enum(int param, DWORD level, char *buffer, int offset, int *nprinters_ptr) { DWORD needed = 0, nprinters = 0; buffer = sresize(buffer, offset+512, char); /* * Exploratory call to EnumPrinters to determine how much space * we'll need for the output. Discard the return value since it * will almost certainly be a failure due to lack of space. */ EnumPrinters(param, NULL, level, buffer+offset, 512, &needed, &nprinters); if (needed < 512) needed = 512; buffer = sresize(buffer, offset+needed, char); if (EnumPrinters(param, NULL, level, buffer+offset, needed, &needed, &nprinters) == 0) return NULL; *nprinters_ptr += nprinters; return buffer; } printer_enum *printer_start_enum(int *nprinters_ptr) { printer_enum *ret = snew(printer_enum); char *buffer = NULL, *retval; *nprinters_ptr = 0; /* default return value */ buffer = snewn(512, char); /* * Determine what enumeration level to use. * When enumerating printers, we need to use PRINTER_INFO_4 on * NT-class systems to avoid Windows looking too hard for them and * slowing things down; and we need to avoid PRINTER_INFO_5 as * we've seen network printers not show up. * On 9x-class systems, PRINTER_INFO_4 isn't available and * PRINTER_INFO_5 is recommended. * Bletch. */ if (osVersion.dwPlatformId != VER_PLATFORM_WIN32_NT) { ret->enum_level = 5; } else { ret->enum_level = 4; } retval = printer_add_enum(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, ret->enum_level, buffer, 0, nprinters_ptr); if (!retval) goto error; else buffer = retval; switch (ret->enum_level) { case 4: ret->info.i4 = (LPPRINTER_INFO_4)buffer; break; case 5: ret->info.i5 = (LPPRINTER_INFO_5)buffer; |
︙ | ︙ |
Changes to windows/winproxy.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | #define DEFINE_PLUG_METHOD_MACROS #include "tree234.h" #include "putty.h" #include "network.h" #include "proxy.h" | > | > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > | | < < < > > > > > < | < | < < < > | < < > > | > > > > | > > > > > | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 | #define DEFINE_PLUG_METHOD_MACROS #include "tree234.h" #include "putty.h" #include "network.h" #include "proxy.h" typedef struct Socket_localproxy_tag *Local_Proxy_Socket; struct Socket_localproxy_tag { const struct socket_function_table *fn; /* the above variable absolutely *must* be the first in this structure */ HANDLE to_cmd_H, from_cmd_H; struct handle *to_cmd_h, *from_cmd_h; char *error; Plug plug; void *privptr; }; int localproxy_gotdata(struct handle *h, void *data, int len) { Local_Proxy_Socket ps = (Local_Proxy_Socket) handle_get_privdata(h); if (len < 0) { return plug_closing(ps->plug, "Read error from local proxy command", 0, 0); } else if (len == 0) { return plug_closing(ps->plug, NULL, 0, 0); } else { return plug_receive(ps->plug, 0, data, len); } } void localproxy_sentdata(struct handle *h, int new_backlog) { Local_Proxy_Socket ps = (Local_Proxy_Socket) handle_get_privdata(h); plug_sent(ps->plug, new_backlog); } static Plug sk_localproxy_plug (Socket s, Plug p) { Local_Proxy_Socket ps = (Local_Proxy_Socket) s; Plug ret = ps->plug; if (p) ps->plug = p; return ret; } static void sk_localproxy_close (Socket s) { Local_Proxy_Socket ps = (Local_Proxy_Socket) s; handle_free(ps->to_cmd_h); handle_free(ps->from_cmd_h); CloseHandle(ps->to_cmd_H); CloseHandle(ps->from_cmd_H); sfree(ps); } static int sk_localproxy_write (Socket s, const char *data, int len) { Local_Proxy_Socket ps = (Local_Proxy_Socket) s; return handle_write(ps->to_cmd_h, data, len); } static int sk_localproxy_write_oob(Socket s, const char *data, int len) { /* * oob data is treated as inband; nasty, but nothing really * better we can do */ return sk_localproxy_write(s, data, len); } static void sk_localproxy_flush(Socket s) { /* Local_Proxy_Socket ps = (Local_Proxy_Socket) s; */ /* do nothing */ } static void sk_localproxy_set_private_ptr(Socket s, void *ptr) { Local_Proxy_Socket ps = (Local_Proxy_Socket) s; ps->privptr = ptr; } static void *sk_localproxy_get_private_ptr(Socket s) { Local_Proxy_Socket ps = (Local_Proxy_Socket) s; return ps->privptr; } static void sk_localproxy_set_frozen(Socket s, int is_frozen) { Local_Proxy_Socket ps = (Local_Proxy_Socket) s; /* * FIXME */ } static const char *sk_localproxy_socket_error(Socket s) { Local_Proxy_Socket ps = (Local_Proxy_Socket) s; return ps->error; } Socket platform_new_connection(SockAddr addr, char *hostname, int port, int privport, int oobinline, int nodelay, int keepalive, Plug plug, const Config *cfg) { char *cmd; static const struct socket_function_table socket_fn_table = { sk_localproxy_plug, sk_localproxy_close, sk_localproxy_write, sk_localproxy_write_oob, sk_localproxy_flush, sk_localproxy_set_private_ptr, sk_localproxy_get_private_ptr, sk_localproxy_set_frozen, sk_localproxy_socket_error }; Local_Proxy_Socket ret; HANDLE us_to_cmd, us_from_cmd, cmd_to_us, cmd_from_us; SECURITY_ATTRIBUTES sa; STARTUPINFO si; PROCESS_INFORMATION pi; if (cfg->proxy_type != PROXY_CMD) return NULL; cmd = format_telnet_command(addr, port, cfg); { char *msg = dupprintf("Starting local proxy command: %s", cmd); /* We're allowed to pass NULL here, because we're part of the Windows * front end so we know logevent doesn't expect any data. */ logevent(NULL, msg); sfree(msg); } ret = snew(struct Socket_localproxy_tag); ret->fn = &socket_fn_table; ret->plug = plug; ret->error = NULL; /* * Create the pipes to the proxy command, and spawn the proxy * command process. */ sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = NULL; /* default */ sa.bInheritHandle = TRUE; if (!CreatePipe(&us_from_cmd, &cmd_to_us, &sa, 0)) { ret->error = dupprintf("Unable to create pipes for proxy command"); return (Socket)ret; } if (!CreatePipe(&cmd_from_us, &us_to_cmd, &sa, 0)) { CloseHandle(us_from_cmd); CloseHandle(cmd_to_us); ret->error = dupprintf("Unable to create pipes for proxy command"); return (Socket)ret; } SetHandleInformation(us_to_cmd, HANDLE_FLAG_INHERIT, 0); SetHandleInformation(us_from_cmd, HANDLE_FLAG_INHERIT, 0); si.cb = sizeof(si); si.lpReserved = NULL; si.lpDesktop = NULL; si.lpTitle = NULL; si.dwFlags = STARTF_USESTDHANDLES; si.cbReserved2 = 0; si.lpReserved2 = NULL; si.hStdInput = cmd_from_us; si.hStdOutput = cmd_to_us; si.hStdError = NULL; CreateProcess(NULL, cmd, NULL, NULL, TRUE, CREATE_NO_WINDOW | NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi); sfree(cmd); CloseHandle(cmd_from_us); CloseHandle(cmd_to_us); ret->to_cmd_H = us_to_cmd; ret->from_cmd_H = us_from_cmd; ret->from_cmd_h = handle_input_new(ret->from_cmd_H, localproxy_gotdata, ret, 0); ret->to_cmd_h = handle_output_new(ret->to_cmd_H, localproxy_sentdata, ret, 0); /* We are responsible for this and don't need it any more */ sk_addr_free(addr); return (Socket) ret; } |
Deleted windows/winsecur.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted windows/winsecur.h.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to windows/winser.c.
︙ | ︙ | |||
83 84 85 86 87 88 89 | connection_fatal(serial->frontend, "%s", error_msg); } else { serial->bufsize = new_backlog; } } | | | 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | connection_fatal(serial->frontend, "%s", error_msg); } else { serial->bufsize = new_backlog; } } static const char *serial_configure(Serial serial, HANDLE serport, Config *cfg) { DCB dcb; COMMTIMEOUTS timeouts; /* * Set up the serial port parameters. If we can't even * GetCommState, we ignore the problem on the grounds that the |
︙ | ︙ | |||
117 118 119 120 121 122 123 | dcb.fAbortOnError = FALSE; dcb.fOutxCtsFlow = FALSE; dcb.fOutxDsrFlow = FALSE; /* * Configurable parameters. */ | | | | | | | | | 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | dcb.fAbortOnError = FALSE; dcb.fOutxCtsFlow = FALSE; dcb.fOutxDsrFlow = FALSE; /* * Configurable parameters. */ dcb.BaudRate = cfg->serspeed; msg = dupprintf("Configuring baud rate %d", cfg->serspeed); logevent(serial->frontend, msg); sfree(msg); dcb.ByteSize = cfg->serdatabits; msg = dupprintf("Configuring %d data bits", cfg->serdatabits); logevent(serial->frontend, msg); sfree(msg); switch (cfg->serstopbits) { case 2: dcb.StopBits = ONESTOPBIT; str = "1"; break; case 3: dcb.StopBits = ONE5STOPBITS; str = "1.5"; break; case 4: dcb.StopBits = TWOSTOPBITS; str = "2"; break; default: return "Invalid number of stop bits (need 1, 1.5 or 2)"; } msg = dupprintf("Configuring %s data bits", str); logevent(serial->frontend, msg); sfree(msg); switch (cfg->serparity) { case SER_PAR_NONE: dcb.Parity = NOPARITY; str = "no"; break; case SER_PAR_ODD: dcb.Parity = ODDPARITY; str = "odd"; break; case SER_PAR_EVEN: dcb.Parity = EVENPARITY; str = "even"; break; case SER_PAR_MARK: dcb.Parity = MARKPARITY; str = "mark"; break; case SER_PAR_SPACE: dcb.Parity = SPACEPARITY; str = "space"; break; } msg = dupprintf("Configuring %s parity", str); logevent(serial->frontend, msg); sfree(msg); switch (cfg->serflow) { case SER_FLOW_NONE: str = "no"; break; case SER_FLOW_XONXOFF: dcb.fOutX = dcb.fInX = TRUE; str = "XON/XOFF"; break; |
︙ | ︙ | |||
195 196 197 198 199 200 201 | * * Returns an error message, or NULL on success. * * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ static const char *serial_init(void *frontend_handle, void **backend_handle, | > | | < < | | 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 | * * Returns an error message, or NULL on success. * * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ static const char *serial_init(void *frontend_handle, void **backend_handle, Config *cfg, char *host, int port, char **realhost, int nodelay, int keepalive) { Serial serial; HANDLE serport; const char *err; serial = snew(struct serial_backend_data); serial->port = INVALID_HANDLE_VALUE; serial->out = serial->in = NULL; serial->bufsize = 0; serial->break_in_progress = FALSE; *backend_handle = serial; serial->frontend = frontend_handle; { char *msg = dupprintf("Opening serial device %s", cfg->serline); logevent(serial->frontend, msg); } { /* * Munge the string supplied by the user into a Windows filename. * |
︙ | ︙ | |||
243 244 245 246 247 248 249 | * So, we believe that prepending "\\.\" should always be the * Right Thing. However, just in case someone finds something to * talk to that doesn't exist under there, if the serial line * contains a backslash, we use it verbatim. (This also lets * existing configurations using \\.\ continue working.) */ char *serfilename = | | > > | | | | | 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 | * So, we believe that prepending "\\.\" should always be the * Right Thing. However, just in case someone finds something to * talk to that doesn't exist under there, if the serial line * contains a backslash, we use it verbatim. (This also lets * existing configurations using \\.\ continue working.) */ char *serfilename = dupprintf("%s%s", strchr(cfg->serline, '\\') ? "" : "\\\\.\\", cfg->serline); serport = CreateFile(serfilename, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); sfree(serfilename); } if (serport == INVALID_HANDLE_VALUE) return "Unable to open serial port"; err = serial_configure(serial, serport, cfg); if (err) return err; serial->port = serport; serial->out = handle_output_new(serport, serial_sentdata, serial, HANDLE_FLAG_OVERLAPPED); serial->in = handle_input_new(serport, serial_gotdata, serial, HANDLE_FLAG_OVERLAPPED | HANDLE_FLAG_IGNOREEOF | HANDLE_FLAG_UNITBUFFER); *realhost = dupstr(cfg->serline); /* * Specials are always available. */ update_specials_menu(serial->frontend); return NULL; } static void serial_free(void *handle) { Serial serial = (Serial) handle; serial_terminate(serial); expire_timer_context(serial); sfree(serial); } static void serial_reconfig(void *handle, Config *cfg) { Serial serial = (Serial) handle; const char *err; err = serial_configure(serial, serial->port, cfg); /* * FIXME: what should we do if err returns something? */ } /* |
︙ | ︙ | |||
327 328 329 330 331 332 333 | */ static void serial_size(void *handle, int width, int height) { /* Do nothing! */ return; } | | | | 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 | */ static void serial_size(void *handle, int width, int height) { /* Do nothing! */ return; } static void serbreak_timer(void *ctx, long now) { Serial serial = (Serial)ctx; if (now >= serial->clearbreak_time && serial->port) { ClearCommBreak(serial->port); serial->break_in_progress = FALSE; logevent(serial->frontend, "Finished serial break"); } } /* |
︙ | ︙ |
Changes to windows/winsftp.c.
︙ | ︙ | |||
16 17 18 19 20 21 22 | int ret; ret = cmdline_get_passwd_input(p, in, inlen); if (ret == -1) ret = console_get_userpass_input(p, in, inlen); return ret; } | | | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | int ret; ret = cmdline_get_passwd_input(p, in, inlen); if (ret == -1) ret = console_get_userpass_input(p, in, inlen); return ret; } void platform_get_x11_auth(struct X11Display *display, const Config *cfg) { /* Do nothing, therefore no auth. */ } const int platform_uses_x11_unix_by_default = TRUE; /* ---------------------------------------------------------------------- * File access abstraction. |
︙ | ︙ | |||
84 85 86 87 88 89 90 | } while(0) struct RFile { HANDLE h; }; RFile *open_existing_file(char *name, uint64 *size, | | < | 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | } while(0) struct RFile { HANDLE h; }; RFile *open_existing_file(char *name, uint64 *size, unsigned long *mtime, unsigned long *atime) { HANDLE h; RFile *ret; h = CreateFile(name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); if (h == INVALID_HANDLE_VALUE) |
︙ | ︙ | |||
110 111 112 113 114 115 116 | GetFileTime(h, NULL, &actime, &wrtime); if (atime) TIME_WIN_TO_POSIX(actime, *atime); if (mtime) TIME_WIN_TO_POSIX(wrtime, *mtime); } | < < < | 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | GetFileTime(h, NULL, &actime, &wrtime); if (atime) TIME_WIN_TO_POSIX(actime, *atime); if (mtime) TIME_WIN_TO_POSIX(wrtime, *mtime); } return ret; } int read_from_file(RFile *f, void *buffer, int length) { int ret; DWORD read; |
︙ | ︙ | |||
137 138 139 140 141 142 143 | sfree(f); } struct WFile { HANDLE h; }; | | | 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | sfree(f); } struct WFile { HANDLE h; }; WFile *open_new_file(char *name) { HANDLE h; WFile *ret; h = CreateFile(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); if (h == INVALID_HANDLE_VALUE) |
︙ | ︙ | |||
482 483 484 485 486 487 488 | return NULL; } extern int select_result(WPARAM, LPARAM); int do_eventsel_loop(HANDLE other_event) { int n, nhandles, nallhandles, netindex, otherindex; | | < | < < | < | < | < < | 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 | return NULL; } extern int select_result(WPARAM, LPARAM); int do_eventsel_loop(HANDLE other_event) { int n, nhandles, nallhandles, netindex, otherindex; long next, ticks; HANDLE *handles; SOCKET *sklist; int skcount; long now = GETTICKCOUNT(); if (run_timers(now, &next)) { ticks = next - GETTICKCOUNT(); if (ticks < 0) ticks = 0; /* just in case */ } else { ticks = INFINITE; } handles = handle_get_events(&nhandles); handles = sresize(handles, nhandles+2, HANDLE); nallhandles = nhandles; |
︙ | ︙ | |||
583 584 585 586 587 588 589 | } sfree(sklist); } sfree(handles); | < < | 572 573 574 575 576 577 578 579 580 581 582 583 584 585 | } sfree(sklist); } sfree(handles); if (n == WAIT_TIMEOUT) { now = next; } else { now = GETTICKCOUNT(); } if (otherindex >= 0 && n == WAIT_OBJECT_0 + otherindex) |
︙ | ︙ | |||
611 612 613 614 615 616 617 | * ssh_sftp_get_cmdline() using a parallel mechanism. */ int ssh_sftp_loop_iteration(void) { if (p_WSAEventSelect == NULL) { fd_set readfds; int ret; | | | < < | < | < | | 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 | * ssh_sftp_get_cmdline() using a parallel mechanism. */ int ssh_sftp_loop_iteration(void) { if (p_WSAEventSelect == NULL) { fd_set readfds; int ret; long now = GETTICKCOUNT(); if (sftp_ssh_socket == INVALID_SOCKET) return -1; /* doom */ if (socket_writable(sftp_ssh_socket)) select_result((WPARAM) sftp_ssh_socket, (LPARAM) FD_WRITE); do { long next, ticks; struct timeval tv, *ptv; if (run_timers(now, &next)) { ticks = next - GETTICKCOUNT(); if (ticks <= 0) ticks = 1; /* just in case */ tv.tv_sec = ticks / 1000; tv.tv_usec = ticks % 1000 * 1000; ptv = &tv; } else { ptv = NULL; } |
︙ | ︙ |
Deleted windows/winshare.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to windows/winstore.c.
︙ | ︙ | |||
146 147 148 149 150 151 152 | } sfree(p); return (void *) sesskey; } | | | | < < < | < < < < < < | | < < < | | | < | < | < | < | | < < < < | | < < < < | | | | | < < < < | < | | | | | | | < < < < < < | | | 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 | } sfree(p); return (void *) sesskey; } char *read_setting_s(void *handle, const char *key, char *buffer, int buflen) { DWORD type, size; size = buflen; if (!handle || RegQueryValueEx((HKEY) handle, key, 0, &type, buffer, &size) != ERROR_SUCCESS || type != REG_SZ) return NULL; else return buffer; } int read_setting_i(void *handle, const char *key, int defvalue) { DWORD type, val, size; size = sizeof(val); if (!handle || RegQueryValueEx((HKEY) handle, key, 0, &type, (BYTE *) &val, &size) != ERROR_SUCCESS || size != sizeof(val) || type != REG_DWORD) return defvalue; else return val; } int read_setting_fontspec(void *handle, const char *name, FontSpec *result) { char *settingname; FontSpec ret; if (!read_setting_s(handle, name, ret.name, sizeof(ret.name))) return 0; settingname = dupcat(name, "IsBold", NULL); ret.isbold = read_setting_i(handle, settingname, -1); sfree(settingname); if (ret.isbold == -1) return 0; settingname = dupcat(name, "CharSet", NULL); ret.charset = read_setting_i(handle, settingname, -1); sfree(settingname); if (ret.charset == -1) return 0; settingname = dupcat(name, "Height", NULL); ret.height = read_setting_i(handle, settingname, INT_MIN); sfree(settingname); if (ret.height == INT_MIN) return 0; *result = ret; return 1; } void write_setting_fontspec(void *handle, const char *name, FontSpec font) { char *settingname; write_setting_s(handle, name, font.name); settingname = dupcat(name, "IsBold", NULL); write_setting_i(handle, settingname, font.isbold); sfree(settingname); settingname = dupcat(name, "CharSet", NULL); write_setting_i(handle, settingname, font.charset); sfree(settingname); settingname = dupcat(name, "Height", NULL); write_setting_i(handle, settingname, font.height); sfree(settingname); } int read_setting_filename(void *handle, const char *name, Filename *result) { return !!read_setting_s(handle, name, result->path, sizeof(result->path)); } void write_setting_filename(void *handle, const char *name, Filename result) { write_setting_s(handle, name, result.path); } void close_settings_r(void *handle) { RegCloseKey((HKEY) handle); } |
︙ | ︙ | |||
351 352 353 354 355 356 357 358 359 360 361 362 | len = 1 + strlen(key); /* * Now read a saved key in from the registry and see what it * says. */ regname = snewn(3 * (strlen(hostname) + strlen(keytype)) + 15, char); hostkey_regname(regname, hostname, port, keytype); if (RegOpenKey(HKEY_CURRENT_USER, PUTTY_REG_POS "\\SshHostKeys", | > | < | < < | 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 | len = 1 + strlen(key); /* * Now read a saved key in from the registry and see what it * says. */ otherstr = snewn(len, char); regname = snewn(3 * (strlen(hostname) + strlen(keytype)) + 15, char); hostkey_regname(regname, hostname, port, keytype); if (RegOpenKey(HKEY_CURRENT_USER, PUTTY_REG_POS "\\SshHostKeys", &rkey) != ERROR_SUCCESS) return 1; /* key does not exist in registry */ readlen = len; ret = RegQueryValueEx(rkey, regname, NULL, &type, otherstr, &readlen); if (ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA && !strcmp(keytype, "rsa")) { /* * Key didn't exist. If the key type is RSA, we'll try * another trick, which is to look up the _old_ key format |
︙ | ︙ | |||
425 426 427 428 429 430 431 | * format. If not, we'll assume something odd went * wrong, and hyper-cautiously do nothing. */ if (!strcmp(otherstr, key)) RegSetValueEx(rkey, regname, 0, REG_SZ, otherstr, strlen(otherstr) + 1); } | < < | 388 389 390 391 392 393 394 395 396 397 398 399 400 401 | * format. If not, we'll assume something odd went * wrong, and hyper-cautiously do nothing. */ if (!strcmp(otherstr, key)) RegSetValueEx(rkey, regname, 0, REG_SZ, otherstr, strlen(otherstr) + 1); } } RegCloseKey(rkey); compare = strcmp(otherstr, key); sfree(otherstr); |
︙ | ︙ | |||
471 472 473 474 475 476 477 | /* * Open (or delete) the random seed file. */ enum { DEL, OPEN_R, OPEN_W }; static int try_random_seed(char const *path, int action, HANDLE *ret) { if (action == DEL) { | | < < < | 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 | /* * Open (or delete) the random seed file. */ enum { DEL, OPEN_R, OPEN_W }; static int try_random_seed(char const *path, int action, HANDLE *ret) { if (action == DEL) { remove(path); *ret = INVALID_HANDLE_VALUE; return FALSE; /* so we'll do the next ones too */ } *ret = CreateFile(path, action == OPEN_W ? GENERIC_WRITE : GENERIC_READ, action == OPEN_W ? 0 : (FILE_SHARE_READ | |
︙ | ︙ | |||
745 746 747 748 749 750 751 | old_value = new_value; } else ret = ERROR_SUCCESS; /* * Either return or free the result. */ | | | 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 | old_value = new_value; } else ret = ERROR_SUCCESS; /* * Either return or free the result. */ if (out) *out = old_value; else sfree(old_value); /* Clean up and return. */ RegCloseKey(pjumplist_key); |
︙ | ︙ | |||
778 779 780 781 782 783 784 | /* Returns the jumplist entries from the registry. Caller must free * the returned pointer. */ char *get_jumplist_registry_entries (void) { char *list_value; | | | 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 | /* Returns the jumplist entries from the registry. Caller must free * the returned pointer. */ char *get_jumplist_registry_entries (void) { char *list_value; if (transform_jumplist_registry(NULL,NULL,&list_value) != ERROR_SUCCESS) { list_value = snewn(2, char); *list_value = '\0'; *(list_value + 1) = '\0'; } return list_value; } |
︙ | ︙ |
Changes to windows/winstuff.h.
︙ | ︙ | |||
12 13 14 15 16 17 18 | #include <stdio.h> /* for FILENAME_MAX */ #include "tree234.h" #include "winhelp.h" struct Filename { | | | | < < | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | #include <stdio.h> /* for FILENAME_MAX */ #include "tree234.h" #include "winhelp.h" struct Filename { char path[FILENAME_MAX]; }; #define f_open(filename, mode, isprivate) ( fopen((filename).path, (mode)) ) struct FontSpec { char name[64]; int isbold; int height; int charset; }; #ifndef CLEARTYPE_QUALITY #define CLEARTYPE_QUALITY 5 #endif #define FONT_QUALITY(fq) ( \ (fq) == FQ_DEFAULT ? DEFAULT_QUALITY : \ (fq) == FQ_ANTIALIASED ? ANTIALIASED_QUALITY : \ |
︙ | ︙ | |||
71 72 73 74 75 76 77 | #define LONG_PTR LONG #endif #define BOXFLAGS DLGWINDOWEXTRA #define BOXRESULT (DLGWINDOWEXTRA + sizeof(LONG_PTR)) #define DF_END 0x0001 | < < < < | 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | #define LONG_PTR LONG #endif #define BOXFLAGS DLGWINDOWEXTRA #define BOXRESULT (DLGWINDOWEXTRA + sizeof(LONG_PTR)) #define DF_END 0x0001 /* * Dynamically linked functions. These come in two flavours: * * - GET_WINDOWS_FUNCTION does not expose "name" to the preprocessor, * so will always dynamically link against exactly what is specified * in "name". If you're not sure, use this one. * |
︙ | ︙ | |||
117 118 119 120 121 122 123 | #else #define GLOBAL extern #endif #endif #ifndef DONE_TYPEDEFS #define DONE_TYPEDEFS | | | 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | #else #define GLOBAL extern #endif #endif #ifndef DONE_TYPEDEFS #define DONE_TYPEDEFS typedef struct config_tag Config; typedef struct backend_tag Backend; typedef struct terminal_tag Terminal; #endif #define PUTTY_REG_POS "Software\\SimonTatham\\PuTTY" #define PUTTY_REG_PARENT "Software\\SimonTatham" #define PUTTY_REG_PARENT_CHILD "PuTTY" |
︙ | ︙ | |||
145 146 147 148 149 150 151 | #define PUTTY_HELP_CONTENTS "putty.cnt" #define GETTICKCOUNT GetTickCount #define CURSORBLINK GetCaretBlinkTime() #define TICKSPERSEC 1000 /* GetTickCount returns milliseconds */ #define DEFAULT_CODEPAGE CP_ACP | < | 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | #define PUTTY_HELP_CONTENTS "putty.cnt" #define GETTICKCOUNT GetTickCount #define CURSORBLINK GetCaretBlinkTime() #define TICKSPERSEC 1000 /* GetTickCount returns milliseconds */ #define DEFAULT_CODEPAGE CP_ACP typedef HDC Context; typedef unsigned int uint32; /* int is 32-bits on Win32 and Win64. */ #define PUTTY_UINT32_DEFINED #ifndef NO_GSSAPI |
︙ | ︙ | |||
237 238 239 240 241 242 243 | "All Files (*.*)\0*\0\0\0") #define FILTER_WAVE_FILES ("Wave Files (*.wav)\0*.WAV\0" \ "All Files (*.*)\0*\0\0\0") #define FILTER_DYNLIB_FILES ("Dynamic Library Files (*.dll)\0*.dll\0" \ "All Files (*.*)\0*\0\0\0") /* | | > > > < > > | 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 | "All Files (*.*)\0*\0\0\0") #define FILTER_WAVE_FILES ("Wave Files (*.wav)\0*.WAV\0" \ "All Files (*.*)\0*\0\0\0") #define FILTER_DYNLIB_FILES ("Dynamic Library Files (*.dll)\0*.dll\0" \ "All Files (*.*)\0*\0\0\0") /* * On some versions of Windows, it has been known for WM_TIMER to * occasionally get its callback time simply wrong, and call us * back several minutes early. Defining these symbols enables * compensation code in timing.c. */ #define TIMING_SYNC #define TIMING_SYNC_TICKCOUNT /* * winnet.c dynamically loads WinSock 2 or WinSock 1 depending on * what it can get, which means any WinSock routines used outside * that module must be exported from it as function pointers. So * here they are. */ |
︙ | ︙ | |||
284 285 286 287 288 289 290 | * Exports from winutils.c. */ typedef struct filereq_tag filereq; /* cwd for file requester */ BOOL request_file(filereq *state, OPENFILENAME *of, int preserve, int save); filereq *filereq_new(void); void filereq_free(filereq *state); int message_box(LPCTSTR text, LPCTSTR caption, DWORD style, DWORD helpctxid); | < | 281 282 283 284 285 286 287 288 289 290 291 292 293 294 | * Exports from winutils.c. */ typedef struct filereq_tag filereq; /* cwd for file requester */ BOOL request_file(filereq *state, OPENFILENAME *of, int preserve, int save); filereq *filereq_new(void); void filereq_free(filereq *state); int message_box(LPCTSTR text, LPCTSTR caption, DWORD style, DWORD helpctxid); void split_into_argv(char *, int *, char ***, char ***); /* * Private structure for prefslist state. Only in the header file * so that we can delegate allocation to callers. */ struct prefslist { |
︙ | ︙ | |||
462 463 464 465 466 467 468 | /* * Exports from winmisc.c. */ extern OSVERSIONINFO osVersion; BOOL init_winver(void); HMODULE load_system32_dll(const char *libname); | < | < < < > > > > > > > > | 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 | /* * Exports from winmisc.c. */ extern OSVERSIONINFO osVersion; BOOL init_winver(void); HMODULE load_system32_dll(const char *libname); /* * Exports from sizetip.c. */ void UpdateSizeTip(HWND src, int cx, int cy); void EnableSizeTip(int bEnable); /* * Exports from unicode.c. */ struct unicode_data; void init_ucs(Config *, struct unicode_data *); /* * Exports from winhandl.c. */ #define HANDLE_FLAG_OVERLAPPED 1 #define HANDLE_FLAG_IGNOREEOF 2 #define HANDLE_FLAG_UNITBUFFER 4 struct handle; typedef int (*handle_inputfn_t)(struct handle *h, void *data, int len); typedef void (*handle_outputfn_t)(struct handle *h, int new_backlog); struct handle *handle_input_new(HANDLE handle, handle_inputfn_t gotdata, void *privdata, int flags); struct handle *handle_output_new(HANDLE handle, handle_outputfn_t sentdata, void *privdata, int flags); int handle_write(struct handle *h, const void *data, int len); HANDLE *handle_get_events(int *nevents); void handle_free(struct handle *h); void handle_got_event(HANDLE event); void handle_unthrottle(struct handle *h, int backlog); int handle_backlog(struct handle *h); void *handle_get_privdata(struct handle *h); /* * winpgntc.c needs to schedule callbacks for asynchronous agent * requests. This has to be done differently in GUI and console, so * there's an exported function used for the purpose. * * Also, we supply FLAG_SYNCAGENT to force agent requests to be * synchronous in pscp and psftp. */ void agent_schedule_callback(void (*callback)(void *, void *, int), void *callback_ctx, void *data, int len); #define FLAG_SYNCAGENT 0x1000 /* * winpgntc.c also exports these two functions which are used by the * server side of Pageant as well, to get the user SID for comparing * with clients'. */ int init_advapi(void); /* initialises everything needed by get_user_sid */ PSID get_user_sid(void); /* * Exports from winser.c. */ extern Backend serial_backend; /* * Exports from winjump.c. |
︙ | ︙ |
Changes to windows/winucs.c.
︙ | ︙ | |||
386 387 388 389 390 391 392 | char *name; int codepage; int cp_size; const wchar_t *cp_table; }; static const struct cp_list_item cp_list[] = { | < < > > < | < | < < | | | | | 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 | char *name; int codepage; int cp_size; const wchar_t *cp_table; }; static const struct cp_list_item cp_list[] = { {"ISO-8859-1:1998 (Latin-1, West Europe)", 0, 96, iso_8859_1}, {"ISO-8859-2:1999 (Latin-2, East Europe)", 0, 96, iso_8859_2}, {"ISO-8859-3:1999 (Latin-3, South Europe)", 0, 96, iso_8859_3}, {"ISO-8859-4:1998 (Latin-4, North Europe)", 0, 96, iso_8859_4}, {"ISO-8859-5:1999 (Latin/Cyrillic)", 0, 96, iso_8859_5}, {"ISO-8859-6:1999 (Latin/Arabic)", 0, 96, iso_8859_6}, {"ISO-8859-7:1987 (Latin/Greek)", 0, 96, iso_8859_7}, {"ISO-8859-8:1999 (Latin/Hebrew)", 0, 96, iso_8859_8}, {"ISO-8859-9:1999 (Latin-5, Turkish)", 0, 96, iso_8859_9}, {"ISO-8859-10:1998 (Latin-6, Nordic)", 0, 96, iso_8859_10}, {"ISO-8859-11:2001 (Latin/Thai)", 0, 96, iso_8859_11}, {"ISO-8859-13:1998 (Latin-7, Baltic)", 0, 96, iso_8859_13}, {"ISO-8859-14:1998 (Latin-8, Celtic)", 0, 96, iso_8859_14}, {"ISO-8859-15:1999 (Latin-9, \"euro\")", 0, 96, iso_8859_15}, {"ISO-8859-16:2001 (Latin-10, Balkan)", 0, 96, iso_8859_16}, {"UTF-8", CP_UTF8}, {"KOI8-U", 0, 128, koi8_u}, {"KOI8-R", 20866}, {"HP-ROMAN8", 0, 96, roman8}, {"VSCII", 0, 256, vscii}, {"DEC-MCS", 0, 96, dec_mcs}, {"Win1250 (Central European)", 1250}, {"Win1251 (Cyrillic)", 1251}, {"Win1252 (Western)", 1252}, {"Win1253 (Greek)", 1253}, {"Win1254 (Turkish)", 1254}, {"Win1255 (Hebrew)", 1255}, {"Win1256 (Arabic)", 1256}, {"Win1257 (Baltic)", 1257}, {"Win1258 (Vietnamese)", 1258}, {"CP437", 437}, {"CP620 (Mazovia)", 0, 128, mazovia}, {"CP819", 28591}, {"CP878", 20866}, {"Use font encoding", -1}, {0, 0} }; static void link_font(WCHAR * line_tbl, WCHAR * font_tbl, WCHAR attr); void init_ucs(Config *cfg, struct unicode_data *ucsdata) { int i, j; int used_dtf = 0; char tbuf[256]; for (i = 0; i < 256; i++) tbuf[i] = i; /* Decide on the Line and Font codepages */ ucsdata->line_codepage = decode_codepage(cfg->line_codepage); if (ucsdata->font_codepage <= 0) { ucsdata->font_codepage=0; ucsdata->dbcs_screenfont=0; } if (cfg->vtmode == VT_OEMONLY) { ucsdata->font_codepage = 437; ucsdata->dbcs_screenfont = 0; if (ucsdata->line_codepage <= 0) ucsdata->line_codepage = GetACP(); } else if (ucsdata->line_codepage <= 0) ucsdata->line_codepage = ucsdata->font_codepage; /* Collect screen font ucs table */ if (ucsdata->dbcs_screenfont || ucsdata->font_codepage == 0) { get_unitab(ucsdata->font_codepage, ucsdata->unitab_font, 2); for (i = 128; i < 256; i++) ucsdata->unitab_font[i] = (WCHAR) (CSET_ACP + i); } else { get_unitab(ucsdata->font_codepage, ucsdata->unitab_font, 1); /* CP437 fonts are often broken ... */ if (ucsdata->font_codepage == 437) ucsdata->unitab_font[0] = ucsdata->unitab_font[255] = 0xFFFF; } if (cfg->vtmode == VT_XWINDOWS) memcpy(ucsdata->unitab_font + 1, unitab_xterm_std, sizeof(unitab_xterm_std)); /* Collect OEMCP ucs table */ get_unitab(CP_OEMCP, ucsdata->unitab_oemcp, 1); /* Collect CP437 ucs table for SCO acs */ if (cfg->vtmode == VT_OEMANSI || cfg->vtmode == VT_XWINDOWS) memcpy(ucsdata->unitab_scoacs, ucsdata->unitab_oemcp, sizeof(ucsdata->unitab_scoacs)); else get_unitab(437, ucsdata->unitab_scoacs, 1); /* Collect line set ucs table */ if (ucsdata->line_codepage == ucsdata->font_codepage && (ucsdata->dbcs_screenfont || cfg->vtmode == VT_POORMAN || ucsdata->font_codepage==0)) { /* For DBCS and POOR fonts force direct to font */ used_dtf = 1; for (i = 0; i < 32; i++) ucsdata->unitab_line[i] = (WCHAR) i; for (i = 32; i < 256; i++) ucsdata->unitab_line[i] = (WCHAR) (CSET_ACP + i); |
︙ | ︙ | |||
560 561 562 563 564 565 566 | || (ucsdata->unitab_line[i] >= 0x7F && ucsdata->unitab_line[i] < 0xA0)) ucsdata->unitab_ctrl[i] = i; else ucsdata->unitab_ctrl[i] = 0xFF; /* Generate line->screen direct conversion links. */ | | | | | 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 | || (ucsdata->unitab_line[i] >= 0x7F && ucsdata->unitab_line[i] < 0xA0)) ucsdata->unitab_ctrl[i] = i; else ucsdata->unitab_ctrl[i] = 0xFF; /* Generate line->screen direct conversion links. */ if (cfg->vtmode == VT_OEMANSI || cfg->vtmode == VT_XWINDOWS) link_font(ucsdata->unitab_scoacs, ucsdata->unitab_oemcp, CSET_OEMCP); link_font(ucsdata->unitab_line, ucsdata->unitab_font, CSET_ACP); link_font(ucsdata->unitab_scoacs, ucsdata->unitab_font, CSET_ACP); link_font(ucsdata->unitab_xterm, ucsdata->unitab_font, CSET_ACP); if (cfg->vtmode == VT_OEMANSI || cfg->vtmode == VT_XWINDOWS) { link_font(ucsdata->unitab_line, ucsdata->unitab_oemcp, CSET_OEMCP); link_font(ucsdata->unitab_xterm, ucsdata->unitab_oemcp, CSET_OEMCP); } if (ucsdata->dbcs_screenfont && ucsdata->font_codepage != ucsdata->line_codepage) { /* F***ing Microsoft fonts, Japanese and Korean codepage fonts * have a currency symbol at 0x5C but their unicode value is * still given as U+005C not the correct U+00A5. */ ucsdata->unitab_line['\\'] = CSET_OEMCP + '\\'; } /* Last chance, if !unicode then try poorman links. */ if (cfg->vtmode != VT_UNICODE) { static const char poorman_scoacs[] = "CueaaaaceeeiiiAAE**ooouuyOUc$YPsaiounNao?++**!<>###||||++||++++++--|-+||++--|-+----++++++++##||#aBTPEsyt******EN=+><++-=... n2* "; static const char poorman_latin1[] = " !cL.Y|S\"Ca<--R~o+23'u|.,1o>///?AAAAAAACEEEEIIIIDNOOOOOxOUUUUYPBaaaaaaaceeeeiiiionooooo/ouuuuypy"; static const char poorman_vt100[] = "*#****o~**+++++-----++++|****L."; for (i = 160; i < 256; i++) |
︙ | ︙ | |||
1012 1013 1014 1015 1016 1017 1018 | int decode_codepage(char *cp_name) { char *s, *d; const struct cp_list_item *cpi; int codepage = -1; CPINFO cpinfo; | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > | | | | | | | | | | | | | | | | | | | | | | | | | > | | < | | < | | | | | | | | | | | > | 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 | int decode_codepage(char *cp_name) { char *s, *d; const struct cp_list_item *cpi; int codepage = -1; CPINFO cpinfo; if (!*cp_name) { /* * Here we select a plausible default code page based on * the locale the user is in. We wish to select an ISO code * page or appropriate local default _rather_ than go with * the Win125* series, because it's more important to have * CSI and friends enabled by default than the ghastly * Windows extra quote characters, and because it's more * likely the user is connecting to a remote server that * does something Unixy or VMSy and hence standards- * compliant than that they're connecting back to a Windows * box using horrible nonstandard charsets. * * Accordingly, Robert de Bath suggests a method for * picking a default character set that runs as follows: * first call GetACP to get the system's ANSI code page * identifier, and translate as follows: * * 1250 -> ISO 8859-2 * 1251 -> KOI8-U * 1252 -> ISO 8859-1 * 1253 -> ISO 8859-7 * 1254 -> ISO 8859-9 * 1255 -> ISO 8859-8 * 1256 -> ISO 8859-6 * 1257 -> ISO 8859-13 (changed from 8859-4 on advice of a Lithuanian) * * and for anything else, choose direct-to-font. */ int cp = GetACP(); switch (cp) { case 1250: cp_name = "ISO-8859-2"; break; case 1251: cp_name = "KOI8-U"; break; case 1252: cp_name = "ISO-8859-1"; break; case 1253: cp_name = "ISO-8859-7"; break; case 1254: cp_name = "ISO-8859-9"; break; case 1255: cp_name = "ISO-8859-8"; break; case 1256: cp_name = "ISO-8859-6"; break; case 1257: cp_name = "ISO-8859-13"; break; /* default: leave it blank, which will select -1, direct->font */ } } if (cp_name && *cp_name) for (cpi = cp_list; cpi->name; cpi++) { s = cp_name; d = cpi->name; for (;;) { while (*s && !isalnum(*s) && *s != ':') s++; while (*d && !isalnum(*d) && *d != ':') d++; if (*s == 0) { codepage = cpi->codepage; if (codepage == CP_UTF8) goto break_break; if (codepage == -1) return codepage; if (codepage == 0) { codepage = 65536 + (cpi - cp_list); goto break_break; } if (GetCPInfo(codepage, &cpinfo) != 0) goto break_break; } if (tolower(*s++) != tolower(*d++)) break; } } if (cp_name && *cp_name) { d = cp_name; if (tolower(d[0]) == 'c' && tolower(d[1]) == 'p') d += 2; if (tolower(d[0]) == 'i' && tolower(d[1]) == 'b' && tolower(d[2]) == 'm') d += 3; for (s = d; *s >= '0' && *s <= '9'; s++); if (*s == 0 && s != d) codepage = atoi(d); /* CP999 or IBM999 */ if (codepage == CP_ACP) codepage = GetACP(); if (codepage == CP_OEMCP) codepage = GetOEMCP(); if (codepage > 65535) codepage = -2; } break_break:; if (codepage != -1) { if (codepage != CP_UTF8 && codepage < 65536) { if (GetCPInfo(codepage, &cpinfo) == 0) { codepage = -2; } else if (cpinfo.MaxCharSize > 1) |
︙ | ︙ | |||
1160 1161 1162 1163 1164 1165 1166 | for (i = 0; i < max; i++) unitab[i] = i; for (i = j; i < max; i++) unitab[i] = cp_list[codepage & 0xFFFF].cp_table[i - j]; } } | | | 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 | for (i = 0; i < max; i++) unitab[i] = i; for (i = j; i < max; i++) unitab[i] = cp_list[codepage & 0xFFFF].cp_table[i - j]; } } int wc_to_mb(int codepage, int flags, wchar_t *wcstr, int wclen, char *mbstr, int mblen, char *defchr, int *defused, struct unicode_data *ucsdata) { char *p; int i; if (ucsdata && codepage == ucsdata->line_codepage && ucsdata->uni_tbl) { /* Do this by array lookup if we can. */ |
︙ | ︙ | |||
1198 1199 1200 1201 1202 1203 1204 | } return p - mbstr; } else return WideCharToMultiByte(codepage, flags, wcstr, wclen, mbstr, mblen, defchr, defused); } | | | 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 | } return p - mbstr; } else return WideCharToMultiByte(codepage, flags, wcstr, wclen, mbstr, mblen, defchr, defused); } int mb_to_wc(int codepage, int flags, char *mbstr, int mblen, wchar_t *wcstr, int wclen) { return MultiByteToWideChar(codepage, flags, mbstr, mblen, wcstr, wclen); } int is_dbcs_leadbyte(int codepage, char byte) { return IsDBCSLeadByteEx(codepage, byte); } |
Changes to windows/winutils.c.
︙ | ︙ | |||
147 148 149 150 151 152 153 | "PuTTY Master Key (DSA), 1024-bit:\n" " " PGP_DSA_MASTER_KEY_FP, "PGP fingerprints", MB_ICONINFORMATION | MB_OK, HELPCTXID(pgp_fingerprints)); } /* | < < < < < < < < < < < < < < < < < < < | | | | | | < < < < < < < < < | < | 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | "PuTTY Master Key (DSA), 1024-bit:\n" " " PGP_DSA_MASTER_KEY_FP, "PGP fingerprints", MB_ICONINFORMATION | MB_OK, HELPCTXID(pgp_fingerprints)); } /* * Split a complete command line into argc/argv, attempting to do * it exactly the same way Windows itself would do it (so that * console utilities, which receive argc and argv from Windows, * will have their command lines processed in the same way as GUI * utilities which get a whole command line and must break it * themselves). * * Does not modify the input command line. * * The final parameter (argstart) is used to return a second array * of char * pointers, the same length as argv, each one pointing * at the start of the corresponding element of argv in the * original command line. So if you get half way through processing * your command line in argc/argv form and then decide you want to * treat the rest as a raw string, you can. If you don't want to, * `argstart' can be safely left NULL. */ void split_into_argv(char *cmdline, int *argc, char ***argv, char ***argstart) { char *p; char *outputline, *q; char **outputargv, **outputargstart; int outputargc; /* * At first glance the rules appeared to be: * * - Single quotes are not special characters. * * - Double quotes are removed, but within them spaces cease * to be special. * * - Backslashes are _only_ special when a sequence of them |
︙ | ︙ |
Changes to windows/winx11.c.
1 2 3 4 5 6 7 8 9 10 11 | /* * winx11.c: fetch local auth data for X forwarding. */ #include <ctype.h> #include <assert.h> #include <stdlib.h> #include "putty.h" #include "ssh.h" | | < | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | /* * winx11.c: fetch local auth data for X forwarding. */ #include <ctype.h> #include <assert.h> #include <stdlib.h> #include "putty.h" #include "ssh.h" void platform_get_x11_auth(struct X11Display *disp, const Config *cfg) { if (cfg->xauthfile.path[0]) x11_get_auth_from_authfile(disp, cfg->xauthfile.path); } const int platform_uses_x11_unix_by_default = FALSE; |
Changes to x11fwd.c.
︙ | ︙ | |||
22 23 24 25 26 27 28 | }; struct XDMSeen { unsigned int time; unsigned char clientid[6]; }; | | < < | | | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | }; struct XDMSeen { unsigned int time; unsigned char clientid[6]; }; struct X11Private { const struct plug_function_table *fn; /* the above variable absolutely *must* be the first in this structure */ unsigned char firstpkt[12]; /* first X data packet */ struct X11Display *disp; char *auth_protocol; unsigned char *auth_data; int data_read, auth_plen, auth_psize, auth_dlen, auth_dsize; int verified; int throttled, throttle_override; unsigned long peer_ip; int peer_port; void *c; /* data used by ssh.c */ Socket s; }; static int xdmseen_cmp(void *a, void *b) { struct XDMSeen *sa = a, *sb = b; return sa->time > sb->time ? 1 : |
︙ | ︙ | |||
60 61 62 63 64 65 66 | const char *error_msg, int error_code) { } static int dummy_plug_closing (Plug p, const char *error_msg, int error_code, int calling_back) { return 1; } static int dummy_plug_receive(Plug p, int urgent, char *data, int len) { return 1; } static void dummy_plug_sent(Plug p, int bufsize) { } | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > > | 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | const char *error_msg, int error_code) { } static int dummy_plug_closing (Plug p, const char *error_msg, int error_code, int calling_back) { return 1; } static int dummy_plug_receive(Plug p, int urgent, char *data, int len) { return 1; } static void dummy_plug_sent(Plug p, int bufsize) { } static int dummy_plug_accepting(Plug p, OSSocket sock) { return 1; } static const struct plug_function_table dummy_plug = { dummy_plug_log, dummy_plug_closing, dummy_plug_receive, dummy_plug_sent, dummy_plug_accepting }; struct X11Display *x11_setup_display(char *display, int authtype, const Config *cfg) { struct X11Display *disp = snew(struct X11Display); char *localcopy; int i; if (!display || !*display) { localcopy = platform_get_x_display(); if (!localcopy || !*localcopy) { sfree(localcopy); localcopy = dupstr(":0"); /* plausible default for any platform */ } |
︙ | ︙ | |||
282 283 284 285 286 287 288 | * Look up the display hostname, if we need to. */ if (!disp->unixdomain) { const char *err; disp->port = 6000 + disp->displaynum; disp->addr = name_lookup(disp->hostname, disp->port, | | < | 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 | * Look up the display hostname, if we need to. */ if (!disp->unixdomain) { const char *err; disp->port = 6000 + disp->displaynum; disp->addr = name_lookup(disp->hostname, disp->port, &disp->realhost, cfg, ADDRTYPE_UNSPEC); if ((err = sk_addr_error(disp->addr)) != NULL) { sk_addr_free(disp->addr); sfree(disp->hostname); sfree(disp->unixsocketpath); return NULL; /* FIXME: report an error */ } } /* * Try upgrading an IP-style localhost display to a Unix-socket * display (as the standard X connection libraries do). |
︙ | ︙ | |||
329 330 331 332 333 334 335 336 337 338 339 340 341 | if (disp->unixsocketpath) disp->realhost = dupstr(disp->unixsocketpath); else disp->realhost = dupprintf("unix:%d", disp->displaynum); disp->port = 0; } /* * Fetch the local authorisation details. */ disp->localauthproto = X11_NO_AUTH; disp->localauthdata = NULL; disp->localauthdatalen = 0; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > | > > > > > | | < < < | < | < < < < < < < < | | < < < < < < < < < < | < | < | | < < < < < | | | | | | | < < | | 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 | if (disp->unixsocketpath) disp->realhost = dupstr(disp->unixsocketpath); else disp->realhost = dupprintf("unix:%d", disp->displaynum); disp->port = 0; } /* * Invent the remote authorisation details. */ if (authtype == X11_MIT) { disp->remoteauthproto = X11_MIT; /* MIT-MAGIC-COOKIE-1. Cookie size is 128 bits (16 bytes). */ disp->remoteauthdata = snewn(16, unsigned char); for (i = 0; i < 16; i++) disp->remoteauthdata[i] = random_byte(); disp->remoteauthdatalen = 16; disp->xdmseen = NULL; } else { assert(authtype == X11_XDM); disp->remoteauthproto = X11_XDM; /* XDM-AUTHORIZATION-1. Cookie size is 16 bytes; byte 8 is zero. */ disp->remoteauthdata = snewn(16, unsigned char); for (i = 0; i < 16; i++) disp->remoteauthdata[i] = (i == 8 ? 0 : random_byte()); disp->remoteauthdatalen = 16; disp->xdmseen = newtree234(xdmseen_cmp); } disp->remoteauthprotoname = dupstr(x11_authnames[disp->remoteauthproto]); disp->remoteauthdatastring = snewn(disp->remoteauthdatalen * 2 + 1, char); for (i = 0; i < disp->remoteauthdatalen; i++) sprintf(disp->remoteauthdatastring + i*2, "%02x", disp->remoteauthdata[i]); /* * Fetch the local authorisation details. */ disp->localauthproto = X11_NO_AUTH; disp->localauthdata = NULL; disp->localauthdatalen = 0; platform_get_x11_auth(disp, cfg); return disp; } void x11_free_display(struct X11Display *disp) { if (disp->xdmseen != NULL) { struct XDMSeen *seen; while ((seen = delpos234(disp->xdmseen, 0)) != NULL) sfree(seen); freetree234(disp->xdmseen); } sfree(disp->hostname); sfree(disp->unixsocketpath); if (disp->localauthdata) memset(disp->localauthdata, 0, disp->localauthdatalen); sfree(disp->localauthdata); if (disp->remoteauthdata) memset(disp->remoteauthdata, 0, disp->remoteauthdatalen); sfree(disp->remoteauthdata); sfree(disp->remoteauthprotoname); sfree(disp->remoteauthdatastring); sk_addr_free(disp->addr); sfree(disp); } #define XDM_MAXSKEW 20*60 /* 20 minute clock skew should be OK */ static char *x11_verify(unsigned long peer_ip, int peer_port, struct X11Display *disp, char *proto, unsigned char *data, int dlen) { if (strcmp(proto, x11_authnames[disp->remoteauthproto]) != 0) return "wrong authorisation protocol attempted"; if (disp->remoteauthproto == X11_MIT) { if (dlen != disp->remoteauthdatalen) return "MIT-MAGIC-COOKIE-1 data was wrong length"; if (memcmp(disp->remoteauthdata, data, dlen) != 0) return "MIT-MAGIC-COOKIE-1 data did not match"; } if (disp->remoteauthproto == X11_XDM) { unsigned long t; time_t tim; int i; struct XDMSeen *seen, *ret; if (dlen != 24) return "XDM-AUTHORIZATION-1 data was wrong length"; if (peer_port == -1) return "cannot do XDM-AUTHORIZATION-1 without remote address data"; des_decrypt_xdmauth(disp->remoteauthdata+9, data, 24); if (memcmp(disp->remoteauthdata, data, 8) != 0) return "XDM-AUTHORIZATION-1 data failed check"; /* cookie wrong */ if (GET_32BIT_MSB_FIRST(data+8) != peer_ip) return "XDM-AUTHORIZATION-1 data failed check"; /* IP wrong */ if ((int)GET_16BIT_MSB_FIRST(data+12) != peer_port) return "XDM-AUTHORIZATION-1 data failed check"; /* port wrong */ t = GET_32BIT_MSB_FIRST(data+14); for (i = 18; i < 24; i++) if (data[i] != 0) /* zero padding wrong */ return "XDM-AUTHORIZATION-1 data failed check"; tim = time(NULL); if (abs(t - tim) > XDM_MAXSKEW) return "XDM-AUTHORIZATION-1 time stamp was too far out"; seen = snew(struct XDMSeen); seen->time = t; memcpy(seen->clientid, data+8, 6); assert(disp->xdmseen != NULL); ret = add234(disp->xdmseen, seen); if (ret != seen) { sfree(seen); return "XDM-AUTHORIZATION-1 data replayed"; } /* While we're here, purge entries too old to be replayed. */ for (;;) { seen = index234(disp->xdmseen, 0); assert(seen != NULL); if (t - seen->time <= XDM_MAXSKEW) break; sfree(delpos234(disp->xdmseen, 0)); } } /* implement other protocols here if ever required */ return NULL; } void x11_get_auth_from_authfile(struct X11Display *disp, const char *authfilename) { FILE *authfp; char *buf, *ptr, *str[4]; int len[4]; int family, protocol; int ideal_match = FALSE; char *ourhostname = get_hostname(); /* * Normally we should look for precisely the details specified in * `disp'. However, there's an oddity when the display is local: * displays like "localhost:0" usually have their details stored * in a Unix-domain-socket record (even if there isn't actually a * real Unix-domain socket available, as with OpenSSH's proxy X11 |
︙ | ︙ | |||
479 480 481 482 483 484 485 | */ int localhost = !disp->unixdomain && sk_address_is_local(disp->addr); authfp = fopen(authfilename, "rb"); if (!authfp) return; | < < | 369 370 371 372 373 374 375 376 377 378 379 380 381 382 | */ int localhost = !disp->unixdomain && sk_address_is_local(disp->addr); authfp = fopen(authfilename, "rb"); if (!authfp) return; /* Records in .Xauthority contain four strings of up to 64K each */ buf = snewn(65537 * 4, char); while (!ideal_match) { int c, i, j, match = FALSE; #define GET do { c = fgetc(authfp); if (c == EOF) goto done; c = (unsigned char)c; } while (0) |
︙ | ︙ | |||
596 597 598 599 600 601 602 | memcpy(disp->localauthdata, str[3], len[3]); disp->localauthdatalen = len[3]; } } done: fclose(authfp); | | < < < | < | < < < < | < < < < | < < < < | < < < < | < | < | | | | < | | | | 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 | memcpy(disp->localauthdata, str[3], len[3]); disp->localauthdatalen = len[3]; } } done: fclose(authfp); memset(buf, 0, 65537 * 4); sfree(buf); sfree(ourhostname); } static void x11_log(Plug p, int type, SockAddr addr, int port, const char *error_msg, int error_code) { /* We have no interface to the logging module here, so we drop these. */ } static int x11_closing(Plug plug, const char *error_msg, int error_code, int calling_back) { struct X11Private *pr = (struct X11Private *) plug; /* * We have no way to communicate down the forwarded connection, * so if an error occurred on the socket, we just ignore it * and treat it like a proper close. */ sshfwd_close(pr->c); x11_close(pr->s); return 1; } static int x11_receive(Plug plug, int urgent, char *data, int len) { struct X11Private *pr = (struct X11Private *) plug; if (sshfwd_write(pr->c, data, len) > 0) { pr->throttled = 1; sk_set_frozen(pr->s, 1); } return 1; } static void x11_sent(Plug plug, int bufsize) { struct X11Private *pr = (struct X11Private *) plug; sshfwd_unthrottle(pr->c, bufsize); } /* * When setting up X forwarding, we should send the screen number * from the specified local display. This function extracts it from * the display string. */ |
︙ | ︙ | |||
683 684 685 686 687 688 689 | n = strcspn(display, "."); if (!display[n]) return 0; return atoi(display + n + 1); } /* | | < > > > | | > > | | | | | | | | < | < < < < < | < < | > | > > | > | < < | < < | < < | > > > | | < < | | | < < | | | < < | < | | > > > > | < < < | < | < | < | < < | < | < < | < < < < < < < < < < < | > > | < | > | < < < < | | < < < < | > | > > | > | > | | | | | | | | | | | < | | < | | | | | < < < < < < < < < < < < | < | | > < > > > > | < | > > < > | | | | | | < > | | | | | < < | < | < < < | | | | | > | < > | < | | | < | < < < | | | < > > > > > | > | < > > > | | < < < | > > | < | | > | > | > | | | < | > | > | > | < < | < < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 | n = strcspn(display, "."); if (!display[n]) return 0; return atoi(display + n + 1); } /* * Called to set up the raw connection. * * Returns an error message, or NULL on success. * also, fills the SocketsStructure */ extern const char *x11_init(Socket *s, struct X11Display *disp, void *c, const char *peeraddr, int peerport, const Config *cfg) { static const struct plug_function_table fn_table = { x11_log, x11_closing, x11_receive, x11_sent, NULL }; const char *err; struct X11Private *pr; /* * Open socket. */ pr = snew(struct X11Private); pr->fn = &fn_table; pr->auth_protocol = NULL; pr->disp = disp; pr->verified = 0; pr->data_read = 0; pr->throttled = pr->throttle_override = 0; pr->c = c; pr->s = *s = new_connection(sk_addr_dup(disp->addr), disp->realhost, disp->port, 0, 1, 0, 0, (Plug) pr, cfg); if ((err = sk_socket_error(*s)) != NULL) { sfree(pr); return err; } /* * See if we can make sense of the peer address we were given. */ { int i[4]; if (peeraddr && 4 == sscanf(peeraddr, "%d.%d.%d.%d", i+0, i+1, i+2, i+3)) { pr->peer_ip = (i[0] << 24) | (i[1] << 16) | (i[2] << 8) | i[3]; pr->peer_port = peerport; } else { pr->peer_ip = 0; pr->peer_port = -1; } } sk_set_private_ptr(*s, pr); return NULL; } void x11_close(Socket s) { struct X11Private *pr; if (!s) return; pr = (struct X11Private *) sk_get_private_ptr(s); if (pr->auth_protocol) { sfree(pr->auth_protocol); sfree(pr->auth_data); } sfree(pr); sk_close(s); } void x11_unthrottle(Socket s) { struct X11Private *pr; if (!s) return; pr = (struct X11Private *) sk_get_private_ptr(s); pr->throttled = 0; sk_set_frozen(s, pr->throttled || pr->throttle_override); } void x11_override_throttle(Socket s, int enable) { struct X11Private *pr; if (!s) return; pr = (struct X11Private *) sk_get_private_ptr(s); pr->throttle_override = enable; sk_set_frozen(s, pr->throttled || pr->throttle_override); } /* * Called to send data down the raw connection. */ int x11_send(Socket s, char *data, int len) { struct X11Private *pr; if (!s) return 0; pr = (struct X11Private *) sk_get_private_ptr(s); /* * Read the first packet. */ while (len > 0 && pr->data_read < 12) pr->firstpkt[pr->data_read++] = (unsigned char) (len--, *data++); if (pr->data_read < 12) return 0; /* * If we have not allocated the auth_protocol and auth_data * strings, do so now. */ if (!pr->auth_protocol) { pr->auth_plen = GET_16BIT(pr->firstpkt[0], pr->firstpkt + 6); pr->auth_dlen = GET_16BIT(pr->firstpkt[0], pr->firstpkt + 8); pr->auth_psize = (pr->auth_plen + 3) & ~3; pr->auth_dsize = (pr->auth_dlen + 3) & ~3; /* Leave room for a terminating zero, to make our lives easier. */ pr->auth_protocol = snewn(pr->auth_psize + 1, char); pr->auth_data = snewn(pr->auth_dsize, unsigned char); } /* * Read the auth_protocol and auth_data strings. */ while (len > 0 && pr->data_read < 12 + pr->auth_psize) pr->auth_protocol[pr->data_read++ - 12] = (len--, *data++); while (len > 0 && pr->data_read < 12 + pr->auth_psize + pr->auth_dsize) pr->auth_data[pr->data_read++ - 12 - pr->auth_psize] = (unsigned char) (len--, *data++); if (pr->data_read < 12 + pr->auth_psize + pr->auth_dsize) return 0; /* * If we haven't verified the authorisation, do so now. */ if (!pr->verified) { char *err; pr->auth_protocol[pr->auth_plen] = '\0'; /* ASCIZ */ err = x11_verify(pr->peer_ip, pr->peer_port, pr->disp, pr->auth_protocol, pr->auth_data, pr->auth_dlen); /* * If authorisation failed, construct and send an error * packet, then terminate the connection. */ if (err) { char *message; int msglen, msgsize; unsigned char *reply; message = dupprintf("%s X11 proxy: %s", appname, err); msglen = strlen(message); reply = snewn(8 + msglen+1 + 4, unsigned char); /* include zero */ msgsize = (msglen + 3) & ~3; reply[0] = 0; /* failure */ reply[1] = msglen; /* length of reason string */ memcpy(reply + 2, pr->firstpkt + 2, 4); /* major/minor proto vsn */ PUT_16BIT(pr->firstpkt[0], reply + 6, msgsize >> 2);/* data len */ memset(reply + 8, 0, msgsize); memcpy(reply + 8, message, msglen); sshfwd_write(pr->c, (char *)reply, 8 + msgsize); sshfwd_close(pr->c); x11_close(s); sfree(reply); sfree(message); return 0; } /* * Now we know we're going to accept the connection. Strip * the fake auth data, and optionally put real auth data in * instead. */ { char realauthdata[64]; int realauthlen = 0; int authstrlen = strlen(x11_authnames[pr->disp->localauthproto]); int buflen = 0; /* initialise to placate optimiser */ static const char zeroes[4] = { 0,0,0,0 }; void *buf; if (pr->disp->localauthproto == X11_MIT) { assert(pr->disp->localauthdatalen <= lenof(realauthdata)); realauthlen = pr->disp->localauthdatalen; memcpy(realauthdata, pr->disp->localauthdata, realauthlen); } else if (pr->disp->localauthproto == X11_XDM && pr->disp->localauthdatalen == 16 && ((buf = sk_getxdmdata(s, &buflen))!=0)) { time_t t; realauthlen = (buflen+12+7) & ~7; assert(realauthlen <= lenof(realauthdata)); memset(realauthdata, 0, realauthlen); memcpy(realauthdata, pr->disp->localauthdata, 8); memcpy(realauthdata+8, buf, buflen); t = time(NULL); PUT_32BIT_MSB_FIRST(realauthdata+8+buflen, t); des_encrypt_xdmauth(pr->disp->localauthdata+9, (unsigned char *)realauthdata, realauthlen); sfree(buf); } /* implement other auth methods here if required */ PUT_16BIT(pr->firstpkt[0], pr->firstpkt + 6, authstrlen); PUT_16BIT(pr->firstpkt[0], pr->firstpkt + 8, realauthlen); sk_write(s, (char *)pr->firstpkt, 12); if (authstrlen) { sk_write(s, x11_authnames[pr->disp->localauthproto], authstrlen); sk_write(s, zeroes, 3 & (-authstrlen)); } if (realauthlen) { sk_write(s, realauthdata, realauthlen); sk_write(s, zeroes, 3 & (-realauthlen)); } } pr->verified = 1; } /* * After initialisation, just copy data simply. */ return sk_write(s, data, len); } |