Experimental Rlogin support, thanks to Delian Delchev. Local flow
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Fri, 19 Jan 2001 10:10:37 +0000 (10:10 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Fri, 19 Jan 2001 10:10:37 +0000 (10:10 +0000)
control is unsupported, and server-to-client comms may fail for want
of working TCP Urgent.

git-svn-id: svn://svn.tartarus.org/sgt/putty@875 cda61777-01e9-0310-a592-d414129be87e

13 files changed:
Makefile
be_all.c
be_none.c
be_nossh.c
network.h
putty.h
raw.c
rlogin.c [new file with mode: 0644]
settings.c
ssh.c
telnet.c
windlg.c
winnet.c

index 79f3fcf..2dedf30 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -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
index 69e44b7..fc0755a 100644 (file)
--- a/be_all.c
+++ b/be_all.c
@@ -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}
 };
index d112143..a08a938 100644 (file)
--- a/be_none.c
+++ b/be_none.c
@@ -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}
 };
index d9777e0..54e0d42 100644 (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}
 };
index dda34bc..4608800 100644 (file)
--- a/network.h
+++ b/network.h
@@ -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);
diff --git a/putty.h b/putty.h
index d807989..34cf069 100644 (file)
--- a/putty.h
+++ b/putty.h
@@ -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;
@@ -334,6 +335,12 @@ void term_copyall(void);
 extern Backend raw_backend;
 
 /*
+ * Exports from rlogin.c.
+ */
+
+extern Backend rlogin_backend;
+
+/*
  * Exports from telnet.c.
  */
 
diff --git a/raw.c b/raw.c
index 833f843..61a7d66 100644 (file)
--- a/raw.c
+++ b/raw.c
@@ -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;
 
diff --git a/rlogin.c b/rlogin.c
new file mode 100644 (file)
index 0000000..bf1db8d
--- /dev/null
+++ b/rlogin.c
@@ -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
+};
index ada2b74..67fd748 100644 (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);
diff --git a/ssh.c b/ssh.c
index a864614..f75041b 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -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;
 
index 8eb6e8a..6797912 100644 (file)
--- a/telnet.c
+++ b/telnet.c
@@ -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;
 
index 96335fd..62b49d0 100644 (file)
--- a/windlg.c
+++ b/windlg.c
@@ -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,
+                   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
@@ -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);
index 86ae41c..53a40e8 100644 (file)
--- a/winnet.c
+++ b/winnet.c
@@ -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
-    {
+        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;
     }