Repository navigation
preferences: default cf hostname to AnyHost + add managed (MDM) subsystem - #446
Merged
Merged
Conversation
The CFPreferences wrappers defaulted `hostname` to `kCFPreferencesCurrentHost`, which scopes reads and writes to the per-device ByHost store (`.../ByHost/<domain>.<host-UUID>.plist`). Ordinary preferences — and the high-level `CFPreferencesCopyAppValue` / `NSUserDefaults` path — use `kCFPreferencesAnyHost`, i.e. the plain `<domain>.plist`. With the old default, `cf.get_value(app, key)` missed keys written by normal apps and daemons, and `cf.set(...)` wrote to a location `defaults`/CopyAppValue never read. Default to `kCFPreferencesAnyHost` so the wrappers match the common case and the high-level API. Callers needing per-host scope can still pass `hostname=kCFPreferencesCurrentHost` explicitly.
doronz88
force-pushed
the
fix/cfpreferences-default-anyhost
branch
13 times, most recently
from
August 14, 2026 08:31
fceb92b to
452d99a
Compare
Expose `p.preferences.managed` on iOS, split by mechanism:
- `managed.profile.*` - the MDM Managed Preferences store
(`com.apple.ManagedClient.preferences`) plus the raw configuration
profiles that deliver it. Reads of the effective value come off
`/Library/Managed Preferences[/<user>]/<domain>.plist`; writes install
/ remove a profile through profiled
(`-[MCProfileConnection installProfileData:outError:]` /
`removeProfileWithIdentifier:`). API: get_dict / get_value / get_keys /
set / set_dict / clear (per-domain) and install / remove / is_installed
/ get / get_data (raw profiles).
- `managed.restricted.*` - the restrictions / MCFeature namespace
(`com.apple.applicationaccess`), the store behind accessors like
`DiagnosticLogSubmissionEnabled()` (`allowDiagnosticSubmission`). These
are not plist keys: the effective value is a merge of the built-in
default and restrictions from profiles/clients. Read via effective_bool
/ default_bool / effective_value / effective_parameters /
default_parameters; set directly via set_bool
(`setBoolValue:forSetting:`) / set_parameters
(`setParameters:for{Bool,Value}Setting:`), or by installing a
Restrictions profile via install / remove.
iOS-only: it goes through `MCProfileConnection` /
`ManagedConfiguration.framework`, which does not exist on macOS - so it
lives under `clients/ios/subsystems/` and is attached via an
`IosPreferences` override on `IosClient`; the shared `preferences`
aggregator keeps just `cf` / `sc`. Non-interactive install requires the
calling process to be entitled for profiled access.
doronz88
force-pushed
the
fix/cfpreferences-default-anyhost
branch
from
August 14, 2026 08:50
452d99a to
832e5d8
Compare
Add `Process.bundle_id()` - the process's code-signing identity via `csops(CS_OPS_IDENTITY)`, which for a signed app or daemon is its bundle identifier (com.apple.CrashReporter, com.apple.springboard, ...), i.e. the domain its NSUserDefaults standardUserDefaults uses. Works for daemons too, unlike SBSCopyDisplayIdentifierForProcessID. Add `process.preferences(application_id=None)`, reading/writing a preference domain the way that *specific* process resolves it. With no `application_id` it uses `Process.bundle_id()` (its standardUserDefaults domain); it is NOT kCFPreferencesCurrentApplication, which would be rpcserver. Preference location is process-relative (container, uid), so a plain CFPreferencesCopyValue from rpcserver would resolve in rpcserver's context. Instead it uses the container-scoped CF SPI (_CFPreferencesCopyValueWithContainer / SetValueWithContainer / CopyKeyListWithContainer / SynchronizeWithContainer), passing the target's container as a CFString path (a CFURL there crashes cfprefsd), so the request goes through cfprefsd (correct merged/managed view, cache-coherent writes) but resolves against the target's home. The container is the target's CFFIXED_USER_HOME, else its uid's home (/var/root for uid 0, else /var/mobile). API: get / get_dict / get_keys / set / remove / set_dict / clear, plus container() / application_id(). get_dict enumerates keys then reads each (CopyMultiple with keysToFetch=NULL crashes the container variant); removals pass a NULL value (not kCFNull). Verified end-to-end on-device against com.apple.springboard, com.apple.CrashReporter (ReportCrash daemon) and a scratch domain.
doronz88
force-pushed
the
fix/cfpreferences-default-anyhost
branch
from
August 14, 2026 09:04
832e5d8 to
5cb4363
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two related preferences changes.
1 —
fix: default cfpreferences hostname toAnyHostThe
p.preferences.cf.*wrappers defaultedhostnametokCFPreferencesCurrentHost, which scopes reads/writes to the per-device ByHost store —…/Library/Preferences/ByHost/<domain>.<host-UUID>.plist.Ordinary apps and daemons, the high-level
CFPreferencesCopyAppValue, andNSUserDefaultsall usekCFPreferencesAnyHost→ the plain<domain>.plist. With the old default:cf.get_value(app, key)missed keys stored in the common AnyHost domain (returnedNonefor values that plainly exist).cf.set(...)wrote into a ByHost file thatdefaults/CopyAppValuenever read back.Defaulting to
AnyHostmakes the low-level wrappers agree with the high-level API and the common case. Callers needing per-host scope can still passhostname=kCFPreferencesCurrentHostexplicitly.usernameis unchanged.2 —
feat: managed-preferences (MDM) subsystemAdds
p.preferences.managed, mirroring thecfAPI (get_value/get_dict/get_keys/set/set_dict/remove/clear) for the MDM Managed Preferences store. cfprefsd merges that store at the front of the read search list, so a managed key wins over anything an app writes viapreferences.cf./Library/Managed Preferences[/<user>]/<application_id>.plist.-[MCProfileConnection installProfileData:outError:]/removeProfileWithIdentifier:, the same path Settings andmdmclientuse — by installing/removing acom.apple.ManagedClient.preferences(MCX "Custom Settings") profile. The store is not poked directly: profiled owns it, so writing the files behind it would be untracked and clobbered.Raw primitives are also exposed:
install_profile(data)/remove_profile(identifier)/is_profile_installed(identifier).Non-interactive install requires the calling process to be entitled for profiled access; otherwise the install is queued for user approval.
ruff/ pre-commit pass and the module imports and builds the MCX profile correctly; the on-device install path is not exercised in this repo's tests.