f26d5c33 |
1 | #include <windows.h> |
2 | #include <stdio.h> |
3 | #include <stdlib.h> |
4 | |
5 | #include "putty.h" |
6 | #include "ssh.h" |
7 | |
8 | #ifndef FALSE |
9 | #define FALSE 0 |
10 | #endif |
11 | #ifndef TRUE |
12 | #define TRUE 1 |
13 | #endif |
14 | |
15 | #define GET_32BIT_LSB_FIRST(cp) \ |
16 | (((unsigned long)(unsigned char)(cp)[0]) | \ |
17 | ((unsigned long)(unsigned char)(cp)[1] << 8) | \ |
18 | ((unsigned long)(unsigned char)(cp)[2] << 16) | \ |
19 | ((unsigned long)(unsigned char)(cp)[3] << 24)) |
20 | |
21 | #define PUT_32BIT_LSB_FIRST(cp, value) ( \ |
22 | (cp)[0] = (value), \ |
23 | (cp)[1] = (value) >> 8, \ |
24 | (cp)[2] = (value) >> 16, \ |
25 | (cp)[3] = (value) >> 24 ) |
26 | |
27 | #define GET_16BIT_LSB_FIRST(cp) \ |
28 | (((unsigned long)(unsigned char)(cp)[0]) | \ |
29 | ((unsigned long)(unsigned char)(cp)[1] << 8)) |
30 | |
31 | #define PUT_16BIT_LSB_FIRST(cp, value) ( \ |
32 | (cp)[0] = (value), \ |
33 | (cp)[1] = (value) >> 8 ) |
34 | |
35 | #define GET_32BIT_MSB_FIRST(cp) \ |
36 | (((unsigned long)(unsigned char)(cp)[0] << 24) | \ |
37 | ((unsigned long)(unsigned char)(cp)[1] << 16) | \ |
38 | ((unsigned long)(unsigned char)(cp)[2] << 8) | \ |
39 | ((unsigned long)(unsigned char)(cp)[3])) |
40 | |
41 | #define PUT_32BIT_MSB_FIRST(cp, value) ( \ |
42 | (cp)[0] = (value) >> 24, \ |
43 | (cp)[1] = (value) >> 16, \ |
44 | (cp)[2] = (value) >> 8, \ |
45 | (cp)[3] = (value) ) |
46 | |
47 | #define GET_16BIT_MSB_FIRST(cp) \ |
48 | (((unsigned long)(unsigned char)(cp)[0] << 8) | \ |
49 | ((unsigned long)(unsigned char)(cp)[1])) |
50 | |
51 | #define PUT_16BIT_MSB_FIRST(cp, value) ( \ |
52 | (cp)[0] = (value) >> 8, \ |
53 | (cp)[1] = (value) ) |
54 | |
55 | extern void sshfwd_close(void *); |
56 | extern void sshfwd_write(void *, char *, int); |
57 | |
58 | struct pfwd_queue { |
59 | struct pfwd_queue *next; |
60 | char *buf; |
61 | }; |
62 | |
63 | struct PFwdPrivate { |
64 | struct plug_function_table *fn; |
65 | /* the above variable absolutely *must* be the first in this structure */ |
66 | void *c; /* (channel) data used by ssh.c */ |
67 | Socket s; |
68 | char hostname[128]; |
69 | int port; |
70 | int ready; |
71 | struct pfwd_queue *waiting; |
72 | }; |
73 | |
74 | void pfd_close(Socket s); |
75 | |
76 | |
77 | static int pfd_closing(Plug plug, char *error_msg, int error_code, |
78 | int calling_back) |
79 | { |
80 | struct PFwdPrivate *pr = (struct PFwdPrivate *) plug; |
81 | |
82 | /* |
83 | * We have no way to communicate down the forwarded connection, |
84 | * so if an error occurred on the socket, we just ignore it |
85 | * and treat it like a proper close. |
86 | */ |
87 | sshfwd_close(pr->c); |
88 | pfd_close(pr->s); |
89 | return 1; |
90 | } |
91 | |
92 | static int pfd_receive(Plug plug, int urgent, char *data, int len) |
93 | { |
94 | struct PFwdPrivate *pr = (struct PFwdPrivate *) plug; |
95 | |
96 | if (pr->ready) |
97 | sshfwd_write(pr->c, data, len); |
98 | return 1; |
99 | } |
100 | |
101 | /* |
102 | * Called when receiving a PORT OPEN from the server |
103 | */ |
104 | char *pfd_newconnect(Socket *s, char *hostname, int port, void *c) |
105 | { |
106 | static struct plug_function_table fn_table = { |
107 | pfd_closing, |
108 | pfd_receive, |
109 | NULL |
110 | }; |
111 | |
112 | SockAddr addr; |
113 | char *err, *dummy_realhost; |
114 | struct PFwdPrivate *pr; |
115 | |
116 | /* |
117 | * Try to find host. |
118 | */ |
119 | addr = sk_namelookup(hostname, &dummy_realhost); |
120 | if ((err = sk_addr_error(addr))) |
121 | return err; |
122 | |
123 | /* |
124 | * Open socket. |
125 | */ |
126 | pr = (struct PFwdPrivate *) smalloc(sizeof(struct PFwdPrivate)); |
127 | pr->fn = &fn_table; |
128 | pr->ready = 1; |
129 | pr->c = c; |
130 | |
131 | pr->s = *s = sk_new(addr, port, 0, 1, (Plug) pr); |
132 | if ((err = sk_socket_error(*s))) { |
133 | sfree(pr); |
134 | return err; |
135 | } |
136 | |
137 | sk_set_private_ptr(*s, pr); |
138 | sk_addr_free(addr); |
139 | return NULL; |
140 | } |
141 | |
142 | /* |
143 | called when someone connects to the local port |
144 | */ |
145 | |
146 | static int pfd_accepting(Plug p, struct sockaddr *addr, void *sock) |
147 | { |
148 | /* for now always accept this socket */ |
149 | static struct plug_function_table fn_table = { |
150 | pfd_closing, |
151 | pfd_receive, |
152 | NULL |
153 | }; |
154 | struct PFwdPrivate *pr, *org; |
155 | struct sockaddr_in *sin = (struct sockaddr_in *)addr; |
156 | Socket s; |
157 | char *err; |
158 | |
159 | if (ntohl(sin->sin_addr.s_addr) != 0x7F000001 && !cfg.lport_acceptall) |
160 | return 1; /* denied */ |
161 | |
162 | org = (struct PFwdPrivate *)p; |
163 | pr = (struct PFwdPrivate *) smalloc(sizeof(struct PFwdPrivate)); |
164 | pr->fn = &fn_table; |
165 | |
166 | pr->c = NULL; |
167 | |
168 | pr->s = s = sk_register(sock, (Plug) pr); |
169 | if ((err = sk_socket_error(s))) { |
170 | sfree(pr); |
171 | return err != NULL; |
172 | } |
173 | |
174 | pr->c = new_sock_channel(s); |
175 | |
176 | strcpy(pr->hostname, org->hostname); |
177 | pr->port = org->port; |
178 | pr->ready = 0; |
179 | pr->waiting = NULL; |
180 | |
181 | sk_set_private_ptr(s, pr); |
182 | |
183 | if (pr->c == NULL) { |
184 | sfree(pr); |
185 | return 1; |
186 | } else { |
187 | /* asks to forward to the specified host/port for this */ |
188 | ssh_send_port_open(pr->c, pr->hostname, pr->port, "forwarding"); |
189 | } |
190 | |
191 | return 0; |
192 | } |
193 | |
194 | |
195 | /* Add a new forwarding from port -> desthost:destport |
196 | sets up a listenner on the local machine on port |
197 | */ |
198 | char *pfd_addforward(char *desthost, int destport, int port) |
199 | { |
200 | static struct plug_function_table fn_table = { |
201 | pfd_closing, |
202 | pfd_receive, /* should not happen... */ |
203 | pfd_accepting |
204 | }; |
205 | |
206 | char *err; |
207 | struct PFwdPrivate *pr; |
208 | Socket s; |
209 | |
210 | /* |
211 | * Open socket. |
212 | */ |
213 | pr = (struct PFwdPrivate *) smalloc(sizeof(struct PFwdPrivate)); |
214 | pr->fn = &fn_table; |
215 | pr->c = NULL; |
216 | strcpy(pr->hostname, desthost); |
217 | pr->port = destport; |
218 | pr->ready = 0; |
219 | pr->waiting = NULL; |
220 | |
221 | pr->s = s = sk_newlistenner(port, (Plug) pr); |
222 | if ((err = sk_socket_error(s))) { |
223 | sfree(pr); |
224 | return err; |
225 | } |
226 | |
227 | sk_set_private_ptr(s, pr); |
228 | |
229 | return NULL; |
230 | } |
231 | |
232 | void pfd_close(Socket s) |
233 | { |
234 | struct PFwdPrivate *pr; |
235 | |
236 | if (!s) |
237 | return; |
238 | |
239 | pr = (struct PFwdPrivate *) sk_get_private_ptr(s); |
240 | |
241 | sfree(pr); |
242 | |
243 | sk_close(s); |
244 | } |
245 | |
246 | /* |
247 | * Called to send data down the raw connection. |
248 | */ |
249 | void pfd_send(Socket s, char *data, int len) |
250 | { |
251 | struct PFwdPrivate *pr = (struct PFwdPrivate *) sk_get_private_ptr(s); |
252 | |
253 | if (s == NULL) |
254 | return; |
255 | |
256 | sk_write(s, data, len); |
257 | } |
258 | |
259 | |
260 | void pfd_confirm(Socket s) |
261 | { |
262 | struct PFwdPrivate *pr = (struct PFwdPrivate *) sk_get_private_ptr(s); |
263 | |
264 | if (s == NULL) |
265 | return; |
266 | |
267 | pr->ready = 1; |
268 | sk_set_frozen(s, 0); |
269 | sk_write(s, NULL, 0); |
270 | } |