+++ /dev/null
-/*\r
- * Rlogin backend.\r
- */\r
-\r
-#include <stdio.h>\r
-#include <stdlib.h>\r
-#include <ctype.h>\r
-\r
-#include "putty.h"\r
-\r
-#ifndef FALSE\r
-#define FALSE 0\r
-#endif\r
-#ifndef TRUE\r
-#define TRUE 1\r
-#endif\r
-\r
-#define RLOGIN_MAX_BACKLOG 4096\r
-\r
-typedef struct rlogin_tag {\r
- const struct plug_function_table *fn;\r
- /* the above field _must_ be first in the structure */\r
-\r
- Socket s;\r
- int bufsize;\r
- int firstbyte;\r
- int cansize;\r
- int term_width, term_height;\r
- void *frontend;\r
-\r
- Config cfg;\r
-\r
- /* In case we need to read a username from the terminal before starting */\r
- prompts_t *prompt;\r
-} *Rlogin;\r
-\r
-static void rlogin_size(void *handle, int width, int height);\r
-\r
-static void c_write(Rlogin rlogin, char *buf, int len)\r
-{\r
- int backlog = from_backend(rlogin->frontend, 0, buf, len);\r
- sk_set_frozen(rlogin->s, backlog > RLOGIN_MAX_BACKLOG);\r
-}\r
-\r
-static void rlogin_log(Plug plug, int type, SockAddr addr, int port,\r
- const char *error_msg, int error_code)\r
-{\r
- Rlogin rlogin = (Rlogin) plug;\r
- char addrbuf[256], *msg;\r
-\r
- sk_getaddr(addr, addrbuf, lenof(addrbuf));\r
-\r
- if (type == 0)\r
- msg = dupprintf("Connecting to %s port %d", addrbuf, port);\r
- else\r
- msg = dupprintf("Failed to connect to %s: %s", addrbuf, error_msg);\r
-\r
- logevent(rlogin->frontend, msg);\r
-}\r
-\r
-static int rlogin_closing(Plug plug, const char *error_msg, int error_code,\r
- int calling_back)\r
-{\r
- Rlogin rlogin = (Rlogin) plug;\r
- if (rlogin->s) {\r
- sk_close(rlogin->s);\r
- rlogin->s = NULL;\r
- notify_remote_exit(rlogin->frontend);\r
- }\r
- if (error_msg) {\r
- /* A socket error has occurred. */\r
- logevent(rlogin->frontend, error_msg);\r
- connection_fatal(rlogin->frontend, "%s", error_msg);\r
- } /* Otherwise, the remote side closed the connection normally. */\r
- return 0;\r
-}\r
-\r
-static int rlogin_receive(Plug plug, int urgent, char *data, int len)\r
-{\r
- Rlogin rlogin = (Rlogin) plug;\r
- if (urgent == 2) {\r
- char c;\r
-\r
- c = *data++;\r
- len--;\r
- if (c == '\x80') {\r
- rlogin->cansize = 1;\r
- rlogin_size(rlogin, rlogin->term_width, rlogin->term_height);\r
- }\r
- /*\r
- * We should flush everything (aka Telnet SYNCH) if we see\r
- * 0x02, and we should turn off and on _local_ flow control\r
- * on 0x10 and 0x20 respectively. I'm not convinced it's\r
- * worth it...\r
- */\r
- } else {\r
- /*\r
- * Main rlogin protocol. This is really simple: the first\r
- * byte is expected to be NULL and is ignored, and the rest\r
- * is printed.\r
- */\r
- if (rlogin->firstbyte) {\r
- if (data[0] == '\0') {\r
- data++;\r
- len--;\r
- }\r
- rlogin->firstbyte = 0;\r
- }\r
- if (len > 0)\r
- c_write(rlogin, data, len);\r
- }\r
- return 1;\r
-}\r
-\r
-static void rlogin_sent(Plug plug, int bufsize)\r
-{\r
- Rlogin rlogin = (Rlogin) plug;\r
- rlogin->bufsize = bufsize;\r
-}\r
-\r
-static void rlogin_startup(Rlogin rlogin, const char *ruser)\r
-{\r
- char z = 0;\r
- char *p;\r
- sk_write(rlogin->s, &z, 1);\r
- sk_write(rlogin->s, rlogin->cfg.localusername,\r
- strlen(rlogin->cfg.localusername));\r
- sk_write(rlogin->s, &z, 1);\r
- sk_write(rlogin->s, ruser,\r
- strlen(ruser));\r
- sk_write(rlogin->s, &z, 1);\r
- sk_write(rlogin->s, rlogin->cfg.termtype,\r
- strlen(rlogin->cfg.termtype));\r
- sk_write(rlogin->s, "/", 1);\r
- for (p = rlogin->cfg.termspeed; isdigit((unsigned char)*p); p++) continue;\r
- sk_write(rlogin->s, rlogin->cfg.termspeed, p - rlogin->cfg.termspeed);\r
- rlogin->bufsize = sk_write(rlogin->s, &z, 1);\r
-\r
- rlogin->prompt = NULL;\r
-}\r
-\r
-/*\r
- * Called to set up the rlogin connection.\r
- * \r
- * Returns an error message, or NULL on success.\r
- *\r
- * Also places the canonical host name into `realhost'. It must be\r
- * freed by the caller.\r
- */\r
-static const char *rlogin_init(void *frontend_handle, void **backend_handle,\r
- Config *cfg,\r
- char *host, int port, char **realhost,\r
- int nodelay, int keepalive)\r
-{\r
- static const struct plug_function_table fn_table = {\r
- rlogin_log,\r
- rlogin_closing,\r
- rlogin_receive,\r
- rlogin_sent\r
- };\r
- SockAddr addr;\r
- const char *err;\r
- Rlogin rlogin;\r
- char ruser[sizeof(cfg->username)];\r
-\r
- rlogin = snew(struct rlogin_tag);\r
- rlogin->fn = &fn_table;\r
- rlogin->s = NULL;\r
- rlogin->frontend = frontend_handle;\r
- rlogin->term_width = cfg->width;\r
- rlogin->term_height = cfg->height;\r
- rlogin->firstbyte = 1;\r
- rlogin->cansize = 0;\r
- rlogin->prompt = NULL;\r
- rlogin->cfg = *cfg; /* STRUCTURE COPY */\r
- *backend_handle = rlogin;\r
-\r
- /*\r
- * Try to find host.\r
- */\r
- {\r
- char *buf;\r
- buf = dupprintf("Looking up host \"%s\"%s", host,\r
- (cfg->addressfamily == ADDRTYPE_IPV4 ? " (IPv4)" :\r
- (cfg->addressfamily == ADDRTYPE_IPV6 ? " (IPv6)" :\r
- "")));\r
- logevent(rlogin->frontend, buf);\r
- sfree(buf);\r
- }\r
- addr = name_lookup(host, port, realhost, cfg, cfg->addressfamily);\r
- if ((err = sk_addr_error(addr)) != NULL) {\r
- sk_addr_free(addr);\r
- return err;\r
- }\r
-\r
- if (port < 0)\r
- port = 513; /* default rlogin port */\r
-\r
- /*\r
- * Open socket.\r
- */\r
- rlogin->s = new_connection(addr, *realhost, port, 1, 0,\r
- nodelay, keepalive, (Plug) rlogin, cfg);\r
- if ((err = sk_socket_error(rlogin->s)) != NULL)\r
- return err;\r
-\r
- if (*cfg->loghost) {\r
- char *colon;\r
-\r
- sfree(*realhost);\r
- *realhost = dupstr(cfg->loghost);\r
- colon = strrchr(*realhost, ':');\r
- if (colon) {\r
- /*\r
- * FIXME: if we ever update this aspect of ssh.c for\r
- * IPv6 literal management, this should change in line\r
- * with it.\r
- */\r
- *colon++ = '\0';\r
- }\r
- }\r
-\r
- /*\r
- * Send local username, remote username, terminal type and\r
- * terminal speed - unless we don't have the remote username yet,\r
- * in which case we prompt for it and may end up deferring doing\r
- * anything else until the local prompt mechanism returns.\r
- */\r
- if (get_remote_username(cfg, ruser, sizeof(ruser))) {\r
- rlogin_startup(rlogin, ruser);\r
- } else {\r
- int ret;\r
-\r
- rlogin->prompt = new_prompts(rlogin->frontend);\r
- rlogin->prompt->to_server = TRUE;\r
- rlogin->prompt->name = dupstr("Rlogin login name");\r
- add_prompt(rlogin->prompt, dupstr("rlogin username: "), TRUE,\r
- sizeof(cfg->username)); \r
- ret = get_userpass_input(rlogin->prompt, NULL, 0);\r
- if (ret >= 0) {\r
- rlogin_startup(rlogin, rlogin->prompt->prompts[0]->result);\r
- }\r
- }\r
-\r
- return NULL;\r
-}\r
-\r
-static void rlogin_free(void *handle)\r
-{\r
- Rlogin rlogin = (Rlogin) handle;\r
-\r
- if (rlogin->prompt)\r
- free_prompts(rlogin->prompt);\r
- if (rlogin->s)\r
- sk_close(rlogin->s);\r
- sfree(rlogin);\r
-}\r
-\r
-/*\r
- * Stub routine (we don't have any need to reconfigure this backend).\r
- */\r
-static void rlogin_reconfig(void *handle, Config *cfg)\r
-{\r
-}\r
-\r
-/*\r
- * Called to send data down the rlogin connection.\r
- */\r
-static int rlogin_send(void *handle, char *buf, int len)\r
-{\r
- Rlogin rlogin = (Rlogin) handle;\r
-\r
- if (rlogin->s == NULL)\r
- return 0;\r
-\r
- if (rlogin->prompt) {\r
- /*\r
- * We're still prompting for a username, and aren't talking\r
- * directly to the network connection yet.\r
- */\r
- int ret = get_userpass_input(rlogin->prompt,\r
- (unsigned char *)buf, len);\r
- if (ret >= 0) {\r
- rlogin_startup(rlogin, rlogin->prompt->prompts[0]->result);\r
- /* that nulls out rlogin->prompt, so then we'll start sending\r
- * data down the wire in the obvious way */\r
- }\r
- } else {\r
- rlogin->bufsize = sk_write(rlogin->s, buf, len);\r
- }\r
-\r
- return rlogin->bufsize;\r
-}\r
-\r
-/*\r
- * Called to query the current socket sendability status.\r
- */\r
-static int rlogin_sendbuffer(void *handle)\r
-{\r
- Rlogin rlogin = (Rlogin) handle;\r
- return rlogin->bufsize;\r
-}\r
-\r
-/*\r
- * Called to set the size of the window\r
- */\r
-static void rlogin_size(void *handle, int width, int height)\r
-{\r
- Rlogin rlogin = (Rlogin) handle;\r
- char b[12] = { '\xFF', '\xFF', 0x73, 0x73, 0, 0, 0, 0, 0, 0, 0, 0 };\r
-\r
- rlogin->term_width = width;\r
- rlogin->term_height = height;\r
-\r
- if (rlogin->s == NULL || !rlogin->cansize)\r
- return;\r
-\r
- b[6] = rlogin->term_width >> 8;\r
- b[7] = rlogin->term_width & 0xFF;\r
- b[4] = rlogin->term_height >> 8;\r
- b[5] = rlogin->term_height & 0xFF;\r
- rlogin->bufsize = sk_write(rlogin->s, b, 12);\r
- return;\r
-}\r
-\r
-/*\r
- * Send rlogin special codes.\r
- */\r
-static void rlogin_special(void *handle, Telnet_Special code)\r
-{\r
- /* Do nothing! */\r
- return;\r
-}\r
-\r
-/*\r
- * Return a list of the special codes that make sense in this\r
- * protocol.\r
- */\r
-static const struct telnet_special *rlogin_get_specials(void *handle)\r
-{\r
- return NULL;\r
-}\r
-\r
-static int rlogin_connected(void *handle)\r
-{\r
- Rlogin rlogin = (Rlogin) handle;\r
- return rlogin->s != NULL;\r
-}\r
-\r
-static int rlogin_sendok(void *handle)\r
-{\r
- /* Rlogin rlogin = (Rlogin) handle; */\r
- return 1;\r
-}\r
-\r
-static void rlogin_unthrottle(void *handle, int backlog)\r
-{\r
- Rlogin rlogin = (Rlogin) handle;\r
- sk_set_frozen(rlogin->s, backlog > RLOGIN_MAX_BACKLOG);\r
-}\r
-\r
-static int rlogin_ldisc(void *handle, int option)\r
-{\r
- /* Rlogin rlogin = (Rlogin) handle; */\r
- return 0;\r
-}\r
-\r
-static void rlogin_provide_ldisc(void *handle, void *ldisc)\r
-{\r
- /* This is a stub. */\r
-}\r
-\r
-static void rlogin_provide_logctx(void *handle, void *logctx)\r
-{\r
- /* This is a stub. */\r
-}\r
-\r
-static int rlogin_exitcode(void *handle)\r
-{\r
- Rlogin rlogin = (Rlogin) handle;\r
- if (rlogin->s != NULL)\r
- return -1; /* still connected */\r
- else\r
- /* If we ever implement RSH, we'll probably need to do this properly */\r
- return 0;\r
-}\r
-\r
-/*\r
- * cfg_info for rlogin does nothing at all.\r
- */\r
-static int rlogin_cfg_info(void *handle)\r
-{\r
- return 0;\r
-}\r
-\r
-Backend rlogin_backend = {\r
- rlogin_init,\r
- rlogin_free,\r
- rlogin_reconfig,\r
- rlogin_send,\r
- rlogin_sendbuffer,\r
- rlogin_size,\r
- rlogin_special,\r
- rlogin_get_specials,\r
- rlogin_connected,\r
- rlogin_exitcode,\r
- rlogin_sendok,\r
- rlogin_ldisc,\r
- rlogin_provide_ldisc,\r
- rlogin_provide_logctx,\r
- rlogin_unthrottle,\r
- rlogin_cfg_info,\r
- "rlogin",\r
- PROT_RLOGIN,\r
- 513\r
-};\r