agentf.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. /*
  2. * SSH agent forwarding.
  3. */
  4. #include <assert.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include "putty.h"
  8. #include "ssh.h"
  9. #include "pageant.h"
  10. #include "channel.h"
  11. typedef struct agentf {
  12. struct callback_set * callback_set; // WINSCP
  13. SshChannel *c;
  14. bufchain inbuffer;
  15. agent_pending_query *pending;
  16. bool input_wanted;
  17. bool rcvd_eof;
  18. Channel chan;
  19. } agentf;
  20. static void agentf_got_response(agentf *af, void *reply, int replylen)
  21. {
  22. af->pending = NULL;
  23. if (!reply) {
  24. /* The real agent didn't send any kind of reply at all for
  25. * some reason, so fake an SSH_AGENT_FAILURE. */
  26. reply = "\0\0\0\1\5";
  27. replylen = 5;
  28. }
  29. sshfwd_write(af->c, reply, replylen);
  30. }
  31. static void agentf_callback(void *vctx, void *reply, int replylen);
  32. static void agentf_try_forward(agentf *af)
  33. {
  34. size_t datalen, length;
  35. strbuf *message;
  36. unsigned char msglen[4];
  37. void *reply;
  38. int replylen;
  39. /*
  40. * Don't try to parallelise agent requests. Wait for each one to
  41. * return before attempting the next.
  42. */
  43. if (af->pending)
  44. return;
  45. /*
  46. * If the outgoing side of the channel connection is currently
  47. * throttled, don't submit any new forwarded requests to the real
  48. * agent. This causes the input side of the agent forwarding not
  49. * to be emptied, exerting the required back-pressure on the
  50. * remote client, and encouraging it to read our responses before
  51. * sending too many more requests.
  52. */
  53. if (!af->input_wanted)
  54. return;
  55. while (1) {
  56. /*
  57. * Try to extract a complete message from the input buffer.
  58. */
  59. datalen = bufchain_size(&af->inbuffer);
  60. if (datalen < 4)
  61. break; /* not even a length field available yet */
  62. bufchain_fetch(&af->inbuffer, msglen, 4);
  63. length = GET_32BIT_MSB_FIRST(msglen);
  64. if (length > AGENT_MAX_MSGLEN-4) {
  65. /*
  66. * If the remote has sent a message that's just _too_
  67. * long, we should reject it in advance of seeing the rest
  68. * of the incoming message, and also close the connection
  69. * for good measure (which avoids us having to faff about
  70. * with carefully ignoring just the right number of bytes
  71. * from the overlong message).
  72. */
  73. agentf_got_response(af, NULL, 0);
  74. sshfwd_write_eof(af->c);
  75. return;
  76. }
  77. if (length > datalen - 4)
  78. break; /* a whole message is not yet available */
  79. bufchain_consume(&af->inbuffer, 4);
  80. message = strbuf_new_for_agent_query();
  81. bufchain_fetch_consume(
  82. &af->inbuffer, strbuf_append(message, length), length);
  83. af->pending = agent_query(
  84. message, &reply, &replylen, agentf_callback, af, af->callback_set); // WINSCP
  85. strbuf_free(message);
  86. if (af->pending)
  87. return; /* agent_query promised to reply in due course */
  88. /*
  89. * If the agent gave us an answer immediately, pass it
  90. * straight on and go round this loop again.
  91. */
  92. agentf_got_response(af, reply, replylen);
  93. sfree(reply);
  94. }
  95. /*
  96. * If we get here (i.e. we left the above while loop via 'break'
  97. * rather than 'return'), that means we've determined that the
  98. * input buffer for the agent forwarding connection doesn't
  99. * contain a complete request.
  100. *
  101. * So if there's potentially more data to come, we can return now,
  102. * and wait for the remote client to send it. But if the remote
  103. * has sent EOF, it would be a mistake to do that, because we'd be
  104. * waiting a long time. So this is the moment to check for EOF,
  105. * and respond appropriately.
  106. */
  107. if (af->rcvd_eof)
  108. sshfwd_write_eof(af->c);
  109. }
  110. static void agentf_callback(void *vctx, void *reply, int replylen)
  111. {
  112. agentf *af = (agentf *)vctx;
  113. agentf_got_response(af, reply, replylen);
  114. sfree(reply);
  115. /*
  116. * Now try to extract and send further messages from the channel's
  117. * input-side buffer.
  118. */
  119. agentf_try_forward(af);
  120. }
  121. static void agentf_free(Channel *chan);
  122. static size_t agentf_send(Channel *chan, bool is_stderr, const void *, size_t);
  123. static void agentf_send_eof(Channel *chan);
  124. static char *agentf_log_close_msg(Channel *chan);
  125. static void agentf_set_input_wanted(Channel *chan, bool wanted);
  126. static const ChannelVtable agentf_channelvt = {
  127. // WINSCP
  128. /*.free =*/ agentf_free,
  129. /*.open_confirmation =*/ chan_remotely_opened_confirmation,
  130. /*.open_failed =*/ chan_remotely_opened_failure,
  131. /*.send =*/ agentf_send,
  132. /*.send_eof =*/ agentf_send_eof,
  133. /*.set_input_wanted =*/ agentf_set_input_wanted,
  134. /*.log_close_msg =*/ agentf_log_close_msg,
  135. /*.want_close =*/ chan_default_want_close,
  136. /*.rcvd_exit_status =*/ chan_no_exit_status,
  137. /*.rcvd_exit_signal =*/ chan_no_exit_signal,
  138. /*.rcvd_exit_signal_numeric =*/ chan_no_exit_signal_numeric,
  139. /*.run_shell =*/ chan_no_run_shell,
  140. /*.run_command =*/ chan_no_run_command,
  141. /*.run_subsystem =*/ chan_no_run_subsystem,
  142. /*.enable_x11_forwarding =*/ chan_no_enable_x11_forwarding,
  143. /*.enable_agent_forwarding =*/ chan_no_enable_agent_forwarding,
  144. /*.allocate_pty =*/ chan_no_allocate_pty,
  145. /*.set_env =*/ chan_no_set_env,
  146. /*.send_break =*/ chan_no_send_break,
  147. /*.send_signal =*/ chan_no_send_signal,
  148. /*.change_window_size =*/ chan_no_change_window_size,
  149. /*.request_response =*/ chan_no_request_response,
  150. };
  151. Channel *agentf_new(SshChannel *c, struct callback_set *callback_set) // WINSCP
  152. {
  153. agentf *af = snew(agentf);
  154. af->callback_set = callback_set; // WINSCP
  155. af->c = c;
  156. af->chan.vt = &agentf_channelvt;
  157. af->chan.initial_fixed_window_size = 0;
  158. af->rcvd_eof = false;
  159. bufchain_init(&af->inbuffer);
  160. af->pending = NULL;
  161. af->input_wanted = true;
  162. return &af->chan;
  163. }
  164. static void agentf_free(Channel *chan)
  165. {
  166. pinitassert(chan->vt == &agentf_channelvt);
  167. agentf *af = container_of(chan, agentf, chan);
  168. if (af->pending)
  169. agent_cancel_query(af->pending);
  170. bufchain_clear(&af->inbuffer);
  171. sfree(af);
  172. }
  173. static size_t agentf_send(Channel *chan, bool is_stderr,
  174. const void *data, size_t length)
  175. {
  176. pinitassert(chan->vt == &agentf_channelvt);
  177. agentf *af = container_of(chan, agentf, chan);
  178. bufchain_add(&af->inbuffer, data, length);
  179. agentf_try_forward(af);
  180. /*
  181. * We exert back-pressure on an agent forwarding client if and
  182. * only if we're waiting for the response to an asynchronous agent
  183. * request. This prevents the client running out of window while
  184. * receiving the _first_ message, but means that if any message
  185. * takes time to process, the client will be discouraged from
  186. * sending an endless stream of further ones after it.
  187. */
  188. return (af->pending ? bufchain_size(&af->inbuffer) : 0);
  189. }
  190. static void agentf_send_eof(Channel *chan)
  191. {
  192. pinitassert(chan->vt == &agentf_channelvt);
  193. agentf *af = container_of(chan, agentf, chan);
  194. af->rcvd_eof = true;
  195. /* Call try_forward, which will respond to the EOF now if
  196. * appropriate, or wait until the queue of outstanding requests is
  197. * dealt with if not. */
  198. agentf_try_forward(af);
  199. }
  200. static char *agentf_log_close_msg(Channel *chan)
  201. {
  202. return dupstr("Agent-forwarding connection closed");
  203. }
  204. static void agentf_set_input_wanted(Channel *chan, bool wanted)
  205. {
  206. pinitassert(chan->vt == &agentf_channelvt);
  207. agentf *af = container_of(chan, agentf, chan);
  208. af->input_wanted = wanted;
  209. /* Agent forwarding channels are buffer-managed by not asking the
  210. * agent questions if the SSH channel isn't accepting input. So if
  211. * it's started again, we should ask a question if we have one
  212. * pending.. */
  213. if (wanted)
  214. agentf_try_forward(af);
  215. }