PageRenderTime 42ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 0ms

/release/src/router/dropbear/svr-x11fwd.c

https://gitlab.com/envieidoc/tomato
C | 241 lines | 147 code | 44 blank | 50 comment | 30 complexity | 8ea00e9707dae8ed8bc9a65ea6d64b9e MD5 | raw file
  1. /*
  2. * Dropbear - a SSH2 server
  3. *
  4. * Copyright (c) 2002,2003 Matt Johnston
  5. * All rights reserved.
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining a copy
  8. * of this software and associated documentation files (the "Software"), to deal
  9. * in the Software without restriction, including without limitation the rights
  10. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. * copies of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included in
  15. * all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  23. * SOFTWARE. */
  24. #include "includes.h"
  25. #ifndef DISABLE_X11FWD
  26. #include "x11fwd.h"
  27. #include "session.h"
  28. #include "ssh.h"
  29. #include "dbutil.h"
  30. #include "chansession.h"
  31. #include "channel.h"
  32. #include "packet.h"
  33. #include "buffer.h"
  34. #include "auth.h"
  35. #define X11BASEPORT 6000
  36. #define X11BINDBASE 6010
  37. static void x11accept(struct Listener* listener, int sock);
  38. static int bindport(int fd);
  39. static int send_msg_channel_open_x11(int fd, struct sockaddr_in* addr);
  40. /* called as a request for a session channel, sets up listening X11 */
  41. /* returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
  42. int x11req(struct ChanSess * chansess) {
  43. int fd;
  44. if (!svr_pubkey_allows_x11fwd()) {
  45. return DROPBEAR_FAILURE;
  46. }
  47. /* we already have an x11 connection */
  48. if (chansess->x11listener != NULL) {
  49. return DROPBEAR_FAILURE;
  50. }
  51. chansess->x11singleconn = buf_getbool(ses.payload);
  52. chansess->x11authprot = buf_getstring(ses.payload, NULL);
  53. chansess->x11authcookie = buf_getstring(ses.payload, NULL);
  54. chansess->x11screennum = buf_getint(ses.payload);
  55. /* create listening socket */
  56. fd = socket(PF_INET, SOCK_STREAM, 0);
  57. if (fd < 0) {
  58. goto fail;
  59. }
  60. /* allocate port and bind */
  61. chansess->x11port = bindport(fd);
  62. if (chansess->x11port < 0) {
  63. goto fail;
  64. }
  65. /* listen */
  66. if (listen(fd, 20) < 0) {
  67. goto fail;
  68. }
  69. /* set non-blocking */
  70. setnonblocking(fd);
  71. /* listener code will handle the socket now.
  72. * No cleanup handler needed, since listener_remove only happens
  73. * from our cleanup anyway */
  74. chansess->x11listener = new_listener( &fd, 1, 0, chansess, x11accept, NULL);
  75. if (chansess->x11listener == NULL) {
  76. goto fail;
  77. }
  78. return DROPBEAR_SUCCESS;
  79. fail:
  80. /* cleanup */
  81. m_free(chansess->x11authprot);
  82. m_free(chansess->x11authcookie);
  83. close(fd);
  84. return DROPBEAR_FAILURE;
  85. }
  86. /* accepts a new X11 socket */
  87. /* returns DROPBEAR_FAILURE or DROPBEAR_SUCCESS */
  88. static void x11accept(struct Listener* listener, int sock) {
  89. int fd;
  90. struct sockaddr_in addr;
  91. int len;
  92. int ret;
  93. struct ChanSess * chansess = (struct ChanSess *)(listener->typedata);
  94. len = sizeof(addr);
  95. fd = accept(sock, (struct sockaddr*)&addr, &len);
  96. if (fd < 0) {
  97. return;
  98. }
  99. /* if single-connection we close it up */
  100. if (chansess->x11singleconn) {
  101. x11cleanup(chansess);
  102. }
  103. ret = send_msg_channel_open_x11(fd, &addr);
  104. if (ret == DROPBEAR_FAILURE) {
  105. close(fd);
  106. }
  107. }
  108. /* This is called after switching to the user, and sets up the xauth
  109. * and environment variables. */
  110. void x11setauth(struct ChanSess *chansess) {
  111. char display[20]; /* space for "localhost:12345.123" */
  112. FILE * authprog = NULL;
  113. int val;
  114. if (chansess->x11listener == NULL) {
  115. return;
  116. }
  117. /* create the DISPLAY string */
  118. val = snprintf(display, sizeof(display), "localhost:%d.%d",
  119. chansess->x11port - X11BASEPORT, chansess->x11screennum);
  120. if (val < 0 || val >= (int)sizeof(display)) {
  121. /* string was truncated */
  122. return;
  123. }
  124. addnewvar("DISPLAY", display);
  125. /* create the xauth string */
  126. val = snprintf(display, sizeof(display), "unix:%d.%d",
  127. chansess->x11port - X11BASEPORT, chansess->x11screennum);
  128. if (val < 0 || val >= (int)sizeof(display)) {
  129. /* string was truncated */
  130. return;
  131. }
  132. /* popen is a nice function - code is strongly based on OpenSSH's */
  133. authprog = popen(XAUTH_COMMAND, "w");
  134. if (authprog) {
  135. fprintf(authprog, "add %s %s %s\n",
  136. display, chansess->x11authprot, chansess->x11authcookie);
  137. pclose(authprog);
  138. } else {
  139. fprintf(stderr, "Failed to run %s\n", XAUTH_COMMAND);
  140. }
  141. }
  142. void x11cleanup(struct ChanSess *chansess) {
  143. m_free(chansess->x11authprot);
  144. m_free(chansess->x11authcookie);
  145. TRACE(("chansess %p", chansess))
  146. if (chansess->x11listener != NULL) {
  147. remove_listener(chansess->x11listener);
  148. chansess->x11listener = NULL;
  149. }
  150. }
  151. static const struct ChanType chan_x11 = {
  152. 0, /* sepfds */
  153. "x11",
  154. NULL, /* inithandler */
  155. NULL, /* checkclose */
  156. NULL, /* reqhandler */
  157. NULL /* closehandler */
  158. };
  159. static int send_msg_channel_open_x11(int fd, struct sockaddr_in* addr) {
  160. char* ipstring = NULL;
  161. if (send_msg_channel_open_init(fd, &chan_x11) == DROPBEAR_SUCCESS) {
  162. ipstring = inet_ntoa(addr->sin_addr);
  163. buf_putstring(ses.writepayload, ipstring, strlen(ipstring));
  164. buf_putint(ses.writepayload, addr->sin_port);
  165. encrypt_packet();
  166. return DROPBEAR_SUCCESS;
  167. } else {
  168. return DROPBEAR_FAILURE;
  169. }
  170. }
  171. /* returns the port bound to, or -1 on failure.
  172. * Will attempt to bind to a port X11BINDBASE (6010 usually) or upwards */
  173. static int bindport(int fd) {
  174. struct sockaddr_in addr;
  175. uint16_t port;
  176. memset((void*)&addr, 0x0, sizeof(addr));
  177. addr.sin_family = AF_INET;
  178. addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  179. /* if we can't find one in 2000 ports free, something's wrong */
  180. for (port = X11BINDBASE; port < X11BINDBASE + 2000; port++) {
  181. addr.sin_port = htons(port);
  182. if (bind(fd, (struct sockaddr*)&addr,
  183. sizeof(struct sockaddr_in)) == 0) {
  184. /* success */
  185. return port;
  186. }
  187. if (errno == EADDRINUSE) {
  188. /* try the next port */
  189. continue;
  190. }
  191. /* otherwise it was an error we don't know about */
  192. dropbear_log(LOG_DEBUG, "Failed to bind x11 socket");
  193. break;
  194. }
  195. return -1;
  196. }
  197. #endif /* DROPBEAR_X11FWD */