I want to store something in the system keychain, but am seeing some weird behavior. In my app's scheme, I have Debug Process As set to root. However, when I check the default keychain via SecKeychainCopyDefault, it returns the login keychain for my current user.
As far as I know, the only way to write a keychain item to a specific keychain is to first set it as the default keychain using SecKeychainSetDefault and then perform the write. Obviously, since the default is set to my login chain in my debug environment, I'd need to set the default to the system keychain before attempting to write. I am doing the following to accomplish this:
// Store original default so we can restore it after we are done
var defaultKeychain: SecKeychain? = nil
SecKeychainCopyDefault(&defaultKeychain)
// Open System keychain
let cs = ("/Library/Keychains/System.keychain" as NSString).utf8String
var buffer = UnsafeMutablePointer<Int8>(mutating: cs)!
var systemKeychain: SecKeychain? = nil
SecKeychainOpen(buffer, &systemKeychain)
// Set System keychain to default
var status = SecKeychainSetDefault(systemKeychain)
NSLog(SecCopyErrorMessageString(status, nil) as String? ?? "")
// Ensure default keychain gets reset at end of scope
defer {
SecKeychainSetDefault(defaultKeychain)
}
// Add item to keychain below
...
However, I get the following output:
Will not set default: UID=0 does not own directory /Users/myuser
2019-12-11 09:54:31.262285-0700 App[99920:12060617] Write permissions error.
It seems as though even though my app is running as root, I don't have write access to the login keychain for some reason. The strange thing is, when I deploy my app as a background launch daemon, the default keychain is already the System keychain, not the login keychain, and things work properly. Obviously though I would like this behavior in my development environment as well.
How can I get around this issue? I need my keychain item to be in the System keychain, but even running the app as root doesn't seem to help when running in a debug environment.
The following workaround worked for me (on Mac OS 10.15) :
In your app's scheme set the "HOME" environment variable to a folder owned by root (e.g. '/' or '/var/root')
Related
I want to have my keys stored in System Keychain and a couple of apps(keySharing and AppGroup enabled) to access them
My current approach
I am using
let path:String = "/Library/Keychains/System.keychain"
var keychain: SecKeychain?
SecKeychainOpen(path, &keychain)
For options in SecItemAdd() ,I added
[kSecUseKeychain as String: keychain! ]
with this approach, I am able to write to System keyChain but only the current app is able to access this KeyChainItem,
kSecAttrAccessGroup
is completely ignored for this keychain item.
After some digging I found
kSecUseDataProtectionKeychain = true
is mandatory to use AccessGroup
When I included this in the options of SecAddItem(), Yes I am able to utilize access groups after this, but it is ignoring kSecUseKeychain now. Though my app is running in root and kSecUseKeychain is set, SecAddtem() is writing to login KeyChain (and apps inside my access are able to access them) instead of System Keychain
Is there a way to write to System KeyChain and allow a set of apps to modify them?
In short
[kSecUseKeychain as String: keychain! ]
is ignored when
kSecUseDataProtectionKeychain = true
Thanks
Any alternatives related to having keys in System Context is much appreciated
Xcode -12.2
macOS :10.15
I'm trying to get my swift Mac app to launch at login using the method described in this page: https://theswiftdev.com/how-to-launch-a-macos-app-at-login/
However, I keep getting the following errors as soon as I call SMLoginItemSetEnabled:
Could not locate login item com.domain.LauncherApplication in the caller's bundle
Could not enable login item: com.domain.LauncherApplication: 3: No such process
I checked that the launcher app ID is correct multiple times, I tried changing it and changing its version number. I even tried cleaning the project and moving the base app to /Applications but I always get these error messages.
Any idea what the problem might be? (Notice the solution must not require me to disable App Sandboxing)
OK, I found the problem but it took a long time since it was so sneaky: In the Copy File Build Phase section I entered "Contents/Library/LoginItem" as the subpath instead of "Contents/Library/LoginItems" (notice the 's' in the end - can't believe I missed it). So thank you #vadian! You were absolutely right.
I'd like to use Realm with app groups to be able to share data with watch extension. I'm facing problem, that when I try to configure default realm.. By that I mean that I create new path and then I create new configuration. So far so good, but when I try to set this configuration as defaultConfiguration, nothing happens. For better idea check screenshot where is my code plus console output. Any idea? Thank you
The defaultConfiguration you set on Realm.Configuration is used to initialize new Realms. So if you would print the path of a Realm instance, e.g. try! Realm().path, then this would reflect the path from the shared app group. You did instead initialize a new & fresh configuration, which always uses the initial default values.
I am creating a application UIPasteboard with my app's identifier as a name (e.g. com.example.app.pboard) as suggested in the docs.
All the copying and pasting works, but the damn thing never goes away. I set its persistent property explicitly to NO every time I access it to copy something onto it, and I even call UIPasteboard's +removePasteboardWithName: every time my app starts.
But every time I look at it, the most recent thing I copied onto it is always there, despite app restarts.
What gives?
No idea why what you are trying isn't working, here are two guesses and a possible solution:
Removing the paste board may be expected to be executed on exit from the app, so it doesn't execute until the app is terminated or backgrounded?
Calling remove and then asking for the items may be recreating it again in the same "place" so the items still remain.
You could perhaps solve this by setting the pasteboard's items to nil when leaving or entering the app.
You can set UIPasteboard to persistent. Accord to Apple's document,
setPersistent:
A Boolean value that indicates whether the pasteboard is persistent.
When a pasteboard is persistent, it continues to exist past app terminations and across system reboots. App pasteboards that are not persistent only last until the owning (creating) app quits. The system wide general pasteboard is persistent. Named, app-specific pasteboards are not persistent.
Update: For iOS 10, UIPasteboard set persistence automatically.
Note
Starting in iOS 10, the system sets pasteboard persistence automatically. If you try to set the setPersistent: property on a pasteboard, Xcode issues a deprecation warning.
Instead of named persistent pasteboards, use shared containers, as described in the Overview section of this document.
I have 4 database catalogues in my app, i will be switching the four catalogues.
When i start the app, i read the NSUserDefaults and try to load the default catalogue in the memory, but in the first time this doesnt happen. Instead i get null values returned first time just because the DB connection is not successful for some unknown reason, the debugger is unable to go there too.
But the app starts up the next time, the values are fetched successfully.
Please help
If your trying to fetch some necessary data from the user defaults, it might not be there the first time you run the app. You probably need to create a default set of defaults (heh) using:
-[NSUserDefaults registerDefaults:]
...before you query the user defaults for any value.
From User Defaults Programming Topics
The registration domain is a set of
application-provided defaults that are
used unless a user overrides them (the
“default defaults” or “factory
settings”). For example, the first
time you run Xcode, there isn’t an
IndexOnOpen value saved in your
defaults database. Consequently, Xcode
registers a default value for
IndexOnOpen in the
NSRegistrationDomain as a “catch all”
value. Xcode can thereafter assume
that an NSUserDefaults object always
has a value to return for the default,
simplifying the use of user defaults.
You set NSRegistrationDomain defaults
programmatically with the method
registerDefaults:.