Retrieving stored passwords from keychain fails outside XCode - objective-c

I am storing generic passwords in the keychain following Apple's example code in the "Keychain Services Programming Guide".
Everything works fine as long as I am running the App in Debug mode from Xcode. However when I archive and export the app, it will still store passwords (visible in Keychain Access) but is not able to retrieve them.
The keychain constantly returns errSecAuthFailed (-25293). This occurs on Mountain Lion but not on Snow Leopard. My App is code signed and sandboxed. To me it seems that when retrieving the password, keychain does not recognize the App as the same one that stored the password, because when I set the password to be accessible by any application it also works well.
I use the following code:
+ (NSString*) retrievePasswordFromKeychainWithKey: (NSString*) theKey {
SecKeychainUnlock(NULL, 0, NULL, FALSE);
const char* userNameUTF8 = [NSUserName() UTF8String];
uint32_t userNameLength = (uint32_t)strlen(userNameUTF8);
uint32_t serviceNameLength = (uint32_t)strlen([theKey UTF8String]);
uint32_t pwLength = 0;
void* pwBuffer = nil;
SecKeychainItemRef itemRef = nil;
OSStatus status1 = SecKeychainFindGenericPassword (NULL, serviceNameLength, serviceNameUTF8, userNameLength, userNameUTF8, &pwLength, &pwBuffer, &itemRef);
if (status1 == noErr) {
NSData* pwData = [NSData dataWithBytes:pwBuffer length:pwLength];
SecKeychainItemFreeContent (NULL, //No attribute data to release
pwBuffer //Release data buffer allocated by SecKeychainFindGenericPassword
);
return [NSString stringWithCString:[pwData bytes] encoding:NSUTF8StringEncoding];
}
//status1 is always -25293
return nil;
}

OK, I just learnt that this is an open bug in Mac OS 10.8.0. Apps signed with a Developer ID cannot access data from the keychain.
I hope this will be fixed in 10.8.1...
A workaround is not to sign the App with your Developer ID. (I have also read that Apps built under Lion are not affected by this bug, but I could not test this, yet)

Related

Issues in using CNCopyCurrentNetworkInfo

I am using the below code to retrieve the SSID of the WiFi network the iPod is connected.
NSArray *ifs = (id)CNCopySupportedInterfaces();
NSLog(#"%s: Supported interfaces: %#", __func__, ifs);
id info = nil;
for (NSString *ifnam in ifs) {
info = (id)CNCopyCurrentNetworkInfo((CFStringRef)ifnam);
NSLog(#"%s: %# => %#", __func__, ifnam, info);
if (info && [info count]) {
break;
}
[info release];
}
Sometimes this code is not returning the proper SSID of the network my device is connected.Any pointers on why the SSID is not retrieved correctly? Does CNCopyCurrentNetworkInfo package dependent on the iOS version of the device?
Thanks.
add SystemConfiguration.framework to project.
import < SystemConfiguration/CaptiveNetwork.h >
CFArrayRef myArray = CNCopySupportedInterfaces();
CFStringRef interfaceName = CFArrayGetValueAtIndex(myArray, 0);
CFDictionaryRef captiveNtwrkDict = CNCopyCurrentNetworkInfo(interfaceName);
NSDictionary *dict = ( NSDictionary*) captiveNtwrkDict;
NSString* ssid = [dict objectForKey:#"SSID"];
NSLog(#"%s ssid : %#",__FUNCTION__, [ssid description]);
For iOS 12 and later, you must enable it from capabilities.
Important
To use this function in iOS 12 and later, enable the Access WiFi Information capability for your app in Xcode. When you enable this capability, Xcode automatically adds the Access WiFi Information entitlement to your entitlements file and App ID. Documentation link
Yes. CNCopyCurrentNetworkInfo is available only in iOS 4.1 and later.
For more info ,please look at the developer.apple SystemConfiguration Reference
you can check the sample code here

Sandboxing coreWLAN?

I'm writing an OS X application that depends on the ability to determine wireless signal strength, but I can't figure out what entitlements to use to sandbox it.
Whenever I use
NSMutableArray *scanResults;
CWInterface *currentInterface = [CWInterface interface];
NSLog(#"currInterface: %#\n", currentInterface);
NSMutableDictionary *signalsDict = [[NSMutableDictionary alloc] init];
NSError *err = nil;
scanResults = [NSMutableSet setWithSet:[currentInterface scanForNetworksWithSSID:nil error:&err]];
I get the error The operation couldn't be completed. (com.apple.coreWLAN.error error 1.) despite having all entitlements checked in XCode. What entitlement(s) am I missing?
The CoreWLANWirelessManager sample project has the same problem.
CoreWLAN doesn't seem to be available at all to sandboxed apps.
Apple's developer documentation states "With App Sandbox, your app cannot modify the system’s network configuration (whether with the System Configuration framework, the CoreWLAN framework, or other similar APIs)", which seems to imply that reading but not writing settings might be OK, but that doesn't seem to work in practice, and this is confirmed by a post by Apple DTS: https://forums.developer.apple.com/thread/11307
How about the entitlements for the Wifi Diagnostics app that ships with Mac OS X 10.11.1, located at /System/Library/CoreServices/Applications/. Checking entitlements I see that it posseses the following: com.apple.wifi.associate, com.apple.wifi.scan, com.apple.wifi.set_channel, com.apple.wifi.start_autojoin, com.apple.wireless-diagnostics, and com.apple.wireless-diagnostics.basic_report.
Are we mere mortals working in a sandbox not able to get these?
I think you need to check Outgoing Connections (Client).
You might want to use Apple80211 private framework by using dlfcn.h library. An iphone example can be found here:
http://www.csse.uwa.edu.au/~chris/iphone/APlogger/
Download the source file and investigate scanner module.
In summary, you will come up with something like this:
#define IF_NAME "en0"
#include <dlfcn.h>
- (void)performScan
{
int (*open)(void *);
int (*bind)(void *, NSString *);
int (*close)(void *);
int (*scan)(void *, NSArray **, void *);
void *libHandle;
void *airportHandle;
libHandle = dlopen("/System/Library/Frameworks/Preferences.framework/Preferences", RTLD_LAZY);
open = dlsym(libHandle, "Apple80211Open");
bind = dlsym(libHandle, "Apple80211BindToInterface");
scan = dlsym(libHandle, "Apple80211Scan");
close = dlsym(libHandle, "Apple80211Close");
open(&airportHandle);
bind(airportHandle, #IF_NAME);
NSArray *found;
NSDictionary *params = [[NSDictionary alloc] init];
scan(airportHandle, &found, params);
int nnw = [found count];
for(int i=0 ; i < nnw ; i++) {
NSDictionary *nw = [found objectAtIndex:i];
NSString *ssid = [self fixSSID:nw];
// RSSI indicates signal strength
int rssi = [[nw objectForKey:#"RSSI"] intValue];
}
// Cleanup
close(airportHandle);
dlclose(libHandle);
}
-(NSString *)fixSSID:(NSDictionary *)nw
{
if ([[nw objectForKey:#"HIDDEN_NETWORK"] boolValue])
return #"<hidden>";
else
return [nw objectForKey:#"SSID_STR"];
}
Note that if you use private frameworks in your iOS apps, you will not be able to publish them on App Store (Apple will reject your app because there is no public documentation for Apple80211 framework). but since your question is regarding OSX development, this doesn't apply for your case.
Hope it helps.

Don't Backup to iCloud but still rejected

In my app i have to store Core Data Database and audio files, so i decoded to put them in Documents directory.
To prevent them from backing up, when i first launch the app, i put the Don't BackUp flag like this
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[self addSkipBackupAttributeToItemAtURL:[self applicationDocumentsDirectory]];
}
- (NSURL *)applicationDocumentsDirectory
{
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
- (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)URL
{
if (&NSURLIsExcludedFromBackupKey == nil) { // iOS <= 5.0.1
const char* filePath = [[URL path] fileSystemRepresentation];
const char* attrName = "com.apple.MobileBackup";
u_int8_t attrValue = 1;
int result = setxattr(filePath, attrName, &attrValue, sizeof(attrValue), 0, 0);
return result == 0;
} else { // iOS >= 5.1
return [URL setResourceValue:[NSNumber numberWithBool:YES] forKey:NSURLIsExcludedFromBackupKey error:nil];
}
}
But it seems like it doesn't work - i still get rejected:
We found that your app does not follow the iOS Data Storage Guidelines, which is required per the App Store Review Guidelines.
In particular, we found that on launch and/or content download, your
app stores 3.6 MB. To check how much data your app is storing:
Install and launch your app
Go to Settings > iCloud > Storage & Backup > Manage Storage
If necessary, tap "Show all apps"
Check your app's storage
And the other problem is that i just can't check that - i don't see my app in
Settings > iCloud > Storage & Backup > Manage Storage
Maybe the problem is only with 5.0 that i kind of not think about here?
The problem is with iOS 5.0, in this iOS you should not put the dont backup flag
The dont back up flag was introduced in ios 5.0.1
We did face similar problem with our app, it has been rejected several times
So we had to do a work around to handle different iOSes
We needed to support iOS < 5.0, iOS 5.0, and iOS > 5.0
So after contacting apple, we didnt find any solution except to have different paths on different iOSes
We had a function like this:
+ (NSString*) savePath
{
NSString *os5 = #"5.0";
NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents"];
if ([currSysVer compare:os5 options:NSNumericSearch] == NSOrderedAscending) //lower than 4
{
return path;
}
else if ([currSysVer compare:os5 options:NSNumericSearch] == NSOrderedDescending) //5.0.1 and above
{
return path;
}
else // IOS 5
{
path = [NSHomeDirectory() stringByAppendingPathComponent:#"Library/Caches"];
return path;
}
return nil;
}
We used and still use this function.
Please read more
iOS 5.0
It is not possible to exclude data from backups on iOS 5.0. If your
app must support iOS 5.0, then you will need to store your app data in
Caches to avoid that data being backed up. iOS will delete your files
from the Caches directory when necessary, so your app will need to
degrade gracefully if it's data files are deleted.
http://developer.apple.com/library/ios/#qa/qa1719/_index.html

Is it possible to programmatically change the volume icon on a mounted drive on Mac OS X?

I want to programmatically change the volume icon for a stacked file system implemented using OSXFUSE (formerly MacFUSE). The icon needs to reflect the state of a mounted file system.
The approach that I have been trying to get working is to map requests for /.VolumeIcon.icns to the appropriate icon in the application bundle. Then sending change notifications to the file system for the actual path (path) and the mount path (mountPath).
[[NSWorkspace sharedWorkspace] noteFileSystemChanged: #"/Volumes"];
[[NSWorkspace sharedWorkspace] noteFileSystemChanged: [mountPath stringByDeletingLastPathComponent]];
[[NSWorkspace sharedWorkspace] noteFileSystemChanged: mountPath];
[[NSWorkspace sharedWorkspace] noteFileSystemChanged: [path stringByDeletingLastPathComponent]];
[[NSWorkspace sharedWorkspace] noteFileSystemChanged: path];
FNNotifyByPath([[[mountPath stringByDeletingLastPathComponent] dataUsingEncoding:NSUTF8StringEncoding] bytes], kFNDirectoryModifiedMessage, kNilOptions);
FNNotifyByPath([[[path stringByDeletingLastPathComponent] dataUsingEncoding:NSUTF8StringEncoding] bytes], kFNDirectoryModifiedMessage, kNilOptions);
FNNotifyByPath([[#"/Volumes" dataUsingEncoding:NSUTF8StringEncoding] bytes], kFNDirectoryModifiedMessage, kNilOptions);
Stepping through the debugger I can see this code being hit but the code to map the /.VolumeIcon.icns gets called infrequently and never in response to these notifications.
I think the short answer is, you're out of luck. The long answer is while the OSXFUSE project is different than the Fuse4X project, they're both derived from the same source, and Fuse4X has this to say about volume icons in their FAQ:
Q 4.1. Why do Fuse4X volumes show up with "server" (or "network
volume") icons?
A: To be precise, by default Fuse4X volumes show up as nonlocal
volumes, which the Finder unfortunately treats the same as "servers".
It's a good question as to why Fuse4X normally tags its volumes as
nonlocal. Some people think that in the case of disk-based file
systems, Fuse4X must tag the volume as local. Well, let us see.
For a vfs to be local on Mac OS X, you need a "real" disk device – a
/dev/disk* style node. Such a real disk device node in Fuse4X's case
is problematic: at mount time, for a local volume, the kernel would
itself open the device node and pass it to Fuse4X. In doing so, the
kernel would make sure that the device is not currently in use (for
one, to disallow multiple mounts of the same device). This happens
before control passes to Fuse4X and mounting can proceed. This would
have been fine if the entire file system lived in the kernel, but in
Fuse4X's case, the user-space file system program would also want to
(exclusively) open the disk device.
Take a look at path finder source code.
- (BOOL)setAsCustomIconForVolume:(NString *)path;
{
FSref FSRefpath = convertoFsref(path);
// filename for custom icon is ".VolumeIcon.icns"
NSString *iconPath = [path stringByAppendingPathComponent:#".VolumeIcon.icns"];
// remove any existing file first.
[self writeToFile:iconPath];
FSSetHasCustomIcon(FSRefpath);
// rebuild volumeList
return YES;
}
OSErr FSSetHasCustomIcon(
const FSRef *ref)
{
return ( FSChangeFinderFlags(ref, true, kHasCustomIcon) );
}
OSErr FSChangeFinderFlags(
const FSRef *ref,
Boolean setBits,
UInt16 flagBits)
{
OSErr result;
FSCatalogInfo catalogInfo;
FSRef parentRef;
/* get the current finderInfo */
result = FSGetCatalogInfo(ref, kFSCatInfoFinderInfo, &catalogInfo, NULL, NULL, &parentRef);
require_noerr(result, FSGetCatalogInfo);
/* set or clear the appropriate bits in the finderInfo.finderFlags */
if ( setBits )
{
/* OR in the bits */
((FileInfo *)&catalogInfo.finderInfo)->finderFlags |= flagBits;
}
else
{
/* AND out the bits */
((FileInfo *)&catalogInfo.finderInfo)->finderFlags &= ~flagBits;
}
/* save the modified finderInfo */
result = FSSetCatalogInfo(ref, kFSCatInfoFinderInfo, &catalogInfo);
require_noerr(result, FSSetCatalogInfo);
FSSetCatalogInfo:
FSGetCatalogInfo:
return ( result );
}
NTVolumeNotificationMgr
NTIconFamily

Get list of installed apps on iPhone

Is there a way (some API) to get the list of installed apps on an iPhone device.
While searching for similar questions, I found some thing related to url registration, but I think there must be some API to do this, as I don't want to do any thing with the app, I just want the list.
No, apps are sandboxed and Apple-accepted APIs do not include anything that would let you do that.
You can, however, test whether a certain app is installed:
if the app is known to handle URLs of a certain type
by using [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:#"thisapp://foo"]
You can get a list of apps and URL schemes from here.
For jailbroken devices you can use next snipped of code:
-(void)appInstalledList
{
static NSString* const path = #"/private/var/mobile/Library/Caches/com.apple.mobile.installation.plist";
NSDictionary *cacheDict = nil;
BOOL isDir = NO;
if ([[NSFileManager defaultManager] fileExistsAtPath: path isDirectory: &isDir] && !isDir)
{
cacheDict = [NSDictionary dictionaryWithContentsOfFile: path];
NSDictionary *system = [cacheDict objectForKey: #"System"]; // First check all system (jailbroken) apps
for (NSString *key in system)
{
NSLog(#"%#",key);
}
NSDictionary *user = [cacheDict objectForKey: #"User"]; // Then all the user (App Store /var/mobile/Applications) apps
for (NSString *key in user)
{
NSLog(#"%#",key);
}
return;
}
NSLog(#"can not find installed app plist");
}
for non jailbroken device, we can use third party framework which is called "ihaspp", also its free and apple accepted. Also they given good documentation how to integrate and how to use. May be this would be helpful to you. Good luck!!
https://github.com/danielamitay/iHasApp
You could do this by using the following:
Class LSApplicationWorkspace_class = objc_getClass("LSApplicationWorkspace");
SEL selector = NSSelectorFromString(#"defaultWorkspace");
NSObject* workspace = [LSApplicationWorkspace_class performSelector:selector];
SEL selectorALL = NSSelectorFromString(#"allApplications");
NSMutableArray *Allapps = [workspace performSelector:selectorALL];
NSLog(#"apps: %#", Allapps);
And then by accessing each element and splitting it you can get your app name, and even the Bundle Identifier, too.
Well, not sure if this was available back when the last answer was given or not (Prior to iOS 6)
Also this one is time intensive, yet simple:
Go into settings > Gen. >usage. The first category under usage at least right now is Storage.
It will show a partial list of apps. At the bottom of this partial list is a button that says "show all apps".
Tap that and you'll have to go through screen by screen, and take screenshots (Quick lock button and home button takes a screenshot).
I'm doing this now and I have hundreds of apps on my iPhone. So it's going to take me a while. But at least at the end of the process I'll have Images of all my apps.