X-Git-Url: http://andersk.mit.edu/gitweb/openssh.git/blobdiff_plain/8e7895b828bf8a34134fa323ee3c2878e035cb51..dd2495cba27edd8a16dca65037ccceb7128d3509:/channels.c diff --git a/channels.c b/channels.c index 518a071b..7bf127d9 100644 --- a/channels.c +++ b/channels.c @@ -12,9 +12,8 @@ * incompatible with the protocol description in the RFC file, it must be * called by a name other than "ssh" or "Secure Shell". * - * * SSH2 support added by Markus Friedl. - * Copyright (c) 1999,2000 Markus Friedl. All rights reserved. + * Copyright (c) 1999, 2000, 2001 Markus Friedl. All rights reserved. * Copyright (c) 1999 Dug Song. All rights reserved. * Copyright (c) 1999 Theo de Raadt. All rights reserved. * @@ -40,7 +39,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: channels.c,v 1.121 2001/05/31 10:30:14 markus Exp $"); +RCSID("$OpenBSD: channels.c,v 1.132 2001/07/17 21:04:56 markus Exp $"); #include "ssh.h" #include "ssh1.h" @@ -133,12 +132,11 @@ static u_int x11_fake_data_len; static char *auth_sock_name = NULL; static char *auth_sock_dir = NULL; - /* AF_UNSPEC or AF_INET or AF_INET6 */ extern int IPv4or6; /* helper */ -void port_open_helper(Channel *c, char *rtype); +static void port_open_helper(Channel *c, char *rtype); /* -- channel core */ @@ -164,7 +162,7 @@ channel_lookup(int id) * when the channel consumer/producer is ready, e.g. shell exec'd */ -void +static void channel_register_fds(Channel *c, int rfd, int wfd, int efd, int extusage, int nonblock) { @@ -223,11 +221,7 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd, channels = xmalloc(channels_alloc * sizeof(Channel *)); for (i = 0; i < channels_alloc; i++) channels[i] = NULL; - /* - * Kludge: arrange a call to channel_stop_listening if we - * terminate with fatal(). - */ - fatal_add_cleanup((void (*) (void *)) channel_stop_listening, NULL); + fatal_add_cleanup((void (*) (void *)) channel_free_all, NULL); } /* Try to find a free slot where to put the new channel. */ for (found = -1, i = 0; i < channels_alloc; i++) @@ -266,36 +260,55 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd, c->cb_fn = NULL; c->cb_arg = NULL; c->cb_event = 0; - c->dettach_user = NULL; + c->detach_user = NULL; c->input_filter = NULL; debug("channel %d: new [%s]", found, remote_name); return c; } +static int +channel_find_maxfd(void) +{ + int i, max = 0; + Channel *c; + + for (i = 0; i < channels_alloc; i++) { + c = channels[i]; + if (c != NULL) { + max = MAX(max, c->rfd); + max = MAX(max, c->wfd); + max = MAX(max, c->efd); + } + } + return max; +} + +int +channel_close_fd(int *fdp) +{ + int ret = 0, fd = *fdp; + + if (fd != -1) { + ret = close(fd); + *fdp = -1; + if (fd == channel_max_fd) + channel_max_fd = channel_find_maxfd(); + } + return ret; +} + /* Close all channel fd/socket. */ -void +static void channel_close_fds(Channel *c) { debug3("channel_close_fds: channel %d: r %d w %d e %d", c->self, c->rfd, c->wfd, c->efd); - if (c->sock != -1) { - close(c->sock); - c->sock = -1; - } - if (c->rfd != -1) { - close(c->rfd); - c->rfd = -1; - } - if (c->wfd != -1) { - close(c->wfd); - c->wfd = -1; - } - if (c->efd != -1) { - close(c->efd); - c->efd = -1; - } + channel_close_fd(&c->sock); + channel_close_fd(&c->rfd); + channel_close_fd(&c->wfd); + channel_close_fd(&c->efd); } /* Free the channel and close its fd/socket. */ @@ -316,9 +329,9 @@ channel_free(Channel *c) debug3("channel_free: status: %s", s); xfree(s); - if (c->dettach_user != NULL) { - debug("channel_free: channel %d: dettaching channel user", c->self); - c->dettach_user(c->self, NULL); + if (c->detach_user != NULL) { + debug("channel_free: channel %d: detaching channel user", c->self); + c->detach_user(c->self, NULL); } if (c->sock != -1) shutdown(c->sock, SHUT_RDWR); @@ -334,36 +347,28 @@ channel_free(Channel *c) xfree(c); } +void +channel_free_all(void) +{ + int i; -/* - * Stops listening for channels, and removes any unix domain sockets that we - * might have. - */ + for (i = 0; i < channels_alloc; i++) + if (channels[i] != NULL) + channel_free(channels[i]); +} void -channel_stop_listening() +channel_detach_all(void) { int i; Channel *c; for (i = 0; i < channels_alloc; i++) { c = channels[i]; - if (c != NULL) { - switch (c->type) { - case SSH_CHANNEL_AUTH_SOCKET: - close(c->sock); - unlink(c->path); - channel_free(c); - break; - case SSH_CHANNEL_PORT_LISTENER: - case SSH_CHANNEL_RPORT_LISTENER: - case SSH_CHANNEL_X11_LISTENER: - close(c->sock); - channel_free(c); - break; - default: - break; - } + if (c != NULL && c->detach_user != NULL) { + debug("channel_detach_all: channel %d", c->self); + c->detach_user(c->self, NULL); + c->detach_user = NULL; } } } @@ -383,6 +388,32 @@ channel_close_all() channel_close_fds(channels[i]); } +/* + * Stop listening to channels. + */ + +void +channel_stop_listening(void) +{ + int i; + Channel *c; + + for (i = 0; i < channels_alloc; i++) { + c = channels[i]; + if (c != NULL) { + switch (c->type) { + case SSH_CHANNEL_AUTH_SOCKET: + case SSH_CHANNEL_PORT_LISTENER: + case SSH_CHANNEL_RPORT_LISTENER: + case SSH_CHANNEL_X11_LISTENER: + channel_close_fd(&c->sock); + channel_free(c); + break; + } + } + } +} + /* * Returns true if no channel has too much buffered data, and false if one or * more channel is overfull. @@ -609,7 +640,7 @@ channel_register_cleanup(int id, channel_callback_fn *fn) log("channel_register_cleanup: %d: bad id", id); return; } - c->dettach_user = fn; + c->detach_user = fn; } void channel_cancel_cleanup(int id) @@ -619,7 +650,7 @@ channel_cancel_cleanup(int id) log("channel_cancel_cleanup: %d: bad id", id); return; } - c->dettach_user = NULL; + c->detach_user = NULL; } void channel_register_filter(int id, channel_filter_fn *fn) @@ -661,20 +692,20 @@ typedef void chan_fn(Channel *c, fd_set * readset, fd_set * writeset); chan_fn *channel_pre[SSH_CHANNEL_MAX_TYPE]; chan_fn *channel_post[SSH_CHANNEL_MAX_TYPE]; -void +static void channel_pre_listener(Channel *c, fd_set * readset, fd_set * writeset) { FD_SET(c->sock, readset); } -void +static void channel_pre_connecting(Channel *c, fd_set * readset, fd_set * writeset) { debug3("channel %d: waiting for connection", c->self); FD_SET(c->sock, writeset); } -void +static void channel_pre_open_13(Channel *c, fd_set * readset, fd_set * writeset) { if (buffer_len(&c->input) < packet_get_maxsize()) @@ -683,7 +714,7 @@ channel_pre_open_13(Channel *c, fd_set * readset, fd_set * writeset) FD_SET(c->sock, writeset); } -void +static void channel_pre_open_15(Channel *c, fd_set * readset, fd_set * writeset) { /* test whether sockets are 'alive' for read/write */ @@ -700,7 +731,7 @@ channel_pre_open_15(Channel *c, fd_set * readset, fd_set * writeset) } } -void +static void channel_pre_open_20(Channel *c, fd_set * readset, fd_set * writeset) { if (c->istate == CHAN_INPUT_OPEN && @@ -726,7 +757,7 @@ channel_pre_open_20(Channel *c, fd_set * readset, fd_set * writeset) } } -void +static void channel_pre_input_draining(Channel *c, fd_set * readset, fd_set * writeset) { if (buffer_len(&c->input) == 0) { @@ -738,7 +769,7 @@ channel_pre_input_draining(Channel *c, fd_set * readset, fd_set * writeset) } } -void +static void channel_pre_output_draining(Channel *c, fd_set * readset, fd_set * writeset) { if (buffer_len(&c->output) == 0) @@ -756,7 +787,7 @@ channel_pre_output_draining(Channel *c, fd_set * readset, fd_set * writeset) * XXX All this happens at the client side. * Returns: 0 = need more data, -1 = wrong cookie, 1 = ok */ -int +static int x11_open_helper(Buffer *b) { u_char *ucp; @@ -814,7 +845,7 @@ x11_open_helper(Buffer *b) return 1; } -void +static void channel_pre_x11_open_13(Channel *c, fd_set * readset, fd_set * writeset) { int ret = x11_open_helper(&c->output); @@ -830,7 +861,7 @@ channel_pre_x11_open_13(Channel *c, fd_set * readset, fd_set * writeset) log("X11 connection rejected because of wrong authentication."); buffer_clear(&c->input); buffer_clear(&c->output); - close(c->sock); + channel_close_fd(&c->sock); c->sock = -1; c->type = SSH_CHANNEL_CLOSED; packet_start(SSH_MSG_CHANNEL_CLOSE); @@ -839,7 +870,7 @@ channel_pre_x11_open_13(Channel *c, fd_set * readset, fd_set * writeset) } } -void +static void channel_pre_x11_open(Channel *c, fd_set * readset, fd_set * writeset) { int ret = x11_open_helper(&c->output); @@ -858,7 +889,7 @@ channel_pre_x11_open(Channel *c, fd_set * readset, fd_set * writeset) } /* try to decode a socks4 header */ -int +static int channel_decode_socks4(Channel *c, fd_set * readset, fd_set * writeset) { u_char *p, *host; @@ -928,7 +959,7 @@ channel_decode_socks4(Channel *c, fd_set * readset, fd_set * writeset) } /* dynamic port forwarding */ -void +static void channel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset) { u_char *p; @@ -968,7 +999,7 @@ channel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset) } /* This is our fake X11 server socket. */ -void +static void channel_post_x11_listener(Channel *c, fd_set * readset, fd_set * writeset) { Channel *nc; @@ -1019,14 +1050,14 @@ channel_post_x11_listener(Channel *c, fd_set * readset, fd_set * writeset) packet_put_int(nc->self); if (packet_get_protocol_flags() & SSH_PROTOFLAG_HOST_IN_FWD_OPEN) - packet_put_string(buf, strlen(buf)); + packet_put_cstring(buf); packet_send(); } xfree(remote_ipaddr); } } -void +static void port_open_helper(Channel *c, char *rtype) { int direct; @@ -1080,7 +1111,7 @@ port_open_helper(Channel *c, char *rtype) /* * This socket is listening for connections to a forwarded TCP/IP port. */ -void +static void channel_post_port_listener(Channel *c, fd_set * readset, fd_set * writeset) { Channel *nc; @@ -1128,7 +1159,7 @@ channel_post_port_listener(Channel *c, fd_set * readset, fd_set * writeset) * This is the authentication agent socket listening for connections from * clients. */ -void +static void channel_post_auth_listener(Channel *c, fd_set * readset, fd_set * writeset) { Channel *nc; @@ -1168,11 +1199,11 @@ channel_post_auth_listener(Channel *c, fd_set * readset, fd_set * writeset) } } -void +static void channel_post_connecting(Channel *c, fd_set * readset, fd_set * writeset) { int err = 0; - int sz = sizeof(err); + socklen_t sz = sizeof(err); if (FD_ISSET(c->sock, writeset)) { if (getsockopt(c->sock, SOL_SOCKET, SO_ERROR, (char *)&err, @@ -1215,7 +1246,7 @@ channel_post_connecting(Channel *c, fd_set * readset, fd_set * writeset) } } -int +static int channel_handle_rfd(Channel *c, fd_set * readset, fd_set * writeset) { char buf[16*1024]; @@ -1253,7 +1284,7 @@ channel_handle_rfd(Channel *c, fd_set * readset, fd_set * writeset) } return 1; } -int +static int channel_handle_wfd(Channel *c, fd_set * readset, fd_set * writeset) { struct termios tio; @@ -1301,7 +1332,7 @@ channel_handle_wfd(Channel *c, fd_set * readset, fd_set * writeset) } return 1; } -int +static int channel_handle_efd(Channel *c, fd_set * readset, fd_set * writeset) { char buf[16*1024]; @@ -1321,8 +1352,7 @@ channel_handle_efd(Channel *c, fd_set * readset, fd_set * writeset) if (len <= 0) { debug2("channel %d: closing write-efd %d", c->self, c->efd); - close(c->efd); - c->efd = -1; + channel_close_fd(&c->efd); } else { buffer_consume(&c->extended, len); c->local_consumed += len; @@ -1337,8 +1367,7 @@ channel_handle_efd(Channel *c, fd_set * readset, fd_set * writeset) if (len <= 0) { debug2("channel %d: closing read-efd %d", c->self, c->efd); - close(c->efd); - c->efd = -1; + channel_close_fd(&c->efd); } else { buffer_append(&c->extended, buf, len); } @@ -1346,7 +1375,7 @@ channel_handle_efd(Channel *c, fd_set * readset, fd_set * writeset) } return 1; } -int +static int channel_check_window(Channel *c) { if (c->type == SSH_CHANNEL_OPEN && @@ -1366,14 +1395,14 @@ channel_check_window(Channel *c) return 1; } -void +static void channel_post_open_1(Channel *c, fd_set * readset, fd_set * writeset) { channel_handle_rfd(c, readset, writeset); channel_handle_wfd(c, readset, writeset); } -void +static void channel_post_open_2(Channel *c, fd_set * readset, fd_set * writeset) { channel_handle_rfd(c, readset, writeset); @@ -1383,7 +1412,7 @@ channel_post_open_2(Channel *c, fd_set * readset, fd_set * writeset) channel_check_window(c); } -void +static void channel_post_output_drain_13(Channel *c, fd_set * readset, fd_set * writeset) { int len; @@ -1398,7 +1427,7 @@ channel_post_output_drain_13(Channel *c, fd_set * readset, fd_set * writeset) } } -void +static void channel_handler_init_20(void) { channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open_20; @@ -1419,7 +1448,7 @@ channel_handler_init_20(void) channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open_2; } -void +static void channel_handler_init_13(void) { channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open_13; @@ -1441,7 +1470,7 @@ channel_handler_init_13(void) channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open_1; } -void +static void channel_handler_init_15(void) { channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open_15; @@ -1460,7 +1489,7 @@ channel_handler_init_15(void) channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open_1; } -void +static void channel_handler_init(void) { int i; @@ -1476,7 +1505,7 @@ channel_handler_init(void) channel_handler_init_15(); } -void +static void channel_handler(chan_fn *ftab[], fd_set * readset, fd_set * writeset) { static int did_init = 0; @@ -1520,7 +1549,7 @@ channel_handler(chan_fn *ftab[], fd_set * readset, fd_set * writeset) */ void channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp, - int rekeying) + int *nallocp, int rekeying) { int n; u_int sz; @@ -1528,15 +1557,13 @@ channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp, n = MAX(*maxfdp, channel_max_fd); sz = howmany(n+1, NFDBITS) * sizeof(fd_mask); - if (*readsetp == NULL || n > *maxfdp) { - if (*readsetp) - xfree(*readsetp); - if (*writesetp) - xfree(*writesetp); - *readsetp = xmalloc(sz); - *writesetp = xmalloc(sz); - *maxfdp = n; + /* perhaps check sz < nalloc/2 and shrink? */ + if (*readsetp == NULL || sz > *nallocp) { + *readsetp = xrealloc(*readsetp, sz); + *writesetp = xrealloc(*writesetp, sz); + *nallocp = sz; } + *maxfdp = n; memset(*readsetp, 0, sz); memset(*writesetp, 0, sz); @@ -1856,7 +1883,7 @@ channel_input_open_confirmation(int type, int plen, void *ctxt) } } -char * +static char * reason2txt(int reason) { switch(reason) { @@ -2248,7 +2275,7 @@ channel_clear_permitted_opens(void) /* return socket to remote host, port */ -int +static int connect_to(const char *host, u_short port) { struct addrinfo hints, *ai, *aitop; @@ -2300,7 +2327,7 @@ connect_to(const char *host, u_short port) } int -channel_connect_by_listen_adress(u_short listen_port) +channel_connect_by_listen_address(u_short listen_port) { int i; @@ -2483,8 +2510,7 @@ x11_create_display_inet(int screen_number, int x11_display_offset) #define X_UNIX_PATH "/tmp/.X11-unix/X" #endif -static -int +static int connect_local_xsocket(u_int dnr) { static const char *const x_sockets[] = { @@ -2777,10 +2803,17 @@ auth_get_socket_name() /* removes the agent forwarding socket */ void -cleanup_socket(void) +auth_sock_cleanup_proc(void *_pw) { - unlink(auth_sock_name); - rmdir(auth_sock_dir); + struct passwd *pw = _pw; + + if (auth_sock_name) { + temporarily_use_uid(pw); + unlink(auth_sock_name); + rmdir(auth_sock_dir); + auth_sock_name = NULL; + restore_uid(); + } } /* @@ -2822,11 +2855,9 @@ auth_input_request_forwarding(struct passwd * pw) snprintf(auth_sock_name, MAXPATHLEN, "%s/agent.%d", auth_sock_dir, (int) getpid()); - if (atexit(cleanup_socket) < 0) { - int saved = errno; - cleanup_socket(); - packet_disconnect("socket: %.100s", strerror(saved)); - } + /* delete agent socket on fatal() */ + fatal_add_cleanup(auth_sock_cleanup_proc, pw); + /* Create the socket. */ sock = socket(AF_UNIX, SOCK_STREAM, 0); if (sock < 0) @@ -2855,6 +2886,8 @@ auth_input_request_forwarding(struct passwd * pw) 0, xstrdup("auth socket"), 1); if (nc == NULL) { error("auth_input_request_forwarding: channel_new failed"); + auth_sock_cleanup_proc(pw); + fatal_remove_cleanup(auth_sock_cleanup_proc, pw); close(sock); return 0; }