psocks.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. /*
  2. * Main program for Unix psocks.
  3. */
  4. #include <string.h>
  5. #include <errno.h>
  6. #include <sys/types.h>
  7. #include <sys/wait.h>
  8. #include <signal.h>
  9. #include <fcntl.h>
  10. #include <unistd.h>
  11. #include "putty.h"
  12. #include "ssh.h"
  13. #include "psocks.h"
  14. typedef struct PsocksDataSinkPopen {
  15. stdio_sink sink[2];
  16. PsocksDataSink pds;
  17. } PsocksDataSinkPopen;
  18. static void popen_free(PsocksDataSink *pds)
  19. {
  20. PsocksDataSinkPopen *pdsp = container_of(pds, PsocksDataSinkPopen, pds);
  21. for (size_t i = 0; i < 2; i++)
  22. pclose(pdsp->sink[i].fp);
  23. sfree(pdsp);
  24. }
  25. static PsocksDataSink *open_pipes(
  26. const char *cmd, const char *const *direction_args,
  27. const char *index_arg, char **err)
  28. {
  29. FILE *fp[2];
  30. char *errmsg = NULL;
  31. for (size_t i = 0; i < 2; i++) {
  32. /* No escaping needed: the provided command is already
  33. * shell-quoted, and our extra arguments are simple */
  34. char *command = dupprintf("%s %s %s", cmd,
  35. direction_args[i], index_arg);
  36. fp[i] = popen(command, "w");
  37. sfree(command);
  38. if (!fp[i]) {
  39. if (!errmsg)
  40. errmsg = dupprintf("%s", strerror(errno));
  41. }
  42. }
  43. if (errmsg) {
  44. for (size_t i = 0; i < 2; i++)
  45. if (fp[i])
  46. pclose(fp[i]);
  47. *err = errmsg;
  48. return NULL;
  49. }
  50. PsocksDataSinkPopen *pdsp = snew(PsocksDataSinkPopen);
  51. for (size_t i = 0; i < 2; i++) {
  52. setvbuf(fp[i], NULL, _IONBF, 0);
  53. stdio_sink_init(&pdsp->sink[i], fp[i]);
  54. pdsp->pds.s[i] = BinarySink_UPCAST(&pdsp->sink[i]);
  55. }
  56. pdsp->pds.free = popen_free;
  57. return &pdsp->pds;
  58. }
  59. static int signalpipe[2] = { -1, -1 };
  60. static void sigchld(int signum)
  61. {
  62. if (write(signalpipe[1], "x", 1) <= 0)
  63. /* not much we can do about it */;
  64. }
  65. static pid_t subcommand_pid = -1;
  66. static bool still_running = true;
  67. static char **exec_args = NULL;
  68. static void found_subcommand(CmdlineArg *arg)
  69. {
  70. exec_args = cmdline_arg_remainder(arg);
  71. }
  72. static void start_subcommand(void)
  73. {
  74. pid_t pid;
  75. /*
  76. * Set up the pipe we'll use to tell us about SIGCHLD.
  77. */
  78. if (pipe(signalpipe) < 0) {
  79. perror("pipe");
  80. exit(1);
  81. }
  82. putty_signal(SIGCHLD, sigchld);
  83. pid = fork();
  84. if (pid < 0) {
  85. perror("fork");
  86. exit(1);
  87. } else if (pid == 0) {
  88. execvp(exec_args[0], exec_args);
  89. perror("exec");
  90. _exit(127);
  91. } else {
  92. subcommand_pid = pid;
  93. }
  94. }
  95. static const PsocksPlatform platform = {
  96. open_pipes,
  97. found_subcommand,
  98. start_subcommand,
  99. };
  100. static bool psocks_pw_setup(void *ctx, pollwrapper *pw)
  101. {
  102. if (signalpipe[0] >= 0)
  103. pollwrap_add_fd_rwx(pw, signalpipe[0], SELECT_R);
  104. return true;
  105. }
  106. static void psocks_pw_check(void *ctx, pollwrapper *pw)
  107. {
  108. if (signalpipe[0] >= 0 &&
  109. pollwrap_check_fd_rwx(pw, signalpipe[0], SELECT_R)) {
  110. while (true) {
  111. int status;
  112. pid_t pid = waitpid(-1, &status, WNOHANG);
  113. if (pid <= 0)
  114. break;
  115. if (pid == subcommand_pid)
  116. still_running = false;
  117. }
  118. }
  119. }
  120. static bool psocks_continue(void *ctx, bool found_any_fd,
  121. bool ran_any_callback)
  122. {
  123. return still_running;
  124. }
  125. int main(int argc, char **argv)
  126. {
  127. psocks_state *ps = psocks_new(&platform);
  128. CmdlineArgList *arglist = cmdline_arg_list_from_argv(argc, argv);
  129. psocks_cmdline(ps, arglist);
  130. sk_init();
  131. uxsel_init();
  132. psocks_start(ps);
  133. cmdline_arg_list_free(arglist);
  134. cli_main_loop(psocks_pw_setup, psocks_pw_check, psocks_continue, NULL);
  135. }