Changeset View
Changeset View
Standalone View
Standalone View
channels.c
/* $OpenBSD: channels.c,v 1.389 2019/01/19 21:37:13 djm Exp $ */ | /* $OpenBSD: channels.c,v 1.402 2020/09/20 05:47:25 djm Exp $ */ | ||||
/* | /* | ||||
* Author: Tatu Ylonen <ylo@cs.hut.fi> | * Author: Tatu Ylonen <ylo@cs.hut.fi> | ||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | ||||
* All rights reserved | * All rights reserved | ||||
* This file contains functions for generic socket connection forwarding. | * This file contains functions for generic socket connection forwarding. | ||||
* There is also code for initiating connection forwarding for X11 connections, | * There is also code for initiating connection forwarding for X11 connections, | ||||
* arbitrary tcp/ip connections, and the authentication agent connection. | * arbitrary tcp/ip connections, and the authentication agent connection. | ||||
* | * | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | |||||
#include <arpa/inet.h> | #include <arpa/inet.h> | ||||
#include <errno.h> | #include <errno.h> | ||||
#include <fcntl.h> | #include <fcntl.h> | ||||
#include <limits.h> | #include <limits.h> | ||||
#include <netdb.h> | #include <netdb.h> | ||||
#include <stdarg.h> | #include <stdarg.h> | ||||
#ifdef HAVE_STDINT_H | #ifdef HAVE_STDINT_H | ||||
#include <stdint.h> | # include <stdint.h> | ||||
#endif | #endif | ||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <termios.h> | #include <termios.h> | ||||
#include <unistd.h> | #include <unistd.h> | ||||
#include "openbsd-compat/sys-queue.h" | #include "openbsd-compat/sys-queue.h" | ||||
▲ Show 20 Lines • Show All 278 Lines • ▼ Show 20 Lines | |||||
*/ | */ | ||||
Channel * | Channel * | ||||
channel_new(struct ssh *ssh, char *ctype, int type, int rfd, int wfd, int efd, | channel_new(struct ssh *ssh, char *ctype, int type, int rfd, int wfd, int efd, | ||||
u_int window, u_int maxpack, int extusage, char *remote_name, int nonblock) | u_int window, u_int maxpack, int extusage, char *remote_name, int nonblock) | ||||
{ | { | ||||
struct ssh_channels *sc = ssh->chanctxt; | struct ssh_channels *sc = ssh->chanctxt; | ||||
u_int i, found; | u_int i, found; | ||||
Channel *c; | Channel *c; | ||||
int r; | |||||
/* Try to find a free slot where to put the new channel. */ | /* Try to find a free slot where to put the new channel. */ | ||||
for (i = 0; i < sc->channels_alloc; i++) { | for (i = 0; i < sc->channels_alloc; i++) { | ||||
if (sc->channels[i] == NULL) { | if (sc->channels[i] == NULL) { | ||||
/* Found a free slot. */ | /* Found a free slot. */ | ||||
found = i; | found = i; | ||||
break; | break; | ||||
} | } | ||||
Show All 13 Lines | if (i >= sc->channels_alloc) { | ||||
debug2("channel: expanding %d", sc->channels_alloc); | debug2("channel: expanding %d", sc->channels_alloc); | ||||
} | } | ||||
/* Initialize and return new channel. */ | /* Initialize and return new channel. */ | ||||
c = sc->channels[found] = xcalloc(1, sizeof(Channel)); | c = sc->channels[found] = xcalloc(1, sizeof(Channel)); | ||||
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("%s: sshbuf_new failed", __func__); | ||||
if ((r = sshbuf_set_max_size(c->input, CHAN_INPUT_MAX)) != 0) | |||||
fatal("%s: sshbuf_set_max_size: %s", __func__, ssh_err(r)); | |||||
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); | ||||
c->self = found; | c->self = found; | ||||
c->type = type; | c->type = type; | ||||
c->ctype = ctype; | c->ctype = ctype; | ||||
c->local_window = window; | c->local_window = window; | ||||
c->local_window_max = window; | c->local_window_max = window; | ||||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
static void | static void | ||||
fwd_perm_clear(struct permission *perm) | fwd_perm_clear(struct permission *perm) | ||||
{ | { | ||||
free(perm->host_to_connect); | free(perm->host_to_connect); | ||||
free(perm->listen_host); | free(perm->listen_host); | ||||
free(perm->listen_path); | free(perm->listen_path); | ||||
bzero(perm, sizeof(*perm)); | memset(perm, 0, sizeof(*perm)); | ||||
} | } | ||||
/* Returns an printable name for the specified forwarding permission list */ | /* Returns an printable name for the specified forwarding permission list */ | ||||
static const char * | static const char * | ||||
fwd_ident(int who, int where) | fwd_ident(int who, int where) | ||||
{ | { | ||||
if (who == FORWARD_ADM) { | if (who == FORWARD_ADM) { | ||||
if (where == FORWARD_LOCAL) | if (where == FORWARD_LOCAL) | ||||
Show All 22 Lines | permission_set_get(struct ssh *ssh, int where) | ||||
case FORWARD_REMOTE: | case FORWARD_REMOTE: | ||||
return &sc->remote_perms; | return &sc->remote_perms; | ||||
break; | break; | ||||
default: | default: | ||||
fatal("%s: invalid forwarding direction %d", __func__, where); | fatal("%s: invalid forwarding direction %d", __func__, where); | ||||
} | } | ||||
} | } | ||||
/* Reutrns pointers to the specified forwarding list and its element count */ | /* Returns pointers to the specified forwarding list and its element count */ | ||||
static void | static void | ||||
permission_set_get_array(struct ssh *ssh, int who, int where, | permission_set_get_array(struct ssh *ssh, int who, int where, | ||||
struct permission ***permpp, u_int **npermpp) | struct permission ***permpp, u_int **npermpp) | ||||
{ | { | ||||
struct permission_set *pset = permission_set_get(ssh, where); | struct permission_set *pset = permission_set_get(ssh, where); | ||||
switch (who) { | switch (who) { | ||||
case FORWARD_USER: | case FORWARD_USER: | ||||
▲ Show 20 Lines • Show All 93 Lines • ▼ Show 20 Lines | if (c->type == SSH_CHANNEL_MUX_CLIENT && | ||||
other->ostate = CHAN_OUTPUT_CLOSED; | other->ostate = CHAN_OUTPUT_CLOSED; | ||||
} | } | ||||
} | } | ||||
debug("channel %d: free: %s, nchannels %u", c->self, | debug("channel %d: free: %s, nchannels %u", c->self, | ||||
c->remote_name ? c->remote_name : "???", n); | c->remote_name ? c->remote_name : "???", n); | ||||
if (c->type == SSH_CHANNEL_MUX_CLIENT) | if (c->type == SSH_CHANNEL_MUX_CLIENT) | ||||
mux_remove_remote_forwardings(ssh, c); | mux_remove_remote_forwardings(ssh, c); | ||||
else if (c->type == SSH_CHANNEL_MUX_LISTENER) { | |||||
free(c->mux_ctx); | |||||
c->mux_ctx = NULL; | |||||
} | |||||
if (log_level_get() >= SYSLOG_LEVEL_DEBUG3) { | if (log_level_get() >= SYSLOG_LEVEL_DEBUG3) { | ||||
s = channel_open_message(ssh); | s = channel_open_message(ssh); | ||||
debug3("channel %d: status: %s", c->self, s); | debug3("channel %d: status: %s", c->self, s); | ||||
free(s); | free(s); | ||||
} | } | ||||
channel_close_fds(ssh, c); | channel_close_fds(ssh, c); | ||||
sshbuf_free(c->input); | sshbuf_free(c->input); | ||||
sshbuf_free(c->output); | sshbuf_free(c->output); | ||||
sshbuf_free(c->extended); | sshbuf_free(c->extended); | ||||
c->input = c->output = c->extended = NULL; | c->input = c->output = c->extended = NULL; | ||||
free(c->remote_name); | free(c->remote_name); | ||||
c->remote_name = NULL; | c->remote_name = NULL; | ||||
free(c->path); | free(c->path); | ||||
c->path = NULL; | c->path = NULL; | ||||
free(c->listening_addr); | free(c->listening_addr); | ||||
c->listening_addr = NULL; | c->listening_addr = NULL; | ||||
while ((cc = TAILQ_FIRST(&c->status_confirms)) != NULL) { | while ((cc = TAILQ_FIRST(&c->status_confirms)) != NULL) { | ||||
if (cc->abandon_cb != NULL) | if (cc->abandon_cb != NULL) | ||||
cc->abandon_cb(ssh, c, cc->ctx); | cc->abandon_cb(ssh, c, cc->ctx); | ||||
TAILQ_REMOVE(&c->status_confirms, cc, entry); | TAILQ_REMOVE(&c->status_confirms, cc, entry); | ||||
explicit_bzero(cc, sizeof(*cc)); | freezero(cc, sizeof(*cc)); | ||||
free(cc); | |||||
} | } | ||||
if (c->filter_cleanup != NULL && c->filter_ctx != NULL) | if (c->filter_cleanup != NULL && c->filter_ctx != NULL) | ||||
c->filter_cleanup(ssh, c->self, c->filter_ctx); | c->filter_cleanup(ssh, c->self, c->filter_ctx); | ||||
sc->channels[c->self] = NULL; | sc->channels[c->self] = NULL; | ||||
explicit_bzero(c, sizeof(*c)); | freezero(c, sizeof(*c)); | ||||
free(c); | |||||
} | } | ||||
void | void | ||||
channel_free_all(struct ssh *ssh) | channel_free_all(struct ssh *ssh) | ||||
{ | { | ||||
u_int i; | u_int i; | ||||
struct ssh_channels *sc = ssh->chanctxt; | |||||
for (i = 0; i < ssh->chanctxt->channels_alloc; i++) | for (i = 0; i < sc->channels_alloc; i++) | ||||
if (ssh->chanctxt->channels[i] != NULL) | if (sc->channels[i] != NULL) | ||||
channel_free(ssh, ssh->chanctxt->channels[i]); | channel_free(ssh, sc->channels[i]); | ||||
free(sc->channels); | |||||
sc->channels = NULL; | |||||
sc->channels_alloc = 0; | |||||
sc->channel_max_fd = 0; | |||||
free(sc->x11_saved_display); | |||||
sc->x11_saved_display = NULL; | |||||
free(sc->x11_saved_proto); | |||||
sc->x11_saved_proto = NULL; | |||||
free(sc->x11_saved_data); | |||||
sc->x11_saved_data = NULL; | |||||
sc->x11_saved_data_len = 0; | |||||
free(sc->x11_fake_data); | |||||
sc->x11_fake_data = NULL; | |||||
sc->x11_fake_data_len = 0; | |||||
} | } | ||||
/* | /* | ||||
* Closes the sockets/fds of all channels. This is used to close extra file | * Closes the sockets/fds of all channels. This is used to close extra file | ||||
* descriptors after a fork. | * descriptors after a fork. | ||||
*/ | */ | ||||
void | void | ||||
channel_close_all(struct ssh *ssh) | channel_close_all(struct ssh *ssh) | ||||
▲ Show 20 Lines • Show All 992 Lines • ▼ Show 20 Lines | channel_post_x11_listener(struct ssh *ssh, Channel *c, | ||||
newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen); | newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen); | ||||
if (c->single_connection) { | if (c->single_connection) { | ||||
oerrno = errno; | oerrno = errno; | ||||
debug2("single_connection: closing X11 listener."); | debug2("single_connection: closing X11 listener."); | ||||
channel_close_fd(ssh, &c->sock); | channel_close_fd(ssh, &c->sock); | ||||
chan_mark_dead(ssh, c); | chan_mark_dead(ssh, c); | ||||
errno = oerrno; | errno = oerrno; | ||||
} | } | ||||
if (newsock < 0) { | if (newsock == -1) { | ||||
if (errno != EINTR && errno != EWOULDBLOCK && | if (errno != EINTR && errno != EWOULDBLOCK && | ||||
errno != ECONNABORTED) | errno != ECONNABORTED) | ||||
error("accept: %.100s", strerror(errno)); | error("accept: %.100s", strerror(errno)); | ||||
if (errno == EMFILE || errno == ENFILE) | if (errno == EMFILE || errno == ENFILE) | ||||
c->notbefore = monotime() + 1; | c->notbefore = monotime() + 1; | ||||
return; | return; | ||||
} | } | ||||
set_nodelay(newsock); | set_nodelay(newsock); | ||||
▲ Show 20 Lines • Show All 126 Lines • ▼ Show 20 Lines | if (c->type == SSH_CHANNEL_RPORT_LISTENER) { | ||||
rtype = "dynamic-tcpip"; | rtype = "dynamic-tcpip"; | ||||
} else { | } else { | ||||
nextstate = SSH_CHANNEL_OPENING; | nextstate = SSH_CHANNEL_OPENING; | ||||
rtype = "direct-tcpip"; | rtype = "direct-tcpip"; | ||||
} | } | ||||
addrlen = sizeof(addr); | addrlen = sizeof(addr); | ||||
newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen); | newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen); | ||||
if (newsock < 0) { | if (newsock == -1) { | ||||
if (errno != EINTR && errno != EWOULDBLOCK && | if (errno != EINTR && errno != EWOULDBLOCK && | ||||
errno != ECONNABORTED) | errno != ECONNABORTED) | ||||
error("accept: %.100s", strerror(errno)); | error("accept: %.100s", strerror(errno)); | ||||
if (errno == EMFILE || errno == ENFILE) | if (errno == EMFILE || errno == ENFILE) | ||||
c->notbefore = monotime() + 1; | c->notbefore = monotime() + 1; | ||||
return; | return; | ||||
} | } | ||||
if (c->host_port != PORT_STREAMLOCAL) | if (c->host_port != PORT_STREAMLOCAL) | ||||
Show All 22 Lines | channel_post_auth_listener(struct ssh *ssh, Channel *c, | ||||
struct sockaddr_storage addr; | struct sockaddr_storage addr; | ||||
socklen_t addrlen; | socklen_t addrlen; | ||||
if (!FD_ISSET(c->sock, readset)) | if (!FD_ISSET(c->sock, readset)) | ||||
return; | return; | ||||
addrlen = sizeof(addr); | addrlen = sizeof(addr); | ||||
newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen); | newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen); | ||||
if (newsock < 0) { | if (newsock == -1) { | ||||
error("accept from auth socket: %.100s", strerror(errno)); | error("accept from auth socket: %.100s", strerror(errno)); | ||||
if (errno == EMFILE || errno == ENFILE) | if (errno == EMFILE || errno == ENFILE) | ||||
c->notbefore = monotime() + 1; | c->notbefore = monotime() + 1; | ||||
return; | return; | ||||
} | } | ||||
nc = channel_new(ssh, "accepted auth socket", | nc = channel_new(ssh, "accepted auth socket", | ||||
SSH_CHANNEL_OPENING, newsock, newsock, -1, | SSH_CHANNEL_OPENING, newsock, newsock, -1, | ||||
c->local_window_max, c->local_maxpacket, | c->local_window_max, c->local_maxpacket, | ||||
Show All 11 Lines | channel_post_connecting(struct ssh *ssh, Channel *c, | ||||
socklen_t sz = sizeof(err); | socklen_t sz = sizeof(err); | ||||
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(":%s: channel %d: no remote id", __func__, 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) < 0) { | if (getsockopt(c->sock, SOL_SOCKET, SO_ERROR, &err, &sz) == -1) { | ||||
err = errno; | err = errno; | ||||
error("getsockopt SO_ERROR failed"); | error("getsockopt SO_ERROR failed"); | ||||
} | } | ||||
if (err == 0) { | if (err == 0) { | ||||
debug("channel %d: connected to %s port %d", | debug("channel %d: connected to %s port %d", | ||||
c->self, c->connect_ctx.host, c->connect_ctx.port); | c->self, c->connect_ctx.host, c->connect_ctx.port); | ||||
channel_connect_ctx_free(&c->connect_ctx); | channel_connect_ctx_free(&c->connect_ctx); | ||||
c->type = SSH_CHANNEL_OPEN; | c->type = SSH_CHANNEL_OPEN; | ||||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | channel_handle_rfd(struct ssh *ssh, Channel *c, | ||||
force = c->isatty && c->detach_close && c->istate != CHAN_INPUT_CLOSED; | force = c->isatty && c->detach_close && c->istate != CHAN_INPUT_CLOSED; | ||||
if (c->rfd == -1 || (!force && !FD_ISSET(c->rfd, readset))) | if (c->rfd == -1 || (!force && !FD_ISSET(c->rfd, readset))) | ||||
return 1; | return 1; | ||||
errno = 0; | errno = 0; | ||||
len = read(c->rfd, buf, sizeof(buf)); | len = read(c->rfd, buf, sizeof(buf)); | ||||
if (len < 0 && (errno == EINTR || | if (len == -1 && (errno == EINTR || | ||||
((errno == EAGAIN || errno == EWOULDBLOCK) && !force))) | ((errno == EAGAIN || errno == EWOULDBLOCK) && !force))) | ||||
return 1; | return 1; | ||||
#ifndef PTY_ZEROREAD | #ifndef PTY_ZEROREAD | ||||
if (len <= 0) { | if (len <= 0) { | ||||
#else | #else | ||||
if ((!c->isatty && len <= 0) || | if ((!c->isatty && len <= 0) || | ||||
(c->isatty && (len < 0 || (len == 0 && errno != 0)))) { | (c->isatty && (len < 0 || (len == 0 && errno != 0)))) { | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | if (c->output_filter != NULL) { | ||||
buf = data = sshbuf_mutable_ptr(c->output); | buf = data = sshbuf_mutable_ptr(c->output); | ||||
dlen = sshbuf_len(c->output); | dlen = sshbuf_len(c->output); | ||||
} | } | ||||
if (c->datagram) { | if (c->datagram) { | ||||
/* ignore truncated writes, datagrams might get lost */ | /* ignore truncated writes, datagrams might get lost */ | ||||
len = write(c->wfd, buf, dlen); | len = write(c->wfd, buf, dlen); | ||||
free(data); | free(data); | ||||
if (len < 0 && (errno == EINTR || errno == EAGAIN || | if (len == -1 && (errno == EINTR || errno == EAGAIN || | ||||
errno == EWOULDBLOCK)) | errno == EWOULDBLOCK)) | ||||
return 1; | return 1; | ||||
if (len <= 0) | if (len <= 0) | ||||
goto write_fail; | goto write_fail; | ||||
goto out; | goto out; | ||||
} | } | ||||
#ifdef _AIX | #ifdef _AIX | ||||
/* XXX: Later AIX versions can't push as much data to tty */ | /* XXX: Later AIX versions can't push as much data to tty */ | ||||
if (c->wfd_isatty) | if (c->wfd_isatty) | ||||
dlen = MIN(dlen, 8*1024); | dlen = MIN(dlen, 8*1024); | ||||
#endif | #endif | ||||
len = write(c->wfd, buf, dlen); | len = write(c->wfd, buf, dlen); | ||||
if (len < 0 && | if (len == -1 && | ||||
(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)) | (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)) | ||||
return 1; | return 1; | ||||
if (len <= 0) { | if (len <= 0) { | ||||
write_fail: | write_fail: | ||||
if (c->type != SSH_CHANNEL_OPEN) { | if (c->type != SSH_CHANNEL_OPEN) { | ||||
debug2("channel %d: not open", c->self); | debug2("channel %d: not open", c->self); | ||||
chan_mark_dead(ssh, c); | chan_mark_dead(ssh, c); | ||||
return -1; | return -1; | ||||
Show All 37 Lines | channel_handle_efd_write(struct ssh *ssh, Channel *c, | ||||
ssize_t len; | ssize_t len; | ||||
if (!FD_ISSET(c->efd, writeset) || sshbuf_len(c->extended) == 0) | if (!FD_ISSET(c->efd, writeset) || sshbuf_len(c->extended) == 0) | ||||
return 1; | return 1; | ||||
len = write(c->efd, sshbuf_ptr(c->extended), | len = write(c->efd, sshbuf_ptr(c->extended), | ||||
sshbuf_len(c->extended)); | sshbuf_len(c->extended)); | ||||
debug2("channel %d: written %zd to efd %d", c->self, len, c->efd); | debug2("channel %d: written %zd to efd %d", c->self, len, c->efd); | ||||
if (len < 0 && (errno == EINTR || errno == EAGAIN || | if (len == -1 && (errno == EINTR || errno == EAGAIN || | ||||
errno == EWOULDBLOCK)) | errno == EWOULDBLOCK)) | ||||
return 1; | return 1; | ||||
if (len <= 0) { | if (len <= 0) { | ||||
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("%s: channel %d: consume: %s", | ||||
Show All 14 Lines | channel_handle_efd_read(struct ssh *ssh, Channel *c, | ||||
force = c->isatty && c->detach_close && c->istate != CHAN_INPUT_CLOSED; | force = c->isatty && c->detach_close && c->istate != CHAN_INPUT_CLOSED; | ||||
if (c->efd == -1 || (!force && !FD_ISSET(c->efd, readset))) | if (c->efd == -1 || (!force && !FD_ISSET(c->efd, readset))) | ||||
return 1; | return 1; | ||||
len = read(c->efd, buf, sizeof(buf)); | len = read(c->efd, buf, sizeof(buf)); | ||||
debug2("channel %d: read %zd from efd %d", c->self, len, c->efd); | debug2("channel %d: read %zd from efd %d", c->self, len, c->efd); | ||||
if (len < 0 && (errno == EINTR || ((errno == EAGAIN || | if (len == -1 && (errno == EINTR || ((errno == EAGAIN || | ||||
errno == EWOULDBLOCK) && !force))) | errno == EWOULDBLOCK) && !force))) | ||||
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) { | ||||
▲ Show 20 Lines • Show All 72 Lines • ▼ Show 20 Lines | read_mux(struct ssh *ssh, Channel *c, u_int need) | ||||
char buf[CHAN_RBUF]; | char buf[CHAN_RBUF]; | ||||
ssize_t len; | ssize_t len; | ||||
u_int rlen; | u_int rlen; | ||||
int r; | int r; | ||||
if (sshbuf_len(c->input) < need) { | if (sshbuf_len(c->input) < need) { | ||||
rlen = need - sshbuf_len(c->input); | rlen = need - sshbuf_len(c->input); | ||||
len = read(c->rfd, buf, MINIMUM(rlen, CHAN_RBUF)); | len = read(c->rfd, buf, MINIMUM(rlen, CHAN_RBUF)); | ||||
if (len < 0 && (errno == EINTR || errno == EAGAIN)) | if (len == -1 && (errno == EINTR || errno == EAGAIN)) | ||||
return sshbuf_len(c->input); | return sshbuf_len(c->input); | ||||
if (len <= 0) { | if (len <= 0) { | ||||
debug2("channel %d: ctl read<=0 rfd %d len %zd", | debug2("channel %d: ctl read<=0 rfd %d len %zd", | ||||
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("%s: channel %d: append: %s", | ||||
▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | channel_post_mux_client_write(struct ssh *ssh, Channel *c, | ||||
ssize_t len; | ssize_t len; | ||||
int r; | int r; | ||||
if (c->wfd == -1 || !FD_ISSET(c->wfd, writeset) || | if (c->wfd == -1 || !FD_ISSET(c->wfd, writeset) || | ||||
sshbuf_len(c->output) == 0) | sshbuf_len(c->output) == 0) | ||||
return; | return; | ||||
len = write(c->wfd, sshbuf_ptr(c->output), sshbuf_len(c->output)); | len = write(c->wfd, sshbuf_ptr(c->output), sshbuf_len(c->output)); | ||||
if (len < 0 && (errno == EINTR || errno == EAGAIN)) | if (len == -1 && (errno == EINTR || errno == EAGAIN)) | ||||
return; | return; | ||||
if (len <= 0) { | if (len <= 0) { | ||||
chan_mark_dead(ssh, c); | chan_mark_dead(ssh, c); | ||||
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("%s: channel %d: consume: %s", __func__, | ||||
c->self, ssh_err(r)); | c->self, ssh_err(r)); | ||||
Show All 31 Lines | channel_post_mux_listener(struct ssh *ssh, Channel *c, | ||||
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("%s accept: %s", __func__, 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) < 0) { | if (getpeereid(newsock, &euid, &egid) == -1) { | ||||
error("%s getpeereid failed: %s", __func__, | error("%s getpeereid failed: %s", __func__, | ||||
strerror(errno)); | strerror(errno)); | ||||
close(newsock); | close(newsock); | ||||
return; | return; | ||||
} | } | ||||
if ((euid != 0) && (getuid() != euid)) { | if ((euid != 0) && (getuid() != euid)) { | ||||
error("multiplex uid mismatch: peer euid %u != uid %u", | error("multiplex uid mismatch: peer euid %u != uid %u", | ||||
(u_int)euid, (u_int)getuid()); | (u_int)euid, (u_int)getuid()); | ||||
▲ Show 20 Lines • Show All 929 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
int | int | ||||
channel_input_status_confirm(int type, u_int32_t seq, struct ssh *ssh) | channel_input_status_confirm(int type, u_int32_t seq, struct ssh *ssh) | ||||
{ | { | ||||
int id = channel_parse_id(ssh, __func__, "status confirm"); | int id = channel_parse_id(ssh, __func__, "status confirm"); | ||||
Channel *c; | Channel *c; | ||||
struct channel_confirm *cc; | struct channel_confirm *cc; | ||||
int r; | |||||
/* 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("%s: type %d id %d", __func__, type, id); | ||||
if ((c = channel_lookup(ssh, id)) == NULL) { | if ((c = channel_lookup(ssh, id)) == NULL) { | ||||
logit("%s: %d: unknown", __func__, id); | logit("%s: %d: unknown", __func__, id); | ||||
return 0; | return 0; | ||||
} | } | ||||
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 (sshpkt_get_end(ssh) != 0) | ||||
ssh_packet_disconnect(ssh, "Invalid status confirm message"); | ssh_packet_disconnect(ssh, "Invalid status confirm message"); | ||||
if ((cc = TAILQ_FIRST(&c->status_confirms)) == NULL) | if ((cc = TAILQ_FIRST(&c->status_confirms)) == NULL) | ||||
return 0; | return 0; | ||||
cc->cb(ssh, type, c, cc->ctx); | cc->cb(ssh, type, c, cc->ctx); | ||||
TAILQ_REMOVE(&c->status_confirms, cc, entry); | TAILQ_REMOVE(&c->status_confirms, cc, entry); | ||||
explicit_bzero(cc, sizeof(*cc)); | freezero(cc, sizeof(*cc)); | ||||
free(cc); | |||||
return 0; | return 0; | ||||
} | } | ||||
/* -- tcp forwarding */ | /* -- tcp forwarding */ | ||||
void | void | ||||
channel_set_af(struct ssh *ssh, int af) | channel_set_af(struct ssh *ssh, int af) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | if (((datafellows & SSH_OLD_FORWARD_ADDR) && | ||||
ssh_packet_send_debug(ssh, | ssh_packet_send_debug(ssh, | ||||
"Forwarding listen address " | "Forwarding listen address " | ||||
"\"%s\" overridden by server " | "\"%s\" overridden by server " | ||||
"GatewayPorts", listen_addr); | "GatewayPorts", listen_addr); | ||||
} | } | ||||
} else if (strcmp(listen_addr, "localhost") != 0 || | } else if (strcmp(listen_addr, "localhost") != 0 || | ||||
strcmp(listen_addr, "127.0.0.1") == 0 || | strcmp(listen_addr, "127.0.0.1") == 0 || | ||||
strcmp(listen_addr, "::1") == 0) { | strcmp(listen_addr, "::1") == 0) { | ||||
/* Accept localhost address when GatewayPorts=yes */ | /* | ||||
* Accept explicit localhost address when | |||||
* GatewayPorts=yes. The "localhost" hostname is | |||||
* deliberately skipped here so it will listen on all | |||||
* available local address families. | |||||
*/ | |||||
addr = listen_addr; | addr = listen_addr; | ||||
} | } | ||||
} else if (strcmp(listen_addr, "127.0.0.1") == 0 || | } else if (strcmp(listen_addr, "127.0.0.1") == 0 || | ||||
strcmp(listen_addr, "::1") == 0) { | strcmp(listen_addr, "::1") == 0) { | ||||
/* | /* | ||||
* If a specific IPv4/IPv6 localhost address has been | * If a specific IPv4/IPv6 localhost address has been | ||||
* requested then accept it even if gateway_ports is in | * requested then accept it even if gateway_ports is in | ||||
* effect. This allows the client to prefer IPv4 or IPv6. | * effect. This allows the client to prefer IPv4 or IPv6. | ||||
▲ Show 20 Lines • Show All 87 Lines • ▼ Show 20 Lines | for (ai = aitop; ai; ai = ai->ai_next) { | ||||
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("%s: getnameinfo failed", __func__); | ||||
continue; | continue; | ||||
} | } | ||||
/* Create a port to listen for the host. */ | /* Create a port to listen for the host. */ | ||||
sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); | sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); | ||||
if (sock < 0) { | if (sock == -1) { | ||||
/* this is no error since kernel may not support ipv6 */ | /* this is no error since kernel may not support ipv6 */ | ||||
verbose("socket [%s]:%s: %.100s", ntop, strport, | verbose("socket [%s]:%s: %.100s", ntop, strport, | ||||
strerror(errno)); | strerror(errno)); | ||||
continue; | continue; | ||||
} | } | ||||
set_reuseaddr(sock); | set_reuseaddr(sock); | ||||
if (ai->ai_family == AF_INET6) | if (ai->ai_family == AF_INET6) | ||||
sock_set_v6only(sock); | sock_set_v6only(sock); | ||||
debug("Local forwarding listening on %s port %s.", | debug("Local forwarding listening on %s port %s.", | ||||
ntop, strport); | ntop, strport); | ||||
/* Bind the socket to the address. */ | /* Bind the socket to the address. */ | ||||
if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { | if (bind(sock, ai->ai_addr, ai->ai_addrlen) == -1) { | ||||
/* | /* | ||||
* address can be in if use ipv6 address is | * address can be in if use ipv6 address is | ||||
* already bound | * already bound | ||||
*/ | */ | ||||
if (!ai->ai_next) | if (!ai->ai_next) | ||||
error("bind [%s]:%s: %.100s", | error("bind [%s]:%s: %.100s", | ||||
ntop, strport, strerror(errno)); | ntop, strport, strerror(errno)); | ||||
else | else | ||||
verbose("bind [%s]:%s: %.100s", | verbose("bind [%s]:%s: %.100s", | ||||
ntop, strport, strerror(errno)); | ntop, strport, strerror(errno)); | ||||
close(sock); | close(sock); | ||||
continue; | continue; | ||||
} | } | ||||
/* Start listening for connections on the socket. */ | /* Start listening for connections on the socket. */ | ||||
if (listen(sock, SSH_LISTEN_BACKLOG) < 0) { | if (listen(sock, SSH_LISTEN_BACKLOG) == -1) { | ||||
error("listen: %.100s", strerror(errno)); | error("listen: %.100s", strerror(errno)); | ||||
error("listen [%s]:%s: %.100s", ntop, strport, | error("listen [%s]:%s: %.100s", ntop, strport, | ||||
strerror(errno)); | strerror(errno)); | ||||
close(sock); | close(sock); | ||||
continue; | continue; | ||||
} | } | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 314 Lines • ▼ Show 20 Lines | |||||
/* protocol v2 remote port fwd, used by sshd */ | /* protocol v2 remote port fwd, used by sshd */ | ||||
int | int | ||||
channel_setup_remote_fwd_listener(struct ssh *ssh, struct Forward *fwd, | channel_setup_remote_fwd_listener(struct ssh *ssh, struct Forward *fwd, | ||||
int *allocated_listen_port, struct ForwardOptions *fwd_opts) | int *allocated_listen_port, struct ForwardOptions *fwd_opts) | ||||
{ | { | ||||
if (!check_rfwd_permission(ssh, fwd)) { | if (!check_rfwd_permission(ssh, fwd)) { | ||||
ssh_packet_send_debug(ssh, "port forwarding refused"); | ssh_packet_send_debug(ssh, "port forwarding refused"); | ||||
if (fwd->listen_path != NULL) | |||||
/* XXX always allowed, see remote_open_match() */ | |||||
logit("Received request from %.100s port %d to " | |||||
"remote forward to path \"%.100s\", " | |||||
"but the request was denied.", | |||||
ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), | |||||
fwd->listen_path); | |||||
else if(fwd->listen_host != NULL) | |||||
logit("Received request from %.100s port %d to " | |||||
"remote forward to host %.100s port %d, " | |||||
"but the request was denied.", | |||||
ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), | |||||
fwd->listen_host, fwd->listen_port ); | |||||
else | |||||
logit("Received request from %.100s port %d to remote " | |||||
"forward, but the request was denied.", | |||||
ssh_remote_ipaddr(ssh), ssh_remote_port(ssh)); | |||||
return 0; | return 0; | ||||
} | } | ||||
if (fwd->listen_path != NULL) { | if (fwd->listen_path != NULL) { | ||||
return channel_setup_fwd_listener_streamlocal(ssh, | return channel_setup_fwd_listener_streamlocal(ssh, | ||||
SSH_CHANNEL_RUNIX_LISTENER, fwd, fwd_opts); | SSH_CHANNEL_RUNIX_LISTENER, fwd, fwd_opts); | ||||
} else { | } else { | ||||
return channel_setup_fwd_listener_tcpip(ssh, | return channel_setup_fwd_listener_tcpip(ssh, | ||||
SSH_CHANNEL_RPORT_LISTENER, fwd, allocated_listen_port, | SSH_CHANNEL_RPORT_LISTENER, fwd, allocated_listen_port, | ||||
▲ Show 20 Lines • Show All 144 Lines • ▼ Show 20 Lines | |||||
static int | static int | ||||
channel_request_rforward_cancel_tcpip(struct ssh *ssh, | channel_request_rforward_cancel_tcpip(struct ssh *ssh, | ||||
const char *host, u_short port) | const char *host, u_short port) | ||||
{ | { | ||||
struct ssh_channels *sc = ssh->chanctxt; | struct ssh_channels *sc = ssh->chanctxt; | ||||
struct permission_set *pset = &sc->local_perms; | struct permission_set *pset = &sc->local_perms; | ||||
int r; | int r; | ||||
u_int i; | u_int i; | ||||
struct permission *perm; | struct permission *perm = NULL; | ||||
for (i = 0; i < pset->num_permitted_user; i++) { | for (i = 0; i < pset->num_permitted_user; i++) { | ||||
perm = &pset->permitted_user[i]; | perm = &pset->permitted_user[i]; | ||||
if (open_listen_match_tcpip(perm, host, port, 0)) | if (open_listen_match_tcpip(perm, host, port, 0)) | ||||
break; | break; | ||||
perm = NULL; | perm = NULL; | ||||
} | } | ||||
if (perm == NULL) { | if (perm == NULL) { | ||||
Show All 19 Lines | |||||
*/ | */ | ||||
static int | static int | ||||
channel_request_rforward_cancel_streamlocal(struct ssh *ssh, const char *path) | channel_request_rforward_cancel_streamlocal(struct ssh *ssh, const char *path) | ||||
{ | { | ||||
struct ssh_channels *sc = ssh->chanctxt; | struct ssh_channels *sc = ssh->chanctxt; | ||||
struct permission_set *pset = &sc->local_perms; | struct permission_set *pset = &sc->local_perms; | ||||
int r; | int r; | ||||
u_int i; | u_int i; | ||||
struct permission *perm; | struct permission *perm = NULL; | ||||
for (i = 0; i < pset->num_permitted_user; i++) { | for (i = 0; i < pset->num_permitted_user; i++) { | ||||
perm = &pset->permitted_user[i]; | perm = &pset->permitted_user[i]; | ||||
if (open_listen_match_streamlocal(perm, path)) | if (open_listen_match_streamlocal(perm, path)) | ||||
break; | break; | ||||
perm = NULL; | perm = NULL; | ||||
} | } | ||||
if (perm == NULL) { | if (perm == NULL) { | ||||
▲ Show 20 Lines • Show All 382 Lines • ▼ Show 20 Lines | for (i = 0; i < pset->num_permitted_admin; i++) { | ||||
if (open_match(perm, host, port)) { | if (open_match(perm, host, port)) { | ||||
permit_adm = 1; | permit_adm = 1; | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
if (!permit || !permit_adm) { | if (!permit || !permit_adm) { | ||||
logit("Received request to connect to host %.100s port %d, " | logit("Received request from %.100s port %d to connect to " | ||||
"but the request was denied.", host, port); | "host %.100s port %d, but the request was denied.", | ||||
ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), host, port); | |||||
if (reason != NULL) | if (reason != NULL) | ||||
*reason = SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED; | *reason = SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED; | ||||
return NULL; | return NULL; | ||||
} | } | ||||
memset(&cctx, 0, sizeof(cctx)); | memset(&cctx, 0, sizeof(cctx)); | ||||
sock = connect_to_helper(ssh, host, port, SOCK_STREAM, ctype, rname, | sock = connect_to_helper(ssh, host, port, SOCK_STREAM, ctype, rname, | ||||
&cctx, reason, errmsg); | &cctx, reason, errmsg); | ||||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | channel_send_window_changes(struct ssh *ssh) | ||||
struct winsize ws; | struct winsize ws; | ||||
int r; | int r; | ||||
u_int i; | u_int i; | ||||
for (i = 0; i < sc->channels_alloc; i++) { | for (i = 0; i < sc->channels_alloc; i++) { | ||||
if (sc->channels[i] == NULL || !sc->channels[i]->client_tty || | if (sc->channels[i] == NULL || !sc->channels[i]->client_tty || | ||||
sc->channels[i]->type != SSH_CHANNEL_OPEN) | sc->channels[i]->type != SSH_CHANNEL_OPEN) | ||||
continue; | continue; | ||||
if (ioctl(sc->channels[i]->rfd, TIOCGWINSZ, &ws) < 0) | if (ioctl(sc->channels[i]->rfd, TIOCGWINSZ, &ws) == -1) | ||||
continue; | continue; | ||||
channel_request_start(ssh, i, "window-change", 0); | channel_request_start(ssh, i, "window-change", 0); | ||||
if ((r = sshpkt_put_u32(ssh, (u_int)ws.ws_col)) != 0 || | if ((r = sshpkt_put_u32(ssh, (u_int)ws.ws_col)) != 0 || | ||||
(r = sshpkt_put_u32(ssh, (u_int)ws.ws_row)) != 0 || | (r = sshpkt_put_u32(ssh, (u_int)ws.ws_row)) != 0 || | ||||
(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("%s: channel %u: send window-change: %s", | ||||
▲ Show 20 Lines • Show All 86 Lines • ▼ Show 20 Lines | if ((gaierr = getaddrinfo(NULL, strport, | ||||
return -1; | return -1; | ||||
} | } | ||||
for (ai = aitop; ai; ai = ai->ai_next) { | for (ai = aitop; ai; ai = ai->ai_next) { | ||||
if (ai->ai_family != AF_INET && | if (ai->ai_family != AF_INET && | ||||
ai->ai_family != AF_INET6) | ai->ai_family != AF_INET6) | ||||
continue; | continue; | ||||
sock = socket(ai->ai_family, ai->ai_socktype, | sock = socket(ai->ai_family, ai->ai_socktype, | ||||
ai->ai_protocol); | ai->ai_protocol); | ||||
if (sock < 0) { | if (sock == -1) { | ||||
if ((errno != EINVAL) && (errno != EAFNOSUPPORT) | if ((errno != EINVAL) && (errno != EAFNOSUPPORT) | ||||
#ifdef EPFNOSUPPORT | #ifdef EPFNOSUPPORT | ||||
&& (errno != EPFNOSUPPORT) | && (errno != EPFNOSUPPORT) | ||||
#endif | #endif | ||||
) { | ) { | ||||
error("socket: %.100s", strerror(errno)); | error("socket: %.100s", strerror(errno)); | ||||
freeaddrinfo(aitop); | freeaddrinfo(aitop); | ||||
return -1; | return -1; | ||||
} else { | } else { | ||||
debug("x11_create_display_inet: Socket family %d not supported", | debug("x11_create_display_inet: Socket family %d not supported", | ||||
ai->ai_family); | ai->ai_family); | ||||
continue; | continue; | ||||
} | } | ||||
} | } | ||||
if (ai->ai_family == AF_INET6) | if (ai->ai_family == AF_INET6) | ||||
sock_set_v6only(sock); | sock_set_v6only(sock); | ||||
if (x11_use_localhost) | if (x11_use_localhost) | ||||
set_reuseaddr(sock); | set_reuseaddr(sock); | ||||
if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { | if (bind(sock, ai->ai_addr, ai->ai_addrlen) == -1) { | ||||
debug2("%s: bind port %d: %.100s", __func__, | debug2("%s: bind port %d: %.100s", __func__, | ||||
port, strerror(errno)); | port, 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]); | ||||
num_socks = 0; | num_socks = 0; | ||||
break; | break; | ||||
} | } | ||||
socks[num_socks++] = sock; | socks[num_socks++] = sock; | ||||
if (num_socks == NUM_SOCKS) | if (num_socks == NUM_SOCKS) | ||||
break; | break; | ||||
} | } | ||||
freeaddrinfo(aitop); | freeaddrinfo(aitop); | ||||
if (num_socks > 0) | if (num_socks > 0) | ||||
break; | break; | ||||
} | } | ||||
if (display_number >= MAX_DISPLAYS) { | if (display_number >= MAX_DISPLAYS) { | ||||
error("Failed to allocate internet-domain X11 display socket."); | error("Failed to allocate internet-domain X11 display socket."); | ||||
return -1; | return -1; | ||||
} | } | ||||
/* Start listening for connections on the socket. */ | /* Start listening for connections on the socket. */ | ||||
for (n = 0; n < num_socks; n++) { | for (n = 0; n < num_socks; n++) { | ||||
sock = socks[n]; | sock = socks[n]; | ||||
if (listen(sock, SSH_LISTEN_BACKLOG) < 0) { | if (listen(sock, SSH_LISTEN_BACKLOG) == -1) { | ||||
error("listen: %.100s", strerror(errno)); | error("listen: %.100s", strerror(errno)); | ||||
close(sock); | close(sock); | ||||
return -1; | return -1; | ||||
} | } | ||||
} | } | ||||
/* Allocate a channel for each socket. */ | /* Allocate a channel for each socket. */ | ||||
*chanids = xcalloc(num_socks + 1, sizeof(**chanids)); | *chanids = xcalloc(num_socks + 1, sizeof(**chanids)); | ||||
Show All 15 Lines | |||||
static int | static int | ||||
connect_local_xsocket_path(const char *pathname) | connect_local_xsocket_path(const char *pathname) | ||||
{ | { | ||||
int sock; | int sock; | ||||
struct sockaddr_un addr; | struct sockaddr_un addr; | ||||
sock = socket(AF_UNIX, SOCK_STREAM, 0); | sock = socket(AF_UNIX, SOCK_STREAM, 0); | ||||
if (sock < 0) | if (sock == -1) | ||||
error("socket: %.100s", strerror(errno)); | error("socket: %.100s", strerror(errno)); | ||||
memset(&addr, 0, sizeof(addr)); | memset(&addr, 0, sizeof(addr)); | ||||
addr.sun_family = AF_UNIX; | addr.sun_family = AF_UNIX; | ||||
strlcpy(addr.sun_path, pathname, sizeof addr.sun_path); | strlcpy(addr.sun_path, pathname, sizeof addr.sun_path); | ||||
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) | if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) | ||||
return sock; | return sock; | ||||
close(sock); | close(sock); | ||||
error("connect %.100s: %.100s", addr.sun_path, strerror(errno)); | error("connect %.100s: %.100s", addr.sun_path, strerror(errno)); | ||||
▲ Show 20 Lines • Show All 124 Lines • ▼ Show 20 Lines | #endif | ||||
if ((gaierr = getaddrinfo(buf, strport, &hints, &aitop)) != 0) { | if ((gaierr = getaddrinfo(buf, strport, &hints, &aitop)) != 0) { | ||||
error("%.100s: unknown host. (%s)", buf, | error("%.100s: unknown host. (%s)", buf, | ||||
ssh_gai_strerror(gaierr)); | ssh_gai_strerror(gaierr)); | ||||
return -1; | return -1; | ||||
} | } | ||||
for (ai = aitop; ai; ai = ai->ai_next) { | for (ai = aitop; ai; ai = ai->ai_next) { | ||||
/* Create a socket. */ | /* Create a socket. */ | ||||
sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); | sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); | ||||
if (sock < 0) { | if (sock == -1) { | ||||
debug2("socket: %.100s", strerror(errno)); | debug2("socket: %.100s", strerror(errno)); | ||||
continue; | continue; | ||||
} | } | ||||
/* Connect it to the display. */ | /* Connect it to the display. */ | ||||
if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) { | if (connect(sock, ai->ai_addr, ai->ai_addrlen) == -1) { | ||||
debug2("connect %.100s port %u: %.100s", buf, | debug2("connect %.100s port %u: %.100s", buf, | ||||
6000 + display_number, strerror(errno)); | 6000 + display_number, strerror(errno)); | ||||
close(sock); | close(sock); | ||||
continue; | continue; | ||||
} | } | ||||
/* Success */ | /* Success */ | ||||
break; | break; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 76 Lines • Show Last 20 Lines |