Annotation of src/usr.bin/ssh/channel.c, Revision 1.2
1.1 markus 1: /*
2: * Author: Tatu Ylonen <ylo@cs.hut.fi>
3: * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4: * All rights reserved
5: * This file contains functions for generic socket connection forwarding.
6: * There is also code for initiating connection forwarding for X11 connections,
7: * arbitrary tcp/ip connections, and the authentication agent connection.
8: *
9: * As far as I am concerned, the code I have written for this software
10: * can be used freely for any purpose. Any derived versions of this
11: * software must be clearly marked as such, and if the derived work is
12: * incompatible with the protocol description in the RFC file, it must be
13: * called by a name other than "ssh" or "Secure Shell".
14: *
15: *
16: * SSH2 support added by Markus Friedl.
17: * Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
18: * Copyright (c) 1999 Dug Song. All rights reserved.
19: * Copyright (c) 1999 Theo de Raadt. All rights reserved.
20: *
21: * Redistribution and use in source and binary forms, with or without
22: * modification, are permitted provided that the following conditions
23: * are met:
24: * 1. Redistributions of source code must retain the above copyright
25: * notice, this list of conditions and the following disclaimer.
26: * 2. Redistributions in binary form must reproduce the above copyright
27: * notice, this list of conditions and the following disclaimer in the
28: * documentation and/or other materials provided with the distribution.
29: *
30: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
31: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
32: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
33: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
34: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
35: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
39: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40: */
41:
42: #include "includes.h"
1.2 ! markus 43: RCSID("$OpenBSD: channel.c,v 1.1 2001/05/30 12:55:08 markus Exp $");
1.1 markus 44:
45: #include "ssh2.h"
46: #include "packet.h"
47: #include "xmalloc.h"
48: #include "log.h"
49: #include "misc.h"
50: #include "channel.h"
51: #include "compat.h"
52:
53: /*
54: * Pointer to an array containing all allocated channels. The array is
55: * dynamically extended as needed.
56: */
57: Channel **channels = NULL;
58:
59: /*
60: * Size of the channel array. All slots of the array must always be
61: * initialized (at least the type field); unused slots set to NULL
62: */
63: int channels_alloc = 0;
64:
65: /*
66: * Maximum file descriptor value used in any of the channels. This is
67: * updated in channel_new.
68: */
69: int channel_max_fd = 0;
70:
71:
72: Channel *
73: channel_lookup(int id)
74: {
75: Channel *c;
76:
77: if (id < 0 || id > channels_alloc) {
78: log("channel_lookup: %d: bad id", id);
79: return NULL;
80: }
81: c = channels[id];
82: if (c == NULL) {
83: log("channel_lookup: %d: bad id: channel free", id);
84: return NULL;
85: }
86: return c;
87: }
88:
89: /*
90: * Register filedescriptors for a channel, used when allocating a channel or
91: * when the channel consumer/producer is ready, e.g. shell exec'd
92: */
93:
94: void
95: channel_register_fds(Channel *c, int rfd, int wfd, int efd,
96: int extusage, int nonblock)
97: {
98: /* Update the maximum file descriptor value. */
99: channel_max_fd = MAX(channel_max_fd, rfd);
100: channel_max_fd = MAX(channel_max_fd, wfd);
101: channel_max_fd = MAX(channel_max_fd, efd);
102:
103: /* XXX set close-on-exec -markus */
104:
105: c->rfd = rfd;
106: c->wfd = wfd;
107: c->sock = (rfd == wfd) ? rfd : -1;
108: c->efd = efd;
109: c->extended_usage = extusage;
110:
111: /* XXX ugly hack: nonblock is only set by the server */
112: if (nonblock && isatty(c->rfd)) {
113: debug("channel %d: rfd %d isatty", c->self, c->rfd);
114: c->isatty = 1;
115: if (!isatty(c->wfd)) {
116: error("channel %d: wfd %d is not a tty?",
117: c->self, c->wfd);
118: }
119: } else {
120: c->isatty = 0;
121: }
122:
123: /* enable nonblocking mode */
124: if (nonblock) {
125: if (rfd != -1)
126: set_nonblock(rfd);
127: if (wfd != -1)
128: set_nonblock(wfd);
129: if (efd != -1)
130: set_nonblock(efd);
131: }
132: }
133:
134: /*
135: * Allocate a new channel object and set its type and socket. This will cause
136: * remote_name to be freed.
137: */
138:
139: Channel *
140: channel_new(char *ctype, int type, int rfd, int wfd, int efd,
141: int window, int maxpack, int extusage, char *remote_name, int nonblock)
142: {
143: int i, found;
144: Channel *c;
145:
146: /* Do initial allocation if this is the first call. */
147: if (channels_alloc == 0) {
148: chan_init();
149: channels_alloc = 10;
150: channels = xmalloc(channels_alloc * sizeof(Channel *));
151: for (i = 0; i < channels_alloc; i++)
152: channels[i] = NULL;
153: /*
154: * Kludge: arrange a call to channel_stop_listening if we
155: * terminate with fatal().
156: */
157: fatal_add_cleanup((void (*) (void *)) channel_stop_listening, NULL);
158: }
159: /* Try to find a free slot where to put the new channel. */
160: for (found = -1, i = 0; i < channels_alloc; i++)
161: if (channels[i] == NULL) {
162: /* Found a free slot. */
163: found = i;
164: break;
165: }
166: if (found == -1) {
167: /* There are no free slots. Take last+1 slot and expand the array. */
168: found = channels_alloc;
169: channels_alloc += 10;
170: debug2("channel: expanding %d", channels_alloc);
171: channels = xrealloc(channels, channels_alloc * sizeof(Channel *));
172: for (i = found; i < channels_alloc; i++)
173: channels[i] = NULL;
174: }
175: /* Initialize and return new channel. */
176: c = channels[found] = xmalloc(sizeof(Channel));
177: buffer_init(&c->input);
178: buffer_init(&c->output);
179: buffer_init(&c->extended);
180: chan_init_iostates(c);
181: channel_register_fds(c, rfd, wfd, efd, extusage, nonblock);
182: c->self = found;
183: c->type = type;
184: c->ctype = ctype;
185: c->local_window = window;
186: c->local_window_max = window;
187: c->local_consumed = 0;
188: c->local_maxpacket = maxpack;
189: c->remote_id = -1;
190: c->remote_name = remote_name;
191: c->remote_window = 0;
192: c->remote_maxpacket = 0;
193: c->cb_fn = NULL;
194: c->cb_arg = NULL;
195: c->cb_event = 0;
196: c->dettach_user = NULL;
197: c->input_filter = NULL;
198: debug("channel %d: new [%s]", found, remote_name);
199: return c;
200: }
201:
202: /* Close all channel fd/socket. */
203:
204: void
205: channel_close_fds(Channel *c)
206: {
207: debug3("channel_close_fds: channel %d: r %d w %d e %d",
208: c->self, c->rfd, c->wfd, c->efd);
209:
210: if (c->sock != -1) {
211: close(c->sock);
212: c->sock = -1;
213: }
214: if (c->rfd != -1) {
215: close(c->rfd);
216: c->rfd = -1;
217: }
218: if (c->wfd != -1) {
219: close(c->wfd);
220: c->wfd = -1;
221: }
222: if (c->efd != -1) {
223: close(c->efd);
224: c->efd = -1;
225: }
226: }
227:
228: /* Free the channel and close its fd/socket. */
229:
230: void
231: channel_free(Channel *c)
232: {
233: char *s;
234: int i, n;
235:
236: for (n = 0, i = 0; i < channels_alloc; i++)
237: if (channels[i])
238: n++;
239: debug("channel_free: channel %d: %s, nchannels %d", c->self,
240: c->remote_name ? c->remote_name : "???", n);
241:
242: s = channel_open_message();
243: debug3("channel_free: status: %s", s);
244: xfree(s);
245:
246: if (c->dettach_user != NULL) {
247: debug("channel_free: channel %d: dettaching channel user", c->self);
248: c->dettach_user(c->self, NULL);
249: }
250: if (c->sock != -1)
251: shutdown(c->sock, SHUT_RDWR);
252: channel_close_fds(c);
253: buffer_free(&c->input);
254: buffer_free(&c->output);
255: buffer_free(&c->extended);
256: if (c->remote_name) {
257: xfree(c->remote_name);
258: c->remote_name = NULL;
259: }
260: channels[c->self] = NULL;
261: xfree(c);
262: }
263:
264:
265: /*
266: * Stops listening for channels, and removes any unix domain sockets that we
267: * might have.
268: */
269:
270: void
271: channel_stop_listening()
272: {
273: int i;
274: Channel *c;
275:
276: for (i = 0; i < channels_alloc; i++) {
277: c = channels[i];
278: if (c != NULL) {
279: switch (c->type) {
280: case SSH_CHANNEL_AUTH_SOCKET:
281: close(c->sock);
282: unlink(c->path);
283: channel_free(c);
284: break;
285: case SSH_CHANNEL_PORT_LISTENER:
286: case SSH_CHANNEL_RPORT_LISTENER:
287: case SSH_CHANNEL_X11_LISTENER:
288: close(c->sock);
289: channel_free(c);
290: break;
291: default:
292: break;
293: }
294: }
295: }
296: }
297:
298: /*
299: * Closes the sockets/fds of all channels. This is used to close extra file
300: * descriptors after a fork.
301: */
302:
303: void
304: channel_close_all()
305: {
306: int i;
307:
308: for (i = 0; i < channels_alloc; i++)
309: if (channels[i] != NULL)
310: channel_close_fds(channels[i]);
311: }
312:
313: /*
314: * Returns true if no channel has too much buffered data, and false if one or
315: * more channel is overfull.
316: */
317:
318: int
319: channel_not_very_much_buffered_data()
320: {
321: u_int i;
322: Channel *c;
323:
324: for (i = 0; i < channels_alloc; i++) {
325: c = channels[i];
326: if (c != NULL && c->type == SSH_CHANNEL_OPEN) {
327: if (!compat20 && buffer_len(&c->input) > packet_get_maxsize()) {
328: debug("channel %d: big input buffer %d",
329: c->self, buffer_len(&c->input));
330: return 0;
331: }
332: if (buffer_len(&c->output) > packet_get_maxsize()) {
333: debug("channel %d: big output buffer %d",
334: c->self, buffer_len(&c->output));
335: return 0;
336: }
337: }
338: }
339: return 1;
340: }
341:
342: /* Returns true if any channel is still open. */
343:
344: int
345: channel_still_open()
346: {
347: int i;
348: Channel *c;
349:
350: for (i = 0; i < channels_alloc; i++) {
351: c = channels[i];
352: if (c == NULL)
353: continue;
354: switch (c->type) {
355: case SSH_CHANNEL_X11_LISTENER:
356: case SSH_CHANNEL_PORT_LISTENER:
357: case SSH_CHANNEL_RPORT_LISTENER:
358: case SSH_CHANNEL_CLOSED:
359: case SSH_CHANNEL_AUTH_SOCKET:
360: case SSH_CHANNEL_DYNAMIC:
361: case SSH_CHANNEL_CONNECTING:
362: case SSH_CHANNEL_ZOMBIE:
363: continue;
364: case SSH_CHANNEL_LARVAL:
365: if (!compat20)
366: fatal("cannot happen: SSH_CHANNEL_LARVAL");
367: continue;
368: case SSH_CHANNEL_OPENING:
369: case SSH_CHANNEL_OPEN:
370: case SSH_CHANNEL_X11_OPEN:
371: return 1;
372: case SSH_CHANNEL_INPUT_DRAINING:
373: case SSH_CHANNEL_OUTPUT_DRAINING:
374: if (!compat13)
375: fatal("cannot happen: OUT_DRAIN");
376: return 1;
377: default:
378: fatal("channel_still_open: bad channel type %d", c->type);
379: /* NOTREACHED */
380: }
381: }
382: return 0;
383: }
384:
385: /* Returns the id of an open channel suitable for keepaliving */
386:
387: int
388: channel_find_open()
389: {
390: int i;
391: Channel *c;
392:
393: for (i = 0; i < channels_alloc; i++) {
394: c = channels[i];
395: if (c == NULL)
396: continue;
397: switch (c->type) {
398: case SSH_CHANNEL_CLOSED:
399: case SSH_CHANNEL_DYNAMIC:
400: case SSH_CHANNEL_X11_LISTENER:
401: case SSH_CHANNEL_PORT_LISTENER:
402: case SSH_CHANNEL_RPORT_LISTENER:
403: case SSH_CHANNEL_OPENING:
404: case SSH_CHANNEL_CONNECTING:
405: case SSH_CHANNEL_ZOMBIE:
406: continue;
407: case SSH_CHANNEL_LARVAL:
408: case SSH_CHANNEL_AUTH_SOCKET:
409: case SSH_CHANNEL_OPEN:
410: case SSH_CHANNEL_X11_OPEN:
411: return i;
412: case SSH_CHANNEL_INPUT_DRAINING:
413: case SSH_CHANNEL_OUTPUT_DRAINING:
414: if (!compat13)
415: fatal("cannot happen: OUT_DRAIN");
416: return i;
417: default:
418: fatal("channel_find_open: bad channel type %d", c->type);
419: /* NOTREACHED */
420: }
421: }
422: return -1;
423: }
424:
425:
426: /*
427: * Returns a message describing the currently open forwarded connections,
428: * suitable for sending to the client. The message contains crlf pairs for
429: * newlines.
430: */
431:
432: char *
433: channel_open_message()
434: {
435: Buffer buffer;
436: Channel *c;
437: char buf[1024], *cp;
438: int i;
439:
440: buffer_init(&buffer);
441: snprintf(buf, sizeof buf, "The following connections are open:\r\n");
442: buffer_append(&buffer, buf, strlen(buf));
443: for (i = 0; i < channels_alloc; i++) {
444: c = channels[i];
445: if (c == NULL)
446: continue;
447: switch (c->type) {
448: case SSH_CHANNEL_X11_LISTENER:
449: case SSH_CHANNEL_PORT_LISTENER:
450: case SSH_CHANNEL_RPORT_LISTENER:
451: case SSH_CHANNEL_CLOSED:
452: case SSH_CHANNEL_AUTH_SOCKET:
453: case SSH_CHANNEL_ZOMBIE:
454: continue;
455: case SSH_CHANNEL_LARVAL:
456: case SSH_CHANNEL_OPENING:
457: case SSH_CHANNEL_CONNECTING:
458: case SSH_CHANNEL_DYNAMIC:
459: case SSH_CHANNEL_OPEN:
460: case SSH_CHANNEL_X11_OPEN:
461: case SSH_CHANNEL_INPUT_DRAINING:
462: case SSH_CHANNEL_OUTPUT_DRAINING:
463: snprintf(buf, sizeof buf, " #%d %.300s (t%d r%d i%d/%d o%d/%d fd %d/%d)\r\n",
464: c->self, c->remote_name,
465: c->type, c->remote_id,
466: c->istate, buffer_len(&c->input),
467: c->ostate, buffer_len(&c->output),
468: c->rfd, c->wfd);
469: buffer_append(&buffer, buf, strlen(buf));
470: continue;
471: default:
472: fatal("channel_open_message: bad channel type %d", c->type);
473: /* NOTREACHED */
474: }
475: }
476: buffer_append(&buffer, "\0", 1);
477: cp = xstrdup(buffer_ptr(&buffer));
478: buffer_free(&buffer);
479: return cp;
480: }
481:
482: void
1.2 ! markus 483: channel_send_open(int id)
1.1 markus 484: {
485: Channel *c = channel_lookup(id);
486: if (c == NULL) {
1.2 ! markus 487: log("channel_send_open: %d: bad id", id);
1.1 markus 488: return;
489: }
490: debug("send channel open %d", id);
491: packet_start(SSH2_MSG_CHANNEL_OPEN);
492: packet_put_cstring(c->ctype);
493: packet_put_int(c->self);
494: packet_put_int(c->local_window);
495: packet_put_int(c->local_maxpacket);
496: packet_send();
497: }
1.2 ! markus 498:
1.1 markus 499: void
500: channel_request(int id, char *service, int wantconfirm)
501: {
502: channel_request_start(id, service, wantconfirm);
503: packet_send();
504: debug("channel request %d: %s", id, service) ;
505: }
506: void
507: channel_request_start(int id, char *service, int wantconfirm)
508: {
509: Channel *c = channel_lookup(id);
510: if (c == NULL) {
511: log("channel_request: %d: bad id", id);
512: return;
513: }
514: packet_start(SSH2_MSG_CHANNEL_REQUEST);
515: packet_put_int(c->remote_id);
516: packet_put_cstring(service);
517: packet_put_char(wantconfirm);
518: }
519: void
520: channel_register_callback(int id, int mtype, channel_callback_fn *fn, void *arg)
521: {
522: Channel *c = channel_lookup(id);
523: if (c == NULL) {
524: log("channel_register_callback: %d: bad id", id);
525: return;
526: }
527: c->cb_event = mtype;
528: c->cb_fn = fn;
529: c->cb_arg = arg;
530: }
531: void
532: channel_register_cleanup(int id, channel_callback_fn *fn)
533: {
534: Channel *c = channel_lookup(id);
535: if (c == NULL) {
536: log("channel_register_cleanup: %d: bad id", id);
537: return;
538: }
539: c->dettach_user = fn;
540: }
541: void
542: channel_cancel_cleanup(int id)
543: {
544: Channel *c = channel_lookup(id);
545: if (c == NULL) {
546: log("channel_cancel_cleanup: %d: bad id", id);
547: return;
548: }
549: c->dettach_user = NULL;
550: }
551: void
552: channel_register_filter(int id, channel_filter_fn *fn)
553: {
554: Channel *c = channel_lookup(id);
555: if (c == NULL) {
556: log("channel_register_filter: %d: bad id", id);
557: return;
558: }
559: c->input_filter = fn;
560: }
561:
562: void
563: channel_set_fds(int id, int rfd, int wfd, int efd,
564: int extusage, int nonblock)
565: {
566: Channel *c = channel_lookup(id);
567: if (c == NULL || c->type != SSH_CHANNEL_LARVAL)
568: fatal("channel_activate for non-larval channel %d.", id);
569: channel_register_fds(c, rfd, wfd, efd, extusage, nonblock);
570: c->type = SSH_CHANNEL_OPEN;
571: /* XXX window size? */
572: c->local_window = c->local_window_max = c->local_maxpacket * 2;
573: packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST);
574: packet_put_int(c->remote_id);
575: packet_put_int(c->local_window);
576: packet_send();
577: }