summaryrefslogtreecommitdiffstats
path: root/src/VBox/HostServices/auth
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/VBox/HostServices/auth/Makefile.kmk76
-rw-r--r--src/VBox/HostServices/auth/directoryservice/Makefile.kup0
-rw-r--r--src/VBox/HostServices/auth/directoryservice/directoryservice.cpp338
-rw-r--r--src/VBox/HostServices/auth/pam/Makefile.kup0
-rw-r--r--src/VBox/HostServices/auth/pam/VBoxAuthPAM.c417
-rw-r--r--src/VBox/HostServices/auth/simple/Makefile.kup0
-rw-r--r--src/VBox/HostServices/auth/simple/VBoxAuthSimple.cpp147
-rw-r--r--src/VBox/HostServices/auth/simple/VBoxAuthSimple.rc61
-rw-r--r--src/VBox/HostServices/auth/winlogon/Makefile.kup0
-rw-r--r--src/VBox/HostServices/auth/winlogon/VBoxAuth.rc61
-rw-r--r--src/VBox/HostServices/auth/winlogon/winlogon.cpp181
11 files changed, 1281 insertions, 0 deletions
diff --git a/src/VBox/HostServices/auth/Makefile.kmk b/src/VBox/HostServices/auth/Makefile.kmk
new file mode 100644
index 00000000..93fc8eea
--- /dev/null
+++ b/src/VBox/HostServices/auth/Makefile.kmk
@@ -0,0 +1,76 @@
+# $Id: Makefile.kmk $
+## @file
+# Sub-Makefile for the VBox RDP authentication plugins.
+#
+
+#
+# Copyright (C) 2006-2023 Oracle and/or its affiliates.
+#
+# This file is part of VirtualBox base platform packages, as
+# available from https://www.virtualbox.org.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation, in version 3 of the
+# License.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses>.
+#
+# SPDX-License-Identifier: GPL-3.0-only
+#
+
+SUB_DEPTH = ../../../..
+include $(KBUILD_PATH)/subheader.kmk
+
+# The plugin.
+ifndef VBOX_ONLY_SDK
+ if ("$(KBUILD_TARGET)" != "linux" && "$(KBUILD_TARGET)" != "solaris") || defined(VBOX_WITH_PAM)
+ DLLS += VBoxAuth
+ endif
+endif
+VBoxAuth_TEMPLATE = VBoxR3Dll
+VBoxAuth_SOURCES.linux = pam/VBoxAuthPAM.c
+VBoxAuth_SOURCES.solaris = pam/VBoxAuthPAM.c
+VBoxAuth_SOURCES.freebsd = pam/VBoxAuthPAM.c
+VBoxAuth_SOURCES.win = winlogon/winlogon.cpp winlogon/VBoxAuth.rc
+VBoxAuth_SOURCES.darwin = directoryservice/directoryservice.cpp
+VBoxAuth_CXXFLAGS.darwin = -Wno-deprecated-declarations
+VBoxAuth_LIBS.linux = $(LIB_RUNTIME) dl
+VBoxAuth_LIBS.solaris = $(LIB_RUNTIME) dl
+VBoxAuth_LIBS.freebsd = $(LIB_RUNTIME)
+VBoxAuth_LIBS.darwin = $(LIB_RUNTIME)
+VBoxAuth_LDFLAGS.darwin = -framework DirectoryService
+
+# The simple plugin.
+ifndef VBOX_ONLY_SDK
+ if defined(VBOX_WITH_MAIN)
+ DLLS += VBoxAuthSimple
+ endif
+endif
+VBoxAuthSimple_TEMPLATE = VBoxMainClientDll
+VBoxAuthSimple_SOURCES = simple/VBoxAuthSimple.cpp
+VBoxAuthSimple_SOURCES.win = simple/VBoxAuthSimple.rc
+
+# Install the SDK samples.
+INSTALLS += VBoxAuth-samples
+VBoxAuth-samples_INST = $(INST_SDK)bindings/auth/
+VBoxAuth-samples_MODE = a+r,u+w
+VBoxAuth-samples_SOURCES = simple/VBoxAuthSimple.cpp
+VBoxAuth-samples_SOURCES.linux = pam/VBoxAuthPAM.c
+VBoxAuth-samples_SOURCES.win = winlogon/winlogon.cpp
+
+# Install the SDK header.
+INSTALLS += VBoxAuth-sdkhdr
+VBoxAuth-sdkhdr_INST = $(INST_SDK)bindings/auth/include/
+VBoxAuth-sdkhdr_MODE = a+r,u+w
+VBoxAuth-sdkhdr_SOURCES = $(PATH_ROOT)/include/VBox/VBoxAuth.h=>VBoxAuth.h
+
+
+include $(FILE_KBUILD_SUB_FOOTER)
+
diff --git a/src/VBox/HostServices/auth/directoryservice/Makefile.kup b/src/VBox/HostServices/auth/directoryservice/Makefile.kup
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/VBox/HostServices/auth/directoryservice/Makefile.kup
diff --git a/src/VBox/HostServices/auth/directoryservice/directoryservice.cpp b/src/VBox/HostServices/auth/directoryservice/directoryservice.cpp
new file mode 100644
index 00000000..ea245961
--- /dev/null
+++ b/src/VBox/HostServices/auth/directoryservice/directoryservice.cpp
@@ -0,0 +1,338 @@
+/** @file
+ *
+ * VirtualBox External Authentication Library:
+ * Mac OS X Authentication. This is based on
+ * http://developer.apple.com/mac/library/samplecode/CryptNoMore/
+ */
+
+/*
+ * Copyright (C) 2009-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#include <iprt/cdefs.h>
+#include <iprt/assert.h>
+
+#include <VBox/VBoxAuth.h>
+
+#include <DirectoryService/DirectoryService.h>
+
+/* Globals */
+static const size_t s_cBufferSize = 32 * 1024;
+
+tDirStatus defaultSearchNodePath(tDirReference pDirRef, tDataListPtr *pdsNodePath)
+{
+ tDirStatus dsErr = eDSNoErr;
+ /* Create a buffer for the resulting nodes */
+ tDataBufferPtr pTmpBuf = NULL;
+ pTmpBuf = dsDataBufferAllocate(pDirRef, s_cBufferSize);
+ if (pTmpBuf)
+ {
+ /* Try to find the default search node for local names */
+ UInt32 cNodes;
+ tContextData hCtx = 0;
+ dsErr = dsFindDirNodes(pDirRef, pTmpBuf, NULL, eDSLocalNodeNames, &cNodes, &hCtx);
+ /* Any nodes found? */
+ if ( dsErr == eDSNoErr
+ && cNodes >= 1)
+ /* The first path of the node list is what we looking for. */
+ dsErr = dsGetDirNodeName(pDirRef, pTmpBuf, 1, pdsNodePath);
+ else
+ dsErr = eDSNodeNotFound;
+
+ if (hCtx) /* (DSoNodeConfig.m from DSTools-162 does exactly the same free if not-zero-regardless-of-return-code.) */
+ dsReleaseContinueData(pDirRef, hCtx);
+ dsDataBufferDeAllocate(pDirRef, pTmpBuf);
+ }
+ else
+ dsErr = eDSAllocationFailed;
+
+ return dsErr;
+}
+
+tDirStatus userAuthInfo(tDirReference pDirRef, tDirNodeReference pNodeRef, const char *pszUsername, tDataListPtr *ppAuthNodeListOut)
+{
+ tDirStatus dsErr = eDSNoErr;
+ tDirStatus dsCleanErr = eDSNoErr;
+ /* Create a buffer for the resulting authentication info */
+ tDataBufferPtr pTmpBuf = dsDataBufferAllocate(pDirRef, s_cBufferSize);
+ if (pTmpBuf)
+ {
+ /* Create the necessary lists for kDSNAttrMetaNodeLocation and kDSNAttrRecordName. */
+ tDataListPtr pRecordType = dsBuildListFromStrings(pDirRef, kDSStdRecordTypeUsers, NULL);
+ tDataListPtr pRecordName = dsBuildListFromStrings(pDirRef, pszUsername, NULL);
+ tDataListPtr pRequestedAttributes = dsBuildListFromStrings(pDirRef, kDSNAttrMetaNodeLocation, kDSNAttrRecordName, NULL);
+ if (!( pRecordType == NULL
+ || pRecordName == NULL
+ || pRequestedAttributes == NULL))
+ {
+ /* Now search for the first matching record */
+ UInt32 cRecords = 1;
+ tContextData hCtx = 0;
+ dsErr = dsGetRecordList(pNodeRef,
+ pTmpBuf,
+ pRecordName,
+ eDSExact,
+ pRecordType,
+ pRequestedAttributes,
+ false,
+ &cRecords,
+ &hCtx);
+ if ( dsErr == eDSNoErr
+ && cRecords >= 1)
+ {
+ /* Process the first found record. Look at any attribute one by one. */
+ tAttributeListRef hRecAttrListRef = 0;
+ tRecordEntryPtr pRecEntry = NULL;
+ tDataListPtr pAuthNodeList = NULL;
+ dsErr = dsGetRecordEntry(pNodeRef, pTmpBuf, 1, &hRecAttrListRef, &pRecEntry);
+ if (dsErr == eDSNoErr)
+ {
+ for (size_t i = 1; i <= pRecEntry->fRecordAttributeCount; ++i)
+ {
+ tAttributeValueListRef hAttrValueListRef = 0;
+ tAttributeEntryPtr pAttrEntry = NULL;
+ /* Get the information for this attribute. */
+ dsErr = dsGetAttributeEntry(pNodeRef, pTmpBuf, hRecAttrListRef, i,
+ &hAttrValueListRef, &pAttrEntry);
+ if (dsErr == eDSNoErr)
+ {
+ tAttributeValueEntryPtr pValueEntry = NULL;
+ /* Has any value? */
+ if (pAttrEntry->fAttributeValueCount > 0)
+ {
+ dsErr = dsGetAttributeValue(pNodeRef, pTmpBuf, 1, hAttrValueListRef, &pValueEntry);
+ if (dsErr == eDSNoErr)
+ {
+ /* Check for kDSNAttrMetaNodeLocation */
+ if (strcmp(pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrMetaNodeLocation) == 0)
+ {
+ /* Convert the meta location attribute to a path node list */
+ pAuthNodeList = dsBuildFromPath(pDirRef,
+ pValueEntry->fAttributeValueData.fBufferData,
+ "/");
+ if (pAuthNodeList == NULL)
+ dsErr = eDSAllocationFailed;
+ }
+ }
+ }
+
+ if (pValueEntry != NULL)
+ dsDeallocAttributeValueEntry(pDirRef, pValueEntry);
+ if (hAttrValueListRef)
+ dsCloseAttributeValueList(hAttrValueListRef);
+ if (pAttrEntry != NULL)
+ dsDeallocAttributeEntry(pDirRef, pAttrEntry);
+
+ if (dsErr != eDSNoErr)
+ break;
+ }
+ }
+ }
+ /* Copy the results */
+ if (dsErr == eDSNoErr)
+ {
+ if (pAuthNodeList != NULL)
+ {
+ /* Copy out results. */
+ *ppAuthNodeListOut = pAuthNodeList;
+ pAuthNodeList = NULL;
+ }
+ else
+ dsErr = eDSAttributeNotFound;
+ }
+
+ if (pAuthNodeList != NULL)
+ {
+ dsCleanErr = dsDataListDeallocate(pDirRef, pAuthNodeList);
+ if (dsCleanErr == eDSNoErr)
+ free(pAuthNodeList);
+ }
+ if (hRecAttrListRef)
+ dsCloseAttributeList(hRecAttrListRef);
+ if (pRecEntry != NULL)
+ dsDeallocRecordEntry(pDirRef, pRecEntry);
+ }
+ else
+ dsErr = eDSRecordNotFound;
+ if (hCtx)
+ dsReleaseContinueData(pDirRef, hCtx);
+ }
+ else
+ dsErr = eDSAllocationFailed;
+ if (pRequestedAttributes != NULL)
+ {
+ dsCleanErr = dsDataListDeallocate(pDirRef, pRequestedAttributes);
+ if (dsCleanErr == eDSNoErr)
+ free(pRequestedAttributes);
+ }
+ if (pRecordName != NULL)
+ {
+ dsCleanErr = dsDataListDeallocate(pDirRef, pRecordName);
+ if (dsCleanErr == eDSNoErr)
+ free(pRecordName);
+ }
+ if (pRecordType != NULL)
+ {
+ dsCleanErr = dsDataListDeallocate(pDirRef, pRecordType);
+ if (dsCleanErr == eDSNoErr)
+ free(pRecordType);
+ }
+ dsDataBufferDeAllocate(pDirRef, pTmpBuf);
+ }
+ else
+ dsErr = eDSAllocationFailed;
+
+ return dsErr;
+}
+
+tDirStatus authWithNode(tDirReference pDirRef, tDataListPtr pAuthNodeList, const char *pszUsername, const char *pszPassword)
+{
+ tDirStatus dsErr = eDSNoErr;
+ /* Open the authentication node. */
+ tDirNodeReference hAuthNodeRef = 0;
+ dsErr = dsOpenDirNode(pDirRef, pAuthNodeList, &hAuthNodeRef);
+ if (dsErr == eDSNoErr)
+ {
+ /* How like we to authenticate! */
+ tDataNodePtr pAuthMethod = dsDataNodeAllocateString(pDirRef, kDSStdAuthNodeNativeClearTextOK);
+ if (pAuthMethod)
+ {
+ /* Create the memory holding the authentication data. The data
+ * structure consists of 4 byte length of the username + zero byte,
+ * the username itself, a 4 byte length of the password & the
+ * password itself + zero byte. */
+ tDataBufferPtr pAuthOutBuf = dsDataBufferAllocate(pDirRef, s_cBufferSize);
+ if (pAuthOutBuf)
+ {
+ size_t cUserName = strlen(pszUsername) + 1;
+ size_t cPassword = strlen(pszPassword) + 1;
+ unsigned long cLen = 0;
+ tDataBufferPtr pAuthInBuf = dsDataBufferAllocate(pDirRef, sizeof(cLen) + cUserName + sizeof(cLen) + cPassword);
+ if (pAuthInBuf)
+ {
+ /* Move the data into the buffer. */
+ pAuthInBuf->fBufferLength = 0;
+ /* Length of the username */
+ cLen = cUserName;
+ memcpy(&pAuthInBuf->fBufferData[pAuthInBuf->fBufferLength], &cLen, sizeof(cLen));
+ pAuthInBuf->fBufferLength += sizeof(cLen);
+ /* The username itself */
+ memcpy(&pAuthInBuf->fBufferData[pAuthInBuf->fBufferLength], pszUsername, cUserName);
+ pAuthInBuf->fBufferLength += cUserName;
+ /* Length of the password */
+ cLen = cPassword;
+ memcpy(&pAuthInBuf->fBufferData[pAuthInBuf->fBufferLength], &cLen, sizeof(cLen));
+ pAuthInBuf->fBufferLength += sizeof(cLen);
+ /* The password itself */
+ memcpy(&pAuthInBuf->fBufferData[pAuthInBuf->fBufferLength], pszPassword, cPassword);
+ pAuthInBuf->fBufferLength += cPassword;
+ /* Now authenticate */
+ dsErr = dsDoDirNodeAuth(hAuthNodeRef, pAuthMethod, true, pAuthInBuf, pAuthOutBuf, NULL);
+ /* Clean up. */
+ dsDataBufferDeAllocate(pDirRef, pAuthInBuf);
+ }
+ else
+ dsErr = eDSAllocationFailed;
+ dsDataBufferDeAllocate(pDirRef, pAuthOutBuf);
+ }
+ else
+ dsErr = eDSAllocationFailed;
+ dsDataNodeDeAllocate(pDirRef, pAuthMethod);
+ }
+ else
+ dsErr = eDSAllocationFailed;
+ dsCloseDirNode(hAuthNodeRef);
+ }
+
+ return dsErr;
+}
+
+RT_C_DECLS_BEGIN
+DECLEXPORT(FNAUTHENTRY3) AuthEntry;
+RT_C_DECLS_END
+
+DECLEXPORT(AuthResult) AUTHCALL AuthEntry(const char *pszCaller,
+ PAUTHUUID pUuid,
+ AuthGuestJudgement guestJudgement,
+ const char *pszUser,
+ const char *pszPassword,
+ const char *pszDomain,
+ int fLogon,
+ unsigned clientId)
+{
+ RT_NOREF(pszCaller, pUuid, guestJudgement, pszDomain, clientId);
+
+ /* Validate input */
+ AssertPtrReturn(pszUser, AuthResultAccessDenied);
+ AssertPtrReturn(pszPassword, AuthResultAccessDenied);
+
+ /* Result to a default value */
+ AuthResult result = AuthResultAccessDenied;
+
+ /* Only process logon requests. */
+ if (!fLogon)
+ return result; /* Return value is ignored by the caller. */
+
+ tDirStatus dsErr = eDSNoErr;
+ tDirStatus dsCleanErr = eDSNoErr;
+ tDirReference hDirRef = 0;
+ /* Connect to the Directory Service. */
+ dsErr = dsOpenDirService(&hDirRef);
+ if (dsErr == eDSNoErr)
+ {
+ /* Fetch the default search node */
+ tDataListPtr pSearchNodeList = NULL;
+ dsErr = defaultSearchNodePath(hDirRef, &pSearchNodeList);
+ if (dsErr == eDSNoErr)
+ {
+ /* Open the default search node */
+ tDirNodeReference hSearchNodeRef = 0;
+ dsErr = dsOpenDirNode(hDirRef, pSearchNodeList, &hSearchNodeRef);
+ if (dsErr == eDSNoErr)
+ {
+ /* Search for the user info, fetch the authentication node &
+ * the authentication user name. This allows the client to
+ * specify a long user name even if the name which is used to
+ * authenticate has the short form. */
+ tDataListPtr pAuthNodeList = NULL;
+ dsErr = userAuthInfo(hDirRef, hSearchNodeRef, pszUser, &pAuthNodeList);
+ if (dsErr == eDSNoErr)
+ {
+ /* Open the authentication node and do the authentication. */
+ dsErr = authWithNode(hDirRef, pAuthNodeList, pszUser, pszPassword);
+ if (dsErr == eDSNoErr)
+ result = AuthResultAccessGranted;
+ dsCleanErr = dsDataListDeallocate(hDirRef, pAuthNodeList);
+ if (dsCleanErr == eDSNoErr)
+ free(pAuthNodeList);
+ }
+ dsCloseDirNode(hSearchNodeRef);
+ }
+ dsCleanErr = dsDataListDeallocate(hDirRef, pSearchNodeList);
+ if (dsCleanErr == eDSNoErr)
+ free(pSearchNodeList);
+ }
+ dsCloseDirService(hDirRef);
+ }
+
+ return result;
+}
+
diff --git a/src/VBox/HostServices/auth/pam/Makefile.kup b/src/VBox/HostServices/auth/pam/Makefile.kup
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/VBox/HostServices/auth/pam/Makefile.kup
diff --git a/src/VBox/HostServices/auth/pam/VBoxAuthPAM.c b/src/VBox/HostServices/auth/pam/VBoxAuthPAM.c
new file mode 100644
index 00000000..5b7f14a3
--- /dev/null
+++ b/src/VBox/HostServices/auth/pam/VBoxAuthPAM.c
@@ -0,0 +1,417 @@
+/** @file
+ *
+ * VirtualBox External Authentication Library:
+ * Linux PAM Authentication.
+ */
+
+/*
+ * Copyright (C) 2006-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+
+/* The PAM service name.
+ *
+ * The service name is the name of a file in the /etc/pam.d which contains
+ * authentication rules. It is possible to use an existing service
+ * name, like "login" for example. But if different set of rules
+ * is required, one can create a new file /etc/pam.d/vrdpauth
+ * specially for VRDP authentication. Note that the name of the
+ * service must be lowercase. See PAM documentation for details.
+ *
+ * The Auth module takes the PAM service name from the
+ * environment variable VBOX_AUTH_PAM_SERVICE. If the variable
+ * is not specified, then the 'login' PAM service is used.
+ */
+#define VBOX_AUTH_PAM_SERVICE_NAME_ENV_OLD "VRDP_AUTH_PAM_SERVICE"
+#define VBOX_AUTH_PAM_SERVICE_NAME_ENV "VBOX_AUTH_PAM_SERVICE"
+#define VBOX_AUTH_PAM_DEFAULT_SERVICE_NAME "login"
+
+
+/* The debug log file name.
+ *
+ * If defined, debug messages will be written to the file specified in the
+ * VBOX_AUTH_DEBUG_FILENAME (or deprecated VRDP_AUTH_DEBUG_FILENAME) environment
+ * variable:
+ *
+ * export VBOX_AUTH_DEBUG_FILENAME=pam.log
+ *
+ * The above will cause writing to the pam.log.
+ */
+#define VBOX_AUTH_DEBUG_FILENAME_ENV_OLD "VRDP_AUTH_DEBUG_FILENAME"
+#define VBOX_AUTH_DEBUG_FILENAME_ENV "VBOX_AUTH_DEBUG_FILENAME"
+
+
+/* Dynamic loading of the PAM library.
+ *
+ * If defined, the libpam.so is loaded dynamically.
+ * Enabled by default since it is often required,
+ * and does not harm.
+ */
+#define VBOX_AUTH_USE_PAM_DLLOAD
+
+
+#ifdef VBOX_AUTH_USE_PAM_DLLOAD
+/* The name of the PAM library */
+# ifdef RT_OS_SOLARIS
+# define PAM_LIB_NAME "libpam.so.1"
+# elif defined(RT_OS_FREEBSD)
+# define PAM_LIB_NAME "libpam.so"
+# else
+# define PAM_LIB_NAME "libpam.so.0"
+# endif
+#endif /* VBOX_AUTH_USE_PAM_DLLOAD */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#ifndef RT_OS_FREEBSD
+# include <malloc.h>
+#endif
+
+#include <security/pam_appl.h>
+
+#include <VBox/VBoxAuth.h>
+
+#ifdef VBOX_AUTH_USE_PAM_DLLOAD
+#include <dlfcn.h>
+
+static int (*fn_pam_start)(const char *service_name,
+ const char *user,
+ const struct pam_conv *pam_conversation,
+ pam_handle_t **pamh);
+static int (*fn_pam_authenticate)(pam_handle_t *pamh, int flags);
+static int (*fn_pam_acct_mgmt)(pam_handle_t *pamh, int flags);
+static int (*fn_pam_end)(pam_handle_t *pamh, int pam_status);
+static const char * (*fn_pam_strerror)(pam_handle_t *pamh, int errnum);
+#else
+#define fn_pam_start pam_start
+#define fn_pam_authenticate pam_authenticate
+#define fn_pam_acct_mgmt pam_acct_mgmt
+#define fn_pam_end pam_end
+#define fn_pam_strerror pam_strerror
+#endif /* VBOX_AUTH_USE_PAM_DLLOAD */
+
+static void debug_printf(const char *fmt, ...)
+{
+#if defined(VBOX_AUTH_DEBUG_FILENAME_ENV) || defined(VBOX_AUTH_DEBUG_FILENAME_ENV_OLD)
+ va_list va;
+
+ char buffer[1024];
+
+ const char *filename = NULL;
+
+ va_start(va, fmt);
+
+#if defined(VBOX_AUTH_DEBUG_FILENAME_ENV)
+ filename = getenv (VBOX_AUTH_DEBUG_FILENAME_ENV);
+#endif /* VBOX_AUTH_DEBUG_FILENAME_ENV */
+
+#if defined(VBOX_AUTH_DEBUG_FILENAME_ENV_OLD)
+ if (filename == NULL)
+ {
+ filename = getenv (VBOX_AUTH_DEBUG_FILENAME_ENV_OLD);
+ }
+#endif /* VBOX_AUTH_DEBUG_FILENAME_ENV_OLD */
+
+ if (filename)
+ {
+ FILE *f;
+
+ vsnprintf (buffer, sizeof (buffer), fmt, va);
+
+ f = fopen (filename, "ab");
+ if (f != NULL)
+ {
+ fprintf (f, "%s", buffer);
+ fclose (f);
+ }
+ }
+
+ va_end (va);
+#endif /* VBOX_AUTH_DEBUG_FILENAME_ENV || VBOX_AUTH_DEBUG_FILENAME_ENV_OLD */
+}
+
+#ifdef VBOX_AUTH_USE_PAM_DLLOAD
+
+static void *gpvLibPam = NULL;
+
+typedef struct _SymMap
+{
+ void **ppfn;
+ const char *pszName;
+} SymMap;
+
+static SymMap symmap[] =
+{
+ { (void **)&fn_pam_start, "pam_start" },
+ { (void **)&fn_pam_authenticate, "pam_authenticate" },
+ { (void **)&fn_pam_acct_mgmt, "pam_acct_mgmt" },
+ { (void **)&fn_pam_end, "pam_end" },
+ { (void **)&fn_pam_strerror, "pam_strerror" },
+ { NULL, NULL }
+};
+
+static int auth_pam_init(void)
+{
+ SymMap *iter;
+
+ gpvLibPam = dlopen(PAM_LIB_NAME, RTLD_LAZY | RTLD_GLOBAL);
+
+ if (!gpvLibPam)
+ {
+ debug_printf("auth_pam_init: dlopen %s failed\n", PAM_LIB_NAME);
+ return PAM_SYSTEM_ERR;
+ }
+
+ iter = &symmap[0];
+
+ while (iter->pszName != NULL)
+ {
+ void *pv = dlsym (gpvLibPam, iter->pszName);
+
+ if (pv == NULL)
+ {
+ debug_printf("auth_pam_init: dlsym %s failed\n", iter->pszName);
+
+ dlclose(gpvLibPam);
+ gpvLibPam = NULL;
+
+ return PAM_SYSTEM_ERR;
+ }
+
+ *iter->ppfn = pv;
+
+ iter++;
+ }
+
+ return PAM_SUCCESS;
+}
+
+static void auth_pam_close(void)
+{
+ if (gpvLibPam)
+ {
+ dlclose(gpvLibPam);
+ gpvLibPam = NULL;
+ }
+
+ return;
+}
+#else
+static int auth_pam_init(void)
+{
+ return PAM_SUCCESS;
+}
+
+static void auth_pam_close(void)
+{
+ return;
+}
+#endif /* VBOX_AUTH_USE_PAM_DLLOAD */
+
+static const char *auth_get_pam_service (void)
+{
+ const char *service = getenv (VBOX_AUTH_PAM_SERVICE_NAME_ENV);
+
+ if (service == NULL)
+ {
+ service = getenv (VBOX_AUTH_PAM_SERVICE_NAME_ENV_OLD);
+
+ if (service == NULL)
+ {
+ service = VBOX_AUTH_PAM_DEFAULT_SERVICE_NAME;
+ }
+ }
+
+ debug_printf ("Using PAM service: %s\n", service);
+
+ return service;
+}
+
+typedef struct _PamContext
+{
+ char *pszUser;
+ char *pszPassword;
+} PamContext;
+
+#if defined(RT_OS_SOLARIS)
+static int conv (int num_msg, struct pam_message **msg,
+ struct pam_response **resp, void *appdata_ptr)
+#else
+static int conv (int num_msg, const struct pam_message **msg,
+ struct pam_response **resp, void *appdata_ptr)
+#endif
+{
+ int i;
+ struct pam_response *r;
+
+ PamContext *ctx = (PamContext *)appdata_ptr;
+
+ if (ctx == NULL)
+ {
+ debug_printf("conv: ctx is NULL\n");
+ return PAM_CONV_ERR;
+ }
+
+ debug_printf("conv: num %d u[%s] p[%d]\n", num_msg, ctx->pszUser, ctx->pszPassword? strlen (ctx->pszPassword): 0);
+
+ r = (struct pam_response *) calloc (num_msg, sizeof (struct pam_response));
+
+ if (r == NULL)
+ {
+ return PAM_CONV_ERR;
+ }
+
+ for (i = 0; i < num_msg; i++)
+ {
+ r[i].resp_retcode = 0;
+
+ if (msg[i]->msg_style == PAM_PROMPT_ECHO_OFF)
+ {
+ r[i].resp = strdup (ctx->pszPassword);
+ debug_printf("conv: %d returning password [%d]\n", i, r[i].resp? strlen (r[i].resp): 0);
+ }
+ else if (msg[i]->msg_style == PAM_PROMPT_ECHO_ON)
+ {
+ r[i].resp = strdup (ctx->pszUser);
+ debug_printf("conv: %d returning name [%s]\n", i, r[i].resp);
+ }
+ else
+ {
+ debug_printf("conv: %d style %d: [%s]\n", i, msg[i]->msg_style, msg[i]->msg? msg[i]->msg: "(null)");
+ r[i].resp = NULL;
+ }
+ }
+
+ *resp = r;
+ return PAM_SUCCESS;
+}
+
+/* The entry point must be visible. */
+#if defined(_MSC_VER) || defined(__OS2__)
+# define DECLEXPORT(type) __declspec(dllexport) type
+#else
+# ifdef VBOX_HAVE_VISIBILITY_HIDDEN
+# define DECLEXPORT(type) __attribute__((visibility("default"))) type
+# else
+# define DECLEXPORT(type) type
+# endif
+#endif
+
+/* prototype to prevent gcc warning */
+DECLEXPORT(AUTHENTRY3) AuthEntry;
+
+DECLEXPORT(AuthResult) AUTHCALL AuthEntry(const char *pszCaller,
+ PAUTHUUID pUuid,
+ AuthGuestJudgement guestJudgement,
+ const char *pszUser,
+ const char *pszPassword,
+ const char *pszDomain,
+ int fLogon,
+ unsigned clientId)
+{
+ AuthResult result = AuthResultAccessDenied;
+ int rc;
+ PamContext ctx;
+ struct pam_conv pam_conversation;
+ pam_handle_t *pam_handle = NULL;
+
+ (void)pszCaller;
+ (void)pUuid;
+ (void)guestJudgement;
+ (void)clientId;
+
+ /* Only process logon requests. */
+ if (!fLogon)
+ return result; /* Return value is ignored by the caller. */
+
+ debug_printf("u[%s], d[%s], p[%d]\n", pszUser, pszDomain, pszPassword ? strlen(pszPassword) : 0);
+
+ ctx.pszUser = (char *)pszUser;
+ ctx.pszPassword = (char *)pszPassword;
+
+ pam_conversation.conv = conv;
+ pam_conversation.appdata_ptr = &ctx;
+
+ rc = auth_pam_init ();
+
+ if (rc == PAM_SUCCESS)
+ {
+ debug_printf("init ok\n");
+
+ rc = fn_pam_start(auth_get_pam_service (), pszUser, &pam_conversation, &pam_handle);
+
+ if (rc == PAM_SUCCESS)
+ {
+ debug_printf("start ok\n");
+
+ rc = fn_pam_authenticate(pam_handle, 0);
+
+ if (rc == PAM_SUCCESS)
+ {
+ debug_printf("auth ok\n");
+
+ rc = fn_pam_acct_mgmt(pam_handle, 0);
+ if (rc == PAM_AUTHINFO_UNAVAIL
+ &&
+ getenv("VBOX_PAM_ALLOW_INACTIVE") != NULL)
+ {
+ debug_printf("PAM_AUTHINFO_UNAVAIL\n");
+ rc = PAM_SUCCESS;
+ }
+
+ if (rc == PAM_SUCCESS)
+ {
+ debug_printf("access granted\n");
+
+ result = AuthResultAccessGranted;
+ }
+ else
+ {
+ debug_printf("pam_acct_mgmt failed %d. %s\n", rc, fn_pam_strerror (pam_handle, rc));
+ }
+ }
+ else
+ {
+ debug_printf("pam_authenticate failed %d. %s\n", rc, fn_pam_strerror (pam_handle, rc));
+ }
+
+ fn_pam_end(pam_handle, rc);
+ }
+ else
+ {
+ debug_printf("pam_start failed %d\n", rc);
+ }
+
+ auth_pam_close ();
+
+ debug_printf("auth_pam_close completed\n");
+ }
+ else
+ {
+ debug_printf("auth_pam_init failed %d\n", rc);
+ }
+
+ return result;
+}
+
diff --git a/src/VBox/HostServices/auth/simple/Makefile.kup b/src/VBox/HostServices/auth/simple/Makefile.kup
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/VBox/HostServices/auth/simple/Makefile.kup
diff --git a/src/VBox/HostServices/auth/simple/VBoxAuthSimple.cpp b/src/VBox/HostServices/auth/simple/VBoxAuthSimple.cpp
new file mode 100644
index 00000000..671f2f00
--- /dev/null
+++ b/src/VBox/HostServices/auth/simple/VBoxAuthSimple.cpp
@@ -0,0 +1,147 @@
+/* $Id: VBoxAuthSimple.cpp $ */
+/** @file
+ * VirtualBox External Authentication Library - Simple Authentication.
+ */
+
+/*
+ * Copyright (C) 2006-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <iprt/cdefs.h>
+#include <iprt/uuid.h>
+#include <iprt/sha.h>
+
+#include <VBox/VBoxAuth.h>
+
+#include <VBox/com/com.h>
+#include <VBox/com/string.h>
+#include <VBox/com/Guid.h>
+#include <VBox/com/VirtualBox.h>
+
+using namespace com;
+
+/* If defined, debug messages will be written to the specified file. */
+//#define AUTH_DEBUG_FILE_NAME "/tmp/VBoxAuth.log"
+
+
+static void dprintf(const char *pszFormat, ...)
+{
+#ifdef AUTH_DEBUG_FILE_NAME
+ FILE *f = fopen(AUTH_DEBUG_FILE_NAME, "ab");
+ if (f)
+ {
+ va_list va;
+ va_start(va, pszFormat);
+ vfprintf(f, pszFormat, va);
+ va_end(va);
+ fclose(f);
+ }
+#else
+ RT_NOREF(pszFormat);
+#endif
+}
+
+RT_C_DECLS_BEGIN
+DECLEXPORT(FNAUTHENTRY3) AuthEntry;
+RT_C_DECLS_END
+
+DECLEXPORT(AuthResult) AUTHCALL AuthEntry(const char *pszCaller,
+ PAUTHUUID pUuid,
+ AuthGuestJudgement guestJudgement,
+ const char *pszUser,
+ const char *pszPassword,
+ const char *pszDomain,
+ int fLogon,
+ unsigned clientId)
+{
+ RT_NOREF(pszCaller, guestJudgement, pszDomain, clientId);
+
+ /* default is failed */
+ AuthResult result = AuthResultAccessDenied;
+
+ /* only interested in logon */
+ if (!fLogon)
+ /* return value ignored */
+ return result;
+
+ char uuid[RTUUID_STR_LENGTH] = {0};
+ if (pUuid)
+ RTUuidToStr((PCRTUUID)pUuid, (char*)uuid, RTUUID_STR_LENGTH);
+
+ /* the user might contain a domain name, split it */
+ const char *user = strchr(pszUser, '\\');
+ if (user)
+ user++;
+ else
+ user = (char*)pszUser;
+
+ dprintf("VBoxAuth: uuid: %s, user: %s, pszPassword: %s\n", uuid, user, pszPassword);
+
+ ComPtr<IVirtualBoxClient> virtualBoxClient;
+ ComPtr<IVirtualBox> virtualBox;
+ HRESULT rc;
+
+ rc = virtualBoxClient.createInprocObject(CLSID_VirtualBoxClient);
+ if (SUCCEEDED(rc))
+ {
+ rc = virtualBoxClient->COMGETTER(VirtualBox)(virtualBox.asOutParam());
+ if (SUCCEEDED(rc))
+ {
+ Bstr key = BstrFmt("VBoxAuthSimple/users/%s", user);
+ Bstr password;
+
+ /* lookup in VM's extra data? */
+ if (pUuid)
+ {
+ ComPtr<IMachine> machine;
+ virtualBox->FindMachine(Bstr(uuid).raw(), machine.asOutParam());
+ if (machine)
+ machine->GetExtraData(key.raw(), password.asOutParam());
+ }
+ else
+ /* lookup global extra data */
+ virtualBox->GetExtraData(key.raw(), password.asOutParam());
+
+ if (!password.isEmpty())
+ {
+ /* calculate hash */
+ uint8_t abDigest[RTSHA256_HASH_SIZE];
+ RTSha256(pszPassword, strlen(pszPassword), abDigest);
+ char pszDigest[RTSHA256_DIGEST_LEN + 1];
+ RTSha256ToString(abDigest, pszDigest, sizeof(pszDigest));
+
+ if (password == pszDigest)
+ result = AuthResultAccessGranted;
+ }
+ }
+ else
+ dprintf("VBoxAuth: failed to get VirtualBox object reference: %#x\n", rc);
+ }
+ else
+ dprintf("VBoxAuth: failed to get VirtualBoxClient object reference: %#x\n", rc);
+
+ return result;
+}
+
diff --git a/src/VBox/HostServices/auth/simple/VBoxAuthSimple.rc b/src/VBox/HostServices/auth/simple/VBoxAuthSimple.rc
new file mode 100644
index 00000000..9f466a46
--- /dev/null
+++ b/src/VBox/HostServices/auth/simple/VBoxAuthSimple.rc
@@ -0,0 +1,61 @@
+/* $Id: VBoxAuthSimple.rc $ */
+/** @file
+ * VBoxAuthSimple - Resource file containing version info and icon.
+ */
+
+/*
+ * Copyright (C) 2015-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#include <windows.h>
+#include <VBox/version.h>
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION VBOX_RC_FILE_VERSION
+ PRODUCTVERSION VBOX_RC_FILE_VERSION
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+ FILEFLAGS VBOX_RC_FILE_FLAGS
+ FILEOS VBOX_RC_FILE_OS
+ FILETYPE VBOX_RC_TYPE_DLL
+ FILESUBTYPE VFT2_UNKNOWN
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0" // Lang=US English, CharSet=Unicode
+ BEGIN
+ VALUE "FileDescription", "VirtualBox Simple Authentication Host Service\0"
+ VALUE "InternalName", "VBoxAuthSimple\0"
+ VALUE "OriginalFilename", "VBoxAuthSimple.dll\0"
+ VALUE "CompanyName", VBOX_RC_COMPANY_NAME
+ VALUE "FileVersion", VBOX_RC_FILE_VERSION_STR
+ VALUE "LegalCopyright", VBOX_RC_LEGAL_COPYRIGHT
+ VALUE "ProductName", VBOX_RC_PRODUCT_NAME_STR
+ VALUE "ProductVersion", VBOX_RC_PRODUCT_VERSION_STR
+ VBOX_RC_MORE_STRINGS
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/src/VBox/HostServices/auth/winlogon/Makefile.kup b/src/VBox/HostServices/auth/winlogon/Makefile.kup
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/VBox/HostServices/auth/winlogon/Makefile.kup
diff --git a/src/VBox/HostServices/auth/winlogon/VBoxAuth.rc b/src/VBox/HostServices/auth/winlogon/VBoxAuth.rc
new file mode 100644
index 00000000..800733f7
--- /dev/null
+++ b/src/VBox/HostServices/auth/winlogon/VBoxAuth.rc
@@ -0,0 +1,61 @@
+/* $Id: VBoxAuth.rc $ */
+/** @file
+ * VBoxAuth - Resource file containing version info and icon.
+ */
+
+/*
+ * Copyright (C) 2015-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#include <windows.h>
+#include <VBox/version.h>
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION VBOX_RC_FILE_VERSION
+ PRODUCTVERSION VBOX_RC_FILE_VERSION
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+ FILEFLAGS VBOX_RC_FILE_FLAGS
+ FILEOS VBOX_RC_FILE_OS
+ FILETYPE VBOX_RC_TYPE_DLL
+ FILESUBTYPE VFT2_UNKNOWN
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0" // Lang=US English, CharSet=Unicode
+ BEGIN
+ VALUE "FileDescription", "VirtualBox Authentication Host Service\0"
+ VALUE "InternalName", "VBoxAuth\0"
+ VALUE "OriginalFilename", "VBoxAuth.dll\0"
+ VALUE "CompanyName", VBOX_RC_COMPANY_NAME
+ VALUE "FileVersion", VBOX_RC_FILE_VERSION_STR
+ VALUE "LegalCopyright", VBOX_RC_LEGAL_COPYRIGHT
+ VALUE "ProductName", VBOX_RC_PRODUCT_NAME_STR
+ VALUE "ProductVersion", VBOX_RC_PRODUCT_VERSION_STR
+ VBOX_RC_MORE_STRINGS
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/src/VBox/HostServices/auth/winlogon/winlogon.cpp b/src/VBox/HostServices/auth/winlogon/winlogon.cpp
new file mode 100644
index 00000000..63277194
--- /dev/null
+++ b/src/VBox/HostServices/auth/winlogon/winlogon.cpp
@@ -0,0 +1,181 @@
+/* $Id: winlogon.cpp $ */
+/** @file
+ * VirtualBox External Authentication Library - Windows Logon Authentication.
+ */
+
+/*
+ * Copyright (C) 2006-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+/* If defined, debug messages will be written to the debugger. */
+// #define AUTH_DEBUG
+
+#include <iprt/win/windows.h>
+#include <VBox/VBoxAuth.h>
+#include <iprt/cdefs.h>
+
+#ifdef AUTH_DEBUG
+# include <stdio.h>
+
+static void dprintfw(const WCHAR *fmt, ...)
+{
+ va_list va;
+ va_start(va, fmt);
+
+ WCHAR buffer[1024];
+
+ _vsnwprintf(buffer, sizeof (buffer), fmt, va);
+
+ OutputDebugStringW(buffer);
+
+ va_end(va);
+}
+# define DBGAUTH(a) dprintfw a
+#else
+# define DBGAUTH(a)
+#endif
+
+static WCHAR g_wszEmpty[] = { L"" };
+
+static void freeWideChar(WCHAR *pwszString)
+{
+ if (pwszString && pwszString != &g_wszEmpty[0])
+ {
+ size_t cb = (wcslen(pwszString) + 1) * sizeof(WCHAR);
+ SecureZeroMemory(pwszString, cb);
+ free(pwszString);
+ }
+}
+
+static WCHAR *utf8ToWideChar(const char *pszString)
+{
+ /*
+ * Shortcut for empty strings.
+ */
+ if (!pszString || *pszString == 0)
+ return &g_wszEmpty[0];
+
+ /*
+ * Return NULL on errors.
+ */
+ WCHAR *pwszString = NULL;
+
+ /*
+ * First calc result string length.
+ */
+ const DWORD dwFlags = MB_ERR_INVALID_CHARS;
+ int cwc = MultiByteToWideChar(CP_UTF8, dwFlags, pszString, -1, NULL, 0);
+ if (cwc > 0)
+ {
+ /*
+ * Alloc space for result buffer.
+ */
+ pwszString = (WCHAR *)malloc(cwc * sizeof(WCHAR));
+ if (pwszString)
+ {
+ /*
+ * Do the translation.
+ */
+ if (MultiByteToWideChar(CP_UTF8, dwFlags, pszString, -1, pwszString, cwc) <= 0)
+ {
+ /* translation error */
+ free(pwszString);
+ pwszString = NULL;
+ }
+ }
+ }
+
+ return pwszString;
+}
+
+/* Prototype it to make sure we've got the right prototype. */
+#if defined(_MSC_VER)
+extern "C" __declspec(dllexport) FNAUTHENTRY3 AuthEntry;
+#else
+extern "C" FNAUTHENTRY3 AuthEntry;
+#endif
+
+/**
+ * @callback_method_impl{FNAUTHENTRY3}
+ */
+extern "C" DECLEXPORT(AuthResult) AUTHCALL
+AuthEntry(const char *pszCaller,
+ PAUTHUUID pUuid,
+ AuthGuestJudgement guestJudgement,
+ const char *pszUser,
+ const char *pszPassword,
+ const char *pszDomain,
+ int fLogon,
+ unsigned clientId)
+{
+ RT_NOREF4(pszCaller, pUuid, guestJudgement, clientId);
+ if (!fLogon)
+ {
+ /* Nothing to cleanup. The return code does not matter. */
+ return AuthResultAccessDenied;
+ }
+
+ LPWSTR pwszUsername = utf8ToWideChar(pszUser);
+ LPWSTR pwszDomain = utf8ToWideChar(pszDomain);
+ LPWSTR pwszPassword = utf8ToWideChar(pszPassword);
+
+ DBGAUTH((L"u[%ls], d[%ls], p[%ls]\n", lpwszUsername, lpwszDomain, lpwszPassword));
+
+ AuthResult result = AuthResultAccessDenied;
+
+ if (pwszUsername && pwszDomain && pwszPassword)
+ {
+ /* LOGON32_LOGON_INTERACTIVE is intended for users who will be interactively using the computer,
+ * such as a user being logged on by a terminal server, remote shell, or similar process.
+ */
+ DWORD dwLogonType = LOGON32_LOGON_INTERACTIVE;
+ DWORD dwLogonProvider = LOGON32_PROVIDER_DEFAULT;
+
+ HANDLE hToken;
+
+ BOOL fSuccess = LogonUserW(pwszUsername,
+ pwszDomain,
+ pwszPassword,
+ dwLogonType,
+ dwLogonProvider,
+ &hToken);
+
+ if (fSuccess)
+ {
+ DBGAUTH((L"LogonUser success. hToken = %p\n", hToken));
+
+ result = AuthResultAccessGranted;
+
+ CloseHandle(hToken);
+ }
+ else
+ {
+ DBGAUTH((L"LogonUser failed %08X\n", GetLastError()));
+ }
+ }
+
+ freeWideChar(pwszUsername);
+ freeWideChar(pwszDomain);
+ freeWideChar(pwszPassword);
+
+ return result;
+}
+