Commit 030ccf67 authored by Vic Lee's avatar Vic Lee Committed by Christian Beier

Add ARD (Apple Remote Desktop) security type support

Signed-off-by: 's avatarVic Lee <llyzs@163.com>
Signed-off-by: 's avatarChristian Beier <dontmind@freeshell.org>
parent ffe30366
......@@ -6999,3 +6999,112 @@ done
SED=$lt_cv_path_SED
AC_MSG_RESULT([$SED])
])
dnl Autoconf macros for libgcrypt
dnl Copyright (C) 2002, 2004 Free Software Foundation, Inc.
dnl
dnl This file is free software; as a special exception the author gives
dnl unlimited permission to copy and/or distribute it, with or without
dnl modifications, as long as this notice is preserved.
dnl
dnl This file is distributed in the hope that it will be useful, but
dnl WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
dnl implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
dnl AM_PATH_LIBGCRYPT([MINIMUM-VERSION,
dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]])
dnl Test for libgcrypt and define LIBGCRYPT_CFLAGS and LIBGCRYPT_LIBS.
dnl MINIMUN-VERSION is a string with the version number optionalliy prefixed
dnl with the API version to also check the API compatibility. Example:
dnl a MINIMUN-VERSION of 1:1.2.5 won't pass the test unless the installed
dnl version of libgcrypt is at least 1.2.5 *and* the API number is 1. Using
dnl this features allows to prevent build against newer versions of libgcrypt
dnl with a changed API.
dnl
AC_DEFUN([AM_PATH_LIBGCRYPT],
[ AC_ARG_WITH(libgcrypt-prefix,
AC_HELP_STRING([--with-libgcrypt-prefix=PFX],
[prefix where LIBGCRYPT is installed (optional)]),
libgcrypt_config_prefix="$withval", libgcrypt_config_prefix="")
if test x$libgcrypt_config_prefix != x ; then
if test x${LIBGCRYPT_CONFIG+set} != xset ; then
LIBGCRYPT_CONFIG=$libgcrypt_config_prefix/bin/libgcrypt-config
fi
fi
AC_PATH_PROG(LIBGCRYPT_CONFIG, libgcrypt-config, no)
tmp=ifelse([$1], ,1:1.2.0,$1)
if echo "$tmp" | grep ':' >/dev/null 2>/dev/null ; then
req_libgcrypt_api=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\1/'`
min_libgcrypt_version=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\2/'`
else
req_libgcrypt_api=0
min_libgcrypt_version="$tmp"
fi
AC_MSG_CHECKING(for LIBGCRYPT - version >= $min_libgcrypt_version)
ok=no
if test "$LIBGCRYPT_CONFIG" != "no" ; then
req_major=`echo $min_libgcrypt_version | \
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\1/'`
req_minor=`echo $min_libgcrypt_version | \
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\2/'`
req_micro=`echo $min_libgcrypt_version | \
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\3/'`
libgcrypt_config_version=`$LIBGCRYPT_CONFIG --version`
major=`echo $libgcrypt_config_version | \
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\1/'`
minor=`echo $libgcrypt_config_version | \
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\2/'`
micro=`echo $libgcrypt_config_version | \
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\3/'`
if test "$major" -gt "$req_major"; then
ok=yes
else
if test "$major" -eq "$req_major"; then
if test "$minor" -gt "$req_minor"; then
ok=yes
else
if test "$minor" -eq "$req_minor"; then
if test "$micro" -ge "$req_micro"; then
ok=yes
fi
fi
fi
fi
fi
fi
if test $ok = yes; then
AC_MSG_RESULT([yes ($libgcrypt_config_version)])
else
AC_MSG_RESULT(no)
fi
if test $ok = yes; then
# If we have a recent libgcrypt, we should also check that the
# API is compatible
if test "$req_libgcrypt_api" -gt 0 ; then
tmp=`$LIBGCRYPT_CONFIG --api-version 2>/dev/null || echo 0`
if test "$tmp" -gt 0 ; then
AC_MSG_CHECKING([LIBGCRYPT API version])
if test "$req_libgcrypt_api" -eq "$tmp" ; then
AC_MSG_RESULT([okay])
else
ok=no
AC_MSG_RESULT([does not match. want=$req_libgcrypt_api got=$tmp])
fi
fi
fi
fi
if test $ok = yes; then
LIBGCRYPT_CFLAGS=`$LIBGCRYPT_CONFIG --cflags`
LIBGCRYPT_LIBS=`$LIBGCRYPT_CONFIG --libs`
ifelse([$2], , :, [$2])
else
LIBGCRYPT_CFLAGS=""
LIBGCRYPT_LIBS=""
ifelse([$3], , :, [$3])
fi
AC_SUBST(LIBGCRYPT_CFLAGS)
AC_SUBST(LIBGCRYPT_LIBS)
])
......@@ -689,6 +689,22 @@ if test ! -z "$MINGW"; then
fi
AC_SUBST(WSOCKLIB)
# Check for libgcrypt
AH_TEMPLATE(WITH_CLIENT_GCRYPT, [Enable support for libgcrypt in libvncclient])
AC_ARG_WITH(gcrypt,
[ --without-gcrypt disable support for gcrypt],,)
AC_ARG_WITH(client-gcrypt,
[ --without-client-gcrypt disable support for gcrypt in libvncclient],,)
if test "x$with_gcrypt" != "xno"; then
AM_PATH_LIBGCRYPT(1.4.0, , with_client_gcrypt=no)
CFLAGS="$CFLAGS $LIBGCRYPT_CFLAGS"
LIBS="$LIBS $LIBGCRYPT_LIBS"
if test "x$with_client_gcrypt" != "xno"; then
AC_DEFINE(WITH_CLIENT_GCRYPT)
fi
fi
# Checks for GnuTLS
AH_TEMPLATE(WITH_CLIENT_TLS, [Enable support for gnutls in libvncclient])
AC_ARG_WITH(gnutls,
......
......@@ -51,6 +51,10 @@
#include <stdarg.h>
#include <time.h>
#ifdef LIBVNCSERVER_WITH_CLIENT_GCRYPT
#include <gcrypt.h>
#endif
#include "minilzo.h"
#include "tls.h"
......@@ -566,6 +570,7 @@ ReadSupportedSecurityType(rfbClient* client, uint32_t *result, rfbBool subAuth)
rfbClientLog("%d) Received security type %d\n", loop, tAuth[loop]);
if (flag) continue;
if (tAuth[loop]==rfbVncAuth || tAuth[loop]==rfbNoAuth || tAuth[loop]==rfbMSLogon ||
tAuth[loop]==rfbARD ||
(!subAuth && (tAuth[loop]==rfbTLS || tAuth[loop]==rfbVeNCrypt)))
{
if (!subAuth && client->clientAuthSchemes)
......@@ -795,6 +800,208 @@ HandleMSLogonAuth(rfbClient *client)
return TRUE;
}
#ifdef LIBVNCSERVER_WITH_CLIENT_GCRYPT
static rfbBool
rfbMpiToBytes(const gcry_mpi_t value, uint8_t *result, size_t size)
{
gcry_error_t error;
size_t len;
int i;
error = gcry_mpi_print(GCRYMPI_FMT_USG, result, size, &len, value);
if (gcry_err_code(error) != GPG_ERR_NO_ERROR)
{
rfbClientLog("gcry_mpi_print error: %s\n", gcry_strerror(error));
return FALSE;
}
for (i=size-1;i>(int)size-1-(int)len;--i)
result[i] = result[i-size+len];
for (;i>=0;--i)
result[i] = 0;
return TRUE;
}
static rfbBool
HandleARDAuth(rfbClient *client)
{
uint8_t gen[2], len[2];
size_t keylen;
uint8_t *mod = NULL, *resp, *pub, *key, *shared;
gcry_mpi_t genmpi = NULL, modmpi = NULL, respmpi = NULL;
gcry_mpi_t privmpi = NULL, pubmpi = NULL, keympi = NULL;
gcry_md_hd_t md5 = NULL;
gcry_cipher_hd_t aes = NULL;
gcry_error_t error;
uint8_t userpass[128], ciphertext[128];
int passwordLen, usernameLen;
rfbCredential *cred = NULL;
rfbBool result = FALSE;
while (1)
{
if (!ReadFromRFBServer(client, (char *)gen, 2))
break;
if (!ReadFromRFBServer(client, (char *)len, 2))
break;
if (!client->GetCredential)
{
rfbClientLog("GetCredential callback is not set.\n");
break;
}
cred = client->GetCredential(client, rfbCredentialTypeUser);
if (!cred)
{
rfbClientLog("Reading credential failed\n");
break;
}
keylen = 256*len[0]+len[1];
mod = (uint8_t*)malloc(keylen*4);
if (!mod)
{
rfbClientLog("malloc out of memory\n");
break;
}
resp = mod+keylen;
pub = resp+keylen;
key = pub+keylen;
if (!ReadFromRFBServer(client, (char *)mod, keylen))
break;
if (!ReadFromRFBServer(client, (char *)resp, keylen))
break;
error = gcry_mpi_scan(&genmpi, GCRYMPI_FMT_USG, gen, 2, NULL);
if (gcry_err_code(error) != GPG_ERR_NO_ERROR)
{
rfbClientLog("gcry_mpi_scan error: %s\n", gcry_strerror(error));
break;
}
error = gcry_mpi_scan(&modmpi, GCRYMPI_FMT_USG, mod, keylen, NULL);
if (gcry_err_code(error) != GPG_ERR_NO_ERROR)
{
rfbClientLog("gcry_mpi_scan error: %s\n", gcry_strerror(error));
break;
}
error = gcry_mpi_scan(&respmpi, GCRYMPI_FMT_USG, resp, keylen, NULL);
if (gcry_err_code(error) != GPG_ERR_NO_ERROR)
{
rfbClientLog("gcry_mpi_scan error: %s\n", gcry_strerror(error));
break;
}
privmpi = gcry_mpi_new(keylen);
if (!privmpi)
{
rfbClientLog("gcry_mpi_new out of memory\n");
break;
}
gcry_mpi_randomize(privmpi, (keylen/8)*8, GCRY_STRONG_RANDOM);
pubmpi = gcry_mpi_new(keylen);
if (!pubmpi)
{
rfbClientLog("gcry_mpi_new out of memory\n");
break;
}
gcry_mpi_powm(pubmpi, genmpi, privmpi, modmpi);
keympi = gcry_mpi_new(keylen);
if (!keympi)
{
rfbClientLog("gcry_mpi_new out of memory\n");
break;
}
gcry_mpi_powm(keympi, respmpi, privmpi, modmpi);
if (!rfbMpiToBytes(pubmpi, pub, keylen))
break;
if (!rfbMpiToBytes(keympi, key, keylen))
break;
error = gcry_md_open(&md5, GCRY_MD_MD5, 0);
if (gcry_err_code(error) != GPG_ERR_NO_ERROR)
{
rfbClientLog("gcry_md_open error: %s\n", gcry_strerror(error));
break;
}
gcry_md_write(md5, key, keylen);
error = gcry_md_final(md5);
if (gcry_err_code(error) != GPG_ERR_NO_ERROR)
{
rfbClientLog("gcry_md_final error: %s\n", gcry_strerror(error));
break;
}
shared = gcry_md_read(md5, GCRY_MD_MD5);
passwordLen = strlen(cred->userCredential.password)+1;
usernameLen = strlen(cred->userCredential.username)+1;
if (passwordLen > sizeof(userpass)/2)
passwordLen = sizeof(userpass)/2;
if (usernameLen > sizeof(userpass)/2)
usernameLen = sizeof(userpass)/2;
gcry_randomize(userpass, sizeof(userpass), GCRY_STRONG_RANDOM);
memcpy(userpass, cred->userCredential.username, usernameLen);
memcpy(userpass+sizeof(userpass)/2, cred->userCredential.password, passwordLen);
error = gcry_cipher_open(&aes, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB, 0);
if (gcry_err_code(error) != GPG_ERR_NO_ERROR)
{
rfbClientLog("gcry_cipher_open error: %s\n", gcry_strerror(error));
break;
}
error = gcry_cipher_setkey(aes, shared, 16);
if (gcry_err_code(error) != GPG_ERR_NO_ERROR)
{
rfbClientLog("gcry_cipher_setkey error: %s\n", gcry_strerror(error));
break;
}
error = gcry_cipher_encrypt(aes, ciphertext, sizeof(ciphertext), userpass, sizeof(userpass));
if (gcry_err_code(error) != GPG_ERR_NO_ERROR)
{
rfbClientLog("gcry_cipher_encrypt error: %s\n", gcry_strerror(error));
break;
}
if (!WriteToRFBServer(client, (char *)ciphertext, sizeof(ciphertext)))
break;
if (!WriteToRFBServer(client, (char *)pub, keylen))
break;
/* Handle the SecurityResult message */
if (!rfbHandleAuthResult(client))
break;
result = TRUE;
break;
}
if (cred)
FreeUserCredential(cred);
if (mod)
free(mod);
if (genmpi)
gcry_mpi_release(genmpi);
if (modmpi)
gcry_mpi_release(modmpi);
if (respmpi)
gcry_mpi_release(respmpi);
if (privmpi)
gcry_mpi_release(privmpi);
if (pubmpi)
gcry_mpi_release(pubmpi);
if (keympi)
gcry_mpi_release(keympi);
if (md5)
gcry_md_close(md5);
if (aes)
gcry_cipher_close(aes);
return result;
}
#endif
/*
* SetClientAuthSchemes.
*/
......@@ -928,6 +1135,15 @@ InitialiseRFBConnection(rfbClient* client)
if (!HandleMSLogonAuth(client)) return FALSE;
break;
case rfbARD:
#ifndef LIBVNCSERVER_WITH_CLIENT_GCRYPT
rfbClientLog("GCrypt support was not compiled in\n");
return FALSE;
#else
if (!HandleARDAuth(client)) return FALSE;
#endif
break;
case rfbTLS:
#ifndef LIBVNCSERVER_WITH_CLIENT_TLS
rfbClientLog("TLS support was not compiled in\n");
......
......@@ -286,6 +286,7 @@ typedef char rfbProtocolVersionMsg[13]; /* allow extra byte for null */
#define rfbUltra 17
#define rfbTLS 18
#define rfbVeNCrypt 19
#define rfbARD 30
#define rfbMSLogon 0xfffffffa
#define rfbVeNCryptPlain 256
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment