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 
87 /**
88  * Initialises a V1 session object
89  *
90  * This is called after the V1 header, command set and command have been read
91  *
92  * @param c Connection
93  * @param [out] session pre-allocated session object
94  * @return SCP_SERVER_STATE_OK for success
95  */
96 static enum SCP_SERVER_STATES_E
scp_v1s_init_session(struct trans * t,struct SCP_SESSION * session)97 scp_v1s_init_session(struct trans *t, struct SCP_SESSION *session)
98 {
99     tui8 type;
100     tui16 height;
101     tui16 width;
102     tui8 bpp;
103     tui8 sz;
104     char buf[256];
105     struct stream *in_s = t->in_s;
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(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(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(in_s, height);
130     scp_session_set_height(session, height);
131     in_uint16_be(in_s, width);
132     scp_session_set_width(session, width);
133     in_uint8(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(in_s, sz);
142     scp_session_set_rsr(session, sz);
143     in_uint8a(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(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(in_s, sz);
157 
158     if (sz == SCP_ADDRESS_TYPE_IPV4)
159     {
160         tui32 ipv4;
161         in_uint32_be(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(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(in_s, buf, 16);
174         scp_session_set_addr(session, sz, buf);
175     }
176 
177     /* reading hostname */
178     if (!in_string8(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(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(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 */
217 enum SCP_SERVER_STATES_E
scp_v1s_accept(struct trans * t,struct SCP_SESSION * s)218 scp_v1s_accept(struct trans *t, struct SCP_SESSION *s)
219 {
220     tui32 size;
221     tui16 cmdset;
222     tui16 cmd;
223     struct stream *in_s = t->in_s;
224     enum SCP_SERVER_STATES_E result;
225 
226     in_uint32_be(in_s, size);
227 
228     /* Check the message is big enough for the header, the command set, and
229      * the command (but not too big) */
230     if (size < (8 + 2 + 2) || size > SCP_MAX_MESSAGE_SIZE)
231     {
232         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: size error", __LINE__);
233         return SCP_SERVER_STATE_SIZE_ERR;
234     }
235 
236     /* reading command set */
237     in_uint16_be(in_s, cmdset);
238 
239     /* if we are starting a management session */
240     if (cmdset == SCP_COMMAND_SET_MANAGE)
241     {
242         LOG(LOG_LEVEL_DEBUG, "[v1s:%d] requested management connection", __LINE__);
243         /* should return SCP_SERVER_STATE_START_MANAGE */
244         return scp_v1s_mng_accept(t, s);
245     }
246 
247     /* if we started with resource sharing... */
248     if (cmdset == SCP_COMMAND_SET_RSR)
249     {
250         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__);
251         return SCP_SERVER_STATE_SEQUENCE_ERR;
252     }
253 
254     /* reading command */
255     in_uint16_be(in_s, cmd);
256 
257     switch (cmd)
258     {
259         case SCP_CMD_LOGIN:
260             s->current_cmd = cmd;
261             result = scp_v1s_init_session(t, s);
262             break;
263 
264         case SCP_CMD_RESEND_CREDS:
265             result = scp_v1s_accept_password_reply(t, s);
266             s->current_cmd = SCP_CMD_LOGIN; /* Caller re-parses credentials */
267             break;
268 
269         default:
270             LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence "
271                 "error. Unrecognised cmd %d", __LINE__, cmd);
272             result = SCP_SERVER_STATE_SEQUENCE_ERR;
273     }
274 
275     return result;
276 }
277 
278 enum SCP_SERVER_STATES_E
scp_v1s_deny_connection(struct trans * t,const char * reason)279 scp_v1s_deny_connection(struct trans *t, const char *reason)
280 {
281     struct stream *out_s;
282     int rlen;
283 
284     /* forcing message not to exceed 64k */
285     rlen = g_strlen(reason);
286     if (rlen > 65535)
287     {
288         rlen = 65535;
289     }
290     out_s = trans_get_out_s(t, rlen + 14);
291     out_uint32_be(out_s, 1); /* version */
292     /* packet size: 4 + 4 + 2 + 2 + 2 + strlen(reason) */
293     /* version + size + cmdset + cmd + msglen + msg */
294     out_uint32_be(out_s, rlen + 14);
295     out_uint16_be(out_s, SCP_COMMAND_SET_DEFAULT);
296     out_uint16_be(out_s, SCP_REPLY_LOGIN_DENIED);
297     out_uint16_be(out_s, rlen);
298     out_uint8p(out_s, reason, rlen);
299     s_mark_end(out_s);
300     if (0 != trans_force_write(t))
301     {
302         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
303         return SCP_SERVER_STATE_NETWORK_ERR;
304     }
305     return SCP_SERVER_STATE_END;
306 }
307 
308 enum SCP_SERVER_STATES_E
scp_v1s_request_password(struct trans * t,struct SCP_SESSION * s,const char * reason)309 scp_v1s_request_password(struct trans *t, struct SCP_SESSION *s,
310                          const char *reason)
311 {
312     struct stream *out_s;
313     int rlen;
314 
315     /* forcing message not to exceed 64k */
316     rlen = g_strlen(reason);
317     if (rlen > 65535)
318     {
319         rlen = 65535;
320     }
321     out_s = trans_get_out_s(t, rlen + 14);
322     out_uint32_be(out_s, 1); /* version */
323     /* packet size: 4 + 4 + 2 + 2 + 2 + strlen(reason) */
324     /* version + size + cmdset + cmd + msglen + msg */
325     out_uint32_be(out_s, rlen + 14);
326     out_uint16_be(out_s, SCP_COMMAND_SET_DEFAULT);
327     out_uint16_be(out_s, SCP_REPLY_REREQUEST_CREDS);
328     out_uint16_be(out_s, rlen);
329     out_uint8p(out_s, reason, rlen);
330     s_mark_end(out_s);
331     if (0 != trans_force_write(t))
332     {
333         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
334         return SCP_SERVER_STATE_NETWORK_ERR;
335     }
336 
337     return SCP_SERVER_STATE_OK;
338 }
339 
340 enum SCP_SERVER_STATES_E
scp_v1s_accept_password_reply(struct trans * t,struct SCP_SESSION * s)341 scp_v1s_accept_password_reply(struct trans *t, struct SCP_SESSION *s)
342 {
343     struct stream *in_s;
344     char buf[257];
345 
346     in_s = t->in_s;
347     buf[256] = '\0';
348 
349     /* reading username */
350     if (!in_string8(in_s, buf, "username", __LINE__))
351     {
352         return SCP_SERVER_STATE_SIZE_ERR;
353     }
354     if (0 != scp_session_set_username(s, buf))
355     {
356         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error",
357             __LINE__);
358         return SCP_SERVER_STATE_INTERNAL_ERR;
359     }
360 
361     /* reading password */
362     if (!in_string8(in_s, buf, "passwd", __LINE__))
363     {
364         return SCP_SERVER_STATE_SIZE_ERR;
365     }
366 
367     if (0 != scp_session_set_password(s, buf))
368     {
369         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error",
370             __LINE__);
371         return SCP_SERVER_STATE_INTERNAL_ERR;
372     }
373 
374     return SCP_SERVER_STATE_OK;
375 }
376 
377 enum SCP_SERVER_STATES_E
scp_v1s_request_pwd_change(struct trans * t,char * reason,char * npw)378 scp_v1s_request_pwd_change(struct trans *t, char *reason, char *npw)
379 {
380     return SCP_SERVER_STATE_INTERNAL_ERR;
381 }
382 
383 enum SCP_SERVER_STATES_E
scp_v1s_pwd_change_error(struct trans * t,char * error,int retry,char * npw)384 scp_v1s_pwd_change_error(struct trans *t, char *error, int retry, char *npw)
385 {
386     return SCP_SERVER_STATE_INTERNAL_ERR;
387 }
388 
389 enum SCP_SERVER_STATES_E
scp_v1s_connect_new_session(struct trans * t,SCP_DISPLAY d)390 scp_v1s_connect_new_session(struct trans *t, SCP_DISPLAY d)
391 {
392     struct stream *out_s;
393 
394     out_s = trans_get_out_s(t, 14);
395     out_uint32_be(out_s, 1); /* version */
396     /* packet size: 4 + 4 + 2 + 2 + 2 */
397     /* version + size + cmdset + cmd + msglen + msg */
398     out_uint32_be(out_s, 14);
399     out_uint16_be(out_s, SCP_COMMAND_SET_DEFAULT);
400     out_uint16_be(out_s, SCP_REPLY_NEW_SESSION);
401     out_uint16_be(out_s, d);
402     s_mark_end(out_s);
403     if (0 != trans_force_write(t))
404     {
405         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
406         return SCP_SERVER_STATE_NETWORK_ERR;
407     }
408     return SCP_SERVER_STATE_OK;
409 }
410 
411 enum SCP_SERVER_STATES_E
scp_v1s_connection_error(struct trans * t,const char * error)412 scp_v1s_connection_error(struct trans *t, const char *error)
413 {
414     struct stream *out_s;
415     tui16 len;
416 
417     len = g_strlen(error);
418     if (len > 8192 - 12)
419     {
420         len = 8192 - 12;
421     }
422     out_s = trans_get_out_s(t, 12 + len);
423     out_uint32_be(out_s, 1); /* version */
424     /* packet size: 4 + 4 + 2 + 2 + len */
425     /* version + size + cmdset + cmd */
426     out_uint32_be(out_s, 12 + len);
427     out_uint16_be(out_s, SCP_COMMAND_SET_DEFAULT);
428     out_uint16_be(out_s, SCP_REPLY_CMD_CONN_ERROR);
429     out_uint8a(out_s, error, len);
430     s_mark_end(out_s);
431     if (0 != trans_force_write(t))
432     {
433         return SCP_SERVER_STATE_NETWORK_ERR;
434     }
435     return SCP_SERVER_STATE_END;
436 }
437 
438 #if 0
439 enum SCP_SERVER_STATES_E
440 scp_v1s_list_sessions(struct SCP_CONNECTION *c, int sescnt, struct SCP_DISCONNECTED_SESSION *ds, SCP_SID *sid)
441 {
442     tui32 version = 1;
443     int size = 12;
444     tui16 cmd = 40;
445     int pktcnt;
446     int idx;
447     int sidx;
448     int pidx;
449     struct SCP_DISCONNECTED_SESSION *cds;
450 
451     /* first we send a notice that we have some disconnected sessions */
452     init_stream(c->out_s, c->out_s->size);
453 
454     out_uint32_be(c->out_s, version);                 /* version */
455     out_uint32_be(c->out_s, size);                    /* size    */
456     out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); /* cmdset  */
457     out_uint16_be(c->out_s, cmd);                     /* cmd     */
458 
459     if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, size))
460     {
461         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
462         return SCP_SERVER_STATE_NETWORK_ERR;
463     }
464 
465     /* then we wait for client ack */
466 
467     /*
468      * Maybe this message could say if the session should be resized on
469      * server side or client side.
470      */
471     init_stream(c->in_s, c->in_s->size);
472 
473     if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, 8))
474     {
475         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
476         return SCP_SERVER_STATE_NETWORK_ERR;
477     }
478 
479     in_uint32_be(c->in_s, version);
480 
481     if (version != 1)
482     {
483         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: version error", __LINE__);
484         return SCP_SERVER_STATE_VERSION_ERR;
485     }
486 
487     in_uint32_be(c->in_s, size);
488 
489     /* Check the message is big enough for the header, the command set, and
490      * the command (but not too big) */
491     if (size < (8 + 2 + 2) || size > SCP_MAX_MESSAGE_SIZE)
492     {
493         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: size error", __LINE__);
494         return SCP_SERVER_STATE_SIZE_ERR;
495     }
496 
497     init_stream(c->in_s, size - 8);
498 
499     if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, (size - 8)))
500     {
501         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
502         return SCP_SERVER_STATE_NETWORK_ERR;
503     }
504 
505     c->in_s->end = c->in_s->data + (size - 8);
506 
507     in_uint16_be(c->in_s, cmd);
508 
509     if (cmd != SCP_COMMAND_SET_DEFAULT)
510     {
511         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__);
512         return SCP_SERVER_STATE_SEQUENCE_ERR;
513     }
514 
515     in_uint16_be(c->in_s, cmd);
516 
517     if (cmd != 41)
518     {
519         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__);
520         return SCP_SERVER_STATE_SEQUENCE_ERR;
521     }
522 
523     /* calculating the number of packets to send */
524     pktcnt = sescnt / SCP_SERVER_MAX_LIST_SIZE;
525 
526     if ((sescnt % SCP_SERVER_MAX_LIST_SIZE) != 0)
527     {
528         pktcnt++;
529     }
530 
531     for (idx = 0; idx < pktcnt; idx++)
532     {
533         /* ok, we send session session list */
534         init_stream(c->out_s, c->out_s->size);
535 
536         /* size: ver+size+cmdset+cmd+sescnt+continue+count */
537         size = 4 + 4 + 2 + 2 + 4 + 1 + 1;
538 
539         /* header */
540         cmd = 42;
541         s_push_layer(c->out_s, channel_hdr, 8);
542         out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT);
543         out_uint16_be(c->out_s, cmd);
544 
545         /* session count */
546         out_uint32_be(c->out_s, sescnt);
547 
548         /* setting the continue flag */
549         if ((idx + 1)*SCP_SERVER_MAX_LIST_SIZE >= sescnt)
550         {
551             out_uint8(c->out_s, 0);
552             /* setting session count for this packet */
553             pidx = sescnt - (idx * SCP_SERVER_MAX_LIST_SIZE);
554             out_uint8(c->out_s, pidx);
555         }
556         else
557         {
558             out_uint8(c->out_s, 1);
559             /* setting session count for this packet */
560             pidx = SCP_SERVER_MAX_LIST_SIZE;
561             out_uint8(c->out_s, pidx);
562         }
563 
564         /* adding session descriptors */
565         for (sidx = 0; sidx < pidx; sidx++)
566         {
567             /* shortcut to the current session to send */
568             cds = ds + ((idx) * SCP_SERVER_MAX_LIST_SIZE) + sidx;
569 
570             /* session data */
571             out_uint32_be(c->out_s, cds->SID); /* session id */
572             out_uint8(c->out_s, cds->type);
573             out_uint16_be(c->out_s, cds->height);
574             out_uint16_be(c->out_s, cds->width);
575             out_uint8(c->out_s, cds->bpp);
576             out_uint8(c->out_s, cds->idle_days);
577             out_uint8(c->out_s, cds->idle_hours);
578             out_uint8(c->out_s, cds->idle_minutes);
579             size += 13;
580 
581             out_uint16_be(c->out_s, cds->conn_year);
582             out_uint8(c->out_s, cds->conn_month);
583             out_uint8(c->out_s, cds->conn_day);
584             out_uint8(c->out_s, cds->conn_hour);
585             out_uint8(c->out_s, cds->conn_minute);
586             out_uint8(c->out_s, cds->addr_type);
587             size += 7;
588 
589             if (cds->addr_type == SCP_ADDRESS_TYPE_IPV4)
590             {
591                 in_uint32_be(c->out_s, cds->ipv4addr);
592                 size += 4;
593             }
594             else if (cds->addr_type == SCP_ADDRESS_TYPE_IPV6)
595             {
596                 in_uint8a(c->out_s, cds->ipv6addr, 16);
597                 size += 16;
598             }
599         }
600 
601         s_pop_layer(c->out_s, channel_hdr);
602         out_uint32_be(c->out_s, version);
603         out_uint32_be(c->out_s, size);
604 
605         if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, size))
606         {
607             LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
608             return SCP_SERVER_STATE_NETWORK_ERR;
609         }
610     }
611 
612     /* we get the response */
613     init_stream(c->in_s, c->in_s->size);
614 
615     if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, (8)))
616     {
617         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
618         return SCP_SERVER_STATE_NETWORK_ERR;
619     }
620 
621     in_uint32_be(c->in_s, version);
622 
623     if (version != 1)
624     {
625         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: version error", __LINE__);
626         return SCP_SERVER_STATE_VERSION_ERR;
627     }
628 
629     in_uint32_be(c->in_s, size);
630 
631     /* Check the message is big enough for the header, the command set, and
632      * the command (but not too big) */
633     if (size < (8 + 2 + 2) || size > SCP_MAX_MESSAGE_SIZE)
634     {
635         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: size error", __LINE__);
636         return SCP_SERVER_STATE_SIZE_ERR;
637     }
638 
639     /* rest of the packet */
640     init_stream(c->in_s, size - 8);
641 
642     if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, (size - 8)))
643     {
644         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
645         return SCP_SERVER_STATE_NETWORK_ERR;
646     }
647 
648     c->in_s->end = c->in_s->data + (size - 8);
649 
650     in_uint16_be(c->in_s, cmd);
651 
652     if (cmd != SCP_COMMAND_SET_DEFAULT)
653     {
654         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__);
655         return SCP_SERVER_STATE_SEQUENCE_ERR;
656     }
657 
658     in_uint16_be(c->in_s, cmd);
659 
660     if (cmd == 43)
661     {
662         if (!s_check_rem(c->in_s, 4))
663         {
664             LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: missing session", __LINE__);
665             return SCP_SERVER_STATE_SIZE_ERR;
666         }
667         /* select session */
668         in_uint32_be(c->in_s, (*sid));
669 
670         /* checking sid value */
671         for (idx = 0; idx < sescnt; idx++)
672         {
673             /* the sid is valid */
674             if (ds[idx].SID == (*sid))
675             {
676                 /* ok, session selected */
677                 return SCP_SERVER_STATE_OK;
678             }
679         }
680 
681         /* if we got here, the requested sid wasn't one from the list we sent */
682         /* we should kill the connection                                      */
683         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error (no such session in list)", __LINE__);
684         return SCP_SERVER_STATE_INTERNAL_ERR;
685     }
686     else if (cmd == 44)
687     {
688         /* cancel connection */
689         return SCP_SERVER_STATE_SELECTION_CANCEL;
690     }
691     //  else if (cmd == 45)
692     //  {
693     //    /* force new connection */
694     //    return SCP_SERVER_STATE_FORCE_NEW;
695     //  }
696     else
697     {
698         /* wrong response */
699         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__);
700         return SCP_SERVER_STATE_SEQUENCE_ERR;
701     }
702 
703     return SCP_SERVER_STATE_OK;
704 }
705 #endif
706 
707 enum SCP_SERVER_STATES_E
scp_v1s_list_sessions40(struct trans * t)708 scp_v1s_list_sessions40(struct trans *t)
709 {
710     struct stream *out_s;
711 
712     out_s = trans_get_out_s(t, 12);
713     /* send a notice that we have some disconnected sessions */
714     out_uint32_be(out_s, 1);                         /* version */
715     out_uint32_be(out_s, 12);                        /* size    */
716     out_uint16_be(out_s, SCP_COMMAND_SET_DEFAULT);   /* cmdset  */
717     out_uint16_be(out_s, SCP_REPLY_USER_SESSIONS_EXIST);/* cmd     */
718     s_mark_end(out_s);
719     if (0 != trans_force_write(t))
720     {
721         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
722         return SCP_SERVER_STATE_NETWORK_ERR;
723     }
724     return SCP_SERVER_STATE_OK;
725 }
726 
727 enum SCP_SERVER_STATES_E
scp_v1s_list_sessions42(struct trans * t,int sescnt,struct SCP_DISCONNECTED_SESSION * ds)728 scp_v1s_list_sessions42(struct trans *t, int sescnt, struct SCP_DISCONNECTED_SESSION *ds)
729 {
730     int pktcnt;
731     int idx;
732     int sidx;
733     int pidx;
734     int size;
735     struct stream *out_s;
736     struct SCP_DISCONNECTED_SESSION *cds;
737 
738     /* calculating the number of packets to send */
739     pktcnt = sescnt / SCP_SERVER_MAX_LIST_SIZE;
740     if ((sescnt % SCP_SERVER_MAX_LIST_SIZE) != 0)
741     {
742         pktcnt++;
743     }
744 
745     for (idx = 0; idx < pktcnt; idx++)
746     {
747         out_s = trans_get_out_s(t, 8192);
748 
749         /* size: ver+size+cmdset+cmd+sescnt+continue+count */
750         size = 4 + 4 + 2 + 2 + 4 + 1 + 1;
751 
752         /* header */
753         s_push_layer(out_s, channel_hdr, 8);
754         out_uint16_be(out_s, SCP_COMMAND_SET_DEFAULT);
755         out_uint16_be(out_s, SCP_REPLY_SESSIONS_INFO);
756 
757         /* session count */
758         out_uint32_be(out_s, sescnt);
759 
760         /* setting the continue flag */
761         if ((idx + 1) * SCP_SERVER_MAX_LIST_SIZE >= sescnt)
762         {
763             out_uint8(out_s, 0);
764             /* setting session count for this packet */
765             pidx = sescnt - (idx * SCP_SERVER_MAX_LIST_SIZE);
766             out_uint8(out_s, pidx);
767         }
768         else
769         {
770             out_uint8(out_s, 1);
771             /* setting session count for this packet */
772             pidx = SCP_SERVER_MAX_LIST_SIZE;
773             out_uint8(out_s, pidx);
774         }
775 
776         /* adding session descriptors */
777         for (sidx = 0; sidx < pidx; sidx++)
778         {
779             /* shortcut to the current session to send */
780             cds = ds + (idx * SCP_SERVER_MAX_LIST_SIZE) + sidx;
781 
782             /* session data */
783             out_uint32_be(out_s, cds->SID); /* session id */
784             out_uint8(out_s, cds->type);
785             out_uint16_be(out_s, cds->height);
786             out_uint16_be(out_s, cds->width);
787             out_uint8(out_s, cds->bpp);
788             out_uint8(out_s, cds->idle_days);
789             out_uint8(out_s, cds->idle_hours);
790             out_uint8(out_s, cds->idle_minutes);
791             size += 13;
792 
793             out_uint16_be(out_s, cds->conn_year);
794             out_uint8(out_s, cds->conn_month);
795             out_uint8(out_s, cds->conn_day);
796             out_uint8(out_s, cds->conn_hour);
797             out_uint8(out_s, cds->conn_minute);
798             out_uint8(out_s, cds->addr_type);
799             size += 7;
800 
801             if (cds->addr_type == SCP_ADDRESS_TYPE_IPV4)
802             {
803                 in_uint32_be(out_s, cds->ipv4addr);
804                 size += 4;
805             }
806             else if (cds->addr_type == SCP_ADDRESS_TYPE_IPV6)
807             {
808                 in_uint8a(out_s, cds->ipv6addr, 16);
809                 size += 16;
810             }
811         }
812         s_mark_end(out_s);
813         s_pop_layer(out_s, channel_hdr);
814         out_uint32_be(out_s, 1); /* version */
815         out_uint32_be(out_s, size);
816 
817         if (0 != trans_force_write(t))
818         {
819             LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
820             return SCP_SERVER_STATE_NETWORK_ERR;
821         }
822     }
823     return SCP_SERVER_STATE_OK;
824 }
825 
826 // TODO
827 enum SCP_SERVER_STATES_E
scp_v1s_accept_list_sessions_reply(int cmd,struct trans * t)828 scp_v1s_accept_list_sessions_reply(int cmd, struct trans *t)
829 {
830     struct SCP_SESSION *s;
831     struct stream *in_s;
832 
833     s = (struct SCP_SESSION *) (t->callback_data);
834     if (s == NULL)
835     {
836         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__);
837         return SCP_SERVER_STATE_INTERNAL_ERR;
838     }
839     s->current_cmd = cmd;
840     in_s = t->in_s;
841     switch (cmd)
842     {
843         case SCP_CMD_GET_SESSION_LIST:
844             break;
845         case SCP_CMD_SELECT_SESSION:
846             in_uint32_be(in_s, s->return_sid);
847             break;
848         case SCP_CMD_SELECT_SESSION_CANCEL:
849             break;
850         case SCP_CMD_FORCE_NEW_CONN:
851             break;
852         default:
853             break;
854     }
855     return SCP_SERVER_STATE_OK;
856 }
857 
858 enum SCP_SERVER_STATES_E
scp_v1s_reconnect_session(struct trans * t,SCP_DISPLAY d)859 scp_v1s_reconnect_session(struct trans *t, SCP_DISPLAY d)
860 {
861     struct stream *out_s;
862 
863     /* ok, we send session data and display */
864     out_s = trans_get_out_s(t, 14);
865     /* header */
866     out_uint32_be(out_s, 1); /* version */
867     out_uint32_be(out_s, 14); /* size */
868     out_uint16_be(out_s, SCP_COMMAND_SET_DEFAULT);
869     out_uint16_be(out_s, SCP_REPLY_SESSION_RECONNECTED); /* cmd */
870     /* session data */
871     out_uint16_be(out_s, d); /* session display */
872     s_mark_end(out_s);
873 
874     /*out_uint8(c->out_s, ds->type);
875     out_uint16_be(c->out_s, ds->height);
876     out_uint16_be(c->out_s, ds->width);
877     out_uint8(c->out_s, ds->bpp);
878     out_uint8(c->out_s, ds->idle_days);
879     out_uint8(c->out_s, ds->idle_hours);
880     out_uint8(c->out_s, ds->idle_minutes);*/
881     /* these last three are not really needed... */
882 
883     if (0 != trans_force_write(t))
884     {
885         LOG(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
886         return SCP_SERVER_STATE_NETWORK_ERR;
887     }
888 
889     return SCP_SERVER_STATE_OK;
890 }
891 
892 #endif
893