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_v1s.c
22  * @brief libscp version 1 server api code
23  * @author Simone Fedele
24  *
25  */
26 
27 #if defined(HAVE_CONFIG_H)
28 #include <config_ac.h>
29 #endif
30 
31 #ifndef LIBSCP_V1S_C
32 #define LIBSCP_V1S_C
33 
34 #include "libscp_v1s.h"
35 #include "string_calls.h"
36 
37 //extern struct log_config* s_log;
38 
39 /**
40  * Reads a uint8 followed by a string into a buffer
41  *
42  * Buffer is null-terminated on success
43  *
44  * @param s Input stream
45  * @param [out] Output buffer (must be >= 256 chars)
46  * @param param Parameter we're reading
47  * @param line Line number reference
48  * @return != 0 if string read OK
49  *
50  * @todo
51  *     This needs to be merged with the func of the same name in
52  *     libscp_v1s_mng.c
53  */
54 static
in_string8(struct stream * s,char str[],const char * param,int line)55 int in_string8(struct stream *s, char str[], const char *param, int line)
56 {
57     int result;
58 
59     if (!s_check_rem(s, 1))
60     {
61         LOG(LOG_LEVEL_WARNING,
62             "[v1s:%d] connection aborted: %s len missing",
63             line, param);
64         result = 0;
65     }
66     else
67     {
68         unsigned int sz;
69 
70         in_uint8(s, sz);
71         result = s_check_rem(s, sz);
72         if (!result)
73         {
74             LOG(LOG_LEVEL_WARNING,
75                 "[v1s:%d] connection aborted: %s data missing",
76                 line, param);
77         }
78         else
79         {
80             in_uint8a(s, str, sz);
81             str[sz] = '\0';
82         }
83     }
84     return result;
85 }
86 /* server API */
87 
88 /**
89  * Initialises a V1 session object
90  *
91  * This is called after the V1 header, command set and command have been read
92  *
93  * @param c Connection
94  * @param [out] session pre-allocated session object
95  * @return SCP_SERVER_STATE_OK for success
96  */
97 static enum SCP_SERVER_STATES_E
scp_v1s_init_session(struct SCP_CONNECTION * c,struct SCP_SESSION * session)98 scp_v1s_init_session(struct SCP_CONNECTION *c, struct SCP_SESSION *session)
99 {
100     tui8 type;
101     tui16 height;
102     tui16 width;
103     tui8 bpp;
104     tui8 sz;
105     char buf[256];
106 
107     scp_session_set_version(session, 1);
108 
109     /* Check there's data for the session type, the height, the width, the
110      * bpp, the resource sharing indicator and the locale */
111     if (!s_check_rem(c->in_s, 1 + 2 + 2 + 1 + 1 + 17))
112     {
113         LOG(LOG_LEVEL_WARNING,
114             "[v1s:%d] connection aborted: short packet",
115             __LINE__);
116         return SCP_SERVER_STATE_SIZE_ERR;
117     }
118 
119     in_uint8(c->in_s, type);
120 
121     if ((type != SCP_SESSION_TYPE_XVNC) && (type != SCP_SESSION_TYPE_XRDP))
122     {
123         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: unknown session type", __LINE__);
124         return SCP_SERVER_STATE_SESSION_TYPE_ERR;
125     }
126 
127     scp_session_set_type(session, type);
128 
129     in_uint16_be(c->in_s, height);
130     scp_session_set_height(session, height);
131     in_uint16_be(c->in_s, width);
132     scp_session_set_width(session, width);
133     in_uint8(c->in_s, bpp);
134     if (0 != scp_session_set_bpp(session, bpp))
135     {
136         LOG(LOG_LEVEL_WARNING,
137             "[v1s:%d] connection aborted: unsupported bpp: %d",
138             __LINE__, bpp);
139         return SCP_SERVER_STATE_INTERNAL_ERR;
140     }
141     in_uint8(c->in_s, sz);
142     scp_session_set_rsr(session, sz);
143     in_uint8a(c->in_s, buf, 17);
144     buf[17] = '\0';
145     scp_session_set_locale(session, buf);
146 
147     /* Check there's enough data left for at least an IPv4 address (+len) */
148     if (!s_check_rem(c->in_s, 1 + 4))
149     {
150         LOG(LOG_LEVEL_WARNING,
151             "[v1s:%d] connection aborted: IP addr len missing",
152             __LINE__);
153         return SCP_SERVER_STATE_SIZE_ERR;
154     }
155 
156     in_uint8(c->in_s, sz);
157 
158     if (sz == SCP_ADDRESS_TYPE_IPV4)
159     {
160         tui32 ipv4;
161         in_uint32_be(c->in_s, ipv4);
162         scp_session_set_addr(session, sz, &ipv4);
163     }
164     else if (sz == SCP_ADDRESS_TYPE_IPV6)
165     {
166         if (!s_check_rem(c->in_s, 16))
167         {
168             LOG(LOG_LEVEL_WARNING,
169                 "[v1s:%d] connection aborted: IP addr missing",
170                 __LINE__);
171             return SCP_SERVER_STATE_SIZE_ERR;
172         }
173         in_uint8a(c->in_s, buf, 16);
174         scp_session_set_addr(session, sz, buf);
175     }
176 
177     /* reading hostname */
178     if (!in_string8(c->in_s, buf, "hostname", __LINE__))
179     {
180         return SCP_SERVER_STATE_SIZE_ERR;
181     }
182 
183     if (0 != scp_session_set_hostname(session, buf))
184     {
185         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__);
186         return SCP_SERVER_STATE_INTERNAL_ERR;
187     }
188 
189     /* reading username */
190     if (!in_string8(c->in_s, buf, "username", __LINE__))
191     {
192         return SCP_SERVER_STATE_SIZE_ERR;
193     }
194 
195     if (0 != scp_session_set_username(session, buf))
196     {
197         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__);
198         return SCP_SERVER_STATE_INTERNAL_ERR;
199     }
200 
201     /* reading password */
202     if (!in_string8(c->in_s, buf, "passwd", __LINE__))
203     {
204         return SCP_SERVER_STATE_SIZE_ERR;
205     }
206 
207     if (0 != scp_session_set_password(session, buf))
208     {
209         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__);
210         return SCP_SERVER_STATE_INTERNAL_ERR;
211     }
212 
213     return SCP_SERVER_STATE_OK;
214 }
215 
216 /* server API */
scp_v1s_accept(struct SCP_CONNECTION * c,struct SCP_SESSION ** s,int skipVchk)217 enum SCP_SERVER_STATES_E scp_v1s_accept(struct SCP_CONNECTION *c, struct SCP_SESSION **s, int skipVchk)
218 {
219     enum SCP_SERVER_STATES_E result;
220     struct SCP_SESSION *session;
221     tui32 version;
222     int size;
223     tui16 cmdset;
224     tui16 cmd;
225 
226     (*s) = NULL;
227 
228     if (!skipVchk)
229     {
230 
231         if (0 == scp_tcp_force_recv(c->in_sck, c->in_s->data, 8))
232         {
233             in_uint32_be(c->in_s, version);
234 
235             if (version != 1)
236             {
237                 LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: version error", __LINE__);
238                 return SCP_SERVER_STATE_VERSION_ERR;
239             }
240         }
241         else
242         {
243             LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
244             return SCP_SERVER_STATE_NETWORK_ERR;
245         }
246     }
247 
248     in_uint32_be(c->in_s, size);
249 
250     /* Check the message is big enough for the header, the command set, and
251      * the command (but not too big) */
252     if (size < (8 + 2 + 2) || size > SCP_MAX_MESSAGE_SIZE)
253     {
254         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: size error", __LINE__);
255         return SCP_SERVER_STATE_SIZE_ERR;
256     }
257 
258     init_stream(c->in_s, size - 8);
259 
260     if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, (size - 8)))
261     {
262         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
263         return SCP_SERVER_STATE_NETWORK_ERR;
264     }
265 
266     c->in_s->end = c->in_s->data + (size - 8);
267 
268     /* reading command set */
269     in_uint16_be(c->in_s, cmdset);
270 
271     /* if we are starting a management session */
272     if (cmdset == SCP_COMMAND_SET_MANAGE)
273     {
274         LOG(LOG_LEVEL_DEBUG, "[v1s:%d] requested management connection", __LINE__);
275         /* should return SCP_SERVER_STATE_START_MANAGE */
276         return scp_v1s_mng_accept(c, s);
277     }
278 
279     /* if we started with resource sharing... */
280     if (cmdset == SCP_COMMAND_SET_RSR)
281     {
282         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__);
283         return SCP_SERVER_STATE_SEQUENCE_ERR;
284     }
285 
286     /* reading command */
287     in_uint16_be(c->in_s, cmd);
288 
289     if (cmd != 1)
290     {
291         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__);
292         return SCP_SERVER_STATE_SEQUENCE_ERR;
293     }
294 
295     session = scp_session_create();
296 
297     if (NULL == session)
298     {
299         LOG(LOG_LEVEL_WARNING,
300             "[v1s:%d] connection aborted: internal error "
301             "(malloc returned NULL)", __LINE__);
302         result = SCP_SERVER_STATE_INTERNAL_ERR;
303     }
304     else
305     {
306         result = scp_v1s_init_session(c, session);
307         if (result != SCP_SERVER_STATE_OK)
308         {
309             scp_session_destroy(session);
310             session = NULL;
311         }
312     }
313 
314     /* returning the struct */
315     (*s) = session;
316 
317     return result;
318 }
319 
320 enum SCP_SERVER_STATES_E
scp_v1s_deny_connection(struct SCP_CONNECTION * c,const char * reason)321 scp_v1s_deny_connection(struct SCP_CONNECTION *c, const char *reason)
322 {
323     int rlen;
324 
325     init_stream(c->out_s, c->out_s->size);
326 
327     /* forcing message not to exceed 64k */
328     rlen = g_strlen(reason);
329 
330     if (rlen > 65535)
331     {
332         rlen = 65535;
333     }
334 
335     out_uint32_be(c->out_s, 1);
336     /* packet size: 4 + 4 + 2 + 2 + 2 + strlen(reason)*/
337     /* version + size + cmdset + cmd + msglen + msg */
338     out_uint32_be(c->out_s, rlen + 14);
339     out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT);
340     out_uint16_be(c->out_s, 2);
341     out_uint16_be(c->out_s, rlen);
342     out_uint8p(c->out_s, reason, rlen);
343 
344     if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, rlen + 14))
345     {
346         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
347         return SCP_SERVER_STATE_NETWORK_ERR;
348     }
349 
350     return SCP_SERVER_STATE_END;
351 }
352 
353 enum SCP_SERVER_STATES_E
scp_v1s_request_password(struct SCP_CONNECTION * c,struct SCP_SESSION * s,const char * reason)354 scp_v1s_request_password(struct SCP_CONNECTION *c, struct SCP_SESSION *s,
355                          const char *reason)
356 {
357     tui32 version;
358     int size;
359     tui16 cmdset;
360     tui16 cmd;
361     int rlen;
362     char buf[256];
363 
364     init_stream(c->in_s, c->in_s->size);
365     init_stream(c->out_s, c->out_s->size);
366 
367     /* forcing message not to exceed 64k */
368     rlen = g_strlen(reason);
369 
370     if (rlen > 65535)
371     {
372         rlen = 65535;
373     }
374 
375     /* send password request */
376     version = 1;
377     cmd = 3;
378 
379     out_uint32_be(c->out_s, version);                 /* version */
380     out_uint32_be(c->out_s, 14 + rlen);               /* size    */
381     out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); /* cmdset  */
382     out_uint16_be(c->out_s, cmd);                     /* cmd     */
383 
384     out_uint16_be(c->out_s, rlen);
385     out_uint8p(c->out_s, reason, rlen);
386 
387     if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, 14 + rlen))
388     {
389         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
390         return SCP_SERVER_STATE_NETWORK_ERR;
391     }
392 
393     /* receive password & username */
394     if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, 8))
395     {
396         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
397         return SCP_SERVER_STATE_NETWORK_ERR;
398     }
399 
400     in_uint32_be(c->in_s, version);
401 
402     if (version != 1)
403     {
404         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: version error", __LINE__);
405         return SCP_SERVER_STATE_VERSION_ERR;
406     }
407 
408     in_uint32_be(c->in_s, size);
409 
410     /* Check the message is big enough for the header, the command set, and
411      * the command (but not too big) */
412     if (size < (8 + 2 + 2) || size > SCP_MAX_MESSAGE_SIZE)
413     {
414         LOG(LOG_LEVEL_WARNING,
415             "[v1s:%d] connection aborted: size error",
416             __LINE__);
417         return SCP_SERVER_STATE_SIZE_ERR;
418     }
419 
420     init_stream(c->in_s, size - 8);
421 
422     if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, (size - 8)))
423     {
424         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
425         return SCP_SERVER_STATE_NETWORK_ERR;
426     }
427 
428     c->in_s->end = c->in_s->data + (size - 8);
429 
430     in_uint16_be(c->in_s, cmdset);
431 
432     if (cmdset != SCP_COMMAND_SET_DEFAULT)
433     {
434         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__);
435         return SCP_SERVER_STATE_SEQUENCE_ERR;
436     }
437 
438     in_uint16_be(c->in_s, cmd);
439 
440     if (cmd != 4)
441     {
442         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__);
443         return SCP_SERVER_STATE_SEQUENCE_ERR;
444     }
445 
446     /* reading username */
447     if (!in_string8(c->in_s, buf, "username", __LINE__))
448     {
449         return SCP_SERVER_STATE_SIZE_ERR;
450     }
451 
452     if (0 != scp_session_set_username(s, buf))
453     {
454         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__);
455         return SCP_SERVER_STATE_INTERNAL_ERR;
456     }
457 
458     /* reading password */
459     if (!in_string8(c->in_s, buf, "passwd", __LINE__))
460     {
461         return SCP_SERVER_STATE_SIZE_ERR;
462     }
463 
464     if (0 != scp_session_set_password(s, buf))
465     {
466         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__);
467         return SCP_SERVER_STATE_INTERNAL_ERR;
468     }
469 
470     return SCP_SERVER_STATE_OK;
471 }
472 
473 /* 020 */
474 enum SCP_SERVER_STATES_E
scp_v1s_request_pwd_change(struct SCP_CONNECTION * c,char * reason,char * npw)475 scp_v1s_request_pwd_change(struct SCP_CONNECTION *c, char *reason, char *npw)
476 {
477     return SCP_SERVER_STATE_INTERNAL_ERR;
478 }
479 
480 /* 023 */
481 enum SCP_SERVER_STATES_E
scp_v1s_pwd_change_error(struct SCP_CONNECTION * c,char * error,int retry,char * npw)482 scp_v1s_pwd_change_error(struct SCP_CONNECTION *c, char *error, int retry, char *npw)
483 {
484     return SCP_SERVER_STATE_INTERNAL_ERR;
485 }
486 
487 /* 030 */
488 enum SCP_SERVER_STATES_E
scp_v1s_connect_new_session(struct SCP_CONNECTION * c,SCP_DISPLAY d)489 scp_v1s_connect_new_session(struct SCP_CONNECTION *c, SCP_DISPLAY d)
490 {
491     /* send password request */
492     tui32 version = 1;
493     tui32 size = 14;
494     tui16 cmd = 30;
495 
496     init_stream(c->out_s, c->out_s->size);
497 
498     out_uint32_be(c->out_s, version);                 /* version */
499     out_uint32_be(c->out_s, size);                    /* size    */
500     out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); /* cmdset  */
501     out_uint16_be(c->out_s, cmd);                     /* cmd     */
502 
503     out_uint16_be(c->out_s, d);                       /* display */
504 
505     if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, 14))
506     {
507         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
508         return SCP_SERVER_STATE_NETWORK_ERR;
509     }
510 
511     return SCP_SERVER_STATE_OK;
512 }
513 
514 /* 032 */
515 enum SCP_SERVER_STATES_E
scp_v1s_connection_error(struct SCP_CONNECTION * c,const char * error)516 scp_v1s_connection_error(struct SCP_CONNECTION *c, const char *error)
517 {
518     tui16 len;
519 
520     len = g_strlen(error);
521     init_stream(c->out_s, c->out_s->size);
522 
523     out_uint32_be(c->out_s, 1);
524     /* packet size: 4 + 4 + 2 + 2 + len */
525     /* version + size + cmdset + cmd */
526     out_uint32_be(c->out_s, (12 + len));
527     out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT);
528     out_uint16_be(c->out_s, SCP_CMD_CONN_ERROR);
529 
530     if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, (12 + len)))
531     {
532         return SCP_SERVER_STATE_NETWORK_ERR;
533     }
534 
535     return SCP_SERVER_STATE_END;
536 }
537 
538 /* 040 */
539 enum SCP_SERVER_STATES_E
scp_v1s_list_sessions(struct SCP_CONNECTION * c,int sescnt,struct SCP_DISCONNECTED_SESSION * ds,SCP_SID * sid)540 scp_v1s_list_sessions(struct SCP_CONNECTION *c, int sescnt, struct SCP_DISCONNECTED_SESSION *ds, SCP_SID *sid)
541 {
542     tui32 version = 1;
543     int size = 12;
544     tui16 cmd = 40;
545     int pktcnt;
546     int idx;
547     int sidx;
548     int pidx;
549     struct SCP_DISCONNECTED_SESSION *cds;
550 
551     /* first we send a notice that we have some disconnected sessions */
552     init_stream(c->out_s, c->out_s->size);
553 
554     out_uint32_be(c->out_s, version);                 /* version */
555     out_uint32_be(c->out_s, size);                    /* size    */
556     out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); /* cmdset  */
557     out_uint16_be(c->out_s, cmd);                     /* cmd     */
558 
559     if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, size))
560     {
561         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
562         return SCP_SERVER_STATE_NETWORK_ERR;
563     }
564 
565     /* then we wait for client ack */
566 
567     /*
568      * Maybe this message could say if the session should be resized on
569      * server side or client side.
570      */
571     init_stream(c->in_s, c->in_s->size);
572 
573     if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, 8))
574     {
575         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
576         return SCP_SERVER_STATE_NETWORK_ERR;
577     }
578 
579     in_uint32_be(c->in_s, version);
580 
581     if (version != 1)
582     {
583         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: version error", __LINE__);
584         return SCP_SERVER_STATE_VERSION_ERR;
585     }
586 
587     in_uint32_be(c->in_s, size);
588 
589     /* Check the message is big enough for the header, the command set, and
590      * the command (but not too big) */
591     if (size < (8 + 2 + 2) || size > SCP_MAX_MESSAGE_SIZE)
592     {
593         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: size error", __LINE__);
594         return SCP_SERVER_STATE_SIZE_ERR;
595     }
596 
597     init_stream(c->in_s, size - 8);
598 
599     if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, (size - 8)))
600     {
601         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
602         return SCP_SERVER_STATE_NETWORK_ERR;
603     }
604 
605     c->in_s->end = c->in_s->data + (size - 8);
606 
607     in_uint16_be(c->in_s, cmd);
608 
609     if (cmd != SCP_COMMAND_SET_DEFAULT)
610     {
611         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__);
612         return SCP_SERVER_STATE_SEQUENCE_ERR;
613     }
614 
615     in_uint16_be(c->in_s, cmd);
616 
617     if (cmd != 41)
618     {
619         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__);
620         return SCP_SERVER_STATE_SEQUENCE_ERR;
621     }
622 
623     /* calculating the number of packets to send */
624     pktcnt = sescnt / SCP_SERVER_MAX_LIST_SIZE;
625 
626     if ((sescnt % SCP_SERVER_MAX_LIST_SIZE) != 0)
627     {
628         pktcnt++;
629     }
630 
631     for (idx = 0; idx < pktcnt; idx++)
632     {
633         /* ok, we send session session list */
634         init_stream(c->out_s, c->out_s->size);
635 
636         /* size: ver+size+cmdset+cmd+sescnt+continue+count */
637         size = 4 + 4 + 2 + 2 + 4 + 1 + 1;
638 
639         /* header */
640         cmd = 42;
641         s_push_layer(c->out_s, channel_hdr, 8);
642         out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT);
643         out_uint16_be(c->out_s, cmd);
644 
645         /* session count */
646         out_uint32_be(c->out_s, sescnt);
647 
648         /* setting the continue flag */
649         if ((idx + 1)*SCP_SERVER_MAX_LIST_SIZE >= sescnt)
650         {
651             out_uint8(c->out_s, 0);
652             /* setting session count for this packet */
653             pidx = sescnt - (idx * SCP_SERVER_MAX_LIST_SIZE);
654             out_uint8(c->out_s, pidx);
655         }
656         else
657         {
658             out_uint8(c->out_s, 1);
659             /* setting session count for this packet */
660             pidx = SCP_SERVER_MAX_LIST_SIZE;
661             out_uint8(c->out_s, pidx);
662         }
663 
664         /* adding session descriptors */
665         for (sidx = 0; sidx < pidx; sidx++)
666         {
667             /* shortcut to the current session to send */
668             cds = ds + ((idx) * SCP_SERVER_MAX_LIST_SIZE) + sidx;
669 
670             /* session data */
671             out_uint32_be(c->out_s, cds->SID); /* session id */
672             out_uint8(c->out_s, cds->type);
673             out_uint16_be(c->out_s, cds->height);
674             out_uint16_be(c->out_s, cds->width);
675             out_uint8(c->out_s, cds->bpp);
676             out_uint8(c->out_s, cds->idle_days);
677             out_uint8(c->out_s, cds->idle_hours);
678             out_uint8(c->out_s, cds->idle_minutes);
679             size += 13;
680 
681             out_uint16_be(c->out_s, cds->conn_year);
682             out_uint8(c->out_s, cds->conn_month);
683             out_uint8(c->out_s, cds->conn_day);
684             out_uint8(c->out_s, cds->conn_hour);
685             out_uint8(c->out_s, cds->conn_minute);
686             out_uint8(c->out_s, cds->addr_type);
687             size += 7;
688 
689             if (cds->addr_type == SCP_ADDRESS_TYPE_IPV4)
690             {
691                 in_uint32_be(c->out_s, cds->ipv4addr);
692                 size += 4;
693             }
694             else if (cds->addr_type == SCP_ADDRESS_TYPE_IPV6)
695             {
696                 in_uint8a(c->out_s, cds->ipv6addr, 16);
697                 size += 16;
698             }
699         }
700 
701         s_pop_layer(c->out_s, channel_hdr);
702         out_uint32_be(c->out_s, version);
703         out_uint32_be(c->out_s, size);
704 
705         if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, size))
706         {
707             LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
708             return SCP_SERVER_STATE_NETWORK_ERR;
709         }
710     }
711 
712     /* we get the response */
713     init_stream(c->in_s, c->in_s->size);
714 
715     if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, (8)))
716     {
717         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
718         return SCP_SERVER_STATE_NETWORK_ERR;
719     }
720 
721     in_uint32_be(c->in_s, version);
722 
723     if (version != 1)
724     {
725         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: version error", __LINE__);
726         return SCP_SERVER_STATE_VERSION_ERR;
727     }
728 
729     in_uint32_be(c->in_s, size);
730 
731     /* Check the message is big enough for the header, the command set, and
732      * the command (but not too big) */
733     if (size < (8 + 2 + 2) || size > SCP_MAX_MESSAGE_SIZE)
734     {
735         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: size error", __LINE__);
736         return SCP_SERVER_STATE_SIZE_ERR;
737     }
738 
739     /* rest of the packet */
740     init_stream(c->in_s, size - 8);
741 
742     if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, (size - 8)))
743     {
744         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
745         return SCP_SERVER_STATE_NETWORK_ERR;
746     }
747 
748     c->in_s->end = c->in_s->data + (size - 8);
749 
750     in_uint16_be(c->in_s, cmd);
751 
752     if (cmd != SCP_COMMAND_SET_DEFAULT)
753     {
754         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__);
755         return SCP_SERVER_STATE_SEQUENCE_ERR;
756     }
757 
758     in_uint16_be(c->in_s, cmd);
759 
760     if (cmd == 43)
761     {
762         if (!s_check_rem(c->in_s, 4))
763         {
764             LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: missing session", __LINE__);
765             return SCP_SERVER_STATE_SIZE_ERR;
766         }
767         /* select session */
768         in_uint32_be(c->in_s, (*sid));
769 
770         /* checking sid value */
771         for (idx = 0; idx < sescnt; idx++)
772         {
773             /* the sid is valid */
774             if (ds[idx].SID == (*sid))
775             {
776                 /* ok, session selected */
777                 return SCP_SERVER_STATE_OK;
778             }
779         }
780 
781         /* if we got here, the requested sid wasn't one from the list we sent */
782         /* we should kill the connection                                      */
783         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error (no such session in list)", __LINE__);
784         return SCP_SERVER_STATE_INTERNAL_ERR;
785     }
786     else if (cmd == 44)
787     {
788         /* cancel connection */
789         return SCP_SERVER_STATE_SELECTION_CANCEL;
790     }
791     //  else if (cmd == 45)
792     //  {
793     //    /* force new connection */
794     //    return SCP_SERVER_STATE_FORCE_NEW;
795     //  }
796     else
797     {
798         /* wrong response */
799         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__);
800         return SCP_SERVER_STATE_SEQUENCE_ERR;
801     }
802 
803     return SCP_SERVER_STATE_OK;
804 }
805 
806 /* 046 was: 031 struct SCP_DISCONNECTED_SESSION* ds, */
807 enum SCP_SERVER_STATES_E
scp_v1s_reconnect_session(struct SCP_CONNECTION * c,SCP_DISPLAY d)808 scp_v1s_reconnect_session(struct SCP_CONNECTION *c, SCP_DISPLAY d)
809 {
810     tui32 version = 1;
811     tui32 size = 14;
812     tui16 cmd = 46;
813 
814     /* ok, we send session data and display */
815     init_stream(c->out_s, c->out_s->size);
816 
817     /* header */
818     out_uint32_be(c->out_s, version);
819     out_uint32_be(c->out_s, size);
820     out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT);
821     out_uint16_be(c->out_s, cmd);
822 
823     /* session data */
824     out_uint16_be(c->out_s, d); /* session display */
825     /*out_uint8(c->out_s, ds->type);
826     out_uint16_be(c->out_s, ds->height);
827     out_uint16_be(c->out_s, ds->width);
828     out_uint8(c->out_s, ds->bpp);
829     out_uint8(c->out_s, ds->idle_days);
830     out_uint8(c->out_s, ds->idle_hours);
831     out_uint8(c->out_s, ds->idle_minutes);*/
832     /* these last three are not really needed... */
833 
834     if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, size))
835     {
836         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
837         return SCP_SERVER_STATE_NETWORK_ERR;
838     }
839 
840     return SCP_SERVER_STATE_OK;
841 }
842 
843 #endif
844