1 |
/* |
/* |
2 |
Copyright (c) 1998-2001, Robert O'Callahan |
Copyright (c) 1998-2001, Robert O'Callahan |
3 |
All rights reserved. |
All rights reserved. |
4 |
|
|
5 |
Redistribution and use in source and binary forms, with or without modification, |
Redistribution and use in source and binary forms, with or without modification, |
6 |
are permitted provided that the following conditions are met: |
are permitted provided that the following conditions are met: |
7 |
|
|
8 |
Redistributions of source code must retain the above copyright notice, this list of |
Redistributions of source code must retain the above copyright notice, this list of |
9 |
conditions and the following disclaimer. |
conditions and the following disclaimer. |
10 |
|
|
11 |
Redistributions in binary form must reproduce the above copyright notice, this list |
Redistributions in binary form must reproduce the above copyright notice, this list |
12 |
of conditions and the following disclaimer in the documentation and/or other materials |
of conditions and the following disclaimer in the documentation and/or other materials |
13 |
provided with the distribution. |
provided with the distribution. |
14 |
|
|
15 |
The name of Robert O'Callahan may not be used to endorse or promote products derived from |
The name of Robert O'Callahan may not be used to endorse or promote products derived from |
16 |
this software without specific prior written permission. |
this software without specific prior written permission. |
17 |
|
|
18 |
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND |
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND |
19 |
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
20 |
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL |
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL |
21 |
THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
22 |
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
23 |
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
24 |
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
25 |
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
26 |
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 |
*/ |
*/ |
28 |
|
|
29 |
#include "x11util.h" |
#include "x11util.h" |
30 |
|
|
31 |
#include <openssl/rand.h> |
#include <openssl/rand.h> |
32 |
#include "util.h" |
#include "util.h" |
33 |
#include <stdlib.h> |
#include <stdlib.h> |
34 |
|
|
35 |
typedef struct { |
typedef struct { |
36 |
PTInstVar pvar; |
PTInstVar pvar; |
37 |
X11AuthData FAR *auth_data; |
X11AuthData FAR *auth_data; |
38 |
|
|
39 |
unsigned char FAR *init_buf; |
unsigned char FAR *init_buf; |
40 |
int init_buf_len; |
int init_buf_len; |
41 |
int init_data_len; |
int init_data_len; |
42 |
} X11UnspoofingFilterClosure; |
} X11UnspoofingFilterClosure; |
43 |
|
|
44 |
void X11_get_DISPLAY_info(char FAR * name_buf, int name_buf_len, |
void X11_get_DISPLAY_info(char FAR * name_buf, int name_buf_len, |
45 |
int FAR * port) |
int FAR * port) |
46 |
{ |
{ |
47 |
char FAR *DISPLAY = getenv("DISPLAY"); |
char FAR *DISPLAY = getenv("DISPLAY"); |
48 |
|
|
49 |
strncpy_s(name_buf, name_buf_len, "localhost", _TRUNCATE); |
strncpy_s(name_buf, name_buf_len, "localhost", _TRUNCATE); |
50 |
*port = 6000; |
*port = 6000; |
51 |
|
|
52 |
if (DISPLAY != NULL) { |
if (DISPLAY != NULL) { |
53 |
int i; |
int i; |
54 |
|
|
55 |
for (i = 0; DISPLAY[i] != 0 && DISPLAY[i] != ':'; i++) { |
for (i = 0; DISPLAY[i] != 0 && DISPLAY[i] != ':'; i++) { |
56 |
} |
} |
57 |
|
|
58 |
if (i > 0) { |
if (i > 0) { |
59 |
char c = DISPLAY[i]; |
char c = DISPLAY[i]; |
60 |
DISPLAY[i] = 0; |
DISPLAY[i] = 0; |
61 |
strncpy_s(name_buf, name_buf_len, DISPLAY, _TRUNCATE); |
strncpy_s(name_buf, name_buf_len, DISPLAY, _TRUNCATE); |
62 |
DISPLAY[i] = c; |
DISPLAY[i] = c; |
63 |
} |
} |
64 |
|
|
65 |
if (DISPLAY[i] == ':') { |
if (DISPLAY[i] == ':') { |
66 |
*port = atoi(DISPLAY + i + 1) + 6000; |
*port = atoi(DISPLAY + i + 1) + 6000; |
67 |
} |
} |
68 |
} |
} |
69 |
} |
} |
70 |
|
|
71 |
X11AuthData FAR *X11_load_local_auth_data(int screen_num) |
X11AuthData FAR *X11_load_local_auth_data(int screen_num) |
72 |
{ |
{ |
73 |
X11AuthData FAR *auth_data = |
X11AuthData FAR *auth_data = |
74 |
(X11AuthData FAR *) malloc(sizeof(X11AuthData)); |
(X11AuthData FAR *) malloc(sizeof(X11AuthData)); |
75 |
char FAR *local_auth_data_str; |
char FAR *local_auth_data_str; |
76 |
|
|
77 |
auth_data->local_protocol = getenv("TTSSH_XAUTH_PROTOCOL_NAME"); |
auth_data->local_protocol = getenv("TTSSH_XAUTH_PROTOCOL_NAME"); |
78 |
|
|
79 |
local_auth_data_str = getenv("TTSSH_XAUTH_PROTOCOL_DATA"); |
local_auth_data_str = getenv("TTSSH_XAUTH_PROTOCOL_DATA"); |
80 |
if (local_auth_data_str == NULL) { |
if (local_auth_data_str == NULL) { |
81 |
auth_data->local_data_len = 0; |
auth_data->local_data_len = 0; |
82 |
auth_data->local_data = NULL; |
auth_data->local_data = NULL; |
83 |
} else { |
} else { |
84 |
int str_len = strlen(local_auth_data_str); |
int str_len = strlen(local_auth_data_str); |
85 |
int i; |
int i; |
86 |
|
|
87 |
auth_data->local_data_len = (str_len + 1) / 2; |
auth_data->local_data_len = (str_len + 1) / 2; |
88 |
auth_data->local_data = malloc(auth_data->local_data_len); |
auth_data->local_data = malloc(auth_data->local_data_len); |
89 |
|
|
90 |
if (auth_data->local_data_len * 2 > str_len) { |
if (auth_data->local_data_len * 2 > str_len) { |
91 |
char buf[2] = { local_auth_data_str[0], 0 }; |
char buf[2] = { local_auth_data_str[0], 0 }; |
92 |
|
|
93 |
auth_data->local_data[0] = |
auth_data->local_data[0] = |
94 |
(unsigned char) strtol(buf, NULL, 16); |
(unsigned char) strtol(buf, NULL, 16); |
95 |
i = 1; |
i = 1; |
96 |
} else { |
} else { |
97 |
i = 0; |
i = 0; |
98 |
} |
} |
99 |
|
|
100 |
for (; i < str_len; i += 2) { |
for (; i < str_len; i += 2) { |
101 |
char buf[3] = |
char buf[3] = |
102 |
{ local_auth_data_str[i], local_auth_data_str[i + 1], 0 }; |
{ local_auth_data_str[i], local_auth_data_str[i + 1], 0 }; |
103 |
|
|
104 |
auth_data->local_data[(i + 1) / 2] = |
auth_data->local_data[(i + 1) / 2] = |
105 |
(unsigned char) strtol(buf, NULL, 16); |
(unsigned char) strtol(buf, NULL, 16); |
106 |
} |
} |
107 |
} |
} |
108 |
|
|
109 |
auth_data->spoofed_protocol = _strdup("MIT-MAGIC-COOKIE-1"); |
auth_data->spoofed_protocol = _strdup("MIT-MAGIC-COOKIE-1"); |
110 |
auth_data->spoofed_data_len = 16; |
auth_data->spoofed_data_len = 16; |
111 |
auth_data->spoofed_data = malloc(auth_data->spoofed_data_len); |
auth_data->spoofed_data = malloc(auth_data->spoofed_data_len); |
112 |
RAND_bytes(auth_data->spoofed_data, auth_data->spoofed_data_len); |
RAND_bytes(auth_data->spoofed_data, auth_data->spoofed_data_len); |
113 |
|
|
114 |
return auth_data; |
return auth_data; |
115 |
} |
} |
116 |
|
|
117 |
void X11_dispose_auth_data(X11AuthData FAR * auth_data) |
void X11_dispose_auth_data(X11AuthData FAR * auth_data) |
118 |
{ |
{ |
119 |
memset(auth_data->local_data, 0, auth_data->local_data_len); |
memset(auth_data->local_data, 0, auth_data->local_data_len); |
120 |
free(auth_data->local_data); |
free(auth_data->local_data); |
121 |
free(auth_data->spoofed_protocol); |
free(auth_data->spoofed_protocol); |
122 |
memset(auth_data->spoofed_data, 0, auth_data->spoofed_data_len); |
memset(auth_data->spoofed_data, 0, auth_data->spoofed_data_len); |
123 |
free(auth_data->spoofed_data); |
free(auth_data->spoofed_data); |
124 |
free(auth_data); |
free(auth_data); |
125 |
} |
} |
126 |
|
|
127 |
void *X11_init_unspoofing_filter(PTInstVar pvar, |
void *X11_init_unspoofing_filter(PTInstVar pvar, |
128 |
X11AuthData FAR * auth_data) |
X11AuthData FAR * auth_data) |
129 |
{ |
{ |
130 |
X11UnspoofingFilterClosure FAR *closure = |
X11UnspoofingFilterClosure FAR *closure = |
131 |
malloc(sizeof(X11UnspoofingFilterClosure)); |
malloc(sizeof(X11UnspoofingFilterClosure)); |
132 |
|
|
133 |
closure->pvar = pvar; |
closure->pvar = pvar; |
134 |
closure->auth_data = auth_data; |
closure->auth_data = auth_data; |
135 |
|
|
136 |
closure->init_data_len = 0; |
closure->init_data_len = 0; |
137 |
buf_create(&closure->init_buf, &closure->init_buf_len); |
buf_create(&closure->init_buf, &closure->init_buf_len); |
138 |
|
|
139 |
return closure; |
return closure; |
140 |
} |
} |
141 |
|
|
142 |
#define MERGE_NEED_MORE 0 |
#define MERGE_NEED_MORE 0 |
143 |
#define MERGE_GOT_GOOD_DATA 1 |
#define MERGE_GOT_GOOD_DATA 1 |
144 |
#define MERGE_GOT_BAD_DATA 2 |
#define MERGE_GOT_BAD_DATA 2 |
145 |
|
|
146 |
static int merge_into_X11_init_packet(X11UnspoofingFilterClosure FAR * |
static int merge_into_X11_init_packet(X11UnspoofingFilterClosure FAR * |
147 |
closure, int length, |
closure, int length, |
148 |
unsigned char FAR * buf) |
unsigned char FAR * buf) |
149 |
{ |
{ |
150 |
buf_ensure_size_growing(&closure->init_buf, &closure->init_buf_len, |
buf_ensure_size_growing(&closure->init_buf, &closure->init_buf_len, |
151 |
closure->init_data_len + length); |
closure->init_data_len + length); |
152 |
memcpy(closure->init_buf + closure->init_data_len, buf, length); |
memcpy(closure->init_buf + closure->init_data_len, buf, length); |
153 |
closure->init_data_len += length; |
closure->init_data_len += length; |
154 |
|
|
155 |
if (closure->init_data_len < 12) { |
if (closure->init_data_len < 12) { |
156 |
return MERGE_NEED_MORE; |
return MERGE_NEED_MORE; |
157 |
} else { |
} else { |
158 |
int name_len; |
int name_len; |
159 |
int data_len; |
int data_len; |
160 |
int padded_name_len; |
int padded_name_len; |
161 |
int padded_data_len; |
int padded_data_len; |
162 |
|
|
163 |
switch (closure->init_buf[0]) { |
switch (closure->init_buf[0]) { |
164 |
case 0x42: /* MSB first */ |
case 0x42: /* MSB first */ |
165 |
name_len = (closure->init_buf[6] << 8) | closure->init_buf[7]; |
name_len = (closure->init_buf[6] << 8) | closure->init_buf[7]; |
166 |
data_len = (closure->init_buf[8] << 8) | closure->init_buf[9]; |
data_len = (closure->init_buf[8] << 8) | closure->init_buf[9]; |
167 |
break; |
break; |
168 |
case 0x6C: /* LSB first */ |
case 0x6C: /* LSB first */ |
169 |
name_len = (closure->init_buf[7] << 8) | closure->init_buf[6]; |
name_len = (closure->init_buf[7] << 8) | closure->init_buf[6]; |
170 |
data_len = (closure->init_buf[9] << 8) | closure->init_buf[8]; |
data_len = (closure->init_buf[9] << 8) | closure->init_buf[8]; |
171 |
break; |
break; |
172 |
default: |
default: |
173 |
return MERGE_GOT_BAD_DATA; |
return MERGE_GOT_BAD_DATA; |
174 |
} |
} |
175 |
|
|
176 |
padded_name_len = (name_len + 3) & ~0x3; |
padded_name_len = (name_len + 3) & ~0x3; |
177 |
padded_data_len = (data_len + 3) & ~0x3; |
padded_data_len = (data_len + 3) & ~0x3; |
178 |
|
|
179 |
if (closure->init_data_len < |
if (closure->init_data_len < |
180 |
12 + padded_name_len + padded_data_len) { |
12 + padded_name_len + padded_data_len) { |
181 |
return MERGE_NEED_MORE; |
return MERGE_NEED_MORE; |
182 |
} else if (name_len == |
} else if (name_len == |
183 |
(int) strlen(closure->auth_data->spoofed_protocol) |
(int) strlen(closure->auth_data->spoofed_protocol) |
184 |
&& memcmp(closure->init_buf + 12, |
&& memcmp(closure->init_buf + 12, |
185 |
closure->auth_data->spoofed_protocol, |
closure->auth_data->spoofed_protocol, |
186 |
name_len) == 0 |
name_len) == 0 |
187 |
&& data_len == closure->auth_data->spoofed_data_len |
&& data_len == closure->auth_data->spoofed_data_len |
188 |
&& memcmp(closure->init_buf + 12 + padded_name_len, |
&& memcmp(closure->init_buf + 12 + padded_name_len, |
189 |
closure->auth_data->spoofed_data, |
closure->auth_data->spoofed_data, |
190 |
data_len) == 0) { |
data_len) == 0) { |
191 |
return MERGE_GOT_GOOD_DATA; |
return MERGE_GOT_GOOD_DATA; |
192 |
} else { |
} else { |
193 |
return MERGE_GOT_BAD_DATA; |
return MERGE_GOT_BAD_DATA; |
194 |
} |
} |
195 |
} |
} |
196 |
} |
} |
197 |
|
|
198 |
static void insert_real_X11_auth_data(X11UnspoofingFilterClosure FAR * |
static void insert_real_X11_auth_data(X11UnspoofingFilterClosure FAR * |
199 |
closure, int FAR * length, |
closure, int FAR * length, |
200 |
unsigned char FAR * FAR * buf) |
unsigned char FAR * FAR * buf) |
201 |
{ |
{ |
202 |
int name_len = closure->auth_data->local_protocol == NULL |
int name_len = closure->auth_data->local_protocol == NULL |
203 |
? 0 : strlen(closure->auth_data->local_protocol); |
? 0 : strlen(closure->auth_data->local_protocol); |
204 |
int data_len = closure->auth_data->local_data_len; |
int data_len = closure->auth_data->local_data_len; |
205 |
int padded_name_len = (name_len + 3) & ~0x3; |
int padded_name_len = (name_len + 3) & ~0x3; |
206 |
int padded_data_len = (data_len + 3) & ~0x3; |
int padded_data_len = (data_len + 3) & ~0x3; |
207 |
|
|
208 |
*length = 12 + padded_name_len + padded_data_len; |
*length = 12 + padded_name_len + padded_data_len; |
209 |
buf_ensure_size(&closure->init_buf, &closure->init_buf_len, *length); |
buf_ensure_size(&closure->init_buf, &closure->init_buf_len, *length); |
210 |
*buf = closure->init_buf; |
*buf = closure->init_buf; |
211 |
|
|
212 |
switch (closure->init_buf[0]) { |
switch (closure->init_buf[0]) { |
213 |
case 0x42: /* MSB first */ |
case 0x42: /* MSB first */ |
214 |
closure->init_buf[6] = name_len >> 8; |
closure->init_buf[6] = name_len >> 8; |
215 |
closure->init_buf[7] = name_len & 0xFF; |
closure->init_buf[7] = name_len & 0xFF; |
216 |
closure->init_buf[8] = data_len >> 8; |
closure->init_buf[8] = data_len >> 8; |
217 |
closure->init_buf[9] = data_len & 0xFF; |
closure->init_buf[9] = data_len & 0xFF; |
218 |
break; |
break; |
219 |
case 0x6C: /* LSB first */ |
case 0x6C: /* LSB first */ |
220 |
closure->init_buf[7] = name_len >> 8; |
closure->init_buf[7] = name_len >> 8; |
221 |
closure->init_buf[6] = name_len & 0xFF; |
closure->init_buf[6] = name_len & 0xFF; |
222 |
closure->init_buf[9] = data_len >> 8; |
closure->init_buf[9] = data_len >> 8; |
223 |
closure->init_buf[8] = data_len & 0xFF; |
closure->init_buf[8] = data_len & 0xFF; |
224 |
break; |
break; |
225 |
} |
} |
226 |
|
|
227 |
memcpy(*buf + 12, closure->auth_data->local_protocol, name_len); |
memcpy(*buf + 12, closure->auth_data->local_protocol, name_len); |
228 |
memcpy(*buf + 12 + padded_name_len, closure->auth_data->local_data, |
memcpy(*buf + 12 + padded_name_len, closure->auth_data->local_data, |
229 |
data_len); |
data_len); |
230 |
} |
} |
231 |
|
|
232 |
int X11_unspoofing_filter(void FAR * void_closure, int direction, |
int X11_unspoofing_filter(void FAR * void_closure, int direction, |
233 |
int FAR * length, unsigned char FAR * FAR * buf) |
int FAR * length, unsigned char FAR * FAR * buf) |
234 |
{ |
{ |
235 |
X11UnspoofingFilterClosure FAR *closure = |
X11UnspoofingFilterClosure FAR *closure = |
236 |
(X11UnspoofingFilterClosure FAR *) void_closure; |
(X11UnspoofingFilterClosure FAR *) void_closure; |
237 |
|
|
238 |
if (length == NULL) { |
if (length == NULL) { |
239 |
buf_destroy(&closure->init_buf, &closure->init_buf_len); |
buf_destroy(&closure->init_buf, &closure->init_buf_len); |
240 |
free(closure); |
free(closure); |
241 |
return FWD_FILTER_REMOVE; |
return FWD_FILTER_REMOVE; |
242 |
} else if (direction == FWD_FILTER_FROM_SERVER) { |
} else if (direction == FWD_FILTER_FROM_SERVER) { |
243 |
switch (merge_into_X11_init_packet(closure, *length, *buf)) { |
switch (merge_into_X11_init_packet(closure, *length, *buf)) { |
244 |
case MERGE_NEED_MORE: |
case MERGE_NEED_MORE: |
245 |
*length = 0; |
*length = 0; |
246 |
return FWD_FILTER_RETAIN; |
return FWD_FILTER_RETAIN; |
247 |
case MERGE_GOT_GOOD_DATA: |
case MERGE_GOT_GOOD_DATA: |
248 |
insert_real_X11_auth_data(closure, length, buf); |
insert_real_X11_auth_data(closure, length, buf); |
249 |
return FWD_FILTER_REMOVE; |
return FWD_FILTER_REMOVE; |
250 |
default: |
default: |
251 |
case MERGE_GOT_BAD_DATA: |
case MERGE_GOT_BAD_DATA: |
252 |
UTIL_get_lang_msg("MSG_X_AUTH_ERROR", closure->pvar, |
UTIL_get_lang_msg("MSG_X_AUTH_ERROR", closure->pvar, |
253 |
"Remote X application sent incorrect authentication data.\n" |
"Remote X application sent incorrect authentication data.\n" |
254 |
"Its X session is being cancelled."); |
"Its X session is being cancelled."); |
255 |
notify_nonfatal_error(closure->pvar, closure->pvar->ts->UIMsg); |
notify_nonfatal_error(closure->pvar, closure->pvar->ts->UIMsg); |
256 |
*length = 0; |
*length = 0; |
257 |
return FWD_FILTER_CLOSECHANNEL; |
return FWD_FILTER_CLOSECHANNEL; |
258 |
} |
} |
259 |
} else { |
} else { |
260 |
return FWD_FILTER_RETAIN; |
return FWD_FILTER_RETAIN; |
261 |
} |
} |
262 |
} |
} |