32

Mac OS X development is a fairly new animal for me, and I'm in the process of porting over some software. For software licensing and registration I need to be able to generate some kind of hardware ID. It doesn't have to be anything fancy; Ethernet MAC address, hard drive serial, CPU serial, something like that.

I've got it covered on Windows, but I haven't a clue on Mac. Any idea of what I need to do, or where I can go for information on this would be great!

Edit:

For anybody else that is interested in this, this is the code I ended up using with Qt's QProcess class:

QProcess proc;

QStringList args;
args << "-c" << "ioreg -rd1 -c IOPlatformExpertDevice |  awk '/IOPlatformUUID/ { print $3; }'";
proc.start( "/bin/bash", args );
proc.waitForFinished();

QString uID = proc.readAll();

Note: I'm using C++.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Gerald
  • 23,011
  • 10
  • 73
  • 102

9 Answers9

42

For C/C++:

#include <IOKit/IOKitLib.h>

void get_platform_uuid(char * buf, int bufSize) {
    io_registry_entry_t ioRegistryRoot = IORegistryEntryFromPath(kIOMasterPortDefault, "IOService:/");
    CFStringRef uuidCf = (CFStringRef) IORegistryEntryCreateCFProperty(ioRegistryRoot, CFSTR(kIOPlatformUUIDKey), kCFAllocatorDefault, 0);
    IOObjectRelease(ioRegistryRoot);
    CFStringGetCString(uuidCf, buf, bufSize, kCFStringEncodingMacRoman);
    CFRelease(uuidCf);    
}
yairchu
  • 23,680
  • 7
  • 69
  • 109
  • 1
    This worked for me with XCode 5.1 and Mac OS X 10.8.5 – Cory Trese May 22 '14 at 05:51
  • can this function return the same UUID even mac version upgraded in future? . (let's assume this function will work in future mac version now ) – Ben Xu Sep 02 '16 at 08:49
  • 1
    Would be an interesting answer but you did not specify the needed #includes ! Can you edit it to add them please ? – elena May 27 '22 at 12:52
  • @Elena Sure thing. Added the include, but do note that in my specific codebase this hasn't been used since 2018 so I can't assure whether this still work – yairchu May 28 '22 at 19:02
19

Try this Terminal command:

ioreg -rd1 -c IOPlatformExpertDevice | awk '/IOPlatformUUID/ { split($0, line, "\""); printf("%s\n", line[4]); }'

From here

Here is that command wrapped in Cocoa (which could probably be made a bit cleaner):

NSArray * args = [NSArray arrayWithObjects:@"-rd1", @"-c", @"IOPlatformExpertDevice", @"|", @"grep", @"model", nil];
NSTask * task = [NSTask new];
[task setLaunchPath:@"/usr/sbin/ioreg"];
[task setArguments:args];

NSPipe * pipe = [NSPipe new];
[task setStandardOutput:pipe];
[task launch];

NSArray * args2 = [NSArray arrayWithObjects:@"/IOPlatformUUID/ { split($0, line, \"\\\"\"); printf(\"%s\\n\", line[4]); }", nil];
NSTask * task2 = [NSTask new];
[task2 setLaunchPath:@"/usr/bin/awk"];
[task2 setArguments:args2];

NSPipe * pipe2 = [NSPipe new];
[task2 setStandardInput:pipe];
[task2 setStandardOutput:pipe2];
NSFileHandle * fileHandle2 = [pipe2 fileHandleForReading];
[task2 launch];

NSData * data = [fileHandle2 readDataToEndOfFile];
NSString * uuid = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
Community
  • 1
  • 1
xyz
  • 27,223
  • 29
  • 105
  • 125
  • Thanks, this seems to be the way that works the best. The System Profiler output seems to vary on different systems so makes me fear a flood of support calls not being able to register the software. – Gerald Jun 03 '09 at 23:01
  • This technique is easy to crack, though — just replace `/usr/sbin/ioreg` with a script that returns a known-good UUID (instead of a machine-specific UUID). Directly calling into the system libraries (@yairchu's answer, for example), will make cracking a little less trivial. – smokris Jun 16 '13 at 15:43
  • @smokris otherwise is this equivalent to IORegistryEntryFromPath? – tofutim Apr 23 '14 at 20:36
12

Why not try gethostuuid()? Here's the documentation from the Mac OS X System Calls Manual:

NAME:

 gethostuuid -- return a unique identifier for the current machine

SYNOPSIS:

 #include <unistd.h>

 int gethostuuid(uuid_t id, const struct timespec *wait);

DESCRIPTION:

The gethostuuid() function returns a 16-byte uuid_t specified by id, that uniquely identifies the current machine. Be aware that the hardware identifiers that gethostuuid() uses to generate the UUID can themselves be modified.

The wait argument is a pointer to a struct timespec that specifies the maximum time to wait for the result. Setting the tv_sec and tv_nsec fields to zero means to wait indefinitely until it completes.

RETURN VALUES:

The gethostuuid() function returns zero on success or -1 on error.

ERRORS

The gethostuuid() functions fails if:

 [EFAULT]           wait points to memory that is not a valid part of the
                    process address space.

 [EWOULDBLOCK]      The wait timeout expired before the UUID could be
                    obtained.
Community
  • 1
  • 1
zhanglin
  • 166
  • 1
  • 4
9

This would be easier to answer if you told us what language you were using. The information is obtainable without any shell commands through the SystemConfiguration framework, and also through IOKit if you want to get your hands really dirty.

- (NSString*) getMACAddress: (BOOL)stripColons {
    NSMutableString         *macAddress         = nil;
    NSArray                 *allInterfaces      = (NSArray*)SCNetworkInterfaceCopyAll();
    NSEnumerator            *interfaceWalker    = [allInterfaces objectEnumerator];
    SCNetworkInterfaceRef   curInterface        = nil;

    while ( curInterface = (SCNetworkInterfaceRef)[interfaceWalker nextObject] ) {
        if ( [(NSString*)SCNetworkInterfaceGetBSDName(curInterface) isEqualToString:@"en0"] ) {
            macAddress = [[(NSString*)SCNetworkInterfaceGetHardwareAddressString(curInterface) mutableCopy] autorelease];

            if ( stripColons == YES ) {
                [macAddress replaceOccurrencesOfString: @":" withString: @"" options: NSLiteralSearch range: NSMakeRange(0, [macAddress length])];
            }

            break;
        }
    }

    return [[macAddress copy] autorelease];
}
Shebuka
  • 3,148
  • 1
  • 26
  • 43
Azeem.Butt
  • 5,855
  • 1
  • 26
  • 22
  • You're right I should have specified the language. I updated the question and tags. I am using C++ and the Qt framework for cross-platform development. – Gerald Oct 17 '09 at 18:19
  • Then SCNetworkInterfaceGetHardwareAddressString will get it for you without forking another process to run a shell script. – Azeem.Butt Oct 17 '09 at 18:29
  • macAddress assignment on line 12 requires an autorelease – Colin Jul 30 '13 at 21:04
7
/*
g++ mac_uuid.cpp -framework CoreFoundation -lIOKit
*/


#include <iostream>
#include <IOKit/IOKitLib.h>

using namespace std;

void get_platform_uuid(char * buf, int bufSize)
{
   io_registry_entry_t ioRegistryRoot = IORegistryEntryFromPath(kIOMasterPortDefault, "IOService:/");
   CFStringRef uuidCf = (CFStringRef) IORegistryEntryCreateCFProperty(ioRegistryRoot, CFSTR(kIOPlatformUUIDKey), kCFAllocatorDefault, 0);
   IOObjectRelease(ioRegistryRoot);
   CFStringGetCString(uuidCf, buf, bufSize, kCFStringEncodingMacRoman);
   CFRelease(uuidCf);
}

int main()
{
   char buf[512] = "";
   get_platform_uuid(buf, sizeof(buf));
   cout << buf << endl;
}
Nitinkumar Ambekar
  • 969
  • 20
  • 39
  • 1
    `$ c++ mac_uuid.cpp -framework CoreFoundation -lIOKit` leads to: `ld: library not found for -lIOKit clang: error: linker command failed with exit code 1 (use -v to see invocation)` – malat Feb 26 '15 at 15:02
  • 1
    `g++ mac_uuid.cpp -o mac_uuid -framework CoreFoundation -framework IOKit` works for me – NexD. Jul 30 '15 at 17:24
  • Thank you for your answer. Btw do you know if it is possible to get the uuid as unformatted binary (the raw 16 bytes) ? – elena May 27 '22 at 13:47
1

Running:

system_profiler | grep 'Serial Number (system)'

in a terminal returns what it likely a unique id. That works on my 10.5 box, I'm not sure what the correct string will be in other versions of OS X.

kbyrd
  • 3,321
  • 27
  • 41
  • 1
    There are actually some Macs that have shipped without a serial number, so you shouldn't do anything that relies 100% on having a unique serial number available. – smorgan Jun 03 '09 at 19:32
  • 1
    `system_profiler` will also sometimes take a while. If you've got a disc in the DVD drive it'll spin up, for example. – Dietrich Epp Jun 04 '09 at 00:06
  • 3
    I've seen some of that Mac's without Serial Number (and had problems with my software licensing), but UUID is always there. You should sick with UUID. – TCB13 Feb 15 '12 at 22:28
  • If you specify the correct datatype with `system_profiler`, it will speed it up significantly by only returning the information associated with that type. In this case, it would be `system_profiler SPHardwareDataType` – dgross Oct 28 '15 at 14:34
1

As some people above have hinted, you can use a Terminal command to get a hardware ID.

I assume you want to do this in code however so I would take a look at the NSTask class in Cocoa. It basically lets you run terminal commands inside your application.

This code is an example of how to use NSTask in Cocoa. It sets up the environment to execute the "killall" command. It passes it the arguement "Finder".

It's the equivilent of running "killall Finder" on the command line, which will kill the Finder obviously.

NSTask *aTask = [[NSTask alloc] init];
NSMutableArray *args = [NSMutableArray array];

[aTask setLaunchPath: @"/usr/bin/killall"];
[args addObject:[@"/Applications/Finder" lastPathComponent]];
[aTask setArguments:args];
[aTask launch];

[aTask release];
Brock Woolf
  • 46,656
  • 50
  • 121
  • 144
  • 2
    What's with the cast to `NSString*`, and why call `lastPathComponent`? That line is equivalent to `[args addObject:@"Finder"]`. – dreamlax Oct 11 '09 at 23:01
0

The following is equivalent and far simpler than the ioreg command.

system_profiler SPHardwareDataType | awk '/UUID/ { print $3 }

fny
  • 31,255
  • 16
  • 96
  • 127
0

System Profiler (in Applications - Utilities) contains most of this kind of info. It has your serial number and your mac address (no relation to Mac. All computers have a mac address which is pretty much unique to every network card).

Singletoned
  • 5,089
  • 3
  • 30
  • 32