I want to identify my mac system uniquely via code. I find the Hardware UUID in my About this Mac.
So how to programmatically access the unique uuid from MAc OS X.
Kindly provide me if there are any alternative suggestion for my problem.
So, if you don't care about the new AppStore rules etc... here you go:
- (NSString *)getSystemUUID {
io_service_t platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault,IOServiceMatching("IOPlatformExpertDevice"));
if (!platformExpert)
return nil;
CFTypeRef serialNumberAsCFString = IORegistryEntryCreateCFProperty(platformExpert,CFSTR(kIOPlatformUUIDKey),kCFAllocatorDefault, 0);
IOObjectRelease(platformExpert);
if (!serialNumberAsCFString)
return nil;
return (__bridge NSString *)(serialNumberAsCFString);;
}
Please Note:
You need to add IOKit.framework to your project in order for this
to work.
This code is ARC compliant;
This code is safe and it will return a nil NSString if something goes wrong;
Apple does not guarantee that all future systems will have a software-readable serial number.
Developers should not make any assumptions about the
format of the serial number such as its length or what characters it
may contain.
From here: https://stackoverflow.com/a/2754563/610351
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);
}
You can replace the CFStringGetCString with a simple conversion to NSString*.
Related
I am working on an app for OSX Lion and onwards. The app has a root daemon process. I have created a system-wide keychain using "SecKeychainCreate" in /Library/Keychains which is accessible only by the daemon and wish to store generic keys in that keychain. Can anyone help me with retrieving generic keys from this keychain programmatically ? To add a key to the keychain, I used the "SecKeychainItemCreateFromContent" function as it accepts a SecKeychainRef parameter and passed kSecPublicKeyItemClass as the first parameter. Here is my code :
char *itemLabel = "Generic public key";
//Setting up the attribute vector (each attribute consists of {tag, length, pointer}):
SecKeychainAttribute attrs[] = {kSecLabelItemAttr, strlen(itemLabel), itemLabel};
SecKeychainAttributeList attributes = { sizeof(attrs)/sizeof(attrs[0]), attrs };
//pubKey is the key (NSData) that I want to store, while tempKeyChain is my keychain
status = SecKeychainItemCreateFromContent(kSecPublicKeyItemClass, &attributes, [pubKey length],(__bridge const void *)pubKey, tempKeyChain, NULL, NULL);
if (status != noErr)
{
NSString *error = (__bridge NSString *)SecCopyErrorMessageString(status, NULL);
NSLog(#"Error in adding item to keychain : %#",error);
return errSecUnimplemented;
}
Now, to retrieve the key, there are two options - "SecKeychainSearchCreateFromAttributes" which is deprecated in OS X 10.7 and so is useless, or "SecItemCopyMatching". The former accepts a SecKeychainRef parameter while the latter does not. So, I manually set my search list using "SecKeychainSetSearchList" to include tempKeyChain, and then used "SecItemCopyMatching". Here is the code for that :
OSStatus status;
SecKeychainRef defaultKeychain = nil;
SecKeychainCopyDefault(&defaultKeychain);
NSArray *searchList = [NSArray arrayWithObjects:(__bridge id)defaultKeychain,tempKeyChain, nil];
OSStatus result = SecKeychainSetSearchList((__bridge CFArrayRef)searchList);
if (result != noErr)
{
NSString *error = (__bridge NSString *)SecCopyErrorMessageString(result, NULL);
NSLog(#"Error : %#",error);
return errSecUnimplemented;
}
NSMutableDictionary *query = [[NSMutableDictionary alloc] init];
[query setObject:kSecClassKey forKey:(id)kSecClass];
[query setObject:#"Generic public key" forKey:kSecAttrLabel];
CFTypeRef items;
status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &items);
return status;
This code always gives a status of "Item not found", even though my keychain is added to the search list alongwith the default search list.
I would greatly appreciate any pointers on why this might be happening, or any other better ways to store and retrieve keys from a custom keychain.
P.S - I do not want to store passwords, only keys (public and private). Could anyone guide me to some code or present a small code snippet explaining the same ? Thanks.
I honestly did a) search using key words and b) read the 'questions with similar titles' before asking this.
Also I tried to make this question more concise, but I had a hard time doing that in this case. If you feel the question is too wordy, I get it. Just don't try to answer.
I'm trying to write very simple objective-C programs that mirror the basic assignments in my introductory java class. I worked through an objective-c book over the summer and now I want to do lots of practice problems in objective-c, at the same time as I do java practice problems. I'm avoiding the objective-c GUI environment and just want to focus on working with the language for awhile. I still have a lot to learn about how to figure things out.
The program I'm duplicating from my java homework, is a standard type. I ask the user for number input and string input via the console. I was able to get numeric input from the console using an example I found here using scan f. (I will put the couple code lines below). But I'm unsure on how to get console input and store it in a string (NSString). I'm trying to learn to use the apple documentation and found a reference to a scan type command, but I cannot figure out how to USE the command. The one that seems likely is
scanCharactersFromSet:(NSCharacterSet )scanSet intoString:(NSString *)name;
Here's what I understand and works
int age = 0;
NSLog (#"How old are y'all?");
scanf("%d", &age);
NSLog (#"\n Wow, you are %d !", age);
But I don't understand how to pickup an NSString called 'name'. I THINK I'm supposed to make my 'name'a pointer, because the class is NSString.
(BTW I did try using scanf to pickup the string, but the compiler doesn't like me trying to use scanf in conjunction with name. It says that I shouldn't be using 'scanf' because it's expecting a different kind of data. I'm not sure where I found the data type 'i'. I was looking through my text for different ideas. I'm guessing that scanf is related to 'scanfloat' which clearly deals with numeric data, so this is not a big surprise)
I realize that 'scanf' isn't the right command (and I don't really get why I can't even find scanf in the apple documentation - maybe it's C?)
I'm guessing that scanCharactersFromSet might be the right thing to use, but I just don't understand how you figure out what goes where in the command. I guess I tend to learn by example, and I haven't found an example. I'd like to figure out how to learn properly by reading the documentation. But I'm not there yet.
NSString* name ;
scanf("%i", &name);
//scanCharactersFromSet:(NSCharacterSet *)scanSet intoString:(NSString **)name;
...
My book is oriented towards moving me into a gui environment, so it doesn't deal with input.
Thank you for any pointers you can give me.
Laurel
I would recommend ramping up on C. Objective-c is a thin layer over C and that knowledge will pay for itself over and over.
There's multiple ways in C to read:
http://www.ehow.com/how_2086237_read-string-c.html
For example:
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
char str[50] = {0}; // init all to 0
printf("Enter you Last name: ");
scanf("%s", str); // read and format into the str buffer
printf("Your name is %s\n", str); // print buffer
// you can create an NS foundation NSString object from the str buffer
NSString *lastName = [NSString stringWithUTF8String:str];
// %# calls description o object - in NSString case, prints the string
NSLog(#"lastName=%#", lastName);
[pool drain];
return 0;
NOTE: the simple scanf is succeptible to buffer overruns. There's multiple approaches around this. see:
How to prevent scanf causing a buffer overflow in C?
Here is what Objective C looks like:
NSString *FNgetInput() {
#autoreleasepool {
return [[[NSString alloc] initWithData:[[NSFileHandle fileHandleWithStandardInput] availableData] encoding:NSUTF8StringEncoding] stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]];
}
}
The way to get data from the standard input (or any other file handle) in cocoa is to use the NSFileHandle class. Check the docs for +fileHandleWithStandardInput
Here's how to get user input using Objective-C in 2020:
main.m
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
#autoreleasepool {
// insert code here...
NSLog(#"Hello, World!");
char str[50] = {0}; // init all to 0
printf("Enter you Last name: ");
scanf("%s", str); // read and format into the str buffer
printf("Your name is %s\n", str); // print buffer
// you can create an NS foundation NSString object from the str buffer
NSString *lastName = [NSString stringWithUTF8String:str];
// %# calls description o object - in NSString case, prints the string
NSLog(#"lastName=%#", lastName);
return 0;
}
return 0;
}
Compile and run:
$ clang -framework Foundation main.m -o app
I'm using a 3rd party library for an iOS project I work on, and I'm down to one warning left in the project, namely on this line of code
[NSNumber numberWithUnsignedLongLong:'oaut']
And the warning is
Multi-character character constant
I suck at C, so I don't know how to fix this, but I'm sure the fix is relatively easy. Help?
EDIT: More context.
#implementation MPOAuthCredentialConcreteStore (KeychainAdditions)
- (void)addToKeychainUsingName:(NSString *)inName andValue:(NSString *)inValue {
NSString *serverName = [self.baseURL host];
NSString *securityDomain = [self.authenticationURL host];
// NSString *itemID = [NSString stringWithFormat:#"%#.oauth.%#", [[NSBundle mainBundle] bundleIdentifier], inName];
NSDictionary *searchDictionary = nil;
NSDictionary *keychainItemAttributeDictionary = [NSDictionary dictionaryWithObjectsAndKeys: (id)kSecClassInternetPassword, kSecClass,
securityDomain, kSecAttrSecurityDomain,
serverName, kSecAttrServer,
inName, kSecAttrAccount,
kSecAttrAuthenticationTypeDefault, kSecAttrAuthenticationType,
[NSNumber numberWithUnsignedLongLong:"oaut"], kSecAttrType,
[inValue dataUsingEncoding:NSUTF8StringEncoding], kSecValueData,
nil];
if ([self findValueFromKeychainUsingName:inName returningItem:&searchDictionary]) {
NSMutableDictionary *updateDictionary = [keychainItemAttributeDictionary mutableCopy];
[updateDictionary removeObjectForKey:(id)kSecClass];
SecItemUpdate((CFDictionaryRef)keychainItemAttributeDictionary, (CFDictionaryRef)updateDictionary);
[updateDictionary release];
} else {
OSStatus success = SecItemAdd( (CFDictionaryRef)keychainItemAttributeDictionary, NULL);
if (success == errSecNotAvailable) {
[NSException raise:#"Keychain Not Available" format:#"Keychain Access Not Currently Available"];
} else if (success == errSecDuplicateItem) {
[NSException raise:#"Keychain duplicate item exception" format:#"Item already exists for %#", keychainItemAttributeDictionary];
}
}
}
EDIT 2: They were attempting to meet the requirements of this by creating that NSNumber:
#constant kSecAttrType Specifies a dictionary key whose value is the item's
type attribute. You use this key to set or get a value of type
CFNumberRef that represents the item's type. This number is the
unsigned integer representation of a four-character code (e.g.,
'aTyp').
In C and Obj-C the single-quote ' is used only for single-character constants. You need to use the double-quote: "
Like so:
[NSNumber numberWithUnsignedLongLong:"oaut"]
That covers the warning, but there's also a semantic issue here. Although a single character constant, such as 'o', can be treated as an integer (and can be promoted to an unsigned long long), a "string" (char * or char []) cannot, which means you can't use "oaut" as an argument to numberWithUnsignedLongLong:
Update:
I guess the four-character code is supposed to be treated as an integer, i.e., the 8 bits of each char put in place as if they together were a 32-bit int:
char code[] = "oaut";
uint32_t code_as_int = code[0] | (code[1] << 8) | (code[2] << 16) | (code[3] << 24);
[NSNumber numberWithUnsignedLongLong:code_as_int]
although I'm not sure which endianness would be expected here, nor why this is calling for an unsigned long long, unless just to be certain there are enough bits.
Rudy's comment, now that I think of it, is correct -- multi-character constants are allowed by some compilers for exactly this purpose (it is "implementation-defined" behavior).
'oaut' (single quotes) is a character, so the compiler tries to interpret it as a multi-byte character but can't make any sense of it. That explains the error message.
I guess that if you gave a proper string, like #"oaut", you'd get another error message, since numberWithUnsignedLongLong: expects an unsigned long long, not a string or a character. Are you trying to pass a variable with the name "oaut"? If so, use
[NSNumber numberWithUnsignedLongLong: oaut];
If not, then please explain what "oaut" is.
Edit
'oaut' may actually be the original value. There are/were multi-character character constants in C. Using a (4 byte) char, used as int and promoted to unsigned long long would then be possible. This must be old code. It seems such code was accepted by CodeWarrior.
Assuming that really a multi-char char const was meant, 'oaut' looks like a "magic number" and this value was chosen because it is the beginning of "oauth". I guess it should either be value 0x6F617574 or 0x7475616F.
#Josh Caswell 's answer is partially right, the simplest and "official" solution is:
[NSNumber numberWithUnsignedInt:'oaut']
unsigned int's length is 32-bit in both 32-bit and 64-bit cpu, there's a practical example from Apple: https://developer.apple.com/library/ios/samplecode/CryptoExercise/Listings/Classes_SecKeyWrapper_m.html
I'm trying to determine the network segment my Macbook is in, because I then want to scan this segment for active hosts (basic IP scanner) by using the CFHost class. Therefore I need the IP and Netmask of my active interface. This is how I get the IP:
NSString *ipAddr = [[[NSHost currentHost] addresses] objectAtIndex:0];
But I have absolutely no idea how to get the Netmask, so I'm kind of stuck. Especially because I'm fairly new at Objective-C and because I also do not have extensive knowledge of plain C. I've looked at CFHost, CFNetwork, NSHost and various Google hits, but have found nothing useful, so far.
As a last resort I could do a system call of sorts, I suppose, or read it from a file (which one?), but I want to avoid that, if possible.
So, how do I get the matching netmask to the ip obtained through NSHost? Any suggestions would be greatly appreciated.
Thanks!
So, to wrap this up, I did finally get around to investigating the System Configuration API. As always, once you know how it's not that difficult.
#0xced - Thanks for pointing me in the right direction. I'd upvote your answer, but I do not have enough reputation to do so.
This is my solution, for anyone who is curious or in the same situation. It involves digging in the dynamic store. See this for infos on the API. You can look at the information the dynamic store holds by using the scutil command line utility (see x-man-page://8/scutil ).
Here are my steps. First, you need a session:
SCDynamicStoreRef storeRef = SCDynamicStoreCreate(NULL, (CFStringRef)#"FindCurrentInterfaceIpMac", NULL, NULL);
Then, I try to get the primary interface (en1, for example):
CFPropertyListRef global = SCDynamicStoreCopyValue (storeRef,CFSTR("State:/Network/Global/IPv4"));
NSString *primaryInterface = [(__bridge NSDictionary *)global valueForKey:#"PrimaryInterface"];
Last, I build a string containing the interface to be able to query the right key. It should look something like State:/Network/Interface/en1/IPv4, depending on the interface, of course. With that I am able to get an array with the ip and the netmask. On my Macbook these arrays hold only one ip and netmask, respectively. I suppose it is possible this could be different for other Macs, I will have to verify that. For my test I simply took the first (and only) element in the array, but some sort of checking for size would have to be implemented there.
NSString *interfaceState = [NSString stringWithFormat:#"State:/Network/Interface/%#/IPv4", primaryInterface];
CFPropertyListRef ipv4 = SCDynamicStoreCopyValue (storeRef, (CFStringRef)interfaceState);
CFRelease(storeRef);
NSString *ip = [(__bridge NSDictionary *)ipv4 valueForKey:#"Addresses"][0];
NSString *netmask = [(__bridge NSDictionary *)ipv4 valueForKey:#"SubnetMasks"][0];
CFRelease(ipv4);
This is just for testing, so it is a little rough around the edges. You will have to look for retain counts and the like. It was only written to get an idea of how it could be done.
Martin had given a nice answer.
And his code in a ARC version is here:
+ (NSDictionary *)primaryIPv4AddressInfoFromSystemConfiguration
{
SCDynamicStoreRef storeRef = SCDynamicStoreCreate(NULL, (CFStringRef)#"FindCurrentInterfaceIpMac", NULL, NULL);
if (!storeRef)
{
return nil;
}
NSDictionary *IPv4Dictionary = nil;
CFPropertyListRef global = SCDynamicStoreCopyValue(storeRef, CFSTR("State:/Network/Global/IPv4"));
id primaryInterface = [(NSDictionary *)CFBridgingRelease(global) valueForKey:#"PrimaryInterface"];
if (primaryInterface)
{
NSString *interfaceState = #"State:/Network/Interface/";
interfaceState = [[interfaceState stringByAppendingString:(NSString *)primaryInterface] stringByAppendingString:#"/IPv4"];
CFPropertyListRef IPv4PropertyList = SCDynamicStoreCopyValue(storeRef, (__bridge CFStringRef)interfaceState);
IPv4Dictionary = (NSDictionary *)CFBridgingRelease(IPv4PropertyList);
}
CFRelease(storeRef);
return IPv4Dictionary;
}
+ (NSDictionary *)primaryIPv6AddressInfoFromSystemConfiguration
{
SCDynamicStoreRef storeRef = SCDynamicStoreCreate(NULL, (CFStringRef)#"FindCurrentInterfaceIpMac", NULL, NULL);
if (!storeRef)
{
return nil;
}
NSDictionary *IPv6Dictionary = nil;
CFPropertyListRef global = SCDynamicStoreCopyValue(storeRef, CFSTR("State:/Network/Global/IPv6"));
id primaryInterface = [(NSDictionary *)CFBridgingRelease(global) valueForKey:#"PrimaryInterface"];
if (primaryInterface)
{
NSString *interfaceState = #"State:/Network/Interface/";
interfaceState = [[interfaceState stringByAppendingString:(NSString *)primaryInterface] stringByAppendingString:#"/IPv6"];
CFPropertyListRef IPv6PropertyList = SCDynamicStoreCopyValue(storeRef, (__bridge CFStringRef)interfaceState);
IPv6Dictionary = (NSDictionary *)CFBridgingRelease(IPv6PropertyList);
}
CFRelease(storeRef);
return IPv6Dictionary;
}
You will have to use the System Configuration API. See System Configuration Programming Guidelines and System Configuration Framework Reference
I am interfacing with a hardware device that streams data to my app over Wifi. The data is streaming in just fine. The data contains a character header (DATA:) that indicates a new record has begun. The issues is that the data I receive doesn't necessarily fall on the header boundary, so I have to capture the data until what I've captured contains the header. Then, everything that precedes the header goes into the previous record and everything that comes after it goes into a new record. I have this working, but wondered if anyone has done this before and has a good computer-sciencey way to solve the problem.
Here's what I do:
Convert the NSData of the current read to an NSString
Append the NSString to a placeholder string
Check placeholder string for the header (DATA:). If the header is not there, just wait for the next read.
If the header exists, append whatever precedes it to a previous record placeholder and hand that placeholder off to an array as a complete record that I can further parse into fields.
Take whatever shows up after the header and place it in the record placeholder so that it can be appended to in the next read. Repeat steps 3 - 5.
Let me know if you see any flaws with this or have a suggestion for a better way.
Seems there should be some design pattern for this, but I can't think of one.
Thanks.
UPDATE: Here is a little bit of code:
uint8_t buf[1024];
unsigned int len = 0;
len = [(NSInputStream *)stream read:buf maxLength:1024];
if(len) {
[data appendBytes:(const void *)buf length:len];
int bytesRead;
bytesRead += len;
} else {
NSLog(#"No data.");
}
How would this code be changed then to implement a finite state machine?
That seems pretty much how I'd do it. The only thing I might do differently is write an NSData category that does the linear search of DATA: for me, just to save the overhead of converting it to a string. It wouldn't be that hard to do, either. Something like:
#interface NSData (Search)
- (NSRange) rangeOfData:(NSData *)aData;
#end
#implementation NSData (Search)
- (NSRange) rangeOfData:(NSData *)aData {
const void * bytes = [self bytes];
NSUInteger length = [self length];
const void * searchBytes = [aData bytes];
NSUInteger searchLength = [aData length];
NSUInteger searchIndex = 0;
NSRange foundRange = {NSNotFound, searchLength};
for (NSUInteger index = 0; index < length; index++) {
if (bytes[index] == searchBytes[searchIndex]) {
//the current character matches
if (foundRange.location == NSNotFound) {
foundRange.location = index;
}
searchIndex++;
if (searchIndex >= searchLength) { return foundRange; }
} else {
searchIndex = 0;
foundRange.location = NSNotFound;
}
}
return foundRange;
}
#end
Then you can just use:
NSData * searchData = [#"DATA:" dataUsingEncoding:NSUTF8StringEncoding];
while(receivingData) {
if ([receivedData rangeOfData:searchData].location != NSNotFound) {
//WOOO!
}
}
(warning: typed in a browser)
This is a classic finite state machine problem. A lot of data protocols that are stream based can be described with a finite state machine.
Basically you have a state, and transition. Boost has a finite state machine library, but it could be overkill. You can implement it as a switch.
while(stream.hasData) {
char nextInput = stream.get();
switch(currentState) {
case D: {
if(nextInput == A)
currentState = A;
else
currentState = D; //die
} case A: {
//Same for A
}
}
}
Requested elaboration:
Basically look at the diagram below...it's a finite state machine. At any given time the machine is in exactly one state. Every time a character is input into the state machine a transition is taken, and the current state moves. (possibly back into the same state). So all you have to do is model your networked data as a finite state machine then implement that machine. There are libraries that lay it out for you, then all you have to do is implement exactly what happens on each transition. For you that you probably mean interpreting or saving the byte of data. The interpretation depends on what transition. The transition depends on the current state and the current input. Here is an example FSM.
alt text http://www.freeimagehosting.net/uploads/b1706f2a8d.png
Note that if the characters DATA: are entered the state moves to the last circle. Any other sequence will keep the state in one of first 5 states. (top row) You can also have splits. So the FSM can make decisions, so if you get a sequence like DATA2: then you can branch off of that machine into the data2: part and interpret differently in a totally different part of the machine.