mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-26 01:32:25 +00:00
Created a shiny new abstraction for the socket handling. Has many
advantages: - protocol modules can call sk_write() without having to worry about writes blocking, because blocking writes are handled in the abstraction layer and retried later. - `Lost connection while sending' is a thing of the past. - <winsock.h> is no longer needed in most modules, because "putty.h" doesn't have to declare `SOCKET' variables any more, only the abstracted `Socket' type. - select()-equivalent between multiple sockets will now be handled sensibly, which opens the way for things like SSH port forwarding. [originally from svn r744]
This commit is contained in:
parent
882f653081
commit
bbbda4110b
49
Makefile
49
Makefile
@ -54,7 +54,7 @@ RES=res
|
|||||||
GOBJS1 = window.$(OBJ) windlg.$(OBJ) winctrls.$(OBJ) terminal.$(OBJ)
|
GOBJS1 = window.$(OBJ) windlg.$(OBJ) winctrls.$(OBJ) terminal.$(OBJ)
|
||||||
GOBJS2 = xlat.$(OBJ) sizetip.$(OBJ)
|
GOBJS2 = xlat.$(OBJ) sizetip.$(OBJ)
|
||||||
##-- objects putty puttytel plink
|
##-- objects putty puttytel plink
|
||||||
LOBJS1 = telnet.$(OBJ) raw.$(OBJ) ldisc.$(OBJ)
|
LOBJS1 = telnet.$(OBJ) raw.$(OBJ) ldisc.$(OBJ) winnet.$(OBJ)
|
||||||
##-- objects putty plink
|
##-- objects putty plink
|
||||||
POBJS = be_all.$(OBJ)
|
POBJS = be_all.$(OBJ)
|
||||||
##-- objects puttytel
|
##-- objects puttytel
|
||||||
@ -62,13 +62,14 @@ TOBJS = be_nossh.$(OBJ)
|
|||||||
##-- objects plink
|
##-- objects plink
|
||||||
PLOBJS = plink.$(OBJ)
|
PLOBJS = plink.$(OBJ)
|
||||||
##-- objects pscp
|
##-- objects pscp
|
||||||
SOBJS = scp.$(OBJ) be_none.$(OBJ)
|
SOBJS = scp.$(OBJ) winnet.$(OBJ) be_none.$(OBJ)
|
||||||
##-- objects putty puttytel pscp plink
|
##-- objects putty puttytel pscp plink
|
||||||
MOBJS = misc.$(OBJ) version.$(OBJ) winstore.$(OBJ) settings.$(OBJ)
|
MOBJS = misc.$(OBJ) version.$(OBJ) winstore.$(OBJ) settings.$(OBJ)
|
||||||
|
MOBJ2 = tree234.$(OBJ)
|
||||||
##-- objects putty pscp plink
|
##-- objects putty pscp plink
|
||||||
OBJS1 = sshcrc.$(OBJ) sshdes.$(OBJ) sshmd5.$(OBJ) sshrsa.$(OBJ) sshrand.$(OBJ)
|
OBJS1 = sshcrc.$(OBJ) sshdes.$(OBJ) sshmd5.$(OBJ) sshrsa.$(OBJ) sshrand.$(OBJ)
|
||||||
OBJS2 = sshsha.$(OBJ) sshblowf.$(OBJ) noise.$(OBJ) sshdh.$(OBJ) sshdss.$(OBJ)
|
OBJS2 = sshsha.$(OBJ) sshblowf.$(OBJ) noise.$(OBJ) sshdh.$(OBJ) sshdss.$(OBJ)
|
||||||
OBJS3 = sshbn.$(OBJ) sshpubk.$(OBJ) ssh.$(OBJ) pageantc.$(OBJ) tree234.$(OBJ)
|
OBJS3 = sshbn.$(OBJ) sshpubk.$(OBJ) ssh.$(OBJ) pageantc.$(OBJ)
|
||||||
##-- objects pageant
|
##-- objects pageant
|
||||||
PAGE1 = pageant.$(OBJ) sshrsa.$(OBJ) sshpubk.$(OBJ) sshdes.$(OBJ) sshbn.$(OBJ)
|
PAGE1 = pageant.$(OBJ) sshrsa.$(OBJ) sshpubk.$(OBJ) sshdes.$(OBJ) sshbn.$(OBJ)
|
||||||
PAGE2 = sshmd5.$(OBJ) version.$(OBJ) tree234.$(OBJ)
|
PAGE2 = sshmd5.$(OBJ) version.$(OBJ) tree234.$(OBJ)
|
||||||
@ -107,10 +108,10 @@ SOCK2 = ws2_32.lib
|
|||||||
|
|
||||||
all: putty.exe puttytel.exe pscp.exe plink.exe pageant.exe puttygen.exe
|
all: putty.exe puttytel.exe pscp.exe plink.exe pageant.exe puttygen.exe
|
||||||
|
|
||||||
putty.exe: $(GOBJS1) $(GOBJS2) $(LOBJS1) $(POBJS) $(MOBJS) $(OBJS1) $(OBJS2) $(OBJS3) $(PRESRC) putty.rsp
|
putty.exe: $(GOBJS1) $(GOBJS2) $(LOBJS1) $(POBJS) $(MOBJS) $(MOBJ2) $(OBJS1) $(OBJS2) $(OBJS3) $(PRESRC) putty.rsp
|
||||||
link $(LFLAGS) -out:putty.exe @putty.rsp
|
link $(LFLAGS) -out:putty.exe @putty.rsp
|
||||||
|
|
||||||
puttytel.exe: $(GOBJS1) $(GOBJS2) $(LOBJS1) $(TOBJS) $(MOBJS) $(PRESRC) puttytel.rsp
|
puttytel.exe: $(GOBJS1) $(GOBJS2) $(LOBJS1) $(TOBJS) $(MOBJS) $(MOBJ2) $(PRESRC) puttytel.rsp
|
||||||
link $(LFLAGS) -out:puttytel.exe @puttytel.rsp
|
link $(LFLAGS) -out:puttytel.exe @puttytel.rsp
|
||||||
|
|
||||||
pageant.exe: $(PAGE1) $(PAGE2) $(PAGERC) pageant.rsp
|
pageant.exe: $(PAGE1) $(PAGE2) $(PAGERC) pageant.rsp
|
||||||
@ -119,10 +120,10 @@ pageant.exe: $(PAGE1) $(PAGE2) $(PAGERC) pageant.rsp
|
|||||||
puttygen.exe: $(GEN1) $(GEN2) $(GEN3) $(GEN4) $(GENRC) puttygen.rsp
|
puttygen.exe: $(GEN1) $(GEN2) $(GEN3) $(GEN4) $(GENRC) puttygen.rsp
|
||||||
link $(LFLAGS) -out:puttygen.exe @puttygen.rsp
|
link $(LFLAGS) -out:puttygen.exe @puttygen.rsp
|
||||||
|
|
||||||
pscp.exe: $(SOBJS) $(MOBJS) $(OBJS1) $(OBJS2) $(OBJS3) $(SRESRC) pscp.rsp
|
pscp.exe: $(SOBJS) $(MOBJS) $(MOBJ2) $(OBJS1) $(OBJS2) $(OBJS3) $(SRESRC) pscp.rsp
|
||||||
link $(LFLAGS) -out:pscp.exe @pscp.rsp
|
link $(LFLAGS) -out:pscp.exe @pscp.rsp
|
||||||
|
|
||||||
plink.exe: $(LOBJS1) $(POBJS) $(PLOBJS) $(MOBJS) $(OBJS1) $(OBJS2) $(OBJS3) $(LRESRC) plink.rsp
|
plink.exe: $(LOBJS1) $(POBJS) $(PLOBJS) $(MOBJS) $(MOBJ2) $(OBJS1) $(OBJS2) $(OBJS3) $(LRESRC) plink.rsp
|
||||||
link $(LFLAGS) -out:plink.exe @plink.rsp
|
link $(LFLAGS) -out:plink.exe @plink.rsp
|
||||||
|
|
||||||
putty.rsp: makefile
|
putty.rsp: makefile
|
||||||
@ -132,6 +133,7 @@ putty.rsp: makefile
|
|||||||
echo $(LOBJS1) >> putty.rsp
|
echo $(LOBJS1) >> putty.rsp
|
||||||
echo $(POBJS) >> putty.rsp
|
echo $(POBJS) >> putty.rsp
|
||||||
echo $(MOBJS) >> putty.rsp
|
echo $(MOBJS) >> putty.rsp
|
||||||
|
echo $(MOBJ2) >> putty.rsp
|
||||||
echo $(OBJS1) >> putty.rsp
|
echo $(OBJS1) >> putty.rsp
|
||||||
echo $(OBJS2) >> putty.rsp
|
echo $(OBJS2) >> putty.rsp
|
||||||
echo $(OBJS3) >> putty.rsp
|
echo $(OBJS3) >> putty.rsp
|
||||||
@ -147,6 +149,7 @@ puttytel.rsp: makefile
|
|||||||
echo $(LOBJS1) >> puttytel.rsp
|
echo $(LOBJS1) >> puttytel.rsp
|
||||||
echo $(TOBJS) >> puttytel.rsp
|
echo $(TOBJS) >> puttytel.rsp
|
||||||
echo $(MOBJS) >> puttytel.rsp
|
echo $(MOBJS) >> puttytel.rsp
|
||||||
|
echo $(MOBJ2) >> puttytel.rsp
|
||||||
echo $(PRESRC) >> puttytel.rsp
|
echo $(PRESRC) >> puttytel.rsp
|
||||||
echo $(LIBS1) >> puttytel.rsp
|
echo $(LIBS1) >> puttytel.rsp
|
||||||
echo $(LIBS2) >> puttytel.rsp
|
echo $(LIBS2) >> puttytel.rsp
|
||||||
@ -176,6 +179,7 @@ pscp.rsp: makefile
|
|||||||
echo /nologo /subsystem:console > pscp.rsp
|
echo /nologo /subsystem:console > pscp.rsp
|
||||||
echo $(SOBJS) >> pscp.rsp
|
echo $(SOBJS) >> pscp.rsp
|
||||||
echo $(MOBJS) >> pscp.rsp
|
echo $(MOBJS) >> pscp.rsp
|
||||||
|
echo $(MOBJ2) >> pscp.rsp
|
||||||
echo $(OBJS1) >> pscp.rsp
|
echo $(OBJS1) >> pscp.rsp
|
||||||
echo $(OBJS2) >> pscp.rsp
|
echo $(OBJS2) >> pscp.rsp
|
||||||
echo $(OBJS3) >> pscp.rsp
|
echo $(OBJS3) >> pscp.rsp
|
||||||
@ -190,6 +194,7 @@ plink.rsp: makefile
|
|||||||
echo $(POBJS) >> plink.rsp
|
echo $(POBJS) >> plink.rsp
|
||||||
echo $(PLOBJS) >> plink.rsp
|
echo $(PLOBJS) >> plink.rsp
|
||||||
echo $(MOBJS) >> plink.rsp
|
echo $(MOBJS) >> plink.rsp
|
||||||
|
echo $(MOBJ2) >> plink.rsp
|
||||||
echo $(OBJS1) >> plink.rsp
|
echo $(OBJS1) >> plink.rsp
|
||||||
echo $(OBJS2) >> plink.rsp
|
echo $(OBJS2) >> plink.rsp
|
||||||
echo $(OBJS3) >> plink.rsp
|
echo $(OBJS3) >> plink.rsp
|
||||||
@ -199,20 +204,20 @@ plink.rsp: makefile
|
|||||||
echo $(SOCK2) >> plink.rsp
|
echo $(SOCK2) >> plink.rsp
|
||||||
|
|
||||||
##-- dependencies
|
##-- dependencies
|
||||||
window.$(OBJ): window.c putty.h win_res.h storage.h winstuff.h
|
window.$(OBJ): window.c putty.h network.h win_res.h storage.h winstuff.h
|
||||||
windlg.$(OBJ): windlg.c putty.h ssh.h win_res.h winstuff.h
|
windlg.$(OBJ): windlg.c putty.h network.h ssh.h win_res.h winstuff.h
|
||||||
winctrls.$(OBJ): winctrls.c winstuff.h winstuff.h
|
winctrls.$(OBJ): winctrls.c winstuff.h winstuff.h
|
||||||
settings.$(OBJ): settings.c putty.h storage.h
|
settings.$(OBJ): settings.c putty.h network.h storage.h
|
||||||
winstore.$(OBJ): winstore.c putty.h storage.h
|
winstore.$(OBJ): winstore.c putty.h network.h storage.h
|
||||||
terminal.$(OBJ): terminal.c putty.h
|
terminal.$(OBJ): terminal.c putty.h network.h
|
||||||
sizetip.$(OBJ): sizetip.c putty.h winstuff.h
|
sizetip.$(OBJ): sizetip.c putty.h network.h winstuff.h
|
||||||
telnet.$(OBJ): telnet.c putty.h
|
telnet.$(OBJ): telnet.c putty.h network.h
|
||||||
raw.$(OBJ): raw.c putty.h
|
raw.$(OBJ): raw.c putty.h network.h
|
||||||
xlat.$(OBJ): xlat.c putty.h
|
xlat.$(OBJ): xlat.c putty.h network.h
|
||||||
ldisc.$(OBJ): ldisc.c putty.h
|
ldisc.$(OBJ): ldisc.c putty.h network.h
|
||||||
misc.$(OBJ): misc.c putty.h
|
misc.$(OBJ): misc.c putty.h network.h
|
||||||
noise.$(OBJ): noise.c putty.h ssh.h storage.h
|
noise.$(OBJ): noise.c putty.h network.h ssh.h storage.h
|
||||||
ssh.$(OBJ): ssh.c ssh.h putty.h tree234.h
|
ssh.$(OBJ): ssh.c ssh.h putty.h network.h tree234.h
|
||||||
sshcrc.$(OBJ): sshcrc.c ssh.h
|
sshcrc.$(OBJ): sshcrc.c ssh.h
|
||||||
sshdes.$(OBJ): sshdes.c ssh.h
|
sshdes.$(OBJ): sshdes.c ssh.h
|
||||||
sshmd5.$(OBJ): sshmd5.c ssh.h
|
sshmd5.$(OBJ): sshmd5.c ssh.h
|
||||||
@ -224,12 +229,12 @@ sshdh.$(OBJ): sshdh.c ssh.h
|
|||||||
sshdss.$(OBJ): sshdss.c ssh.h
|
sshdss.$(OBJ): sshdss.c ssh.h
|
||||||
sshbn.$(OBJ): sshbn.c ssh.h
|
sshbn.$(OBJ): sshbn.c ssh.h
|
||||||
sshpubk.$(OBJ): sshpubk.c ssh.h
|
sshpubk.$(OBJ): sshpubk.c ssh.h
|
||||||
scp.$(OBJ): scp.c putty.h winstuff.h
|
scp.$(OBJ): scp.c putty.h network.h winstuff.h
|
||||||
version.$(OBJ): version.c
|
version.$(OBJ): version.c
|
||||||
be_all.$(OBJ): be_all.c
|
be_all.$(OBJ): be_all.c
|
||||||
be_nossh.$(OBJ): be_nossh.c
|
be_nossh.$(OBJ): be_nossh.c
|
||||||
be_none.$(OBJ): be_none.c
|
be_none.$(OBJ): be_none.c
|
||||||
plink.$(OBJ): plink.c putty.h winstuff.h
|
plink.$(OBJ): plink.c putty.h network.h winstuff.h
|
||||||
pageant.$(OBJ): pageant.c ssh.h tree234.h
|
pageant.$(OBJ): pageant.c ssh.h tree234.h
|
||||||
tree234.$(OBJ): tree234.c tree234.h
|
tree234.$(OBJ): tree234.c tree234.h
|
||||||
##--
|
##--
|
||||||
|
7
be_all.c
7
be_all.c
@ -4,13 +4,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#ifndef AUTO_WINSOCK
|
|
||||||
#ifdef WINSOCK_TWO
|
|
||||||
#include <winsock2.h>
|
|
||||||
#else
|
|
||||||
#include <winsock.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "putty.h"
|
#include "putty.h"
|
||||||
|
|
||||||
|
@ -5,13 +5,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#ifndef AUTO_WINSOCK
|
|
||||||
#ifdef WINSOCK_TWO
|
|
||||||
#include <winsock2.h>
|
|
||||||
#else
|
|
||||||
#include <winsock.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "putty.h"
|
#include "putty.h"
|
||||||
|
|
||||||
|
@ -4,13 +4,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#ifndef AUTO_WINSOCK
|
|
||||||
#ifdef WINSOCK_TWO
|
|
||||||
#include <winsock2.h>
|
|
||||||
#else
|
|
||||||
#include <winsock.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "putty.h"
|
#include "putty.h"
|
||||||
|
|
||||||
|
7
ldisc.c
7
ldisc.c
@ -1,11 +1,4 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#ifndef AUTO_WINSOCK
|
|
||||||
#ifdef WINSOCK_TWO
|
|
||||||
#include <winsock2.h>
|
|
||||||
#else
|
|
||||||
#include <winsock.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
|
7
misc.c
7
misc.c
@ -1,11 +1,4 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#ifndef AUTO_WINSOCK
|
|
||||||
#ifdef WINSOCK_TWO
|
|
||||||
#include <winsock2.h>
|
|
||||||
#else
|
|
||||||
#include <winsock.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "putty.h"
|
#include "putty.h"
|
||||||
|
7
noise.c
7
noise.c
@ -4,13 +4,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#ifndef AUTO_WINSOCK
|
|
||||||
#ifdef WINSOCK_TWO
|
|
||||||
#include <winsock2.h>
|
|
||||||
#else
|
|
||||||
#include <winsock.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "putty.h"
|
#include "putty.h"
|
||||||
|
95
plink.c
95
plink.c
@ -11,8 +11,8 @@
|
|||||||
|
|
||||||
#define PUTTY_DO_GLOBALS /* actually _define_ globals */
|
#define PUTTY_DO_GLOBALS /* actually _define_ globals */
|
||||||
#include "putty.h"
|
#include "putty.h"
|
||||||
#include "winstuff.h"
|
|
||||||
#include "storage.h"
|
#include "storage.h"
|
||||||
|
#include "tree234.h"
|
||||||
|
|
||||||
void fatalbox (char *p, ...) {
|
void fatalbox (char *p, ...) {
|
||||||
va_list ap;
|
va_list ap;
|
||||||
@ -121,6 +121,8 @@ void verify_ssh_host_key(char *host, int port, char *keytype,
|
|||||||
HANDLE outhandle, errhandle;
|
HANDLE outhandle, errhandle;
|
||||||
DWORD orig_console_mode;
|
DWORD orig_console_mode;
|
||||||
|
|
||||||
|
WSAEVENT netevent;
|
||||||
|
|
||||||
void begin_session(void) {
|
void begin_session(void) {
|
||||||
if (!cfg.ldisc_term)
|
if (!cfg.ldisc_term)
|
||||||
SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), ENABLE_PROCESSED_INPUT);
|
SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), ENABLE_PROCESSED_INPUT);
|
||||||
@ -144,7 +146,7 @@ void from_backend(int is_stderr, char *data, int len) {
|
|||||||
struct input_data {
|
struct input_data {
|
||||||
DWORD len;
|
DWORD len;
|
||||||
char buffer[4096];
|
char buffer[4096];
|
||||||
HANDLE event;
|
HANDLE event, eventback;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int get_password(const char *prompt, char *str, int maxlen)
|
static int get_password(const char *prompt, char *str, int maxlen)
|
||||||
@ -196,8 +198,9 @@ static DWORD WINAPI stdin_read_thread(void *param) {
|
|||||||
inhandle = GetStdHandle(STD_INPUT_HANDLE);
|
inhandle = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
|
|
||||||
while (ReadFile(inhandle, idata->buffer, sizeof(idata->buffer),
|
while (ReadFile(inhandle, idata->buffer, sizeof(idata->buffer),
|
||||||
&idata->len, NULL)) {
|
&idata->len, NULL) && idata->len > 0) {
|
||||||
SetEvent(idata->event);
|
SetEvent(idata->event);
|
||||||
|
WaitForSingleObject(idata->eventback, INFINITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
idata->len = 0;
|
idata->len = 0;
|
||||||
@ -222,19 +225,39 @@ static void usage(void)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *do_select(SOCKET skt, int startup) {
|
||||||
|
int events;
|
||||||
|
if (startup) {
|
||||||
|
events = FD_READ | FD_WRITE | FD_OOB | FD_CLOSE;
|
||||||
|
} else {
|
||||||
|
events = 0;
|
||||||
|
}
|
||||||
|
if (WSAEventSelect (skt, netevent, events) == SOCKET_ERROR) {
|
||||||
|
switch (WSAGetLastError()) {
|
||||||
|
case WSAENETDOWN: return "Network is down";
|
||||||
|
default: return "WSAAsyncSelect(): unknown error";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
WSADATA wsadata;
|
WSADATA wsadata;
|
||||||
WORD winsock_ver;
|
WORD winsock_ver;
|
||||||
WSAEVENT netevent, stdinevent;
|
WSAEVENT stdinevent;
|
||||||
HANDLE handles[2];
|
HANDLE handles[2];
|
||||||
SOCKET socket;
|
|
||||||
DWORD threadid;
|
DWORD threadid;
|
||||||
struct input_data idata;
|
struct input_data idata;
|
||||||
int sending;
|
int sending;
|
||||||
int portnumber = -1;
|
int portnumber = -1;
|
||||||
|
SOCKET *sklist;
|
||||||
|
int skcount, sksize;
|
||||||
|
int connopen;
|
||||||
|
|
||||||
ssh_get_password = get_password;
|
ssh_get_password = get_password;
|
||||||
|
|
||||||
|
sklist = NULL; skcount = sksize = 0;
|
||||||
|
|
||||||
flags = FLAG_STDERR;
|
flags = FLAG_STDERR;
|
||||||
/*
|
/*
|
||||||
* Process the command line.
|
* Process the command line.
|
||||||
@ -429,22 +452,24 @@ int main(int argc, char **argv) {
|
|||||||
WSACleanup();
|
WSACleanup();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
sk_init();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Start up the connection.
|
* Start up the connection.
|
||||||
*/
|
*/
|
||||||
|
netevent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||||
{
|
{
|
||||||
char *error;
|
char *error;
|
||||||
char *realhost;
|
char *realhost;
|
||||||
|
|
||||||
error = back->init (NULL, cfg.host, cfg.port, &realhost);
|
error = back->init (cfg.host, cfg.port, &realhost);
|
||||||
if (error) {
|
if (error) {
|
||||||
fprintf(stderr, "Unable to open connection:\n%s", error);
|
fprintf(stderr, "Unable to open connection:\n%s", error);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
connopen = 1;
|
||||||
|
|
||||||
netevent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
||||||
stdinevent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
stdinevent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||||
|
|
||||||
GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &orig_console_mode);
|
GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &orig_console_mode);
|
||||||
@ -452,16 +477,11 @@ int main(int argc, char **argv) {
|
|||||||
outhandle = GetStdHandle(STD_OUTPUT_HANDLE);
|
outhandle = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
errhandle = GetStdHandle(STD_ERROR_HANDLE);
|
errhandle = GetStdHandle(STD_ERROR_HANDLE);
|
||||||
|
|
||||||
/*
|
|
||||||
* Now we must send the back end oodles of stuff.
|
|
||||||
*/
|
|
||||||
socket = back->socket();
|
|
||||||
/*
|
/*
|
||||||
* Turn off ECHO and LINE input modes. We don't care if this
|
* Turn off ECHO and LINE input modes. We don't care if this
|
||||||
* call fails, because we know we aren't necessarily running in
|
* call fails, because we know we aren't necessarily running in
|
||||||
* a console.
|
* a console.
|
||||||
*/
|
*/
|
||||||
WSAEventSelect(socket, netevent, FD_READ | FD_CLOSE);
|
|
||||||
handles[0] = netevent;
|
handles[0] = netevent;
|
||||||
handles[1] = stdinevent;
|
handles[1] = stdinevent;
|
||||||
sending = FALSE;
|
sending = FALSE;
|
||||||
@ -486,6 +506,7 @@ int main(int argc, char **argv) {
|
|||||||
* - so we're back to ReadFile blocking.
|
* - so we're back to ReadFile blocking.
|
||||||
*/
|
*/
|
||||||
idata.event = stdinevent;
|
idata.event = stdinevent;
|
||||||
|
idata.eventback = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||||
if (!CreateThread(NULL, 0, stdin_read_thread,
|
if (!CreateThread(NULL, 0, stdin_read_thread,
|
||||||
&idata, 0, &threadid)) {
|
&idata, 0, &threadid)) {
|
||||||
fprintf(stderr, "Unable to create second thread\n");
|
fprintf(stderr, "Unable to create second thread\n");
|
||||||
@ -497,12 +518,51 @@ int main(int argc, char **argv) {
|
|||||||
n = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
|
n = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
WSANETWORKEVENTS things;
|
WSANETWORKEVENTS things;
|
||||||
|
enum234 e;
|
||||||
|
SOCKET socket;
|
||||||
|
extern SOCKET first_socket(enum234 *), next_socket(enum234 *);
|
||||||
|
extern int select_result(WPARAM, LPARAM);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We must not call select_result() for any socket
|
||||||
|
* until we have finished enumerating within the tree.
|
||||||
|
* This is because select_result() may close the socket
|
||||||
|
* and modify the tree.
|
||||||
|
*/
|
||||||
|
/* Count the active sockets. */
|
||||||
|
i = 0;
|
||||||
|
for (socket = first_socket(&e); socket != INVALID_SOCKET;
|
||||||
|
socket = next_socket(&e))
|
||||||
|
i++;
|
||||||
|
|
||||||
|
/* Expand the buffer if necessary. */
|
||||||
|
if (i > sksize) {
|
||||||
|
sksize = i+16;
|
||||||
|
sklist = srealloc(sklist, sksize * sizeof(*sklist));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Retrieve the sockets into sklist. */
|
||||||
|
skcount = 0;
|
||||||
|
for (socket = first_socket(&e); socket != INVALID_SOCKET;
|
||||||
|
socket = next_socket(&e)) {
|
||||||
|
sklist[skcount++] = socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now we're done enumerating; go through the list. */
|
||||||
|
for (i = 0; i < skcount; i++) {
|
||||||
|
WPARAM wp;
|
||||||
|
socket = sklist[i];
|
||||||
|
wp = (WPARAM)socket;
|
||||||
if (!WSAEnumNetworkEvents(socket, netevent, &things)) {
|
if (!WSAEnumNetworkEvents(socket, netevent, &things)) {
|
||||||
if (things.lNetworkEvents & FD_READ)
|
if (things.lNetworkEvents & FD_READ)
|
||||||
back->msg(0, FD_READ);
|
connopen &= select_result(wp, (LPARAM)FD_READ);
|
||||||
if (things.lNetworkEvents & FD_CLOSE) {
|
if (things.lNetworkEvents & FD_CLOSE)
|
||||||
back->msg(0, FD_CLOSE);
|
connopen &= select_result(wp, (LPARAM)FD_CLOSE);
|
||||||
break;
|
if (things.lNetworkEvents & FD_OOB)
|
||||||
|
connopen &= select_result(wp, (LPARAM)FD_OOB);
|
||||||
|
if (things.lNetworkEvents & FD_WRITE)
|
||||||
|
connopen &= select_result(wp, (LPARAM)FD_WRITE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (n == 1) {
|
} else if (n == 1) {
|
||||||
@ -511,8 +571,9 @@ int main(int argc, char **argv) {
|
|||||||
} else {
|
} else {
|
||||||
back->special(TS_EOF);
|
back->special(TS_EOF);
|
||||||
}
|
}
|
||||||
|
SetEvent(idata.eventback);
|
||||||
}
|
}
|
||||||
if (back->socket() == INVALID_SOCKET)
|
if (!connopen || back->socket() == NULL)
|
||||||
break; /* we closed the connection */
|
break; /* we closed the connection */
|
||||||
}
|
}
|
||||||
WSACleanup();
|
WSACleanup();
|
||||||
|
7
putty.h
7
putty.h
@ -1,6 +1,8 @@
|
|||||||
#ifndef PUTTY_PUTTY_H
|
#ifndef PUTTY_PUTTY_H
|
||||||
#define PUTTY_PUTTY_H
|
#define PUTTY_PUTTY_H
|
||||||
|
|
||||||
|
#include "network.h"
|
||||||
|
|
||||||
#define PUTTY_REG_POS "Software\\SimonTatham\\PuTTY"
|
#define PUTTY_REG_POS "Software\\SimonTatham\\PuTTY"
|
||||||
#define PUTTY_REG_PARENT "Software\\SimonTatham"
|
#define PUTTY_REG_PARENT "Software\\SimonTatham"
|
||||||
#define PUTTY_REG_PARENT_CHILD "PuTTY"
|
#define PUTTY_REG_PARENT_CHILD "PuTTY"
|
||||||
@ -104,12 +106,11 @@ typedef enum {
|
|||||||
} VT_Mode;
|
} VT_Mode;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char *(*init) (HWND hwnd, char *host, int port, char **realhost);
|
char *(*init) (char *host, int port, char **realhost);
|
||||||
int (*msg) (WPARAM wParam, LPARAM lParam);
|
|
||||||
void (*send) (char *buf, int len);
|
void (*send) (char *buf, int len);
|
||||||
void (*size) (void);
|
void (*size) (void);
|
||||||
void (*special) (Telnet_Special code);
|
void (*special) (Telnet_Special code);
|
||||||
SOCKET (*socket) (void);
|
Socket (*socket) (void);
|
||||||
int (*sendok) (void);
|
int (*sendok) (void);
|
||||||
int default_port;
|
int default_port;
|
||||||
} Backend;
|
} Backend;
|
||||||
|
184
raw.c
184
raw.c
@ -1,13 +1,6 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#ifndef AUTO_WINSOCK
|
|
||||||
#ifdef WINSOCK_TWO
|
|
||||||
#include <winsock2.h>
|
|
||||||
#else
|
|
||||||
#include <winsock.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "putty.h"
|
#include "putty.h"
|
||||||
|
|
||||||
@ -18,7 +11,7 @@
|
|||||||
#define TRUE 1
|
#define TRUE 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static SOCKET s = INVALID_SOCKET;
|
static Socket s = NULL;
|
||||||
|
|
||||||
static void raw_size(void);
|
static void raw_size(void);
|
||||||
|
|
||||||
@ -27,67 +20,38 @@ static char *sb_buf = NULL;
|
|||||||
static int sb_size = 0;
|
static int sb_size = 0;
|
||||||
#define SB_DELTA 1024
|
#define SB_DELTA 1024
|
||||||
|
|
||||||
static void try_write (void) {
|
|
||||||
while (outbuf_head != outbuf_reap) {
|
|
||||||
int end = (outbuf_reap < outbuf_head ? outbuf_head : OUTBUF_SIZE);
|
|
||||||
int len = end - outbuf_reap;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = send (s, outbuf+outbuf_reap, len, 0);
|
|
||||||
if (ret > 0)
|
|
||||||
outbuf_reap = (outbuf_reap + ret) & OUTBUF_MASK;
|
|
||||||
if (ret < len)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void s_write (void *buf, int len) {
|
|
||||||
unsigned char *p = buf;
|
|
||||||
while (len--) {
|
|
||||||
int new_head = (outbuf_head + 1) & OUTBUF_MASK;
|
|
||||||
if (new_head != outbuf_reap) {
|
|
||||||
outbuf[outbuf_head] = *p++;
|
|
||||||
outbuf_head = new_head;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
try_write();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void c_write (char *buf, int len) {
|
static void c_write (char *buf, int len) {
|
||||||
from_backend(0, buf, len);
|
from_backend(0, buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int raw_receive (Socket s, int urgent, char *data, int len) {
|
||||||
|
if (!len) {
|
||||||
|
/* Connection has closed. */
|
||||||
|
sk_close(s);
|
||||||
|
s = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
c_write(data, len);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called to set up the raw connection. Will arrange for
|
* Called to set up the raw connection.
|
||||||
* WM_NETEVENT messages to be passed to the specified window, whose
|
|
||||||
* window procedure should then call raw_msg().
|
|
||||||
*
|
*
|
||||||
* Returns an error message, or NULL on success.
|
* Returns an error message, or NULL on success.
|
||||||
*
|
*
|
||||||
* Also places the canonical host name into `realhost'.
|
* Also places the canonical host name into `realhost'.
|
||||||
*/
|
*/
|
||||||
static char *raw_init (HWND hwnd, char *host, int port, char **realhost) {
|
static char *raw_init (char *host, int port, char **realhost) {
|
||||||
SOCKADDR_IN addr;
|
SockAddr addr;
|
||||||
struct hostent *h;
|
char *err;
|
||||||
unsigned long a;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Try to find host.
|
* Try to find host.
|
||||||
*/
|
*/
|
||||||
if ( (a = inet_addr(host)) == (unsigned long) INADDR_NONE) {
|
addr = sk_namelookup(host, realhost);
|
||||||
if ( (h = gethostbyname(host)) == NULL)
|
if ( (err = sk_addr_error(addr)) )
|
||||||
switch (WSAGetLastError()) {
|
return err;
|
||||||
case WSAENETDOWN: return "Network is down";
|
|
||||||
case WSAHOST_NOT_FOUND: case WSANO_DATA:
|
|
||||||
return "Host does not exist";
|
|
||||||
case WSATRY_AGAIN: return "Host not found";
|
|
||||||
default: return "gethostbyname: unknown error";
|
|
||||||
}
|
|
||||||
memcpy (&a, h->h_addr, sizeof(a));
|
|
||||||
*realhost = h->h_name;
|
|
||||||
} else
|
|
||||||
*realhost = host;
|
|
||||||
a = ntohl(a);
|
|
||||||
|
|
||||||
if (port < 0)
|
if (port < 0)
|
||||||
port = 23; /* default telnet port */
|
port = 23; /* default telnet port */
|
||||||
@ -95,46 +59,11 @@ static char *raw_init (HWND hwnd, char *host, int port, char **realhost) {
|
|||||||
/*
|
/*
|
||||||
* Open socket.
|
* Open socket.
|
||||||
*/
|
*/
|
||||||
s = socket(AF_INET, SOCK_STREAM, 0);
|
s = sk_new(addr, port, raw_receive);
|
||||||
if (s == INVALID_SOCKET)
|
if ( (err = sk_socket_error(s)) )
|
||||||
switch (WSAGetLastError()) {
|
return err;
|
||||||
case WSAENETDOWN: return "Network is down";
|
|
||||||
case WSAEAFNOSUPPORT: return "TCP/IP support not present";
|
|
||||||
default: return "socket(): unknown error";
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
sk_addr_free(addr);
|
||||||
* Bind to local address.
|
|
||||||
*/
|
|
||||||
addr.sin_family = AF_INET;
|
|
||||||
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
||||||
addr.sin_port = htons(0);
|
|
||||||
if (bind (s, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR)
|
|
||||||
switch (WSAGetLastError()) {
|
|
||||||
case WSAENETDOWN: return "Network is down";
|
|
||||||
default: return "bind(): unknown error";
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Connect to remote address.
|
|
||||||
*/
|
|
||||||
addr.sin_addr.s_addr = htonl(a);
|
|
||||||
addr.sin_port = htons((short)port);
|
|
||||||
if (connect (s, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR)
|
|
||||||
switch (WSAGetLastError()) {
|
|
||||||
case WSAENETDOWN: return "Network is down";
|
|
||||||
case WSAECONNREFUSED: return "Connection refused";
|
|
||||||
case WSAENETUNREACH: return "Network is unreachable";
|
|
||||||
case WSAEHOSTUNREACH: return "No route to host";
|
|
||||||
default: return "connect(): unknown error";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hwnd && WSAAsyncSelect (s, hwnd, WM_NETEVENT, FD_READ |
|
|
||||||
FD_WRITE | FD_OOB | FD_CLOSE) == SOCKET_ERROR)
|
|
||||||
switch (WSAGetLastError()) {
|
|
||||||
case WSAENETDOWN: return "Network is down";
|
|
||||||
default: return "WSAAsyncSelect(): unknown error";
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We have no pre-session phase.
|
* We have no pre-session phase.
|
||||||
@ -144,75 +73,15 @@ static char *raw_init (HWND hwnd, char *host, int port, char **realhost) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Process a WM_NETEVENT message. Will return 0 if the connection
|
|
||||||
* has closed, or <0 for a socket error.
|
|
||||||
*/
|
|
||||||
static int raw_msg (WPARAM wParam, LPARAM lParam) {
|
|
||||||
int ret;
|
|
||||||
char buf[256];
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Because reading less than the whole of the available pending
|
|
||||||
* data can generate an FD_READ event, we need to allow for the
|
|
||||||
* possibility that FD_READ may arrive with FD_CLOSE already in
|
|
||||||
* the queue; so it's possible that we can get here even with s
|
|
||||||
* invalid. If so, we return 1 and don't worry about it.
|
|
||||||
*/
|
|
||||||
if (s == INVALID_SOCKET) {
|
|
||||||
closesocket(s);
|
|
||||||
s = INVALID_SOCKET;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (WSAGETSELECTERROR(lParam) != 0)
|
|
||||||
return -WSAGETSELECTERROR(lParam);
|
|
||||||
|
|
||||||
switch (WSAGETSELECTEVENT(lParam)) {
|
|
||||||
case FD_READ:
|
|
||||||
case FD_CLOSE:
|
|
||||||
ret = recv(s, buf, sizeof(buf), 0);
|
|
||||||
if (ret < 0 && WSAGetLastError() == WSAEWOULDBLOCK)
|
|
||||||
return 1;
|
|
||||||
if (ret < 0) { /* any _other_ error */
|
|
||||||
closesocket(s);
|
|
||||||
s = INVALID_SOCKET;
|
|
||||||
return -10000-WSAGetLastError();
|
|
||||||
}
|
|
||||||
if (ret == 0) {
|
|
||||||
s = INVALID_SOCKET;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
c_write( buf, ret );
|
|
||||||
return 1;
|
|
||||||
case FD_OOB:
|
|
||||||
do {
|
|
||||||
ret = recv(s, buf, sizeof(buf), 0);
|
|
||||||
c_write( buf, ret );
|
|
||||||
} while (ret > 0);
|
|
||||||
do {
|
|
||||||
ret = recv(s, buf, 1, MSG_OOB);
|
|
||||||
} while (ret > 0);
|
|
||||||
if (ret < 0 && WSAGetLastError() != WSAEWOULDBLOCK)
|
|
||||||
return -30000-WSAGetLastError();
|
|
||||||
return 1;
|
|
||||||
case FD_WRITE:
|
|
||||||
if (outbuf_head != outbuf_reap)
|
|
||||||
try_write();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 1; /* shouldn't happen, but WTF */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called to send data down the raw connection.
|
* Called to send data down the raw connection.
|
||||||
*/
|
*/
|
||||||
static void raw_send (char *buf, int len) {
|
static void raw_send (char *buf, int len) {
|
||||||
|
|
||||||
if (s == INVALID_SOCKET)
|
if (s == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
s_write( buf, len );
|
sk_write(s, buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -231,13 +100,12 @@ static void raw_special (Telnet_Special code) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static SOCKET raw_socket(void) { return s; }
|
static Socket raw_socket(void) { return s; }
|
||||||
|
|
||||||
static int raw_sendok(void) { return 1; }
|
static int raw_sendok(void) { return 1; }
|
||||||
|
|
||||||
Backend raw_backend = {
|
Backend raw_backend = {
|
||||||
raw_init,
|
raw_init,
|
||||||
raw_msg,
|
|
||||||
raw_send,
|
raw_send,
|
||||||
raw_size,
|
raw_size,
|
||||||
raw_special,
|
raw_special,
|
||||||
|
38
scp.c
38
scp.c
@ -241,6 +241,19 @@ void connection_fatal(char *fmt, ...)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Be told what socket we're supposed to be using.
|
||||||
|
*/
|
||||||
|
static SOCKET scp_ssh_socket;
|
||||||
|
char *do_select(SOCKET skt, int startup) {
|
||||||
|
if (startup)
|
||||||
|
scp_ssh_socket = skt;
|
||||||
|
else
|
||||||
|
scp_ssh_socket = INVALID_SOCKET;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
extern int select_result(WPARAM, LPARAM);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Receive a block of data from the SSH link. Block until all data
|
* Receive a block of data from the SSH link. Block until all data
|
||||||
* is available.
|
* is available.
|
||||||
@ -249,6 +262,7 @@ void connection_fatal(char *fmt, ...)
|
|||||||
* own trap in from_backend() to catch the data that comes back. We
|
* own trap in from_backend() to catch the data that comes back. We
|
||||||
* do this until we have enough data.
|
* do this until we have enough data.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static unsigned char *outptr; /* where to put the data */
|
static unsigned char *outptr; /* where to put the data */
|
||||||
static unsigned outlen; /* how much data required */
|
static unsigned outlen; /* how much data required */
|
||||||
static unsigned char *pending = NULL; /* any spare data */
|
static unsigned char *pending = NULL; /* any spare data */
|
||||||
@ -295,8 +309,6 @@ void from_backend(int is_stderr, char *data, int datalen) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
static int ssh_scp_recv(unsigned char *buf, int len) {
|
static int ssh_scp_recv(unsigned char *buf, int len) {
|
||||||
SOCKET s;
|
|
||||||
|
|
||||||
outptr = buf;
|
outptr = buf;
|
||||||
outlen = len;
|
outlen = len;
|
||||||
|
|
||||||
@ -324,16 +336,12 @@ static int ssh_scp_recv(unsigned char *buf, int len) {
|
|||||||
|
|
||||||
while (outlen > 0) {
|
while (outlen > 0) {
|
||||||
fd_set readfds;
|
fd_set readfds;
|
||||||
s = back->socket();
|
|
||||||
if (s == INVALID_SOCKET) {
|
|
||||||
connection_open = FALSE;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
FD_ZERO(&readfds);
|
FD_ZERO(&readfds);
|
||||||
FD_SET(s, &readfds);
|
FD_SET(scp_ssh_socket, &readfds);
|
||||||
if (select(1, &readfds, NULL, NULL, NULL) < 0)
|
if (select(1, &readfds, NULL, NULL, NULL) < 0)
|
||||||
return 0; /* doom */
|
return 0; /* doom */
|
||||||
back->msg(0, FD_READ);
|
select_result((WPARAM)scp_ssh_socket, (LPARAM)FD_READ);
|
||||||
}
|
}
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
@ -343,18 +351,15 @@ static int ssh_scp_recv(unsigned char *buf, int len) {
|
|||||||
* Loop through the ssh connection and authentication process.
|
* Loop through the ssh connection and authentication process.
|
||||||
*/
|
*/
|
||||||
static void ssh_scp_init(void) {
|
static void ssh_scp_init(void) {
|
||||||
SOCKET s;
|
if (scp_ssh_socket == INVALID_SOCKET)
|
||||||
|
|
||||||
s = back->socket();
|
|
||||||
if (s == INVALID_SOCKET)
|
|
||||||
return;
|
return;
|
||||||
while (!back->sendok()) {
|
while (!back->sendok()) {
|
||||||
fd_set readfds;
|
fd_set readfds;
|
||||||
FD_ZERO(&readfds);
|
FD_ZERO(&readfds);
|
||||||
FD_SET(s, &readfds);
|
FD_SET(scp_ssh_socket, &readfds);
|
||||||
if (select(1, &readfds, NULL, NULL, NULL) < 0)
|
if (select(1, &readfds, NULL, NULL, NULL) < 0)
|
||||||
return; /* doom */
|
return; /* doom */
|
||||||
back->msg(0, FD_READ);
|
select_result((WPARAM)scp_ssh_socket, (LPARAM)FD_READ);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -464,7 +469,7 @@ static void do_cmd(char *host, char *user, char *cmd)
|
|||||||
|
|
||||||
back = &ssh_backend;
|
back = &ssh_backend;
|
||||||
|
|
||||||
err = back->init(NULL, cfg.host, cfg.port, &realhost);
|
err = back->init(cfg.host, cfg.port, &realhost);
|
||||||
if (err != NULL)
|
if (err != NULL)
|
||||||
bump("ssh_init: %s", err);
|
bump("ssh_init: %s", err);
|
||||||
ssh_scp_init();
|
ssh_scp_init();
|
||||||
@ -1178,6 +1183,7 @@ int main(int argc, char *argv[])
|
|||||||
flags = FLAG_STDERR;
|
flags = FLAG_STDERR;
|
||||||
ssh_get_password = &get_password;
|
ssh_get_password = &get_password;
|
||||||
init_winsock();
|
init_winsock();
|
||||||
|
sk_init();
|
||||||
|
|
||||||
for (i = 1; i < argc; i++) {
|
for (i = 1; i < argc; i++) {
|
||||||
if (argv[i][0] != '-')
|
if (argv[i][0] != '-')
|
||||||
|
@ -3,13 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#ifndef AUTO_WINSOCK
|
|
||||||
#ifdef WINSOCK_TWO
|
|
||||||
#include <winsock2.h>
|
|
||||||
#else
|
|
||||||
#include <winsock.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "putty.h"
|
#include "putty.h"
|
||||||
#include "storage.h"
|
#include "storage.h"
|
||||||
|
@ -1,11 +1,4 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#ifndef AUTO_WINSOCK
|
|
||||||
#ifdef WINSOCK_TWO
|
|
||||||
#include <winsock2.h>
|
|
||||||
#else
|
|
||||||
#include <winsock.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#include <winreg.h>
|
#include <winreg.h>
|
||||||
#include <tchar.h>
|
#include <tchar.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
413
ssh.c
413
ssh.c
@ -1,14 +1,8 @@
|
|||||||
|
#include <windows.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#ifndef AUTO_WINSOCK
|
|
||||||
#ifdef WINSOCK_TWO
|
|
||||||
#include <winsock2.h>
|
|
||||||
#else
|
|
||||||
#include <winsock.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "putty.h"
|
#include "putty.h"
|
||||||
#include "tree234.h"
|
#include "tree234.h"
|
||||||
@ -25,8 +19,8 @@
|
|||||||
if ((flags & FLAG_STDERR) && (flags & FLAG_VERBOSE)) \
|
if ((flags & FLAG_STDERR) && (flags & FLAG_VERBOSE)) \
|
||||||
fprintf(stderr, "%s\n", s); }
|
fprintf(stderr, "%s\n", s); }
|
||||||
|
|
||||||
#define bombout(msg) ( ssh_state = SSH_STATE_CLOSED, closesocket(s), \
|
#define bombout(msg) ( ssh_state = SSH_STATE_CLOSED, sk_close(s), \
|
||||||
s = INVALID_SOCKET, connection_fatal msg )
|
s = NULL, connection_fatal msg )
|
||||||
|
|
||||||
#define SSH1_MSG_DISCONNECT 1 /* 0x1 */
|
#define SSH1_MSG_DISCONNECT 1 /* 0x1 */
|
||||||
#define SSH1_SMSG_PUBLIC_KEY 2 /* 0x2 */
|
#define SSH1_SMSG_PUBLIC_KEY 2 /* 0x2 */
|
||||||
@ -217,7 +211,7 @@ struct Packet {
|
|||||||
|
|
||||||
static SHA_State exhash;
|
static SHA_State exhash;
|
||||||
|
|
||||||
static SOCKET s = INVALID_SOCKET;
|
static Socket s = NULL;
|
||||||
|
|
||||||
static unsigned char session_key[32];
|
static unsigned char session_key[32];
|
||||||
static const struct ssh_cipher *cipher = NULL;
|
static const struct ssh_cipher *cipher = NULL;
|
||||||
@ -288,32 +282,6 @@ static int ssh_channelfind(void *av, void *bv) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void s_write (char *buf, int len) {
|
|
||||||
while (len > 0) {
|
|
||||||
int i = send (s, buf, len, 0);
|
|
||||||
noise_ultralight(i);
|
|
||||||
if (i <= 0) {
|
|
||||||
bombout(("Lost connection while sending"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (i > 0)
|
|
||||||
len -= i, buf += i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int s_read (char *buf, int len) {
|
|
||||||
int ret = 0;
|
|
||||||
while (len > 0) {
|
|
||||||
int i = recv (s, buf, len, 0);
|
|
||||||
noise_ultralight(i);
|
|
||||||
if (i > 0)
|
|
||||||
len -= i, buf += i, ret += i;
|
|
||||||
else
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void c_write (char *buf, int len) {
|
static void c_write (char *buf, int len) {
|
||||||
if ((flags & FLAG_STDERR)) {
|
if ((flags & FLAG_STDERR)) {
|
||||||
int i;
|
int i;
|
||||||
@ -544,19 +512,6 @@ next_packet:
|
|||||||
crFinish(0);
|
crFinish(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ssh_gotdata(unsigned char *data, int datalen)
|
|
||||||
{
|
|
||||||
while (datalen > 0) {
|
|
||||||
if ( s_rdpkt(&data, &datalen) == 0 ) {
|
|
||||||
ssh_protocol(NULL, 0, 1);
|
|
||||||
if (ssh_state == SSH_STATE_CLOSED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void s_wrpkt_start(int type, int len) {
|
static void s_wrpkt_start(int type, int len) {
|
||||||
int pad, biglen;
|
int pad, biglen;
|
||||||
|
|
||||||
@ -608,7 +563,7 @@ static void s_wrpkt(void) {
|
|||||||
if (cipher)
|
if (cipher)
|
||||||
cipher->encrypt(pktout.data+4, biglen);
|
cipher->encrypt(pktout.data+4, biglen);
|
||||||
|
|
||||||
s_write(pktout.data, biglen+4);
|
sk_write(s, pktout.data, biglen+4);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -695,109 +650,6 @@ static void send_packet(int pkttype, ...)
|
|||||||
s_wrpkt();
|
s_wrpkt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Connect to specified host and port.
|
|
||||||
* Returns an error message, or NULL on success.
|
|
||||||
* Also places the canonical host name into `realhost'.
|
|
||||||
*/
|
|
||||||
static char *connect_to_host(char *host, int port, char **realhost)
|
|
||||||
{
|
|
||||||
SOCKADDR_IN addr;
|
|
||||||
struct hostent *h;
|
|
||||||
unsigned long a;
|
|
||||||
#ifdef FWHACK
|
|
||||||
char *FWhost;
|
|
||||||
int FWport;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
savedhost = malloc(1+strlen(host));
|
|
||||||
if (!savedhost)
|
|
||||||
fatalbox("Out of memory");
|
|
||||||
strcpy(savedhost, host);
|
|
||||||
|
|
||||||
if (port < 0)
|
|
||||||
port = 22; /* default ssh port */
|
|
||||||
savedport = port;
|
|
||||||
|
|
||||||
#ifdef FWHACK
|
|
||||||
FWhost = host;
|
|
||||||
FWport = port;
|
|
||||||
host = FWSTR;
|
|
||||||
port = 23;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Try to find host.
|
|
||||||
*/
|
|
||||||
if ( (a = inet_addr(host)) == (unsigned long) INADDR_NONE) {
|
|
||||||
if ( (h = gethostbyname(host)) == NULL)
|
|
||||||
switch (WSAGetLastError()) {
|
|
||||||
case WSAENETDOWN: return "Network is down";
|
|
||||||
case WSAHOST_NOT_FOUND: case WSANO_DATA:
|
|
||||||
return "Host does not exist";
|
|
||||||
case WSATRY_AGAIN: return "Host not found";
|
|
||||||
default: return "gethostbyname: unknown error";
|
|
||||||
}
|
|
||||||
memcpy (&a, h->h_addr, sizeof(a));
|
|
||||||
*realhost = h->h_name;
|
|
||||||
} else
|
|
||||||
*realhost = host;
|
|
||||||
#ifdef FWHACK
|
|
||||||
*realhost = FWhost;
|
|
||||||
#endif
|
|
||||||
a = ntohl(a);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Open socket.
|
|
||||||
*/
|
|
||||||
s = socket(AF_INET, SOCK_STREAM, 0);
|
|
||||||
if (s == INVALID_SOCKET)
|
|
||||||
switch (WSAGetLastError()) {
|
|
||||||
case WSAENETDOWN: return "Network is down";
|
|
||||||
case WSAEAFNOSUPPORT: return "TCP/IP support not present";
|
|
||||||
default: return "socket(): unknown error";
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Bind to local address.
|
|
||||||
*/
|
|
||||||
addr.sin_family = AF_INET;
|
|
||||||
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
||||||
addr.sin_port = htons(0);
|
|
||||||
if (bind (s, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR)
|
|
||||||
switch (WSAGetLastError()) {
|
|
||||||
case WSAENETDOWN: return "Network is down";
|
|
||||||
default: return "bind(): unknown error";
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Connect to remote address.
|
|
||||||
*/
|
|
||||||
addr.sin_addr.s_addr = htonl(a);
|
|
||||||
addr.sin_port = htons((short)port);
|
|
||||||
if (connect (s, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR)
|
|
||||||
switch (WSAGetLastError()) {
|
|
||||||
case WSAENETDOWN: return "Network is down";
|
|
||||||
case WSAECONNREFUSED: return "Connection refused";
|
|
||||||
case WSAENETUNREACH: return "Network is unreachable";
|
|
||||||
case WSAEHOSTUNREACH: return "No route to host";
|
|
||||||
default: return "connect(): unknown error";
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef FWHACK
|
|
||||||
send(s, "connect ", 8, 0);
|
|
||||||
send(s, FWhost, strlen(FWhost), 0);
|
|
||||||
{
|
|
||||||
char buf[20];
|
|
||||||
sprintf(buf, " %d\n", FWport);
|
|
||||||
send (s, buf, strlen(buf), 0);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ssh_versioncmp(char *a, char *b) {
|
static int ssh_versioncmp(char *a, char *b) {
|
||||||
char *ae, *be;
|
char *ae, *be;
|
||||||
unsigned long av, bv;
|
unsigned long av, bv;
|
||||||
@ -931,7 +783,7 @@ static void ssh2_pkt_send(void) {
|
|||||||
cscipher->encrypt(pktout.data, pktout.length + padding);
|
cscipher->encrypt(pktout.data, pktout.length + padding);
|
||||||
maclen = csmac ? csmac->len : 0;
|
maclen = csmac ? csmac->len : 0;
|
||||||
|
|
||||||
s_write(pktout.data, pktout.length + padding + maclen);
|
sk_write(s, pktout.data, pktout.length + padding + maclen);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
@ -1000,33 +852,35 @@ static Bignum ssh2_pkt_getmp(void) {
|
|||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_ssh_init(void) {
|
static int do_ssh_init(unsigned char c) {
|
||||||
char c, *vsp;
|
static char *vsp;
|
||||||
char version[10];
|
static char version[10];
|
||||||
char vstring[80];
|
static char vstring[80];
|
||||||
char vlog[sizeof(vstring)+20];
|
static char vlog[sizeof(vstring)+20];
|
||||||
int i;
|
static int i;
|
||||||
|
|
||||||
#ifdef FWHACK
|
crBegin;
|
||||||
i = 0;
|
|
||||||
while (s_read(&c, 1) == 1) {
|
/* Search for the string "SSH-" in the input. */
|
||||||
if (c == 'S' && i < 2) i++;
|
|
||||||
else if (c == 'S' && i == 2) i = 2;
|
|
||||||
else if (c == 'H' && i == 2) break;
|
|
||||||
else i = 0;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (s_read(&c,1) != 1 || c != 'S') return 0;
|
|
||||||
if (s_read(&c,1) != 1 || c != 'S') return 0;
|
|
||||||
if (s_read(&c,1) != 1 || c != 'H') return 0;
|
|
||||||
#endif
|
|
||||||
strcpy(vstring, "SSH-");
|
|
||||||
vsp = vstring+4;
|
|
||||||
if (s_read(&c,1) != 1 || c != '-') return 0;
|
|
||||||
i = 0;
|
i = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
if (s_read(&c,1) != 1)
|
static const int transS[] = { 1, 2, 2, 1 };
|
||||||
return 0;
|
static const int transH[] = { 0, 0, 3, 0 };
|
||||||
|
static const int transminus[] = { 0, 0, 0, -1 };
|
||||||
|
if (c == 'S') i = transS[i];
|
||||||
|
else if (c == 'H') i = transH[i];
|
||||||
|
else if (c == '-') i = transminus[i];
|
||||||
|
else i = 0;
|
||||||
|
if (i < 0)
|
||||||
|
break;
|
||||||
|
crReturn(1); /* get another character */
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(vstring, "SSH-");
|
||||||
|
vsp = vstring+4;
|
||||||
|
i = 0;
|
||||||
|
while (1) {
|
||||||
|
crReturn(1); /* get another char */
|
||||||
if (vsp < vstring+sizeof(vstring)-1)
|
if (vsp < vstring+sizeof(vstring)-1)
|
||||||
*vsp++ = c;
|
*vsp++ = c;
|
||||||
if (i >= 0) {
|
if (i >= 0) {
|
||||||
@ -1066,7 +920,7 @@ static int do_ssh_init(void) {
|
|||||||
sprintf(vlog, "We claim version: %s", verstring);
|
sprintf(vlog, "We claim version: %s", verstring);
|
||||||
logevent(vlog);
|
logevent(vlog);
|
||||||
logevent("Using SSH protocol version 2");
|
logevent("Using SSH protocol version 2");
|
||||||
s_write(vstring, strlen(vstring));
|
sk_write(s, vstring, strlen(vstring));
|
||||||
ssh_protocol = ssh2_protocol;
|
ssh_protocol = ssh2_protocol;
|
||||||
ssh_version = 2;
|
ssh_version = 2;
|
||||||
s_rdpkt = ssh2_rdpkt;
|
s_rdpkt = ssh2_rdpkt;
|
||||||
@ -1080,15 +934,129 @@ static int do_ssh_init(void) {
|
|||||||
vlog[strcspn(vlog, "\r\n")] = '\0';
|
vlog[strcspn(vlog, "\r\n")] = '\0';
|
||||||
logevent(vlog);
|
logevent(vlog);
|
||||||
logevent("Using SSH protocol version 1");
|
logevent("Using SSH protocol version 1");
|
||||||
s_write(vstring, strlen(vstring));
|
sk_write(s, vstring, strlen(vstring));
|
||||||
ssh_protocol = ssh1_protocol;
|
ssh_protocol = ssh1_protocol;
|
||||||
ssh_version = 1;
|
ssh_version = 1;
|
||||||
s_rdpkt = ssh1_rdpkt;
|
s_rdpkt = ssh1_rdpkt;
|
||||||
}
|
}
|
||||||
ssh_send_ok = 0;
|
|
||||||
|
crFinish(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ssh_gotdata(unsigned char *data, int datalen)
|
||||||
|
{
|
||||||
|
crBegin;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
if (datalen == 0)
|
||||||
|
crReturnV; /* more data please */
|
||||||
|
ret = do_ssh_init(*data);
|
||||||
|
data++; datalen--;
|
||||||
|
if (ret == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We emerge from that loop when the initial negotiation is
|
||||||
|
* over and we have selected an s_rdpkt function. Now pass
|
||||||
|
* everything to s_rdpkt, and then pass the resulting packets
|
||||||
|
* to the proper protocol handler.
|
||||||
|
*/
|
||||||
|
if (datalen == 0)
|
||||||
|
crReturnV;
|
||||||
|
while (1) {
|
||||||
|
while (datalen > 0) {
|
||||||
|
if ( s_rdpkt(&data, &datalen) == 0 ) {
|
||||||
|
ssh_protocol(NULL, 0, 1);
|
||||||
|
if (ssh_state == SSH_STATE_CLOSED) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
crReturnV;
|
||||||
|
}
|
||||||
|
crFinishV;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ssh_receive(Socket s, int urgent, char *data, int len) {
|
||||||
|
if (!len) {
|
||||||
|
/* Connection has closed. */
|
||||||
|
sk_close(s);
|
||||||
|
s = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ssh_gotdata (data, len);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Connect to specified host and port.
|
||||||
|
* Returns an error message, or NULL on success.
|
||||||
|
* Also places the canonical host name into `realhost'.
|
||||||
|
*/
|
||||||
|
static char *connect_to_host(char *host, int port, char **realhost)
|
||||||
|
{
|
||||||
|
SockAddr addr;
|
||||||
|
char *err;
|
||||||
|
#ifdef FWHACK
|
||||||
|
char *FWhost;
|
||||||
|
int FWport;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
savedhost = malloc(1+strlen(host));
|
||||||
|
if (!savedhost)
|
||||||
|
fatalbox("Out of memory");
|
||||||
|
strcpy(savedhost, host);
|
||||||
|
|
||||||
|
if (port < 0)
|
||||||
|
port = 22; /* default ssh port */
|
||||||
|
savedport = port;
|
||||||
|
|
||||||
|
#ifdef FWHACK
|
||||||
|
FWhost = host;
|
||||||
|
FWport = port;
|
||||||
|
host = FWSTR;
|
||||||
|
port = 23;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try to find host.
|
||||||
|
*/
|
||||||
|
addr = sk_namelookup(host, realhost);
|
||||||
|
if ( (err = sk_addr_error(addr)) )
|
||||||
|
return err;
|
||||||
|
|
||||||
|
#ifdef FWHACK
|
||||||
|
*realhost = FWhost;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Open socket.
|
||||||
|
*/
|
||||||
|
s = sk_new(addr, port, ssh_receive);
|
||||||
|
if ( (err = sk_socket_error(s)) )
|
||||||
|
return err;
|
||||||
|
|
||||||
|
#ifdef FWHACK
|
||||||
|
sk_write(s, "connect ", 8);
|
||||||
|
sk_write(s, FWhost, strlen(FWhost));
|
||||||
|
{
|
||||||
|
char buf[20];
|
||||||
|
sprintf(buf, " %d\n", FWport);
|
||||||
|
sk_write(s, buf, strlen(buf));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handle the key exchange and user authentication phases.
|
* Handle the key exchange and user authentication phases.
|
||||||
*/
|
*/
|
||||||
@ -1775,8 +1743,13 @@ static void ssh1_protocol(unsigned char *in, int inlen, int ispkt) {
|
|||||||
crReturnV;
|
crReturnV;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
while (inlen > 0) {
|
||||||
|
int len = min(inlen, 512);
|
||||||
send_packet(SSH1_CMSG_STDIN_DATA,
|
send_packet(SSH1_CMSG_STDIN_DATA,
|
||||||
PKT_INT, inlen, PKT_DATA, in, inlen, PKT_END);
|
PKT_INT, len, PKT_DATA, in, len, PKT_END);
|
||||||
|
in += len;
|
||||||
|
inlen -= len;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2441,8 +2414,8 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
|
|||||||
ssh2_pkt_init(SSH2_MSG_DISCONNECT);
|
ssh2_pkt_init(SSH2_MSG_DISCONNECT);
|
||||||
ssh2_pkt_send();
|
ssh2_pkt_send();
|
||||||
ssh_state = SSH_STATE_CLOSED;
|
ssh_state = SSH_STATE_CLOSED;
|
||||||
closesocket(s);
|
sk_close(s);
|
||||||
s = INVALID_SOCKET;
|
s = NULL;
|
||||||
}
|
}
|
||||||
continue; /* remote sends close; ignore (FIXME) */
|
continue; /* remote sends close; ignore (FIXME) */
|
||||||
} else if (pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST) {
|
} else if (pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST) {
|
||||||
@ -2510,13 +2483,11 @@ static void ssh2_protocol(unsigned char *in, int inlen, int ispkt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called to set up the connection. Will arrange for WM_NETEVENT
|
* Called to set up the connection.
|
||||||
* messages to be passed to the specified window, whose window
|
|
||||||
* procedure should then call telnet_msg().
|
|
||||||
*
|
*
|
||||||
* Returns an error message, or NULL on success.
|
* Returns an error message, or NULL on success.
|
||||||
*/
|
*/
|
||||||
static char *ssh_init (HWND hwnd, char *host, int port, char **realhost) {
|
static char *ssh_init (char *host, int port, char **realhost) {
|
||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
#ifdef MSCRYPTOAPI
|
#ifdef MSCRYPTOAPI
|
||||||
@ -2524,77 +2495,20 @@ static char *ssh_init (HWND hwnd, char *host, int port, char **realhost) {
|
|||||||
return "Microsoft high encryption pack not installed!";
|
return "Microsoft high encryption pack not installed!";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
ssh_send_ok = 0;
|
||||||
|
|
||||||
p = connect_to_host(host, port, realhost);
|
p = connect_to_host(host, port, realhost);
|
||||||
if (p != NULL)
|
if (p != NULL)
|
||||||
return p;
|
return p;
|
||||||
|
|
||||||
if (!do_ssh_init())
|
|
||||||
return "Protocol initialisation error";
|
|
||||||
|
|
||||||
if (hwnd && WSAAsyncSelect (s, hwnd, WM_NETEVENT, FD_READ | FD_CLOSE) == SOCKET_ERROR)
|
|
||||||
switch (WSAGetLastError()) {
|
|
||||||
case WSAENETDOWN: return "Network is down";
|
|
||||||
default: return "WSAAsyncSelect(): unknown error";
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Process a WM_NETEVENT message. Will return 0 if the connection
|
|
||||||
* has closed, or <0 for a socket error.
|
|
||||||
*/
|
|
||||||
static int ssh_msg (WPARAM wParam, LPARAM lParam) {
|
|
||||||
int ret;
|
|
||||||
char buf[256];
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Because reading less than the whole of the available pending
|
|
||||||
* data can generate an FD_READ event, we need to allow for the
|
|
||||||
* possibility that FD_READ may arrive with FD_CLOSE already in
|
|
||||||
* the queue; so it's possible that we can get here even with s
|
|
||||||
* invalid. If so, we return 1 and don't worry about it.
|
|
||||||
*/
|
|
||||||
if (s == INVALID_SOCKET)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
if (WSAGETSELECTERROR(lParam) != 0) {
|
|
||||||
closesocket(s);
|
|
||||||
s = INVALID_SOCKET;
|
|
||||||
return -WSAGETSELECTERROR(lParam);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (WSAGETSELECTEVENT(lParam)) {
|
|
||||||
case FD_READ:
|
|
||||||
case FD_CLOSE:
|
|
||||||
ret = recv(s, buf, sizeof(buf), 0);
|
|
||||||
if (ret < 0 && WSAGetLastError() == WSAEWOULDBLOCK)
|
|
||||||
return 1;
|
|
||||||
if (ret < 0) { /* any _other_ error */
|
|
||||||
closesocket(s);
|
|
||||||
s = INVALID_SOCKET;
|
|
||||||
return -10000-WSAGetLastError();
|
|
||||||
}
|
|
||||||
if (ret == 0) {
|
|
||||||
s = INVALID_SOCKET;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
ssh_gotdata (buf, ret);
|
|
||||||
if (ssh_state == SSH_STATE_CLOSED) {
|
|
||||||
closesocket(s);
|
|
||||||
s = INVALID_SOCKET;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 1; /* shouldn't happen, but WTF */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called to send data down the Telnet connection.
|
* Called to send data down the Telnet connection.
|
||||||
*/
|
*/
|
||||||
static void ssh_send (char *buf, int len) {
|
static void ssh_send (char *buf, int len) {
|
||||||
if (s == INVALID_SOCKET)
|
if (s == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ssh_protocol(buf, len, 0);
|
ssh_protocol(buf, len, 0);
|
||||||
@ -2648,13 +2562,12 @@ static void ssh_special (Telnet_Special code) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static SOCKET ssh_socket(void) { return s; }
|
static Socket ssh_socket(void) { return s; }
|
||||||
|
|
||||||
static int ssh_sendok(void) { return ssh_send_ok; }
|
static int ssh_sendok(void) { return ssh_send_ok; }
|
||||||
|
|
||||||
Backend ssh_backend = {
|
Backend ssh_backend = {
|
||||||
ssh_init,
|
ssh_init,
|
||||||
ssh_msg,
|
|
||||||
ssh_send,
|
ssh_send,
|
||||||
ssh_size,
|
ssh_size,
|
||||||
ssh_special,
|
ssh_special,
|
||||||
|
241
telnet.c
241
telnet.c
@ -1,13 +1,6 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#ifndef AUTO_WINSOCK
|
|
||||||
#ifdef WINSOCK_TWO
|
|
||||||
#include <winsock2.h>
|
|
||||||
#else
|
|
||||||
#include <winsock.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "putty.h"
|
#include "putty.h"
|
||||||
|
|
||||||
@ -18,7 +11,7 @@
|
|||||||
#define TRUE 1
|
#define TRUE 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static SOCKET s = INVALID_SOCKET;
|
static Socket s = NULL;
|
||||||
|
|
||||||
#define IAC 255 /* interpret as command: */
|
#define IAC 255 /* interpret as command: */
|
||||||
#define DONT 254 /* you are not to use option */
|
#define DONT 254 /* you are not to use option */
|
||||||
@ -145,32 +138,6 @@ static char *sb_buf = NULL;
|
|||||||
static int sb_size = 0;
|
static int sb_size = 0;
|
||||||
#define SB_DELTA 1024
|
#define SB_DELTA 1024
|
||||||
|
|
||||||
static void try_write (void) {
|
|
||||||
while (outbuf_head != outbuf_reap) {
|
|
||||||
int end = (outbuf_reap < outbuf_head ? outbuf_head : OUTBUF_SIZE);
|
|
||||||
int len = end - outbuf_reap;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = send (s, outbuf+outbuf_reap, len, 0);
|
|
||||||
if (ret > 0)
|
|
||||||
outbuf_reap = (outbuf_reap + ret) & OUTBUF_MASK;
|
|
||||||
if (ret < len)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void s_write (void *buf, int len) {
|
|
||||||
unsigned char *p = buf;
|
|
||||||
while (len--) {
|
|
||||||
int new_head = (outbuf_head + 1) & OUTBUF_MASK;
|
|
||||||
if (new_head != outbuf_reap) {
|
|
||||||
outbuf[outbuf_head] = *p++;
|
|
||||||
outbuf_head = new_head;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
try_write();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void c_write1(int c) {
|
static void c_write1(int c) {
|
||||||
char cc = (char)c;
|
char cc = (char)c;
|
||||||
from_backend(0, &cc, 1);
|
from_backend(0, &cc, 1);
|
||||||
@ -189,7 +156,7 @@ static void send_opt (int cmd, int option) {
|
|||||||
unsigned char b[3];
|
unsigned char b[3];
|
||||||
|
|
||||||
b[0] = IAC; b[1] = cmd; b[2] = option;
|
b[0] = IAC; b[1] = cmd; b[2] = option;
|
||||||
s_write (b, 3);
|
sk_write(s, b, 3);
|
||||||
log_option("client", cmd, option);
|
log_option("client", cmd, option);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -286,7 +253,7 @@ static void process_subneg (void) {
|
|||||||
strcpy(b+4, cfg.termspeed);
|
strcpy(b+4, cfg.termspeed);
|
||||||
n = 4 + strlen(cfg.termspeed);
|
n = 4 + strlen(cfg.termspeed);
|
||||||
b[n] = IAC; b[n+1] = SE;
|
b[n] = IAC; b[n+1] = SE;
|
||||||
s_write (b, n+2);
|
sk_write(s, b, n+2);
|
||||||
logevent("server:\tSB TSPEED SEND");
|
logevent("server:\tSB TSPEED SEND");
|
||||||
sprintf(logbuf, "client:\tSB TSPEED IS %s", cfg.termspeed);
|
sprintf(logbuf, "client:\tSB TSPEED IS %s", cfg.termspeed);
|
||||||
logevent (logbuf);
|
logevent (logbuf);
|
||||||
@ -302,7 +269,7 @@ static void process_subneg (void) {
|
|||||||
b[n+4] = (cfg.termtype[n] >= 'a' && cfg.termtype[n] <= 'z' ?
|
b[n+4] = (cfg.termtype[n] >= 'a' && cfg.termtype[n] <= 'z' ?
|
||||||
cfg.termtype[n] + 'A'-'a' : cfg.termtype[n]);
|
cfg.termtype[n] + 'A'-'a' : cfg.termtype[n]);
|
||||||
b[n+4] = IAC; b[n+5] = SE;
|
b[n+4] = IAC; b[n+5] = SE;
|
||||||
s_write (b, n+6);
|
sk_write(s, b, n+6);
|
||||||
b[n+4] = 0;
|
b[n+4] = 0;
|
||||||
logevent("server:\tSB TTYPE SEND");
|
logevent("server:\tSB TTYPE SEND");
|
||||||
sprintf(logbuf, "client:\tSB TTYPE IS %s", b+4);
|
sprintf(logbuf, "client:\tSB TTYPE IS %s", b+4);
|
||||||
@ -367,7 +334,7 @@ static void process_subneg (void) {
|
|||||||
while (*e) b[n++] = *e++;
|
while (*e) b[n++] = *e++;
|
||||||
}
|
}
|
||||||
b[n++] = IAC; b[n++] = SE;
|
b[n++] = IAC; b[n++] = SE;
|
||||||
s_write (b, n);
|
sk_write(s, b, n);
|
||||||
sprintf(logbuf, "client:\tSB %s IS %s", telopt(sb_opt),
|
sprintf(logbuf, "client:\tSB %s IS %s", telopt(sb_opt),
|
||||||
n==6 ? "<nothing>" : "<stuff>");
|
n==6 ? "<nothing>" : "<stuff>");
|
||||||
logevent (logbuf);
|
logevent (logbuf);
|
||||||
@ -486,37 +453,34 @@ static void do_telnet_read (char *buf, int len) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int telnet_receive(Socket s, int urgent, char *data, int len) {
|
||||||
|
if (!len) {
|
||||||
|
/* Connection has closed. */
|
||||||
|
sk_close(s);
|
||||||
|
s = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
do_telnet_read (data, len);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called to set up the Telnet connection. Will arrange for
|
* Called to set up the Telnet connection.
|
||||||
* WM_NETEVENT messages to be passed to the specified window, whose
|
|
||||||
* window procedure should then call telnet_msg().
|
|
||||||
*
|
*
|
||||||
* Returns an error message, or NULL on success.
|
* Returns an error message, or NULL on success.
|
||||||
*
|
*
|
||||||
* Also places the canonical host name into `realhost'.
|
* Also places the canonical host name into `realhost'.
|
||||||
*/
|
*/
|
||||||
static char *telnet_init (HWND hwnd, char *host, int port, char **realhost) {
|
static char *telnet_init (char *host, int port, char **realhost) {
|
||||||
SOCKADDR_IN addr;
|
SockAddr addr;
|
||||||
struct hostent *h;
|
char *err;
|
||||||
unsigned long a;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Try to find host.
|
* Try to find host.
|
||||||
*/
|
*/
|
||||||
if ( (a = inet_addr(host)) == (unsigned long) INADDR_NONE) {
|
addr = sk_namelookup(host, realhost);
|
||||||
if ( (h = gethostbyname(host)) == NULL)
|
if ( (err = sk_addr_error(addr)) )
|
||||||
switch (WSAGetLastError()) {
|
return err;
|
||||||
case WSAENETDOWN: return "Network is down";
|
|
||||||
case WSAHOST_NOT_FOUND: case WSANO_DATA:
|
|
||||||
return "Host does not exist";
|
|
||||||
case WSATRY_AGAIN: return "Host not found";
|
|
||||||
default: return "gethostbyname: unknown error";
|
|
||||||
}
|
|
||||||
memcpy (&a, h->h_addr, sizeof(a));
|
|
||||||
*realhost = h->h_name;
|
|
||||||
} else
|
|
||||||
*realhost = host;
|
|
||||||
a = ntohl(a);
|
|
||||||
|
|
||||||
if (port < 0)
|
if (port < 0)
|
||||||
port = 23; /* default telnet port */
|
port = 23; /* default telnet port */
|
||||||
@ -524,51 +488,11 @@ static char *telnet_init (HWND hwnd, char *host, int port, char **realhost) {
|
|||||||
/*
|
/*
|
||||||
* Open socket.
|
* Open socket.
|
||||||
*/
|
*/
|
||||||
s = socket(AF_INET, SOCK_STREAM, 0);
|
s = sk_new(addr, port, telnet_receive);
|
||||||
if (s == INVALID_SOCKET)
|
if ( (err = sk_socket_error(s)) )
|
||||||
switch (WSAGetLastError()) {
|
return err;
|
||||||
case WSAENETDOWN: return "Network is down";
|
|
||||||
case WSAEAFNOSUPPORT: return "TCP/IP support not present";
|
|
||||||
default: return "socket(): unknown error";
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
sk_addr_free(addr);
|
||||||
BOOL b = TRUE;
|
|
||||||
setsockopt (s, SOL_SOCKET, SO_OOBINLINE, (void *)&b, sizeof(b));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Bind to local address.
|
|
||||||
*/
|
|
||||||
addr.sin_family = AF_INET;
|
|
||||||
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
||||||
addr.sin_port = htons(0);
|
|
||||||
if (bind (s, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR)
|
|
||||||
switch (WSAGetLastError()) {
|
|
||||||
case WSAENETDOWN: return "Network is down";
|
|
||||||
default: return "bind(): unknown error";
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Connect to remote address.
|
|
||||||
*/
|
|
||||||
addr.sin_addr.s_addr = htonl(a);
|
|
||||||
addr.sin_port = htons((short)port);
|
|
||||||
if (connect (s, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR)
|
|
||||||
switch (WSAGetLastError()) {
|
|
||||||
case WSAENETDOWN: return "Network is down";
|
|
||||||
case WSAECONNREFUSED: return "Connection refused";
|
|
||||||
case WSAENETUNREACH: return "Network is unreachable";
|
|
||||||
case WSAEHOSTUNREACH: return "No route to host";
|
|
||||||
default: return "connect(): unknown error";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hwnd && WSAAsyncSelect (s, hwnd, WM_NETEVENT, FD_READ |
|
|
||||||
FD_WRITE | FD_OOB | FD_CLOSE) == SOCKET_ERROR)
|
|
||||||
switch (WSAGetLastError()) {
|
|
||||||
case WSAENETDOWN: return "Network is down";
|
|
||||||
default: return "WSAAsyncSelect(): unknown error";
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialise option states.
|
* Initialise option states.
|
||||||
@ -603,72 +527,6 @@ static char *telnet_init (HWND hwnd, char *host, int port, char **realhost) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Process a WM_NETEVENT message. Will return 0 if the connection
|
|
||||||
* has closed, or <0 for a socket error.
|
|
||||||
*/
|
|
||||||
static int telnet_msg (WPARAM wParam, LPARAM lParam) {
|
|
||||||
int ret;
|
|
||||||
/* This needs to be larger than the packet size now that inbuf
|
|
||||||
* cannot overflow, in fact the fewer calls we make to windows
|
|
||||||
* the faster we will run!
|
|
||||||
*/
|
|
||||||
char buf[16384];
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Because reading less than the whole of the available pending
|
|
||||||
* data can generate an FD_READ event, we need to allow for the
|
|
||||||
* possibility that FD_READ may arrive with FD_CLOSE already in
|
|
||||||
* the queue; so it's possible that we can get here even with s
|
|
||||||
* invalid. If so, we return 1 and don't worry about it.
|
|
||||||
*/
|
|
||||||
if (s == INVALID_SOCKET)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
if (WSAGETSELECTERROR(lParam) != 0) {
|
|
||||||
closesocket(s);
|
|
||||||
s = INVALID_SOCKET;
|
|
||||||
return -WSAGETSELECTERROR(lParam);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (WSAGETSELECTEVENT(lParam)) {
|
|
||||||
case FD_READ:
|
|
||||||
case FD_CLOSE:
|
|
||||||
{
|
|
||||||
int clear_of_oob = 1;
|
|
||||||
|
|
||||||
/* Don't check for error return; some shims don't support
|
|
||||||
* this ioctl.
|
|
||||||
*/
|
|
||||||
ioctlsocket (s, SIOCATMARK, &clear_of_oob);
|
|
||||||
|
|
||||||
in_synch = !clear_of_oob;
|
|
||||||
|
|
||||||
do {
|
|
||||||
ret = recv(s, buf, sizeof(buf), 0);
|
|
||||||
if (ret < 0 && WSAGetLastError() == WSAEWOULDBLOCK)
|
|
||||||
return 1;
|
|
||||||
if (ret < 0) { /* any _other_ error */
|
|
||||||
closesocket(s);
|
|
||||||
s = INVALID_SOCKET;
|
|
||||||
return -10000-WSAGetLastError();
|
|
||||||
}
|
|
||||||
if (ret == 0) {
|
|
||||||
s = INVALID_SOCKET;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
do_telnet_read (buf, ret);
|
|
||||||
} while (in_synch);
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
case FD_WRITE:
|
|
||||||
if (outbuf_head != outbuf_reap)
|
|
||||||
try_write();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 1; /* shouldn't happen, but WTF */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called to send data down the Telnet connection.
|
* Called to send data down the Telnet connection.
|
||||||
*/
|
*/
|
||||||
@ -678,7 +536,7 @@ static void telnet_send (char *buf, int len) {
|
|||||||
static unsigned char cr[2] = { CR, NUL };
|
static unsigned char cr[2] = { CR, NUL };
|
||||||
static unsigned char nl[2] = { CR, LF };
|
static unsigned char nl[2] = { CR, LF };
|
||||||
|
|
||||||
if (s == INVALID_SOCKET)
|
if (s == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
p = buf;
|
p = buf;
|
||||||
@ -686,10 +544,10 @@ static void telnet_send (char *buf, int len) {
|
|||||||
char *q = p;
|
char *q = p;
|
||||||
|
|
||||||
while (iswritable((unsigned char)*p) && p < buf+len) p++;
|
while (iswritable((unsigned char)*p) && p < buf+len) p++;
|
||||||
s_write (q, p-q);
|
sk_write(s, q, p-q);
|
||||||
|
|
||||||
while (p < buf+len && !iswritable((unsigned char)*p)) {
|
while (p < buf+len && !iswritable((unsigned char)*p)) {
|
||||||
s_write ((unsigned char)*p == IAC ? iac : nl, 2);
|
sk_write(s, (unsigned char)*p == IAC ? iac : nl, 2);
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -702,13 +560,13 @@ static void telnet_size(void) {
|
|||||||
unsigned char b[16];
|
unsigned char b[16];
|
||||||
char logbuf[50];
|
char logbuf[50];
|
||||||
|
|
||||||
if (s == INVALID_SOCKET || o_naws.state != ACTIVE)
|
if (s == NULL || o_naws.state != ACTIVE)
|
||||||
return;
|
return;
|
||||||
b[0] = IAC; b[1] = SB; b[2] = TELOPT_NAWS;
|
b[0] = IAC; b[1] = SB; b[2] = TELOPT_NAWS;
|
||||||
b[3] = cols >> 8; b[4] = cols & 0xFF;
|
b[3] = cols >> 8; b[4] = cols & 0xFF;
|
||||||
b[5] = rows >> 8; b[6] = rows & 0xFF;
|
b[5] = rows >> 8; b[6] = rows & 0xFF;
|
||||||
b[7] = IAC; b[8] = SE;
|
b[7] = IAC; b[8] = SE;
|
||||||
s_write (b, 9);
|
sk_write(s, b, 9);
|
||||||
sprintf(logbuf, "client:\tSB NAWS %d,%d",
|
sprintf(logbuf, "client:\tSB NAWS %d,%d",
|
||||||
((unsigned char)b[3] << 8) + (unsigned char)b[4],
|
((unsigned char)b[3] << 8) + (unsigned char)b[4],
|
||||||
((unsigned char)b[5] << 8) + (unsigned char)b[6]);
|
((unsigned char)b[5] << 8) + (unsigned char)b[6]);
|
||||||
@ -721,27 +579,27 @@ static void telnet_size(void) {
|
|||||||
static void telnet_special (Telnet_Special code) {
|
static void telnet_special (Telnet_Special code) {
|
||||||
unsigned char b[2];
|
unsigned char b[2];
|
||||||
|
|
||||||
if (s == INVALID_SOCKET)
|
if (s == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
b[0] = IAC;
|
b[0] = IAC;
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case TS_AYT: b[1] = AYT; s_write (b, 2); break;
|
case TS_AYT: b[1] = AYT; sk_write(s, b, 2); break;
|
||||||
case TS_BRK: b[1] = BREAK; s_write (b, 2); break;
|
case TS_BRK: b[1] = BREAK; sk_write(s, b, 2); break;
|
||||||
case TS_EC: b[1] = EC; s_write (b, 2); break;
|
case TS_EC: b[1] = EC; sk_write(s, b, 2); break;
|
||||||
case TS_EL: b[1] = EL; s_write (b, 2); break;
|
case TS_EL: b[1] = EL; sk_write(s, b, 2); break;
|
||||||
case TS_GA: b[1] = GA; s_write (b, 2); break;
|
case TS_GA: b[1] = GA; sk_write(s, b, 2); break;
|
||||||
case TS_NOP: b[1] = NOP; s_write (b, 2); break;
|
case TS_NOP: b[1] = NOP; sk_write(s, b, 2); break;
|
||||||
case TS_ABORT: b[1] = ABORT; s_write (b, 2); break;
|
case TS_ABORT: b[1] = ABORT; sk_write(s, b, 2); break;
|
||||||
case TS_AO: b[1] = AO; s_write (b, 2); break;
|
case TS_AO: b[1] = AO; sk_write(s, b, 2); break;
|
||||||
case TS_IP: b[1] = IP; s_write (b, 2); break;
|
case TS_IP: b[1] = IP; sk_write(s, b, 2); break;
|
||||||
case TS_SUSP: b[1] = SUSP; s_write (b, 2); break;
|
case TS_SUSP: b[1] = SUSP; sk_write(s, b, 2); break;
|
||||||
case TS_EOR: b[1] = EOR; s_write (b, 2); break;
|
case TS_EOR: b[1] = EOR; sk_write(s, b, 2); break;
|
||||||
case TS_EOF: b[1] = xEOF; s_write (b, 2); break;
|
case TS_EOF: b[1] = xEOF; sk_write(s, b, 2); break;
|
||||||
case TS_SYNCH:
|
case TS_SYNCH:
|
||||||
outbuf_head = outbuf_reap = 0;
|
|
||||||
b[1] = DM;
|
b[1] = DM;
|
||||||
send (s, b, 2, MSG_OOB);
|
sk_write (s, b, 1);
|
||||||
|
sk_write_oob (s, b+1, 1);
|
||||||
break;
|
break;
|
||||||
case TS_RECHO:
|
case TS_RECHO:
|
||||||
if (o_echo.state == INACTIVE || o_echo.state == REALLY_INACTIVE) {
|
if (o_echo.state == INACTIVE || o_echo.state == REALLY_INACTIVE) {
|
||||||
@ -758,19 +616,18 @@ static void telnet_special (Telnet_Special code) {
|
|||||||
case TS_PING:
|
case TS_PING:
|
||||||
if (o_they_sga.state == ACTIVE) {
|
if (o_they_sga.state == ACTIVE) {
|
||||||
b[1] = NOP;
|
b[1] = NOP;
|
||||||
s_write (b, 2);
|
sk_write(s, b, 2);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static SOCKET telnet_socket(void) { return s; }
|
static Socket telnet_socket(void) { return s; }
|
||||||
|
|
||||||
static int telnet_sendok(void) { return 1; }
|
static int telnet_sendok(void) { return 1; }
|
||||||
|
|
||||||
Backend telnet_backend = {
|
Backend telnet_backend = {
|
||||||
telnet_init,
|
telnet_init,
|
||||||
telnet_msg,
|
|
||||||
telnet_send,
|
telnet_send,
|
||||||
telnet_size,
|
telnet_size,
|
||||||
telnet_special,
|
telnet_special,
|
||||||
|
18
terminal.c
18
terminal.c
@ -1,11 +1,4 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#ifndef AUTO_WINSOCK
|
|
||||||
#ifdef WINSOCK_TWO
|
|
||||||
#include <winsock2.h>
|
|
||||||
#else
|
|
||||||
#include <winsock.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -2166,10 +2159,15 @@ static long last_paste = 0;
|
|||||||
|
|
||||||
while(paste_pos<paste_len)
|
while(paste_pos<paste_len)
|
||||||
{
|
{
|
||||||
char c = paste_buffer[paste_pos++];
|
int n = 0;
|
||||||
ldisc->send (&c, 1);
|
while (n + paste_pos < paste_len) {
|
||||||
|
if (paste_buffer[paste_pos + n++] == '\r')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ldisc->send (paste_buffer+paste_pos, n);
|
||||||
|
paste_pos += n;
|
||||||
|
|
||||||
if (c =='\r') {
|
if (paste_pos < paste_len) {
|
||||||
paste_hold = 1;
|
paste_hold = 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
7
windlg.c
7
windlg.c
@ -1,13 +1,6 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <commctrl.h>
|
#include <commctrl.h>
|
||||||
#include <commdlg.h>
|
#include <commdlg.h>
|
||||||
#ifndef AUTO_WINSOCK
|
|
||||||
#ifdef WINSOCK_TWO
|
|
||||||
#include <winsock2.h>
|
|
||||||
#else
|
|
||||||
#include <winsock.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
47
window.c
47
window.c
@ -129,6 +129,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
/* WISHLIST: maybe allow config tweaking even if winsock not present? */
|
/* WISHLIST: maybe allow config tweaking even if winsock not present? */
|
||||||
|
sk_init();
|
||||||
|
|
||||||
InitCommonControls();
|
InitCommonControls();
|
||||||
|
|
||||||
@ -435,7 +436,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) {
|
|||||||
char msg[1024], *title;
|
char msg[1024], *title;
|
||||||
char *realhost;
|
char *realhost;
|
||||||
|
|
||||||
error = back->init (hwnd, cfg.host, cfg.port, &realhost);
|
error = back->init (cfg.host, cfg.port, &realhost);
|
||||||
if (error) {
|
if (error) {
|
||||||
sprintf(msg, "Unable to open connection:\n%s", error);
|
sprintf(msg, "Unable to open connection:\n%s", error);
|
||||||
MessageBox(NULL, msg, "PuTTY Error", MB_ICONERROR | MB_OK);
|
MessageBox(NULL, msg, "PuTTY Error", MB_ICONERROR | MB_OK);
|
||||||
@ -623,6 +624,28 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) {
|
|||||||
return msg.wParam;
|
return msg.wParam;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set up, or shut down, an AsyncSelect. Called from winnet.c.
|
||||||
|
*/
|
||||||
|
char *do_select(SOCKET skt, int startup) {
|
||||||
|
int msg, events;
|
||||||
|
if (startup) {
|
||||||
|
msg = WM_NETEVENT;
|
||||||
|
events = FD_READ | FD_WRITE | FD_OOB | FD_CLOSE;
|
||||||
|
} else {
|
||||||
|
msg = events = 0;
|
||||||
|
}
|
||||||
|
if (!hwnd)
|
||||||
|
return "do_select(): internal error (hwnd==NULL)";
|
||||||
|
if (WSAAsyncSelect (skt, hwnd, msg, events) == SOCKET_ERROR) {
|
||||||
|
switch (WSAGetLastError()) {
|
||||||
|
case WSAENETDOWN: return "Network is down";
|
||||||
|
default: return "WSAAsyncSelect(): unknown error";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Print a message box and close the connection.
|
* Print a message box and close the connection.
|
||||||
*/
|
*/
|
||||||
@ -646,8 +669,9 @@ void connection_fatal(char *fmt, ...) {
|
|||||||
* Actually do the job requested by a WM_NETEVENT
|
* Actually do the job requested by a WM_NETEVENT
|
||||||
*/
|
*/
|
||||||
static void enact_pending_netevent(void) {
|
static void enact_pending_netevent(void) {
|
||||||
int i;
|
|
||||||
static int reentering = 0;
|
static int reentering = 0;
|
||||||
|
extern int select_result(WPARAM, LPARAM);
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (reentering)
|
if (reentering)
|
||||||
return; /* don't unpend the pending */
|
return; /* don't unpend the pending */
|
||||||
@ -655,25 +679,10 @@ static void enact_pending_netevent(void) {
|
|||||||
pending_netevent = FALSE;
|
pending_netevent = FALSE;
|
||||||
|
|
||||||
reentering = 1;
|
reentering = 1;
|
||||||
i = back->msg (pend_netevent_wParam, pend_netevent_lParam);
|
ret = select_result (pend_netevent_wParam, pend_netevent_lParam);
|
||||||
reentering = 0;
|
reentering = 0;
|
||||||
|
|
||||||
if (i < 0) {
|
if (ret == 0) {
|
||||||
char buf[1024];
|
|
||||||
switch (WSABASEERR + (-i) % 10000) {
|
|
||||||
case WSAECONNRESET:
|
|
||||||
sprintf(buf, "Connection reset by peer");
|
|
||||||
break;
|
|
||||||
case WSAECONNABORTED:
|
|
||||||
sprintf(buf, "Connection aborted");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
sprintf(buf, "Unexpected network error %d", -i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
connection_fatal(buf);
|
|
||||||
}
|
|
||||||
if (i <= 0) {
|
|
||||||
if (cfg.close_on_exit)
|
if (cfg.close_on_exit)
|
||||||
PostQuitMessage(0);
|
PostQuitMessage(0);
|
||||||
else {
|
else {
|
||||||
|
@ -4,13 +4,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#ifndef AUTO_WINSOCK
|
|
||||||
#ifdef WINSOCK_TWO
|
|
||||||
#include <winsock2.h>
|
|
||||||
#else
|
|
||||||
#include <winsock.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "putty.h"
|
#include "putty.h"
|
||||||
#include "storage.h"
|
#include "storage.h"
|
||||||
|
Loading…
Reference in New Issue
Block a user