1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 09:27:59 +00:00

Experimental Rlogin support, thanks to Delian Delchev. Local flow

control is unsupported, and server-to-client comms may fail for want
of working TCP Urgent.

[originally from svn r875]
This commit is contained in:
Simon Tatham 2001-01-19 10:10:37 +00:00
parent 72cdcc611a
commit ca90be26a8
13 changed files with 271 additions and 36 deletions

View File

@ -65,7 +65,7 @@ RES=res
GOBJS1 = window.$(OBJ) windlg.$(OBJ) winctrls.$(OBJ) terminal.$(OBJ)
GOBJS2 = xlat.$(OBJ) sizetip.$(OBJ)
##-- objects putty puttytel plink
LOBJS1 = telnet.$(OBJ) raw.$(OBJ) ldisc.$(OBJ) winnet.$(OBJ)
LOBJS1 = telnet.$(OBJ) raw.$(OBJ) rlogin.$(OBJ) ldisc.$(OBJ) winnet.$(OBJ)
##-- objects putty plink
POBJS = be_all.$(OBJ)
##-- objects puttytel
@ -224,6 +224,7 @@ terminal.$(OBJ): terminal.c putty.h puttymem.h network.h
sizetip.$(OBJ): sizetip.c putty.h puttymem.h network.h winstuff.h
telnet.$(OBJ): telnet.c putty.h puttymem.h network.h
raw.$(OBJ): raw.c putty.h puttymem.h network.h
rlogin.$(OBJ): rlogin.c putty.h puttymem.h network.h
xlat.$(OBJ): xlat.c putty.h puttymem.h network.h
ldisc.$(OBJ): ldisc.c putty.h puttymem.h network.h
misc.$(OBJ): misc.c putty.h puttymem.h network.h

View File

@ -10,6 +10,7 @@
struct backend_list backends[] = {
{PROT_SSH, "ssh", &ssh_backend},
{PROT_TELNET, "telnet", &telnet_backend},
{PROT_RLOGIN, "rlogin", &rlogin_backend},
{PROT_RAW, "raw", &raw_backend},
{0, NULL}
};

View File

@ -11,6 +11,7 @@
struct backend_list backends[] = {
{PROT_SSH, "ssh", NULL},
{PROT_TELNET, "telnet", NULL},
{PROT_RLOGIN, "rlogin", NULL},
{PROT_RAW, "raw", NULL},
{0, NULL}
};

View File

@ -9,6 +9,7 @@
struct backend_list backends[] = {
{PROT_TELNET, "telnet", &telnet_backend},
{PROT_RLOGIN, "rlogin", &rlogin_backend},
{PROT_RAW, "raw", &raw_backend},
{0, NULL}
};

View File

@ -26,7 +26,7 @@ void sk_init(void); /* called once at program startup */
SockAddr sk_namelookup(char *host, char **canonicalname);
void sk_addr_free(SockAddr addr);
Socket sk_new(SockAddr addr, int port, sk_receiver_t receiver);
Socket sk_new(SockAddr addr, int port, int privport, sk_receiver_t receiver);
void sk_close(Socket s);
void sk_write(Socket s, char *buf, int len);
void sk_write_oob(Socket s, char *buf, int len);

View File

@ -137,7 +137,7 @@ typedef struct {
/* Basic options */
char host[512];
int port;
enum { PROT_RAW, PROT_TELNET, PROT_SSH } protocol;
enum { PROT_RAW, PROT_TELNET, PROT_RLOGIN, PROT_SSH } protocol;
int close_on_exit;
int warn_on_close;
int ping_interval; /* in seconds */
@ -156,6 +156,7 @@ typedef struct {
char termspeed[32];
char environmt[1024]; /* VAR\tvalue\0VAR\tvalue\0\0 */
char username[32];
char localusername[32];
int rfc_environ;
/* Keyboard options */
int bksp_is_delete;
@ -333,6 +334,12 @@ void term_copyall(void);
extern Backend raw_backend;
/*
* Exports from rlogin.c.
*/
extern Backend rlogin_backend;
/*
* Exports from telnet.c.
*/

2
raw.c
View File

@ -59,7 +59,7 @@ static char *raw_init (char *host, int port, char **realhost) {
/*
* Open socket.
*/
s = sk_new(addr, port, raw_receive);
s = sk_new(addr, port, 0, raw_receive);
if ( (err = sk_socket_error(s)) )
return err;

149
rlogin.c Normal file
View File

@ -0,0 +1,149 @@
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include "putty.h"
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
static Socket s = NULL;
static void rlogin_size(void);
static int sb_opt, sb_len;
static char *sb_buf = NULL;
static int sb_size = 0;
#define SB_DELTA 1024
static void c_write (char *buf, int len) {
from_backend(0, buf, len);
}
static int rlogin_receive (Socket s, int urgent, char *data, int len) {
if (!len) {
/* Connection has closed. */
sk_close(s);
s = NULL;
return 0;
}
if (urgent == 2) {
char c;
int i;
c = *data++; len--;
if (c == 0x80)
rlogin_size();
/*
* We should flush everything (aka Telnet SYNCH) if we see
* 0x02, and we should turn off and on _local_ flow control
* on 0x10 and 0x20 respectively. I'm not convinced it's
* worth it...
*/
}
c_write(data, len);
return 1;
}
/*
* Called to set up the rlogin connection.
*
* Returns an error message, or NULL on success.
*
* Also places the canonical host name into `realhost'.
*/
static char *rlogin_init (char *host, int port, char **realhost) {
SockAddr addr;
char *err;
/*
* Try to find host.
*/
addr = sk_namelookup(host, realhost);
if ( (err = sk_addr_error(addr)) )
return err;
if (port < 0)
port = 513; /* default rlogin port */
/*
* Open socket.
*/
s = sk_new(addr, port, 1, rlogin_receive);
if ( (err = sk_socket_error(s)) )
return err;
sk_addr_free(addr);
/*
* Send local username, remote username, terminal/speed
*/
{
char z = 0;
char *p;
sk_write(s, &z, 1);
sk_write(s, cfg.localusername, strlen(cfg.localusername));
sk_write(s, &z, 1);
sk_write(s, cfg.username, strlen(cfg.username));
sk_write(s, &z, 1);
sk_write(s, cfg.termtype, strlen(cfg.termtype));
sk_write(s, "/", 1);
for(p = cfg.termspeed; isdigit(*p); p++);
sk_write(s, cfg.termspeed, p - cfg.termspeed);
sk_write(s, &z, 1);
}
begin_session();
return NULL;
}
/*
* Called to send data down the rlogin connection.
*/
static void rlogin_send (char *buf, int len) {
if (s == NULL)
return;
sk_write(s, buf, len);
}
/*
* Called to set the size of the window
*/
static void rlogin_size(void) {
char b[12] = { 0xFF, 0xFF, 0x73, 0x73, 0, 0, 0, 0, 0, 0, 0, 0 };
b[6] = cols >> 8; b[7] = cols & 0xFF;
b[4] = rows >> 8; b[5] = rows & 0xFF;
sk_write(s, b, 12);
return;
}
/*
* Send rlogin special codes.
*/
static void rlogin_special (Telnet_Special code) {
/* Do nothing! */
return;
}
static Socket rlogin_socket(void) { return s; }
static int rlogin_sendok(void) { return 1; }
Backend rlogin_backend = {
rlogin_init,
rlogin_send,
rlogin_size,
rlogin_special,
rlogin_socket,
rlogin_sendok,
1
};

View File

@ -68,6 +68,7 @@ void save_settings (char *section, int do_host, Config *cfg) {
write_setting_s (sesskey, "Environment", buf);
}
write_setting_s (sesskey, "UserName", cfg->username);
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, "AgentFwd", cfg->agentfwd);
@ -199,6 +200,7 @@ void load_settings (char *section, int do_host, Config *cfg) {
*q = '\0';
}
gpps (sesskey, "UserName", "", cfg->username, sizeof(cfg->username));
gpps (sesskey, "LocalUserName", "", cfg->localusername, sizeof(cfg->localusername));
gppi (sesskey, "NoPTY", 0, &cfg->nopty);
gppi (sesskey, "Compression", 0, &cfg->compression);
gppi (sesskey, "AgentFwd", 0, &cfg->agentfwd);

2
ssh.c
View File

@ -1184,7 +1184,7 @@ static char *connect_to_host(char *host, int port, char **realhost)
/*
* Open socket.
*/
s = sk_new(addr, port, ssh_receive);
s = sk_new(addr, port, 0, ssh_receive);
if ( (err = sk_socket_error(s)) )
return err;

View File

@ -495,7 +495,7 @@ static char *telnet_init (char *host, int port, char **realhost) {
/*
* Open socket.
*/
s = sk_new(addr, port, telnet_receive);
s = sk_new(addr, port, 0, telnet_receive);
if ( (err = sk_socket_error(s)) )
return err;

View File

@ -189,6 +189,7 @@ enum { IDCX_ABOUT = IDC_ABOUT, IDCX_TVSTATIC, IDCX_TREEVIEW, controlstartvalue,
IDC_PROTSTATIC,
IDC_PROTRAW,
IDC_PROTTELNET,
IDC_PROTRLOGIN,
IDC_PROTSSH,
IDC_SESSSTATIC,
IDC_SESSEDIT,
@ -317,6 +318,16 @@ enum { IDCX_ABOUT = IDC_ABOUT, IDCX_TVSTATIC, IDCX_TREEVIEW, controlstartvalue,
IDC_EMRFC,
telnetpanelend,
rloginpanelstart,
IDC_TITLE_RLOGIN,
IDC_BOX_RLOGIN1, IDC_BOXT_RLOGIN1,
IDC_BOX_RLOGIN2, IDC_BOXT_RLOGIN2,
IDC_R_TSSTATIC,
IDC_R_TSEDIT,
IDC_RLLUSERSTATIC,
IDC_RLLUSEREDIT,
rloginpanelend,
sshpanelstart,
IDC_TITLE_SSH,
IDC_BOX_SSH1, IDC_BOXT_SSH1,
@ -433,7 +444,8 @@ static void init_dlg_ctrls(HWND hwnd) {
SetDlgItemInt (hwnd, IDC_PORT, cfg.port, FALSE);
CheckRadioButton (hwnd, IDC_PROTRAW, IDC_PROTSSH,
cfg.protocol==PROT_SSH ? IDC_PROTSSH :
cfg.protocol==PROT_TELNET ? IDC_PROTTELNET : IDC_PROTRAW );
cfg.protocol==PROT_TELNET ? IDC_PROTTELNET :
cfg.protocol==PROT_RLOGIN ? IDC_PROTRLOGIN : IDC_PROTRAW );
SetDlgItemInt (hwnd, IDC_PINGEDIT, cfg.ping_interval, FALSE);
CheckRadioButton (hwnd, IDC_DEL008, IDC_DEL127,
@ -487,6 +499,8 @@ static void init_dlg_ctrls(HWND hwnd) {
SetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype);
SetDlgItemText (hwnd, IDC_TSEDIT, cfg.termspeed);
SetDlgItemText (hwnd, IDC_R_TSEDIT, cfg.termspeed);
SetDlgItemText (hwnd, IDC_RLLUSEREDIT, cfg.localusername);
SetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username);
SetDlgItemText (hwnd, IDC_LGFEDIT, cfg.logfilename);
CheckRadioButton(hwnd, IDC_LSTATOFF, IDC_LSTATRAW,
@ -693,13 +707,15 @@ static int GenericMainDlgProc (HWND hwnd, UINT msg,
"&Port", IDC_PORTSTATIC, IDC_PORT, 25, NULL);
if (backends[2].backend == NULL) {
/* this is PuTTYtel, so only two protocols available */
radioline(&cp, "Protocol:", IDC_PROTSTATIC, 3,
"&Raw", IDC_PROTRAW,
"&Telnet", IDC_PROTTELNET, NULL);
} else {
radioline(&cp, "Protocol:", IDC_PROTSTATIC, 3,
radioline(&cp, "Protocol:", IDC_PROTSTATIC, 4,
"&Raw", IDC_PROTRAW,
"&Telnet", IDC_PROTTELNET,
"R&login", IDC_PROTRLOGIN, NULL);
} else {
radioline(&cp, "Protocol:", IDC_PROTSTATIC, 4,
"&Raw", IDC_PROTRAW,
"&Telnet", IDC_PROTTELNET,
"R&login", IDC_PROTRLOGIN,
#ifdef FWHACK
"SS&H/hack",
#else
@ -993,6 +1009,23 @@ static int GenericMainDlgProc (HWND hwnd, UINT msg,
}
}
/* The Rlogin Panel */
{
struct ctlpos cp;
ctlposinit(&cp, hwnd, 80, 3, 13);
if (dlgtype == 0) {
bartitle(&cp, "Options controlling Rlogin connections", IDC_TITLE_RLOGIN);
beginbox(&cp, "Data to send to the server",
IDC_BOX_RLOGIN1, IDC_BOXT_RLOGIN1);
staticedit(&cp, "Terminal-&speed string", IDC_R_TSSTATIC, IDC_R_TSEDIT, 50);
staticedit(&cp, "&Local username:", IDC_RLLUSERSTATIC, IDC_RLLUSEREDIT, 50);
endbox(&cp);
treeview_insert(&tvfaff, 1, "Rlogin");
}
}
/* The SSH panel. Accelerators used: [acgo] rmakwp123bd */
if (backends[2].backend != NULL) {
struct ctlpos cp;
@ -1095,6 +1128,8 @@ static int GenericMainDlgProc (HWND hwnd, UINT msg,
hide(hwnd, FALSE, connectionpanelstart, connectionpanelend);
if (!strcmp(buffer, "Telnet"))
hide(hwnd, FALSE, telnetpanelstart, telnetpanelend);
if (!strcmp(buffer, "Rlogin"))
hide(hwnd, FALSE, rloginpanelstart, rloginpanelend);
if (!strcmp(buffer, "SSH"))
hide(hwnd, FALSE, sshpanelstart, sshpanelend);
if (!strcmp(buffer, "Selection"))
@ -1123,16 +1158,19 @@ static int GenericMainDlgProc (HWND hwnd, UINT msg,
EndDialog (hwnd, 0);
return 0;
case IDC_PROTTELNET:
case IDC_PROTRLOGIN:
case IDC_PROTSSH:
case IDC_PROTRAW:
if (HIWORD(wParam) == BN_CLICKED ||
HIWORD(wParam) == BN_DOUBLECLICKED) {
int i = IsDlgButtonChecked (hwnd, IDC_PROTSSH);
int j = IsDlgButtonChecked (hwnd, IDC_PROTTELNET);
cfg.protocol = i ? PROT_SSH : j ? PROT_TELNET : PROT_RAW ;
if ((cfg.protocol == PROT_SSH && cfg.port == 23) ||
(cfg.protocol == PROT_TELNET && cfg.port == 22)) {
cfg.port = i ? 22 : 23;
int k = IsDlgButtonChecked (hwnd, IDC_PROTRLOGIN);
cfg.protocol = i ? PROT_SSH : j ? PROT_TELNET : k ? PROT_RLOGIN : PROT_RAW ;
if ((cfg.protocol == PROT_SSH && cfg.port != 22) ||
(cfg.protocol == PROT_TELNET && cfg.port != 23) ||
(cfg.protocol == PROT_RLOGIN && cfg.port != 513)) {
cfg.port = i ? 22 : j ? 23 : 513;
SetDlgItemInt (hwnd, IDC_PORT, cfg.port, FALSE);
}
}
@ -1517,8 +1555,9 @@ static int GenericMainDlgProc (HWND hwnd, UINT msg,
}
break;
case IDC_TSEDIT:
case IDC_R_TSEDIT:
if (HIWORD(wParam) == EN_CHANGE)
GetDlgItemText (hwnd, IDC_TSEDIT, cfg.termspeed,
GetDlgItemText (hwnd, LOWORD(wParam), cfg.termspeed,
sizeof(cfg.termspeed)-1);
break;
case IDC_LOGEDIT:
@ -1526,6 +1565,11 @@ static int GenericMainDlgProc (HWND hwnd, UINT msg,
GetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username,
sizeof(cfg.username)-1);
break;
case IDC_RLLUSEREDIT:
if (HIWORD(wParam) == EN_CHANGE)
GetDlgItemText (hwnd, IDC_RLLUSEREDIT, cfg.localusername,
sizeof(cfg.localusername)-1);
break;
case IDC_EMBSD:
case IDC_EMRFC:
cfg.rfc_environ = IsDlgButtonChecked (hwnd, IDC_EMRFC);

View File

@ -288,7 +288,7 @@ void sk_addr_free(SockAddr addr) {
sfree(addr);
}
Socket sk_new(SockAddr addr, int port, sk_receiver_t receiver) {
Socket sk_new(SockAddr addr, int port, int privport, sk_receiver_t receiver) {
SOCKET s;
#ifdef IPV6
SOCKADDR_IN6 a6;
@ -298,6 +298,7 @@ Socket sk_new(SockAddr addr, int port, sk_receiver_t receiver) {
char *errstr;
Socket ret;
extern char *do_select(SOCKET skt, int startup);
short localport;
/*
* Create Socket structure.
@ -325,28 +326,56 @@ Socket sk_new(SockAddr addr, int port, sk_receiver_t receiver) {
/*
* Bind to local address.
*/
#ifdef IPV6
if (addr->family == AF_INET6)
{
memset(&a6,0,sizeof(a6));
a6.sin6_family = AF_INET6;
/*a6.sin6_addr = in6addr_any;*/ /* == 0 */
a6.sin6_port = htons(0);
}
if (privport)
localport = 1023; /* count from 1023 downwards */
else
{
#endif
a.sin_family = AF_INET;
a.sin_addr.s_addr = htonl(INADDR_ANY);
a.sin_port = htons(0);
localport = 0; /* just use port 0 (ie winsock picks) */
/* Loop round trying to bind */
while (1) {
int retcode;
#ifdef IPV6
}
if (bind (s, (addr->family == AF_INET6) ? (struct sockaddr *)&a6 : (struct sockaddr *)&a, (addr->family == AF_INET6) ? sizeof(a6) : sizeof(a)) == SOCKET_ERROR)
#else
if (bind (s, (struct sockaddr *)&a, sizeof(a)) == SOCKET_ERROR)
if (addr->family == AF_INET6)
{
memset(&a6,0,sizeof(a6));
a6.sin6_family = AF_INET6;
/*a6.sin6_addr = in6addr_any;*/ /* == 0 */
a6.sin6_port = htons(localport);
}
else
{
#endif
a.sin_family = AF_INET;
a.sin_addr.s_addr = htonl(INADDR_ANY);
a.sin_port = htons(localport);
#ifdef IPV6
}
retcode = bind (s, (addr->family == AF_INET6 ?
(struct sockaddr *)&a6 :
(struct sockaddr *)&a),
(addr->family == AF_INET6 ? sizeof(a6) : sizeof(a)));
#else
retcode = bind (s, (struct sockaddr *)&a, sizeof(a));
#endif
if (retcode != SOCKET_ERROR) {
err = 0;
break; /* done */
} else {
err = WSAGetLastError();
if (err != WSAEADDRINUSE) /* failed, for a bad reason */
break;
}
if (localport == 0)
break; /* we're only looping once */
localport--;
if (localport == 0)
break; /* we might have got to the end */
}
if (err)
{
err = WSAGetLastError();
ret->error = winsock_error_string(err);
return ret;
}