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