From c917c6a5448400246a523a40bd09a971b6e9b7c3 Mon Sep 17 00:00:00 2001
From: Jay Sorg <jay.sorg@gmail.com>
Date: Sun, 13 Nov 2016 23:37:37 -0800
Subject: [PATCH] sesman: change vnc password file to guid

---
 common/ssl_calls.c             | 77 ++++++++++++++++++++++++++++++++++
 common/ssl_calls.h             | 10 +++++
 sesman/libscp/libscp_session.c | 18 +++++++-
 sesman/libscp/libscp_session.h |  3 ++
 sesman/libscp/libscp_types.h   |  6 +++
 sesman/libscp/libscp_v0.c      | 35 +++++++++-------
 sesman/libscp/libscp_v0.h      |  4 +-
 sesman/scp_v0.c                | 12 ++++--
 sesman/scp_v1.c                |  6 +--
 sesman/session.c               | 17 +++++++-
 sesman/session.h               |  2 +-
 vnc/vnc.c                      | 73 ++++++++++++++++++++++++++++----
 vnc/vnc.h                      |  3 ++
 xrdp/xrdp_mm.c                 | 18 ++++++--
 14 files changed, 246 insertions(+), 38 deletions(-)

diff --git a/common/ssl_calls.c b/common/ssl_calls.c
index 960c0569..2b4df0be 100644
--- a/common/ssl_calls.c
+++ b/common/ssl_calls.c
@@ -24,6 +24,7 @@
 #include <openssl/rc4.h>
 #include <openssl/md5.h>
 #include <openssl/sha.h>
+#include <openssl/hmac.h>
 #include <openssl/bn.h>
 #include <openssl/rsa.h>
 
@@ -141,6 +142,82 @@ ssl_md5_complete(void* md5_info, char* data)
   MD5_Final((tui8*)data, (MD5_CTX*)md5_info);
 }
 
+/*****************************************************************************/
+void *APP_CC
+ssl_des3_encrypt_info_create(const char *key, const char* ivec)
+{
+    EVP_CIPHER_CTX *des3_ctx;
+    const tui8 *lkey;
+    const tui8 *livec;
+
+    des3_ctx = (EVP_CIPHER_CTX *) g_malloc(sizeof(EVP_CIPHER_CTX), 1);
+    EVP_CIPHER_CTX_init(des3_ctx);
+    lkey = (const tui8 *) key;
+    livec = (const tui8 *) ivec;
+    EVP_EncryptInit_ex(des3_ctx, EVP_des_ede3_cbc(), NULL, lkey, livec);
+    EVP_CIPHER_CTX_set_padding(des3_ctx, 0);
+    return des3_ctx;
+}
+
+/*****************************************************************************/
+void *APP_CC
+ssl_des3_decrypt_info_create(const char *key, const char* ivec)
+{
+    EVP_CIPHER_CTX *des3_ctx;
+    const tui8 *lkey;
+    const tui8 *livec;
+
+    des3_ctx = g_malloc(sizeof(EVP_CIPHER_CTX), 1);
+    EVP_CIPHER_CTX_init(des3_ctx);
+    lkey = (const tui8 *) key;
+    livec = (const tui8 *) ivec;
+    EVP_DecryptInit_ex(des3_ctx, EVP_des_ede3_cbc(), NULL, lkey, livec);
+    EVP_CIPHER_CTX_set_padding(des3_ctx, 0);
+    return des3_ctx;
+}
+
+/*****************************************************************************/
+void APP_CC
+ssl_des3_info_delete(void *des3)
+{
+    EVP_CIPHER_CTX *des3_ctx;
+
+    des3_ctx = (EVP_CIPHER_CTX *) des3;
+    EVP_CIPHER_CTX_cleanup(des3_ctx);
+}
+
+/*****************************************************************************/
+int APP_CC
+ssl_des3_encrypt(void *des3, int length, const char *in_data, char *out_data)
+{
+    EVP_CIPHER_CTX *des3_ctx;
+    int len;
+    const tui8 *lin_data;
+    tui8 *lout_data;
+
+    des3_ctx = (EVP_CIPHER_CTX *) des3;
+    lin_data = (const tui8 *) in_data;
+    lout_data = (tui8 *) out_data;
+    EVP_EncryptUpdate(des3_ctx, lout_data, &len, lin_data, length);
+    return 0;
+}
+
+/*****************************************************************************/
+int APP_CC
+ssl_des3_decrypt(void *des3, int length, const char *in_data, char *out_data)
+{
+    EVP_CIPHER_CTX *des3_ctx;
+    int len;
+    const tui8 *lin_data;
+    tui8 *lout_data;
+
+    des3_ctx = (EVP_CIPHER_CTX *) des3;
+    lin_data = (const tui8 *) in_data;
+    lout_data = (tui8 *) out_data;
+    EVP_DecryptUpdate(des3_ctx, lout_data, &len, lin_data, length);
+    return 0;
+}
+
 /*****************************************************************************/
 static void APP_CC
 ssl_reverse_it(char* p, int len)
diff --git a/common/ssl_calls.h b/common/ssl_calls.h
index f0f0f91b..c8759b1f 100644
--- a/common/ssl_calls.h
+++ b/common/ssl_calls.h
@@ -51,6 +51,16 @@ void APP_CC
 ssl_md5_transform(void* md5_info, char* data, int len);
 void APP_CC
 ssl_md5_complete(void* md5_info, char* data);
+void *APP_CC
+ssl_des3_encrypt_info_create(const char *key, const char* ivec);
+void *APP_CC
+ssl_des3_decrypt_info_create(const char *key, const char* ivec);
+void APP_CC
+ssl_des3_info_delete(void *des3);
+int APP_CC
+ssl_des3_encrypt(void *des3, int length, const char *in_data, char *out_data);
+int APP_CC
+ssl_des3_decrypt(void *des3, int length, const char *in_data, char *out_data);
 int APP_CC
 ssl_mod_exp(char* out, int out_len, char* in, int in_len,
             char* mod, int mod_len, char* exp, int exp_len);
diff --git a/sesman/libscp/libscp_session.c b/sesman/libscp/libscp_session.c
index fabc0937..15ce1e75 100644
--- a/sesman/libscp/libscp_session.c
+++ b/sesman/libscp/libscp_session.c
@@ -339,6 +339,21 @@ scp_session_set_layout(struct SCP_SESSION* s, tui16 layout)
   return 0;
 }
 
+/*******************************************************************/
+int
+scp_session_set_guid(struct SCP_SESSION *s, const tui8 *guid)
+{
+    if (0 == guid)
+    {
+        log_message(s_log, LOG_LEVEL_WARNING, "[session:%d] set_guid: null guid", __LINE__);
+        return 1;
+    }
+
+    g_memcpy(s->guid, guid, 16);
+
+    return 0;
+}
+
 /*******************************************************************/
 void
 scp_session_destroy(struct SCP_SESSION* s)
@@ -367,5 +382,6 @@ scp_session_destroy(struct SCP_SESSION* s)
     s->errstr=0;
   }
 
-  g_free(s);
+    g_free(s->mng);
+    g_free(s);
 }
diff --git a/sesman/libscp/libscp_session.h b/sesman/libscp/libscp_session.h
index eacc1097..043cc5d2 100644
--- a/sesman/libscp/libscp_session.h
+++ b/sesman/libscp/libscp_session.h
@@ -86,6 +86,9 @@ scp_session_set_errstr(struct SCP_SESSION* s, char* str);
 int
 scp_session_set_layout(struct SCP_SESSION* s, tui16 layout);
 
+int
+scp_session_set_guid(struct SCP_SESSION *s, const tui8 *guid);
+
 /**
  *
  * @brief destroys a session object
diff --git a/sesman/libscp/libscp_types.h b/sesman/libscp/libscp_types.h
index cacc4d52..1905178c 100644
--- a/sesman/libscp/libscp_types.h
+++ b/sesman/libscp/libscp_types.h
@@ -87,6 +87,12 @@ struct SCP_SESSION
   tui16 display;
   char* errstr;
   tui16 layout;
+  struct SCP_MNG_DATA* mng;
+  char* domain;
+  char* program;
+  char* directory;
+  char* client_ip;
+  tui8 guid[16];
 };
 
 struct SCP_DISCONNECTED_SESSION
diff --git a/sesman/libscp/libscp_v0.c b/sesman/libscp/libscp_v0.c
index 6dad6076..6744caee 100644
--- a/sesman/libscp/libscp_v0.c
+++ b/sesman/libscp/libscp_v0.c
@@ -375,23 +375,30 @@ scp_v0s_accept(struct SCP_CONNECTION *c, struct SCP_SESSION **s, int skipVchk)
 }
 
 /******************************************************************************/
-enum SCP_SERVER_STATES_E scp_v0s_allow_connection(struct SCP_CONNECTION* c, SCP_DISPLAY d)
+enum SCP_SERVER_STATES_E
+scp_v0s_allow_connection(struct SCP_CONNECTION *c, SCP_DISPLAY d, const tui8 *guid)
 {
-  out_uint32_be(c->out_s, 0);  /* version */
-  out_uint32_be(c->out_s, 14); /* size */
-  out_uint16_be(c->out_s, 3);  /* cmd */
-  out_uint16_be(c->out_s, 1);  /* data */
-  out_uint16_be(c->out_s, d);  /* data */
-  s_mark_end(c->out_s);
+    int msg_size;
+
+    msg_size = guid == 0 ? 14 : 14 + 16;
+    out_uint32_be(c->out_s, 0);  /* version */
+    out_uint32_be(c->out_s, msg_size); /* size */
+    out_uint16_be(c->out_s, 3);  /* cmd */
+    out_uint16_be(c->out_s, 1);  /* data */
+    out_uint16_be(c->out_s, d);  /* data */
+    if (msg_size > 14)
+    {
+        out_uint8a(c->out_s, guid, 16);
+    }
+    s_mark_end(c->out_s);
 
-  if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, c->out_s->end - c->out_s->data))
-  {
-    log_message(s_log, LOG_LEVEL_WARNING, "[v0:%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, c->out_s->end - c->out_s->data))
+    {
+        log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__);
+        return SCP_SERVER_STATE_NETWORK_ERR;
+    }
 
-  LOG_DBG(s_log, "[v0:%d] connection terminated (allowed)", __LINE__);
-  return SCP_SERVER_STATE_OK;
+    return SCP_SERVER_STATE_OK;
 }
 
 /******************************************************************************/
diff --git a/sesman/libscp/libscp_v0.h b/sesman/libscp/libscp_v0.h
index fa219348..de36fd24 100644
--- a/sesman/libscp/libscp_v0.h
+++ b/sesman/libscp/libscp_v0.h
@@ -61,8 +61,8 @@ scp_v0s_accept(struct SCP_CONNECTION* c, struct SCP_SESSION** s, int skipVchk);
  * @param c connection descriptor
  *
  */
-enum SCP_SERVER_STATES_E 
-scp_v0s_allow_connection(struct SCP_CONNECTION* c, SCP_DISPLAY d);
+enum SCP_SERVER_STATES_E
+scp_v0s_allow_connection(struct SCP_CONNECTION* c, SCP_DISPLAY d, const tui8 *guid);
 
 /**
  *
diff --git a/sesman/scp_v0.c b/sesman/scp_v0.c
index 428e0b79..e1dc29c7 100644
--- a/sesman/scp_v0.c
+++ b/sesman/scp_v0.c
@@ -38,6 +38,7 @@ scp_v0_process(struct SCP_CONNECTION* c, struct SCP_SESSION* s)
     struct session_item *s_item;
     int errorcode = 0;
     int do_auth_end = 1;
+    tui8 guid[16];
 
   data = auth_userpass(s->username, s->password);
 
@@ -55,24 +56,27 @@ scp_v0_process(struct SCP_CONNECTION* c, struct SCP_SESSION* s)
       LOG_DBG(&(g_cfg->log), "pre auth");
       if (1 == access_login_allowed(s->username))
       {
+        g_random((char *) guid, 16);
+        scp_session_set_guid(s, guid);
+
         log_message(&(g_cfg->log), LOG_LEVEL_INFO, "granted TS access to user %s", s->username);
         if (SCP_SESSION_TYPE_XVNC == s->type)
         {
           log_message(&(g_cfg->log), LOG_LEVEL_INFO, "starting Xvnc session...");
           display = session_start(s->width, s->height, s->bpp, s->layout, s->username, s->password,
-                                  s->wm, data, SESMAN_SESSION_TYPE_XVNC);
+                                  s->wm, data, SESMAN_SESSION_TYPE_XVNC, s->guid);
         }
         else if (SCP_SESSION_TYPE_XRDP == s->type)
         {
           log_message(&(g_cfg->log), LOG_LEVEL_INFO, "starting X11rdp session...");
           display = session_start(s->width, s->height, s->bpp, s->layout, s->username, s->password,
-                                  s->wm, data, SESMAN_SESSION_TYPE_XRDP);
+                                  s->wm, data, SESMAN_SESSION_TYPE_XRDP, s->guid);
         }
 	else
         {
           log_message(&(g_cfg->log), LOG_LEVEL_INFO, "starting Xdmx session...");
           display = session_start(s->width, s->height, s->bpp, s->layout, s->username, s->password,
-                                  s->wm, data, SESMAN_SESSION_TYPE_XDMX);
+                                  s->wm, data, SESMAN_SESSION_TYPE_XDMX, s->guid);
         }
       }
       else
@@ -88,7 +92,7 @@ scp_v0_process(struct SCP_CONNECTION* c, struct SCP_SESSION* s)
     }
     else
     {
-      scp_v0s_allow_connection(c, display);
+      scp_v0s_allow_connection(c, display, s->guid);
     }
   }
   else
diff --git a/sesman/scp_v1.c b/sesman/scp_v1.c
index 6fdad8de..6162773b 100644
--- a/sesman/scp_v1.c
+++ b/sesman/scp_v1.c
@@ -113,19 +113,19 @@ scp_v1_process(struct SCP_CONNECTION* c, struct SCP_SESSION* s)
     {
       log_message(&(g_cfg->log), LOG_LEVEL_INFO, "starting Xvnc session...");
       display = session_start(s->width, s->height, s->bpp, s->layout, s->username,
-                              s->password, s->wm, data, SESMAN_SESSION_TYPE_XVNC);
+                              s->password, s->wm, data, SESMAN_SESSION_TYPE_XVNC, s->guid);
     }
     else if (SCP_SESSION_TYPE_XRDP == s->type)
     {
       log_message(&(g_cfg->log), LOG_LEVEL_INFO, "starting X11rdp session...");
       display = session_start(s->width, s->height, s->bpp, s->layout, s->username,
-                              s->password, s->wm, data, SESMAN_SESSION_TYPE_XRDP);
+                              s->password, s->wm, data, SESMAN_SESSION_TYPE_XRDP, s->guid);
     }
     else
     {
       log_message(&(g_cfg->log), LOG_LEVEL_INFO, "starting Xdmx session...");
       display = session_start(s->width, s->height, s->bpp, s->layout, s->username,
-                              s->password, s->wm, data, SESMAN_SESSION_TYPE_XDMX);
+                              s->password, s->wm, data, SESMAN_SESSION_TYPE_XDMX, s->guid);
     }
 
     do_auth_end = display == 0;
diff --git a/sesman/session.c b/sesman/session.c
index 0ef91730..90f71c59 100644
--- a/sesman/session.c
+++ b/sesman/session.c
@@ -557,7 +557,7 @@ session_setup_auth (char* display,
 int DEFAULT_CC
 session_start(int width, int height, int bpp, int layout,
 	      char* username, char* password,
-              char* wm, long data, unsigned char type)
+              char* wm, long data, unsigned char type, char *guid)
 {
   int display;
   int pid;
@@ -726,7 +726,20 @@ for user %s denied", username);
       g_exit(1);
     }
 
-    env_check_password_file(passwd_file, password);
+   if (guid != 0)
+   {
+      char guid_str[64];
+      char *pguid_str;
+      int index;
+      pguid_str = guid_str;
+      for (index = 0; index < 16; index++)
+      {
+        g_snprintf(pguid_str, 4, "%2.2x", guid[index]);
+        pguid_str += 2;
+      }
+      guid_str[32] = 0;
+      env_check_password_file(passwd_file, guid_str);
+   }
 
 #ifndef _WIN32
     g_signal (SIGUSR1, sig_usr1_waiting);
diff --git a/sesman/session.h b/sesman/session.h
index 83c2fe71..822b98f6 100644
--- a/sesman/session.h
+++ b/sesman/session.h
@@ -109,7 +109,7 @@ session_get_bydata(char* name, int width, int height, int bpp, int type);
 int DEFAULT_CC
 session_start(int width, int height, int bpp, int layout,
 	      char* username, char* password,
-              char* wm, long data, unsigned char type);
+              char* wm, long data, unsigned char type, char* guid);
 
 /**
  *
diff --git a/vnc/vnc.c b/vnc/vnc.c
index 0a348840..6a928084 100644
--- a/vnc/vnc.c
+++ b/vnc/vnc.c
@@ -24,17 +24,52 @@
 
 /******************************************************************************/
 /* taken from vncauth.c */
+/* performing the des3 crypt on the password so it can not be seen
+   on the wire
+   'bytes' in, contains 16 bytes server random
+           out, random and 'passwd' conbined */
 void DEFAULT_CC
-rfbEncryptBytes(char* bytes, char* passwd)
+rfbEncryptBytes(char* bytes, const char* passwd)
 {
-  char key[12];
+    char key[24];
+    void *des;
+    int len;
 
-  /* key is simply password padded with nulls */
-  g_memset(key, 0, sizeof(key));
-  g_strncpy(key, passwd, 8);
-  rfbDesKey((unsigned char*)key, EN0); /* 0, encrypt */
-  rfbDes((unsigned char*)bytes, (unsigned char*)bytes);
-  rfbDes((unsigned char*)(bytes + 8), (unsigned char*)(bytes + 8));
+    /* key is simply password padded with nulls */
+    g_memset(key, 0, sizeof(key));
+    len = MIN(g_strlen(passwd), 8);
+    g_mirror_memcpy(key, passwd, len);
+    des = ssl_des3_encrypt_info_create(key, 0);
+    ssl_des3_encrypt(des, 8, bytes, bytes);
+    ssl_des3_info_delete(des);
+    des = ssl_des3_encrypt_info_create(key, 0);
+    ssl_des3_encrypt(des, 8, bytes + 8, bytes + 8);
+    ssl_des3_info_delete(des);
+}
+
+/******************************************************************************/
+/* sha1 hash 'passwd', create a string from the hash and call rfbEncryptBytes */
+static void APP_CC
+rfbHashEncryptBytes(char *bytes, const char *passwd)
+{
+    char passwd_hash[20];
+    char passwd_hash_text[40];
+    void *sha1;
+    int passwd_bytes;
+
+    /* create password hash from password */
+    passwd_bytes = g_strlen(passwd);
+    sha1 = ssl_sha1_info_create();
+    ssl_sha1_transform(sha1, "xrdp_vnc", 8);
+    ssl_sha1_transform(sha1, passwd, passwd_bytes);
+    ssl_sha1_transform(sha1, passwd, passwd_bytes);
+    ssl_sha1_complete(sha1, passwd_hash);
+    ssl_sha1_info_delete(sha1);
+    g_snprintf(passwd_hash_text, 39, "%2.2x%2.2x%2.2x%2.2x",
+               (tui8)passwd_hash[0], (tui8)passwd_hash[1],
+               (tui8)passwd_hash[2], (tui8)passwd_hash[3]);
+    passwd_hash_text[39] = 0;
+    rfbEncryptBytes(bytes, passwd_hash_text);
 }
 
 /******************************************************************************/
@@ -1207,7 +1242,24 @@ connections", 0);
         error = lib_recv(v, s->data, 16);
         if (error == 0)
         {
+          if (v->got_guid)
+          {
+            char guid_str[64];
+            char *pguid_str;
+            int index;
+            pguid_str = guid_str;
+            for (index = 0; index < 16; index++)
+            {
+              g_snprintf(pguid_str, 4, "%2.2x", v->guid[index]);
+              pguid_str += 2;
+            }
+            guid_str[32] = 0;
+            rfbHashEncryptBytes(s->data, guid_str);
+          }
+          else
+          {
           rfbEncryptBytes(s->data, v->password);
+          }
           error = lib_send(v, s->data, 16);
         }
       }
@@ -1445,6 +1497,11 @@ lib_mod_set_param(struct vnc* v, char* name, char* value)
   {
     v->keylayout = g_atoi(value);
   }
+  else if (g_strcasecmp(name, "guid") == 0)
+  {
+    v->got_guid = 1;
+    g_memcpy(v->guid, value, 16);
+  }
   return 0;
 }
 
diff --git a/vnc/vnc.h b/vnc/vnc.h
index 1d664eb3..9865d4a1 100644
--- a/vnc/vnc.h
+++ b/vnc/vnc.h
@@ -24,6 +24,7 @@
 #include "arch.h"
 #include "parse.h"
 #include "os_calls.h"
+#include "ssl_calls.h"
 #include "d3des.h"
 
 struct vnc
@@ -112,4 +113,6 @@ struct vnc
   char* clip_data;
   int clip_data_size;
   tbus sck_obj;
+  int got_guid;
+  tui8 guid[16];
 };
diff --git a/xrdp/xrdp_mm.c b/xrdp/xrdp_mm.c
index 814497d9..699acbd8 100644
--- a/xrdp/xrdp_mm.c
+++ b/xrdp/xrdp_mm.c
@@ -437,7 +437,7 @@ xrdp_mm_setup_mod1(struct xrdp_mm* self)
 
 /*****************************************************************************/
 static int APP_CC
-xrdp_mm_setup_mod2(struct xrdp_mm* self)
+xrdp_mm_setup_mod2(struct xrdp_mm* self, tui8 *guid)
 {
   char text[256];
   char* name;
@@ -495,6 +495,10 @@ xrdp_mm_setup_mod2(struct xrdp_mm* self)
     self->mod->mod_set_param(self->mod, "hostname", name);
     g_snprintf(text, 255, "%d", self->wm->session->client_info->keylayout);
     self->mod->mod_set_param(self->mod, "keylayout", text);
+    if (guid != 0)
+    {
+        self->mod->mod_set_param(self->mod, "guid", (char*)guid);
+    }
     for (i = 0; i < self->login_names->count; i++)
     {
       name = (char*)list_get_item(self->login_names, i);
@@ -544,10 +548,18 @@ xrdp_mm_process_login_response(struct xrdp_mm* self, struct stream* s)
   int display;
   int rv;
   char text[256];
+  tui8 guid[16];
+  tui8 *pguid;
 
   rv = 0;
   in_uint16_be(s, ok);
   in_uint16_be(s, display);
+  pguid = 0;
+  if (s_check_rem(s, 16))
+  {
+      in_uint8a(s, guid, 16);
+      pguid = guid;
+  }
   if (ok)
   {
     self->display = display;
@@ -555,7 +567,7 @@ xrdp_mm_process_login_response(struct xrdp_mm* self, struct stream* s)
     xrdp_wm_log_msg(self->wm, text);
     if (xrdp_mm_setup_mod1(self) == 0)
     {
-      if (xrdp_mm_setup_mod2(self) == 0)
+      if (xrdp_mm_setup_mod2(self, pguid) == 0)
       {
 	if (self->wm->login_mode == 3)
 	  xrdp_wm_set_login_mode(self->wm, 10);
@@ -679,7 +691,7 @@ xrdp_mm_connect(struct xrdp_mm* self)
   {
     if (xrdp_mm_setup_mod1(self) == 0)
     {
-      if (xrdp_mm_setup_mod2(self) == 0)
+      if (xrdp_mm_setup_mod2(self, 0) == 0)
       {
 	if (self->wm->login_mode == 3)
 	  xrdp_wm_set_login_mode(self->wm, 10);
-- 
2.26.2

