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.
Related
Since updating to OSX 10.7 Lion, Xcode tells me that AuthorizationExecuteWithPrivileges is deprecated.
Can anyone suggest a way my application can write to a directory it doesn't have permission for?
I know it sounds crazy, but this actually works:
NSDictionary *error = [NSDictionary new];
NSString *script = #"do shell script \"whoami > /tmp/me\" with administrator privileges";
NSAppleScript *appleScript = [[NSAppleScript alloc] initWithSource:script];
if ([appleScript executeAndReturnError:&error]) {
NSLog(#"success!");
} else {
NSLog(#"failure!");
}
I'm executing an Applescript from Objective C. The only disadvantage is that you cannot gain permanent root privileges with this. It will ask for the password each time you run this.
In fact, AuthorizationExecuteWithPrivileges() has been deprecated for a very long time, it's only recently that the header file has caught up with this fact.
You can create a privileged helper tool as part of your application. You can use ServiceManagement.framework's SMJobBless() function to have the helper deployed into the system launchd context: then when you need to perform privileged tasks, you just message the privileged helper to do that work.
There's a little bit of hidden complexity, in that the app and the helper must each declare the signing identity of the other before SMJobBless() believes they're supposed to be used together, and you need to get the linker to write the helper tool's Info.plist file into the binary. That's all covered by Apple's Documentation and Apple have provided a sample project, too.
I wrote an example application that uses SMJobBless() to deploy its privileged helper.
Based on a great find by user950473 I've implemented his/her discovery as a method; thought I'd share the code in case it's helpful.
- (BOOL) runProcessAsAdministrator:(NSString*)scriptPath
withArguments:(NSArray *)arguments
output:(NSString **)output
errorDescription:(NSString **)errorDescription {
NSString * allArgs = [arguments componentsJoinedByString:#" "];
NSString * fullScript = [NSString stringWithFormat:#"'%#' %#", scriptPath, allArgs];
NSDictionary *errorInfo = [NSDictionary new];
NSString *script = [NSString stringWithFormat:#"do shell script \"%#\" with administrator privileges", fullScript];
NSAppleScript *appleScript = [[NSAppleScript new] initWithSource:script];
NSAppleEventDescriptor * eventResult = [appleScript executeAndReturnError:&errorInfo];
// Check errorInfo
if (! eventResult)
{
// Describe common errors
*errorDescription = nil;
if ([errorInfo valueForKey:NSAppleScriptErrorNumber])
{
NSNumber * errorNumber = (NSNumber *)[errorInfo valueForKey:NSAppleScriptErrorNumber];
if ([errorNumber intValue] == -128)
*errorDescription = #"The administrator password is required to do this.";
}
// Set error message from provided message
if (*errorDescription == nil)
{
if ([errorInfo valueForKey:NSAppleScriptErrorMessage])
*errorDescription = (NSString *)[errorInfo valueForKey:NSAppleScriptErrorMessage];
}
return NO;
}
else
{
// Set output to the AppleScript's output
*output = [eventResult stringValue];
return YES;
}
}
Usage example:
NSString * output = nil;
NSString * processErrorDescription = nil;
BOOL success = [self runProcessAsAdministrator:#"/usr/bin/id"
withArguments:[NSArray arrayWithObjects:#"-un", nil]
output:&output
errorDescription:&processErrorDescription];
if (!success) // Process failed to run
{
// ...look at errorDescription
}
else
{
// ...process output
}
It's very slightly hacky, but IMHO is a satisfactory solution.
AuthorizationExecuteWithPrivileges is indeed deprecated.
But fortunately, there is a new recommended way to proceed.
As of 10.6 there is the new API and it is recommended to install a helper tool that will perform the privileged operation. Apple provide a code sample that clearly demonstrate how to manage it.
Make sure you check out their readme.txt since contrarily to other code sample there is more to do than just downloading the project and running it.
From The SMJobBless example introduction
SMJobBless demonstrates how to securely install a helper tool that performs a privileged operation and how to associate the tool
with an application that invokes it.
As of Snow Leopard, this is the preferred method of managing privilege
escalation on Mac OS X and should be used instead of earlier
approaches such as BetterAuthorizationSample or directly calling
AuthorizationExecuteWithPrivileges.
SMJobBless uses ServiceManagement.framework that was introduced in Mac
OS X v10.6 Snow Leopard.
Source: Apple SMJobBless code sample
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
The question is in the title :) I'm playing a bit with Objective-C and Scripting Bridge. I know it is possible to get information (readonly) from iTunes, but i see nowhere a way to modify a track, for exemple change its name. Is it possible with this or another technology ?
Thanks a lot :)
Well, from the Scripting Library in AppleScript Editor, I can see that a file_track inherits from item and an item has the read-write property name. So you should be able to set it just as easily as you can read it.
Edit: Actually, almost every piece of meta-data is part of track (of which file_track inherits aswell) and most are read-write properties...
Doug Adams has one such script which can change titles from song in iTunes. Maybe have a look at it?
As for setting it via Objective-C, perhaps this documention can help you.
Exerpt from the website:
Listing 2-3 Setting the locked property of Finder items
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
FinderApplication *theFinder = [SBApplication applicationWithBundleIdentifier: #"com.apple.finder"];
SBElementArray *trashItems = [[theFinder trash] items];
if ([trashItems count] > 0) {
for (FinderItem *item in trashItems) {
if ([item locked]==YES)
[item setLocked:NO]; // <<<-- Setting the property
}
}
[pool drain];
return 0;
}
Have you tried:
iTunesApplication *iTunes = [SBApplication applicationWithBundleIdentifier:#"com.apple.iTunes"];
[[iTunes currentTrack] setName:#"The New Song Title"]);
I am developping an iPhone App using XCode 4.2 .in a portion of the App I will be getting a VCard as an NSString
I found this function initWithVCardRepresentation and i think it will be easier than parsing the data one by one (i.e getting the first name then the last name etc ... , but I have a hard time to implement it in my code .
I have the AddressBook and the AddressBookUI frameworks and I am trying to use this code but can t find an exact way to do it
-(IBAction)Add{
// I have a NSString *card defined somewhere else
ABAddressBookRef *iPhoneAddressBook = ABAddressBookCreate();
ABRecordRef *contact = ABPersonCreatePeopleInSourceWithVCardRepresentation(iPhoneAddressBook, (__bridge_retained CFStringRef) card);
CFRelease(contact);
CFRelease(iPhoneAddressBook);
}
when I compile ,it crashes at the line
ABRecordRef *contact = ABPersonCreatePeopleInSourceWithVCardRepresentation(iPhoneAddressBook, (__bridge_retained CFStringRef) card);
and I get the following green error in the #autoreleasepool
Thread1:Program Received Signal "SIGABRT".
I am quite new to the Apps development , please let me know if the information I gave is sufficient
Thanks
If you want to have an ABPerson afterwards (what is advisable), use:
// Assuming NSString *card exists already.
ABPerson *person = [[[ABPerson alloc] initWithVCardRepresentation:[card dataUsingEncoding:NSUTF8StringEncoding] autorelease];
Since updating to OSX 10.7 Lion, Xcode tells me that AuthorizationExecuteWithPrivileges is deprecated.
Can anyone suggest a way my application can write to a directory it doesn't have permission for?
I know it sounds crazy, but this actually works:
NSDictionary *error = [NSDictionary new];
NSString *script = #"do shell script \"whoami > /tmp/me\" with administrator privileges";
NSAppleScript *appleScript = [[NSAppleScript alloc] initWithSource:script];
if ([appleScript executeAndReturnError:&error]) {
NSLog(#"success!");
} else {
NSLog(#"failure!");
}
I'm executing an Applescript from Objective C. The only disadvantage is that you cannot gain permanent root privileges with this. It will ask for the password each time you run this.
In fact, AuthorizationExecuteWithPrivileges() has been deprecated for a very long time, it's only recently that the header file has caught up with this fact.
You can create a privileged helper tool as part of your application. You can use ServiceManagement.framework's SMJobBless() function to have the helper deployed into the system launchd context: then when you need to perform privileged tasks, you just message the privileged helper to do that work.
There's a little bit of hidden complexity, in that the app and the helper must each declare the signing identity of the other before SMJobBless() believes they're supposed to be used together, and you need to get the linker to write the helper tool's Info.plist file into the binary. That's all covered by Apple's Documentation and Apple have provided a sample project, too.
I wrote an example application that uses SMJobBless() to deploy its privileged helper.
Based on a great find by user950473 I've implemented his/her discovery as a method; thought I'd share the code in case it's helpful.
- (BOOL) runProcessAsAdministrator:(NSString*)scriptPath
withArguments:(NSArray *)arguments
output:(NSString **)output
errorDescription:(NSString **)errorDescription {
NSString * allArgs = [arguments componentsJoinedByString:#" "];
NSString * fullScript = [NSString stringWithFormat:#"'%#' %#", scriptPath, allArgs];
NSDictionary *errorInfo = [NSDictionary new];
NSString *script = [NSString stringWithFormat:#"do shell script \"%#\" with administrator privileges", fullScript];
NSAppleScript *appleScript = [[NSAppleScript new] initWithSource:script];
NSAppleEventDescriptor * eventResult = [appleScript executeAndReturnError:&errorInfo];
// Check errorInfo
if (! eventResult)
{
// Describe common errors
*errorDescription = nil;
if ([errorInfo valueForKey:NSAppleScriptErrorNumber])
{
NSNumber * errorNumber = (NSNumber *)[errorInfo valueForKey:NSAppleScriptErrorNumber];
if ([errorNumber intValue] == -128)
*errorDescription = #"The administrator password is required to do this.";
}
// Set error message from provided message
if (*errorDescription == nil)
{
if ([errorInfo valueForKey:NSAppleScriptErrorMessage])
*errorDescription = (NSString *)[errorInfo valueForKey:NSAppleScriptErrorMessage];
}
return NO;
}
else
{
// Set output to the AppleScript's output
*output = [eventResult stringValue];
return YES;
}
}
Usage example:
NSString * output = nil;
NSString * processErrorDescription = nil;
BOOL success = [self runProcessAsAdministrator:#"/usr/bin/id"
withArguments:[NSArray arrayWithObjects:#"-un", nil]
output:&output
errorDescription:&processErrorDescription];
if (!success) // Process failed to run
{
// ...look at errorDescription
}
else
{
// ...process output
}
It's very slightly hacky, but IMHO is a satisfactory solution.
AuthorizationExecuteWithPrivileges is indeed deprecated.
But fortunately, there is a new recommended way to proceed.
As of 10.6 there is the new API and it is recommended to install a helper tool that will perform the privileged operation. Apple provide a code sample that clearly demonstrate how to manage it.
Make sure you check out their readme.txt since contrarily to other code sample there is more to do than just downloading the project and running it.
From The SMJobBless example introduction
SMJobBless demonstrates how to securely install a helper tool that performs a privileged operation and how to associate the tool
with an application that invokes it.
As of Snow Leopard, this is the preferred method of managing privilege
escalation on Mac OS X and should be used instead of earlier
approaches such as BetterAuthorizationSample or directly calling
AuthorizationExecuteWithPrivileges.
SMJobBless uses ServiceManagement.framework that was introduced in Mac
OS X v10.6 Snow Leopard.
Source: Apple SMJobBless code sample