1 /**
2 * xrdp: A Remote Desktop Protocol server.
3 *
4 * Copyright (C) Jay Sorg 2004-2012
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19 /**
20 *
21 * @file libscp_v0.c
22 * @brief libscp version 0 code
23 * @author Simone Fedele
24 *
25 */
26
27 #if defined(HAVE_CONFIG_H)
28 #include <config_ac.h>
29 #endif
30
31 #include "libscp_v0.h"
32
33 #include "os_calls.h"
34 #include "string_calls.h"
35
36 extern struct log_config *s_log;
37
38 /** Maximum length of a string (two bytes + len), excluding the terminator
39 *
40 * Practially this is limited by [MS-RDPBCGR] TS_INFO_PACKET
41 * */
42 #define STRING16_MAX_LEN 512
43
44 /**
45 * Reads a big-endian uint16 followed by a string into a buffer
46 *
47 * Buffer is null-terminated on success
48 *
49 * @param s Input stream
50 * @param [out] Output buffer (must be >= (STRING16_MAX_LEN+1) chars)
51 * @param param Parameter we're reading
52 * @return != 0 if string read OK
53 */
54 static
in_string16(struct stream * s,char str[],const char * param)55 int in_string16(struct stream *s, char str[], const char *param)
56 {
57 int result;
58
59 if (!s_check_rem(s, 2))
60 {
61 LOG(LOG_LEVEL_WARNING, "connection aborted: %s len missing", param);
62 result = 0;
63 }
64 else
65 {
66 unsigned int sz;
67
68 in_uint16_be(s, sz);
69 if (sz > STRING16_MAX_LEN)
70 {
71 LOG(LOG_LEVEL_WARNING,
72 "connection aborted: %s too long (%u chars)", param, sz);
73 result = 0;
74 }
75 else
76 {
77 result = s_check_rem(s, sz);
78 if (!result)
79 {
80 LOG(LOG_LEVEL_WARNING, "connection aborted: %s data missing", param);
81 }
82 else
83 {
84 in_uint8a(s, str, sz);
85 str[sz] = '\0';
86 }
87 }
88 }
89 return result;
90 }
91 /* client API */
92 #if 0
93 /******************************************************************************/
94 static enum SCP_CLIENT_STATES_E
95 scp_v0c_connect(struct SCP_CONNECTION *c, struct SCP_SESSION *s)
96 {
97 tui32 version;
98 int size;
99 tui16 sz;
100
101 init_stream(c->in_s, c->in_s->size);
102 init_stream(c->out_s, c->in_s->size);
103
104 LOG_DEVEL(LOG_LEVEL_DEBUG, "starting connection");
105 g_tcp_set_non_blocking(c->in_sck);
106 g_tcp_set_no_delay(c->in_sck);
107 s_push_layer(c->out_s, channel_hdr, 8);
108
109 /* code */
110 if (s->type == SCP_SESSION_TYPE_XVNC)
111 {
112 out_uint16_be(c->out_s, 0);
113 }
114 else if (s->type == SCP_SESSION_TYPE_XRDP)
115 {
116 out_uint16_be(c->out_s, 10);
117 }
118 else if (s->type == SCP_SESSION_TYPE_XORG)
119 {
120 out_uint16_be(c->out_s, 20);
121 }
122 else
123 {
124 LOG(LOG_LEVEL_WARNING, "connection aborted: network error");
125 return SCP_CLIENT_STATE_INTERNAL_ERR;
126 }
127
128 sz = g_strlen(s->username);
129 if (sz > STRING16_MAX_LEN)
130 {
131 LOG(LOG_LEVEL_WARNING, "connection aborted: username too long");
132 return SCP_CLIENT_STATE_SIZE_ERR;
133 }
134 out_uint16_be(c->out_s, sz);
135 out_uint8a(c->out_s, s->username, sz);
136
137 sz = g_strlen(s->password);
138 if (sz > STRING16_MAX_LEN)
139 {
140 LOG(LOG_LEVEL_WARNING, "connection aborted: password too long");
141 return SCP_CLIENT_STATE_SIZE_ERR;
142 }
143 out_uint16_be(c->out_s, sz);
144 out_uint8a(c->out_s, s->password, sz);
145 out_uint16_be(c->out_s, s->width);
146 out_uint16_be(c->out_s, s->height);
147 out_uint16_be(c->out_s, s->bpp);
148
149 s_mark_end(c->out_s);
150 s_pop_layer(c->out_s, channel_hdr);
151
152 /* version */
153 out_uint32_be(c->out_s, 0);
154 /* size */
155 out_uint32_be(c->out_s, c->out_s->end - c->out_s->data);
156
157 if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, c->out_s->end - c->out_s->data))
158 {
159 LOG(LOG_LEVEL_WARNING, "connection aborted: network error");
160 return SCP_CLIENT_STATE_NETWORK_ERR;
161 }
162
163 if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, 8))
164 {
165 LOG(LOG_LEVEL_WARNING, "connection aborted: network error");
166 return SCP_CLIENT_STATE_NETWORK_ERR;
167 }
168
169 in_uint32_be(c->in_s, version);
170
171 if (0 != version)
172 {
173 LOG(LOG_LEVEL_WARNING, "connection aborted: version error");
174 return SCP_CLIENT_STATE_VERSION_ERR;
175 }
176
177 in_uint32_be(c->in_s, size);
178
179 if (size < (8 + 2 + 2 + 2) || size > SCP_MAX_MESSAGE_SIZE)
180 {
181 LOG(LOG_LEVEL_WARNING, "connection aborted: msg size = %d", size);
182 return SCP_CLIENT_STATE_SIZE_ERR;
183 }
184
185 /* getting payload */
186 init_stream(c->in_s, size - 8);
187
188 if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, size - 8))
189 {
190 LOG(LOG_LEVEL_WARNING, "connection aborted: network error");
191 return SCP_CLIENT_STATE_NETWORK_ERR;
192 }
193
194 c->in_s->end = c->in_s->data + (size - 8);
195
196 /* check code */
197 in_uint16_be(c->in_s, sz);
198
199 if (3 != sz)
200 {
201 LOG(LOG_LEVEL_WARNING, "connection aborted: sequence error");
202 return SCP_CLIENT_STATE_SEQUENCE_ERR;
203 }
204
205 /* message payload */
206 in_uint16_be(c->in_s, sz);
207
208 if (1 != sz)
209 {
210 LOG(LOG_LEVEL_WARNING, "connection aborted: connection denied");
211 return SCP_CLIENT_STATE_CONNECTION_DENIED;
212 }
213
214 in_uint16_be(c->in_s, sz);
215 s->display = sz;
216
217 LOG_DEVEL(LOG_LEVEL_DEBUG, "connection terminated");
218 return SCP_CLIENT_STATE_END;
219 }
220 #endif
221
222 /* server API */
223
224 /**
225 * Initialises a V0 session object
226 *
227 * At the time of the call, the version has been read from the connection
228 *
229 * @param c Connection
230 * @param [out] session pre-allocated session object
231 * @return SCP_SERVER_STATE_OK for success
232 */
233 enum SCP_SERVER_STATES_E
scp_v0s_accept(struct trans * atrans,struct SCP_SESSION * session)234 scp_v0s_accept(struct trans *atrans, struct SCP_SESSION *session)
235 {
236 tui16 height;
237 tui16 width;
238 tui16 bpp;
239 tui32 code = 0;
240 char buf[STRING16_MAX_LEN + 1];
241 struct stream *in_s = atrans->in_s;
242 int session_type = -1;
243 scp_session_set_version(session, 0);
244
245 if (!s_check_rem(in_s, 6))
246 {
247 return SCP_SERVER_STATE_SIZE_ERR;
248 }
249 in_uint8s(in_s, 4); /* size */
250 in_uint16_be(in_s, code);
251 if ((code == 0) || (code == 10) || (code == 20))
252 {
253 if (code == 0)
254 {
255 session_type = SCP_SESSION_TYPE_XVNC;
256 }
257 else if (code == 10)
258 {
259 session_type = SCP_SESSION_TYPE_XRDP;
260 }
261 else
262 {
263 session_type = SCP_SESSION_TYPE_XORG;
264 }
265 scp_session_set_type(session, session_type);
266
267 /* reading username */
268 if (!in_string16(in_s, buf, "username"))
269 {
270 return SCP_SERVER_STATE_SIZE_ERR;
271 }
272 if (0 != scp_session_set_username(session, buf))
273 {
274 LOG(LOG_LEVEL_WARNING, "connection aborted: error setting username");
275 return SCP_SERVER_STATE_INTERNAL_ERR;
276 }
277
278 /* reading password */
279 if (!in_string16(in_s, buf, "passwd"))
280 {
281 return SCP_SERVER_STATE_SIZE_ERR;
282 }
283 if (0 != scp_session_set_password(session, buf))
284 {
285 LOG(LOG_LEVEL_WARNING, "connection aborted: error setting password");
286 return SCP_SERVER_STATE_INTERNAL_ERR;
287 }
288
289 /* width + height + bpp */
290 if (!s_check_rem(in_s, 2 + 2 + 2))
291 {
292 LOG(LOG_LEVEL_WARNING, "connection aborted: width+height+bpp missing");
293 return SCP_SERVER_STATE_SIZE_ERR;
294 }
295 in_uint16_be(in_s, width);
296 scp_session_set_width(session, width);
297 in_uint16_be(in_s, height);
298 scp_session_set_height(session, height);
299 in_uint16_be(in_s, bpp);
300 if (session_type == SCP_SESSION_TYPE_XORG && bpp != 24)
301 {
302 LOG(LOG_LEVEL_WARNING,
303 "Setting bpp to 24 from %d for Xorg session", bpp);
304 bpp = 24;
305 }
306 if (0 != scp_session_set_bpp(session, (tui8)bpp))
307 {
308 LOG(LOG_LEVEL_WARNING,
309 "connection aborted: unsupported bpp: %d", (tui8)bpp);
310 return SCP_SERVER_STATE_INTERNAL_ERR;
311 }
312
313 if (s_check_rem(in_s, 2))
314 {
315 /* reading domain */
316 if (!in_string16(in_s, buf, "domain"))
317 {
318 return SCP_SERVER_STATE_SIZE_ERR;
319 }
320
321 if (buf[0] != '\0')
322 {
323 scp_session_set_domain(session, buf);
324 }
325 }
326
327 if (s_check_rem(in_s, 2))
328 {
329 /* reading program */
330 if (!in_string16(in_s, buf, "program"))
331 {
332 return SCP_SERVER_STATE_SIZE_ERR;
333 }
334
335 if (buf[0] != '\0')
336 {
337 scp_session_set_program(session, buf);
338 }
339 }
340
341 if (s_check_rem(in_s, 2))
342 {
343 /* reading directory */
344 if (!in_string16(in_s, buf, "directory"))
345 {
346 return SCP_SERVER_STATE_SIZE_ERR;
347 }
348
349 if (buf[0] != '\0')
350 {
351 scp_session_set_directory(session, buf);
352 }
353 }
354
355 if (s_check_rem(in_s, 2))
356 {
357 /* reading client IP address */
358 if (!in_string16(in_s, buf, "client IP"))
359 {
360 return SCP_SERVER_STATE_SIZE_ERR;
361 }
362 if (buf[0] != '\0')
363 {
364 scp_session_set_client_ip(session, buf);
365 }
366 }
367 }
368 else if (code == SCP_GW_AUTHENTICATION)
369 {
370 scp_session_set_type(session, SCP_GW_AUTHENTICATION);
371 /* reading username */
372 if (!in_string16(in_s, buf, "username"))
373 {
374 return SCP_SERVER_STATE_SIZE_ERR;
375 }
376
377 if (0 != scp_session_set_username(session, buf))
378 {
379 LOG(LOG_LEVEL_WARNING, "connection aborted: error setting username");
380 return SCP_SERVER_STATE_INTERNAL_ERR;
381 }
382
383 /* reading password */
384 if (!in_string16(in_s, buf, "passwd"))
385 {
386 return SCP_SERVER_STATE_SIZE_ERR;
387 }
388
389 if (0 != scp_session_set_password(session, buf))
390 {
391 LOG(LOG_LEVEL_WARNING, "connection aborted: error setting password");
392 return SCP_SERVER_STATE_INTERNAL_ERR;
393 }
394 }
395 else
396 {
397 LOG(LOG_LEVEL_WARNING, "connection aborted: sequence error");
398 return SCP_SERVER_STATE_SEQUENCE_ERR;
399 }
400
401 return SCP_SERVER_STATE_OK;
402 }
403
404 /******************************************************************************/
405 enum SCP_SERVER_STATES_E
scp_v0s_allow_connection(struct trans * atrans,SCP_DISPLAY d,const tui8 * guid)406 scp_v0s_allow_connection(struct trans *atrans, SCP_DISPLAY d, const tui8 *guid)
407 {
408 int msg_size;
409 struct stream *out_s;
410
411 out_s = trans_get_out_s(atrans, 0);
412 msg_size = guid == 0 ? 14 : 14 + 16;
413 out_uint32_be(out_s, 0); /* version */
414 out_uint32_be(out_s, msg_size); /* size */
415 out_uint16_be(out_s, 3); /* cmd */
416 out_uint16_be(out_s, 1); /* data */
417 out_uint16_be(out_s, d); /* data */
418 if (msg_size > 14)
419 {
420 out_uint8a(out_s, guid, 16);
421 }
422 s_mark_end(out_s);
423 if (0 != trans_write_copy(atrans))
424 {
425 LOG(LOG_LEVEL_WARNING, "connection aborted: network error");
426 return SCP_SERVER_STATE_NETWORK_ERR;
427 }
428
429 LOG_DEVEL(LOG_LEVEL_DEBUG, "connection terminated (allowed)");
430 return SCP_SERVER_STATE_OK;
431 }
432
433 /******************************************************************************/
434 enum SCP_SERVER_STATES_E
scp_v0s_deny_connection(struct trans * atrans)435 scp_v0s_deny_connection(struct trans *atrans)
436 {
437 struct stream *out_s;
438
439 out_s = trans_get_out_s(atrans, 0);
440 out_uint32_be(out_s, 0); /* version */
441 out_uint32_be(out_s, 14); /* size */
442 out_uint16_be(out_s, 3); /* cmd */
443 out_uint16_be(out_s, 0); /* data = 0 - means NOT ok*/
444 out_uint16_be(out_s, 0); /* reserved for display number*/
445 s_mark_end(out_s);
446 if (0 != trans_write_copy(atrans))
447 {
448 LOG(LOG_LEVEL_WARNING, "connection aborted: network error");
449 return SCP_SERVER_STATE_NETWORK_ERR;
450 }
451
452 LOG_DEVEL(LOG_LEVEL_DEBUG, "connection terminated (denied)");
453 return SCP_SERVER_STATE_OK;
454 }
455
456 /******************************************************************************/
457 enum SCP_SERVER_STATES_E
scp_v0s_replyauthentication(struct trans * atrans,unsigned short int value)458 scp_v0s_replyauthentication(struct trans *atrans, unsigned short int value)
459 {
460 struct stream *out_s;
461
462 out_s = trans_get_out_s(atrans, 0);
463 out_uint32_be(out_s, 0); /* version */
464 out_uint32_be(out_s, 14); /* size */
465 /* cmd SCP_GW_AUTHENTICATION means authentication reply */
466 out_uint16_be(out_s, SCP_GW_AUTHENTICATION);
467 out_uint16_be(out_s, value); /* reply code */
468 out_uint16_be(out_s, 0); /* dummy data */
469 s_mark_end(out_s);
470 if (0 != trans_write_copy(atrans))
471 {
472 LOG(LOG_LEVEL_WARNING, "connection aborted: network error");
473 return SCP_SERVER_STATE_NETWORK_ERR;
474 }
475
476 LOG_DEVEL(LOG_LEVEL_DEBUG, "connection terminated (scp_v0s_deny_authentication)");
477 return SCP_SERVER_STATE_OK;
478 }
479