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 /******************************************************************************/
93 enum SCP_CLIENT_STATES_E
scp_v0c_connect(struct SCP_CONNECTION * c,struct SCP_SESSION * s)94 scp_v0c_connect(struct SCP_CONNECTION *c, struct SCP_SESSION *s)
95 {
96 tui32 version;
97 int size;
98 tui16 sz;
99
100 init_stream(c->in_s, c->in_s->size);
101 init_stream(c->out_s, c->in_s->size);
102
103 LOG_DEVEL(LOG_LEVEL_DEBUG, "starting connection");
104 g_tcp_set_non_blocking(c->in_sck);
105 g_tcp_set_no_delay(c->in_sck);
106 s_push_layer(c->out_s, channel_hdr, 8);
107
108 /* code */
109 if (s->type == SCP_SESSION_TYPE_XVNC)
110 {
111 out_uint16_be(c->out_s, 0);
112 }
113 else if (s->type == SCP_SESSION_TYPE_XRDP)
114 {
115 out_uint16_be(c->out_s, 10);
116 }
117 else if (s->type == SCP_SESSION_TYPE_XORG)
118 {
119 out_uint16_be(c->out_s, 20);
120 }
121 else
122 {
123 LOG(LOG_LEVEL_WARNING, "connection aborted: network error");
124 return SCP_CLIENT_STATE_INTERNAL_ERR;
125 }
126
127 sz = g_strlen(s->username);
128 if (sz > STRING16_MAX_LEN)
129 {
130 LOG(LOG_LEVEL_WARNING, "connection aborted: username too long");
131 return SCP_CLIENT_STATE_SIZE_ERR;
132 }
133 out_uint16_be(c->out_s, sz);
134 out_uint8a(c->out_s, s->username, sz);
135
136 sz = g_strlen(s->password);
137 if (sz > STRING16_MAX_LEN)
138 {
139 LOG(LOG_LEVEL_WARNING, "connection aborted: password too long");
140 return SCP_CLIENT_STATE_SIZE_ERR;
141 }
142 out_uint16_be(c->out_s, sz);
143 out_uint8a(c->out_s, s->password, sz);
144 out_uint16_be(c->out_s, s->width);
145 out_uint16_be(c->out_s, s->height);
146 out_uint16_be(c->out_s, s->bpp);
147
148 s_mark_end(c->out_s);
149 s_pop_layer(c->out_s, channel_hdr);
150
151 /* version */
152 out_uint32_be(c->out_s, 0);
153 /* size */
154 out_uint32_be(c->out_s, c->out_s->end - c->out_s->data);
155
156 if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, c->out_s->end - c->out_s->data))
157 {
158 LOG(LOG_LEVEL_WARNING, "connection aborted: network error");
159 return SCP_CLIENT_STATE_NETWORK_ERR;
160 }
161
162 if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, 8))
163 {
164 LOG(LOG_LEVEL_WARNING, "connection aborted: network error");
165 return SCP_CLIENT_STATE_NETWORK_ERR;
166 }
167
168 in_uint32_be(c->in_s, version);
169
170 if (0 != version)
171 {
172 LOG(LOG_LEVEL_WARNING, "connection aborted: version error");
173 return SCP_CLIENT_STATE_VERSION_ERR;
174 }
175
176 in_uint32_be(c->in_s, size);
177
178 if (size < (8 + 2 + 2 + 2) || size > SCP_MAX_MESSAGE_SIZE)
179 {
180 LOG(LOG_LEVEL_WARNING, "connection aborted: msg size = %d", size);
181 return SCP_CLIENT_STATE_SIZE_ERR;
182 }
183
184 /* getting payload */
185 init_stream(c->in_s, size - 8);
186
187 if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, size - 8))
188 {
189 LOG(LOG_LEVEL_WARNING, "connection aborted: network error");
190 return SCP_CLIENT_STATE_NETWORK_ERR;
191 }
192
193 c->in_s->end = c->in_s->data + (size - 8);
194
195 /* check code */
196 in_uint16_be(c->in_s, sz);
197
198 if (3 != sz)
199 {
200 LOG(LOG_LEVEL_WARNING, "connection aborted: sequence error");
201 return SCP_CLIENT_STATE_SEQUENCE_ERR;
202 }
203
204 /* message payload */
205 in_uint16_be(c->in_s, sz);
206
207 if (1 != sz)
208 {
209 LOG(LOG_LEVEL_WARNING, "connection aborted: connection denied");
210 return SCP_CLIENT_STATE_CONNECTION_DENIED;
211 }
212
213 in_uint16_be(c->in_s, sz);
214 s->display = sz;
215
216 LOG_DEVEL(LOG_LEVEL_DEBUG, "connection terminated");
217 return SCP_CLIENT_STATE_END;
218 }
219
220 /**
221 * Initialises a V0 session object
222 *
223 * At the time of the call, the version has been read from the connection
224 *
225 * @param c Connection
226 * @param [out] session pre-allocated session object
227 * @return SCP_SERVER_STATE_OK for success
228 */
229 static enum SCP_SERVER_STATES_E
scp_v0s_init_session(struct SCP_CONNECTION * c,struct SCP_SESSION * session)230 scp_v0s_init_session(struct SCP_CONNECTION *c, struct SCP_SESSION *session)
231 {
232 int size;
233 tui16 height;
234 tui16 width;
235 tui16 bpp;
236 tui32 code = 0;
237 char buf[STRING16_MAX_LEN + 1];
238
239 scp_session_set_version(session, 0);
240
241 /* Check for a header and a code value in the length */
242 in_uint32_be(c->in_s, size);
243 if (size < (8 + 2) || size > SCP_MAX_MESSAGE_SIZE)
244 {
245 LOG(LOG_LEVEL_WARNING, "connection aborted: msg size = %d", size);
246 return SCP_SERVER_STATE_SIZE_ERR;
247 }
248
249 init_stream(c->in_s, size - 8);
250
251 if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, size - 8))
252 {
253 LOG(LOG_LEVEL_WARNING, "connection aborted: network error");
254 return SCP_SERVER_STATE_NETWORK_ERR;
255 }
256
257 c->in_s->end = c->in_s->data + (size - 8);
258
259 in_uint16_be(c->in_s, code);
260
261 if (code == 0 || code == 10 || code == 20)
262 {
263 if (code == 0)
264 {
265 scp_session_set_type(session, SCP_SESSION_TYPE_XVNC);
266 }
267 else if (code == 10)
268 {
269 scp_session_set_type(session, SCP_SESSION_TYPE_XRDP);
270 }
271 else if (code == 20)
272 {
273 scp_session_set_type(session, SCP_SESSION_TYPE_XORG);
274 }
275
276 /* reading username */
277 if (!in_string16(c->in_s, buf, "username"))
278 {
279 return SCP_SERVER_STATE_SIZE_ERR;
280 }
281 if (0 != scp_session_set_username(session, buf))
282 {
283 LOG(LOG_LEVEL_WARNING, "connection aborted: error setting username");
284 return SCP_SERVER_STATE_INTERNAL_ERR;
285 }
286
287 /* reading password */
288 if (!in_string16(c->in_s, buf, "passwd"))
289 {
290 return SCP_SERVER_STATE_SIZE_ERR;
291 }
292 if (0 != scp_session_set_password(session, buf))
293 {
294 LOG(LOG_LEVEL_WARNING, "connection aborted: error setting password");
295 return SCP_SERVER_STATE_INTERNAL_ERR;
296 }
297
298 /* width + height + bpp */
299 if (!s_check_rem(c->in_s, 2 + 2 + 2))
300 {
301 LOG(LOG_LEVEL_WARNING, "connection aborted: width+height+bpp missing");
302 return SCP_SERVER_STATE_SIZE_ERR;
303 }
304 in_uint16_be(c->in_s, width);
305 scp_session_set_width(session, width);
306 in_uint16_be(c->in_s, height);
307 scp_session_set_height(session, height);
308 in_uint16_be(c->in_s, bpp);
309 if (0 != scp_session_set_bpp(session, (tui8)bpp))
310 {
311 LOG(LOG_LEVEL_WARNING,
312 "connection aborted: unsupported bpp: %d", (tui8)bpp);
313 return SCP_SERVER_STATE_INTERNAL_ERR;
314 }
315
316 if (s_check_rem(c->in_s, 2))
317 {
318 /* reading domain */
319 if (!in_string16(c->in_s, buf, "domain"))
320 {
321 return SCP_SERVER_STATE_SIZE_ERR;
322 }
323 if (buf[0] != '\0')
324 {
325 scp_session_set_domain(session, buf);
326 }
327 }
328
329 if (s_check_rem(c->in_s, 2))
330 {
331 /* reading program */
332 if (!in_string16(c->in_s, buf, "program"))
333 {
334 return SCP_SERVER_STATE_SIZE_ERR;
335 }
336
337 if (buf[0] != '\0')
338 {
339 scp_session_set_program(session, buf);
340 }
341 }
342
343 if (s_check_rem(c->in_s, 2))
344 {
345 /* reading directory */
346 if (!in_string16(c->in_s, buf, "directory"))
347 {
348 return SCP_SERVER_STATE_SIZE_ERR;
349 }
350
351 if (buf[0] != '\0')
352 {
353 scp_session_set_directory(session, buf);
354 }
355 }
356
357 if (s_check_rem(c->in_s, 2))
358 {
359 /* reading client IP address */
360 if (!in_string16(c->in_s, buf, "client IP"))
361 {
362 return SCP_SERVER_STATE_SIZE_ERR;
363 }
364 if (buf[0] != '\0')
365 {
366 scp_session_set_client_ip(session, buf);
367 }
368 }
369 }
370 else if (code == SCP_GW_AUTHENTICATION)
371 {
372 scp_session_set_type(session, SCP_GW_AUTHENTICATION);
373 /* reading username */
374 if (!in_string16(c->in_s, buf, "username"))
375 {
376 return SCP_SERVER_STATE_SIZE_ERR;
377 }
378
379 /* g_writeln("Received user name: %s",buf); */
380 if (0 != scp_session_set_username(session, buf))
381 {
382 LOG(LOG_LEVEL_WARNING, "connection aborted: error setting username");
383 return SCP_SERVER_STATE_INTERNAL_ERR;
384 }
385
386 /* reading password */
387 if (!in_string16(c->in_s, buf, "passwd"))
388 {
389 return SCP_SERVER_STATE_SIZE_ERR;
390 }
391
392 /* g_writeln("Received password: %s",buf); */
393 if (0 != scp_session_set_password(session, buf))
394 {
395 LOG(LOG_LEVEL_WARNING, "connection aborted: error setting password");
396 return SCP_SERVER_STATE_INTERNAL_ERR;
397 }
398 }
399 else
400 {
401 LOG(LOG_LEVEL_WARNING, "connection aborted: sequence error");
402 return SCP_SERVER_STATE_SEQUENCE_ERR;
403 }
404
405 return SCP_SERVER_STATE_OK;
406 }
407
408
409 /* server API */
410 /******************************************************************************/
411 enum SCP_SERVER_STATES_E
scp_v0s_accept(struct SCP_CONNECTION * c,struct SCP_SESSION ** s,int skipVchk)412 scp_v0s_accept(struct SCP_CONNECTION *c, struct SCP_SESSION **s, int skipVchk)
413 {
414 enum SCP_SERVER_STATES_E result = SCP_SERVER_STATE_OK;
415 struct SCP_SESSION *session = NULL;
416 tui32 version = 0;
417
418 if (!skipVchk)
419 {
420 LOG_DEVEL(LOG_LEVEL_DEBUG, "starting connection");
421
422 if (0 == scp_tcp_force_recv(c->in_sck, c->in_s->data, 8))
423 {
424 c->in_s->end = c->in_s->data + 8;
425 in_uint32_be(c->in_s, version);
426
427 if (version != 0)
428 {
429 LOG(LOG_LEVEL_WARNING, "connection aborted: version error");
430 result = SCP_SERVER_STATE_VERSION_ERR;
431 }
432 }
433 else
434 {
435 LOG(LOG_LEVEL_WARNING, "connection aborted: network error");
436 result = SCP_SERVER_STATE_NETWORK_ERR;
437 }
438 }
439
440 if (result == SCP_SERVER_STATE_OK)
441 {
442 session = scp_session_create();
443 if (NULL == session)
444 {
445 LOG(LOG_LEVEL_WARNING, "connection aborted: no memory");
446 result = SCP_SERVER_STATE_INTERNAL_ERR;
447 }
448 else
449 {
450 result = scp_v0s_init_session(c, session);
451 if (result != SCP_SERVER_STATE_OK)
452 {
453 scp_session_destroy(session);
454 session = NULL;
455 }
456 }
457 }
458
459 (*s) = session;
460
461 return result;
462 }
463
464 /******************************************************************************/
465 enum SCP_SERVER_STATES_E
scp_v0s_allow_connection(struct SCP_CONNECTION * c,SCP_DISPLAY d,const tui8 * guid)466 scp_v0s_allow_connection(struct SCP_CONNECTION *c, SCP_DISPLAY d, const tui8 *guid)
467 {
468 int msg_size;
469
470 msg_size = guid == 0 ? 14 : 14 + 16;
471 out_uint32_be(c->out_s, 0); /* version */
472 out_uint32_be(c->out_s, msg_size); /* size */
473 out_uint16_be(c->out_s, 3); /* cmd */
474 out_uint16_be(c->out_s, 1); /* data */
475 out_uint16_be(c->out_s, d); /* data */
476 if (msg_size > 14)
477 {
478 out_uint8a(c->out_s, guid, 16);
479 }
480 s_mark_end(c->out_s);
481
482 if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, c->out_s->end - c->out_s->data))
483 {
484 LOG(LOG_LEVEL_WARNING, "connection aborted: network error");
485 return SCP_SERVER_STATE_NETWORK_ERR;
486 }
487
488 LOG_DEVEL(LOG_LEVEL_DEBUG, "connection terminated (allowed)");
489 return SCP_SERVER_STATE_OK;
490 }
491
492 /******************************************************************************/
493 enum SCP_SERVER_STATES_E
scp_v0s_deny_connection(struct SCP_CONNECTION * c)494 scp_v0s_deny_connection(struct SCP_CONNECTION *c)
495 {
496 out_uint32_be(c->out_s, 0); /* version */
497 out_uint32_be(c->out_s, 14); /* size */
498 out_uint16_be(c->out_s, 3); /* cmd */
499 out_uint16_be(c->out_s, 0); /* data = 0 - means NOT ok*/
500 out_uint16_be(c->out_s, 0); /* reserved for display number*/
501 s_mark_end(c->out_s);
502
503 if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, c->out_s->end - c->out_s->data))
504 {
505 LOG(LOG_LEVEL_WARNING, "connection aborted: network error");
506 return SCP_SERVER_STATE_NETWORK_ERR;
507 }
508
509 LOG_DEVEL(LOG_LEVEL_DEBUG, "connection terminated (denied)");
510 return SCP_SERVER_STATE_OK;
511 }
512
513 /******************************************************************************/
514 enum SCP_SERVER_STATES_E
scp_v0s_replyauthentication(struct SCP_CONNECTION * c,unsigned short int value)515 scp_v0s_replyauthentication(struct SCP_CONNECTION *c, unsigned short int value)
516 {
517 out_uint32_be(c->out_s, 0); /* version */
518 out_uint32_be(c->out_s, 14); /* size */
519 /* cmd SCP_GW_AUTHENTICATION means authentication reply */
520 out_uint16_be(c->out_s, SCP_GW_AUTHENTICATION);
521 out_uint16_be(c->out_s, value); /* reply code */
522 out_uint16_be(c->out_s, 0); /* dummy data */
523 s_mark_end(c->out_s);
524
525 /* g_writeln("Total number of bytes that will be sent %d",c->out_s->end - c->out_s->data);*/
526 if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, c->out_s->end - c->out_s->data))
527 {
528 LOG(LOG_LEVEL_WARNING, "connection aborted: network error");
529 return SCP_SERVER_STATE_NETWORK_ERR;
530 }
531
532 LOG_DEVEL(LOG_LEVEL_DEBUG, "connection terminated (scp_v0s_deny_authentication)");
533 return SCP_SERVER_STATE_OK;
534 }
535