comparison svr-tcpfwd.c @ 673:c519b78b6d1a

- Don't sent SSH_MSG_UNIMPLEMENTED if we don't have ENABLE_SVR_REMOTETCPFWD - Fix build if ENABLE_SVR_REMOTETCPFWD is disabled but ENABLE_SVR_LOCALTCPFWD is enabled
author Matt Johnston <matt@ucc.asn.au>
date Wed, 09 May 2012 20:33:16 +0800
parents 79d48028457c
children dfdb9d9189ff
comparison
equal deleted inserted replaced
672:6c35ff40e496 673:c519b78b6d1a
32 #include "packet.h" 32 #include "packet.h"
33 #include "listener.h" 33 #include "listener.h"
34 #include "runopts.h" 34 #include "runopts.h"
35 #include "auth.h" 35 #include "auth.h"
36 36
37 #ifdef ENABLE_SVR_REMOTETCPFWD 37 static void send_msg_request_failure();
38
39 static void send_msg_request_failure() {
40 CHECKCLEARTOWRITE();
41 buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_FAILURE);
42 encrypt_packet();
43 }
44
45 #ifndef ENABLE_SVR_REMOTETCPFWD
46
47 /* This is better than SSH_MSG_UNIMPLEMENTED */
48 void recv_msg_global_request_remotetcp() {
49 TRACE(("recv_msg_global_request_remotetcp: remote tcp forwarding not compiled in"))
50 send_msg_request_failure();
51 }
52
53 /* */
54 #endif /* !ENABLE_SVR_REMOTETCPFWD */
38 55
39 static void send_msg_request_success(); 56 static void send_msg_request_success();
40 static void send_msg_request_failure();
41 static int svr_cancelremotetcp(); 57 static int svr_cancelremotetcp();
42 static int svr_remotetcpreq(); 58 static int svr_remotetcpreq();
43 static int newtcpdirect(struct Channel * channel); 59 static int newtcpdirect(struct Channel * channel);
44 60
61 #ifdef ENABLE_SVR_REMOTETCPFWD
62 static const struct ChanType svr_chan_tcpremote = {
63 1, /* sepfds */
64 "forwarded-tcpip",
65 NULL,
66 NULL,
67 NULL,
68 NULL
69 };
70
71 /* At the moment this is completely used for tcp code (with the name reflecting
72 * that). If new request types are added, this should be replaced with code
73 * similar to the request-switching in chansession.c */
74 void recv_msg_global_request_remotetcp() {
75
76 unsigned char* reqname = NULL;
77 unsigned int namelen;
78 unsigned int wantreply = 0;
79 int ret = DROPBEAR_FAILURE;
80
81 TRACE(("enter recv_msg_global_request_remotetcp"))
82
83 if (svr_opts.noremotetcp || !svr_pubkey_allows_tcpfwd()) {
84 TRACE(("leave recv_msg_global_request_remotetcp: remote tcp forwarding disabled"))
85 goto out;
86 }
87
88 reqname = buf_getstring(ses.payload, &namelen);
89 wantreply = buf_getbool(ses.payload);
90
91 if (namelen > MAX_NAME_LEN) {
92 TRACE(("name len is wrong: %d", namelen))
93 goto out;
94 }
95
96 if (strcmp("tcpip-forward", reqname) == 0) {
97 ret = svr_remotetcpreq();
98 } else if (strcmp("cancel-tcpip-forward", reqname) == 0) {
99 ret = svr_cancelremotetcp();
100 } else {
101 TRACE(("reqname isn't tcpip-forward: '%s'", reqname))
102 }
103
104 out:
105 if (wantreply) {
106 if (ret == DROPBEAR_SUCCESS) {
107 send_msg_request_success();
108 } else {
109 send_msg_request_failure();
110 }
111 }
112
113 m_free(reqname);
114
115 TRACE(("leave recv_msg_global_request"))
116 }
117
118
119 static void send_msg_request_success() {
120
121 CHECKCLEARTOWRITE();
122 buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_SUCCESS);
123 encrypt_packet();
124
125 }
126
127 static int matchtcp(void* typedata1, void* typedata2) {
128
129 const struct TCPListener *info1 = (struct TCPListener*)typedata1;
130 const struct TCPListener *info2 = (struct TCPListener*)typedata2;
131
132 return (info1->listenport == info2->listenport)
133 && (info1->chantype == info2->chantype)
134 && (strcmp(info1->listenaddr, info2->listenaddr) == 0);
135 }
136
137 static int svr_cancelremotetcp() {
138
139 int ret = DROPBEAR_FAILURE;
140 unsigned char * bindaddr = NULL;
141 unsigned int addrlen;
142 unsigned int port;
143 struct Listener * listener = NULL;
144 struct TCPListener tcpinfo;
145
146 TRACE(("enter cancelremotetcp"))
147
148 bindaddr = buf_getstring(ses.payload, &addrlen);
149 if (addrlen > MAX_IP_LEN) {
150 TRACE(("addr len too long: %d", addrlen))
151 goto out;
152 }
153
154 port = buf_getint(ses.payload);
155
156 tcpinfo.sendaddr = NULL;
157 tcpinfo.sendport = 0;
158 tcpinfo.listenaddr = bindaddr;
159 tcpinfo.listenport = port;
160 listener = get_listener(CHANNEL_ID_TCPFORWARDED, &tcpinfo, matchtcp);
161 if (listener) {
162 remove_listener( listener );
163 ret = DROPBEAR_SUCCESS;
164 }
165
166 out:
167 m_free(bindaddr);
168 TRACE(("leave cancelremotetcp"))
169 return ret;
170 }
171
172 static int svr_remotetcpreq() {
173
174 int ret = DROPBEAR_FAILURE;
175 unsigned char * bindaddr = NULL;
176 unsigned int addrlen;
177 struct TCPListener *tcpinfo = NULL;
178 unsigned int port;
179
180 TRACE(("enter remotetcpreq"))
181
182 bindaddr = buf_getstring(ses.payload, &addrlen);
183 if (addrlen > MAX_IP_LEN) {
184 TRACE(("addr len too long: %d", addrlen))
185 goto out;
186 }
187
188 port = buf_getint(ses.payload);
189
190 if (port == 0) {
191 dropbear_log(LOG_INFO, "Server chosen tcpfwd ports are unsupported");
192 goto out;
193 }
194
195 if (port < 1 || port > 65535) {
196 TRACE(("invalid port: %d", port))
197 goto out;
198 }
199
200 if (!ses.allowprivport && port < IPPORT_RESERVED) {
201 TRACE(("can't assign port < 1024 for non-root"))
202 goto out;
203 }
204
205 tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener));
206 tcpinfo->sendaddr = NULL;
207 tcpinfo->sendport = 0;
208 tcpinfo->listenport = port;
209 tcpinfo->chantype = &svr_chan_tcpremote;
210 tcpinfo->tcp_type = forwarded;
211
212 if (!opts.listen_fwd_all || (strcmp(bindaddr, "localhost") == 0) ) {
213 // NULL means "localhost only"
214 m_free(bindaddr);
215 bindaddr = NULL;
216 }
217 tcpinfo->listenaddr = bindaddr;
218
219 ret = listen_tcpfwd(tcpinfo);
220
221 out:
222 if (ret == DROPBEAR_FAILURE) {
223 /* we only free it if a listener wasn't created, since the listener
224 * has to remember it if it's to be cancelled */
225 m_free(bindaddr);
226 m_free(tcpinfo);
227 }
228 TRACE(("leave remotetcpreq"))
229 return ret;
230 }
231
232 #endif /* ENABLE_SVR_REMOTETCPFWD */
233
234 #ifdef ENABLE_SVR_LOCALTCPFWD
45 235
46 const struct ChanType svr_chan_tcpdirect = { 236 const struct ChanType svr_chan_tcpdirect = {
47 1, /* sepfds */ 237 1, /* sepfds */
48 "direct-tcpip", 238 "direct-tcpip",
49 newtcpdirect, /* init */ 239 newtcpdirect, /* init */
50 NULL, /* checkclose */ 240 NULL, /* checkclose */
51 NULL, /* reqhandler */ 241 NULL, /* reqhandler */
52 NULL /* closehandler */ 242 NULL /* closehandler */
53 }; 243 };
54 244
55 static const struct ChanType svr_chan_tcpremote = {
56 1, /* sepfds */
57 "forwarded-tcpip",
58 NULL,
59 NULL,
60 NULL,
61 NULL
62 };
63
64 /* At the moment this is completely used for tcp code (with the name reflecting
65 * that). If new request types are added, this should be replaced with code
66 * similar to the request-switching in chansession.c */
67 void recv_msg_global_request_remotetcp() {
68
69 unsigned char* reqname = NULL;
70 unsigned int namelen;
71 unsigned int wantreply = 0;
72 int ret = DROPBEAR_FAILURE;
73
74 TRACE(("enter recv_msg_global_request_remotetcp"))
75
76 if (svr_opts.noremotetcp || !svr_pubkey_allows_tcpfwd()) {
77 TRACE(("leave recv_msg_global_request_remotetcp: remote tcp forwarding disabled"))
78 goto out;
79 }
80
81 reqname = buf_getstring(ses.payload, &namelen);
82 wantreply = buf_getbool(ses.payload);
83
84 if (namelen > MAX_NAME_LEN) {
85 TRACE(("name len is wrong: %d", namelen))
86 goto out;
87 }
88
89 if (strcmp("tcpip-forward", reqname) == 0) {
90 ret = svr_remotetcpreq();
91 } else if (strcmp("cancel-tcpip-forward", reqname) == 0) {
92 ret = svr_cancelremotetcp();
93 } else {
94 TRACE(("reqname isn't tcpip-forward: '%s'", reqname))
95 }
96
97 out:
98 if (wantreply) {
99 if (ret == DROPBEAR_SUCCESS) {
100 send_msg_request_success();
101 } else {
102 send_msg_request_failure();
103 }
104 }
105
106 m_free(reqname);
107
108 TRACE(("leave recv_msg_global_request"))
109 }
110
111
112 static void send_msg_request_success() {
113
114 CHECKCLEARTOWRITE();
115 buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_SUCCESS);
116 encrypt_packet();
117
118 }
119
120 static void send_msg_request_failure() {
121
122 CHECKCLEARTOWRITE();
123 buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_FAILURE);
124 encrypt_packet();
125
126 }
127
128 static int matchtcp(void* typedata1, void* typedata2) {
129
130 const struct TCPListener *info1 = (struct TCPListener*)typedata1;
131 const struct TCPListener *info2 = (struct TCPListener*)typedata2;
132
133 return (info1->listenport == info2->listenport)
134 && (info1->chantype == info2->chantype)
135 && (strcmp(info1->listenaddr, info2->listenaddr) == 0);
136 }
137
138 static int svr_cancelremotetcp() {
139
140 int ret = DROPBEAR_FAILURE;
141 unsigned char * bindaddr = NULL;
142 unsigned int addrlen;
143 unsigned int port;
144 struct Listener * listener = NULL;
145 struct TCPListener tcpinfo;
146
147 TRACE(("enter cancelremotetcp"))
148
149 bindaddr = buf_getstring(ses.payload, &addrlen);
150 if (addrlen > MAX_IP_LEN) {
151 TRACE(("addr len too long: %d", addrlen))
152 goto out;
153 }
154
155 port = buf_getint(ses.payload);
156
157 tcpinfo.sendaddr = NULL;
158 tcpinfo.sendport = 0;
159 tcpinfo.listenaddr = bindaddr;
160 tcpinfo.listenport = port;
161 listener = get_listener(CHANNEL_ID_TCPFORWARDED, &tcpinfo, matchtcp);
162 if (listener) {
163 remove_listener( listener );
164 ret = DROPBEAR_SUCCESS;
165 }
166
167 out:
168 m_free(bindaddr);
169 TRACE(("leave cancelremotetcp"))
170 return ret;
171 }
172
173 static int svr_remotetcpreq() {
174
175 int ret = DROPBEAR_FAILURE;
176 unsigned char * bindaddr = NULL;
177 unsigned int addrlen;
178 struct TCPListener *tcpinfo = NULL;
179 unsigned int port;
180
181 TRACE(("enter remotetcpreq"))
182
183 bindaddr = buf_getstring(ses.payload, &addrlen);
184 if (addrlen > MAX_IP_LEN) {
185 TRACE(("addr len too long: %d", addrlen))
186 goto out;
187 }
188
189 port = buf_getint(ses.payload);
190
191 if (port == 0) {
192 dropbear_log(LOG_INFO, "Server chosen tcpfwd ports are unsupported");
193 goto out;
194 }
195
196 if (port < 1 || port > 65535) {
197 TRACE(("invalid port: %d", port))
198 goto out;
199 }
200
201 if (!ses.allowprivport && port < IPPORT_RESERVED) {
202 TRACE(("can't assign port < 1024 for non-root"))
203 goto out;
204 }
205
206 tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener));
207 tcpinfo->sendaddr = NULL;
208 tcpinfo->sendport = 0;
209 tcpinfo->listenport = port;
210 tcpinfo->chantype = &svr_chan_tcpremote;
211 tcpinfo->tcp_type = forwarded;
212
213 if (!opts.listen_fwd_all || (strcmp(bindaddr, "localhost") == 0) ) {
214 // NULL means "localhost only"
215 m_free(bindaddr);
216 bindaddr = NULL;
217 }
218 tcpinfo->listenaddr = bindaddr;
219
220 ret = listen_tcpfwd(tcpinfo);
221
222 out:
223 if (ret == DROPBEAR_FAILURE) {
224 /* we only free it if a listener wasn't created, since the listener
225 * has to remember it if it's to be cancelled */
226 m_free(bindaddr);
227 m_free(tcpinfo);
228 }
229 TRACE(("leave remotetcpreq"))
230 return ret;
231 }
232
233 /* Called upon creating a new direct tcp channel (ie we connect out to an 245 /* Called upon creating a new direct tcp channel (ie we connect out to an
234 * address */ 246 * address */
235 static int newtcpdirect(struct Channel * channel) { 247 static int newtcpdirect(struct Channel * channel) {
236 248
237 unsigned char* desthost = NULL; 249 unsigned char* desthost = NULL;
292 m_free(orighost); 304 m_free(orighost);
293 TRACE(("leave newtcpdirect: err %d", err)) 305 TRACE(("leave newtcpdirect: err %d", err))
294 return err; 306 return err;
295 } 307 }
296 308
297 #endif 309 #endif /* ENABLE_SVR_LOCALTCPFWD */