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