version 1.402, 2020/09/20 05:47:25 |
version 1.403, 2020/10/18 11:32:01 |
|
|
struct ssh_channels *sc; |
struct ssh_channels *sc; |
|
|
if ((sc = calloc(1, sizeof(*sc))) == NULL) |
if ((sc = calloc(1, sizeof(*sc))) == NULL) |
fatal("%s: allocation failed", __func__); |
fatal_f("allocation failed"); |
sc->channels_alloc = 10; |
sc->channels_alloc = 10; |
sc->channels = xcalloc(sc->channels_alloc, sizeof(*sc->channels)); |
sc->channels = xcalloc(sc->channels_alloc, sizeof(*sc->channels)); |
sc->IPv4or6 = AF_UNSPEC; |
sc->IPv4or6 = AF_UNSPEC; |
|
|
Channel *c; |
Channel *c; |
|
|
if (id < 0 || (u_int)id >= ssh->chanctxt->channels_alloc) { |
if (id < 0 || (u_int)id >= ssh->chanctxt->channels_alloc) { |
logit("%s: %d: bad id", __func__, id); |
logit_f("%d: bad id", id); |
return NULL; |
return NULL; |
} |
} |
c = ssh->chanctxt->channels[id]; |
c = ssh->chanctxt->channels[id]; |
if (c == NULL) { |
if (c == NULL) { |
logit("%s: %d: bad id: channel free", __func__, id); |
logit_f("%d: bad id: channel free", id); |
return NULL; |
return NULL; |
} |
} |
return c; |
return c; |
|
|
*/ |
*/ |
found = sc->channels_alloc; |
found = sc->channels_alloc; |
if (sc->channels_alloc > CHANNELS_MAX_CHANNELS) |
if (sc->channels_alloc > CHANNELS_MAX_CHANNELS) |
fatal("%s: internal error: channels_alloc %d too big", |
fatal_f("internal error: channels_alloc %d too big", |
__func__, sc->channels_alloc); |
sc->channels_alloc); |
sc->channels = xrecallocarray(sc->channels, sc->channels_alloc, |
sc->channels = xrecallocarray(sc->channels, sc->channels_alloc, |
sc->channels_alloc + 10, sizeof(*sc->channels)); |
sc->channels_alloc + 10, sizeof(*sc->channels)); |
sc->channels_alloc += 10; |
sc->channels_alloc += 10; |
|
|
if ((c->input = sshbuf_new()) == NULL || |
if ((c->input = sshbuf_new()) == NULL || |
(c->output = sshbuf_new()) == NULL || |
(c->output = sshbuf_new()) == NULL || |
(c->extended = sshbuf_new()) == NULL) |
(c->extended = sshbuf_new()) == NULL) |
fatal("%s: sshbuf_new failed", __func__); |
fatal_f("sshbuf_new failed"); |
if ((r = sshbuf_set_max_size(c->input, CHAN_INPUT_MAX)) != 0) |
if ((r = sshbuf_set_max_size(c->input, CHAN_INPUT_MAX)) != 0) |
fatal("%s: sshbuf_set_max_size: %s", __func__, ssh_err(r)); |
fatal_fr(r, "sshbuf_set_max_size"); |
c->ostate = CHAN_OUTPUT_OPEN; |
c->ostate = CHAN_OUTPUT_OPEN; |
c->istate = CHAN_INPUT_OPEN; |
c->istate = CHAN_INPUT_OPEN; |
channel_register_fds(ssh, c, rfd, wfd, efd, extusage, nonblock, 0); |
channel_register_fds(ssh, c, rfd, wfd, efd, extusage, nonblock, 0); |
|
|
return &sc->remote_perms; |
return &sc->remote_perms; |
break; |
break; |
default: |
default: |
fatal("%s: invalid forwarding direction %d", __func__, where); |
fatal_f("invalid forwarding direction %d", where); |
} |
} |
} |
} |
|
|
|
|
*npermpp = &pset->num_permitted_admin; |
*npermpp = &pset->num_permitted_admin; |
break; |
break; |
default: |
default: |
fatal("%s: invalid forwarding client %d", __func__, who); |
fatal_f("invalid forwarding client %d", who); |
} |
} |
} |
} |
|
|
|
|
permission_set_get_array(ssh, who, where, &permp, &npermp); |
permission_set_get_array(ssh, who, where, &permp, &npermp); |
|
|
if (*npermp >= INT_MAX) |
if (*npermp >= INT_MAX) |
fatal("%s: %s overflow", __func__, fwd_ident(who, where)); |
fatal_f("%s overflow", fwd_ident(who, where)); |
|
|
*permp = xrecallocarray(*permp, *npermp, *npermp + 1, sizeof(**permp)); |
*permp = xrecallocarray(*permp, *npermp, *npermp + 1, sizeof(**permp)); |
n = (*npermp)++; |
n = (*npermp)++; |
|
|
channel_rfwd_bind_host(perm->listen_host))) != 0 || |
channel_rfwd_bind_host(perm->listen_host))) != 0 || |
(r = sshpkt_put_u32(ssh, perm->listen_port)) != 0 || |
(r = sshpkt_put_u32(ssh, perm->listen_port)) != 0 || |
(r = sshpkt_send(ssh)) != 0) { |
(r = sshpkt_send(ssh)) != 0) { |
fatal("%s: channel %i: %s", __func__, |
fatal_fr(r, "channel %i", c->self); |
c->self, ssh_err(r)); |
|
} |
} |
fwd_perm_clear(perm); /* unregister */ |
fwd_perm_clear(perm); /* unregister */ |
} |
} |
|
|
case SSH_CHANNEL_MUX_PROXY: |
case SSH_CHANNEL_MUX_PROXY: |
return 1; |
return 1; |
default: |
default: |
fatal("%s: bad channel type %d", __func__, c->type); |
fatal_f("bad channel type %d", c->type); |
/* NOTREACHED */ |
/* NOTREACHED */ |
} |
} |
} |
} |
|
|
case SSH_CHANNEL_X11_OPEN: |
case SSH_CHANNEL_X11_OPEN: |
return i; |
return i; |
default: |
default: |
fatal("%s: bad channel type %d", __func__, c->type); |
fatal_f("bad channel type %d", c->type); |
/* NOTREACHED */ |
/* NOTREACHED */ |
} |
} |
} |
} |
|
|
char *cp, *ret; |
char *cp, *ret; |
|
|
if ((buf = sshbuf_new()) == NULL) |
if ((buf = sshbuf_new()) == NULL) |
fatal("%s: sshbuf_new", __func__); |
fatal_f("sshbuf_new"); |
if ((r = sshbuf_putf(buf, |
if ((r = sshbuf_putf(buf, |
"The following connections are open:\r\n")) != 0) |
"The following connections are open:\r\n")) != 0) |
fatal("%s: sshbuf_putf: %s", __func__, ssh_err(r)); |
fatal_fr(r, "sshbuf_putf"); |
for (i = 0; i < ssh->chanctxt->channels_alloc; i++) { |
for (i = 0; i < ssh->chanctxt->channels_alloc; i++) { |
c = ssh->chanctxt->channels[i]; |
c = ssh->chanctxt->channels[i]; |
if (c == NULL) |
if (c == NULL) |
|
|
if ((r = sshbuf_putf(buf, " #%d %.300s (%s)\r\n", |
if ((r = sshbuf_putf(buf, " #%d %.300s (%s)\r\n", |
c->self, c->remote_name, cp)) != 0) { |
c->self, c->remote_name, cp)) != 0) { |
free(cp); |
free(cp); |
fatal("%s: sshbuf_putf: %s", |
fatal_fr(r, "sshbuf_putf"); |
__func__, ssh_err(r)); |
|
} |
} |
free(cp); |
free(cp); |
continue; |
continue; |
default: |
default: |
fatal("%s: bad channel type %d", __func__, c->type); |
fatal_f("bad channel type %d", c->type); |
/* NOTREACHED */ |
/* NOTREACHED */ |
} |
} |
} |
} |
if ((ret = sshbuf_dup_string(buf)) == NULL) |
if ((ret = sshbuf_dup_string(buf)) == NULL) |
fatal("%s: sshbuf_dup_string", __func__); |
fatal_f("sshbuf_dup_string"); |
sshbuf_free(buf); |
sshbuf_free(buf); |
return ret; |
return ret; |
} |
} |
|
|
(r = sshpkt_put_u32(ssh, c->self)) != 0 || |
(r = sshpkt_put_u32(ssh, c->self)) != 0 || |
(r = sshpkt_put_u32(ssh, c->local_window)) != 0 || |
(r = sshpkt_put_u32(ssh, c->local_window)) != 0 || |
(r = sshpkt_put_u32(ssh, c->local_maxpacket)) != 0) { |
(r = sshpkt_put_u32(ssh, c->local_maxpacket)) != 0) { |
fatal("%s: channel %i: open: %s", where, c->self, ssh_err(r)); |
fatal_r(r, "%s: channel %i: open", where, c->self); |
} |
} |
} |
} |
|
|
|
|
debug2("channel %d: send open", id); |
debug2("channel %d: send open", id); |
open_preamble(ssh, __func__, c, c->ctype); |
open_preamble(ssh, __func__, c, c->ctype); |
if ((r = sshpkt_send(ssh)) != 0) |
if ((r = sshpkt_send(ssh)) != 0) |
fatal("%s: channel %i: %s", __func__, c->self, ssh_err(r)); |
fatal_fr(r, "channel %i", c->self); |
} |
} |
|
|
void |
void |
|
|
int r; |
int r; |
|
|
if (c == NULL) { |
if (c == NULL) { |
logit("%s: %d: unknown channel id", __func__, id); |
logit_f("%d: unknown channel id", id); |
return; |
return; |
} |
} |
if (!c->have_remote_id) |
if (!c->have_remote_id) |
fatal(":%s: channel %d: no remote id", __func__, c->self); |
fatal_f("channel %d: no remote id", c->self); |
|
|
debug2("channel %d: request %s confirm %d", id, service, wantconfirm); |
debug2("channel %d: request %s confirm %d", id, service, wantconfirm); |
if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_REQUEST)) != 0 || |
if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_REQUEST)) != 0 || |
(r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || |
(r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || |
(r = sshpkt_put_cstring(ssh, service)) != 0 || |
(r = sshpkt_put_cstring(ssh, service)) != 0 || |
(r = sshpkt_put_u8(ssh, wantconfirm)) != 0) { |
(r = sshpkt_put_u8(ssh, wantconfirm)) != 0) { |
fatal("%s: channel %i: %s", __func__, c->self, ssh_err(r)); |
fatal_fr(r, "channel %i", c->self); |
} |
} |
} |
} |
|
|
|
|
Channel *c; |
Channel *c; |
|
|
if ((c = channel_lookup(ssh, id)) == NULL) |
if ((c = channel_lookup(ssh, id)) == NULL) |
fatal("%s: %d: bad id", __func__, id); |
fatal_f("%d: bad id", id); |
|
|
cc = xcalloc(1, sizeof(*cc)); |
cc = xcalloc(1, sizeof(*cc)); |
cc->cb = cb; |
cc->cb = cb; |
|
|
Channel *c = channel_lookup(ssh, id); |
Channel *c = channel_lookup(ssh, id); |
|
|
if (c == NULL) { |
if (c == NULL) { |
logit("%s: %d: bad id", __func__, id); |
logit_f("%d: bad id", id); |
return; |
return; |
} |
} |
c->open_confirm = fn; |
c->open_confirm = fn; |
|
|
Channel *c = channel_by_id(ssh, id); |
Channel *c = channel_by_id(ssh, id); |
|
|
if (c == NULL) { |
if (c == NULL) { |
logit("%s: %d: bad id", __func__, id); |
logit_f("%d: bad id", id); |
return; |
return; |
} |
} |
c->detach_user = fn; |
c->detach_user = fn; |
|
|
Channel *c = channel_by_id(ssh, id); |
Channel *c = channel_by_id(ssh, id); |
|
|
if (c == NULL) { |
if (c == NULL) { |
logit("%s: %d: bad id", __func__, id); |
logit_f("%d: bad id", id); |
return; |
return; |
} |
} |
c->detach_user = NULL; |
c->detach_user = NULL; |
|
|
Channel *c = channel_lookup(ssh, id); |
Channel *c = channel_lookup(ssh, id); |
|
|
if (c == NULL) { |
if (c == NULL) { |
logit("%s: %d: bad id", __func__, id); |
logit_f("%d: bad id", id); |
return; |
return; |
} |
} |
c->input_filter = ifn; |
c->input_filter = ifn; |
|
|
if (c == NULL || c->type != SSH_CHANNEL_LARVAL) |
if (c == NULL || c->type != SSH_CHANNEL_LARVAL) |
fatal("channel_activate for non-larval channel %d.", id); |
fatal("channel_activate for non-larval channel %d.", id); |
if (!c->have_remote_id) |
if (!c->have_remote_id) |
fatal(":%s: channel %d: no remote id", __func__, c->self); |
fatal_f("channel %d: no remote id", c->self); |
|
|
channel_register_fds(ssh, c, rfd, wfd, efd, extusage, nonblock, is_tty); |
channel_register_fds(ssh, c, rfd, wfd, efd, extusage, nonblock, is_tty); |
c->type = SSH_CHANNEL_OPEN; |
c->type = SSH_CHANNEL_OPEN; |
|
|
(r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || |
(r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || |
(r = sshpkt_put_u32(ssh, c->local_window)) != 0 || |
(r = sshpkt_put_u32(ssh, c->local_window)) != 0 || |
(r = sshpkt_send(ssh)) != 0) |
(r = sshpkt_send(ssh)) != 0) |
fatal("%s: channel %i: %s", __func__, c->self, ssh_err(r)); |
fatal_fr(r, "channel %i", c->self); |
} |
} |
|
|
static void |
static void |
|
|
(r = sshbuf_get(input, &s4_req.command, 1)) != 0 || |
(r = sshbuf_get(input, &s4_req.command, 1)) != 0 || |
(r = sshbuf_get(input, &s4_req.dest_port, 2)) != 0 || |
(r = sshbuf_get(input, &s4_req.dest_port, 2)) != 0 || |
(r = sshbuf_get(input, &s4_req.dest_addr, 4)) != 0) { |
(r = sshbuf_get(input, &s4_req.dest_addr, 4)) != 0) { |
debug("channels %d: decode socks4: %s", c->self, ssh_err(r)); |
debug_r(r, "channels %d: decode socks4", c->self); |
return -1; |
return -1; |
} |
} |
have = sshbuf_len(input); |
have = sshbuf_len(input); |
p = sshbuf_ptr(input); |
p = sshbuf_ptr(input); |
if (memchr(p, '\0', have) == NULL) { |
if (memchr(p, '\0', have) == NULL) { |
error("channel %d: decode socks4: user not nul terminated", |
error("channel %d: decode socks4: unterminated user", c->self); |
c->self); |
|
return -1; |
return -1; |
} |
} |
len = strlen(p); |
len = strlen(p); |
debug2("channel %d: decode socks4: user %s/%d", c->self, p, len); |
debug2("channel %d: decode socks4: user %s/%d", c->self, p, len); |
len++; /* trailing '\0' */ |
len++; /* trailing '\0' */ |
strlcpy(username, p, sizeof(username)); |
strlcpy(username, p, sizeof(username)); |
if ((r = sshbuf_consume(input, len)) != 0) { |
if ((r = sshbuf_consume(input, len)) != 0) |
fatal("%s: channel %d: consume: %s", __func__, |
fatal_fr(r, "channel %d: consume", c->self); |
c->self, ssh_err(r)); |
|
} |
|
free(c->path); |
free(c->path); |
c->path = NULL; |
c->path = NULL; |
if (need == 1) { /* SOCKS4: one string */ |
if (need == 1) { /* SOCKS4: one string */ |
|
|
return -1; |
return -1; |
} |
} |
c->path = xstrdup(p); |
c->path = xstrdup(p); |
if ((r = sshbuf_consume(input, len)) != 0) { |
if ((r = sshbuf_consume(input, len)) != 0) |
fatal("%s: channel %d: consume: %s", __func__, |
fatal_fr(r, "channel %d: consume", c->self); |
c->self, ssh_err(r)); |
|
} |
|
} |
} |
c->host_port = ntohs(s4_req.dest_port); |
c->host_port = ntohs(s4_req.dest_port); |
|
|
|
|
s4_rsp.command = 90; /* cd: req granted */ |
s4_rsp.command = 90; /* cd: req granted */ |
s4_rsp.dest_port = 0; /* ignored */ |
s4_rsp.dest_port = 0; /* ignored */ |
s4_rsp.dest_addr.s_addr = INADDR_ANY; /* ignored */ |
s4_rsp.dest_addr.s_addr = INADDR_ANY; /* ignored */ |
if ((r = sshbuf_put(output, &s4_rsp, sizeof(s4_rsp))) != 0) { |
if ((r = sshbuf_put(output, &s4_rsp, sizeof(s4_rsp))) != 0) |
fatal("%s: channel %d: append reply: %s", __func__, |
fatal_fr(r, "channel %d: append reply", c->self); |
c->self, ssh_err(r)); |
|
} |
|
return 1; |
return 1; |
} |
} |
|
|
|
|
c->self); |
c->self); |
return -1; |
return -1; |
} |
} |
if ((r = sshbuf_consume(input, nmethods + 2)) != 0) { |
if ((r = sshbuf_consume(input, nmethods + 2)) != 0) |
fatal("%s: channel %d: consume: %s", __func__, |
fatal_fr(r, "channel %d: consume", c->self); |
c->self, ssh_err(r)); |
|
} |
|
/* version, method */ |
/* version, method */ |
if ((r = sshbuf_put_u8(output, 0x05)) != 0 || |
if ((r = sshbuf_put_u8(output, 0x05)) != 0 || |
(r = sshbuf_put_u8(output, SSH_SOCKS5_NOAUTH)) != 0) { |
(r = sshbuf_put_u8(output, SSH_SOCKS5_NOAUTH)) != 0) |
fatal("%s: channel %d: append reply: %s", __func__, |
fatal_fr(r, "channel %d: append reply", c->self); |
c->self, ssh_err(r)); |
|
} |
|
c->flags |= SSH_SOCKS5_AUTHDONE; |
c->flags |= SSH_SOCKS5_AUTHDONE; |
debug2("channel %d: socks5 auth done", c->self); |
debug2("channel %d: socks5 auth done", c->self); |
return 0; /* need more */ |
return 0; /* need more */ |
|
|
need++; |
need++; |
if (have < need) |
if (have < need) |
return 0; |
return 0; |
if ((r = sshbuf_consume(input, sizeof(s5_req))) != 0) { |
if ((r = sshbuf_consume(input, sizeof(s5_req))) != 0) |
fatal("%s: channel %d: consume: %s", __func__, |
fatal_fr(r, "channel %d: consume", c->self); |
c->self, ssh_err(r)); |
|
} |
|
if (s5_req.atyp == SSH_SOCKS5_DOMAIN) { |
if (s5_req.atyp == SSH_SOCKS5_DOMAIN) { |
/* host string length */ |
/* host string length */ |
if ((r = sshbuf_consume(input, 1)) != 0) { |
if ((r = sshbuf_consume(input, 1)) != 0) |
fatal("%s: channel %d: consume: %s", __func__, |
fatal_fr(r, "channel %d: consume", c->self); |
c->self, ssh_err(r)); |
|
} |
|
} |
} |
if ((r = sshbuf_get(input, &dest_addr, addrlen)) != 0 || |
if ((r = sshbuf_get(input, &dest_addr, addrlen)) != 0 || |
(r = sshbuf_get(input, &dest_port, 2)) != 0) { |
(r = sshbuf_get(input, &dest_port, 2)) != 0) { |
debug("channel %d: parse addr/port: %s", c->self, ssh_err(r)); |
debug_r(r, "channel %d: parse addr/port", c->self); |
return -1; |
return -1; |
} |
} |
dest_addr[addrlen] = '\0'; |
dest_addr[addrlen] = '\0'; |
|
|
if ((r = sshbuf_put(output, &s5_rsp, sizeof(s5_rsp))) != 0 || |
if ((r = sshbuf_put(output, &s5_rsp, sizeof(s5_rsp))) != 0 || |
(r = sshbuf_put_u32(output, ntohl(INADDR_ANY))) != 0 || |
(r = sshbuf_put_u32(output, ntohl(INADDR_ANY))) != 0 || |
(r = sshbuf_put(output, &dest_port, sizeof(dest_port))) != 0) |
(r = sshbuf_put(output, &dest_port, sizeof(dest_port))) != 0) |
fatal("%s: channel %d: append reply: %s", __func__, |
fatal_fr(r, "channel %d: append reply", c->self); |
c->self, ssh_err(r)); |
|
return 1; |
return 1; |
} |
} |
|
|
|
|
{ |
{ |
Channel *c; |
Channel *c; |
|
|
debug("%s %s:%d", __func__, host_to_connect, port_to_connect); |
debug_f("%s:%d", host_to_connect, port_to_connect); |
|
|
c = channel_new(ssh, "stdio-forward", SSH_CHANNEL_OPENING, in, out, |
c = channel_new(ssh, "stdio-forward", SSH_CHANNEL_OPENING, in, out, |
-1, CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, |
-1, CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, |
|
|
/* sshbuf_dump(c->output, stderr); */ |
/* sshbuf_dump(c->output, stderr); */ |
/* EOF received */ |
/* EOF received */ |
if (c->flags & CHAN_EOF_RCVD) { |
if (c->flags & CHAN_EOF_RCVD) { |
if ((r = sshbuf_consume(c->output, have)) != 0) { |
if ((r = sshbuf_consume(c->output, have)) != 0) |
fatal("%s: channel %d: consume: %s", |
fatal_fr(r, "channel %d: consume", c->self); |
__func__, c->self, ssh_err(r)); |
|
} |
|
rdynamic_close(ssh, c); |
rdynamic_close(ssh, c); |
return; |
return; |
} |
} |
|
|
(r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || |
(r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || |
(r = sshpkt_put_stringb(ssh, c->input)) != 0 || |
(r = sshpkt_put_stringb(ssh, c->input)) != 0 || |
(r = sshpkt_send(ssh)) != 0) { |
(r = sshpkt_send(ssh)) != 0) { |
fatal("%s: channel %i: rdynamic: %s", __func__, |
fatal_fr(r, "channel %i: rdynamic", c->self); |
c->self, ssh_err(r)); |
|
} |
} |
if ((r = sshbuf_consume(c->input, len)) != 0) { |
if ((r = sshbuf_consume(c->input, len)) != 0) |
fatal("%s: channel %d: consume: %s", |
fatal_fr(r, "channel %d: consume", c->self); |
__func__, c->self, ssh_err(r)); |
|
} |
|
c->remote_window -= len; |
c->remote_window -= len; |
} |
} |
} else if (rdynamic_connect_finish(ssh, c) < 0) { |
} else if (rdynamic_connect_finish(ssh, c) < 0) { |
|
|
open_preamble(ssh, __func__, nc, "x11"); |
open_preamble(ssh, __func__, nc, "x11"); |
if ((r = sshpkt_put_cstring(ssh, remote_ipaddr)) != 0 || |
if ((r = sshpkt_put_cstring(ssh, remote_ipaddr)) != 0 || |
(r = sshpkt_put_u32(ssh, remote_port)) != 0) { |
(r = sshpkt_put_u32(ssh, remote_port)) != 0) { |
fatal("%s: channel %i: reply %s", __func__, |
fatal_fr(r, "channel %i: reply", c->self); |
c->self, ssh_err(r)); |
|
} |
} |
if ((r = sshpkt_send(ssh)) != 0) |
if ((r = sshpkt_send(ssh)) != 0) |
fatal("%s: channel %i: send %s", __func__, c->self, ssh_err(r)); |
fatal_fr(r, "channel %i: send", c->self); |
free(remote_ipaddr); |
free(remote_ipaddr); |
} |
} |
|
|
|
|
if (strcmp(rtype, "direct-tcpip") == 0) { |
if (strcmp(rtype, "direct-tcpip") == 0) { |
/* target host, port */ |
/* target host, port */ |
if ((r = sshpkt_put_cstring(ssh, c->path)) != 0 || |
if ((r = sshpkt_put_cstring(ssh, c->path)) != 0 || |
(r = sshpkt_put_u32(ssh, c->host_port)) != 0) { |
(r = sshpkt_put_u32(ssh, c->host_port)) != 0) |
fatal("%s: channel %i: reply %s", __func__, |
fatal_fr(r, "channel %i: reply", c->self); |
c->self, ssh_err(r)); |
|
} |
|
} else if (strcmp(rtype, "direct-streamlocal@openssh.com") == 0) { |
} else if (strcmp(rtype, "direct-streamlocal@openssh.com") == 0) { |
/* target path */ |
/* target path */ |
if ((r = sshpkt_put_cstring(ssh, c->path)) != 0) { |
if ((r = sshpkt_put_cstring(ssh, c->path)) != 0) |
fatal("%s: channel %i: reply %s", __func__, |
fatal_fr(r, "channel %i: reply", c->self); |
c->self, ssh_err(r)); |
|
} |
|
} else if (strcmp(rtype, "forwarded-streamlocal@openssh.com") == 0) { |
} else if (strcmp(rtype, "forwarded-streamlocal@openssh.com") == 0) { |
/* listen path */ |
/* listen path */ |
if ((r = sshpkt_put_cstring(ssh, c->path)) != 0) { |
if ((r = sshpkt_put_cstring(ssh, c->path)) != 0) |
fatal("%s: channel %i: reply %s", __func__, |
fatal_fr(r, "channel %i: reply", c->self); |
c->self, ssh_err(r)); |
|
} |
|
} else { |
} else { |
/* listen address, port */ |
/* listen address, port */ |
if ((r = sshpkt_put_cstring(ssh, c->path)) != 0 || |
if ((r = sshpkt_put_cstring(ssh, c->path)) != 0 || |
(r = sshpkt_put_u32(ssh, local_port)) != 0) { |
(r = sshpkt_put_u32(ssh, local_port)) != 0) |
fatal("%s: channel %i: reply %s", __func__, |
fatal_fr(r, "channel %i: reply", c->self); |
c->self, ssh_err(r)); |
|
} |
|
} |
} |
if (strcmp(rtype, "forwarded-streamlocal@openssh.com") == 0) { |
if (strcmp(rtype, "forwarded-streamlocal@openssh.com") == 0) { |
/* reserved for future owner/mode info */ |
/* reserved for future owner/mode info */ |
if ((r = sshpkt_put_cstring(ssh, "")) != 0) { |
if ((r = sshpkt_put_cstring(ssh, "")) != 0) |
fatal("%s: channel %i: reply %s", __func__, |
fatal_fr(r, "channel %i: reply", c->self); |
c->self, ssh_err(r)); |
|
} |
|
} else { |
} else { |
/* originator host and port */ |
/* originator host and port */ |
if ((r = sshpkt_put_cstring(ssh, remote_ipaddr)) != 0 || |
if ((r = sshpkt_put_cstring(ssh, remote_ipaddr)) != 0 || |
(r = sshpkt_put_u32(ssh, (u_int)remote_port)) != 0) { |
(r = sshpkt_put_u32(ssh, (u_int)remote_port)) != 0) |
fatal("%s: channel %i: reply %s", __func__, |
fatal_fr(r, "channel %i: reply", c->self); |
c->self, ssh_err(r)); |
|
} |
|
} |
} |
if ((r = sshpkt_send(ssh)) != 0) |
if ((r = sshpkt_send(ssh)) != 0) |
fatal("%s: channel %i: send %s", __func__, c->self, ssh_err(r)); |
fatal_fr(r, "channel %i: send", c->self); |
free(remote_ipaddr); |
free(remote_ipaddr); |
free(local_ipaddr); |
free(local_ipaddr); |
} |
} |
|
|
0, "accepted auth socket", 1); |
0, "accepted auth socket", 1); |
open_preamble(ssh, __func__, nc, "auth-agent@openssh.com"); |
open_preamble(ssh, __func__, nc, "auth-agent@openssh.com"); |
if ((r = sshpkt_send(ssh)) != 0) |
if ((r = sshpkt_send(ssh)) != 0) |
fatal("%s: channel %i: %s", __func__, c->self, ssh_err(r)); |
fatal_fr(r, "channel %i", c->self); |
} |
} |
|
|
static void |
static void |
|
|
if (!FD_ISSET(c->sock, writeset)) |
if (!FD_ISSET(c->sock, writeset)) |
return; |
return; |
if (!c->have_remote_id) |
if (!c->have_remote_id) |
fatal(":%s: channel %d: no remote id", __func__, c->self); |
fatal_f("channel %d: no remote id", c->self); |
/* for rdynamic the OPEN_CONFIRMATION has been sent already */ |
/* for rdynamic the OPEN_CONFIRMATION has been sent already */ |
isopen = (c->type == SSH_CHANNEL_RDYNAMIC_FINISH); |
isopen = (c->type == SSH_CHANNEL_RDYNAMIC_FINISH); |
if (getsockopt(c->sock, SOL_SOCKET, SO_ERROR, &err, &sz) == -1) { |
if (getsockopt(c->sock, SOL_SOCKET, SO_ERROR, &err, &sz) == -1) { |
|
|
(r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || |
(r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || |
(r = sshpkt_put_u32(ssh, c->self)) != 0 || |
(r = sshpkt_put_u32(ssh, c->self)) != 0 || |
(r = sshpkt_put_u32(ssh, c->local_window)) != 0 || |
(r = sshpkt_put_u32(ssh, c->local_window)) != 0 || |
(r = sshpkt_put_u32(ssh, c->local_maxpacket)) |
(r = sshpkt_put_u32(ssh, c->local_maxpacket)) != 0 || |
!= 0) |
(r = sshpkt_send(ssh)) != 0) |
fatal("%s: channel %i: confirm: %s", __func__, |
fatal_fr(r, "channel %i open confirm", c->self); |
c->self, ssh_err(r)); |
|
if ((r = sshpkt_send(ssh)) != 0) |
|
fatal("%s: channel %i: %s", __func__, c->self, |
|
ssh_err(r)); |
|
} |
} |
} else { |
} else { |
debug("channel %d: connection failed: %s", |
debug("channel %d: connection failed: %s", |
|
|
(r = sshpkt_put_u32(ssh, |
(r = sshpkt_put_u32(ssh, |
SSH2_OPEN_CONNECT_FAILED)) != 0 || |
SSH2_OPEN_CONNECT_FAILED)) != 0 || |
(r = sshpkt_put_cstring(ssh, strerror(err))) != 0 || |
(r = sshpkt_put_cstring(ssh, strerror(err))) != 0 || |
(r = sshpkt_put_cstring(ssh, "")) != 0) { |
(r = sshpkt_put_cstring(ssh, "")) != 0 || |
fatal("%s: channel %i: failure: %s", __func__, |
(r = sshpkt_send(ssh)) != 0) |
c->self, ssh_err(r)); |
fatal_fr(r, "channel %i: failure", c->self); |
} |
|
if ((r = sshpkt_send(ssh)) != 0) |
|
fatal("%s: channel %i: %s", __func__, c->self, |
|
ssh_err(r)); |
|
chan_mark_dead(ssh, c); |
chan_mark_dead(ssh, c); |
} |
} |
} |
} |
|
|
} |
} |
} else if (c->datagram) { |
} else if (c->datagram) { |
if ((r = sshbuf_put_string(c->input, buf, len)) != 0) |
if ((r = sshbuf_put_string(c->input, buf, len)) != 0) |
fatal("%s: channel %d: put datagram: %s", __func__, |
fatal_fr(r, "channel %i: put datagram", c->self); |
c->self, ssh_err(r)); |
} else if ((r = sshbuf_put(c->input, buf, len)) != 0) |
} else if ((r = sshbuf_put(c->input, buf, len)) != 0) { |
fatal_fr(r, "channel %i: put data", c->self); |
fatal("%s: channel %d: put data: %s", __func__, |
|
c->self, ssh_err(r)); |
|
} |
|
return 1; |
return 1; |
} |
} |
|
|
|
|
} |
} |
} else if (c->datagram) { |
} else if (c->datagram) { |
if ((r = sshbuf_get_string(c->output, &data, &dlen)) != 0) |
if ((r = sshbuf_get_string(c->output, &data, &dlen)) != 0) |
fatal("%s: channel %d: get datagram: %s", __func__, |
fatal_fr(r, "channel %i: get datagram", c->self); |
c->self, ssh_err(r)); |
|
buf = data; |
buf = data; |
} else { |
} else { |
buf = data = sshbuf_mutable_ptr(c->output); |
buf = data = sshbuf_mutable_ptr(c->output); |
|
|
*/ |
*/ |
if ((r = sshpkt_msg_ignore(ssh, 4+len)) != 0 || |
if ((r = sshpkt_msg_ignore(ssh, 4+len)) != 0 || |
(r = sshpkt_send(ssh)) != 0) |
(r = sshpkt_send(ssh)) != 0) |
fatal("%s: channel %d: ignore: %s", |
fatal_fr(r, "channel %i: ignore", c->self); |
__func__, c->self, ssh_err(r)); |
|
} |
} |
} |
} |
if ((r = sshbuf_consume(c->output, len)) != 0) { |
if ((r = sshbuf_consume(c->output, len)) != 0) |
fatal("%s: channel %d: consume: %s", |
fatal_fr(r, "channel %i: consume", c->self); |
__func__, c->self, ssh_err(r)); |
|
} |
|
out: |
out: |
c->local_consumed += olen - sshbuf_len(c->output); |
c->local_consumed += olen - sshbuf_len(c->output); |
|
|
|
|
debug2("channel %d: closing write-efd %d", c->self, c->efd); |
debug2("channel %d: closing write-efd %d", c->self, c->efd); |
channel_close_fd(ssh, &c->efd); |
channel_close_fd(ssh, &c->efd); |
} else { |
} else { |
if ((r = sshbuf_consume(c->extended, len)) != 0) { |
if ((r = sshbuf_consume(c->extended, len)) != 0) |
fatal("%s: channel %d: consume: %s", |
fatal_fr(r, "channel %i: consume", c->self); |
__func__, c->self, ssh_err(r)); |
|
} |
|
c->local_consumed += len; |
c->local_consumed += len; |
} |
} |
return 1; |
return 1; |
|
|
if (len == -1 && (errno == EINTR || errno == EAGAIN)) |
if (len == -1 && (errno == EINTR || errno == EAGAIN)) |
return 1; |
return 1; |
if (len <= 0) { |
if (len <= 0) { |
debug2("channel %d: closing read-efd %d", |
debug2("channel %d: closing read-efd %d", c->self, c->efd); |
c->self, c->efd); |
|
channel_close_fd(ssh, &c->efd); |
channel_close_fd(ssh, &c->efd); |
} else { |
} else if (c->extended_usage == CHAN_EXTENDED_IGNORE) |
if (c->extended_usage == CHAN_EXTENDED_IGNORE) { |
debug3("channel %d: discard efd", c->self); |
debug3("channel %d: discard efd", |
else if ((r = sshbuf_put(c->extended, buf, len)) != 0) |
c->self); |
fatal_fr(r, "channel %i: append", c->self); |
} else if ((r = sshbuf_put(c->extended, buf, len)) != 0) { |
|
fatal("%s: channel %d: append: %s", |
|
__func__, c->self, ssh_err(r)); |
|
} |
|
} |
|
return 1; |
return 1; |
} |
} |
|
|
|
|
c->local_window < c->local_window_max/2) && |
c->local_window < c->local_window_max/2) && |
c->local_consumed > 0) { |
c->local_consumed > 0) { |
if (!c->have_remote_id) |
if (!c->have_remote_id) |
fatal(":%s: channel %d: no remote id", |
fatal_f("channel %d: no remote id", c->self); |
__func__, c->self); |
|
if ((r = sshpkt_start(ssh, |
if ((r = sshpkt_start(ssh, |
SSH2_MSG_CHANNEL_WINDOW_ADJUST)) != 0 || |
SSH2_MSG_CHANNEL_WINDOW_ADJUST)) != 0 || |
(r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || |
(r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || |
(r = sshpkt_put_u32(ssh, c->local_consumed)) != 0 || |
(r = sshpkt_put_u32(ssh, c->local_consumed)) != 0 || |
(r = sshpkt_send(ssh)) != 0) { |
(r = sshpkt_send(ssh)) != 0) { |
fatal("%s: channel %i: %s", __func__, |
fatal_fr(r, "channel %i", c->self); |
c->self, ssh_err(r)); |
|
} |
} |
debug2("channel %d: window %d sent adjust %d", |
debug2("channel %d: window %d sent adjust %d", c->self, |
c->self, c->local_window, |
c->local_window, c->local_consumed); |
c->local_consumed); |
|
c->local_window += c->local_consumed; |
c->local_window += c->local_consumed; |
c->local_consumed = 0; |
c->local_consumed = 0; |
} |
} |
|
|
c->self, c->rfd, len); |
c->self, c->rfd, len); |
chan_read_failed(ssh, c); |
chan_read_failed(ssh, c); |
return 0; |
return 0; |
} else if ((r = sshbuf_put(c->input, buf, len)) != 0) { |
} else if ((r = sshbuf_put(c->input, buf, len)) != 0) |
fatal("%s: channel %d: append: %s", |
fatal_fr(r, "channel %i: append", c->self); |
__func__, c->self, ssh_err(r)); |
|
} |
|
} |
} |
return sshbuf_len(c->input); |
return sshbuf_len(c->input); |
} |
} |
|
|
return; |
return; |
} |
} |
if ((r = sshbuf_consume(c->output, len)) != 0) |
if ((r = sshbuf_consume(c->output, len)) != 0) |
fatal("%s: channel %d: consume: %s", __func__, |
fatal_fr(r, "channel %i: consume", c->self); |
c->self, ssh_err(r)); |
|
} |
} |
|
|
static void |
static void |
|
|
addrlen = sizeof(addr); |
addrlen = sizeof(addr); |
if ((newsock = accept(c->sock, (struct sockaddr*)&addr, |
if ((newsock = accept(c->sock, (struct sockaddr*)&addr, |
&addrlen)) == -1) { |
&addrlen)) == -1) { |
error("%s accept: %s", __func__, strerror(errno)); |
error_f("accept: %s", strerror(errno)); |
if (errno == EMFILE || errno == ENFILE) |
if (errno == EMFILE || errno == ENFILE) |
c->notbefore = monotime() + 1; |
c->notbefore = monotime() + 1; |
return; |
return; |
} |
} |
|
|
if (getpeereid(newsock, &euid, &egid) == -1) { |
if (getpeereid(newsock, &euid, &egid) == -1) { |
error("%s getpeereid failed: %s", __func__, |
error_f("getpeereid failed: %s", strerror(errno)); |
strerror(errno)); |
|
close(newsock); |
close(newsock); |
return; |
return; |
} |
} |
|
|
newsock, newsock, -1, c->local_window_max, |
newsock, newsock, -1, c->local_window_max, |
c->local_maxpacket, 0, "mux-control", 1); |
c->local_maxpacket, 0, "mux-control", 1); |
nc->mux_rcb = c->mux_rcb; |
nc->mux_rcb = c->mux_rcb; |
debug3("%s: new mux channel %d fd %d", __func__, nc->self, nc->sock); |
debug3_f("new mux channel %d fd %d", nc->self, nc->sock); |
/* establish state */ |
/* establish state */ |
nc->mux_rcb(ssh, nc); |
nc->mux_rcb(ssh, nc); |
/* mux state transitions must not elicit protocol messages */ |
/* mux state transitions must not elicit protocol messages */ |
|
|
|
|
if ((pre = calloc(SSH_CHANNEL_MAX_TYPE, sizeof(*pre))) == NULL || |
if ((pre = calloc(SSH_CHANNEL_MAX_TYPE, sizeof(*pre))) == NULL || |
(post = calloc(SSH_CHANNEL_MAX_TYPE, sizeof(*post))) == NULL) |
(post = calloc(SSH_CHANNEL_MAX_TYPE, sizeof(*post))) == NULL) |
fatal("%s: allocation failed", __func__); |
fatal_f("allocation failed"); |
|
|
pre[SSH_CHANNEL_OPEN] = &channel_pre_open; |
pre[SSH_CHANNEL_OPEN] = &channel_pre_open; |
pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open; |
pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open; |
|
|
* Collect the time that the earliest |
* Collect the time that the earliest |
* channel comes off pause. |
* channel comes off pause. |
*/ |
*/ |
debug3("%s: chan %d: skip for %d more seconds", |
debug3_f("chan %d: skip for %d more " |
__func__, c->self, |
"seconds", c->self, |
(int)(c->notbefore - now)); |
(int)(c->notbefore - now)); |
if (*unpause_secs == 0 || |
if (*unpause_secs == 0 || |
(c->notbefore - now) < *unpause_secs) |
(c->notbefore - now) < *unpause_secs) |
|
|
channel_garbage_collect(ssh, c); |
channel_garbage_collect(ssh, c); |
} |
} |
if (unpause_secs != NULL && *unpause_secs != 0) |
if (unpause_secs != NULL && *unpause_secs != 0) |
debug3("%s: first channel unpauses in %d seconds", |
debug3_f("first channel unpauses in %d seconds", |
__func__, (int)*unpause_secs); |
(int)*unpause_secs); |
} |
} |
|
|
/* |
/* |
|
|
} |
} |
|
|
if (!c->have_remote_id) |
if (!c->have_remote_id) |
fatal(":%s: channel %d: no remote id", __func__, c->self); |
fatal_f("channel %d: no remote id", c->self); |
|
|
if (c->datagram) { |
if (c->datagram) { |
/* Check datagram will fit; drop if not */ |
/* Check datagram will fit; drop if not */ |
if ((r = sshbuf_get_string_direct(c->input, &pkt, &plen)) != 0) |
if ((r = sshbuf_get_string_direct(c->input, &pkt, &plen)) != 0) |
fatal("%s: channel %d: get datagram: %s", __func__, |
fatal_fr(r, "channel %i: get datagram", c->self); |
c->self, ssh_err(r)); |
|
/* |
/* |
* XXX this does tail-drop on the datagram queue which is |
* XXX this does tail-drop on the datagram queue which is |
* usually suboptimal compared to head-drop. Better to have |
* usually suboptimal compared to head-drop. Better to have |
|
|
if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_DATA)) != 0 || |
if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_DATA)) != 0 || |
(r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || |
(r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || |
(r = sshpkt_put_string(ssh, pkt, plen)) != 0 || |
(r = sshpkt_put_string(ssh, pkt, plen)) != 0 || |
(r = sshpkt_send(ssh)) != 0) { |
(r = sshpkt_send(ssh)) != 0) |
fatal("%s: channel %i: datagram: %s", __func__, |
fatal_fr(r, "channel %i: send datagram", c->self); |
c->self, ssh_err(r)); |
|
} |
|
c->remote_window -= plen; |
c->remote_window -= plen; |
return; |
return; |
} |
} |
|
|
if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_DATA)) != 0 || |
if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_DATA)) != 0 || |
(r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || |
(r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || |
(r = sshpkt_put_string(ssh, sshbuf_ptr(c->input), len)) != 0 || |
(r = sshpkt_put_string(ssh, sshbuf_ptr(c->input), len)) != 0 || |
(r = sshpkt_send(ssh)) != 0) { |
(r = sshpkt_send(ssh)) != 0) |
fatal("%s: channel %i: data: %s", __func__, |
fatal_fr(r, "channel %i: send data", c->self); |
c->self, ssh_err(r)); |
|
} |
|
if ((r = sshbuf_consume(c->input, len)) != 0) |
if ((r = sshbuf_consume(c->input, len)) != 0) |
fatal("%s: channel %i: consume: %s", __func__, |
fatal_fr(r, "channel %i: consume", c->self); |
c->self, ssh_err(r)); |
|
c->remote_window -= len; |
c->remote_window -= len; |
} |
} |
|
|
|
|
if (len == 0) |
if (len == 0) |
return; |
return; |
if (!c->have_remote_id) |
if (!c->have_remote_id) |
fatal(":%s: channel %d: no remote id", __func__, c->self); |
fatal_f("channel %d: no remote id", c->self); |
if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_EXTENDED_DATA)) != 0 || |
if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_EXTENDED_DATA)) != 0 || |
(r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || |
(r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || |
(r = sshpkt_put_u32(ssh, SSH2_EXTENDED_DATA_STDERR)) != 0 || |
(r = sshpkt_put_u32(ssh, SSH2_EXTENDED_DATA_STDERR)) != 0 || |
(r = sshpkt_put_string(ssh, sshbuf_ptr(c->extended), len)) != 0 || |
(r = sshpkt_put_string(ssh, sshbuf_ptr(c->extended), len)) != 0 || |
(r = sshpkt_send(ssh)) != 0) { |
(r = sshpkt_send(ssh)) != 0) |
fatal("%s: channel %i: data: %s", __func__, |
fatal_fr(r, "channel %i: data", c->self); |
c->self, ssh_err(r)); |
|
} |
|
if ((r = sshbuf_consume(c->extended, len)) != 0) |
if ((r = sshbuf_consume(c->extended, len)) != 0) |
fatal("%s: channel %i: consume: %s", __func__, |
fatal_fr(r, "channel %i: consume", c->self); |
c->self, ssh_err(r)); |
|
c->remote_window -= len; |
c->remote_window -= len; |
debug2("channel %d: sent ext data %zu", c->self, len); |
debug2("channel %d: sent ext data %zu", c->self, len); |
} |
} |
|
|
/* sshbuf_dump(downstream->input, stderr); */ |
/* sshbuf_dump(downstream->input, stderr); */ |
if ((r = sshbuf_get_string_direct(downstream->input, &cp, &have)) |
if ((r = sshbuf_get_string_direct(downstream->input, &cp, &have)) |
!= 0) { |
!= 0) { |
error("%s: malformed message: %s", __func__, ssh_err(r)); |
error_fr(r, "parse"); |
return -1; |
return -1; |
} |
} |
if (have < 2) { |
if (have < 2) { |
error("%s: short message", __func__); |
error_f("short message"); |
return -1; |
return -1; |
} |
} |
type = cp[1]; |
type = cp[1]; |
|
|
cp += 2; |
cp += 2; |
have -= 2; |
have -= 2; |
if (ssh_packet_log_type(type)) |
if (ssh_packet_log_type(type)) |
debug3("%s: channel %u: down->up: type %u", __func__, |
debug3_f("channel %u: down->up: type %u", |
downstream->self, type); |
downstream->self, type); |
|
|
switch (type) { |
switch (type) { |
case SSH2_MSG_CHANNEL_OPEN: |
case SSH2_MSG_CHANNEL_OPEN: |
if ((original = sshbuf_from(cp, have)) == NULL || |
if ((original = sshbuf_from(cp, have)) == NULL || |
(modified = sshbuf_new()) == NULL) { |
(modified = sshbuf_new()) == NULL) { |
error("%s: alloc", __func__); |
error_f("alloc"); |
goto out; |
goto out; |
} |
} |
if ((r = sshbuf_get_cstring(original, &ctype, NULL)) != 0 || |
if ((r = sshbuf_get_cstring(original, &ctype, NULL)) != 0 || |
(r = sshbuf_get_u32(original, &id)) != 0) { |
(r = sshbuf_get_u32(original, &id)) != 0) { |
error("%s: parse error %s", __func__, ssh_err(r)); |
error_fr(r, "parse"); |
goto out; |
goto out; |
} |
} |
c = channel_new(ssh, "mux proxy", SSH_CHANNEL_MUX_PROXY, |
c = channel_new(ssh, "mux proxy", SSH_CHANNEL_MUX_PROXY, |
|
|
if ((r = sshbuf_put_cstring(modified, ctype)) != 0 || |
if ((r = sshbuf_put_cstring(modified, ctype)) != 0 || |
(r = sshbuf_put_u32(modified, c->self)) != 0 || |
(r = sshbuf_put_u32(modified, c->self)) != 0 || |
(r = sshbuf_putb(modified, original)) != 0) { |
(r = sshbuf_putb(modified, original)) != 0) { |
error("%s: compose error %s", __func__, ssh_err(r)); |
error_fr(r, "compose"); |
channel_free(ssh, c); |
channel_free(ssh, c); |
goto out; |
goto out; |
} |
} |
|
|
*/ |
*/ |
if ((original = sshbuf_from(cp, have)) == NULL || |
if ((original = sshbuf_from(cp, have)) == NULL || |
(modified = sshbuf_new()) == NULL) { |
(modified = sshbuf_new()) == NULL) { |
error("%s: alloc", __func__); |
error_f("alloc"); |
goto out; |
goto out; |
} |
} |
if ((r = sshbuf_get_u32(original, &remote_id)) != 0 || |
if ((r = sshbuf_get_u32(original, &remote_id)) != 0 || |
(r = sshbuf_get_u32(original, &id)) != 0) { |
(r = sshbuf_get_u32(original, &id)) != 0) { |
error("%s: parse error %s", __func__, ssh_err(r)); |
error_fr(r, "parse"); |
goto out; |
goto out; |
} |
} |
c = channel_new(ssh, "mux proxy", SSH_CHANNEL_MUX_PROXY, |
c = channel_new(ssh, "mux proxy", SSH_CHANNEL_MUX_PROXY, |
|
|
if ((r = sshbuf_put_u32(modified, remote_id)) != 0 || |
if ((r = sshbuf_put_u32(modified, remote_id)) != 0 || |
(r = sshbuf_put_u32(modified, c->self)) != 0 || |
(r = sshbuf_put_u32(modified, c->self)) != 0 || |
(r = sshbuf_putb(modified, original)) != 0) { |
(r = sshbuf_putb(modified, original)) != 0) { |
error("%s: compose error %s", __func__, ssh_err(r)); |
error_fr(r, "compose"); |
channel_free(ssh, c); |
channel_free(ssh, c); |
goto out; |
goto out; |
} |
} |
break; |
break; |
case SSH2_MSG_GLOBAL_REQUEST: |
case SSH2_MSG_GLOBAL_REQUEST: |
if ((original = sshbuf_from(cp, have)) == NULL) { |
if ((original = sshbuf_from(cp, have)) == NULL) { |
error("%s: alloc", __func__); |
error_f("alloc"); |
goto out; |
goto out; |
} |
} |
if ((r = sshbuf_get_cstring(original, &ctype, NULL)) != 0) { |
if ((r = sshbuf_get_cstring(original, &ctype, NULL)) != 0) { |
error("%s: parse error %s", __func__, ssh_err(r)); |
error_fr(r, "parse"); |
goto out; |
goto out; |
} |
} |
if (strcmp(ctype, "tcpip-forward") != 0) { |
if (strcmp(ctype, "tcpip-forward") != 0) { |
error("%s: unsupported request %s", __func__, ctype); |
error_f("unsupported request %s", ctype); |
goto out; |
goto out; |
} |
} |
if ((r = sshbuf_get_u8(original, NULL)) != 0 || |
if ((r = sshbuf_get_u8(original, NULL)) != 0 || |
(r = sshbuf_get_cstring(original, &listen_host, NULL)) != 0 || |
(r = sshbuf_get_cstring(original, &listen_host, NULL)) != 0 || |
(r = sshbuf_get_u32(original, &listen_port)) != 0) { |
(r = sshbuf_get_u32(original, &listen_port)) != 0) { |
error("%s: parse error %s", __func__, ssh_err(r)); |
error_fr(r, "parse"); |
goto out; |
goto out; |
} |
} |
if (listen_port > 65535) { |
if (listen_port > 65535) { |
error("%s: tcpip-forward for %s: bad port %u", |
error_f("tcpip-forward for %s: bad port %u", |
__func__, listen_host, listen_port); |
listen_host, listen_port); |
goto out; |
goto out; |
} |
} |
/* Record that connection to this host/port is permitted. */ |
/* Record that connection to this host/port is permitted. */ |
|
|
if ((r = sshpkt_start(ssh, type)) != 0 || |
if ((r = sshpkt_start(ssh, type)) != 0 || |
(r = sshpkt_putb(ssh, modified)) != 0 || |
(r = sshpkt_putb(ssh, modified)) != 0 || |
(r = sshpkt_send(ssh)) != 0) { |
(r = sshpkt_send(ssh)) != 0) { |
error("%s: send %s", __func__, ssh_err(r)); |
error_fr(r, "send"); |
goto out; |
goto out; |
} |
} |
} else { |
} else { |
if ((r = sshpkt_start(ssh, type)) != 0 || |
if ((r = sshpkt_start(ssh, type)) != 0 || |
(r = sshpkt_put(ssh, cp, have)) != 0 || |
(r = sshpkt_put(ssh, cp, have)) != 0 || |
(r = sshpkt_send(ssh)) != 0) { |
(r = sshpkt_send(ssh)) != 0) { |
error("%s: send %s", __func__, ssh_err(r)); |
error_fr(r, "send"); |
goto out; |
goto out; |
} |
} |
} |
} |
|
|
case SSH2_MSG_CHANNEL_REQUEST: |
case SSH2_MSG_CHANNEL_REQUEST: |
break; |
break; |
default: |
default: |
debug2("%s: channel %u: unsupported type %u", __func__, |
debug2_f("channel %u: unsupported type %u", c->self, type); |
c->self, type); |
|
return 0; |
return 0; |
} |
} |
if ((b = sshbuf_new()) == NULL) { |
if ((b = sshbuf_new()) == NULL) { |
error("%s: alloc reply", __func__); |
error_f("alloc reply"); |
goto out; |
goto out; |
} |
} |
/* get remaining payload (after id) */ |
/* get remaining payload (after id) */ |
cp = sshpkt_ptr(ssh, &len); |
cp = sshpkt_ptr(ssh, &len); |
if (cp == NULL) { |
if (cp == NULL) { |
error("%s: no packet", __func__); |
error_f("no packet"); |
goto out; |
goto out; |
} |
} |
/* translate id and send to muxclient */ |
/* translate id and send to muxclient */ |
|
|
(r = sshbuf_put_u32(b, c->mux_downstream_id)) != 0 || |
(r = sshbuf_put_u32(b, c->mux_downstream_id)) != 0 || |
(r = sshbuf_put(b, cp, len)) != 0 || |
(r = sshbuf_put(b, cp, len)) != 0 || |
(r = sshbuf_put_stringb(downstream->output, b)) != 0) { |
(r = sshbuf_put_stringb(downstream->output, b)) != 0) { |
error("%s: compose for muxclient %s", __func__, ssh_err(r)); |
error_fr(r, "compose muxclient"); |
goto out; |
goto out; |
} |
} |
/* sshbuf_dump(b, stderr); */ |
/* sshbuf_dump(b, stderr); */ |
if (ssh_packet_log_type(type)) |
if (ssh_packet_log_type(type)) |
debug3("%s: channel %u: up->down: type %u", __func__, c->self, |
debug3_f("channel %u: up->down: type %u", c->self, type); |
type); |
|
out: |
out: |
/* update state */ |
/* update state */ |
switch (type) { |
switch (type) { |
|
|
int r; |
int r; |
|
|
if ((r = sshpkt_get_u32(ssh, &id)) != 0) { |
if ((r = sshpkt_get_u32(ssh, &id)) != 0) { |
error("%s: parse id: %s", where, ssh_err(r)); |
error_r(r, "%s: parse id", where); |
ssh_packet_disconnect(ssh, "Invalid %s message", what); |
ssh_packet_disconnect(ssh, "Invalid %s message", what); |
} |
} |
if (id > INT_MAX) { |
if (id > INT_MAX) { |
error("%s: bad channel id %u: %s", where, id, ssh_err(r)); |
error_r(r, "%s: bad channel id %u", where, id); |
ssh_packet_disconnect(ssh, "Invalid %s channel id", what); |
ssh_packet_disconnect(ssh, "Invalid %s channel id", what); |
} |
} |
return (int)id; |
return (int)id; |
|
|
/* Get the data. */ |
/* Get the data. */ |
if ((r = sshpkt_get_string_direct(ssh, &data, &data_len)) != 0 || |
if ((r = sshpkt_get_string_direct(ssh, &data, &data_len)) != 0 || |
(r = sshpkt_get_end(ssh)) != 0) |
(r = sshpkt_get_end(ssh)) != 0) |
fatal("%s: channel %d: get data: %s", __func__, |
fatal_fr(r, "channel %i: get data", c->self); |
c->self, ssh_err(r)); |
|
|
|
win_len = data_len; |
win_len = data_len; |
if (c->datagram) |
if (c->datagram) |
|
|
|
|
if (c->datagram) { |
if (c->datagram) { |
if ((r = sshbuf_put_string(c->output, data, data_len)) != 0) |
if ((r = sshbuf_put_string(c->output, data, data_len)) != 0) |
fatal("%s: channel %d: append datagram: %s", |
fatal_fr(r, "channel %i: append datagram", c->self); |
__func__, c->self, ssh_err(r)); |
|
} else if ((r = sshbuf_put(c->output, data, data_len)) != 0) |
} else if ((r = sshbuf_put(c->output, data, data_len)) != 0) |
fatal("%s: channel %d: append data: %s", |
fatal_fr(r, "channel %i: append data", c->self); |
__func__, c->self, ssh_err(r)); |
|
|
|
return 0; |
return 0; |
} |
} |
|
|
} |
} |
|
|
if ((r = sshpkt_get_u32(ssh, &tcode)) != 0) { |
if ((r = sshpkt_get_u32(ssh, &tcode)) != 0) { |
error("%s: parse tcode: %s", __func__, ssh_err(r)); |
error_fr(r, "parse tcode"); |
ssh_packet_disconnect(ssh, "Invalid extended_data message"); |
ssh_packet_disconnect(ssh, "Invalid extended_data message"); |
} |
} |
if (c->efd == -1 || |
if (c->efd == -1 || |
|
|
} |
} |
if ((r = sshpkt_get_string_direct(ssh, &data, &data_len)) != 0 || |
if ((r = sshpkt_get_string_direct(ssh, &data, &data_len)) != 0 || |
(r = sshpkt_get_end(ssh)) != 0) { |
(r = sshpkt_get_end(ssh)) != 0) { |
error("%s: parse data: %s", __func__, ssh_err(r)); |
error_fr(r, "parse data"); |
ssh_packet_disconnect(ssh, "Invalid extended_data message"); |
ssh_packet_disconnect(ssh, "Invalid extended_data message"); |
} |
} |
|
|
|
|
debug2("channel %d: rcvd ext data %zu", c->self, data_len); |
debug2("channel %d: rcvd ext data %zu", c->self, data_len); |
/* XXX sshpkt_getb? */ |
/* XXX sshpkt_getb? */ |
if ((r = sshbuf_put(c->extended, data, data_len)) != 0) |
if ((r = sshbuf_put(c->extended, data, data_len)) != 0) |
error("%s: append: %s", __func__, ssh_err(r)); |
error_fr(r, "append"); |
c->local_window -= data_len; |
c->local_window -= data_len; |
return 0; |
return 0; |
} |
} |
|
|
int r; |
int r; |
|
|
if ((r = sshpkt_get_end(ssh)) != 0) { |
if ((r = sshpkt_get_end(ssh)) != 0) { |
error("%s: parse data: %s", __func__, ssh_err(r)); |
error_fr(r, "parse data"); |
ssh_packet_disconnect(ssh, "Invalid ieof message"); |
ssh_packet_disconnect(ssh, "Invalid ieof message"); |
} |
} |
|
|
|
|
if (channel_proxy_upstream(c, type, seq, ssh)) |
if (channel_proxy_upstream(c, type, seq, ssh)) |
return 0; |
return 0; |
if ((r = sshpkt_get_end(ssh)) != 0) { |
if ((r = sshpkt_get_end(ssh)) != 0) { |
error("%s: parse data: %s", __func__, ssh_err(r)); |
error_fr(r, "parse data"); |
ssh_packet_disconnect(ssh, "Invalid oclose message"); |
ssh_packet_disconnect(ssh, "Invalid oclose message"); |
} |
} |
chan_rcvd_oclose(ssh, c); |
chan_rcvd_oclose(ssh, c); |
|
|
(r = sshpkt_get_u32(ssh, &remote_window)) != 0 || |
(r = sshpkt_get_u32(ssh, &remote_window)) != 0 || |
(r = sshpkt_get_u32(ssh, &remote_maxpacket)) != 0 || |
(r = sshpkt_get_u32(ssh, &remote_maxpacket)) != 0 || |
(r = sshpkt_get_end(ssh)) != 0) { |
(r = sshpkt_get_end(ssh)) != 0) { |
error("%s: window/maxpacket: %s", __func__, ssh_err(r)); |
error_fr(r, "window/maxpacket"); |
ssh_packet_disconnect(ssh, "Invalid open confirmation message"); |
ssh_packet_disconnect(ssh, "Invalid open confirmation message"); |
} |
} |
|
|
|
|
c->remote_maxpacket = remote_maxpacket; |
c->remote_maxpacket = remote_maxpacket; |
c->type = SSH_CHANNEL_OPEN; |
c->type = SSH_CHANNEL_OPEN; |
if (c->open_confirm) { |
if (c->open_confirm) { |
debug2("%s: channel %d: callback start", __func__, c->self); |
debug2_f("channel %d: callback start", c->self); |
c->open_confirm(ssh, c->self, 1, c->open_confirm_ctx); |
c->open_confirm(ssh, c->self, 1, c->open_confirm_ctx); |
debug2("%s: channel %d: callback done", __func__, c->self); |
debug2_f("channel %d: callback done", c->self); |
} |
} |
debug2("channel %d: open confirm rwindow %u rmax %u", c->self, |
debug2("channel %d: open confirm rwindow %u rmax %u", c->self, |
c->remote_window, c->remote_maxpacket); |
c->remote_window, c->remote_maxpacket); |
|
|
ssh_packet_disconnect(ssh, "Received open failure for " |
ssh_packet_disconnect(ssh, "Received open failure for " |
"non-opening channel %d.", c->self); |
"non-opening channel %d.", c->self); |
if ((r = sshpkt_get_u32(ssh, &reason)) != 0) { |
if ((r = sshpkt_get_u32(ssh, &reason)) != 0) { |
error("%s: reason: %s", __func__, ssh_err(r)); |
error_fr(r, "parse reason"); |
ssh_packet_disconnect(ssh, "Invalid open failure message"); |
ssh_packet_disconnect(ssh, "Invalid open failure message"); |
} |
} |
/* skip language */ |
/* skip language */ |
if ((r = sshpkt_get_cstring(ssh, &msg, NULL)) != 0 || |
if ((r = sshpkt_get_cstring(ssh, &msg, NULL)) != 0 || |
(r = sshpkt_get_string_direct(ssh, NULL, NULL)) != 0 || |
(r = sshpkt_get_string_direct(ssh, NULL, NULL)) != 0 || |
(r = sshpkt_get_end(ssh)) != 0) { |
(r = sshpkt_get_end(ssh)) != 0) { |
error("%s: message/lang: %s", __func__, ssh_err(r)); |
error_fr(r, "parse msg/lang"); |
ssh_packet_disconnect(ssh, "Invalid open failure message"); |
ssh_packet_disconnect(ssh, "Invalid open failure message"); |
} |
} |
logit("channel %d: open failed: %s%s%s", c->self, |
logit("channel %d: open failed: %s%s%s", c->self, |
reason2txt(reason), msg ? ": ": "", msg ? msg : ""); |
reason2txt(reason), msg ? ": ": "", msg ? msg : ""); |
free(msg); |
free(msg); |
if (c->open_confirm) { |
if (c->open_confirm) { |
debug2("%s: channel %d: callback start", __func__, c->self); |
debug2_f("channel %d: callback start", c->self); |
c->open_confirm(ssh, c->self, 0, c->open_confirm_ctx); |
c->open_confirm(ssh, c->self, 0, c->open_confirm_ctx); |
debug2("%s: channel %d: callback done", __func__, c->self); |
debug2_f("channel %d: callback done", c->self); |
} |
} |
/* Schedule the channel for cleanup/deletion. */ |
/* Schedule the channel for cleanup/deletion. */ |
chan_mark_dead(ssh, c); |
chan_mark_dead(ssh, c); |
|
|
return 0; |
return 0; |
if ((r = sshpkt_get_u32(ssh, &adjust)) != 0 || |
if ((r = sshpkt_get_u32(ssh, &adjust)) != 0 || |
(r = sshpkt_get_end(ssh)) != 0) { |
(r = sshpkt_get_end(ssh)) != 0) { |
error("%s: adjust: %s", __func__, ssh_err(r)); |
error_fr(r, "parse adjust"); |
ssh_packet_disconnect(ssh, "Invalid window adjust message"); |
ssh_packet_disconnect(ssh, "Invalid window adjust message"); |
} |
} |
debug2("channel %d: rcvd adjust %u", c->self, adjust); |
debug2("channel %d: rcvd adjust %u", c->self, adjust); |
|
|
/* Reset keepalive timeout */ |
/* Reset keepalive timeout */ |
ssh_packet_set_alive_timeouts(ssh, 0); |
ssh_packet_set_alive_timeouts(ssh, 0); |
|
|
debug2("%s: type %d id %d", __func__, type, id); |
debug2_f("type %d id %d", type, id); |
|
|
if ((c = channel_lookup(ssh, id)) == NULL) { |
if ((c = channel_lookup(ssh, id)) == NULL) { |
logit("%s: %d: unknown", __func__, id); |
logit_f("%d: unknown", id); |
return 0; |
return 0; |
} |
} |
if (channel_proxy_upstream(c, type, seq, ssh)) |
if (channel_proxy_upstream(c, type, seq, ssh)) |
|
|
/* Determine the bind address, cf. channel_fwd_bind_addr() comment */ |
/* Determine the bind address, cf. channel_fwd_bind_addr() comment */ |
addr = channel_fwd_bind_addr(ssh, fwd->listen_host, &wildcard, |
addr = channel_fwd_bind_addr(ssh, fwd->listen_host, &wildcard, |
is_client, fwd_opts); |
is_client, fwd_opts); |
debug3("%s: type %d wildcard %d addr %s", __func__, |
debug3_f("type %d wildcard %d addr %s", type, wildcard, |
type, wildcard, (addr == NULL) ? "NULL" : addr); |
(addr == NULL) ? "NULL" : addr); |
|
|
/* |
/* |
* getaddrinfo returns a loopback address if the hostname is |
* getaddrinfo returns a loopback address if the hostname is |
|
|
ssh_packet_disconnect(ssh, "getaddrinfo: fatal error: %s", |
ssh_packet_disconnect(ssh, "getaddrinfo: fatal error: %s", |
ssh_gai_strerror(r)); |
ssh_gai_strerror(r)); |
} else { |
} else { |
error("%s: getaddrinfo(%.64s): %s", __func__, addr, |
error_f("getaddrinfo(%.64s): %s", addr, |
ssh_gai_strerror(r)); |
ssh_gai_strerror(r)); |
} |
} |
return 0; |
return 0; |
|
|
if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop), |
if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop), |
strport, sizeof(strport), |
strport, sizeof(strport), |
NI_NUMERICHOST|NI_NUMERICSERV) != 0) { |
NI_NUMERICHOST|NI_NUMERICSERV) != 0) { |
error("%s: getnameinfo failed", __func__); |
error_f("getnameinfo failed"); |
continue; |
continue; |
} |
} |
/* Create a port to listen for the host. */ |
/* Create a port to listen for the host. */ |
|
|
success = 1; |
success = 1; |
} |
} |
if (success == 0) |
if (success == 0) |
error("%s: cannot listen to port: %d", __func__, |
error_f("cannot listen to port: %d", fwd->listen_port); |
fwd->listen_port); |
|
freeaddrinfo(aitop); |
freeaddrinfo(aitop); |
return success; |
return success; |
} |
} |
|
|
port = PORT_STREAMLOCAL; |
port = PORT_STREAMLOCAL; |
break; |
break; |
default: |
default: |
error("%s: unexpected channel type %d", __func__, type); |
error_f("unexpected channel type %d", type); |
return 0; |
return 0; |
} |
} |
|
|
|
|
return 0; |
return 0; |
} |
} |
|
|
debug3("%s: type %d path %s", __func__, type, fwd->listen_path); |
debug3_f("type %d path %s", type, fwd->listen_path); |
|
|
/* Start a Unix domain listener. */ |
/* Start a Unix domain listener. */ |
omask = umask(fwd_opts->streamlocal_bind_mask); |
omask = umask(fwd_opts->streamlocal_bind_mask); |
|
|
if (c == NULL || c->type != SSH_CHANNEL_RPORT_LISTENER) |
if (c == NULL || c->type != SSH_CHANNEL_RPORT_LISTENER) |
continue; |
continue; |
if (strcmp(c->path, host) == 0 && c->listening_port == port) { |
if (strcmp(c->path, host) == 0 && c->listening_port == port) { |
debug2("%s: close channel %d", __func__, i); |
debug2_f("close channel %d", i); |
channel_free(ssh, c); |
channel_free(ssh, c); |
found = 1; |
found = 1; |
} |
} |
|
|
if (c->path == NULL) |
if (c->path == NULL) |
continue; |
continue; |
if (strcmp(c->path, path) == 0) { |
if (strcmp(c->path, path) == 0) { |
debug2("%s: close channel %d", __func__, i); |
debug2_f("close channel %d", i); |
channel_free(ssh, c); |
channel_free(ssh, c); |
found = 1; |
found = 1; |
} |
} |
|
|
(c->listening_addr != NULL && addr == NULL)) |
(c->listening_addr != NULL && addr == NULL)) |
continue; |
continue; |
if (addr == NULL || strcmp(c->listening_addr, addr) == 0) { |
if (addr == NULL || strcmp(c->listening_addr, addr) == 0) { |
debug2("%s: close channel %d", __func__, i); |
debug2_f("close channel %d", i); |
channel_free(ssh, c); |
channel_free(ssh, c); |
found = 1; |
found = 1; |
} |
} |
|
|
int found = 0; |
int found = 0; |
|
|
if (path == NULL) { |
if (path == NULL) { |
error("%s: no path specified.", __func__); |
error_f("no path specified."); |
return 0; |
return 0; |
} |
} |
|
|
|
|
if (c->listening_addr == NULL) |
if (c->listening_addr == NULL) |
continue; |
continue; |
if (strcmp(c->listening_addr, path) == 0) { |
if (strcmp(c->listening_addr, path) == 0) { |
debug2("%s: close channel %d", __func__, i); |
debug2_f("close channel %d", i); |
channel_free(ssh, c); |
channel_free(ssh, c); |
found = 1; |
found = 1; |
} |
} |
|
|
(r = sshpkt_put_cstring(ssh, fwd->listen_path)) != 0 || |
(r = sshpkt_put_cstring(ssh, fwd->listen_path)) != 0 || |
(r = sshpkt_send(ssh)) != 0 || |
(r = sshpkt_send(ssh)) != 0 || |
(r = ssh_packet_write_wait(ssh)) != 0) |
(r = ssh_packet_write_wait(ssh)) != 0) |
fatal("%s: request streamlocal: %s", |
fatal_fr(r, "request streamlocal"); |
__func__, ssh_err(r)); |
|
} else { |
} else { |
if ((r = sshpkt_start(ssh, SSH2_MSG_GLOBAL_REQUEST)) != 0 || |
if ((r = sshpkt_start(ssh, SSH2_MSG_GLOBAL_REQUEST)) != 0 || |
(r = sshpkt_put_cstring(ssh, "tcpip-forward")) != 0 || |
(r = sshpkt_put_cstring(ssh, "tcpip-forward")) != 0 || |
|
|
(r = sshpkt_put_u32(ssh, fwd->listen_port)) != 0 || |
(r = sshpkt_put_u32(ssh, fwd->listen_port)) != 0 || |
(r = sshpkt_send(ssh)) != 0 || |
(r = sshpkt_send(ssh)) != 0 || |
(r = ssh_packet_write_wait(ssh)) != 0) |
(r = ssh_packet_write_wait(ssh)) != 0) |
fatal("%s: request tcpip-forward: %s", |
fatal_fr(r, "request tcpip-forward"); |
__func__, ssh_err(r)); |
|
} |
} |
/* Assume that server accepts the request */ |
/* Assume that server accepts the request */ |
success = 1; |
success = 1; |
|
|
perm = NULL; |
perm = NULL; |
} |
} |
if (perm == NULL) { |
if (perm == NULL) { |
debug("%s: requested forward not found", __func__); |
debug_f("requested forward not found"); |
return -1; |
return -1; |
} |
} |
if ((r = sshpkt_start(ssh, SSH2_MSG_GLOBAL_REQUEST)) != 0 || |
if ((r = sshpkt_start(ssh, SSH2_MSG_GLOBAL_REQUEST)) != 0 || |
|
|
(r = sshpkt_put_cstring(ssh, channel_rfwd_bind_host(host))) != 0 || |
(r = sshpkt_put_cstring(ssh, channel_rfwd_bind_host(host))) != 0 || |
(r = sshpkt_put_u32(ssh, port)) != 0 || |
(r = sshpkt_put_u32(ssh, port)) != 0 || |
(r = sshpkt_send(ssh)) != 0) |
(r = sshpkt_send(ssh)) != 0) |
fatal("%s: send cancel: %s", __func__, ssh_err(r)); |
fatal_fr(r, "send cancel"); |
|
|
fwd_perm_clear(perm); /* unregister */ |
fwd_perm_clear(perm); /* unregister */ |
|
|
|
|
perm = NULL; |
perm = NULL; |
} |
} |
if (perm == NULL) { |
if (perm == NULL) { |
debug("%s: requested forward not found", __func__); |
debug_f("requested forward not found"); |
return -1; |
return -1; |
} |
} |
if ((r = sshpkt_start(ssh, SSH2_MSG_GLOBAL_REQUEST)) != 0 || |
if ((r = sshpkt_start(ssh, SSH2_MSG_GLOBAL_REQUEST)) != 0 || |
|
|
(r = sshpkt_put_u8(ssh, 0)) != 0 || /* want reply */ |
(r = sshpkt_put_u8(ssh, 0)) != 0 || /* want reply */ |
(r = sshpkt_put_cstring(ssh, path)) != 0 || |
(r = sshpkt_put_cstring(ssh, path)) != 0 || |
(r = sshpkt_send(ssh)) != 0) |
(r = sshpkt_send(ssh)) != 0) |
fatal("%s: send cancel: %s", __func__, ssh_err(r)); |
fatal_fr(r, "send cancel"); |
|
|
fwd_perm_clear(perm); /* unregister */ |
fwd_perm_clear(perm); /* unregister */ |
|
|
|
|
struct permission_set *pset = &ssh->chanctxt->local_perms; |
struct permission_set *pset = &ssh->chanctxt->local_perms; |
|
|
if (idx < 0 || (u_int)idx >= pset->num_permitted_user) { |
if (idx < 0 || (u_int)idx >= pset->num_permitted_user) { |
debug("%s: index out of range: %d num_permitted_user %d", |
debug_f("index out of range: %d num_permitted_user %d", |
__func__, idx, pset->num_permitted_user); |
idx, pset->num_permitted_user); |
return; |
return; |
} |
} |
debug("%s allowed port %d for forwarding to host %s port %d", |
debug("%s allowed port %d for forwarding to host %s port %d", |
|
|
continue; |
continue; |
} |
} |
if (set_nonblock(sock) == -1) |
if (set_nonblock(sock) == -1) |
fatal("%s: set_nonblock(%d)", __func__, sock); |
fatal_f("set_nonblock(%d)", sock); |
if (connect(sock, cctx->ai->ai_addr, |
if (connect(sock, cctx->ai->ai_addr, |
cctx->ai->ai_addrlen) == -1 && errno != EINPROGRESS) { |
cctx->ai->ai_addrlen) == -1 && errno != EINPROGRESS) { |
debug("connect_next: host %.100s ([%.100s]:%s): " |
debug("connect_next: host %.100s ([%.100s]:%s): " |
|
|
(r = sshpkt_put_u32(ssh, (u_int)ws.ws_xpixel)) != 0 || |
(r = sshpkt_put_u32(ssh, (u_int)ws.ws_xpixel)) != 0 || |
(r = sshpkt_put_u32(ssh, (u_int)ws.ws_ypixel)) != 0 || |
(r = sshpkt_put_u32(ssh, (u_int)ws.ws_ypixel)) != 0 || |
(r = sshpkt_send(ssh)) != 0) |
(r = sshpkt_send(ssh)) != 0) |
fatal("%s: channel %u: send window-change: %s", |
fatal_fr(r, "channel %u; send window-change", i); |
__func__, i, ssh_err(r)); |
|
} |
} |
} |
} |
|
|
|
|
(r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || |
(r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || |
(r = sshpkt_put_u32(ssh, c->self)) != 0 || |
(r = sshpkt_put_u32(ssh, c->self)) != 0 || |
(r = sshpkt_put_u32(ssh, c->local_window)) != 0 || |
(r = sshpkt_put_u32(ssh, c->local_window)) != 0 || |
(r = sshpkt_put_u32(ssh, c->local_maxpacket)) != 0) { |
(r = sshpkt_put_u32(ssh, c->local_maxpacket)) != 0) |
fatal("%s: channel %i: confirm: %s", __func__, |
fatal_fr(r, "channel %i; confirm", c->self); |
c->self, ssh_err(r)); |
|
} |
|
return c; |
return c; |
} |
} |
|
|
|
|
} |
} |
set_reuseaddr(sock); |
set_reuseaddr(sock); |
if (bind(sock, ai->ai_addr, ai->ai_addrlen) == -1) { |
if (bind(sock, ai->ai_addr, ai->ai_addrlen) == -1) { |
debug2("%s: bind port %d: %.100s", __func__, |
debug2_f("bind port %d: %.100s", port, |
port, strerror(errno)); |
strerror(errno)); |
close(sock); |
close(sock); |
for (n = 0; n < num_socks; n++) |
for (n = 0; n < num_socks; n++) |
close(socks[n]); |
close(socks[n]); |
|
|
/* Extract real authentication data. */ |
/* Extract real authentication data. */ |
sc->x11_saved_data = xmalloc(data_len); |
sc->x11_saved_data = xmalloc(data_len); |
for (i = 0; i < data_len; i++) { |
for (i = 0; i < data_len; i++) { |
if (sscanf(data + 2 * i, "%2x", &value) != 1) |
if (sscanf(data + 2 * i, "%2x", &value) != 1) { |
fatal("x11_request_forwarding: bad " |
fatal("x11_request_forwarding: bad " |
"authentication data: %.100s", data); |
"authentication data: %.100s", data); |
|
} |
sc->x11_saved_data[i] = value; |
sc->x11_saved_data[i] = value; |
} |
} |
sc->x11_saved_data_len = data_len; |
sc->x11_saved_data_len = data_len; |
|
|
(r = sshpkt_put_u32(ssh, screen_number)) != 0 || |
(r = sshpkt_put_u32(ssh, screen_number)) != 0 || |
(r = sshpkt_send(ssh)) != 0 || |
(r = sshpkt_send(ssh)) != 0 || |
(r = ssh_packet_write_wait(ssh)) != 0) |
(r = ssh_packet_write_wait(ssh)) != 0) |
fatal("%s: send x11-req: %s", __func__, ssh_err(r)); |
fatal_fr(r, "send x11-req"); |
free(new_data); |
free(new_data); |
} |
} |