diff --git a/libraries/networking/src/FingerprintUtils.cpp b/libraries/networking/src/FingerprintUtils.cpp index 216e0f28dd..83a4f19703 100644 --- a/libraries/networking/src/FingerprintUtils.cpp +++ b/libraries/networking/src/FingerprintUtils.cpp @@ -17,6 +17,9 @@ #include #include #include +#include +#include +#include #ifdef Q_OS_WIN #include @@ -36,8 +39,80 @@ QUuid FingerprintUtils::_machineFingerprint { QUuid() }; 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. + // As per the documentation: + // https://man7.org/linux/man-pages/man5/machine-id.5.html + // + // we use the machine id as a base, but add an application-specific key to it. + // If machine-id isn't available, we try hardware networking devices instead. + + QCryptographicHash hash(QCryptographicHash::Keccak_256); + + QFile machineIdFile("/etc/machine-id"); + if (!machineIdFile.open(QIODevice::ReadOnly | QIODevice::Text)) { + // No machine ID, probably no systemd. + qCWarning(networking) << "Failed to open /etc/machine-id"; + + QDir netDevicesDir("/sys/class/net"); + QFileInfoList netDevicesInfo = netDevicesDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name); + + if (netDevicesInfo.empty()) { + // Let getMachineFingerprint handle this contingency + qCWarning(networking) << "Failed to find any hardware networking devices"; + return ""; + } + + for(auto& fileInfo : netDevicesInfo) { + + if (fileInfo.isSymLink() && fileInfo.symLinkTarget().contains("virtual")) { + // symlink points to something like: + // ../../devices/virtual/net/lo + // these are not real devices and have random IDs, so we + // don't care about them. + continue; + } + + QFile addressFile(fileInfo.filePath() + "/address"); + if (addressFile.open(QIODevice::ReadOnly | QIODevice::Text)) { + qCDebug(networking) << "Adding contents of " << addressFile.fileName(); + hash.addData(addressFile.readAll()); + } else { + qCWarning(networking) << "Failed to read " << addressFile.fileName(); + } + } + } else { + QByteArray data = machineIdFile.readAll(); + hash.addData(data); + } + + // Makes this hash unique to us + hash.addData("Vircadia"); + + // Stretching + for (int i=0; i < 65535; i++) { + hash.addData(hash.result()); + } + + QByteArray result = hash.result(); + result.resize(128 / 8); // GUIDs are 128 bit numbers + + // Set UUID version to 4, ensuring it's a valid UUID + result[6] = (result[6] & 0x0F) | 0x40; + + // Of course, Qt couldn't be nice and just parse something like: + // 1b1b9d6d45c2473bac13dc3011ff58d6 + // + // So we have to turn it into: + // {1b1b9d6d-45c2-473b-ac13-dc3011ff58d6} + + uuidString = result.toHex(); + uuidString.insert(20, '-'); + uuidString.insert(16, '-'); + uuidString.insert(12, '-'); + uuidString.insert(8, '-'); + uuidString.prepend("{"); + uuidString.append("}"); + + qCDebug(networking) << "Linux machine fingerprint:" << uuidString; #endif //Q_OS_LINUX #ifdef Q_OS_MAC