sesschan.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795
  1. /*
  2. * Implement the "session" channel type for the SSH server.
  3. */
  4. #include <assert.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <ctype.h>
  8. #include "putty.h"
  9. #include "ssh.h"
  10. #include "channel.h"
  11. #include "server.h"
  12. #include "sftp.h"
  13. struct agentfwd {
  14. ConnectionLayer *cl;
  15. Socket *socket;
  16. Plug plug;
  17. };
  18. typedef struct sesschan {
  19. SshChannel *c;
  20. LogContext *parent_logctx, *child_logctx;
  21. Conf *conf;
  22. const SftpServerVtable *sftpserver_vt;
  23. LogPolicy logpolicy;
  24. Seat seat;
  25. bool want_pty;
  26. struct ssh_ttymodes ttymodes;
  27. int wc, hc, wp, hp;
  28. strbuf *termtype;
  29. bool ignoring_input;
  30. bool seen_eof, seen_exit;
  31. Plug xfwd_plug;
  32. int n_x11_sockets;
  33. Socket *x11_sockets[MAX_X11_SOCKETS];
  34. agentfwd *agent;
  35. Backend *backend;
  36. bufchain subsys_input;
  37. SftpServer *sftpsrv;
  38. ScpServer *scpsrv;
  39. const SshServerConfig *ssc;
  40. Channel chan;
  41. } sesschan;
  42. static void sesschan_free(Channel *chan);
  43. static size_t sesschan_send(
  44. Channel *chan, bool is_stderr, const void *, size_t);
  45. static void sesschan_send_eof(Channel *chan);
  46. static char *sesschan_log_close_msg(Channel *chan);
  47. static bool sesschan_want_close(Channel *, bool, bool);
  48. static void sesschan_set_input_wanted(Channel *chan, bool wanted);
  49. static bool sesschan_run_shell(Channel *chan);
  50. static bool sesschan_run_command(Channel *chan, ptrlen command);
  51. static bool sesschan_run_subsystem(Channel *chan, ptrlen subsys);
  52. static bool sesschan_enable_x11_forwarding(
  53. Channel *chan, bool oneshot, ptrlen authproto, ptrlen authdata,
  54. unsigned screen_number);
  55. static bool sesschan_enable_agent_forwarding(Channel *chan);
  56. static bool sesschan_allocate_pty(
  57. Channel *chan, ptrlen termtype, unsigned width, unsigned height,
  58. unsigned pixwidth, unsigned pixheight, struct ssh_ttymodes modes);
  59. static bool sesschan_set_env(Channel *chan, ptrlen var, ptrlen value);
  60. static bool sesschan_send_break(Channel *chan, unsigned length);
  61. static bool sesschan_send_signal(Channel *chan, ptrlen signame);
  62. static bool sesschan_change_window_size(
  63. Channel *chan, unsigned width, unsigned height,
  64. unsigned pixwidth, unsigned pixheight);
  65. static const ChannelVtable sesschan_channelvt = {
  66. .free = sesschan_free,
  67. .open_confirmation = chan_remotely_opened_confirmation,
  68. .open_failed = chan_remotely_opened_failure,
  69. .send = sesschan_send,
  70. .send_eof = sesschan_send_eof,
  71. .set_input_wanted = sesschan_set_input_wanted,
  72. .log_close_msg = sesschan_log_close_msg,
  73. .want_close = sesschan_want_close,
  74. .rcvd_exit_status = chan_no_exit_status,
  75. .rcvd_exit_signal = chan_no_exit_signal,
  76. .rcvd_exit_signal_numeric = chan_no_exit_signal_numeric,
  77. .run_shell = sesschan_run_shell,
  78. .run_command = sesschan_run_command,
  79. .run_subsystem = sesschan_run_subsystem,
  80. .enable_x11_forwarding = sesschan_enable_x11_forwarding,
  81. .enable_agent_forwarding = sesschan_enable_agent_forwarding,
  82. .allocate_pty = sesschan_allocate_pty,
  83. .set_env = sesschan_set_env,
  84. .send_break = sesschan_send_break,
  85. .send_signal = sesschan_send_signal,
  86. .change_window_size = sesschan_change_window_size,
  87. .request_response = chan_no_request_response,
  88. };
  89. static size_t sftp_chan_send(
  90. Channel *chan, bool is_stderr, const void *, size_t);
  91. static void sftp_chan_send_eof(Channel *chan);
  92. static char *sftp_log_close_msg(Channel *chan);
  93. static const ChannelVtable sftp_channelvt = {
  94. .free = sesschan_free,
  95. .open_confirmation = chan_remotely_opened_confirmation,
  96. .open_failed = chan_remotely_opened_failure,
  97. .send = sftp_chan_send,
  98. .send_eof = sftp_chan_send_eof,
  99. .set_input_wanted = sesschan_set_input_wanted,
  100. .log_close_msg = sftp_log_close_msg,
  101. .want_close = chan_default_want_close,
  102. .rcvd_exit_status = chan_no_exit_status,
  103. .rcvd_exit_signal = chan_no_exit_signal,
  104. .rcvd_exit_signal_numeric = chan_no_exit_signal_numeric,
  105. .run_shell = chan_no_run_shell,
  106. .run_command = chan_no_run_command,
  107. .run_subsystem = chan_no_run_subsystem,
  108. .enable_x11_forwarding = chan_no_enable_x11_forwarding,
  109. .enable_agent_forwarding = chan_no_enable_agent_forwarding,
  110. .allocate_pty = chan_no_allocate_pty,
  111. .set_env = chan_no_set_env,
  112. .send_break = chan_no_send_break,
  113. .send_signal = chan_no_send_signal,
  114. .change_window_size = chan_no_change_window_size,
  115. .request_response = chan_no_request_response,
  116. };
  117. static size_t scp_chan_send(
  118. Channel *chan, bool is_stderr, const void *, size_t);
  119. static void scp_chan_send_eof(Channel *chan);
  120. static void scp_set_input_wanted(Channel *chan, bool wanted);
  121. static char *scp_log_close_msg(Channel *chan);
  122. static const ChannelVtable scp_channelvt = {
  123. .free = sesschan_free,
  124. .open_confirmation = chan_remotely_opened_confirmation,
  125. .open_failed = chan_remotely_opened_failure,
  126. .send = scp_chan_send,
  127. .send_eof = scp_chan_send_eof,
  128. .set_input_wanted = scp_set_input_wanted,
  129. .log_close_msg = scp_log_close_msg,
  130. .want_close = chan_default_want_close,
  131. .rcvd_exit_status = chan_no_exit_status,
  132. .rcvd_exit_signal = chan_no_exit_signal,
  133. .rcvd_exit_signal_numeric = chan_no_exit_signal_numeric,
  134. .run_shell = chan_no_run_shell,
  135. .run_command = chan_no_run_command,
  136. .run_subsystem = chan_no_run_subsystem,
  137. .enable_x11_forwarding = chan_no_enable_x11_forwarding,
  138. .enable_agent_forwarding = chan_no_enable_agent_forwarding,
  139. .allocate_pty = chan_no_allocate_pty,
  140. .set_env = chan_no_set_env,
  141. .send_break = chan_no_send_break,
  142. .send_signal = chan_no_send_signal,
  143. .change_window_size = chan_no_change_window_size,
  144. .request_response = chan_no_request_response,
  145. };
  146. static void sesschan_eventlog(LogPolicy *lp, const char *event) {}
  147. static void sesschan_logging_error(LogPolicy *lp, const char *event) {}
  148. static int sesschan_askappend(
  149. LogPolicy *lp, Filename *filename,
  150. void (*callback)(void *ctx, int result), void *ctx) { return 2; }
  151. static const LogPolicyVtable sesschan_logpolicy_vt = {
  152. .eventlog = sesschan_eventlog,
  153. .askappend = sesschan_askappend,
  154. .logging_error = sesschan_logging_error,
  155. .verbose = null_lp_verbose_no,
  156. };
  157. static size_t sesschan_seat_output(
  158. Seat *, SeatOutputType type, const void *, size_t);
  159. static bool sesschan_seat_eof(Seat *);
  160. static void sesschan_notify_remote_exit(Seat *seat);
  161. static void sesschan_connection_fatal(Seat *seat, const char *message);
  162. static bool sesschan_get_window_pixel_size(Seat *seat, int *w, int *h);
  163. static const SeatVtable sesschan_seat_vt = {
  164. .output = sesschan_seat_output,
  165. .eof = sesschan_seat_eof,
  166. .sent = nullseat_sent,
  167. .banner = nullseat_banner,
  168. .get_userpass_input = nullseat_get_userpass_input,
  169. .notify_session_started = nullseat_notify_session_started,
  170. .notify_remote_exit = sesschan_notify_remote_exit,
  171. .notify_remote_disconnect = nullseat_notify_remote_disconnect,
  172. .connection_fatal = sesschan_connection_fatal,
  173. .nonfatal = nullseat_nonfatal,
  174. .update_specials_menu = nullseat_update_specials_menu,
  175. .get_ttymode = nullseat_get_ttymode,
  176. .set_busy_status = nullseat_set_busy_status,
  177. .confirm_ssh_host_key = nullseat_confirm_ssh_host_key,
  178. .confirm_weak_crypto_primitive = nullseat_confirm_weak_crypto_primitive,
  179. .confirm_weak_cached_hostkey = nullseat_confirm_weak_cached_hostkey,
  180. .prompt_descriptions = nullseat_prompt_descriptions,
  181. .is_utf8 = nullseat_is_never_utf8,
  182. .echoedit_update = nullseat_echoedit_update,
  183. .get_x_display = nullseat_get_x_display,
  184. .get_windowid = nullseat_get_windowid,
  185. .get_window_pixel_size = sesschan_get_window_pixel_size,
  186. .stripctrl_new = nullseat_stripctrl_new,
  187. .set_trust_status = nullseat_set_trust_status,
  188. .can_set_trust_status = nullseat_can_set_trust_status_no,
  189. .has_mixed_input_stream = nullseat_has_mixed_input_stream_no,
  190. .verbose = nullseat_verbose_no,
  191. .interactive = nullseat_interactive_no,
  192. .get_cursor_position = nullseat_get_cursor_position,
  193. };
  194. Channel *sesschan_new(SshChannel *c, LogContext *logctx,
  195. const SftpServerVtable *sftpserver_vt,
  196. const SshServerConfig *ssc)
  197. {
  198. sesschan *sess = snew(sesschan);
  199. memset(sess, 0, sizeof(sesschan));
  200. sess->c = c;
  201. sess->chan.vt = &sesschan_channelvt;
  202. sess->chan.initial_fixed_window_size = 0;
  203. sess->parent_logctx = logctx;
  204. sess->ssc = ssc;
  205. /* Start with a completely default Conf */
  206. sess->conf = conf_new();
  207. load_open_settings(NULL, sess->conf);
  208. /* Set close-on-exit = true to suppress pty.c's "[pterm: process
  209. * terminated with status x]" message */
  210. conf_set_int(sess->conf, CONF_close_on_exit, FORCE_ON);
  211. sess->seat.vt = &sesschan_seat_vt;
  212. sess->logpolicy.vt = &sesschan_logpolicy_vt;
  213. sess->child_logctx = log_init(&sess->logpolicy, sess->conf);
  214. sess->sftpserver_vt = sftpserver_vt;
  215. bufchain_init(&sess->subsys_input);
  216. return &sess->chan;
  217. }
  218. static void sesschan_free(Channel *chan)
  219. {
  220. sesschan *sess = container_of(chan, sesschan, chan);
  221. int i;
  222. delete_callbacks_for_context(sess);
  223. conf_free(sess->conf);
  224. if (sess->backend)
  225. backend_free(sess->backend);
  226. bufchain_clear(&sess->subsys_input);
  227. if (sess->sftpsrv)
  228. sftpsrv_free(sess->sftpsrv);
  229. for (i = 0; i < sess->n_x11_sockets; i++)
  230. sk_close(sess->x11_sockets[i]);
  231. if (sess->agent)
  232. agentfwd_free(sess->agent);
  233. sfree(sess);
  234. }
  235. static size_t sesschan_send(Channel *chan, bool is_stderr,
  236. const void *data, size_t length)
  237. {
  238. sesschan *sess = container_of(chan, sesschan, chan);
  239. if (!sess->backend || sess->ignoring_input)
  240. return 0;
  241. backend_send(sess->backend, data, length);
  242. return backend_sendbuffer(sess->backend);
  243. }
  244. static void sesschan_send_eof(Channel *chan)
  245. {
  246. sesschan *sess = container_of(chan, sesschan, chan);
  247. if (sess->backend)
  248. backend_special(sess->backend, SS_EOF, 0);
  249. }
  250. static char *sesschan_log_close_msg(Channel *chan)
  251. {
  252. return dupstr("Session channel closed");
  253. }
  254. static void sesschan_set_input_wanted(Channel *chan, bool wanted)
  255. {
  256. sesschan *sess = container_of(chan, sesschan, chan);
  257. /* Request the back end to resume sending input, if it had become
  258. * throttled by the channel window shortening */
  259. if (wanted && sess->backend)
  260. backend_unthrottle(sess->backend, 0);
  261. }
  262. static void sesschan_start_backend(sesschan *sess, const char *cmd)
  263. {
  264. /*
  265. * List of environment variables that we should not pass through
  266. * from the login session Uppity was run in (which, it being a
  267. * test server, there will usually be one of). These variables
  268. * will be set as part of X or agent forwarding, and shouldn't be
  269. * confusingly set in the absence of that.
  270. *
  271. * (DISPLAY must also be cleared, but pty.c will do that anyway
  272. * when our get_x_display method returns NULL.)
  273. */
  274. static const char *const env_to_unset[] = {
  275. "XAUTHORITY", "SSH_AUTH_SOCK", "SSH_AGENT_PID",
  276. NULL /* terminator */
  277. };
  278. sess->backend = pty_backend_create(
  279. &sess->seat, sess->child_logctx, sess->conf, NULL, cmd,
  280. sess->ttymodes, !sess->want_pty, sess->ssc->session_starting_dir,
  281. env_to_unset);
  282. backend_size(sess->backend, sess->wc, sess->hc);
  283. }
  284. bool sesschan_run_shell(Channel *chan)
  285. {
  286. sesschan *sess = container_of(chan, sesschan, chan);
  287. if (sess->backend)
  288. return false;
  289. sesschan_start_backend(sess, NULL);
  290. return true;
  291. }
  292. bool sesschan_run_command(Channel *chan, ptrlen command)
  293. {
  294. sesschan *sess = container_of(chan, sesschan, chan);
  295. if (sess->backend)
  296. return false;
  297. /* FIXME: make this possible to configure off */
  298. if ((sess->scpsrv = scp_recognise_exec(sess->c, sess->sftpserver_vt,
  299. command)) != NULL) {
  300. sess->chan.vt = &scp_channelvt;
  301. logevent(sess->parent_logctx, "Starting built-in SCP server");
  302. return true;
  303. }
  304. char *command_str = mkstr(command);
  305. sesschan_start_backend(sess, command_str);
  306. sfree(command_str);
  307. return true;
  308. }
  309. bool sesschan_run_subsystem(Channel *chan, ptrlen subsys)
  310. {
  311. sesschan *sess = container_of(chan, sesschan, chan);
  312. if (ptrlen_eq_string(subsys, "sftp") && sess->sftpserver_vt) {
  313. sess->sftpsrv = sftpsrv_new(sess->sftpserver_vt);
  314. sess->chan.vt = &sftp_channelvt;
  315. logevent(sess->parent_logctx, "Starting built-in SFTP subsystem");
  316. return true;
  317. }
  318. return false;
  319. }
  320. static int xfwd_accepting(Plug *p, accept_fn_t constructor, accept_ctx_t ctx)
  321. {
  322. sesschan *sess = container_of(p, sesschan, xfwd_plug);
  323. Plug *plug;
  324. Channel *chan;
  325. Socket *s;
  326. SocketEndpointInfo *pi;
  327. const char *err;
  328. chan = portfwd_raw_new(sess->c->cl, &plug, false);
  329. s = constructor(ctx, plug);
  330. if ((err = sk_socket_error(s)) != NULL) {
  331. portfwd_raw_free(chan);
  332. return 1;
  333. }
  334. pi = sk_peer_info(s);
  335. portfwd_raw_setup(chan, s, ssh_serverside_x11_open(sess->c->cl, chan, pi));
  336. sk_free_endpoint_info(pi);
  337. return 0;
  338. }
  339. static const PlugVtable xfwd_plugvt = {
  340. .log = nullplug_log,
  341. .closing = nullplug_closing,
  342. .accepting = xfwd_accepting,
  343. };
  344. bool sesschan_enable_x11_forwarding(
  345. Channel *chan, bool oneshot, ptrlen authproto, ptrlen authdata_hex,
  346. unsigned screen_number)
  347. {
  348. sesschan *sess = container_of(chan, sesschan, chan);
  349. strbuf *authdata_bin;
  350. size_t i;
  351. if (oneshot)
  352. return false; /* not supported */
  353. /*
  354. * Decode the authorisation data from ASCII hex into binary.
  355. */
  356. if (authdata_hex.len % 2)
  357. return false; /* expected an even number of digits */
  358. authdata_bin = strbuf_new_nm();
  359. for (i = 0; i < authdata_hex.len; i += 2) {
  360. const unsigned char *hex = authdata_hex.ptr;
  361. char hexbuf[3];
  362. if (!isxdigit((unsigned char)hex[i]) ||
  363. !isxdigit((unsigned char)hex[i+1])) {
  364. strbuf_free(authdata_bin);
  365. return false; /* not hex */
  366. }
  367. hexbuf[0] = hex[i];
  368. hexbuf[1] = hex[i+1];
  369. hexbuf[2] = '\0';
  370. put_byte(authdata_bin, strtoul(hexbuf, NULL, 16));
  371. }
  372. sess->xfwd_plug.vt = &xfwd_plugvt;
  373. char *screensuffix = dupprintf(".%u", screen_number);
  374. sess->n_x11_sockets = platform_make_x11_server(
  375. &sess->xfwd_plug, appname, 10, screensuffix,
  376. authproto, ptrlen_from_strbuf(authdata_bin),
  377. sess->x11_sockets, sess->conf);
  378. sfree(screensuffix);
  379. strbuf_free(authdata_bin);
  380. return sess->n_x11_sockets != 0;
  381. }
  382. static int agentfwd_accepting(
  383. Plug *p, accept_fn_t constructor, accept_ctx_t ctx)
  384. {
  385. agentfwd *agent = container_of(p, agentfwd, plug);
  386. Plug *plug;
  387. Channel *chan;
  388. Socket *s;
  389. const char *err;
  390. chan = portfwd_raw_new(agent->cl, &plug, false);
  391. s = constructor(ctx, plug);
  392. if ((err = sk_socket_error(s)) != NULL) {
  393. portfwd_raw_free(chan);
  394. return 1;
  395. }
  396. portfwd_raw_setup(chan, s, ssh_serverside_agent_open(agent->cl, chan));
  397. return 0;
  398. }
  399. static const PlugVtable agentfwd_plugvt = {
  400. .log = nullplug_log,
  401. .closing = nullplug_closing,
  402. .accepting = agentfwd_accepting,
  403. };
  404. agentfwd *agentfwd_new(ConnectionLayer *cl, char **socketname_out)
  405. {
  406. agentfwd *agent = snew(agentfwd);
  407. agent->cl = cl;
  408. agent->plug.vt = &agentfwd_plugvt;
  409. char *dir_prefix = dupprintf("/tmp/%s-agentfwd", appname);
  410. char *error = NULL, *socketname = NULL;
  411. agent->socket = platform_make_agent_socket(
  412. &agent->plug, dir_prefix, &error, &socketname);
  413. sfree(dir_prefix);
  414. sfree(error);
  415. if (!agent->socket) {
  416. sfree(agent);
  417. sfree(socketname);
  418. return NULL;
  419. }
  420. *socketname_out = socketname;
  421. return agent;
  422. }
  423. void agentfwd_free(agentfwd *agent)
  424. {
  425. if (agent->socket)
  426. sk_close(agent->socket);
  427. sfree(agent);
  428. }
  429. bool sesschan_enable_agent_forwarding(Channel *chan)
  430. {
  431. sesschan *sess = container_of(chan, sesschan, chan);
  432. char *socketname;
  433. assert(!sess->agent);
  434. sess->agent = agentfwd_new(sess->c->cl, &socketname);
  435. if (!sess->agent)
  436. return false;
  437. conf_set_str_str(sess->conf, CONF_environmt, "SSH_AUTH_SOCK", socketname);
  438. sfree(socketname);
  439. return true;
  440. }
  441. bool sesschan_allocate_pty(
  442. Channel *chan, ptrlen termtype, unsigned width, unsigned height,
  443. unsigned pixwidth, unsigned pixheight, struct ssh_ttymodes modes)
  444. {
  445. sesschan *sess = container_of(chan, sesschan, chan);
  446. char *s;
  447. if (sess->want_pty)
  448. return false;
  449. s = mkstr(termtype);
  450. conf_set_str(sess->conf, CONF_termtype, s);
  451. sfree(s);
  452. sess->want_pty = true;
  453. sess->ttymodes = modes;
  454. sess->wc = width;
  455. sess->hc = height;
  456. sess->wp = pixwidth;
  457. sess->hp = pixheight;
  458. return true;
  459. }
  460. bool sesschan_set_env(Channel *chan, ptrlen var, ptrlen value)
  461. {
  462. sesschan *sess = container_of(chan, sesschan, chan);
  463. char *svar = mkstr(var), *svalue = mkstr(value);
  464. conf_set_str_str(sess->conf, CONF_environmt, svar, svalue);
  465. sfree(svar);
  466. sfree(svalue);
  467. return true;
  468. }
  469. bool sesschan_send_break(Channel *chan, unsigned length)
  470. {
  471. sesschan *sess = container_of(chan, sesschan, chan);
  472. if (sess->backend) {
  473. /* We ignore the break length. We could pass it through as the
  474. * 'arg' parameter, and have pty.c collect it and pass it on
  475. * to tcsendbreak, but since tcsendbreak in turn assigns
  476. * implementation-defined semantics to _its_ duration
  477. * parameter, this all just sounds too difficult. */
  478. backend_special(sess->backend, SS_BRK, 0);
  479. return true;
  480. }
  481. return false;
  482. }
  483. bool sesschan_send_signal(Channel *chan, ptrlen signame)
  484. {
  485. sesschan *sess = container_of(chan, sesschan, chan);
  486. /* Start with a code that definitely isn't a signal (or indeed a
  487. * special command at all), to indicate 'nothing matched'. */
  488. SessionSpecialCode code = SS_EXITMENU;
  489. #define SIGNAL_SUB(name) \
  490. if (ptrlen_eq_string(signame, #name)) code = SS_SIG ## name;
  491. #define SIGNAL_MAIN(name, text) SIGNAL_SUB(name)
  492. #include "signal-list.h"
  493. #undef SIGNAL_MAIN
  494. #undef SIGNAL_SUB
  495. if (code == SS_EXITMENU)
  496. return false;
  497. backend_special(sess->backend, code, 0);
  498. return true;
  499. }
  500. bool sesschan_change_window_size(
  501. Channel *chan, unsigned width, unsigned height,
  502. unsigned pixwidth, unsigned pixheight)
  503. {
  504. sesschan *sess = container_of(chan, sesschan, chan);
  505. if (!sess->want_pty)
  506. return false;
  507. sess->wc = width;
  508. sess->hc = height;
  509. sess->wp = pixwidth;
  510. sess->hp = pixheight;
  511. if (sess->backend)
  512. backend_size(sess->backend, sess->wc, sess->hc);
  513. return true;
  514. }
  515. static size_t sesschan_seat_output(
  516. Seat *seat, SeatOutputType type, const void *data, size_t len)
  517. {
  518. sesschan *sess = container_of(seat, sesschan, seat);
  519. return sshfwd_write_ext(sess->c, type == SEAT_OUTPUT_STDERR, data, len);
  520. }
  521. static void sesschan_check_close_callback(void *vctx)
  522. {
  523. sesschan *sess = (sesschan *)vctx;
  524. /*
  525. * Once we've seen incoming EOF from the backend (aka EIO from the
  526. * pty master) and also passed on the process's exit status, we
  527. * should proactively initiate closure of the session channel.
  528. */
  529. if (sess->seen_eof && sess->seen_exit)
  530. sshfwd_initiate_close(sess->c, NULL);
  531. }
  532. static bool sesschan_want_close(Channel *chan, bool seen_eof, bool rcvd_eof)
  533. {
  534. sesschan *sess = container_of(chan, sesschan, chan);
  535. /*
  536. * Similarly to above, we don't want to initiate channel closure
  537. * until we've sent the process's exit status, _even_ if EOF of
  538. * the actual data stream has happened in both directions.
  539. */
  540. return (sess->seen_eof && sess->seen_exit);
  541. }
  542. static bool sesschan_seat_eof(Seat *seat)
  543. {
  544. sesschan *sess = container_of(seat, sesschan, seat);
  545. sshfwd_write_eof(sess->c);
  546. sess->seen_eof = true;
  547. queue_toplevel_callback(sesschan_check_close_callback, sess);
  548. return true;
  549. }
  550. static void sesschan_notify_remote_exit(Seat *seat)
  551. {
  552. sesschan *sess = container_of(seat, sesschan, seat);
  553. if (!sess->backend)
  554. return;
  555. bool got_signal = false;
  556. if (!sess->ssc->exit_signal_numeric) {
  557. char *sigmsg;
  558. ptrlen signame = pty_backend_exit_signame(sess->backend, &sigmsg);
  559. if (signame.len) {
  560. if (!sigmsg)
  561. sigmsg = dupstr("");
  562. sshfwd_send_exit_signal(
  563. sess->c, signame, false, ptrlen_from_asciz(sigmsg));
  564. got_signal = true;
  565. }
  566. sfree(sigmsg);
  567. } else {
  568. int signum = pty_backend_exit_signum(sess->backend);
  569. if (signum >= 0) {
  570. sshfwd_send_exit_signal_numeric(sess->c, signum, false,
  571. PTRLEN_LITERAL(""));
  572. got_signal = true;
  573. }
  574. }
  575. if (!got_signal)
  576. sshfwd_send_exit_status(sess->c, backend_exitcode(sess->backend));
  577. sess->seen_exit = true;
  578. queue_toplevel_callback(sesschan_check_close_callback, sess);
  579. }
  580. static void sesschan_connection_fatal(Seat *seat, const char *message)
  581. {
  582. sesschan *sess = container_of(seat, sesschan, seat);
  583. /* Closest translation I can think of */
  584. sshfwd_send_exit_signal(
  585. sess->c, PTRLEN_LITERAL("HUP"), false, ptrlen_from_asciz(message));
  586. sess->ignoring_input = true;
  587. }
  588. static bool sesschan_get_window_pixel_size(Seat *seat, int *width, int *height)
  589. {
  590. sesschan *sess = container_of(seat, sesschan, seat);
  591. *width = sess->wp;
  592. *height = sess->hp;
  593. return true;
  594. }
  595. /* ----------------------------------------------------------------------
  596. * Built-in SFTP subsystem.
  597. */
  598. static size_t sftp_chan_send(Channel *chan, bool is_stderr,
  599. const void *data, size_t length)
  600. {
  601. sesschan *sess = container_of(chan, sesschan, chan);
  602. bufchain_add(&sess->subsys_input, data, length);
  603. while (bufchain_size(&sess->subsys_input) >= 4) {
  604. char lenbuf[4];
  605. unsigned pktlen;
  606. struct sftp_packet *pkt, *reply;
  607. bufchain_fetch(&sess->subsys_input, lenbuf, 4);
  608. pktlen = GET_32BIT_MSB_FIRST(lenbuf);
  609. if (bufchain_size(&sess->subsys_input) - 4 < pktlen)
  610. break; /* wait for more data */
  611. bufchain_consume(&sess->subsys_input, 4);
  612. pkt = sftp_recv_prepare(pktlen);
  613. bufchain_fetch_consume(&sess->subsys_input, pkt->data, pktlen);
  614. sftp_recv_finish(pkt);
  615. reply = sftp_handle_request(sess->sftpsrv, pkt);
  616. sftp_pkt_free(pkt);
  617. sftp_send_prepare(reply);
  618. sshfwd_write(sess->c, reply->data, reply->length);
  619. sftp_pkt_free(reply);
  620. }
  621. return 0;
  622. }
  623. static void sftp_chan_send_eof(Channel *chan)
  624. {
  625. sesschan *sess = container_of(chan, sesschan, chan);
  626. sshfwd_write_eof(sess->c);
  627. }
  628. static char *sftp_log_close_msg(Channel *chan)
  629. {
  630. return dupstr("Session channel (SFTP) closed");
  631. }
  632. /* ----------------------------------------------------------------------
  633. * Built-in SCP subsystem.
  634. */
  635. static size_t scp_chan_send(Channel *chan, bool is_stderr,
  636. const void *data, size_t length)
  637. {
  638. sesschan *sess = container_of(chan, sesschan, chan);
  639. return scp_send(sess->scpsrv, data, length);
  640. }
  641. static void scp_chan_send_eof(Channel *chan)
  642. {
  643. sesschan *sess = container_of(chan, sesschan, chan);
  644. scp_eof(sess->scpsrv);
  645. }
  646. static char *scp_log_close_msg(Channel *chan)
  647. {
  648. return dupstr("Session channel (SCP) closed");
  649. }
  650. static void scp_set_input_wanted(Channel *chan, bool wanted)
  651. {
  652. sesschan *sess = container_of(chan, sesschan, chan);
  653. scp_throttle(sess->scpsrv, !wanted);
  654. }