Hello, as the title says, I am trying to access Bluetooth in a system daemon. I am running on MacOS Sonoma 14.5.
When initializing Bluetooth, my daemon received Unauthorized
state.
I have tried to add my daemon in the system settings (System Preferences > Security & Privacy > Privacy > Bluetooth) "Allow applications to access Bluetooth" by adding the program executable path defined by the entry Program
of my system daemon as suggested here: https://developer.apple.com/forums/thread/662459.
But I am still having the issue.
Writing a system daemon with Bluetooth is not my final goal. The bigger picture is the smartcard reader driver with Bluetooth access which as the same issue and the solution is probably related.
I do not remember how but my smartcard reader driver use to work with Bluetooth but it does now with the same Unauthorized
error.
As far as I can see daemon and smartcard drivers does not have support for entitlement.
Here are the logs for my sample system daemon:
my_daemon [0x6000011b0000] activating connection: mach=true listener=false peer=false name=com.apple.server.bluetooth.le.att.xpc
bluetoothd [0x7f804828e8a0] activating connection: mach=false listener=false peer=true name=com.apple.server.bluetooth.le.att.xpc.peer[76672].0x7f804828e8a0
bluetoothd Received XPC message "CBMsgIdCheckIn" from session ""
bluetoothd Received XPC check-in from session "my_daemon-5555494498236e3b5e2e395b93c13af176769937-peripheral-76672-67" fAccessLevel 0 fProgrammaticPairing 0 fLimitedForMediaAccess 0
bluetoothd Access level is less than kXPCAccessLevelSystem for session "my_daemon-5555494498236e3b5e2e395b93c13af176769937-peripheral-76672-67". Restricted state operation not allowed
bluetoothd Sending 'session attached' event for session "my_daemon-5555494498236e3b5e2e395b93c13af176769937-peripheral-76672-67"
bluetoothd Attached session for "my_daemon-5555494498236e3b5e2e395b93c13af176769937-peripheral-76672-67" with session: 0x7f804802d1b0, session handle: 0xef8d0000
bluetoothd Registering peripheral session "my_daemon-5555494498236e3b5e2e395b93c13af176769937-peripheral-76672-67" with backgrounding: off, persistence: off (CBSR) restoreID: (null)
bluetoothd Error getting Application State for <private>: <private>, 3
bluetoothd Error getting Application State for <private>: <private>, 3
bluetoothd Session "my_daemon-5555494498236e3b5e2e395b93c13af176769937-peripheral-76672-67" tccRequired : 1
bluetoothd ReadyForTCC. TCC required:1 fLimitedForMediaAccess:0 fDeviceAccessForMediaExtension:0
bluetoothd Session "my_daemon-5555494498236e3b5e2e395b93c13af176769937-peripheral-76672-67" : needsRestrictedStateOperation = 0, overrideRestrictedState = 0 , denylistMode = 0, receivesControllerBTClockEvents=0
my_daemon Received CBMsgIdReadyForTCC
my_daemon Running performTccCheck CBManager tccAvail 1, tccRequired 1
my_daemon TCC required
my_daemon [0x6000011b8000] activating connection: mach=true listener=false peer=false name=com.apple.tccd
my_daemon [0x6000011b8000] failed to do a bootstrap look-up: xpc_error=[3: No such process]
my_daemon [0x6000011b8000] invalidated after a failed init
my_daemon send_message_with_reply(): user tccd unavailable, sending 0x600000ab4000 to system tccd
my_daemon [0x6000011b4000] activating connection: mach=true listener=false peer=false name=com.apple.tccd.system
tccd [0x7fd4d1f7ed80] activating connection: mach=false listener=false peer=true name=com.apple.tccd.system.peer[76672].0x7fd4d1f7ed80
tccd REQUEST: tccd_uid=0, sender_pid=76672, sender_uid=0, sender_auid=-1, function=TCCAccessRequest, msgID=76672.1
tccd AUTHREQ_CTX: msgID=76672.1, function=<private>, service=kTCCServiceBluetoothAlways, preflight=no, query=1, client_dict=(null), daemon_dict=<private>
tccd AUTHREQ_ATTRIBUTION: msgID=76672.1, attribution={requesting={TCCDProcess: identifier=my_daemon-5555494498236e3b5e2e395b93c13af176769937, pid=76672, auid=0, euid=0, binary_path=/Users/olivier/daemon/my_daemon}, },
tccd AUTHREQ_SUBJECT: msgID=76672.1, subject=/Users/olivier/daemon/my_daemon,
tccd Refusing TCCAccessRequest for service kTCCServiceBluetoothAlways from client Sub:{/Users/olivier/daemon/my_daemon}Resp:{TCCDProcess: identifier=my_daemon-5555494498236e3b5e2e395b93c13af176769937, pid=76672, auid=0, euid=0, binary_path=/Users/olivier/daemon/my_daemon} in background session
tccd AUTHREQ_RESULT: msgID=76672.1, authValue=0, authReason=5, authVersion=1, error=(null),
tccd REPLY: (0) function=TCCAccessRequest, msgID=76672.1
my_daemon [0x6000011b4000] invalidated after the last release of the connection object
bluetoothd Received XPC message "CBMsgIdTCCDone" from session "my_daemon-5555494498236e3b5e2e395b93c13af176769937-peripheral-76672-67"
tccd [0x7fd4d1f7ed80] invalidated after getting a no-senders notification - client is gone
bluetoothd [0x7f80482820f0] activating connection: mach=true listener=false peer=false name=com.apple.tccd.system
tccd [0x7fd4d32585f0] activating connection: mach=false listener=false peer=true name=com.apple.tccd.system.peer[169].0x7fd4d32585f0
tccd REQUEST: tccd_uid=0, sender_pid=169, sender_uid=0, sender_auid=-1, function=TCCAccessRequest, msgID=169.48
tccd [0x7fd4d313d880] activating connection: mach=true listener=false peer=false name=com.apple.tccd
tccd [0x7fd4d313d880] failed to do a bootstrap look-up: xpc_error=[3: No such process]
bluetoothd [0x7f80482820f0] invalidated after the last release of the connection object
bluetoothd Bluetooth user permission alwaysAuth: denied
tccd [0x7fd4d313d880] invalidated after a failed init
tccd FORWARD: to=com.apple.tccd/0, request: {
require_purpose=<xpc_null>
service="kTCCServiceBluetoothAlways"
function="TCCAccessRequest"
preflight=true
target_token={pid:76672, auid:-1, euid:0}
TCCD_MSG_ID="169.48"
background_session=false
}
tccd REPLY: from=com.apple.tccd, reply: {
XPCErrorDescription="Connection invalid"
}
tccd forwardMessage error: Connection invalid.
tccd [0x7fd4d3152bf0] activating connection: mach=false listener=false peer=true name=com.apple.tccd.system.peer[169].0x7fd4d3152bf0
bluetoothd [0x7f80482820f0] activating connection: mach=true listener=false peer=false name=com.apple.tccd.system
tccd REQUEST: tccd_uid=0, sender_pid=169, sender_uid=0, sender_auid=-1, function=TCCAccessRequest, msgID=169.49
tccd [0x7fd4d32585f0] invalidated after getting a no-senders notification - client is gone
tccd [0x7fd4d1f4c810] activating connection: mach=true listener=false peer=false name=com.apple.tccd
tccd [0x7fd4d1f4c810] failed to do a bootstrap look-up: xpc_error=[3: No such process]
tccd [0x7fd4d1f4c810] invalidated after a failed init
tccd FORWARD: to=com.apple.tccd/0, request: {
require_purpose=<xpc_null>
service="kTCCServiceBluetoothAlways"
function="TCCAccessRequest"
preflight=true
target_token={pid:76672, auid:-1, euid:0}
TCCD_MSG_ID="169.49"
background_session=false
}
tccd REPLY: from=com.apple.tccd, reply: {
XPCErrorDescription="Connection invalid"
}
tccd forwardMessage error: Connection invalid.
Accessing Bluetooth is protected behind user level TCC (Transparency, Consent, and Control) prompts, which requires the requesting app to be running in a user context.
Therefore is not possible to use Bluetooth from a system level daemon.
Your best bet would be to separate the Bluetooth functionality into a user level component, perhaps a user agent, and communicate between your daemon and your process interacting with Bluetooth. If there are specific actions the daemon needs to take, it can delegate them to the user level process.
These are somewhat recent changes to Bluetooth security, so you may have observed the driver working before they have been implemented.