views:

742

answers:

6

Hi, I'd like to get an id unique to a computer with Python on Windows and Linux. It could be the CPU ID, the motherboard serial, ... or anything else.

I looked at several modules (pycpuid, psi, ...) without luck.

Any idea on how to do that ?

Thanks in advance.

+1  A: 

UUID -Universally Unique Identifier

Python uuid module

[RFC 4122] A Universally Unique IDentifier (UUID) URN Namespace

TheMachineCharmer
This module provides uniqueness across space and time, like GUIDs. I don't think this is what he wants. He wants a way to uniquely identify a computer (for licensing purposes for instance) but consistent over time...
David
This is exactly what he wants, however the python module does not do what he wants - he should read the UUID from the BIOS, on linux `dmidecode|grep UUID` can do the trick
Kimvais
+3  A: 

How about using the MAC address as unique id?

The discussion here http://stackoverflow.com/questions/1750803/obtain-mac-address-from-devices-using-python shows how to obtain the MAC address

Findekano
That's what I wanted to do at first but after several test on several computers, I found that sometimes there are several mac address on a single computer.For example, one of my *test* computer had a VPN server and a network card. And I want to be sure to use the network card MAC address, not the VPN (or other stuff)
darkpotpot
Since you only want to get an unique ID for the computer. Let's assume the hardware/software configuration of the computer is not changed frequently. In this way you can get MAC address for ALL network adapters, and hash them together to create an id. Does this sound workable for your requirements?
Findekano
Yeah, it should work. I think I'll do that until I find a better way.
darkpotpot
A: 

I don't think there is a reliable, cross platform, way to do this. I know of one network device that changes its MAC address as a form of hardware error reporting, and there are a million other ways this could fail.

The only reliable solution is for your application to assign a unique key to each machine. Yes it can be spoofed, but you don't have to worry about it completely breaking. If you are worried about spoofing you can apply some sort of heuristic (like a change in mac address) to try and determine if the key has been moved.

UPDATE: You can use bacterial fingerprinting.

mikerobi
+1  A: 

There seems to be no direct "python" way of doing this. On modern PC hardware, there usually is an UUID stored in the BIOS - on Linux there is a command line utility dmidecode that can read this; example from my desktop:

System Information
        Manufacturer: Dell Inc.
        Product Name: OptiPlex 755                 
        Version: Not Specified
        Serial Number: 5Y8YF3J
        UUID: 44454C4C-5900-1038-8059-B5C04F46334A
        Wake-up Type: Power Switch
        SKU Number: Not Specified
        Family: Not Specified

The problem with MAC addresses is that usually you can easily change them programmatically (at least if you run the OS in a VM)

On Windows, you can use this C API

Kimvais
Note that you need root privileges to read the DMI data on Linux. Also, the same number can be found in /sys/class/dmi/id/product_uuid .
Juliano
The problem is I don't have (and don't want to use) root privileges in my application.
darkpotpot
+1  A: 

for Windows you need DmiDecode for Windows (link) :

subprocess.Popen('dmidecode.exe -s system-uuid'.split())

for Linux (non root):

subprocess.Popen('hal-get-property --udi /org/freedesktop/Hal/devices/computer --key system.hardware.uuid'.split())
nazca
A: 

Or if you don't want to use subprocess, (It's slow) use ctypes. This is for Linux non root.

import ctypes
from ctypes.util import find_library
from ctypes import Structure

class DBusError(Structure):
    _fields_ = [("name", ctypes.c_char_p),
                ("message", ctypes.c_char_p),
                ("dummy1", ctypes.c_int),
                ("dummy2", ctypes.c_int),
                ("dummy3", ctypes.c_int),
                ("dummy4", ctypes.c_int),
                ("dummy5", ctypes.c_int),
                ("padding1", ctypes.c_void_p),]


class HardwareUuid(object):

    def __init__(self, dbus_error=DBusError):
        self._hal = ctypes.cdll.LoadLibrary(find_library('hal'))
        self._ctx = self._hal.libhal_ctx_new()
        self._dbus_error = dbus_error()
        self._hal.dbus_error_init(ctypes.byref(self._dbus_error))
        self._conn = self._hal.dbus_bus_get(ctypes.c_int(1),
                                            ctypes.byref(self._dbus_error))
        self._hal.libhal_ctx_set_dbus_connection(self._ctx, self._conn)
        self._uuid_ = None

    def __call__(self):
        return self._uuid

    @property
    def _uuid(self):
        if not self._uuid_:
            udi = ctypes.c_char_p("/org/freedesktop/Hal/devices/computer")
            key = ctypes.c_char_p("system.hardware.uuid")
            self._hal.libhal_device_get_property_string.restype = \
                                                            ctypes.c_char_p
            self._uuid_ = self._hal.libhal_device_get_property_string(
                                self._ctx, udi, key, self._dbus_error)
        return self._uuid_

You can use this like:

get_uuid = HardwareUuid()
print get_uuid()
Six