From c87ea981860983c78ff1f5a23e330a651e2c5026 Mon Sep 17 00:00:00 2001
From: Mosakuji Hokuto <shikieiki@yamaxanadu.org>
Date: Tue, 13 Sep 2022 10:14:26 +0800
Subject: [PATCH] Backport fix of CVE-2020-4044

---
 sesman/libscp/libscp_types.h |   2 +
 sesman/libscp/libscp_v0.c    | 326 ++++++++------
 sesman/libscp/libscp_v1s.c   | 825 ++++++++++++++++++++++++-----------
 sesman/scp.c                 |  11 +-
 4 files changed, 779 insertions(+), 385 deletions(-)

diff --git a/sesman/libscp/libscp_types.h b/sesman/libscp/libscp_types.h
index 04350aaa..cacc4d52 100644
--- a/sesman/libscp/libscp_types.h
+++ b/sesman/libscp/libscp_types.h
@@ -59,6 +59,8 @@
 
 #define free_session(s) {g_free((s)->username); g_free((s)->password); g_free((s)->hostname); g_free(s);}
 
+#define SCP_MAX_MESSAGE_SIZE 8192
+
 struct SCP_CONNECTION
 {
   int in_sck;
diff --git a/sesman/libscp/libscp_v0.c b/sesman/libscp/libscp_v0.c
index 6fc6d2e8..6dad6076 100644
--- a/sesman/libscp/libscp_v0.c
+++ b/sesman/libscp/libscp_v0.c
@@ -31,6 +31,65 @@
 
 extern struct log_config* s_log;
 
+/** Maximum length of a string (two bytes + len), excluding the terminator
+ *
+ * Practially this is limited by [MS-RDPBCGR] TS_INFO_PACKET
+ * */
+#define STRING16_MAX_LEN 512
+
+/**
+ * Reads a big-endian uint16 followed by a string into a buffer
+ *
+ * Buffer is null-terminated on success
+ *
+ * @param s Input stream
+ * @param [out] Output buffer (must be >= (STRING16_MAX_LEN+1) chars)
+ * @param param Parameter we're reading
+ * @param line Line number reference
+ * @return != 0 if string read OK
+ */
+static
+int in_string16(struct stream *s, char str[], const char *param, int line)
+{
+    int result;
+
+    if (!s_check_rem(s, 2))
+    {
+        log_message(s_log, LOG_LEVEL_WARNING,
+                    "[v0:%d] connection aborted: %s len missing",
+                    line, param);
+        result = 0;
+    }
+    else
+    {
+        unsigned int sz;
+
+        in_uint16_be(s, sz);
+        if (sz > STRING16_MAX_LEN)
+        {
+            log_message(s_log, LOG_LEVEL_WARNING,
+                        "[v0:%d] connection aborted: %s too long (%u chars)",
+                        line, param, sz);
+            result = 0;
+        }
+        else
+        {
+            result = s_check_rem(s, sz);
+            if (!result)
+            {
+                log_message(s_log, LOG_LEVEL_WARNING,
+                            "[v0:%d] connection aborted: %s data missing",
+                            line, param);
+            }
+            else
+            {
+                in_uint8a(s, str, sz);
+                str[sz] = '\0';
+            }
+        }
+    }
+    return result;
+}
 /* client API */
 /******************************************************************************/
 enum SCP_CLIENT_STATES_E scp_v0c_connect(struct SCP_CONNECTION* c, struct SCP_SESSION* s)
@@ -146,150 +205,173 @@ enum SCP_CLIENT_STATES_E scp_v0c_connect(struct SCP_CONNECTION* c, struct SCP_SE
 
 /* server API */
 /******************************************************************************/
-enum SCP_SERVER_STATES_E scp_v0s_accept(struct SCP_CONNECTION* c, struct SCP_SESSION** s, int skipVchk)
-{
-  tui32 version = 0;
-  tui32 size;
-  struct SCP_SESSION* session = 0;
-  tui16 sz;
-  tui32 code = 0;
-  char buf[257];
 
-  if (!skipVchk)
-  {
-    LOG_DBG(s_log, "[v0:%d] starting connection", __LINE__);
-    if (0==scp_tcp_force_recv(c->in_sck, c->in_s->data, 8))
-    {
-      in_uint32_be(c->in_s, version);
-      if (version != 0)
-      {
-        log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: version error", __LINE__);
-        return SCP_SERVER_STATE_VERSION_ERR;
-      }
-    }
-    else
+/**
+ * Initialises a V0 session object
+ *
+ * At the time of the call, the version has been read from the connection
+ *
+ * @param c Connection
+ * @param [out] session pre-allocated session object
+ * @return SCP_SERVER_STATE_OK for success
+ */
+static enum SCP_SERVER_STATES_E
+scp_v0s_init_session(struct SCP_CONNECTION *c, struct SCP_SESSION *session)
+{
+    tui32 size;
+    tui16 height;
+    tui16 width;
+    tui16 bpp;
+    tui32 code = 0;
+    char buf[STRING16_MAX_LEN + 1];
+
+    scp_session_set_version(session, 0);
+
+    /* Check for a header and a code value in the length */
+    in_uint32_be(c->in_s, size);
+    if (size < (8 + 2) || size > SCP_MAX_MESSAGE_SIZE)
     {
-      log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__);
-      return SCP_SERVER_STATE_NETWORK_ERR;
+        log_message(s_log, LOG_LEVEL_WARNING,
+                    "[v0:%d] connection aborted: msg size = %u",
+                    __LINE__, (unsigned int)size);
+        return SCP_SERVER_STATE_SIZE_ERR;
     }
-  }
 
-  in_uint32_be(c->in_s, size);
-  if (size < 24 || size > 8196)
-  {
-    log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: size error", __LINE__);
-    return SCP_SERVER_STATE_SIZE_ERR;
-  }
+    init_stream(c->in_s, size - 8);
 
-  init_stream(c->in_s, 8196);
-  if (0!=scp_tcp_force_recv(c->in_sck, c->in_s->data, size-8))
-  {
-    log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__);
-    return SCP_SERVER_STATE_NETWORK_ERR;
-  }
-
-  size -= 24;
-
-  in_uint16_be(c->in_s, code);
-
-  if (code == 0 || code == 10 || code == 20)
-  {
-	session = scp_session_create();
-    if (0 == session)
+    if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, size - 8))
     {
-      log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__);
-      return SCP_SERVER_STATE_INTERNAL_ERR;
+        log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__);
+        return SCP_SERVER_STATE_NETWORK_ERR;
     }
 
-    scp_session_set_version(session, version);
-    if (code == 0)
-    {
-      scp_session_set_type(session, SCP_SESSION_TYPE_XVNC);
-    }
-    else if (code == 10)
+    c->in_s->end = c->in_s->data + (size - 8);
+
+    in_uint16_be(c->in_s, code);
+
+    if (code == 0 || code == 10 || code == 20)
     {
-      scp_session_set_type(session, SCP_SESSION_TYPE_XRDP);
+        if (code == 0)
+        {
+            scp_session_set_type(session, SCP_SESSION_TYPE_XVNC);
+        }
+        else if (code == 10)
+        {
+            scp_session_set_type(session, SCP_SESSION_TYPE_XRDP);
+        }
+        else if (code == 20)
+        {
+            scp_session_set_type(session, SCP_SESSION_TYPE_XDMX);
+        }
+
+        /* reading username */
+        if (!in_string16(c->in_s, buf, "username", __LINE__))
+        {
+            return SCP_SERVER_STATE_SIZE_ERR;
+        }
+        if (0 != scp_session_set_username(session, buf))
+        {
+            log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: error setting username", __LINE__);
+            return SCP_SERVER_STATE_INTERNAL_ERR;
+        }
+
+        /* reading password */
+        if (!in_string16(c->in_s, buf, "passwd", __LINE__))
+        {
+            return SCP_SERVER_STATE_SIZE_ERR;
+        }
+        if (0 != scp_session_set_password(session, buf))
+        {
+            log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: error setting password", __LINE__);
+            return SCP_SERVER_STATE_INTERNAL_ERR;
+        }
+
+        /* width  + height + bpp */
+        if (!s_check_rem(c->in_s, 2 + 2 + 2))
+        {
+            log_message(s_log, LOG_LEVEL_WARNING,
+                        "[v0:%d] connection aborted: width+height+bpp missing",
+                        __LINE__);
+            return SCP_SERVER_STATE_SIZE_ERR;
+        }
+        in_uint16_be(c->in_s, width);
+        scp_session_set_width(session, width);
+        in_uint16_be(c->in_s, height);
+        scp_session_set_height(session, height);
+        in_uint16_be(c->in_s, bpp);
+        if (0 != scp_session_set_bpp(session, (tui8)bpp))
+        {
+            log_message(s_log, LOG_LEVEL_WARNING,
+                        "[v0:%d] connection aborted: unsupported bpp: %d",
+                        __LINE__, (tui8)bpp);
+            return SCP_SERVER_STATE_INTERNAL_ERR;
+        }
     }
     else
     {
-      scp_session_set_type(session, SCP_SESSION_TYPE_XDMX);
+      
+      log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: sequence error", __LINE__);
+      return SCP_SERVER_STATE_SEQUENCE_ERR;
     }
 
-    /* reading username */
-    in_uint16_be(c->in_s, sz);
-    if (sz >= sizeof (buf) || sz > size)
-    {
-      scp_session_destroy(session);
-      log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: size error", __LINE__);
-      return SCP_SERVER_STATE_SIZE_ERR;
-    }
-    size -= sz;
-    buf[sz]='\0';
-    in_uint8a(c->in_s, buf, sz);
-    if (0 != scp_session_set_username(session, buf))
-    {
-      scp_session_destroy(session);
-      log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: error setting username", __LINE__);
-      return SCP_SERVER_STATE_INTERNAL_ERR;
-    }
+    return SCP_SERVER_STATE_OK;
+}
 
-    /* reading password */
-    in_uint16_be(c->in_s, sz);
-    if (sz >= sizeof (buf) || sz > size)
-    {
-      scp_session_destroy(session);
-      log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: size error", __LINE__);
-      return SCP_SERVER_STATE_SIZE_ERR;
-    }
-    size -= sz;
-    buf[sz]='\0';
-    in_uint8a(c->in_s, buf, sz);
-    if (0 != scp_session_set_password(session, buf))
-    {
-      scp_session_destroy(session);
-      log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: error setting password", __LINE__);
-      return SCP_SERVER_STATE_INTERNAL_ERR;
-    }
+/* server API */
+/******************************************************************************/
+enum SCP_SERVER_STATES_E
+scp_v0s_accept(struct SCP_CONNECTION *c, struct SCP_SESSION **s, int skipVchk)
+{
+    enum SCP_SERVER_STATES_E result = SCP_SERVER_STATE_OK;
+    struct SCP_SESSION *session = NULL;
+    tui32 version = 0;
 
-    /* reading wm */
-    in_uint16_be(c->in_s, sz);
-    if (sz >= sizeof (buf) || sz > size)
+    if (!skipVchk)
     {
-      scp_session_destroy(session);
-      log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: size error", __LINE__);
-      return SCP_SERVER_STATE_SIZE_ERR;
+        LOG_DBG(s_log, "[v0:%d] starting connection", __LINE__);
+
+        if (0 == scp_tcp_force_recv(c->in_sck, c->in_s->data, 8))
+        {
+            c->in_s->end = c->in_s->data + 8;
+            in_uint32_be(c->in_s, version);
+
+            if (version != 0)
+            {
+                log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: version error", __LINE__);
+                result = SCP_SERVER_STATE_VERSION_ERR;
+            }
+        }
+        else
+        {
+            log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__);
+            result = SCP_SERVER_STATE_NETWORK_ERR;
+        }
     }
-    size -= sz;
-    buf[sz]='\0';
-    in_uint8a(c->in_s, buf, sz);
-    if (0 != scp_session_set_wm(session, buf))
+
+    if (result == SCP_SERVER_STATE_OK)
     {
-      scp_session_destroy(session);
-      log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: error setting wm", __LINE__);
-      return SCP_SERVER_STATE_INTERNAL_ERR;
+        session = scp_session_create();
+        if (NULL == session)
+        {
+            log_message(s_log, LOG_LEVEL_WARNING,
+                        "[v0:%d] connection aborted: no memory",
+                        __LINE__);
+            result = SCP_SERVER_STATE_INTERNAL_ERR;
+        }
+        else
+        {
+            result = scp_v0s_init_session(c, session);
+            if (result != SCP_SERVER_STATE_OK)
+            {
+                scp_session_destroy(session);
+                session = NULL;
+            }
+        }
     }
 
-    /* width */
-    in_uint16_be(c->in_s, sz);
-    scp_session_set_width(session, sz);
-    /* height */
-    in_uint16_be(c->in_s, sz);
-    scp_session_set_height(session, sz);
-    /* bpp */
-    in_uint16_be(c->in_s, sz);
-    scp_session_set_bpp(session, (tui8)sz);
-    /* layout */
-    in_uint16_be(c->in_s, sz);
-    scp_session_set_layout(session, (tui16)sz);
-  }
-  else
-  {
-    log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: sequence error", __LINE__);
-    return SCP_SERVER_STATE_SEQUENCE_ERR;
-  }
+    (*s) = session;
 
-  (*s)=session;
-  return SCP_SERVER_STATE_OK;
+    return result;
 }
 
 /******************************************************************************/
diff --git a/sesman/libscp/libscp_v1s.c b/sesman/libscp/libscp_v1s.c
index 4f5009c6..754506c6 100644
--- a/sesman/libscp/libscp_v1s.c
+++ b/sesman/libscp/libscp_v1s.c
@@ -32,196 +32,284 @@
 
 extern struct log_config* s_log;
 
-/* server API */
-enum SCP_SERVER_STATES_E scp_v1s_accept(struct SCP_CONNECTION* c, struct SCP_SESSION** s, int skipVchk)
+/**
+ * Reads a uint8 followed by a string into a buffer
+ *
+ * Buffer is null-terminated on success
+ *
+ * @param s Input stream
+ * @param [out] Output buffer (must be >= 256 chars)
+ * @param param Parameter we're reading
+ * @param line Line number reference
+ * @return != 0 if string read OK
+ *
+ * @todo
+ *     This needs to be merged with the func of the same name in
+ *     libscp_v1s_mng.c
+ */
+static
+int in_string8(struct stream *s, char str[], const char *param, int line)
 {
-  struct SCP_SESSION* session;
-  tui32 version;
-  tui32 size;
-  tui16 cmdset;
-  tui16 cmd;
-  tui8 sz;
-  char buf[257];
-
-  if (!skipVchk)
-  {
+    int result;
 
-    if (0==scp_tcp_force_recv(c->in_sck, c->in_s->data, 8))
+    if (!s_check_rem(s, 1))
     {
-      in_uint32_be(c->in_s, version);
-      if (version != 1)
-      {
-        log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: version error", __LINE__);
-        return SCP_SERVER_STATE_VERSION_ERR;
-      }
+        log_message(s_log, LOG_LEVEL_WARNING,
+                    "[v1s:%d] connection aborted: %s len missing",
+                    line, param);
+        result = 0;
     }
     else
     {
-      log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
-      return SCP_SERVER_STATE_NETWORK_ERR;
+        unsigned int sz;
+
+        in_uint8(s, sz);
+        result = s_check_rem(s, sz);
+        if (!result)
+        {
+            log_message(s_log, LOG_LEVEL_WARNING,
+                        "[v1s:%d] connection aborted: %s data missing",
+                        line, param);
+        }
+        else
+        {
+            in_uint8a(s, str, sz);
+            str[sz] = '\0';
+        }
     }
-  }
-  else
-  {
-    version = 1;
-  }
+    return result;
+}
+/* server API */
 
-  in_uint32_be(c->in_s, size);
-  if (size < 40 || size > 8196)
-  {
-    log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: size error", __LINE__);
-    return SCP_SERVER_STATE_SIZE_ERR;
-  }
+/**
+ * Initialises a V1 session object
+ *
+ * This is called after the V1 header, command set and command have been read
+ *
+ * @param c Connection
+ * @param [out] session pre-allocated session object
+ * @return SCP_SERVER_STATE_OK for success
+ */
+static enum SCP_SERVER_STATES_E
+scp_v1s_init_session(struct SCP_CONNECTION *c, struct SCP_SESSION *session)
+{
+    tui8 type;
+    tui16 height;
+    tui16 width;
+    tui8 bpp;
+    tui8 sz;
+    char buf[256];
+
+    scp_session_set_version(session, 1);
+
+    /* Check there's data for the session type, the height, the width, the
+     * bpp, the resource sharing indicator and the locale */
+    if (!s_check_rem(c->in_s, 1 + 2 + 2 + 1 + 1 + 17))
+    {
+        log_message(s_log, LOG_LEVEL_WARNING,
+                    "[v1s:%d] connection aborted: short packet",
+                    __LINE__);
+        return SCP_SERVER_STATE_SIZE_ERR;
+    }
 
-  init_stream(c->in_s, 8196);
-  if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, (size-8)))
-  {
-    log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
-    return SCP_SERVER_STATE_NETWORK_ERR;
-  }
+    in_uint8(c->in_s, type);
 
-  size -= 40;
+    if ((type != SCP_SESSION_TYPE_XVNC) && (type != SCP_SESSION_TYPE_XRDP))
+    {
+        log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: unknown session type", __LINE__);
+        return SCP_SERVER_STATE_SESSION_TYPE_ERR;
+    }
 
-  /* reading command set */
-  in_uint16_be(c->in_s, cmdset);
+    scp_session_set_type(session, type);
 
-  /* if we are starting a management session */
-  if (cmdset == SCP_COMMAND_SET_MANAGE)
-  {
-    log_message(s_log, LOG_LEVEL_DEBUG, "[v1s:%d] requested management connection", __LINE__);
-    return SCP_SERVER_STATE_START_MANAGE;
-  }
+    in_uint16_be(c->in_s, height);
+    scp_session_set_height(session, height);
+    in_uint16_be(c->in_s, width);
+    scp_session_set_width(session, width);
+    in_uint8(c->in_s, bpp);
+    if (0 != scp_session_set_bpp(session, bpp))
+    {
+        log_message(s_log, LOG_LEVEL_WARNING,
+                    "[v1s:%d] connection aborted: unsupported bpp: %d",
+                    __LINE__, bpp);
+        return SCP_SERVER_STATE_INTERNAL_ERR;
+    }
+    in_uint8(c->in_s, sz);
+    scp_session_set_rsr(session, sz);
+    in_uint8a(c->in_s, buf, 17);
+    buf[17] = '\0';
+    scp_session_set_locale(session, buf);
+
+    /* Check there's enough data left for at least an IPv4 address (+len) */
+    if (!s_check_rem(c->in_s, 1 + 4))
+    {
+        log_message(s_log, LOG_LEVEL_WARNING,
+                    "[v1s:%d] connection aborted: IP addr len missing",
+                    __LINE__);
+        return SCP_SERVER_STATE_SIZE_ERR;
+    }
 
-  /* if we started with resource sharing... */
-  if (cmdset == SCP_COMMAND_SET_RSR)
-  {
-    log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__);
-    return SCP_SERVER_STATE_SEQUENCE_ERR;
-  }
+    in_uint8(c->in_s, sz);
 
-  /* reading command */
-  in_uint16_be(c->in_s, cmd);
-  if (cmd != 1)
-  {
-    log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__);
-    return SCP_SERVER_STATE_SEQUENCE_ERR;
-  }
+    if (sz == SCP_ADDRESS_TYPE_IPV4)
+    {
+        tui32 ipv4;
+        in_uint32_be(c->in_s, ipv4);
+        scp_session_set_addr(session, sz, &ipv4);
+    }
+    else if (sz == SCP_ADDRESS_TYPE_IPV6)
+    {
+        if (!s_check_rem(c->in_s, 16))
+        {
+            log_message(s_log, LOG_LEVEL_WARNING,
+                        "[v1s:%d] connection aborted: IP addr missing",
+                        __LINE__);
+            return SCP_SERVER_STATE_SIZE_ERR;
+        }
+        in_uint8a(c->in_s, buf, 16);
+        scp_session_set_addr(session, sz, buf);
+    }
 
-  session = scp_session_create();
-  if (0 == session)
-  {
-    log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error (malloc returned NULL)", __LINE__);
-    return SCP_SERVER_STATE_INTERNAL_ERR;
-  }
-  scp_session_set_version(session, 1);
+    /* reading hostname */
+    if (!in_string8(c->in_s, buf, "hostname", __LINE__))
+    {
+        return SCP_SERVER_STATE_SIZE_ERR;
+    }
 
-  in_uint8(c->in_s, sz);
-  if ((sz != SCP_SESSION_TYPE_XVNC) &&
-      (sz != SCP_SESSION_TYPE_XRDP) &&
-      (sz != SCP_SESSION_TYPE_XDMX))
-  {
-    scp_session_destroy(session);
-    log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: unknown session type", __LINE__);
-    return SCP_SERVER_STATE_SESSION_TYPE_ERR;
-  }
-  scp_session_set_type(session, sz);
+    if (0 != scp_session_set_hostname(session, buf))
+    {
+        log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__);
+        return SCP_SERVER_STATE_INTERNAL_ERR;
+    }
 
-  in_uint16_be(c->in_s, cmd);
-  scp_session_set_height(session, cmd);
-  in_uint16_be(c->in_s, cmd);
-  scp_session_set_height(session, cmd);
-  in_uint8(c->in_s, sz);
-  scp_session_set_bpp(session, sz);
-  in_uint8(c->in_s, sz);
-  scp_session_set_rsr(session, sz);
-  in_uint8a(c->in_s, buf, 17);
-    buf[17]='\0';
-  scp_session_set_locale(session, buf);
-
-  in_uint8(c->in_s, sz);
-  if (sz == SCP_ADDRESS_TYPE_IPV6)
-      sz = 16;
-  else
-      sz = 4;
+    /* reading username */
+    if (!in_string8(c->in_s, buf, "username", __LINE__))
+    {
+        return SCP_SERVER_STATE_SIZE_ERR;
+    }
 
-  if (sz > size)
-  {
-    scp_session_destroy(session);
-    log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: size error", __LINE__);
-    return SCP_SERVER_STATE_SIZE_ERR;
-  }
-  size -= sz;
+    if (0 != scp_session_set_username(session, buf))
+    {
+        log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__);
+        return SCP_SERVER_STATE_INTERNAL_ERR;
+    }
 
-  if (sz == 4)
-  {
-    tui32 addr;
-    in_uint32_be(c->in_s, addr);
-    scp_session_set_addr(session, SCP_ADDRESS_TYPE_IPV4_BIN, &addr);
-  }
-  else
-  {
-    in_uint8a(c->in_s, buf, 16);
-    scp_session_set_addr(session, SCP_ADDRESS_TYPE_IPV6_BIN, buf);
-  }
+    /* reading password */
+    if (!in_string8(c->in_s, buf, "passwd", __LINE__))
+    {
+        return SCP_SERVER_STATE_SIZE_ERR;
+    }
 
-  /* reading hostname */
-  in_uint8(c->in_s, sz);
-  if (sz > size)
-  {
-    scp_session_destroy(session);
-    log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: size error", __LINE__);
-    return SCP_SERVER_STATE_SIZE_ERR;
-  }
-  size -= sz;
-  buf[sz]='\0';
-  in_uint8a(c->in_s, buf, sz);
-  if (0 != scp_session_set_hostname(session, buf))
-  {
-    scp_session_destroy(session);
-    log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__);
-    return SCP_SERVER_STATE_INTERNAL_ERR;
-  }
+    if (0 != scp_session_set_password(session, buf))
+    {
+        log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__);
+        return SCP_SERVER_STATE_INTERNAL_ERR;
+    }
 
-  /* reading username */
-  in_uint8(c->in_s, sz);
-  if (sz > size)
-  {
-    scp_session_destroy(session);
-    log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: size error", __LINE__);
-    return SCP_SERVER_STATE_SIZE_ERR;
-  }
-  size -= sz;
-  buf[sz]='\0';
-  in_uint8a(c->in_s, buf, sz);
-  if (0 != scp_session_set_username(session, buf))
-  {
-    scp_session_destroy(session);
-    log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__);
-    return SCP_SERVER_STATE_INTERNAL_ERR;
-  }
+    return SCP_SERVER_STATE_OK;
+}
 
-  /* reading password */
-  in_uint8(c->in_s, sz);
-  if (sz > size)
-  {
-    scp_session_destroy(session);
-    log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: size error", __LINE__);
-    return SCP_SERVER_STATE_SIZE_ERR;
-  }
-  size -= sz;
-  buf[sz]='\0';
-  in_uint8a(c->in_s, buf, sz);
-  if (0 != scp_session_set_password(session, buf))
-  {
-    scp_session_destroy(session);
-    log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__);
-    return SCP_SERVER_STATE_INTERNAL_ERR;
-  }
+/* server API */
+enum SCP_SERVER_STATES_E scp_v1s_accept(struct SCP_CONNECTION* c, struct SCP_SESSION** s, int skipVchk)
+{
+    enum SCP_SERVER_STATES_E result;
+    struct SCP_SESSION *session;
+    tui32 version;
+    tui32 size;
+    tui16 cmdset;
+    tui16 cmd;
+
+    (*s) = NULL;
+
+    if (!skipVchk)
+    {
+
+        if (0 == scp_tcp_force_recv(c->in_sck, c->in_s->data, 8))
+        {
+            in_uint32_be(c->in_s, version);
+
+            if (version != 1)
+            {
+                log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: version error", __LINE__);
+                return SCP_SERVER_STATE_VERSION_ERR;
+            }
+        }
+        else
+        {
+            log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
+            return SCP_SERVER_STATE_NETWORK_ERR;
+        }
+    }
+
+    in_uint32_be(c->in_s, size);
+
+    /* Check the message is big enough for the header, the command set, and
+     * the command (but not too big) */
+    if (size < (8 + 2 + 2) || size > SCP_MAX_MESSAGE_SIZE)
+    {
+        log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: size error", __LINE__);
+        return SCP_SERVER_STATE_SIZE_ERR;
+    }
+
+    init_stream(c->in_s, size - 8);
+
+    if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, (size - 8)))
+    {
+        log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
+        return SCP_SERVER_STATE_NETWORK_ERR;
+    }
+
+    c->in_s->end = c->in_s->data + (size - 8);
+
+    /* reading command set */
+    in_uint16_be(c->in_s, cmdset);
+
+    /* if we are starting a management session */
+    if (cmdset == SCP_COMMAND_SET_MANAGE)
+    {
+        log_message(s_log, LOG_LEVEL_DEBUG, "[v1s:%d] requested management connection", __LINE__);
+        return SCP_SERVER_STATE_START_MANAGE;
+    }
+
+    /* if we started with resource sharing... */
+    if (cmdset == SCP_COMMAND_SET_RSR)
+    {
+        log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__);
+        return SCP_SERVER_STATE_SEQUENCE_ERR;
+    }
+
+    /* reading command */
+    in_uint16_be(c->in_s, cmd);
+
+    if (cmd != 1)
+    {
+        log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__);
+        return SCP_SERVER_STATE_SEQUENCE_ERR;
+    }
+
+    session = scp_session_create();
+
+    if (NULL == session)
+    {
+        log_message(s_log, LOG_LEVEL_WARNING,
+                    "[v1s:%d] connection aborted: internal error "
+                    "(malloc returned NULL)", __LINE__);
+        result = SCP_SERVER_STATE_INTERNAL_ERR;
+    }
+    else
+    {
+        result = scp_v1s_init_session(c, session);
+        if (result != SCP_SERVER_STATE_OK)
+        {
+            scp_session_destroy(session);
+            session = NULL;
+        }
+    }
 
   /* returning the struct */
   (*s)=session;
 
-  return SCP_SERVER_STATE_OK;
+    return result;
 }
 
 enum SCP_SERVER_STATES_E
@@ -259,13 +347,12 @@ scp_v1s_deny_connection(struct SCP_CONNECTION* c, char* reason)
 enum SCP_SERVER_STATES_E
 scp_v1s_request_password(struct SCP_CONNECTION* c, struct SCP_SESSION* s, char* reason)
 {
-  tui8 sz;
-  tui32 version;
-  tui32 size;
-  tui16 cmdset;
-  tui16 cmd;
-  int rlen;
-  char buf[257];
+    tui32 version;
+    tui32 size;
+    tui16 cmdset;
+    tui16 cmd;
+    int rlen;
+    char buf[256];
 
   init_stream(c->in_s, 8);
   init_stream(c->out_s, 14 + 4096);
@@ -283,94 +370,96 @@ scp_v1s_request_password(struct SCP_CONNECTION* c, struct SCP_SESSION* s, char*
   cmdset=0;
   cmd=3;
 
-  out_uint32_be(c->out_s, version);                 /* version */
-  out_uint32_be(c->out_s, 14+rlen);                 /* size    */
-  out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); /* cmdset  */
-  out_uint16_be(c->out_s, cmd);                     /* cmd     */
+    out_uint32_be(c->out_s, version);                 /* version */
+    out_uint32_be(c->out_s, 14 + rlen);               /* size    */
+    out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); /* cmdset  */
+    out_uint16_be(c->out_s, cmd);                     /* cmd     */
 
-  out_uint16_be(c->out_s, rlen);
-  out_uint8p(c->out_s, reason, rlen);
+    out_uint16_be(c->out_s, rlen);
+    out_uint8p(c->out_s, reason, rlen);
 
-  if (0!=scp_tcp_force_send(c->in_sck, c->out_s->data, 14+rlen))
-  {
-    log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
-    return SCP_SERVER_STATE_NETWORK_ERR;
-  }
+    if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, 14 + rlen))
+    {
+        log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
+        return SCP_SERVER_STATE_NETWORK_ERR;
+    }
 
-  /* receive password & username */
-  if (0!=scp_tcp_force_recv(c->in_sck, c->in_s->data, 8))
-  {
-    log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
-    return SCP_SERVER_STATE_NETWORK_ERR;
-  }
+    /* receive password & username */
+    if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, 8))
+    {
+        log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
+        return SCP_SERVER_STATE_NETWORK_ERR;
+    }
 
-  in_uint32_be(c->in_s, version);
-  if (version!=1)
-  {
-    log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: version error", __LINE__);
-    return SCP_SERVER_STATE_VERSION_ERR;
-  }
+    in_uint32_be(c->in_s, version);
 
-  in_uint32_be(c->in_s, size);
-  if (size<12 || size > 8192)
-  {
-    log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: size error", __LINE__);
-    return SCP_SERVER_STATE_SIZE_ERR;
-  }
+    if (version != 1)
+    {
+        log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: version error", __LINE__);
+        return SCP_SERVER_STATE_VERSION_ERR;
+    }
 
-  init_stream(c->in_s, size-8);
-  if (0!=scp_tcp_force_recv(c->in_sck, c->in_s->data, (size-8)))
-  {
-    log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
-    return SCP_SERVER_STATE_NETWORK_ERR;
-  }
-  size -= 14;
+    in_uint32_be(c->in_s, size);
 
-  in_uint16_be(c->in_s, cmdset);
-  if (cmdset != SCP_COMMAND_SET_DEFAULT)
-  {
-    log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__);
-    return SCP_SERVER_STATE_SEQUENCE_ERR;
-  }
+    /* Check the message is big enough for the header, the command set, and
+     * the command (but not too big) */
+    if (size < (8 + 2 + 2) || size > SCP_MAX_MESSAGE_SIZE)
+    {
+        log_message(s_log, LOG_LEVEL_WARNING,
+                    "[v1s:%d] connection aborted: size error",
+                    __LINE__);
+        return SCP_SERVER_STATE_SIZE_ERR;
+    }
 
-  in_uint16_be(c->in_s, cmd);
-  if (cmd != 4)
-  {
-    log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__);
-    return SCP_SERVER_STATE_SEQUENCE_ERR;
-  }
+    init_stream(c->in_s, size - 8);
 
-  /* reading username */
-  in_uint8(c->in_s, sz);
-  if (sz > size)
-  {
-    log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: size error", __LINE__);
-    return SCP_SERVER_STATE_SIZE_ERR;
-  }
-  size -= sz;
-  buf[sz] = '\0';
-  in_uint8a(c->in_s, buf, sz);
-  if (0 != scp_session_set_username(s, buf))
-  {
-    log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__);
-    return SCP_SERVER_STATE_INTERNAL_ERR;
-  }
+    if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, (size - 8)))
+    {
+        log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
+        return SCP_SERVER_STATE_NETWORK_ERR;
+    }
 
-  /* reading password */
-  in_uint8(c->in_s, sz);
-  if (sz > size)
-  {
-    log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: size error", __LINE__);
-    return SCP_SERVER_STATE_SIZE_ERR;
-  }
-  size -= sz;
-  buf[sz]='\0';
-  in_uint8a(c->in_s, buf, sz);
-  if (0 != scp_session_set_password(s, buf))
-  {
-    log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__);
-    return SCP_SERVER_STATE_INTERNAL_ERR;
-  }
+    c->in_s->end = c->in_s->data + (size - 8);
+
+    in_uint16_be(c->in_s, cmdset);
+
+    if (cmdset != SCP_COMMAND_SET_DEFAULT)
+    {
+        log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__);
+        return SCP_SERVER_STATE_SEQUENCE_ERR;
+    }
+
+    in_uint16_be(c->in_s, cmd);
+
+    if (cmd != 4)
+    {
+        log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__);
+        return SCP_SERVER_STATE_SEQUENCE_ERR;
+    }
+
+    /* reading username */
+    if (!in_string8(c->in_s, buf, "username", __LINE__))
+    {
+        return SCP_SERVER_STATE_SIZE_ERR;
+    }
+
+    if (0 != scp_session_set_username(s, buf))
+    {
+        log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__);
+        return SCP_SERVER_STATE_INTERNAL_ERR;
+    }
+
+    /* reading password */
+    if (!in_string8(c->in_s, buf, "passwd", __LINE__))
+    {
+        return SCP_SERVER_STATE_SIZE_ERR;
+    }
+
+    if (0 != scp_session_set_password(s, buf))
+    {
+        log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__);
+        return SCP_SERVER_STATE_INTERNAL_ERR;
+    }
 
   return SCP_SERVER_STATE_OK;
 }
@@ -508,20 +597,240 @@ scp_v1s_list_sessions(struct SCP_CONNECTION* c, int sescnt, struct SCP_DISCONNEC
     /* ok, we send session session list */
     init_stream(c->out_s, 8192);
 
-    /* size: ver+size+cmdset+cmd+sescnt+continue+count */
-    size=4+4+2+2+4+1+1;
+    out_uint32_be(c->out_s, version);                 /* version */
+    out_uint32_be(c->out_s, size);                    /* size    */
+    out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); /* cmdset  */
+    out_uint16_be(c->out_s, cmd);                     /* cmd     */
+
+    if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, size))
+    {
+        log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
+        return SCP_SERVER_STATE_NETWORK_ERR;
+    }
+
+    /* then we wait for client ack */
+
+    /*
+     * Maybe this message could say if the session should be resized on
+     * server side or client side.
+     */
+    init_stream(c->in_s, c->in_s->size);
+
+    if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, 8))
+    {
+        log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
+        return SCP_SERVER_STATE_NETWORK_ERR;
+    }
+
+    in_uint32_be(c->in_s, version);
+
+    if (version != 1)
+    {
+        log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: version error", __LINE__);
+        return SCP_SERVER_STATE_VERSION_ERR;
+    }
+
+    in_uint32_be(c->in_s, size);
+
+    /* Check the message is big enough for the header, the command set, and
+     * the command (but not too big) */
+    if (size < (8 + 2 + 2) || size > SCP_MAX_MESSAGE_SIZE)
+    {
+        log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: size error", __LINE__);
+        return SCP_SERVER_STATE_SIZE_ERR;
+    }
+
+    init_stream(c->in_s, size - 8);
+
+    if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, (size - 8)))
+    {
+        log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
+        return SCP_SERVER_STATE_NETWORK_ERR;
+    }
+
+    c->in_s->end = c->in_s->data + (size - 8);
+
+    in_uint16_be(c->in_s, cmd);
+
+    if (cmd != SCP_COMMAND_SET_DEFAULT)
+    {
+        log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__);
+        return SCP_SERVER_STATE_SEQUENCE_ERR;
+    }
+
+    in_uint16_be(c->in_s, cmd);
+
+    if (cmd != 41)
+    {
+        log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__);
+        return SCP_SERVER_STATE_SEQUENCE_ERR;
+    }
+
+    /* calculating the number of packets to send */
+    pktcnt = sescnt / SCP_SERVER_MAX_LIST_SIZE;
+
+    if ((sescnt % SCP_SERVER_MAX_LIST_SIZE) != 0)
+    {
+        pktcnt++;
+    }
+
+    for (idx = 0; idx < pktcnt; idx++)
+    {
+        /* ok, we send session session list */
+        init_stream(c->out_s, c->out_s->size);
+
+        /* size: ver+size+cmdset+cmd+sescnt+continue+count */
+        size = 4 + 4 + 2 + 2 + 4 + 1 + 1;
+
+        /* header */
+        cmd = 42;
+        s_push_layer(c->out_s, channel_hdr, 8);
+        out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT);
+        out_uint16_be(c->out_s, cmd);
+
+        /* session count */
+        out_uint32_be(c->out_s, sescnt);
+
+        /* setting the continue flag */
+        if ((idx + 1)*SCP_SERVER_MAX_LIST_SIZE >= sescnt)
+        {
+            out_uint8(c->out_s, 0);
+            /* setting session count for this packet */
+            pidx = sescnt - (idx * SCP_SERVER_MAX_LIST_SIZE);
+            out_uint8(c->out_s, pidx);
+        }
+        else
+        {
+            out_uint8(c->out_s, 1);
+            /* setting session count for this packet */
+            pidx = SCP_SERVER_MAX_LIST_SIZE;
+            out_uint8(c->out_s, pidx);
+        }
+
+        /* adding session descriptors */
+        for (sidx = 0; sidx < pidx; sidx++)
+        {
+            /* shortcut to the current session to send */
+            cds = ds + ((idx) * SCP_SERVER_MAX_LIST_SIZE) + sidx;
+
+            /* session data */
+            out_uint32_be(c->out_s, cds->SID); /* session id */
+            out_uint8(c->out_s, cds->type);
+            out_uint16_be(c->out_s, cds->height);
+            out_uint16_be(c->out_s, cds->width);
+            out_uint8(c->out_s, cds->bpp);
+            out_uint8(c->out_s, cds->idle_days);
+            out_uint8(c->out_s, cds->idle_hours);
+            out_uint8(c->out_s, cds->idle_minutes);
+            size += 13;
+
+            out_uint16_be(c->out_s, cds->conn_year);
+            out_uint8(c->out_s, cds->conn_month);
+            out_uint8(c->out_s, cds->conn_day);
+            out_uint8(c->out_s, cds->conn_hour);
+            out_uint8(c->out_s, cds->conn_minute);
+            out_uint8(c->out_s, cds->addr_type);
+            size += 7;
+
+            if (cds->addr_type == SCP_ADDRESS_TYPE_IPV4)
+            {
+                in_uint32_be(c->out_s, cds->ipv4addr);
+                size += 4;
+            }
+            else if (cds->addr_type == SCP_ADDRESS_TYPE_IPV6)
+            {
+                in_uint8a(c->out_s, cds->ipv6addr, 16);
+                size += 16;
+            }
+        }
+
+        s_pop_layer(c->out_s, channel_hdr);
+        out_uint32_be(c->out_s, version);
+        out_uint32_be(c->out_s, size);
+
+        if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, size))
+        {
+            log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
+            return SCP_SERVER_STATE_NETWORK_ERR;
+        }
+    }
+
+    /* we get the response */
+    init_stream(c->in_s, c->in_s->size);
 
-    /* header */
-    cmd=42;
-    s_push_layer(c->out_s, channel_hdr, 8);
-    out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT);
-    out_uint16_be(c->out_s, cmd);
+    if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, (8)))
+    {
+        log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
+        return SCP_SERVER_STATE_NETWORK_ERR;
+    }
+
+    in_uint32_be(c->in_s, version);
+
+    if (version != 1)
+    {
+        log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: version error", __LINE__);
+        return SCP_SERVER_STATE_VERSION_ERR;
+    }
+
+    in_uint32_be(c->in_s, size);
+
+    /* Check the message is big enough for the header, the command set, and
+     * the command (but not too big) */
+    if (size < (8 + 2 + 2) || size > SCP_MAX_MESSAGE_SIZE)
+    {
+        log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: size error", __LINE__);
+        return SCP_SERVER_STATE_SIZE_ERR;
+    }
+
+    /* rest of the packet */
+    init_stream(c->in_s, size - 8);
+
+    if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, (size - 8)))
+    {
+        log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__);
+        return SCP_SERVER_STATE_NETWORK_ERR;
+    }
+
+    c->in_s->end = c->in_s->data + (size - 8);
+
+    in_uint16_be(c->in_s, cmd);
+
+    if (cmd != SCP_COMMAND_SET_DEFAULT)
+    {
+        log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__);
+        return SCP_SERVER_STATE_SEQUENCE_ERR;
+    }
 
     /* session count */
     out_uint32_be(c->out_s, sescnt);
 
-    /* setting the continue flag */
-    if ((idx+1)*SCP_SERVER_MAX_LIST_SIZE >= sescnt)
+    if (cmd == 43)
+    {
+        if (!s_check_rem(c->in_s, 4))
+        {
+            log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: missing session", __LINE__);
+            return SCP_SERVER_STATE_SIZE_ERR;
+        }
+        /* select session */
+        in_uint32_be(c->in_s, (*sid));
+
+        /* checking sid value */
+        for (idx = 0; idx < sescnt; idx++)
+        {
+            /* the sid is valid */
+            if (ds[idx].SID == (*sid))
+            {
+                /* ok, session selected */
+                return SCP_SERVER_STATE_OK;
+            }
+        }
+
+        /* if we got here, the requested sid wasn't one from the list we sent */
+        /* we should kill the connection                                      */
+        log_message(s_log, LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error (no such session in list)", __LINE__);
+        return SCP_SERVER_STATE_INTERNAL_ERR;
+    }
+    else if (cmd == 44)
     {
       out_uint8(c->out_s, 0);
       /* setting session count for this packet */
diff --git a/sesman/scp.c b/sesman/scp.c
index ea5a8ec0..727b2611 100644
--- a/sesman/scp.c
+++ b/sesman/scp.c
@@ -51,8 +51,8 @@ scp_process_start(void* sck)
   make_stream(scon.in_s);
   make_stream(scon.out_s);
 
-  init_stream(scon.in_s, 8192);
-  init_stream(scon.out_s, 8192);
+  init_stream(scon.in_s, SCP_MAX_MESSAGE_SIZE);
+  init_stream(scon.out_s, SCP_MAX_MESSAGE_SIZE);
 
   switch (scp_vXs_accept(&scon, &(sdata)))
   {
@@ -77,10 +77,11 @@ scp_process_start(void* sck)
 //      scp_v1s_mng_process(&scon, sdata);
       break;
     case SCP_SERVER_STATE_VERSION_ERR:
-      /* an unknown scp version was requested, so we shut down the */
-      /* connection (and log the fact)                             */
+    case SCP_SERVER_STATE_SIZE_ERR:
+      /* an unknown scp version was requested, or the sizes are */
+      /* inconsist. shut down the connection and log the fact   */
       log_message(&(g_cfg.log), LOG_LEVEL_WARNING,
-        "unknown protocol version specified. connection refused.");
+        "protocol violation. connection refused.");
       break;
     case SCP_SERVER_STATE_NETWORK_ERR:
       log_message(&(g_cfg.log), LOG_LEVEL_WARNING, "libscp network error.");
-- 
2.26.2

