Use correct method for string comparison
[TortoiseGit.git] / src / TortoisePlink / ssh2connection-client.c
blob3fe38ab3bcba050db903ef786e303e9a21a6dff4
1 /*
2 * Client-specific parts of the SSH-2 connection layer.
3 */
5 #include <assert.h>
7 #include "putty.h"
8 #include "ssh.h"
9 #include "sshbpp.h"
10 #include "sshppl.h"
11 #include "sshchan.h"
12 #include "sshcr.h"
13 #include "ssh2connection.h"
15 static ChanopenResult chan_open_x11(
16 struct ssh2_connection_state *s, SshChannel *sc,
17 ptrlen peeraddr, int peerport)
19 PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */
20 char *peeraddr_str;
21 Channel *ch;
23 ppl_logevent("Received X11 connect request from %.*s:%d",
24 PTRLEN_PRINTF(peeraddr), peerport);
26 if (!s->X11_fwd_enabled && !s->connshare) {
27 CHANOPEN_RETURN_FAILURE(
28 SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED,
29 ("X11 forwarding is not enabled"));
32 peeraddr_str = peeraddr.ptr ? mkstr(peeraddr) : NULL;
33 ch = x11_new_channel(
34 s->x11authtree, sc, peeraddr_str, peerport, s->connshare != NULL);
35 sfree(peeraddr_str);
36 ppl_logevent("Opened X11 forward channel");
37 CHANOPEN_RETURN_SUCCESS(ch);
40 static ChanopenResult chan_open_forwarded_tcpip(
41 struct ssh2_connection_state *s, SshChannel *sc,
42 ptrlen fwdaddr, int fwdport, ptrlen peeraddr, int peerport)
44 PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */
45 struct ssh_rportfwd pf, *realpf;
46 Channel *ch;
47 char *err;
49 ppl_logevent("Received remote port %.*s:%d open request from %.*s:%d",
50 PTRLEN_PRINTF(fwdaddr), fwdport,
51 PTRLEN_PRINTF(peeraddr), peerport);
53 pf.shost = mkstr(fwdaddr);
54 pf.sport = fwdport;
55 realpf = find234(s->rportfwds, &pf, NULL);
56 sfree(pf.shost);
58 if (realpf == NULL) {
59 CHANOPEN_RETURN_FAILURE(
60 SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED,
61 ("Remote port is not recognised"));
64 if (realpf->share_ctx) {
66 * This port forwarding is on behalf of a connection-sharing
67 * downstream.
69 CHANOPEN_RETURN_DOWNSTREAM(realpf->share_ctx);
72 err = portfwdmgr_connect(
73 s->portfwdmgr, &ch, realpf->dhost, realpf->dport,
74 sc, realpf->addressfamily);
75 ppl_logevent("Attempting to forward remote port to %s:%d",
76 realpf->dhost, realpf->dport);
77 if (err != NULL) {
78 ppl_logevent("Port open failed: %s", err);
79 sfree(err);
80 CHANOPEN_RETURN_FAILURE(
81 SSH2_OPEN_CONNECT_FAILED,
82 ("Port open failed"));
85 ppl_logevent("Forwarded port opened successfully");
86 CHANOPEN_RETURN_SUCCESS(ch);
89 static ChanopenResult chan_open_auth_agent(
90 struct ssh2_connection_state *s, SshChannel *sc)
92 if (!ssh_agent_forwarding_permitted(&s->cl)) {
93 CHANOPEN_RETURN_FAILURE(
94 SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED,
95 ("Agent forwarding is not enabled"));
99 * If possible, make a stream-oriented connection to the agent and
100 * set up an ordinary port-forwarding type channel over it.
102 Plug *plug;
103 Channel *ch = portfwd_raw_new(&s->cl, &plug, true);
104 Socket *skt = agent_connect(plug);
106 if (!sk_socket_error(skt)) {
107 portfwd_raw_setup(ch, skt, sc);
108 CHANOPEN_RETURN_SUCCESS(ch);
109 } else {
110 portfwd_raw_free(ch);
112 * Otherwise, fall back to the old-fashioned system of parsing the
113 * forwarded data stream ourselves for message boundaries, and
114 * passing each individual message to the one-off agent_query().
116 CHANOPEN_RETURN_SUCCESS(agentf_new(sc));
120 ChanopenResult ssh2_connection_parse_channel_open(
121 struct ssh2_connection_state *s, ptrlen type,
122 PktIn *pktin, SshChannel *sc)
124 if (ptrlen_eq_string(type, "x11")) {
125 ptrlen peeraddr = get_string(pktin);
126 int peerport = get_uint32(pktin);
128 return chan_open_x11(s, sc, peeraddr, peerport);
129 } else if (ptrlen_eq_string(type, "forwarded-tcpip")) {
130 ptrlen fwdaddr = get_string(pktin);
131 int fwdport = toint(get_uint32(pktin));
132 ptrlen peeraddr = get_string(pktin);
133 int peerport = toint(get_uint32(pktin));
135 return chan_open_forwarded_tcpip(
136 s, sc, fwdaddr, fwdport, peeraddr, peerport);
137 } else if (ptrlen_eq_string(type, "auth-agent@openssh.com")) {
138 return chan_open_auth_agent(s, sc);
139 } else {
140 CHANOPEN_RETURN_FAILURE(
141 SSH2_OPEN_UNKNOWN_CHANNEL_TYPE,
142 ("Unsupported channel type requested"));
146 bool ssh2_connection_parse_global_request(
147 struct ssh2_connection_state *s, ptrlen type, PktIn *pktin)
150 * We don't know of any global requests that an SSH client needs
151 * to honour.
153 return false;
156 PktOut *ssh2_portfwd_chanopen(
157 struct ssh2_connection_state *s, struct ssh2_channel *c,
158 const char *hostname, int port,
159 const char *description, const SocketPeerInfo *peerinfo)
161 PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */
162 PktOut *pktout;
165 * In client mode, this function is called by portfwdmgr in
166 * response to PortListeners that were set up in
167 * portfwdmgr_config, which means that the hostname and port
168 * parameters will indicate the host we want to tell the server to
169 * connect _to_.
172 ppl_logevent("Opening connection to %s:%d for %s",
173 hostname, port, description);
175 pktout = ssh2_chanopen_init(c, "direct-tcpip");
177 char *trimmed_host = host_strduptrim(hostname);
178 put_stringz(pktout, trimmed_host);
179 sfree(trimmed_host);
181 put_uint32(pktout, port);
184 * We make up values for the originator data; partly it's too much
185 * hassle to keep track, and partly I'm not convinced the server
186 * should be told details like that about my local network
187 * configuration. The "originator IP address" is syntactically a
188 * numeric IP address, and some servers (e.g., Tectia) get upset
189 * if it doesn't match this syntax.
191 put_stringz(pktout, "0.0.0.0");
192 put_uint32(pktout, 0);
194 return pktout;
197 static int ssh2_rportfwd_cmp(void *av, void *bv)
199 struct ssh_rportfwd *a = (struct ssh_rportfwd *) av;
200 struct ssh_rportfwd *b = (struct ssh_rportfwd *) bv;
201 int i;
202 if ( (i = strcmp(a->shost, b->shost)) != 0)
203 return i < 0 ? -1 : +1;
204 if (a->sport > b->sport)
205 return +1;
206 if (a->sport < b->sport)
207 return -1;
208 return 0;
211 static void ssh2_rportfwd_globreq_response(struct ssh2_connection_state *s,
212 PktIn *pktin, void *ctx)
214 PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */
215 struct ssh_rportfwd *rpf = (struct ssh_rportfwd *)ctx;
217 if (pktin->type == SSH2_MSG_REQUEST_SUCCESS) {
218 ppl_logevent("Remote port forwarding from %s enabled",
219 rpf->log_description);
220 } else {
221 ppl_logevent("Remote port forwarding from %s refused",
222 rpf->log_description);
224 struct ssh_rportfwd *realpf = del234(s->rportfwds, rpf);
225 assert(realpf == rpf);
226 portfwdmgr_close(s->portfwdmgr, rpf->pfr);
227 free_rportfwd(rpf);
231 struct ssh_rportfwd *ssh2_rportfwd_alloc(
232 ConnectionLayer *cl,
233 const char *shost, int sport, const char *dhost, int dport,
234 int addressfamily, const char *log_description, PortFwdRecord *pfr,
235 ssh_sharing_connstate *share_ctx)
237 struct ssh2_connection_state *s =
238 container_of(cl, struct ssh2_connection_state, cl);
239 struct ssh_rportfwd *rpf = snew(struct ssh_rportfwd);
241 if (!s->rportfwds)
242 s->rportfwds = newtree234(ssh2_rportfwd_cmp);
244 rpf->shost = dupstr(shost);
245 rpf->sport = sport;
246 rpf->dhost = dupstr(dhost);
247 rpf->dport = dport;
248 rpf->addressfamily = addressfamily;
249 rpf->log_description = dupstr(log_description);
250 rpf->pfr = pfr;
251 rpf->share_ctx = share_ctx;
253 if (add234(s->rportfwds, rpf) != rpf) {
254 free_rportfwd(rpf);
255 return NULL;
258 if (!rpf->share_ctx) {
259 PktOut *pktout = ssh_bpp_new_pktout(
260 s->ppl.bpp, SSH2_MSG_GLOBAL_REQUEST);
261 put_stringz(pktout, "tcpip-forward");
262 put_bool(pktout, true); /* want reply */
263 put_stringz(pktout, rpf->shost);
264 put_uint32(pktout, rpf->sport);
265 pq_push(s->ppl.out_pq, pktout);
267 ssh2_queue_global_request_handler(
268 s, ssh2_rportfwd_globreq_response, rpf);
271 return rpf;
274 void ssh2_rportfwd_remove(ConnectionLayer *cl, struct ssh_rportfwd *rpf)
276 struct ssh2_connection_state *s =
277 container_of(cl, struct ssh2_connection_state, cl);
279 if (rpf->share_ctx) {
281 * We don't manufacture a cancel-tcpip-forward message for
282 * remote port forwardings being removed on behalf of a
283 * downstream; we just pass through the one the downstream
284 * sent to us.
286 } else {
287 PktOut *pktout = ssh_bpp_new_pktout(
288 s->ppl.bpp, SSH2_MSG_GLOBAL_REQUEST);
289 put_stringz(pktout, "cancel-tcpip-forward");
290 put_bool(pktout, false); /* _don't_ want reply */
291 put_stringz(pktout, rpf->shost);
292 put_uint32(pktout, rpf->sport);
293 pq_push(s->ppl.out_pq, pktout);
296 assert(s->rportfwds);
297 struct ssh_rportfwd *realpf = del234(s->rportfwds, rpf);
298 assert(realpf == rpf);
299 free_rportfwd(rpf);
302 SshChannel *ssh2_session_open(ConnectionLayer *cl, Channel *chan)
304 struct ssh2_connection_state *s =
305 container_of(cl, struct ssh2_connection_state, cl);
306 PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */
307 struct ssh2_channel *c = snew(struct ssh2_channel);
308 PktOut *pktout;
310 c->connlayer = s;
311 ssh2_channel_init(c);
312 c->halfopen = true;
313 c->chan = chan;
315 ppl_logevent("Opening main session channel");
317 pktout = ssh2_chanopen_init(c, "session");
318 pq_push(s->ppl.out_pq, pktout);
320 return &c->sc;
323 SshChannel *ssh2_serverside_x11_open(
324 ConnectionLayer *cl, Channel *chan, const SocketPeerInfo *pi)
326 unreachable("Should never be called in the client");
329 SshChannel *ssh2_serverside_agent_open(ConnectionLayer *cl, Channel *chan)
331 unreachable("Should never be called in the client");
334 static void ssh2_channel_response(
335 struct ssh2_channel *c, PktIn *pkt, void *ctx)
337 /* If pkt==NULL (because this handler has been called in response
338 * to CHANNEL_CLOSE arriving while the request was still
339 * outstanding), we treat that the same as CHANNEL_FAILURE. */
340 chan_request_response(c->chan,
341 pkt && pkt->type == SSH2_MSG_CHANNEL_SUCCESS);
344 void ssh2channel_start_shell(SshChannel *sc, bool want_reply)
346 struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc);
347 struct ssh2_connection_state *s = c->connlayer;
349 PktOut *pktout = ssh2_chanreq_init(
350 c, "shell", want_reply ? ssh2_channel_response : NULL, NULL);
351 pq_push(s->ppl.out_pq, pktout);
354 void ssh2channel_start_command(
355 SshChannel *sc, bool want_reply, const char *command)
357 struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc);
358 struct ssh2_connection_state *s = c->connlayer;
360 PktOut *pktout = ssh2_chanreq_init(
361 c, "exec", want_reply ? ssh2_channel_response : NULL, NULL);
362 put_stringz(pktout, command);
363 pq_push(s->ppl.out_pq, pktout);
366 bool ssh2channel_start_subsystem(
367 SshChannel *sc, bool want_reply, const char *subsystem)
369 struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc);
370 struct ssh2_connection_state *s = c->connlayer;
372 PktOut *pktout = ssh2_chanreq_init(
373 c, "subsystem", want_reply ? ssh2_channel_response : NULL, NULL);
374 put_stringz(pktout, subsystem);
375 pq_push(s->ppl.out_pq, pktout);
377 return true;
380 void ssh2channel_send_exit_status(SshChannel *sc, int status)
382 unreachable("Should never be called in the client");
385 void ssh2channel_send_exit_signal(
386 SshChannel *sc, ptrlen signame, bool core_dumped, ptrlen msg)
388 unreachable("Should never be called in the client");
391 void ssh2channel_send_exit_signal_numeric(
392 SshChannel *sc, int signum, bool core_dumped, ptrlen msg)
394 unreachable("Should never be called in the client");
397 void ssh2channel_request_x11_forwarding(
398 SshChannel *sc, bool want_reply, const char *authproto,
399 const char *authdata, int screen_number, bool oneshot)
401 struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc);
402 struct ssh2_connection_state *s = c->connlayer;
404 PktOut *pktout = ssh2_chanreq_init(
405 c, "x11-req", want_reply ? ssh2_channel_response : NULL, NULL);
406 put_bool(pktout, oneshot);
407 put_stringz(pktout, authproto);
408 put_stringz(pktout, authdata);
409 put_uint32(pktout, screen_number);
410 pq_push(s->ppl.out_pq, pktout);
413 void ssh2channel_request_agent_forwarding(SshChannel *sc, bool want_reply)
415 struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc);
416 struct ssh2_connection_state *s = c->connlayer;
418 PktOut *pktout = ssh2_chanreq_init(
419 c, "auth-agent-req@openssh.com",
420 want_reply ? ssh2_channel_response : NULL, NULL);
421 pq_push(s->ppl.out_pq, pktout);
424 void ssh2channel_request_pty(
425 SshChannel *sc, bool want_reply, Conf *conf, int w, int h)
427 struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc);
428 struct ssh2_connection_state *s = c->connlayer;
429 strbuf *modebuf;
431 PktOut *pktout = ssh2_chanreq_init(
432 c, "pty-req", want_reply ? ssh2_channel_response : NULL, NULL);
433 put_stringz(pktout, conf_get_str(conf, CONF_termtype));
434 put_uint32(pktout, w);
435 put_uint32(pktout, h);
436 put_uint32(pktout, 0); /* pixel width */
437 put_uint32(pktout, 0); /* pixel height */
438 modebuf = strbuf_new();
439 write_ttymodes_to_packet(
440 BinarySink_UPCAST(modebuf), 2,
441 get_ttymodes_from_conf(s->ppl.seat, conf));
442 put_stringsb(pktout, modebuf);
443 pq_push(s->ppl.out_pq, pktout);
446 bool ssh2channel_send_env_var(
447 SshChannel *sc, bool want_reply, const char *var, const char *value)
449 struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc);
450 struct ssh2_connection_state *s = c->connlayer;
452 PktOut *pktout = ssh2_chanreq_init(
453 c, "env", want_reply ? ssh2_channel_response : NULL, NULL);
454 put_stringz(pktout, var);
455 put_stringz(pktout, value);
456 pq_push(s->ppl.out_pq, pktout);
458 return true;
461 bool ssh2channel_send_serial_break(SshChannel *sc, bool want_reply, int length)
463 struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc);
464 struct ssh2_connection_state *s = c->connlayer;
466 PktOut *pktout = ssh2_chanreq_init(
467 c, "break", want_reply ? ssh2_channel_response : NULL, NULL);
468 put_uint32(pktout, length);
469 pq_push(s->ppl.out_pq, pktout);
471 return true;
474 bool ssh2channel_send_signal(
475 SshChannel *sc, bool want_reply, const char *signame)
477 struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc);
478 struct ssh2_connection_state *s = c->connlayer;
480 PktOut *pktout = ssh2_chanreq_init(
481 c, "signal", want_reply ? ssh2_channel_response : NULL, NULL);
482 put_stringz(pktout, signame);
483 pq_push(s->ppl.out_pq, pktout);
485 return true;
488 void ssh2channel_send_terminal_size_change(SshChannel *sc, int w, int h)
490 struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc);
491 struct ssh2_connection_state *s = c->connlayer;
493 PktOut *pktout = ssh2_chanreq_init(c, "window-change", NULL, NULL);
494 put_uint32(pktout, w);
495 put_uint32(pktout, h);
496 put_uint32(pktout, 0); /* pixel width */
497 put_uint32(pktout, 0); /* pixel height */
498 pq_push(s->ppl.out_pq, pktout);
501 bool ssh2_connection_need_antispoof_prompt(struct ssh2_connection_state *s)
503 bool success = seat_set_trust_status(s->ppl.seat, false);
504 return (!success && !ssh_is_bare(s->ppl.ssh));