1 /*
2  * Rlogin backend.
3  */
4 
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <limits.h>
8 #include <ctype.h>
9 
10 #include "putty.h"
11 
12 #define RLOGIN_MAX_BACKLOG 4096
13 
14 typedef struct Rlogin Rlogin;
15 struct Rlogin {
16     Socket *s;
17     bool closed_on_socket_error;
18     int bufsize;
19     bool firstbyte;
20     bool cansize;
21     int term_width, term_height;
22     Seat *seat;
23     LogContext *logctx;
24 
25     Conf *conf;
26 
27     /* In case we need to read a username from the terminal before starting */
28     prompts_t *prompt;
29 
30     Plug plug;
31     Backend backend;
32 };
33 
c_write(Rlogin * rlogin,const void * buf,size_t len)34 static void c_write(Rlogin *rlogin, const void *buf, size_t len)
35 {
36     size_t backlog = seat_stdout(rlogin->seat, buf, len);
37     sk_set_frozen(rlogin->s, backlog > RLOGIN_MAX_BACKLOG);
38 }
39 
rlogin_log(Plug * plug,PlugLogType type,SockAddr * addr,int port,const char * error_msg,int error_code)40 static void rlogin_log(Plug *plug, PlugLogType type, SockAddr *addr, int port,
41                        const char *error_msg, int error_code)
42 {
43     Rlogin *rlogin = container_of(plug, Rlogin, plug);
44     backend_socket_log(rlogin->seat, rlogin->logctx, type, addr, port,
45                        error_msg, error_code,
46                        rlogin->conf, !rlogin->firstbyte);
47 }
48 
rlogin_closing(Plug * plug,const char * error_msg,int error_code,bool calling_back)49 static void rlogin_closing(Plug *plug, const char *error_msg, int error_code,
50                            bool calling_back)
51 {
52     Rlogin *rlogin = container_of(plug, Rlogin, plug);
53 
54     /*
55      * We don't implement independent EOF in each direction for Telnet
56      * connections; as soon as we get word that the remote side has
57      * sent us EOF, we wind up the whole connection.
58      */
59 
60     if (rlogin->s) {
61         sk_close(rlogin->s);
62         rlogin->s = NULL;
63         if (error_msg)
64             rlogin->closed_on_socket_error = true;
65         seat_notify_remote_exit(rlogin->seat);
66     }
67     if (error_msg) {
68         /* A socket error has occurred. */
69         logevent(rlogin->logctx, error_msg);
70         seat_connection_fatal(rlogin->seat, "%s", error_msg);
71     }                                  /* Otherwise, the remote side closed the connection normally. */
72 }
73 
rlogin_receive(Plug * plug,int urgent,const char * data,size_t len)74 static void rlogin_receive(
75     Plug *plug, int urgent, const char *data, size_t len)
76 {
77     Rlogin *rlogin = container_of(plug, Rlogin, plug);
78     if (len == 0)
79         return;
80     if (urgent == 2) {
81         char c;
82 
83         c = *data++;
84         len--;
85         if (c == '\x80') {
86             rlogin->cansize = true;
87             backend_size(&rlogin->backend,
88                          rlogin->term_width, rlogin->term_height);
89         }
90         /*
91          * We should flush everything (aka Telnet SYNCH) if we see
92          * 0x02, and we should turn off and on _local_ flow control
93          * on 0x10 and 0x20 respectively. I'm not convinced it's
94          * worth it...
95          */
96     } else {
97         /*
98          * Main rlogin protocol. This is really simple: the first
99          * byte is expected to be NULL and is ignored, and the rest
100          * is printed.
101          */
102         if (rlogin->firstbyte) {
103             if (data[0] == '\0') {
104                 data++;
105                 len--;
106             }
107             rlogin->firstbyte = false;
108         }
109         if (len > 0)
110             c_write(rlogin, data, len);
111     }
112 }
113 
rlogin_sent(Plug * plug,size_t bufsize)114 static void rlogin_sent(Plug *plug, size_t bufsize)
115 {
116     Rlogin *rlogin = container_of(plug, Rlogin, plug);
117     rlogin->bufsize = bufsize;
118 }
119 
rlogin_startup(Rlogin * rlogin,const char * ruser)120 static void rlogin_startup(Rlogin *rlogin, const char *ruser)
121 {
122     char z = 0;
123     char *p;
124 
125     sk_write(rlogin->s, &z, 1);
126     p = conf_get_str(rlogin->conf, CONF_localusername);
127     sk_write(rlogin->s, p, strlen(p));
128     sk_write(rlogin->s, &z, 1);
129     sk_write(rlogin->s, ruser, strlen(ruser));
130     sk_write(rlogin->s, &z, 1);
131     p = conf_get_str(rlogin->conf, CONF_termtype);
132     sk_write(rlogin->s, p, strlen(p));
133     sk_write(rlogin->s, "/", 1);
134     p = conf_get_str(rlogin->conf, CONF_termspeed);
135     sk_write(rlogin->s, p, strspn(p, "0123456789"));
136     rlogin->bufsize = sk_write(rlogin->s, &z, 1);
137 
138     rlogin->prompt = NULL;
139 }
140 
141 static const PlugVtable Rlogin_plugvt = {
142     .log = rlogin_log,
143     .closing = rlogin_closing,
144     .receive = rlogin_receive,
145     .sent = rlogin_sent,
146 };
147 
148 /*
149  * Called to set up the rlogin connection.
150  *
151  * Returns an error message, or NULL on success.
152  *
153  * Also places the canonical host name into `realhost'. It must be
154  * freed by the caller.
155  */
rlogin_init(const BackendVtable * vt,Seat * seat,Backend ** backend_handle,LogContext * logctx,Conf * conf,const char * host,int port,char ** realhost,bool nodelay,bool keepalive)156 static char *rlogin_init(const BackendVtable *vt, Seat *seat,
157                          Backend **backend_handle, LogContext *logctx,
158                          Conf *conf, const char *host, int port,
159                          char **realhost, bool nodelay, bool keepalive)
160 {
161     SockAddr *addr;
162     const char *err;
163     Rlogin *rlogin;
164     char *ruser;
165     int addressfamily;
166     char *loghost;
167 
168     rlogin = snew(Rlogin);
169     rlogin->plug.vt = &Rlogin_plugvt;
170     rlogin->backend.vt = vt;
171     rlogin->s = NULL;
172     rlogin->closed_on_socket_error = false;
173     rlogin->seat = seat;
174     rlogin->logctx = logctx;
175     rlogin->term_width = conf_get_int(conf, CONF_width);
176     rlogin->term_height = conf_get_int(conf, CONF_height);
177     rlogin->firstbyte = true;
178     rlogin->cansize = false;
179     rlogin->prompt = NULL;
180     rlogin->conf = conf_copy(conf);
181     *backend_handle = &rlogin->backend;
182 
183     addressfamily = conf_get_int(conf, CONF_addressfamily);
184     /*
185      * Try to find host.
186      */
187     addr = name_lookup(host, port, realhost, conf, addressfamily,
188                        rlogin->logctx, "rlogin connection");
189     if ((err = sk_addr_error(addr)) != NULL) {
190         sk_addr_free(addr);
191         return dupstr(err);
192     }
193 
194     if (port < 0)
195         port = 513;                    /* default rlogin port */
196 
197     /*
198      * Open socket.
199      */
200     rlogin->s = new_connection(addr, *realhost, port, true, false,
201                                nodelay, keepalive, &rlogin->plug, conf);
202     if ((err = sk_socket_error(rlogin->s)) != NULL)
203         return dupstr(err);
204 
205     loghost = conf_get_str(conf, CONF_loghost);
206     if (*loghost) {
207         char *colon;
208 
209         sfree(*realhost);
210         *realhost = dupstr(loghost);
211 
212         colon = host_strrchr(*realhost, ':');
213         if (colon)
214             *colon++ = '\0';
215     }
216 
217     /*
218      * Send local username, remote username, terminal type and
219      * terminal speed - unless we don't have the remote username yet,
220      * in which case we prompt for it and may end up deferring doing
221      * anything else until the local prompt mechanism returns.
222      */
223     if ((ruser = get_remote_username(conf)) != NULL) {
224         /* Next terminal output will come from server */
225         seat_set_trust_status(rlogin->seat, false);
226         rlogin_startup(rlogin, ruser);
227         sfree(ruser);
228     } else {
229         int ret;
230 
231         rlogin->prompt = new_prompts();
232         rlogin->prompt->to_server = true;
233         rlogin->prompt->from_server = false;
234         rlogin->prompt->name = dupstr("Rlogin login name");
235         add_prompt(rlogin->prompt, dupstr("rlogin username: "), true);
236         ret = seat_get_userpass_input(rlogin->seat, rlogin->prompt, NULL);
237         if (ret >= 0) {
238             /* Next terminal output will come from server */
239             seat_set_trust_status(rlogin->seat, false);
240             rlogin_startup(rlogin, prompt_get_result_ref(
241                                rlogin->prompt->prompts[0]));
242         }
243     }
244 
245     return NULL;
246 }
247 
rlogin_free(Backend * be)248 static void rlogin_free(Backend *be)
249 {
250     Rlogin *rlogin = container_of(be, Rlogin, backend);
251 
252     if (rlogin->prompt)
253         free_prompts(rlogin->prompt);
254     if (rlogin->s)
255         sk_close(rlogin->s);
256     conf_free(rlogin->conf);
257     sfree(rlogin);
258 }
259 
260 /*
261  * Stub routine (we don't have any need to reconfigure this backend).
262  */
rlogin_reconfig(Backend * be,Conf * conf)263 static void rlogin_reconfig(Backend *be, Conf *conf)
264 {
265 }
266 
267 /*
268  * Called to send data down the rlogin connection.
269  */
rlogin_send(Backend * be,const char * buf,size_t len)270 static size_t rlogin_send(Backend *be, const char *buf, size_t len)
271 {
272     Rlogin *rlogin = container_of(be, Rlogin, backend);
273     bufchain bc;
274 
275     if (rlogin->s == NULL)
276         return 0;
277 
278     bufchain_init(&bc);
279     bufchain_add(&bc, buf, len);
280 
281     if (rlogin->prompt) {
282         /*
283          * We're still prompting for a username, and aren't talking
284          * directly to the network connection yet.
285          */
286         int ret = seat_get_userpass_input(rlogin->seat, rlogin->prompt, &bc);
287         if (ret >= 0) {
288             /* Next terminal output will come from server */
289             seat_set_trust_status(rlogin->seat, false);
290             rlogin_startup(rlogin, prompt_get_result_ref(
291                                rlogin->prompt->prompts[0]));
292             /* that nulls out rlogin->prompt, so then we'll start sending
293              * data down the wire in the obvious way */
294         }
295     }
296 
297     if (!rlogin->prompt) {
298         while (bufchain_size(&bc) > 0) {
299             ptrlen data = bufchain_prefix(&bc);
300             rlogin->bufsize = sk_write(rlogin->s, data.ptr, data.len);
301             bufchain_consume(&bc, len);
302         }
303     }
304 
305     bufchain_clear(&bc);
306 
307     return rlogin->bufsize;
308 }
309 
310 /*
311  * Called to query the current socket sendability status.
312  */
rlogin_sendbuffer(Backend * be)313 static size_t rlogin_sendbuffer(Backend *be)
314 {
315     Rlogin *rlogin = container_of(be, Rlogin, backend);
316     return rlogin->bufsize;
317 }
318 
319 /*
320  * Called to set the size of the window
321  */
rlogin_size(Backend * be,int width,int height)322 static void rlogin_size(Backend *be, int width, int height)
323 {
324     Rlogin *rlogin = container_of(be, Rlogin, backend);
325     char b[12] = { '\xFF', '\xFF', 0x73, 0x73, 0, 0, 0, 0, 0, 0, 0, 0 };
326 
327     rlogin->term_width = width;
328     rlogin->term_height = height;
329 
330     if (rlogin->s == NULL || !rlogin->cansize)
331         return;
332 
333     b[6] = rlogin->term_width >> 8;
334     b[7] = rlogin->term_width & 0xFF;
335     b[4] = rlogin->term_height >> 8;
336     b[5] = rlogin->term_height & 0xFF;
337     rlogin->bufsize = sk_write(rlogin->s, b, 12);
338     return;
339 }
340 
341 /*
342  * Send rlogin special codes.
343  */
rlogin_special(Backend * be,SessionSpecialCode code,int arg)344 static void rlogin_special(Backend *be, SessionSpecialCode code, int arg)
345 {
346     /* Do nothing! */
347     return;
348 }
349 
350 /*
351  * Return a list of the special codes that make sense in this
352  * protocol.
353  */
rlogin_get_specials(Backend * be)354 static const SessionSpecial *rlogin_get_specials(Backend *be)
355 {
356     return NULL;
357 }
358 
rlogin_connected(Backend * be)359 static bool rlogin_connected(Backend *be)
360 {
361     Rlogin *rlogin = container_of(be, Rlogin, backend);
362     return rlogin->s != NULL;
363 }
364 
rlogin_sendok(Backend * be)365 static bool rlogin_sendok(Backend *be)
366 {
367     /* Rlogin *rlogin = container_of(be, Rlogin, backend); */
368     return true;
369 }
370 
rlogin_unthrottle(Backend * be,size_t backlog)371 static void rlogin_unthrottle(Backend *be, size_t backlog)
372 {
373     Rlogin *rlogin = container_of(be, Rlogin, backend);
374     sk_set_frozen(rlogin->s, backlog > RLOGIN_MAX_BACKLOG);
375 }
376 
rlogin_ldisc(Backend * be,int option)377 static bool rlogin_ldisc(Backend *be, int option)
378 {
379     /* Rlogin *rlogin = container_of(be, Rlogin, backend); */
380     return false;
381 }
382 
rlogin_provide_ldisc(Backend * be,Ldisc * ldisc)383 static void rlogin_provide_ldisc(Backend *be, Ldisc *ldisc)
384 {
385     /* This is a stub. */
386 }
387 
rlogin_exitcode(Backend * be)388 static int rlogin_exitcode(Backend *be)
389 {
390     Rlogin *rlogin = container_of(be, Rlogin, backend);
391     if (rlogin->s != NULL)
392         return -1;                     /* still connected */
393     else if (rlogin->closed_on_socket_error)
394         return INT_MAX;     /* a socket error counts as an unclean exit */
395     else
396         /* If we ever implement RSH, we'll probably need to do this properly */
397         return 0;
398 }
399 
400 /*
401  * cfg_info for rlogin does nothing at all.
402  */
rlogin_cfg_info(Backend * be)403 static int rlogin_cfg_info(Backend *be)
404 {
405     return 0;
406 }
407 
408 const BackendVtable rlogin_backend = {
409     .init = rlogin_init,
410     .free = rlogin_free,
411     .reconfig = rlogin_reconfig,
412     .send = rlogin_send,
413     .sendbuffer = rlogin_sendbuffer,
414     .size = rlogin_size,
415     .special = rlogin_special,
416     .get_specials = rlogin_get_specials,
417     .connected = rlogin_connected,
418     .exitcode = rlogin_exitcode,
419     .sendok = rlogin_sendok,
420     .ldisc_option_state = rlogin_ldisc,
421     .provide_ldisc = rlogin_provide_ldisc,
422     .unthrottle = rlogin_unthrottle,
423     .cfg_info = rlogin_cfg_info,
424     .id = "rlogin",
425     .displayname = "Rlogin",
426     .protocol = PROT_RLOGIN,
427     .default_port = 513,
428 };
429