geom_gate userland utility improvements
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

477 lines
12 KiB

  1. /*
  2. *
  3. * Sample showing how to makes SSH2 with X11 Forwarding works.
  4. *
  5. * Usage :
  6. * "ssh2 host user password [DEBUG]"
  7. */
  8. #include <string.h>
  9. #include <sys/ioctl.h>
  10. #include <netinet/in.h>
  11. #include <sys/socket.h>
  12. #include <sys/select.h>
  13. #include <arpa/inet.h>
  14. #include <unistd.h>
  15. #include <sys/types.h>
  16. #include <sys/un.h>
  17. #include <fcntl.h>
  18. #include <errno.h>
  19. #include <stdio.h>
  20. #include <ctype.h>
  21. #include <stdlib.h>
  22. #include <termios.h>
  23. #include <libssh2.h>
  24. #define _PATH_UNIX_X "/tmp/.X11-unix/X%d"
  25. /*
  26. * Chained list that contains channels and associated X11 socket for each X11
  27. * connections
  28. */
  29. struct chan_X11_list {
  30. LIBSSH2_CHANNEL *chan;
  31. int sock;
  32. struct chan_X11_list *next;
  33. };
  34. struct chan_X11_list * gp_x11_chan = NULL;
  35. struct termios _saved_tio;
  36. /*
  37. * Utility function to remove a Node of the chained list
  38. */
  39. static void remove_node(struct chan_X11_list *elem)
  40. {
  41. struct chan_X11_list *current_node = NULL;
  42. current_node = gp_x11_chan;
  43. if(gp_x11_chan == elem) {
  44. gp_x11_chan = gp_x11_chan->next;
  45. free(current_node);
  46. return;
  47. }
  48. while(current_node->next != NULL) {
  49. if(current_node->next == elem) {
  50. current_node->next = current_node->next->next;
  51. current_node = current_node->next;
  52. free(current_node);
  53. break;
  54. }
  55. }
  56. }
  57. static void session_shutdown(LIBSSH2_SESSION *session)
  58. {
  59. libssh2_session_disconnect(session,
  60. "Session Shutdown, Thank you for playing");
  61. libssh2_session_free(session);
  62. }
  63. static int _raw_mode(void)
  64. {
  65. int rc;
  66. struct termios tio;
  67. rc = tcgetattr(fileno(stdin), &tio);
  68. if(rc != -1) {
  69. _saved_tio = tio;
  70. /* do the equivalent of cfmakeraw() manually, to build on Solaris */
  71. tio.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
  72. tio.c_oflag &= ~OPOST;
  73. tio.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
  74. tio.c_cflag &= ~(CSIZE|PARENB);
  75. tio.c_cflag |= CS8;
  76. rc = tcsetattr(fileno(stdin), TCSADRAIN, &tio);
  77. }
  78. return rc;
  79. }
  80. static int _normal_mode(void)
  81. {
  82. int rc;
  83. rc = tcsetattr(fileno(stdin), TCSADRAIN, &_saved_tio);
  84. return rc;
  85. }
  86. /*
  87. * CallBack to initialize the forwarding.
  88. * Save the channel to loop on it, save the X11 forwarded socket to send
  89. * and receive info from our X server.
  90. */
  91. static void x11_callback(LIBSSH2_SESSION *session, LIBSSH2_CHANNEL *channel,
  92. char *shost, int sport, void **abstract)
  93. {
  94. const char *display = NULL;
  95. char *ptr = NULL;
  96. char *temp_buff = NULL;
  97. int display_port = 0;
  98. int sock = 0;
  99. int rc = 0;
  100. struct sockaddr_un addr;
  101. struct chan_X11_list *new;
  102. struct chan_X11_list *chan_iter;
  103. (void)session;
  104. (void)shost;
  105. (void)sport;
  106. (void)abstract;
  107. /*
  108. * Connect to the display
  109. * Inspired by x11_connect_display in openssh
  110. */
  111. display = getenv("DISPLAY");
  112. if(display != NULL) {
  113. if(strncmp(display, "unix:", 5) == 0 ||
  114. display[0] == ':') {
  115. /* Connect to the local unix domain */
  116. ptr = strrchr(display, ':');
  117. temp_buff = (char *) calloc(strlen(ptr + 1), sizeof(char));
  118. if(!temp_buff) {
  119. perror("calloc");
  120. return;
  121. }
  122. memcpy(temp_buff, ptr + 1, strlen(ptr + 1));
  123. display_port = atoi(temp_buff);
  124. free(temp_buff);
  125. sock = socket(AF_UNIX, SOCK_STREAM, 0);
  126. if(sock < 0)
  127. return;
  128. memset(&addr, 0, sizeof(addr));
  129. addr.sun_family = AF_UNIX;
  130. snprintf(addr.sun_path, sizeof(addr.sun_path),
  131. _PATH_UNIX_X, display_port);
  132. rc = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
  133. if(rc != -1) {
  134. /* Connection Successfull */
  135. if(gp_x11_chan == NULL) {
  136. /* Calloc ensure that gp_X11_chan is full of 0 */
  137. gp_x11_chan = (struct chan_X11_list *)
  138. calloc(1, sizeof(struct chan_X11_list));
  139. gp_x11_chan->sock = sock;
  140. gp_x11_chan->chan = channel;
  141. gp_x11_chan->next = NULL;
  142. }
  143. else {
  144. chan_iter = gp_x11_chan;
  145. while(chan_iter->next != NULL)
  146. chan_iter = chan_iter->next;
  147. /* Create the new Node */
  148. new = (struct chan_X11_list *)
  149. malloc(sizeof(struct chan_X11_list));
  150. new->sock = sock;
  151. new->chan = channel;
  152. new->next = NULL;
  153. chan_iter->next = new;
  154. }
  155. }
  156. else
  157. close(sock);
  158. }
  159. }
  160. return;
  161. }
  162. /*
  163. * Send and receive Data for the X11 channel.
  164. * If the connection is closed, returns -1, 0 either.
  165. */
  166. static int x11_send_receive(LIBSSH2_CHANNEL *channel, int sock)
  167. {
  168. char *buf = NULL;
  169. int bufsize = 8192;
  170. int rc = 0;
  171. int nfds = 1;
  172. LIBSSH2_POLLFD *fds = NULL;
  173. fd_set set;
  174. struct timeval timeval_out;
  175. timeval_out.tv_sec = 0;
  176. timeval_out.tv_usec = 0;
  177. FD_ZERO(&set);
  178. FD_SET(sock, &set);
  179. buf = calloc(bufsize, sizeof(char));
  180. if(!buf)
  181. return 0;
  182. fds = malloc(sizeof (LIBSSH2_POLLFD));
  183. if(!fds) {
  184. free(buf);
  185. return 0;
  186. }
  187. fds[0].type = LIBSSH2_POLLFD_CHANNEL;
  188. fds[0].fd.channel = channel;
  189. fds[0].events = LIBSSH2_POLLFD_POLLIN;
  190. fds[0].revents = LIBSSH2_POLLFD_POLLIN;
  191. rc = libssh2_poll(fds, nfds, 0);
  192. if(rc >0) {
  193. rc = libssh2_channel_read(channel, buf, bufsize);
  194. write(sock, buf, rc);
  195. }
  196. rc = select(sock + 1, &set, NULL, NULL, &timeval_out);
  197. if(rc > 0) {
  198. memset((void *)buf, 0, bufsize);
  199. /* Data in sock*/
  200. rc = read(sock, buf, bufsize);
  201. if(rc > 0) {
  202. libssh2_channel_write(channel, buf, rc);
  203. }
  204. else {
  205. free(buf);
  206. return -1;
  207. }
  208. }
  209. free(fds);
  210. free(buf);
  211. if(libssh2_channel_eof(channel) == 1) {
  212. return -1;
  213. }
  214. return 0;
  215. }
  216. /*
  217. * Main, more than inspired by ssh2.c by Bagder
  218. */
  219. int
  220. main (int argc, char *argv[])
  221. {
  222. unsigned long hostaddr = 0;
  223. int sock = 0;
  224. int rc = 0;
  225. struct sockaddr_in sin;
  226. LIBSSH2_SESSION *session;
  227. LIBSSH2_CHANNEL *channel;
  228. char *username = NULL;
  229. char *password = NULL;
  230. size_t bufsiz = 8193;
  231. char *buf = NULL;
  232. int set_debug_on = 0;
  233. int nfds = 1;
  234. LIBSSH2_POLLFD *fds = NULL;
  235. /* Chan List struct */
  236. struct chan_X11_list *current_node = NULL;
  237. /* Struct winsize for term size */
  238. struct winsize w_size;
  239. struct winsize w_size_bck;
  240. /* For select on stdin */
  241. fd_set set;
  242. struct timeval timeval_out;
  243. timeval_out.tv_sec = 0;
  244. timeval_out.tv_usec = 10;
  245. if(argc > 3) {
  246. hostaddr = inet_addr(argv[1]);
  247. username = argv[2];
  248. password = argv[3];
  249. }
  250. else {
  251. fprintf(stderr, "Usage: %s destination username password",
  252. argv[0]);
  253. return -1;
  254. }
  255. if(argc > 4) {
  256. set_debug_on = 1;
  257. fprintf(stderr, "DEBUG is ON: %d\n", set_debug_on);
  258. }
  259. rc = libssh2_init(0);
  260. if(rc != 0) {
  261. fprintf(stderr, "libssh2 initialization failed (%d)\n", rc);
  262. return 1;
  263. }
  264. sock = socket(AF_INET, SOCK_STREAM, 0);
  265. if(sock == -1) {
  266. perror("socket");
  267. return -1;
  268. }
  269. sin.sin_family = AF_INET;
  270. sin.sin_port = htons(22);
  271. sin.sin_addr.s_addr = hostaddr;
  272. rc = connect(sock, (struct sockaddr *) &sin,
  273. sizeof(struct sockaddr_in));
  274. if(rc != 0) {
  275. fprintf(stderr, "Failed to established connection!\n");
  276. return -1;
  277. }
  278. /* Open a session */
  279. session = libssh2_session_init();
  280. rc = libssh2_session_handshake(session, sock);
  281. if(rc != 0) {
  282. fprintf(stderr, "Failed Start the SSH session\n");
  283. return -1;
  284. }
  285. if(set_debug_on == 1)
  286. libssh2_trace(session, LIBSSH2_TRACE_CONN);
  287. /* ignore pedantic warnings by gcc on the callback argument */
  288. #pragma GCC diagnostic push
  289. #pragma GCC diagnostic ignored "-Wpedantic"
  290. /* Set X11 Callback */
  291. libssh2_session_callback_set(session, LIBSSH2_CALLBACK_X11,
  292. (void *)x11_callback);
  293. #pragma GCC diagnostic pop
  294. /* Authenticate via password */
  295. rc = libssh2_userauth_password(session, username, password);
  296. if(rc != 0) {
  297. fprintf(stderr, "Failed to authenticate\n");
  298. session_shutdown(session);
  299. close(sock);
  300. return -1;
  301. }
  302. /* Open a channel */
  303. channel = libssh2_channel_open_session(session);
  304. if(channel == NULL) {
  305. fprintf(stderr, "Failed to open a new channel\n");
  306. session_shutdown(session);
  307. close(sock);
  308. return -1;
  309. }
  310. /* Request a PTY */
  311. rc = libssh2_channel_request_pty(channel, "xterm");
  312. if(rc != 0) {
  313. fprintf(stderr, "Failed to request a pty\n");
  314. session_shutdown(session);
  315. close(sock);
  316. return -1;
  317. }
  318. /* Request X11 */
  319. rc = libssh2_channel_x11_req(channel, 0);
  320. if(rc != 0) {
  321. fprintf(stderr, "Failed to request X11 forwarding\n");
  322. session_shutdown(session);
  323. close(sock);
  324. return -1;
  325. }
  326. /* Request a shell */
  327. rc = libssh2_channel_shell(channel);
  328. if(rc != 0) {
  329. fprintf(stderr, "Failed to open a shell\n");
  330. session_shutdown(session);
  331. close(sock);
  332. return -1;
  333. }
  334. rc = _raw_mode();
  335. if(rc != 0) {
  336. fprintf(stderr, "Failed to entered in raw mode\n");
  337. session_shutdown(session);
  338. close(sock);
  339. return -1;
  340. }
  341. memset(&w_size, 0, sizeof(struct winsize));
  342. memset(&w_size_bck, 0, sizeof(struct winsize));
  343. while(1) {
  344. FD_ZERO(&set);
  345. FD_SET(fileno(stdin), &set);
  346. /* Search if a resize pty has to be send */
  347. ioctl(fileno(stdin), TIOCGWINSZ, &w_size);
  348. if((w_size.ws_row != w_size_bck.ws_row) ||
  349. (w_size.ws_col != w_size_bck.ws_col)) {
  350. w_size_bck = w_size;
  351. libssh2_channel_request_pty_size(channel,
  352. w_size.ws_col,
  353. w_size.ws_row);
  354. }
  355. buf = calloc(bufsiz, sizeof(char));
  356. if(buf == NULL)
  357. break;
  358. fds = malloc(sizeof (LIBSSH2_POLLFD));
  359. if(fds == NULL) {
  360. free(buf);
  361. break;
  362. }
  363. fds[0].type = LIBSSH2_POLLFD_CHANNEL;
  364. fds[0].fd.channel = channel;
  365. fds[0].events = LIBSSH2_POLLFD_POLLIN;
  366. fds[0].revents = LIBSSH2_POLLFD_POLLIN;
  367. rc = libssh2_poll(fds, nfds, 0);
  368. if(rc >0) {
  369. libssh2_channel_read(channel, buf, sizeof(buf));
  370. fprintf(stdout, "%s", buf);
  371. fflush(stdout);
  372. }
  373. /* Looping on X clients */
  374. if(gp_x11_chan != NULL) {
  375. current_node = gp_x11_chan;
  376. }
  377. else
  378. current_node = NULL;
  379. while(current_node != NULL) {
  380. struct chan_X11_list *next_node;
  381. rc = x11_send_receive(current_node->chan, current_node->sock);
  382. next_node = current_node->next;
  383. if(rc == -1) {
  384. shutdown(current_node->sock, SHUT_RDWR);
  385. close(current_node->sock);
  386. remove_node(current_node);
  387. }
  388. current_node = next_node;
  389. }
  390. rc = select(fileno(stdin) + 1, &set, NULL, NULL, &timeval_out);
  391. if(rc > 0) {
  392. /* Data in stdin*/
  393. rc = read(fileno(stdin), buf, 1);
  394. if(rc > 0)
  395. libssh2_channel_write(channel, buf, sizeof(buf));
  396. }
  397. free(fds);
  398. free(buf);
  399. if(libssh2_channel_eof (channel) == 1) {
  400. break;
  401. }
  402. }
  403. if(channel) {
  404. libssh2_channel_free(channel);
  405. channel = NULL;
  406. }
  407. _normal_mode();
  408. libssh2_exit();
  409. return 0;
  410. }