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
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
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}
};
struct backend_list backends[] = {
{PROT_SSH, "ssh", NULL},
{PROT_TELNET, "telnet", NULL},
+ {PROT_RLOGIN, "rlogin", NULL},
{PROT_RAW, "raw", NULL},
{0, NULL}
};
struct backend_list backends[] = {
{PROT_TELNET, "telnet", &telnet_backend},
+ {PROT_RLOGIN, "rlogin", &rlogin_backend},
{PROT_RAW, "raw", &raw_backend},
{0, NULL}
};
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);
/* 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 */
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;
extern Backend raw_backend;
/*
+ * Exports from rlogin.c.
+ */
+
+extern Backend rlogin_backend;
+
+/*
* Exports from telnet.c.
*/
/*
* 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;
--- /dev/null
+#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
+};
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);
*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);
/*
* 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;
/*
* 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;
IDC_PROTSTATIC,
IDC_PROTRAW,
IDC_PROTTELNET,
+ IDC_PROTRLOGIN,
IDC_PROTSSH,
IDC_SESSSTATIC,
IDC_SESSEDIT,
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,
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,
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,
"&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,
+ radioline(&cp, "Protocol:", IDC_PROTSTATIC, 4,
"&Raw", IDC_PROTRAW,
- "&Telnet", IDC_PROTTELNET, NULL);
+ "&Telnet", IDC_PROTTELNET,
+ "R&login", IDC_PROTRLOGIN, NULL);
} else {
- radioline(&cp, "Protocol:", IDC_PROTSTATIC, 3,
+ radioline(&cp, "Protocol:", IDC_PROTSTATIC, 4,
"&Raw", IDC_PROTRAW,
"&Telnet", IDC_PROTTELNET,
+ "R&login", IDC_PROTRLOGIN,
#ifdef FWHACK
"SS&H/hack",
#else
}
}
+
+ /* 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;
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"))
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);
}
}
}
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:
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);
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;
char *errstr;
Socket ret;
extern char *do_select(SOCKET skt, int startup);
+ short localport;
/*
* Create Socket structure.
/*
* 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
- {
+ localport = 0; /* just use port 0 (ie winsock picks) */
+
+ /* Loop round trying to bind */
+ while (1) {
+ int retcode;
+
+#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(localport);
+ }
+ else
+ {
#endif
- a.sin_family = AF_INET;
- a.sin_addr.s_addr = htonl(INADDR_ANY);
- a.sin_port = htons(0);
+ a.sin_family = AF_INET;
+ a.sin_addr.s_addr = htonl(INADDR_ANY);
+ a.sin_port = htons(localport);
#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)
+ }
+ retcode = bind (s, (addr->family == AF_INET6 ?
+ (struct sockaddr *)&a6 :
+ (struct sockaddr *)&a),
+ (addr->family == AF_INET6 ? sizeof(a6) : sizeof(a)));
#else
- if (bind (s, (struct sockaddr *)&a, sizeof(a)) == SOCKET_ERROR)
+ 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;
}