diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index cff4d6a614..c6150dcc53 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -62,6 +62,7 @@ #include #include #include +#include #include #include #include @@ -568,7 +569,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo _window->setWindowTitle("Interface"); Model::setAbstractViewStateInterface(this); // The model class will sometimes need to know view state details from us - + + // TODO: This is temporary, while developing + FingerprintUtils::getMachineFingerprint(); + // End TODO auto nodeList = DependencyManager::get(); // Set up a watchdog thread to intentionally crash the application on deadlocks diff --git a/libraries/networking/CMakeLists.txt b/libraries/networking/CMakeLists.txt index 53ebb86b83..8ef67cb2a4 100644 --- a/libraries/networking/CMakeLists.txt +++ b/libraries/networking/CMakeLists.txt @@ -15,6 +15,10 @@ add_dependency_external_projects(tbb) find_package(OpenSSL REQUIRED) find_package(TBB REQUIRED) +if (APPLE) + find_library(FRAMEWORK_IOKIT IOKit) +endif () + if (APPLE AND ${OPENSSL_INCLUDE_DIR} STREQUAL "/usr/include") # this is a user on OS X using system OpenSSL, which is going to throw warnings since they're deprecating for their common crypto message(WARNING "The found version of OpenSSL is the OS X system version. This will produce deprecation warnings." @@ -26,6 +30,11 @@ include_directories(SYSTEM "${OPENSSL_INCLUDE_DIR}") # append OpenSSL to our list of libraries to link target_link_libraries(${TARGET_NAME} ${OPENSSL_LIBRARIES} ${TBB_LIBRARIES}) +# IOKit is needed for getting machine fingerprint +if (APPLE) + target_link_libraries(${TARGET_NAME} ${FRAMEWORK_IOKIT}) +endif (APPLE) + # libcrypto uses dlopen in libdl if (UNIX) target_link_libraries(${TARGET_NAME} ${CMAKE_DL_LIBS}) diff --git a/libraries/networking/src/FingerprintUtils.cpp b/libraries/networking/src/FingerprintUtils.cpp new file mode 100644 index 0000000000..42a617e93d --- /dev/null +++ b/libraries/networking/src/FingerprintUtils.cpp @@ -0,0 +1,180 @@ +// +// FingerprintUtils.h +// libraries/networking/src +// +// Created by David Kelly on 2016-12-02. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "FingerprintUtils.h" +#include +#include +#ifdef Q_OS_WIN +#include +#include +#endif //Q_OS_WIN + +#ifdef Q_OS_MAC +#include +#include +#include +#endif //Q_OS_MAC + +static const QString FALLBACK_FINGERPRINT_KEY = "fallbackFingerprint"; +QString FingerprintUtils::getMachineFingerprintString() { + QString uuidString; +#ifdef Q_OS_LINUX + // sadly need to be root to get smbios guid from linux, so + // for now lets do nothing. +#endif //Q_OS_LINUX + +#ifdef Q_OS_MAC + io_registry_entry_t ioRegistryRoot = IORegistryEntryFromPath(kIOMasterPortDefault, "IOService:/"); + CFStringRef uuidCf = (CFStringRef) IORegistryEntryCreateCFProperty(ioRegistryRoot, CFSTR(kIOPlatformUUIDKey), kCFAllocatorDefault, 0); + IOObjectRelease(ioRegistryRoot); + uuidString = QString::fromCFString(uuidCf); + CFRelease(uuidCf); + qDebug() << "Mac serial number: " << uuidString; +#endif //Q_OS_MAC + +#ifdef Q_OS_WIN + HRESULT hres; + IWbemLocator *pLoc = NULL; + + // initialize com + hres = CoCreateInstance( + CLSID_WbemLocator, + 0, + CLSCTX_INPROC_SERVER, + IID_IWbemLocator, (LPVOID *) &pLoc); + + if (FAILED(hres)) { + qDebug() << "Failed to initialize WbemLocator"; + return uuidString; + } + + // Connect to WMI through the IWbemLocator::ConnectServer method + IWbemServices *pSvc = NULL; + + // Connect to the root\cimv2 namespace with + // the current user and obtain pointer pSvc + // to make IWbemServices calls. + hres = pLoc->ConnectServer( + _bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace + NULL, // User name. NULL = current user + NULL, // User password. NULL = current + 0, // Locale. NULL indicates current + NULL, // Security flags. + 0, // Authority (for example, Kerberos) + 0, // Context object + &pSvc // pointer to IWbemServices proxy + ); + + if (FAILED(hres)) { + pLoc->Release(); + qDebug() << "Failed to connect to WMI"; + return uuidString; + } + + // Set security levels on the proxy + hres = CoSetProxyBlanket( + pSvc, // Indicates the proxy to set + RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx + RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx + NULL, // Server principal name + RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx + RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx + NULL, // client identity + EOAC_NONE // proxy capabilities + ); + + if (FAILED(hres)) { + pSvc->Release(); + pLoc->Release(); + qDebug() << "Failed to set security on proxy blanket"; + return uuidString; + } + + // Use the IWbemServices pointer to grab the Win32_BIOS stuff + IEnumWbemClassObject* pEnumerator = NULL; + hres = pSvc->ExecQuery( + bstr_t("WQL"), + bstr_t("SELECT * FROM Win32_ComputerSystemProduct"), + WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, + NULL, + &pEnumerator); + + if (FAILED(hres)) { + pSvc->Release(); + pLoc->Release(); + qDebug() << "query to get Win32_ComputerSystemProduct info"; + return uuidString; + } + + // Get the SerialNumber from the Win32_BIOS data + IWbemClassObject *pclsObj; + ULONG uReturn = 0; + + SHORT sRetStatus = -100; + + while (pEnumerator) { + HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn); + + if(0 == uReturn){ + break; + } + + VARIANT vtProp; + + // Get the value of the Name property + hr = pclsObj->Get(L"UUID", 0, &vtProp, 0, 0); + if (!FAILED(hres)) { + switch (vtProp.vt) { + case VT_BSTR: + uuidString = QString::fromWCharArray(vtProp.bstrVal); + break; + } + } + VariantClear(&vtProp); + + pclsObj->Release(); + } + pEnumerator->Release(); + + // Cleanup + pSvc->Release(); + pLoc->Release(); + + qDebug() << "Windows BIOS UUID: " << uuidString; +#endif //Q_OS_WIN + + return uuidString; + +} + +QUuid FingerprintUtils::getMachineFingerprint() { + + QString uuidString = getMachineFingerprintString(); + + // now, turn into uuid. A malformed string will + // return QUuid() ("{00000...}"), which handles + // any errors in getting the string + QUuid uuid(uuidString); + if (uuid == QUuid()) { + // read fallback key (if any) + Settings settings; + uuid = QUuid(settings.value(FALLBACK_FINGERPRINT_KEY).toString()); + qDebug() << "read fallback maching fingerprint: " << uuid.toString(); + if (uuid == QUuid()) { + // no fallback yet, set one + uuid = QUuid::createUuid(); + settings.setValue(FALLBACK_FINGERPRINT_KEY, uuid.toString()); + qDebug() << "no fallback machine fingerprint, setting it to: " << uuid.toString(); + } + } + return uuid; +} + diff --git a/libraries/networking/src/FingerprintUtils.h b/libraries/networking/src/FingerprintUtils.h new file mode 100644 index 0000000000..572b150ec4 --- /dev/null +++ b/libraries/networking/src/FingerprintUtils.h @@ -0,0 +1,27 @@ +// +// FingerprintUtils.h +// libraries/networking/src +// +// Created by David Kelly on 2016-12-02. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_FingerprintUtils_h +#define hifi_FingerprintUtils_h + +#include +#include + +class FingerprintUtils { +public: + static QUuid getMachineFingerprint(); + +private: + static QString getMachineFingerprintString(); +}; + +#endif // hifi_FingerprintUtils_h +