From 16fba4a28f119f87bbdad3f1e07b3df5b18953d2 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 8 Apr 2015 16:56:22 -0700 Subject: QSysInfo: add a function that returns a somewhat permanent unique ID We can use the D-Bus / systemd machine-id file (which is a UUID without the dashes) on systems with D-Bus. On Windows, there's a value in the registry that is filled when Windows is installed, like on Linux. For BSD systems, the kernel has a UUID we can use too, so extract that. Task-number: QTBUG-63425 Change-Id: I27eaacb532114dd188c4ffff13d32f2e3c1d74bb Reviewed-by: Edward Welbourne --- src/corelib/global/qglobal.cpp | 90 +++++++++++++++++++++++++++++++++++++++++- src/corelib/global/qsysinfo.h | 1 + 2 files changed, 89 insertions(+), 2 deletions(-) (limited to 'src/corelib/global') diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index 6ab45e1487..62d4624878 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. -** Copyright (C) 2016 Intel Corporation. +** Copyright (C) 2017 Intel Corporation. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -73,6 +73,10 @@ #include #endif // Q_OS_WINRT +#ifdef Q_OS_WIN +# include +#endif + #if defined(Q_OS_VXWORKS) && defined(_WRS_KERNEL) # include #endif @@ -2818,10 +2822,11 @@ QString QSysInfo::prettyProductName() This function returns the same as QHostInfo::localHostName(). - \sa QHostInfo::localDomainName + \sa QHostInfo::localDomainName, machineUniqueId() */ QString QSysInfo::machineHostName() { + // the hostname can change, so we can't cache it #if defined(Q_OS_LINUX) // gethostname(3) on Linux just calls uname(2), so do it ourselves // and avoid a memcpy @@ -2844,6 +2849,87 @@ QString QSysInfo::machineHostName() } #endif // QT_BOOTSTRAPPED +enum { + UuidStringLen = sizeof("00000000-0000-0000-0000-000000000000") - 1 +}; + +/*! + \since 5.10 + + Returns a unique ID for this machine, if one can be determined. If no + unique ID could be determined, this function returns an empty byte array. + Unlike machineHostName(), the value returned by this function is likely + globally unique. + + A unique ID is useful in network operations to identify this machine for an + extended period of time, when the IP address could change or if this + machine could have more than one IP address. For example, the ID could be + used when communicating with a server or when storing device-specific data + in shared network storage. + + Note that on some systems, this value will persist across reboots and on + some it will not. Applications should not blindly depend on this fact + without verifying the OS capabilities. In particular, on Linux systems, + this ID is usually permanent and it matches the D-Bus machine ID, except + for nodes without their own storage (replicated nodes). + + \sa machineHostName() +*/ +QByteArray QSysInfo::machineUniqueId() +{ + // the machine unique ID cannot change + static const QByteArray cache = []() { +#ifdef Q_OS_BSD4 + char uuid[UuidStringLen]; + size_t uuidlen = sizeof(uuid); +# ifdef KERN_HOSTUUID + int name[] = { CTL_KERN, KERN_HOSTUUID }; + if (sysctl(name, sizeof name / sizeof name[0], &uuid, &uuidlen, nullptr, 0) == 0 + && uuidlen == sizeof(uuid)) + return QByteArray(uuid, uuidlen); + +# else + // Darwin: no fixed value, we need to search by name + if (sysctlbyname("kern.uuid", uuid, &uuidlen, nullptr, 0) == 0 && uuidlen == sizeof(uuid)) + return QByteArray(uuid, uuidlen); +# endif +#elif defined(Q_OS_UNIX) + // the modern name on Linux is /etc/machine-id, but that path is + // unlikely to exist on non-Linux (non-systemd) systems. The old + // path is more than enough. + static const char fullfilename[] = "/usr/local/var/lib/dbus/machine-id"; + const char *firstfilename = fullfilename + sizeof("/usr/local") - 1; + int fd = qt_safe_open(firstfilename, O_RDONLY); + if (fd == -1 && errno == ENOENT) + fd = qt_safe_open(fullfilename, O_RDONLY); + + if (fd != -1) { + char buffer[32]; // 128 bits, hex-encoded + qint64 len = qt_safe_read(fd, buffer, sizeof(buffer)); + qt_safe_close(fd); + + if (len != -1) + return QByteArray(buffer, len); + } +#elif defined(Q_OS_WIN) && !defined(Q_OS_WINRT) + // Let's poke at the registry + HKEY key = NULL; + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Cryptography", 0, KEY_READ, &key) + == ERROR_SUCCESS) { + wchar_t buffer[UuidStringLen + 1]; + DWORD size = sizeof(buffer); + bool ok = (RegQueryValueEx(key, L"MachineGuid", NULL, NULL, (LPBYTE)buffer, &size) == + ERROR_SUCCESS); + RegCloseKey(key); + if (ok) + return QStringView(buffer, (size - 1) / 2).toLatin1(); + } +#endif + return QByteArray(); + }(); + return cache; +} + /*! \macro void Q_ASSERT(bool test) \relates diff --git a/src/corelib/global/qsysinfo.h b/src/corelib/global/qsysinfo.h index 6b73a17dc5..1415dc8cd5 100644 --- a/src/corelib/global/qsysinfo.h +++ b/src/corelib/global/qsysinfo.h @@ -240,6 +240,7 @@ QT_WARNING_POP static QString prettyProductName(); static QString machineHostName(); + static QByteArray machineUniqueId(); }; #undef QT_SYSINFO_DEPRECATED_X -- cgit v1.2.3