From cb14b0e3e02eefd0868c338ebc118592a0c4dc7d Mon Sep 17 00:00:00 2001 From: David Kelly Date: Wed, 14 Dec 2016 14:51:35 -0800 Subject: [PATCH] inital cut, passing fingerprint in does permissions same as mac address, more or less. Not exposed yet, just a beginning. --- domain-server/src/DomainGatekeeper.cpp | 26 ++++++++--- domain-server/src/DomainGatekeeper.h | 4 +- domain-server/src/DomainServerNodeData.h | 6 ++- .../src/DomainServerSettingsManager.cpp | 44 ++++++++++++++++++- .../src/DomainServerSettingsManager.h | 6 +++ domain-server/src/NodeConnectionData.cpp | 3 ++ domain-server/src/NodeConnectionData.h | 1 + libraries/networking/src/FingerprintUtils.cpp | 7 +++ libraries/networking/src/NodeList.cpp | 5 +++ .../networking/src/udt/PacketHeaders.cpp | 2 +- libraries/networking/src/udt/PacketHeaders.h | 3 +- 11 files changed, 94 insertions(+), 13 deletions(-) diff --git a/domain-server/src/DomainGatekeeper.cpp b/domain-server/src/DomainGatekeeper.cpp index f55a2073d1..762871ed8b 100644 --- a/domain-server/src/DomainGatekeeper.cpp +++ b/domain-server/src/DomainGatekeeper.cpp @@ -120,19 +120,21 @@ void DomainGatekeeper::processConnectRequestPacket(QSharedPointersetPlaceName(nodeConnection.placeName); qDebug() << "Allowed connection from node" << uuidStringWithoutCurlyBraces(node->getUUID()) - << "on" << message->getSenderSockAddr() << "with MAC" << nodeConnection.hardwareAddress; + << "on" << message->getSenderSockAddr() << "with MAC" << nodeConnection.hardwareAddress + << " and machine fingerprint " << nodeConnection.machineFingerprint; // signal that we just connected a node so the DomainServer can get it a list // and broadcast its presence right away emit connectedNode(node); } else { qDebug() << "Refusing connection from node at" << message->getSenderSockAddr() - << "with hardware address" << nodeConnection.hardwareAddress; + << "with hardware address" << nodeConnection.hardwareAddress + << " and machine fingerprint " << nodeConnection.machineFingerprint; } } -NodePermissions DomainGatekeeper::setPermissionsForUser(bool isLocalUser, QString verifiedUsername, - const QHostAddress& senderAddress, const QString& hardwareAddress) { +NodePermissions DomainGatekeeper::setPermissionsForUser(bool isLocalUser, QString verifiedUsername, const QHostAddress& senderAddress, + const QString& hardwareAddress, const QUuid& machineFingerprint) { NodePermissions userPerms; userPerms.setAll(false); @@ -155,6 +157,11 @@ NodePermissions DomainGatekeeper::setPermissionsForUser(bool isLocalUser, QStrin #ifdef WANT_DEBUG qDebug() << "| user-permissions: specific MAC matches, so:" << userPerms; +#endif + } else if (_server->_settingsManager.hasPermissionsForMachineFingerprint(machineFingerprint)) { + userPerms = _server->_settingsManager.getPermissionsForMachineFingerprint(machineFingerprint); +#ifdef WANT_DEBUG + qDebug(() << "| user-permissions: specific Machine Fingerprint matches, so: " << userPerms; #endif } else if (_server->_settingsManager.hasPermissionsForIP(senderAddress)) { // this user comes from an IP we have in our permissions table, apply those permissions @@ -274,13 +281,15 @@ void DomainGatekeeper::updateNodePermissions() { HifiSockAddr connectingAddr = node->getActiveSocket() ? *node->getActiveSocket() : node->getPublicSocket(); QString hardwareAddress; + QUuid machineFingerprint; DomainServerNodeData* nodeData = reinterpret_cast(node->getLinkedData()); if (nodeData) { hardwareAddress = nodeData->getHardwareAddress(); + machineFingerprint = nodeData->getMachineFingerprint(); } - userPerms = setPermissionsForUser(isLocalUser, verifiedUsername, connectingAddr.getAddress(), hardwareAddress); + userPerms = setPermissionsForUser(isLocalUser, verifiedUsername, connectingAddr.getAddress(), hardwareAddress, machineFingerprint); } node->setPermissions(userPerms); @@ -334,6 +343,8 @@ SharedNodePointer DomainGatekeeper::processAssignmentConnectRequest(const NodeCo nodeData->setWalletUUID(it->second.getWalletUUID()); nodeData->setNodeVersion(it->second.getNodeVersion()); nodeData->setHardwareAddress(nodeConnection.hardwareAddress); + nodeData->setMachineFingerprint(nodeConnection.machineFingerprint); + nodeData->setWasAssigned(true); // cleanup the PendingAssignedNodeData for this assignment now that it's connecting @@ -396,7 +407,7 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect } userPerms = setPermissionsForUser(isLocalUser, verifiedUsername, nodeConnection.senderSockAddr.getAddress(), - nodeConnection.hardwareAddress); + nodeConnection.hardwareAddress, nodeConnection.machineFingerprint); if (!userPerms.can(NodePermissions::Permission::canConnectToDomain)) { sendConnectionDeniedPacket("You lack the required permissions to connect to this domain.", @@ -455,6 +466,9 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect // set the hardware address passed in the connect request nodeData->setHardwareAddress(nodeConnection.hardwareAddress); + // set the machine fingerprint passed in the connect request + nodeData->setMachineFingerprint(nodeConnection.machineFingerprint); + // also add an interpolation to DomainServerNodeData so that servers can get username in stats nodeData->addOverrideForKey(USERNAME_UUID_REPLACEMENT_STATS_KEY, uuidStringWithoutCurlyBraces(newNode->getUUID()), username); diff --git a/domain-server/src/DomainGatekeeper.h b/domain-server/src/DomainGatekeeper.h index b17d0f61a4..70f1bdaef6 100644 --- a/domain-server/src/DomainGatekeeper.h +++ b/domain-server/src/DomainGatekeeper.h @@ -107,8 +107,8 @@ private: QSet _domainOwnerFriends; // keep track of friends of the domain owner QSet _inFlightGroupMembershipsRequests; // keep track of which we've already asked for - NodePermissions setPermissionsForUser(bool isLocalUser, QString verifiedUsername, - const QHostAddress& senderAddress, const QString& hardwareAddress); + NodePermissions setPermissionsForUser(bool isLocalUser, QString verifiedUsername, const QHostAddress& senderAddress, + const QString& hardwareAddress, const QUuid& machineFingerprint); void getGroupMemberships(const QString& username); // void getIsGroupMember(const QString& username, const QUuid groupID); diff --git a/domain-server/src/DomainServerNodeData.h b/domain-server/src/DomainServerNodeData.h index ff637844f1..db41c77cf2 100644 --- a/domain-server/src/DomainServerNodeData.h +++ b/domain-server/src/DomainServerNodeData.h @@ -56,7 +56,10 @@ public: void setHardwareAddress(const QString& hardwareAddress) { _hardwareAddress = hardwareAddress; } const QString& getHardwareAddress() { return _hardwareAddress; } - + + void setMachineFingerprint(const QUuid& machineFingerprint) { _machineFingerprint = machineFingerprint; } + const QUuid& getMachineFingerprint() { return _machineFingerprint; } + void addOverrideForKey(const QString& key, const QString& value, const QString& overrideValue); void removeOverrideForKey(const QString& key, const QString& value); @@ -85,6 +88,7 @@ private: NodeSet _nodeInterestSet; QString _nodeVersion; QString _hardwareAddress; + QUuid _machineFingerprint; QString _placeName; diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index 21214ed5f6..c49e591e4c 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -444,6 +444,9 @@ void DomainServerSettingsManager::packPermissions() { // save settings for MAC addresses packPermissionsForMap("permissions", _macPermissions, MAC_PERMISSIONS_KEYPATH); + // save settings for Machine Fingerprint + packPermissionsForMap("permissions", _machineFingerprintPermissions, MACHINE_FINGERPRINT_PERMISSIONS_KEYPATH); + // save settings for groups packPermissionsForMap("permissions", _groupPermissions, GROUP_PERMISSIONS_KEYPATH); @@ -522,6 +525,18 @@ void DomainServerSettingsManager::unpackPermissions() { } }); + needPack |= unpackPermissionsForKeypath(MACHINE_FINGERPRINT_PERMISSIONS_KEYPATH, &_machineFingerprintPermissions, + [&](NodePermissionsPointer perms){ + // make sure that this permission row has valid machine fingerprint + if (QUuid(perms->getKey().first) == QUuid()) { + _machineFingerprintPermissions.remove(perms->getKey()); + + // we removed a row, so we'll need a re-pack + needPack = true; + } + + }); + needPack |= unpackPermissionsForKeypath(GROUP_PERMISSIONS_KEYPATH, &_groupPermissions, [&](NodePermissionsPointer perms){ @@ -575,7 +590,9 @@ void DomainServerSettingsManager::unpackPermissions() { QList> permissionsSets; permissionsSets << _standardAgentPermissions.get() << _agentPermissions.get() << _groupPermissions.get() << _groupForbiddens.get() - << _ipPermissions.get() << _macPermissions.get(); + << _ipPermissions.get() << _macPermissions.get() + << _machineFingerprintPermissions.get(); + foreach (auto permissionSet, permissionsSets) { QHashIterator i(permissionSet); while (i.hasNext()) { @@ -707,9 +724,10 @@ void DomainServerSettingsManager::processNodeKickRequestPacket(QSharedPointerclear(NodePermissions::Permission::canConnectToDomain); } - // potentially remove connect permissions for the MAC address + // potentially remove connect permissions for the MAC address and machine fingerprint DomainServerNodeData* nodeData = reinterpret_cast(matchingNode->getLinkedData()); if (nodeData) { + // mac address first NodePermissionsKey macAddressKey(nodeData->getHardwareAddress(), 0); bool hadMACPermissions = hasPermissionsForMAC(nodeData->getHardwareAddress()); @@ -721,6 +739,18 @@ void DomainServerSettingsManager::processNodeKickRequestPacket(QSharedPointerclear(NodePermissions::Permission::canConnectToDomain); } + + // now for machine fingerprint + NodePermissionsKey machineFingerprintKey(nodeData->getMachineFingerprint().toString(), 0); + + bool hadFingerprintPermissions = hasPermissionsForMachineFingerprint(nodeData->getMachineFingerprint()); + + auto fingerprintPermissions = _machineFingerprintPermissions[machineFingerprintKey]; + + if (!hadFingerprintPermissions || fingerprintPermissions->can(NodePermissions::Permission::canConnectToDomain)) { + newPermissions = true; + fingerprintPermissions->clear(NodePermissions::Permission::canConnectToDomain); + } } } @@ -795,6 +825,16 @@ NodePermissions DomainServerSettingsManager::getPermissionsForMAC(const QString& return nullPermissions; } +NodePermissions DomainServerSettingsManager::getPermissionsForMachineFingerprint(const QUuid& machineFingerprint) const { + NodePermissionsKey fingerprintKey = NodePermissionsKey(machineFingerprint.toString(), 0); + if (_machineFingerprintPermissions.contains(fingerprintKey)) { + return *(_machineFingerprintPermissions[fingerprintKey].get()); + } + NodePermissions nullPermissions; + nullPermissions.setAll(false); + return nullPermissions; +} + NodePermissions DomainServerSettingsManager::getPermissionsForGroup(const QString& groupName, QUuid rankID) const { NodePermissionsKey groupRankKey = NodePermissionsKey(groupName, rankID); if (_groupPermissions.contains(groupRankKey)) { diff --git a/domain-server/src/DomainServerSettingsManager.h b/domain-server/src/DomainServerSettingsManager.h index fcc3e9d91d..ee62b213e6 100644 --- a/domain-server/src/DomainServerSettingsManager.h +++ b/domain-server/src/DomainServerSettingsManager.h @@ -29,6 +29,7 @@ const QString AGENT_STANDARD_PERMISSIONS_KEYPATH = "security.standard_permission const QString AGENT_PERMISSIONS_KEYPATH = "security.permissions"; const QString IP_PERMISSIONS_KEYPATH = "security.ip_permissions"; const QString MAC_PERMISSIONS_KEYPATH = "security.mac_permissions"; +const QString MACHINE_FINGERPRINT_PERMISSIONS_KEYPATH = "security.machine_fingerprint_permissions"; const QString GROUP_PERMISSIONS_KEYPATH = "security.group_permissions"; const QString GROUP_FORBIDDENS_KEYPATH = "security.group_forbiddens"; @@ -67,6 +68,10 @@ public: bool hasPermissionsForMAC(const QString& macAddress) const { return _macPermissions.contains(macAddress, 0); } NodePermissions getPermissionsForMAC(const QString& macAddress) const; + // these give access to permissions for specific machine fingerprints from the domain-server settings page + bool hasPermissionsForMachineFingerprint(const QUuid& machineFingerprint) { return _machineFingerprintPermissions.contains(machineFingerprint.toString(), 0); } + NodePermissions getPermissionsForMachineFingerprint(const QUuid& machineFingerprint) const; + // these give access to permissions for specific groups from the domain-server settings page bool havePermissionsForGroup(const QString& groupName, QUuid rankID) const { return _groupPermissions.contains(groupName, rankID); @@ -148,6 +153,7 @@ private: NodePermissionsMap _ipPermissions; // permissions granted by node IP address NodePermissionsMap _macPermissions; // permissions granted by node MAC address + NodePermissionsMap _machineFingerprintPermissions; // permissions granted by Machine Fingerprint NodePermissionsMap _groupPermissions; // permissions granted by membership to specific groups NodePermissionsMap _groupForbiddens; // permissions denied due to membership in a specific group diff --git a/domain-server/src/NodeConnectionData.cpp b/domain-server/src/NodeConnectionData.cpp index 93d6802d84..0a3782d79b 100644 --- a/domain-server/src/NodeConnectionData.cpp +++ b/domain-server/src/NodeConnectionData.cpp @@ -32,6 +32,9 @@ NodeConnectionData NodeConnectionData::fromDataStream(QDataStream& dataStream, c // read the hardware address sent by the client dataStream >> newHeader.hardwareAddress; + + // now the machine fingerprint + dataStream >> newHeader.machineFingerprint; } dataStream >> newHeader.nodeType diff --git a/domain-server/src/NodeConnectionData.h b/domain-server/src/NodeConnectionData.h index bcbbdf0a40..dd9ca6b650 100644 --- a/domain-server/src/NodeConnectionData.h +++ b/domain-server/src/NodeConnectionData.h @@ -29,6 +29,7 @@ public: QList interestList; QString placeName; QString hardwareAddress; + QUuid machineFingerprint; QByteArray protocolVersion; }; diff --git a/libraries/networking/src/FingerprintUtils.cpp b/libraries/networking/src/FingerprintUtils.cpp index 42a617e93d..cabd352999 100644 --- a/libraries/networking/src/FingerprintUtils.cpp +++ b/libraries/networking/src/FingerprintUtils.cpp @@ -45,6 +45,13 @@ QString FingerprintUtils::getMachineFingerprintString() { IWbemLocator *pLoc = NULL; // initialize com + hres = CoInitializeEx(0, COINIT_MULTITHREADED); + if (FAILED(hres)) { + qDebug() << "Failed to initialize COM library!"; + return uuidString; + } + + // initialize WbemLocator hres = CoCreateInstance( CLSID_WbemLocator, 0, diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index c44681ac79..4686f49f16 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -27,6 +27,7 @@ #include "AddressManager.h" #include "Assignment.h" #include "HifiSockAddr.h" +#include "FingerprintUtils.h" #include "NetworkLogging.h" #include "udt/PacketHeaders.h" @@ -369,6 +370,10 @@ void NodeList::sendDomainServerCheckIn() { } packetStream << hardwareAddress; + + // add in machine fingerprint + QUuid machineFingerprint = FingerprintUtils::getMachineFingerprint(); + packetStream << machineFingerprint; } // pack our data to send to the domain-server including diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 34a70f8da6..35ad7fa4de 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -67,7 +67,7 @@ PacketVersion versionForPacketType(PacketType packetType) { return static_cast(DomainConnectionDeniedVersion::IncludesExtraInfo); case PacketType::DomainConnectRequest: - return static_cast(DomainConnectRequestVersion::HasMACAddress); + return static_cast(DomainConnectRequestVersion::HasMachineFingerprint); case PacketType::DomainServerAddedNode: return static_cast(DomainServerAddedNodeVersion::PermissionsGrid); diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index dbeb1e63b0..fb50431355 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -210,7 +210,8 @@ enum class DomainConnectRequestVersion : PacketVersion { NoHostname = 17, HasHostname, HasProtocolVersions, - HasMACAddress + HasMACAddress, + HasMachineFingerprint }; enum class DomainConnectionDeniedVersion : PacketVersion {