Objective C : How can we retrieve information stored in Local Items in key chain? - objective-c

I have saved the username and password for a website in safari, Safari saved this information in Local Items keychain, how can I retrieve stored information using objective C ?
I am trying to retrieve website password stored in Local Items Keychain in OS X version 10.11.4 by safari.
if I access username and password stored in login keychain. then username and password can be retrieved by below code.
OSStatus status;
NSString *account = #"Safari";
const char *cService_name = "PersonalFormsAutoFillDatabase";
UInt32 service_length = strlen(cService_name);
const char *cAccount_name = [account cStringUsingEncoding:NSUTF8StringEncoding];
UInt32 account_length = strlen(cAccount_name);
void *passwordData = nil;
SecKeychainItemRef itemRef = nil;
UInt32 passwordLength = 0;
status = SecKeychainFindGenericPassword(NULL, service_length, cService_name, account_length, cAccount_name, &passwordLength, &passwordData, NULL);
NSString *pw = [[NSString alloc]initWithBytes:passwordData length:passwordLength encoding:NSUTF8StringEncoding];
When i run above code system prompt a popup and ask for permission to allow retrieve the password . if I want to change the default Login Keychain to another keychain then user need to create the reference for new keychain like below code and need to pass reference of new keychain in SecKeychainFindGenericPassword method.
SecKeychainRef keychain ;
OSStatus status1 = SecKeychainOpen("/Users/xxxx/Library/Keychains/mykeychain.keychain", &keychain);
if(status1 != errSecSuccess) {
NSLog(#"Failed to open System keychain %#", SecCopyErrorMessageString(status1, NULL));
}
status1 = SecKeychainUnlock(keychain, 0, NULL, FALSE);
My First question is what will be path for Local Items keychain like “/Users/xxxx/Library/Keychains/mykeychain.keychain” ?
As I don’t have the path then i created a new keychain From File->Add KeyChain and give the name testing.keychain. After that I copied one keychain item form Local Items keychain and Pasted into testing.keychain. and used the above code and changed the path as below.
SecKeychainRef keychain ;
OSStatus status1 = SecKeychainOpen("/Users/xxxx/Library/Keychains/testing.keychain", &keychain);
if(status1 != errSecSuccess) {
NSLog(#"Failed to open System keychain %#", SecCopyErrorMessageString(status1, NULL));
}
status1 = SecKeychainUnlock(keychain, 0, NULL, FALSE);
and passed the reference in find generic password method and also change the service name and account name to "a#gmail.com" and service name "https://accounts.google.com"
status = SecKeychainFindGenericPassword(keychain, service_length, cService_name, account_length, cAccount_name, &passwordLength, &passwordData, NULL);
this return the password data but as i think it is in encrypted mode then it return NULL. How can I decrypt this stored password.
Anyone who can help so i can retrieve the password stored in Local Items keychain.

Related

Creating local group on MacOS Catalina using Core Services and Objective-C

How do I create a local group using Core Services.? Documentation for Core Services says "The Core Services Identity Reference allows developers to support user and group creation.." but there are no examples on how to do it.
Update. This is the code I have so far but It doesn't work and ErrorCode return -2, error description is null. Really struggling to find any documentation that explains how to do it. 0 information on error codes as well.
CFStringRef realName = CFStringCreateWithCString(NULL, "newGroupTest",
kCFStringEncodingMacRoman);
CFStringRef posixName = CFStringCreateWithCString(NULL, "newgrptst1",
kCFStringEncodingMacRoman);
AuthorizationRef auth;
OSStatus status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment,
kAuthorizationFlagDefaults,
&auth);
CSIdentityAuthorityRef authority = CSGetDefaultIdentityAuthority();
CSIdentityRef identity = CSIdentityCreate(NULL, kCSIdentityClassGroup, realName,
posixName, kCSIdentityFlagNone, authority);
CFErrorRef error;
BOOL success = CSIdentityCommit(Identity, auth, &error);
if(!success)
{
CFIndex index = CFErrorGetCode(error);
CFStringRef desc = CFErrorCopyDescription(error);
const char* cDesc = CFStringGetCStringPtr(desc, CFStringGetSystemEncoding());
}
Found what was the problem. I wasn't using correct identity authority. To create a local group you need to use CSGetLocaldentityAuthority() that get a local identity authority that stores the identities local to the system, instead of
CSGetDefaultIdentityAuthority() that represents the network-bound authorities.

How to make a secure password input field in a command line app?

I am writing a command line application for OS X in Swift. I need to prompt for a username and password (not the user's account on the computer and not credentials saved in the Keychain). I can prompt for the username just fine:
func getInput() -> String {
var keyboard = NSFileHandle.fileHandleWithStandardInput()
var inputData = keyboard.availableData
return NSString(data: inputData, encoding:NSUTF8StringEncoding)!.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
}
let username = getInput()
I would like to prompt for the password as well but it prints the password in the console as the user types it. How can I accept input from STDIN without having it echoed back to the console?
Please note that I need the application to be interactive, the user will never be passing the username and password as command line arguments, so argv is not the correct answer.
For example, when doing this in Ruby, you would enter this:
require 'io/console'
puts "Enter your password"
#password = STDIN.noecho(&:gets).chomp
And then it would display on the screen as this image:
No matter how many letters are entered, it only shows that blue box with the dot in it. It doesn't print the password to the screen and it doesn't show ********* for the password either.
Is it possible to do the same thing with Swift or Objective-C in a command line OS X application?
Just for the sake of completeness: getpass() works great for passwords, but unfortunately this function also has the limitation that it can only read up to 128 characters. If you want to prompt for really long passphrase or private keys, use BSD's readpassphrase() instead.
Swift 2.0 example:
var buf = [Int8](count: 8192, repeatedValue: 0)
let passphrase = readpassphrase("Enter passphrase: ", &buf, buf.count, 0)
if let passphraseStr = String.fromCString(passphrase) {
print(passphraseStr)
}
Swift 3.1 and later:
var buf = [CChar](repeating: 0, count: 8192)
if let passphrase = readpassphrase("Enter passphrase: ", &buf, buf.count, 0),
let passphraseStr = String(validatingUTF8: passphrase) {
print(passphraseStr)
}
inputString = String(validatingUTF8: UnsafePointer<CChar>(getpass("Please enter your password: ")))
This is how you could get the input using swift
Use the C function getpass(3). For example:
char *p = getpass("Please enter your password: ");
NSString *password = [NSString stringWithUTF8String:p];
NSLog(#"%#", password);

Set Custom KeyEquivalent in Services Menu

OmniFocus has a Cocoa Service that allows you to create tasks based upon selected items.
It has a preference that allows you to set the keyboard shortcut that triggers the Service. This is not just a global hotkey, it's a bona fide Service that shows up in the menu.
You can the keyboard shortcut to pretty much any combination, including combinations with ⌥ and ^. This functionality is not documented - the docs seem to say that KeyEquivalents must be a ⌘+[⇧]+someKey.
Once this is set, I observe three things:
The OmniFocus Info.plist file does not contain a KeyEquivalent listed. This is not surprising, as the file is read-only.
The pbs -dump_pboard utility lists NSKeyEquivalent = {}; for the service.
Using NSDebugServices lists this interesting line that does not show up with most debugging sessions (Obviously, for keyboard shortcut ⌃⌥⌘M): OmniFocus: Send to Inbox (com.omnigroup.OmniFocus) has a custom key equivalent: <NSKeyboardShortcut: 0x7fb18a0d18f0 (⌃⌥⌘M)>.
So my questions are twofold, and I suspect they are related:
How do you dynamically change a service's KeyEquivalent?
How do you set the KeyEquivalent to a combination including ⌃ and ⌥
Thank you!
Figured it out. The basic process is described here: Register NSService with Command Alt NSKeyEquivalent
The code is this:
//Bundle identifier from Info.plist
NSString* bundleIdentifier = #"com.whatever.MyApp";
//Services -> Menu -> Menu item title from Info.plist
NSString* appServiceName = #"Launch My Service";
//Services -> Instance method name from Info.plist
NSString* methodNameForService = #"myServiceMethod";
//The key equivalent
NSString* keyEquivalent = #"#~r";
CFStringRef serviceStatusName = (CFStringRef)[NSString stringWithFormat:#"%# - %# - %#", bundleIdentifier, appServiceName, methodNameForService];
CFStringRef serviceStatusRoot = CFSTR("NSServicesStatus");
CFPropertyListRef pbsAllServices = (CFPropertyListRef) CFMakeCollectable ( CFPreferencesCopyAppValue(serviceStatusRoot, CFSTR("pbs")) );
// the user did not configure any custom services
BOOL otherServicesDefined = pbsAllServices != NULL;
BOOL ourServiceDefined = NO;
if ( otherServicesDefined ) {
ourServiceDefined = NULL != CFDictionaryGetValue((CFDictionaryRef)pbsAllServices, serviceStatusName);
}
NSUpdateDynamicServices();
NSMutableDictionary *pbsAllServicesNew = nil;
if (otherServicesDefined) {
pbsAllServicesNew = [NSMutableDictionary dictionaryWithDictionary:(NSDictionary*)pbsAllServices];
} else {
pbsAllServicesNew = [NSMutableDictionary dictionaryWithCapacity:1];
}
NSDictionary *serviceStatus = [NSDictionary dictionaryWithObjectsAndKeys:
(id)kCFBooleanTrue, #"enabled_context_menu",
(id)kCFBooleanTrue, #"enabled_services_menu",
keyEquivalent, #"key_equivalent", nil];
[pbsAllServicesNew setObject:serviceStatus forKey:(NSString*)serviceStatusName];
CFPreferencesSetAppValue (
serviceStatusRoot,
(CFPropertyListRef) pbsAllServicesNew,
CFSTR("pbs"));
Boolean result = CFPreferencesAppSynchronize(CFSTR("pbs"));
if (result) {
NSUpdateDynamicServices();
NSLog(#"successfully installed our alt-command-r service");
} else {
NSLog(#"couldn't install our alt-command-r service");
}
If the code succeeds, you can view this in ~/Library/Preferences/pbs.plist
You should see something like:
NSServicesStatus = {
"com.whatever.MyApp - Launch My Service - myServiceMethod" = {
enabled_context_menu = :true;
enabled_services_menu = :true;
key_equivalent = "#~r";
};

How to find Printer URI using CUPS

Anyone know to get a printer URI using CUPS API?
If not, does anyone know where I can find a list of allowable options that can be passed to cupsGetOption function.
Right now I can only find printer-info, printer-location, printer-make-and-model.
What your probably looking for is a the "device-uri". This is the uri to the remote device i.e lpd/socket/server address. If you're looking for the local uri it would be "printer-uri-supported" which would result in ipp://localhost:631/printers/printername. Here's how to get the remote uri...
#import <cups/cups.h>
const char * printer = "name_of_printer";
int num_dests;
cups_dest_t *dest,
*dests;
const char *value;
num_dests = cupsGetDests(&dests);
dest = cupsGetDest(printer, NULL, num_dests, dests);
if( dest == NULL){
return 0;
};
value = NULL;
if (dest->instance == NULL)
{
value = cupsGetOption("device-uri", dest->num_options, dest->options);
}
cupsFreeDests(num_dests, dests);
printf("uri - %s",value);

Not able to update firefox sqlite database when firefox is running-MacOS

I have the following code snippet to update firefox extension sqlite data base
NSString * profileFolderPath = [[ #"~" stringByExpandingTildeInPath] stringByAppendingPathComponent:#"/Library/Application Support/Firefox/Profiles"];
NSString *sqlitePath = [pathToProfileFolder stringByAppendingPathComponent:#"extensions.sqlite"];
int rc = sqlite3_open([sqlitePath UTF8String], &db);
if( rc )
{
NSLog(#"enable extension :%#\n",[NSString stringWithCString:sqlite3_errmsg(db)]);
sqlite3_close(db);
return NO;
}
else {
NSLog(#"opened entensions db successfully \n");
}
// check the values for active and userDisabled fields
rc = sqlite3_exec(db,"SELECT active,userDisabled FROM addon where id='myId.com'",sqliteCallback,0,&zErrMsg);
if (rc!=SQLITE_OK ) {
NSLog(#"error quering the entensions database :%#\n",[NSString stringWithCString:zErrMsg]);
if(zErrMsg)
sqlite3_free(zErrMsg);
sqlite3_close(db);
return NO;
// handle error
}
When firefox application is not in running state,I can read the values and also update the database,but when the firefox is running I am not able to read the values from the database as sqlite3_exec statement is returning the value 5 and I can see the error in console saying "error quering the extensions database :database is locked".
How can I resolve this issue.Please help.
You cannot b/c firefox keeps its own config file (and extensions db file IS a firefox own config file) open while it runs.