From 29990f0090754c722653aafd3fc6800cebc1584c Mon Sep 17 00:00:00 2001 From: Vic Lee Date: Wed, 7 Oct 2009 11:01:55 +0800 Subject: [PATCH] Add MSLogon security type Signed-off-by: Vic Lee Signed-off-by: Johannes Schindelin --- libvncclient/rfbproto.c | 124 +++++++++++++++++++++++++++++++++++++--- libvncserver/vncauth.c | 15 +++++ rfb/rfbclient.h | 10 ++++ rfb/rfbproto.h | 1 + 4 files changed, 142 insertions(+), 8 deletions(-) diff --git a/libvncclient/rfbproto.c b/libvncclient/rfbproto.c index 497facb..7b53722 100644 --- a/libvncclient/rfbproto.c +++ b/libvncclient/rfbproto.c @@ -414,6 +414,7 @@ ConnectToRFBServer(rfbClient* client,const char *hostname, int port) } extern void rfbClientEncryptBytes(unsigned char* bytes, char* passwd); +extern void rfbClientEncryptBytes2(unsigned char *where, const int length, unsigned char *key); rfbBool rfbHandleAuthResult(rfbClient* client) @@ -503,7 +504,7 @@ ReadSupportedSecurityType(rfbClient* client, uint32_t *result, rfbBool subAuth) if (!ReadFromRFBServer(client, (char *)&tAuth[loop], 1)) return FALSE; rfbClientLog("%d) Received security type %d\n", loop, tAuth[loop]); if (flag) continue; - if (tAuth[loop]==rfbVncAuth || tAuth[loop]==rfbNoAuth || + if (tAuth[loop]==rfbVncAuth || tAuth[loop]==rfbNoAuth || tAuth[loop]==rfbMSLogon || (!subAuth && (tAuth[loop]==rfbTLS || tAuth[loop]==rfbVeNCrypt))) { flag++; @@ -569,6 +570,14 @@ HandleVncAuth(rfbClient *client) return TRUE; } +static void +FreeUserCredential(rfbCredential *cred) +{ + if (cred->userCredential.username) free(cred->userCredential.username); + if (cred->userCredential.password) free(cred->userCredential.password); + free(cred); +} + static rfbBool HandlePlainAuth(rfbClient *client) { @@ -592,20 +601,114 @@ HandlePlainAuth(rfbClient *client) ulensw = rfbClientSwap32IfLE(ulen); plen = (cred->userCredential.password ? strlen(cred->userCredential.password) : 0); plensw = rfbClientSwap32IfLE(plen); - if (!WriteToRFBServer(client, (char *)&ulensw, 4)) return FALSE; - if (!WriteToRFBServer(client, (char *)&plensw, 4)) return FALSE; + if (!WriteToRFBServer(client, (char *)&ulensw, 4) || + !WriteToRFBServer(client, (char *)&plensw, 4)) + { + FreeUserCredential(cred); + return FALSE; + } if (ulen > 0) { - if (!WriteToRFBServer(client, cred->userCredential.username, ulen)) return FALSE; + if (!WriteToRFBServer(client, cred->userCredential.username, ulen)) + { + FreeUserCredential(cred); + return FALSE; + } } if (plen > 0) { - if (!WriteToRFBServer(client, cred->userCredential.password, plen)) return FALSE; + if (!WriteToRFBServer(client, cred->userCredential.password, plen)) + { + FreeUserCredential(cred); + return FALSE; + } } - if (cred->userCredential.username) free(cred->userCredential.username); - if (cred->userCredential.password) free(cred->userCredential.password); - free(cred); + FreeUserCredential(cred); + + /* Handle the SecurityResult message */ + if (!rfbHandleAuthResult(client)) return FALSE; + + return TRUE; +} + +/* Simple 64bit big integer arithmetic implementation */ +/* (x + y) % m, works even if (x + y) > 64bit */ +#define rfbAddM64(x,y,m) ((x+y)%m+(x+y0;x>>=1) + { + if (x&1) r=rfbAddM64(r,y,m); + y=rfbAddM64(y,y,m); + } + return r; +} +/* (x ^ y) % m */ +static uint64_t +rfbPowM64(uint64_t b, uint64_t e, uint64_t m) +{ + uint64_t r; + for(r=1;e>0;e>>=1) + { + if(e&1) r=rfbMulM64(r,b,m); + b=rfbMulM64(b,b,m); + } + return r; +} + +static rfbBool +HandleMSLogonAuth(rfbClient *client) +{ + uint64_t gen, mod, resp, priv, pub, key; + uint8_t username[256], password[64]; + rfbCredential *cred; + + if (!ReadFromRFBServer(client, (char *)&gen, 8)) return FALSE; + if (!ReadFromRFBServer(client, (char *)&mod, 8)) return FALSE; + if (!ReadFromRFBServer(client, (char *)&resp, 8)) return FALSE; + gen = rfbClientSwap64IfLE(gen); + mod = rfbClientSwap64IfLE(mod); + resp = rfbClientSwap64IfLE(resp); + + if (!client->GetCredential) + { + rfbClientLog("GetCredential callback is not set.\n"); + return FALSE; + } + rfbClientLog("WARNING! MSLogon security type has very low password encryption! "\ + "Use it only with SSH tunnel or trusted network.\n"); + cred = client->GetCredential(client, rfbCredentialTypeUser); + if (!cred) + { + rfbClientLog("Reading credential failed\n"); + return FALSE; + } + + memset(username, 0, sizeof(username)); + strncpy((char *)username, cred->userCredential.username, sizeof(username)); + memset(password, 0, sizeof(password)); + strncpy((char *)password, cred->userCredential.password, sizeof(password)); + FreeUserCredential(cred); + + srand(time(NULL)); + priv = ((uint64_t)rand())<<32; + priv |= (uint64_t)rand(); + + pub = rfbPowM64(gen, priv, mod); + key = rfbPowM64(resp, priv, mod); + pub = rfbClientSwap64IfLE(pub); + key = rfbClientSwap64IfLE(key); + + rfbClientEncryptBytes2(username, sizeof(username), (unsigned char *)&key); + rfbClientEncryptBytes2(password, sizeof(password), (unsigned char *)&key); + + if (!WriteToRFBServer(client, (char *)&pub, 8)) return FALSE; + if (!WriteToRFBServer(client, (char *)username, sizeof(username))) return FALSE; + if (!WriteToRFBServer(client, (char *)password, sizeof(password))) return FALSE; /* Handle the SecurityResult message */ if (!rfbHandleAuthResult(client)) return FALSE; @@ -713,6 +816,10 @@ InitialiseRFBConnection(rfbClient* client) if (!HandleVncAuth(client)) return FALSE; break; + case rfbMSLogon: + if (!HandleMSLogonAuth(client)) return FALSE; + break; + case rfbTLS: if (!HandleAnonTLSAuth(client)) return FALSE; /* After the TLS session is established, sub auth types are expected. @@ -1889,6 +1996,7 @@ PrintPixelFormat(rfbPixelFormat *format) /* avoid name clashes with LibVNCServer */ #define rfbEncryptBytes rfbClientEncryptBytes +#define rfbEncryptBytes2 rfbClientEncryptBytes2 #define rfbDes rfbClientDes #define rfbDesKey rfbClientDesKey #define rfbUseKey rfbClientUseKey diff --git a/libvncserver/vncauth.c b/libvncserver/vncauth.c index b8ee288..0b73531 100644 --- a/libvncserver/vncauth.c +++ b/libvncserver/vncauth.c @@ -191,3 +191,18 @@ rfbEncryptBytes(unsigned char *bytes, char *passwd) rfbDes(bytes+i, bytes+i); } } + +void +rfbEncryptBytes2(unsigned char *where, const int length, unsigned char *key) { + int i, j; + rfbDesKey(key, EN0); + for (i = 0; i< 8; i++) + where[i] ^= key[i]; + rfbDes(where, where); + for (i = 8; i < length; i += 8) { + for (j = 0; j < 8; j++) + where[i + j] ^= where[i + j - 8]; + rfbDes(where + i, where + i); + } +} + diff --git a/rfb/rfbclient.h b/rfb/rfbclient.h index c32168c..6d38c8f 100644 --- a/rfb/rfbclient.h +++ b/rfb/rfbclient.h @@ -46,6 +46,16 @@ (((l) & 0x0000ff00) << 8) | \ (((l) & 0x000000ff) << 24)) : (l)) +#define rfbClientSwap64IfLE(l) \ + (*(char *)&client->endianTest ? ((((l) & 0xff00000000000000ULL) >> 56) | \ + (((l) & 0x00ff000000000000ULL) >> 40) | \ + (((l) & 0x0000ff0000000000ULL) >> 24) | \ + (((l) & 0x000000ff00000000ULL) >> 8) | \ + (((l) & 0x00000000ff000000ULL) << 8) | \ + (((l) & 0x0000000000ff0000ULL) << 24) | \ + (((l) & 0x000000000000ff00ULL) << 40) | \ + (((l) & 0x00000000000000ffULL) << 56)) : (l)) + #define FLASH_PORT_OFFSET 5400 #define LISTEN_PORT_OFFSET 5500 #define TUNNEL_PORT_OFFSET 5500 diff --git a/rfb/rfbproto.h b/rfb/rfbproto.h index 06ab579..b6f201c 100644 --- a/rfb/rfbproto.h +++ b/rfb/rfbproto.h @@ -265,6 +265,7 @@ typedef char rfbProtocolVersionMsg[13]; /* allow extra byte for null */ #define rfbUltra 17 #define rfbTLS 18 #define rfbVeNCrypt 19 +#define rfbMSLogon 0xfffffffa #define rfbVeNCryptPlain 256 #define rfbVeNCryptTLSNone 257