#define SSH2_MSG_USERAUTH_BANNER 53 /* 0x35 */
#define SSH2_MSG_USERAUTH_PK_OK 60 /* 0x3c */
#define SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ 60 /* 0x3c */
+#define SSH2_MSG_USERAUTH_INFO_REQUEST 60 /* 0x3c */
+#define SSH2_MSG_USERAUTH_INFO_RESPONSE 61 /* 0x3d */
#define SSH2_MSG_GLOBAL_REQUEST 80 /* 0x50 */
#define SSH2_MSG_REQUEST_SUCCESS 81 /* 0x51 */
#define SSH2_MSG_REQUEST_FAILURE 82 /* 0x52 */
extern void x11_send(Socket, char *, int);
extern void x11_invent_auth(char *, int, char *, int);
+extern char *pfd_newconnect(Socket * s, char *hostname, int port, void *c);
+extern char *pfd_addforward(char *desthost, int destport, int port);
+extern void pfd_close(Socket s);
+extern void pfd_send(Socket s, char *data, int len);
+extern void pfd_confirm(Socket s);
+
/*
* Ciphers for SSH2. We miss out single-DES because it isn't
* supported; also 3DES and Blowfish are both done differently from
CHAN_MAINSESSION,
CHAN_X11,
CHAN_AGENT,
+ CHAN_SOCKDATA,
+ CHAN_SOCKDATA_DORMANT /* one the remote hasn't confirmed */
};
/*
struct ssh_x11_channel {
Socket s;
} x11;
+ struct ssh_pfd_channel {
+ Socket s;
+ } pfd;
} u;
};
+/*
+ * 2-3-4 tree storing remote->local port forwardings. SSH 1 and SSH
+ * 2 use this structure in different ways, reflecting SSH 2's
+ * altogether saner approach to port forwarding.
+ *
+ * In SSH 1, you arrange a remote forwarding by sending the server
+ * the remote port number, and the local destination host:port.
+ * When a connection comes in, the server sends you back that
+ * host:port pair, and you connect to it. This is a ready-made
+ * security hole if you're not on the ball: a malicious server
+ * could send you back _any_ host:port pair, so if you trustingly
+ * connect to the address it gives you then you've just opened the
+ * entire inside of your corporate network just by connecting
+ * through it to a dodgy SSH server. Hence, we must store a list of
+ * host:port pairs we _are_ trying to forward to, and reject a
+ * connection request from the server if it's not in the list.
+ *
+ * In SSH 2, each side of the connection minds its own business and
+ * doesn't send unnecessary information to the other. You arrange a
+ * remote forwarding by sending the server just the remote port
+ * number. When a connection comes in, the server tells you which
+ * of its ports was connected to; and _you_ have to remember what
+ * local host:port pair went with that port number.
+ *
+ * Hence: in SSH 1 this structure stores host:port pairs we intend
+ * to allow connections to, and is indexed by those host:port
+ * pairs. In SSH 2 it stores a mapping from source port to
+ * destination host:port pair, and is indexed by source port.
+ */
+struct ssh_rportfwd {
+ unsigned sport, dport;
+ char dhost[256];
+};
+
struct Packet {
long length;
int type;
static tree234 *ssh_channels; /* indexed by local id */
static struct ssh_channel *mainchan; /* primary session channel */
+static tree234 *ssh_rportfwds;
+
static enum {
SSH_STATE_PREPACKET,
SSH_STATE_BEFORE_SIZE,
return 0;
}
+static int ssh_rportcmp_ssh1(void *av, void *bv)
+{
+ struct ssh_rportfwd *a = (struct ssh_rportfwd *) av;
+ struct ssh_rportfwd *b = (struct ssh_rportfwd *) bv;
+ int i;
+ if ( (i = strcmp(a->dhost, b->dhost)) != 0)
+ return i < 0 ? -1 : +1;
+ if (a->dport > b->dport)
+ return +1;
+ if (a->dport < b->dport)
+ return -1;
+ return 0;
+}
+
+static int ssh_rportcmp_ssh2(void *av, void *bv)
+{
+ struct ssh_rportfwd *a = (struct ssh_rportfwd *) av;
+ struct ssh_rportfwd *b = (struct ssh_rportfwd *) bv;
+ int i;
+ if (a->sport > b->sport)
+ return +1;
+ if (a->sport < b->sport)
+ return -1;
+ return 0;
+}
+
static int alloc_channel_id(void)
{
const unsigned CHANNEL_NUMBER_OFFSET = 256;
static int do_ssh_init(unsigned char c)
{
- static char vslen;
+ static int vslen;
static char version[10];
static char *vstring;
static int vstrsize;
int calling_back)
{
ssh_state = SSH_STATE_CLOSED;
- sk_close(s);
- s = NULL;
+ if (s) {
+ sk_close(s);
+ s = NULL;
+ }
if (error_msg) {
/* A socket error has occurred. */
connection_fatal(error_msg);
*/
static int do_ssh1_login(unsigned char *in, int inlen, int ispkt)
{
- int i, j, len;
- unsigned char *rsabuf, *keystr1, *keystr2;
+ int i, j;
+ static int len;
+ static unsigned char *rsabuf, *keystr1, *keystr2;
unsigned char cookie[8];
struct RSAKey servkey, hostkey;
struct MD5Context md5c;
static unsigned long supported_ciphers_mask, supported_auths_mask;
static int tried_publickey;
static unsigned char session_id[16];
- int cipher_type;
+ static int cipher_type;
static char username[100];
crBegin;
break;
default:
if (((c >= ' ' && c <= '~') ||
- ((unsigned char) c >= 160)) && pos < 40) {
+ ((unsigned char) c >= 160))
+ && pos < sizeof(username)-1) {
username[pos++] = c;
c_write(&c, 1);
}
ssh1_read_bignum(pktin.body, &challenge);
{
char *agentreq, *q, *ret;
+ void *vret;
int len, retlen;
len = 1 + 4; /* message type, bit count */
len += ssh1_bignum_length(key.exponent);
memcpy(q, session_id, 16);
q += 16;
PUT_32BIT(q, 1); /* response format */
- agent_query(agentreq, len + 4, &ret, &retlen);
+ agent_query(agentreq, len + 4, &vret, &retlen);
+ ret = vret;
sfree(agentreq);
if (ret) {
if (ret[4] == SSH1_AGENT_RSA_RESPONSE) {
exit(0);
break;
default:
- if (((c >= ' ' && c <= '~') ||
- ((unsigned char) c >= 160))
- && pos < sizeof(password))
+ if (pos < sizeof(password)-1)
password[pos++] = c;
break;
}
c->closes = 1;
if (c->type == CHAN_X11) {
c->u.x11.s = NULL;
- logevent("X11 connection terminated");
+ logevent("Forwarded X11 connection terminated");
+ } else if (c->type == CHAN_SOCKDATA) {
+ c->u.pfd.s = NULL;
+ logevent("Forwarded port closed");
}
}
}
}
}
+ {
+ char type, *e;
+ int n;
+ int sport,dport;
+ char sports[256], dports[256], host[256];
+ char buf[1024];
+
+ ssh_rportfwds = newtree234(ssh_rportcmp_ssh1);
+ /* Add port forwardings. */
+ e = cfg.portfwd;
+ while (*e) {
+ type = *e++;
+ n = 0;
+ while (*e && *e != '\t')
+ sports[n++] = *e++;
+ sports[n] = 0;
+ if (*e == '\t')
+ e++;
+ n = 0;
+ while (*e && *e != ':')
+ host[n++] = *e++;
+ host[n] = 0;
+ if (*e == ':')
+ e++;
+ n = 0;
+ while (*e)
+ dports[n++] = *e++;
+ dports[n] = 0;
+ e++;
+ dport = atoi(dports);
+ sport = atoi(sports);
+ if (sport && dport) {
+ if (type == 'L') {
+ pfd_addforward(host, dport, sport);
+ sprintf(buf, "Local port %d forwarding to %s:%d",
+ sport, host, dport);
+ logevent(buf);
+ } else {
+ struct ssh_rportfwd *pf;
+ pf = smalloc(sizeof(*pf));
+ strcpy(pf->dhost, host);
+ pf->dport = dport;
+ if (add234(ssh_rportfwds, pf) != pf) {
+ sprintf(buf,
+ "Duplicate remote port forwarding to %s:%d",
+ host, dport);
+ logevent(buf);
+ sfree(pf);
+ } else {
+ sprintf(buf, "Requesting remote port %d forward to %s:%d",
+ sport, host, dport);
+ logevent(buf);
+ send_packet(SSH1_CMSG_PORT_FORWARD_REQUEST,
+ PKT_INT, sport,
+ PKT_STR, host,
+ PKT_INT, dport,
+ PKT_END);
+ }
+ }
+ }
+ }
+ }
+
if (!cfg.nopty) {
send_packet(SSH1_CMSG_REQUEST_PTY,
PKT_STR, cfg.termtype,
PKT_INT, c->remoteid, PKT_INT, c->localid,
PKT_END);
}
+ } else if (pktin.type == SSH1_MSG_PORT_OPEN) {
+ /* Remote side is trying to open a channel to talk to a
+ * forwarded port. Give them back a local channel number. */
+ struct ssh_channel *c;
+ struct ssh_rportfwd pf;
+ int hostsize, port;
+ char host[256], buf[1024];
+ char *p, *h, *e;
+ c = smalloc(sizeof(struct ssh_channel));
+
+ hostsize = GET_32BIT(pktin.body+4);
+ for(h = host, p = pktin.body+8; hostsize != 0; hostsize--) {
+ if (h+1 < host+sizeof(host))
+ *h++ = *p;
+ p++;
+ }
+ *h = 0;
+ port = GET_32BIT(p);
+
+ strcpy(pf.dhost, host);
+ pf.dport = port;
+
+ if (find234(ssh_rportfwds, &pf, NULL) == NULL) {
+ sprintf(buf, "Rejected remote port open request for %s:%d",
+ host, port);
+ logevent(buf);
+ send_packet(SSH1_MSG_CHANNEL_OPEN_FAILURE,
+ PKT_INT, GET_32BIT(pktin.body), PKT_END);
+ } else {
+ sprintf(buf, "Received remote port open request for %s:%d",
+ host, port);
+ logevent(buf);
+ e = pfd_newconnect(&c->u.pfd.s, host, port, c);
+ if (e != NULL) {
+ char buf[256];
+ sprintf(buf, "Port open failed: %s", e);
+ logevent(buf);
+ sfree(c);
+ send_packet(SSH1_MSG_CHANNEL_OPEN_FAILURE,
+ PKT_INT, GET_32BIT(pktin.body),
+ PKT_END);
+ } else {
+ c->remoteid = GET_32BIT(pktin.body);
+ c->localid = alloc_channel_id();
+ c->closes = 0;
+ c->type = CHAN_SOCKDATA; /* identify channel type */
+ add234(ssh_channels, c);
+ send_packet(SSH1_MSG_CHANNEL_OPEN_CONFIRMATION,
+ PKT_INT, c->remoteid, PKT_INT,
+ c->localid, PKT_END);
+ logevent("Forwarded port opened successfully");
+ }
+ }
+
+ } else if (pktin.type == SSH1_MSG_CHANNEL_OPEN_CONFIRMATION) {
+ unsigned int remoteid = GET_32BIT(pktin.body);
+ unsigned int localid = GET_32BIT(pktin.body+4);
+ struct ssh_channel *c;
+
+ c = find234(ssh_channels, &remoteid, ssh_channelfind);
+ if (c && c->type == CHAN_SOCKDATA_DORMANT) {
+ c->remoteid = localid;
+ c->type = CHAN_SOCKDATA;
+ pfd_confirm(c->u.pfd.s);
+ }
+
} else if (pktin.type == SSH1_MSG_CHANNEL_CLOSE ||
pktin.type == SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION) {
/* Remote side closes a channel. */
send_packet(pktin.type, PKT_INT, c->remoteid,
PKT_END);
if ((c->closes == 0) && (c->type == CHAN_X11)) {
- logevent("X11 connection closed");
+ logevent("Forwarded X11 connection terminated");
assert(c->u.x11.s != NULL);
x11_close(c->u.x11.s);
c->u.x11.s = NULL;
}
+ if ((c->closes == 0) && (c->type == CHAN_SOCKDATA)) {
+ logevent("Forwarded port closed");
+ assert(c->u.pfd.s != NULL);
+ pfd_close(c->u.pfd.s);
+ c->u.pfd.s = NULL;
+ }
c->closes |= closetype;
if (c->closes == 3) {
del234(ssh_channels, c);
case CHAN_X11:
x11_send(c->u.x11.s, p, len);
break;
+ case CHAN_SOCKDATA:
+ pfd_send(c->u.pfd.s, p, len);
+ break;
case CHAN_AGENT:
/* Data for an agent message. Buffer it. */
while (len > 0) {
#endif
hkey = hostkey->newkey(hostkeydata, hostkeylen);
- if (!hostkey->verifysig(hkey, sigdata, siglen, exchange_hash, 20)) {
- bombout(("Server failed host key check"));
+ if (!hkey ||
+ !hostkey->verifysig(hkey, sigdata, siglen, exchange_hash, 20)) {
+ bombout(("Server's host key did not match the signature supplied"));
crReturn(0);
}
*/
static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
{
- static unsigned long remote_winsize;
- static unsigned long remote_maxpkt;
static enum {
AUTH_INVALID, AUTH_PUBLICKEY_AGENT, AUTH_PUBLICKEY_FILE,
- AUTH_PASSWORD
+ AUTH_PASSWORD,
+ AUTH_KEYBOARD_INTERACTIVE
} method;
static enum {
AUTH_TYPE_NONE,
AUTH_TYPE_PUBLICKEY,
AUTH_TYPE_PUBLICKEY_OFFER_LOUD,
AUTH_TYPE_PUBLICKEY_OFFER_QUIET,
- AUTH_TYPE_PASSWORD
+ AUTH_TYPE_PASSWORD,
+ AUTH_TYPE_KEYBOARD_INTERACTIVE,
+ AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET
} type;
- static int gotit, need_pw, can_pubkey, can_passwd;
- static int tried_pubkey_config, tried_agent;
+ static int gotit, need_pw, can_pubkey, can_passwd, can_keyb_inter;
+ static int tried_pubkey_config, tried_agent, tried_keyb_inter;
static int we_are_in;
+ static int num_prompts, echo;
static char username[100];
static char pwprompt[200];
static char password[100];
break;
default:
if (((c >= ' ' && c <= '~') ||
- ((unsigned char) c >= 160)) && pos < 40) {
+ ((unsigned char) c >= 160))
+ && pos < sizeof(username)-1) {
username[pos++] = c;
c_write(&c, 1);
}
if (type == AUTH_TYPE_PUBLICKEY_OFFER_LOUD)
c_write_str("Server refused our key\r\n");
logevent("Server refused public key");
+ } else if (type == AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET) {
+ /* server declined keyboard-interactive; ignore */
} else {
c_write_str("Access denied\r\n");
logevent("Access denied");
in_commasep_string("publickey", methods, methlen);
can_passwd =
in_commasep_string("password", methods, methlen);
+ can_passwd =
+ in_commasep_string("password", methods, methlen);
+ can_keyb_inter =
+ in_commasep_string("keyboard-interactive", methods, methlen);
}
method = 0;
+ if (!method && can_keyb_inter && !tried_keyb_inter) {
+ method = AUTH_KEYBOARD_INTERACTIVE;
+ type = AUTH_TYPE_KEYBOARD_INTERACTIVE;
+ tried_keyb_inter = TRUE;
+
+ ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);
+ ssh2_pkt_addstring(username);
+ ssh2_pkt_addstring("ssh-connection"); /* service requested */
+ ssh2_pkt_addstring("keyboard-interactive"); /* method */
+ ssh2_pkt_addstring(""); /* lang */
+ ssh2_pkt_addstring("");
+ ssh2_pkt_send();
+
+ crWaitUntilV(ispkt);
+ if (pktin.type != SSH2_MSG_USERAUTH_INFO_REQUEST) {
+ if (pktin.type == SSH2_MSG_USERAUTH_FAILURE)
+ gotit = TRUE;
+ logevent("Keyboard-interactive authentication refused");
+ type = AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET;
+ continue;
+ }
+
+ /* We've got packet with that "interactive" info
+ dump banners, and set its prompt as ours */
+ {
+ char *name, *inst, *lang, *prompt;
+ int name_len, inst_len, lang_len, prompt_len;
+ ssh2_pkt_getstring(&name, &name_len);
+ ssh2_pkt_getstring(&inst, &inst_len);
+ ssh2_pkt_getstring(&lang, &lang_len);
+ if (name_len > 0)
+ c_write_untrusted(name, name_len);
+ if (inst_len > 0)
+ c_write_untrusted(inst, inst_len);
+ num_prompts = ssh2_pkt_getuint32();
+
+ ssh2_pkt_getstring(&prompt, &prompt_len);
+ strncpy(pwprompt, prompt, sizeof(pwprompt));
+ need_pw = TRUE;
+
+ echo = ssh2_pkt_getbool();
+ }
+ }
+
if (!method && can_pubkey && agent_exists() && !tried_agent) {
/*
* Attempt public-key authentication using Pageant.
static int pklen, alglen, commentlen;
static int siglen, retlen, len;
static char *q, *agentreq, *ret;
+ void *vret;
{
char buf[64];
q += pktout.length - 5;
/* And finally the (zero) flags word. */
PUT_32BIT(q, 0);
- agent_query(agentreq, len + 4, &ret, &retlen);
+ agent_query(agentreq, len + 4, &vret, &retlen);
+ ret = vret;
sfree(agentreq);
if (ret) {
if (ret[4] == SSH2_AGENT_SIGN_RESPONSE) {
static int pos = 0;
static char c;
- c_write_str(pwprompt);
+ c_write_untrusted(pwprompt, strlen(pwprompt));
ssh_send_ok = 1;
pos = 0;
exit(0);
break;
default:
- if (((c >= ' ' && c <= '~') ||
- ((unsigned char) c >= 160))
- && pos < 40)
+ if (pos < sizeof(password)-1)
password[pos++] = c;
break;
}
ssh_pkt_defersend();
logevent("Sent password");
type = AUTH_TYPE_PASSWORD;
+ } else if (method == AUTH_KEYBOARD_INTERACTIVE) {
+ ssh2_pkt_init(SSH2_MSG_USERAUTH_INFO_RESPONSE);
+ ssh2_pkt_adduint32(num_prompts);
+ ssh2_pkt_addstring(password);
+ memset(password, 0, sizeof(password));
+ ssh2_pkt_send();
+ type = AUTH_TYPE_KEYBOARD_INTERACTIVE;
} else {
c_write_str
("No supported authentication methods left to try!\r\n");
}
/*
+ * Enable port forwardings.
+ */
+ {
+ static char *e; /* preserve across crReturn */
+ char type;
+ int n;
+ int sport,dport;
+ char sports[256], dports[256], host[256];
+ char buf[1024];
+
+ ssh_rportfwds = newtree234(ssh_rportcmp_ssh2);
+ /* Add port forwardings. */
+ e = cfg.portfwd;
+ while (*e) {
+ type = *e++;
+ n = 0;
+ while (*e && *e != '\t')
+ sports[n++] = *e++;
+ sports[n] = 0;
+ if (*e == '\t')
+ e++;
+ n = 0;
+ while (*e && *e != ':')
+ host[n++] = *e++;
+ host[n] = 0;
+ if (*e == ':')
+ e++;
+ n = 0;
+ while (*e)
+ dports[n++] = *e++;
+ dports[n] = 0;
+ e++;
+ dport = atoi(dports);
+ sport = atoi(sports);
+ if (sport && dport) {
+ if (type == 'L') {
+ pfd_addforward(host, dport, sport);
+ sprintf(buf, "Local port %d forwarding to %s:%d",
+ sport, host, dport);
+ logevent(buf);
+ } else {
+ struct ssh_rportfwd *pf;
+ pf = smalloc(sizeof(*pf));
+ strcpy(pf->dhost, host);
+ pf->dport = dport;
+ pf->sport = sport;
+ if (add234(ssh_rportfwds, pf) != pf) {
+ sprintf(buf,
+ "Duplicate remote port forwarding to %s:%d",
+ host, dport);
+ logevent(buf);
+ sfree(pf);
+ } else {
+ sprintf(buf, "Requesting remote port %d (forwarded to %s:%d)",
+ sport, host, dport);
+ logevent(buf);
+ ssh2_pkt_init(SSH2_MSG_GLOBAL_REQUEST);
+ ssh2_pkt_addstring("tcpip-forward");
+ ssh2_pkt_addbool(1);/* want reply */
+ ssh2_pkt_addstring("127.0.0.1");
+ ssh2_pkt_adduint32(sport);
+ ssh2_pkt_send();
+
+ do {
+ crWaitUntilV(ispkt);
+ if (pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST) {
+ unsigned i = ssh2_pkt_getuint32();
+ struct ssh_channel *c;
+ c = find234(ssh_channels, &i, ssh_channelfind);
+ if (!c)
+ continue;/* nonexistent channel */
+ c->v2.remwindow += ssh2_pkt_getuint32();
+ }
+ } while (pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST);
+
+ if (pktin.type != SSH2_MSG_REQUEST_SUCCESS) {
+ if (pktin.type != SSH2_MSG_REQUEST_FAILURE) {
+ bombout(("Server got confused by port forwarding request"));
+ crReturnV;
+ }
+ logevent("Server refused this port forwarding");
+ } else {
+ logevent("Remote port forwarding enabled");
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /*
* Potentially enable agent forwarding.
*/
if (cfg.agentfwd && agent_exists()) {
case CHAN_X11:
x11_send(c->u.x11.s, data, length);
break;
+ case CHAN_SOCKDATA:
+ pfd_send(c->u.pfd.s, data, length);
+ break;
case CHAN_AGENT:
while (length > 0) {
if (c->u.a.lensofar < 4) {
sshfwd_close(c);
} else if (c->type == CHAN_AGENT) {
sshfwd_close(c);
+ } else if (c->type == CHAN_SOCKDATA) {
+ pfd_close(c->u.pfd.s);
+ sshfwd_close(c);
}
} else if (pktin.type == SSH2_MSG_CHANNEL_CLOSE) {
unsigned i = ssh2_pkt_getuint32();
break;
case CHAN_AGENT:
break;
+ case CHAN_SOCKDATA:
+ break;
}
del234(ssh_channels, c);
sfree(c->v2.outbuffer);
continue; /* nonexistent channel */
c->v2.remwindow += ssh2_pkt_getuint32();
try_send = TRUE;
+ } else if (pktin.type == SSH2_MSG_CHANNEL_OPEN_CONFIRMATION) {
+ unsigned i = ssh2_pkt_getuint32();
+ struct ssh_channel *c;
+ c = find234(ssh_channels, &i, ssh_channelfind);
+ if (!c)
+ continue; /* nonexistent channel */
+ if (c->type != CHAN_SOCKDATA_DORMANT)
+ continue; /* dunno why they're confirming this */
+ c->remoteid = ssh2_pkt_getuint32();
+ c->type = CHAN_SOCKDATA;
+ c->closes = 0;
+ c->v2.remwindow = ssh2_pkt_getuint32();
+ c->v2.remmaxpkt = ssh2_pkt_getuint32();
+ c->v2.outbuffer = NULL;
+ c->v2.outbuflen = c->v2.outbufsize = 0;
+ pfd_confirm(c->u.pfd.s);
} else if (pktin.type == SSH2_MSG_CHANNEL_OPEN) {
char *type;
int typelen;
char *error = NULL;
struct ssh_channel *c;
+ unsigned remid, winsize, pktsize;
ssh2_pkt_getstring(&type, &typelen);
c = smalloc(sizeof(struct ssh_channel));
+ remid = ssh2_pkt_getuint32();
+ winsize = ssh2_pkt_getuint32();
+ pktsize = ssh2_pkt_getuint32();
+
if (typelen == 3 && !memcmp(type, "x11", 3)) {
if (!ssh_X11_fwd_enabled)
error = "X11 forwarding is not enabled";
} else {
c->type = CHAN_X11;
}
+ } else if (typelen == 15 &&
+ !memcmp(type, "forwarded-tcpip", 15)) {
+ struct ssh_rportfwd pf, *realpf;
+ char *dummy;
+ int dummylen;
+ ssh2_pkt_getstring(&dummy, &dummylen);/* skip address */
+ pf.sport = ssh2_pkt_getuint32();
+ realpf = find234(ssh_rportfwds, &pf, NULL);
+ if (realpf == NULL) {
+ error = "Remote port is not recognised";
+ } else {
+ char *e = pfd_newconnect(&c->u.pfd.s, realpf->dhost,
+ realpf->dport, c);
+ char buf[1024];
+ sprintf(buf, "Received remote port open request for %s:%d",
+ realpf->dhost, realpf->dport);
+ logevent(buf);
+ if (e != NULL) {
+ sprintf(buf, "Port open failed: %s", e);
+ logevent(buf);
+ error = "Port open failed";
+ } else {
+ logevent("Forwarded port opened successfully");
+ c->type = CHAN_SOCKDATA;
+ }
+ }
} else if (typelen == 22 &&
!memcmp(type, "auth-agent@openssh.com", 3)) {
if (!ssh_agentfwd_enabled)
error = "Unsupported channel type requested";
}
- c->remoteid = ssh2_pkt_getuint32();
+ c->remoteid = remid;
if (error) {
ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN_FAILURE);
ssh2_pkt_adduint32(c->remoteid);
} else {
c->localid = alloc_channel_id();
c->closes = 0;
- c->v2.remwindow = ssh2_pkt_getuint32();
- c->v2.remmaxpkt = ssh2_pkt_getuint32();
+ c->v2.remwindow = winsize;
+ c->v2.remmaxpkt = pktsize;
c->v2.outbuffer = NULL;
c->v2.outbuflen = c->v2.outbufsize = 0;
add234(ssh_channels, c);
}
}
+void *new_sock_channel(Socket s)
+{
+ struct ssh_channel *c;
+ c = smalloc(sizeof(struct ssh_channel));
+
+ if (c) {
+ c->remoteid = -1; /* to be set when open confirmed */
+ c->localid = alloc_channel_id();
+ c->closes = 0;
+ c->type = CHAN_SOCKDATA_DORMANT;/* identify channel type */
+ c->u.pfd.s = s;
+ add234(ssh_channels, c);
+ }
+ return c;
+}
+
+void ssh_send_port_open(void *channel, char *hostname, int port, char *org)
+{
+ struct ssh_channel *c = (struct ssh_channel *)channel;
+ char buf[1024];
+
+ sprintf(buf, "Opening forwarded connection to %.512s:%d", hostname, port);
+ logevent(buf);
+
+ if (ssh_version == 1) {
+ send_packet(SSH1_MSG_PORT_OPEN,
+ PKT_INT, c->localid,
+ PKT_STR, hostname,
+ PKT_INT, port,
+ //PKT_STR, <org:orgport>,
+ PKT_END);
+ } else {
+ ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN);
+ ssh2_pkt_addstring("direct-tcpip");
+ ssh2_pkt_adduint32(c->localid);
+ ssh2_pkt_adduint32(0x8000UL); /* our window size */
+ ssh2_pkt_adduint32(0x4000UL); /* our max pkt size */
+ ssh2_pkt_addstring(hostname);
+ ssh2_pkt_adduint32(port);
+ /*
+ * We make up values for the originator data; partly it's
+ * too much hassle to keep track, and partly I'm not
+ * convinced the server should be told details like that
+ * about my local network configuration.
+ */
+ ssh2_pkt_addstring("client-side-connection");
+ ssh2_pkt_adduint32(0);
+ ssh2_pkt_send();
+ }
+}
+
+
static Socket ssh_socket(void)
{
return s;