Mac Launch Daemon unable to retrieve password from system keychain after saving it there - macos

We have a Launch Daemon which (necessarily, for various reasons) runs as root, and which communicates with a server component via the network. It needs to authenticate with the service, so when it first obtains the password, we save it to the system keychain. On subsequent launches, the idea is to retrieve the password from the keychain and use it to authenticate with the network service.
This has been working fine, but on macOS 10.12 the existing code stopped working, and we've been entirely stumped on how to fix this. It boils down to this:
Regardless of whether we're saving a new password or retrieving an old one, we obtain a reference to the system keychain using this:
SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem, &system_keychain);
We also disable user interaction for good measure, although we'd expect it to already be off in the context of a daemon.
SecKeychainSetUserInteractionAllowed(false);
When saving a new password to the keychain, we use
OSStatus status = SecKeychainAddInternetPassword(
system_keychain,
urlLength, server_base_url,
0, NULL,
usernameLength, username,
0, NULL,
0,
kSecProtocolTypeAny, kSecAuthenticationTypeAny,
passwordLength, password,
NULL);
This much works. Success is reported, and I can see the item in the "system" keychain in Keychain Access.app.
Retrieving it on subsequent runs of our daemon is done with this line:
status = SecKeychainFindInternetPassword(
system_keychain,
urlLength, url,
0, NULL,
usernameLength, username,
0, NULL,
0,
kSecProtocolTypeAny, kSecAuthenticationTypeAny,
&passwordLength, &password_data,
NULL);
Unfortunately, this has started returning errSecAuthFailed for reasons that are unclear to us.
A few additional details we've checked and things we've tried, to no avail:
The daemon binary is signed with a Developer Id certificate.
The daemon binary contains an embedded Info.plist section with a bundle ID and version.
I can see the daemon binary in the "Always allow access by these applications" list in the "Access Control" tab of the password item in Keychain Access.app.
If I manually switch to "Allow all applications to access this item" in Keychain Access, it works. This somewhat defeats the point of saving the password in the keychain, however.
We've tried playing around with the parameters to SecKeychainAddInternetPassword, but this doesn't seem to have made any difference.
We've tried explicitly unlocking the keychain with SecKeychainUnlock(), but as the documentation suggests, this seems to be superfluous.
Deleting the item in Keychain Access.app causes SecKeychainFindInternetPassword() to yield errSecItemNotFound, as you'd expect. So it can definitely find the saved item, it just isn't allowed to read it.
The keychain documentation isn't exactly easy to read and in parts rather tautological. ("In order to do Y, you need to do Y," without mentioning why you'd want to do Y.) Nevertheless, I think I've made it through and have understood most of it. Various aspects of our particular setup aren't covered in detail (access from a daemon), but it seems pretty clear that accessing an item previously saved by the same app should not require any special authorisation or authentication. Which is in direct contradiction to the behaviour we're seeing.
Any ideas?

After spending some more hours on this across several days, we finally worked out what was going on.
First, I tried to build a minimal example that would reproduce the problem. This did not fail with errSecAuthFailed and thus didn't reproduce the problem. So back to the original daemon, there must be something specifically about it that was going wrong.
The next idea was to check the system log for the time when SecKeychainFindInternetPassword() was called. This turned up some error messages:
securityd CSSM Exception: -2147411889 CSSMERR_CL_UNKNOWN_TAG
securityd MacOS error: -67063
securityd MacOS error: -67063
securityd code requirement check failed (-67063), client is not Apple-signed
securityd CSSM Exception: 32 CSSM_ERRCODE_OPERATION_AUTH_DENIED
OurDaemon subsystem: com.apple.securityd, category: security_exception, enable_level: 0, persist_level: 0, default_ttl: 0, info_ttl: 0, debug_ttl: 0, generate_symptoms: 0, enable_oversize: 0, privacy_setting: 2, enable_private_data: 0
OurDaemon CSSM Exception: -2147416032 CSSMERR_CSP_OPERATION_AUTH_DENIED
This suggested the problem might be with code signing. Strange. Checking the code signature of the binary with codesign -vv returned no issues.
After hunting around the web for various parts of the error messages, I found -67063 corresponds to errSecCSGuestInvalid. The comment reads "code identity has been invalidated."
Okay, definitely some codesigning error, but what does it mean, and why did it occur?
Hunting around some more finally turned up the explanation, and also the solution: http://lists.apple.com/archives/apple-cdsa/2010/Mar/msg00027.html
It means that at some point since the program got started, something
happened to it that made it invalid.
and
if you run a signed program, then replace it (by, say, building a
new version in place :-), and then run the new version, the kernel
will still hold the old signature attached to the executable's vnode.
If that's your situation, just removing the executable and recreating
it clears up the problem for good (until you overwrite the file again
:-). We recommend that signed code always be replaced (mv(1), not
cp(1), or equivalents).
This explained it. I was copying new versions of the daemon into place using
sudo cp path/to/built/daemon /usr/local/libexec/
Apparently, that overwrites the file in-place rather than creating a new vnode, writing that, and then renaming it over the old file. So the solution is to either cp to a temp directory first, and then mv into place. Or delete the destination file before using cp.
As soon as I did that, it worked!

Related

Sourcetree: Invalid password for Github despite having a valid OAUTH token on Windows

I use Github and Sourcetree on my Windows machine.
I have been into Tools - Options - Authentication and added my Github account. I am 120% sure that my settings are correct.
However, when I try to push anything, I keep getting:
git -c diff.mnemonicprefix=false -c core.quotepath=false push -v --tags origin develop:develop
fatal: HttpRequestException encountered.
An error occurred while sending the request.
remote: Invalid username or password.
fatal: Authentication failed for 'REPOLINK'
Pushing to REPOLINK
Completed with errors, see above.
Now, I also tried to remove the account in my settings, and then entering e-mail / password manually. Usually it will say OK and ask for my 2FA code on my phone, but for now it just fails and responds with invalid username/password.
Any ideas?
EDIT:
Still a problem. I also tried to decrease my commit size from 15k files to just 1. Doesn't work.
I managed to commit through the console (but I have to fill credentials each time).
So unfortunately this is still unsolved.
http://www.omniweb.com/wordpress/?p=1291 this person solved it, it works for me.
navigating to C:\Users\USERNAME\AppData\Local\Atlassian\SourceTree and removing (or renaming) the passwd file.
Once this file is removed, restart SourceTree and execute a fetch or something else that requires access to the repo in question. SourceTree will then prompt you for your password, rewriting the cached credentials.
This is not a very good answer, but I still wanted to show my solution now 1.5 months have gone by.
On 3 computers I've failed to get Sourcetree to work. I'm using Windows on all machines, and above problem keeps happening no matter what I do. I've tried preferences/settings, filling it on prompt...
I doubt it's my account - I use Github OAUTH in many other programs.
The day after this post, I switched to SmartGit. Works much better and no problems, and will not go back.
This is a very bad answer - but if you're ending up here from Google - this is one possible solution.

signpass error: Couldn't find an identity for pass.com.xxx.xxxx (continued)

I have used the pass kit demos provided by Apple and made some changes, bought a new MacBook and the error "Couldn't find an identity for pass for pass.com.xxx.xxx" has came up. I did admittedly make a silly mistake of not downloading the certificates again thinking iCloud would do that for me. However, even after doing that and double checking it in the keychain, it still comes up with the same error. I have checked the passTypeIdentifier and the teamIdentifier.
signpass error:Couldn't find an identity for pass.com.xxx.xxxx
I turned to jsonlint to ensure that my pass.json file was free from errors. The file was validated so I am left a bit clueless as to what the problem may be.
Passbook: Couldn't find a passTypeIdentifier in the pass?
When I execute: ./signapss -p /myPass in terminal, it shows:
2016-12-25 13:15:19.219 signpass[4024:556398] {
"icon.png" = ba47a8021c8d74d2146d7244c8a0566be37df43b;
"icon#2x.png" = bd5442b4b08aa4dde333ec9ef0269e7fd93140b3;
"logo.png" = 6d4e7410569679d1ad9ec8040b072d5c6fc46285;
"logo#2x.png" = a718ffd4e611e404dd3eb701454bcaefdabbe311;
"pass.json" = bf3b10c7b714fccd38e564e30d2b9342a016615c;
}
2016-12-25 13:15:19.236 signpass[4024:556398] Couldn't find an identity for pass.com.VirtualCard.Virtual-Card
When moving from a old Mac device to another there is a key that also needs to be transferred and apple's security needs to be contacted. Upon contacting them they refer you to this https://developer.apple.com/library/content/documentation/IDEs/Conceptual/AppDistributionGuide/Troubleshooting/Troubleshooting.html#//apple_ref/doc/uid/TP40012582-CH5-SW1 to import. You can either go down that route or just generate another certificate from scratch and use that instead which is what I have done.

RmGetList consistently returning 0x5 ERROR_ACCESS_DNIED

I am getting consistently a return value of 5 from RmGetList, any possible reasons?
I am following this tutorial: http://blogs.msdn.com/b/oldnewthing/archive/2012/02/17/10268840.aspx
My RmStartSession and RmRegstierResources both return 0 which means success. A note though, after RmStartSession the dwSession is always 0, and my szSessionKey stays a string in the form of 0ea790d06656a54f84645b5755f7b6d6 null terminated. Is this a problem?
My code is js-ctypes so I'm reluctant to share this in winapi but ill share it: https://github.com/Noitidart/_scratchpad/blob/master/_WinAPI-RstrtMgr.js#L293
Edit: I learned that dwSession of 0 is a valid. However I still can't figure out why I'm getting access denied on RmGetList, anyone any ideas?
I've learned that the restart manager doesn't support folders, and the error 5 is returned when you're trying to pass a folder:
https://blog.yaakov.online/failed-experiment-what-processes-have-a-lock-on-this-folder/
Update: here's some sample code of how to use the restart manager API:
https://github.com/Microsoft/msbuild/blob/master/src/Tasks/LockCheck.cs
RmGetList will return error 5 if any higher level thing like a file system fillter block the file
the driver filter denies access to file xxx from any process and function whether windows kernel or user code tries to access it
it does the same with restart manager , restart manger tries to access the file , the driver throws error 5 , the restart manager wont know what to do with it ,and rethrows it back to calling function ,so you'll get a access denied
if you are trying it for all files in windows volume, there will be much files with throwing error 5, including 3rd parity antivirus files or ms defender or ...
simply use a try catch and ignore them because even if you know what pid is locking them you couldn't do anything about it, other than watching
it also happens if you don't have even read access to the locked file ,in this case try fixing security permotions and trying again

Cannot re-create app due to error "This Firebase URL is not available"

I decided to try out Firebase hosting and wanted to start fresh so I deleted my one and only app, but when I tried to create a new app with the same name I was unable to due to the error:
"This Firebase URL is not available"
I can only guess this is because of caching of app names/URLs? Hopefully it will become available (unless someone else beats me to it) after some timeout? Any info from others who have experience with this issue or otherwise know the answer is appreciated!
Not sure whether this is the right place to ask although Firebase suggest coming to SO because they apparently monitor Firebase-related questions closely according to their website.
Thanks!
Once you delete a Firebase URL, it is permanently unavailable. It cannot be recovered.
During confirmation, you should see a message like this, which explains in detail:
This stems from a number of abuse vectors that are possible by misappropriating a project id that the prior owner believes is deleted and could still have apps/releases in the wild attached to the defunct backend. Since compliance requires that we purge all data related to the project, including information about ownership, there's not even a way to restore one you personally deleted.

IOKit not permitted in Sandbox?

I'm new to using IOKit and have noticed what I think is the sandbox making it fail.
Here is the test I'm trying (in Pascal) which runs fine outside the sandbox but when I enable it IOServiceOpen returns the error kIOReturnNotPermitted every time.
Is IOKit not safe in the sandbox for certain services? I was trying to get some fan speeds/cpu temperatures and I see there are some apps in the AppStore (sandboxed) doing this so I believe it's possible. The only one I could confirm appears to have an XPC service bundled with the app as a helper so maybe that's a clue to make IOKit work? I tried basically all the entitlements and none of them seemed to help any.
Thanks for any ideas you may have.
procedure TestIOKit;
var
err: kern_return_t;
masterPort: mach_port_t;
iterator: io_iterator_t;
device: io_object_t;
matchingDictionary: CFMutableDictionaryRef;
conn: io_connect_t;
begin
IOMasterPort(0, masterPort);
matchingDictionary := IOServiceMatching('AppleSMC');
err := IOServiceGetMatchingServices(masterPort, matchingDictionary, iterator);
if err <> kIOReturnSuccess then
writeln('IOServiceGetMatchingServices: ', err);
device := IOIteratorNext(iterator);
IOObjectRelease(iterator);
if device = 0 then
writeln('no smc found');
err := IOServiceOpen(device, mach_task_self_, 0, conn);
if err <> kIOReturnSuccess then
writeln('IOServiceOpen: ', err);
end;
I found the same problem trying to read SMC keys in order get sensor temps and fan speeds from inside an OSX Yosemite 'Today extension'. The extension needs to be sandboxed, and I was also getting the kIOReturnNotPermitted error every time I tried to read the temp and fan sensors.
The only way I got it working was by creating a XPC service that manages all the SMC stuff, configured as a launch agent. This way, the sandboxed app (the 'today' extension) asks the XPC service for all the relevant data, instead of messing with IOKit directly.
So far, it seems to be working properly.
You don't need an XPC (not sure I understand that answer given it would also need to be sandboxed).
You can use this temporary entitlement although I don't hold any hope of apple approving it for MAS - you'd need to make your case to try and justify its use in iTunes connect. I have a similar problem and it's the only "solution" i've found so far:
com.apple.security.temporary-exception.sbpl string (allow iokit-open)
I don't see the answer from Luis Glez provide a solution but wrong information.
In fact there is currently no way to access this I/O Kit functionality from a sandboxed app neither would it be approved by Apple for the App Store.
If you check sandbox status of the app from from Luis Glez you will see that it's not sandboxed at all. Also it's not available at the App Store and I assume this is the reason.
Terminal:
codesign --display --entitlements - VitalStats.app
There was a recent discussion on the Developer Forums and someone from Apple confirmed that there is no way.
https://devforums.apple.com/message/1082393#1082393
The solution is very simple. You need to add a few lines in the file entitlements
<key>com.apple.security.temporary-exception.sbpl</key>
<array>
<string>(allow iokit-open)</string>
<string>(allow iokit-set-properties (iokit-property "ConsoleUID"))</string>
<string>(allow mach-lookup (global-name "com.apple.AssetCacheLocatorService"))</string>
</array>
My app was just rejected for using IOKit in general. Does anyone else have the same problem? The app was approved for 60 earlier builds, but all of the sudden, Apple seems to have a problem with that now. I use IOKit to read battery information like current voltage etc.
Rejected because of 1.1.6 - Safety.
Thank you for your submission. During our review, we found that your app is not appropriate for the App Store.
We encourage you to review your app concept and evaluate whether you
can incorporate different content and features to bring it into
compliance with the App Store Review Guidelines.
For those who may still look for answer, in Catalina, the problem might be that the app first needs to get the Input Monitoring permission, if it's not granted or denied - You would certainly get kIOReturnNotPermitted error.
To try if this is the case, go to System Settings, Privacy, select Input Monitoring and check if Your app is allowed.
After granting the permission the error should disappear

Resources