remove unused variable
[dropbear.git] / svr-x11fwd.c
blob7618e3b69414184902a70e27067bbaecdd66c6c3
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:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
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. */
25 #include "includes.h"
27 #ifndef DISABLE_X11FWD
28 #include "x11fwd.h"
29 #include "session.h"
30 #include "ssh.h"
31 #include "dbutil.h"
32 #include "chansession.h"
33 #include "channel.h"
34 #include "packet.h"
35 #include "buffer.h"
36 #include "auth.h"
38 #define X11BASEPORT 6000
39 #define X11BINDBASE 6010
41 static void x11accept(struct Listener* listener, int sock);
42 static int bindport(int fd);
43 static int send_msg_channel_open_x11(int fd, struct sockaddr_in* addr);
45 /* called as a request for a session channel, sets up listening X11 */
46 /* returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
47 int x11req(struct ChanSess * chansess) {
49 int fd;
51 if (!svr_pubkey_allows_x11fwd()) {
52 return DROPBEAR_FAILURE;
55 /* we already have an x11 connection */
56 if (chansess->x11listener != NULL) {
57 return DROPBEAR_FAILURE;
60 chansess->x11singleconn = buf_getbool(ses.payload);
61 chansess->x11authprot = buf_getstring(ses.payload, NULL);
62 chansess->x11authcookie = buf_getstring(ses.payload, NULL);
63 chansess->x11screennum = buf_getint(ses.payload);
65 /* create listening socket */
66 fd = socket(PF_INET, SOCK_STREAM, 0);
67 if (fd < 0) {
68 goto fail;
71 /* allocate port and bind */
72 chansess->x11port = bindport(fd);
73 if (chansess->x11port < 0) {
74 goto fail;
77 /* listen */
78 if (listen(fd, 20) < 0) {
79 goto fail;
82 /* set non-blocking */
83 setnonblocking(fd);
85 /* listener code will handle the socket now.
86 * No cleanup handler needed, since listener_remove only happens
87 * from our cleanup anyway */
88 chansess->x11listener = new_listener( &fd, 1, 0, chansess, x11accept, NULL);
89 if (chansess->x11listener == NULL) {
90 goto fail;
93 return DROPBEAR_SUCCESS;
95 fail:
96 /* cleanup */
97 m_free(chansess->x11authprot);
98 m_free(chansess->x11authcookie);
99 close(fd);
101 return DROPBEAR_FAILURE;
104 /* accepts a new X11 socket */
105 /* returns DROPBEAR_FAILURE or DROPBEAR_SUCCESS */
106 static void x11accept(struct Listener* listener, int sock) {
108 int fd;
109 struct sockaddr_in addr;
110 int len;
111 int ret;
112 struct ChanSess * chansess = (struct ChanSess *)(listener->typedata);
114 len = sizeof(addr);
116 fd = accept(sock, (struct sockaddr*)&addr, &len);
117 if (fd < 0) {
118 return;
121 /* if single-connection we close it up */
122 if (chansess->x11singleconn) {
123 x11cleanup(chansess);
126 ret = send_msg_channel_open_x11(fd, &addr);
127 if (ret == DROPBEAR_FAILURE) {
128 close(fd);
132 /* This is called after switching to the user, and sets up the xauth
133 * and environment variables. */
134 void x11setauth(struct ChanSess *chansess) {
136 char display[20]; /* space for "localhost:12345.123" */
137 FILE * authprog = NULL;
138 int val;
140 if (chansess->x11listener == NULL) {
141 return;
144 /* create the DISPLAY string */
145 val = snprintf(display, sizeof(display), "localhost:%d.%d",
146 chansess->x11port - X11BASEPORT, chansess->x11screennum);
147 if (val < 0 || val >= (int)sizeof(display)) {
148 /* string was truncated */
149 return;
152 addnewvar("DISPLAY", display);
154 /* create the xauth string */
155 val = snprintf(display, sizeof(display), "unix:%d.%d",
156 chansess->x11port - X11BASEPORT, chansess->x11screennum);
157 if (val < 0 || val >= (int)sizeof(display)) {
158 /* string was truncated */
159 return;
162 /* popen is a nice function - code is strongly based on OpenSSH's */
163 authprog = popen(XAUTH_COMMAND, "w");
164 if (authprog) {
165 fprintf(authprog, "add %s %s %s\n",
166 display, chansess->x11authprot, chansess->x11authcookie);
167 pclose(authprog);
168 } else {
169 fprintf(stderr, "Failed to run %s\n", XAUTH_COMMAND);
173 void x11cleanup(struct ChanSess *chansess) {
175 m_free(chansess->x11authprot);
176 m_free(chansess->x11authcookie);
178 TRACE(("chansess %s", chansess))
179 if (chansess->x11listener != NULL) {
180 remove_listener(chansess->x11listener);
181 chansess->x11listener = NULL;
185 static const struct ChanType chan_x11 = {
186 0, /* sepfds */
187 "x11",
188 NULL, /* inithandler */
189 NULL, /* checkclose */
190 NULL, /* reqhandler */
191 NULL /* closehandler */
195 static int send_msg_channel_open_x11(int fd, struct sockaddr_in* addr) {
197 char* ipstring = NULL;
199 if (send_msg_channel_open_init(fd, &chan_x11) == DROPBEAR_SUCCESS) {
200 ipstring = inet_ntoa(addr->sin_addr);
201 buf_putstring(ses.writepayload, ipstring, strlen(ipstring));
202 buf_putint(ses.writepayload, addr->sin_port);
204 encrypt_packet();
205 return DROPBEAR_SUCCESS;
206 } else {
207 return DROPBEAR_FAILURE;
212 /* returns the port bound to, or -1 on failure.
213 * Will attempt to bind to a port X11BINDBASE (6010 usually) or upwards */
214 static int bindport(int fd) {
216 struct sockaddr_in addr;
217 uint16_t port;
219 memset((void*)&addr, 0x0, sizeof(addr));
220 addr.sin_family = AF_INET;
221 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
223 /* if we can't find one in 2000 ports free, something's wrong */
224 for (port = X11BINDBASE; port < X11BINDBASE + 2000; port++) {
225 addr.sin_port = htons(port);
226 if (bind(fd, (struct sockaddr*)&addr,
227 sizeof(struct sockaddr_in)) == 0) {
228 /* success */
229 return port;
231 if (errno == EADDRINUSE) {
232 /* try the next port */
233 continue;
235 /* otherwise it was an error we don't know about */
236 dropbear_log(LOG_DEBUG, "failed to bind x11 socket");
237 break;
239 return -1;
241 #endif /* DROPBEAR_X11FWD */