A deep dive into what the TCC database contains and the meaning of the various fields present in it.
What is TCC?
TCC (Transparency, Consent, and Control) is a mechanism in macOS to limit and control application access to certain features, usually from a privacy perspective. This can include things such as location services, contacts, photos, microphone, camera, accessibility, full disk access, and a bunch more. TCC was introduced with OSX Mavericks and has gone through a number of changes since to expand what it has control over. TCC also appears to exist and provide the same functionality on iOS, but in this post we’ll only be looking at TCC on macOS.
Why write this?
TCC is an end-user protection feature, and tends to get in the way when you’re trying to provision machines in an automatic manner without user interaction. Part of the RainforestQA service is that we run all tests in fresh VMs that we keep up-to-date, and to do this we want to automate as much of the VM build process as possible and we don’t want to babysit the build process to click “allow” when dialogs pop up. Instead we would rather have a reliable way of manipulating TCC to grant access programatically with zero human interaction. TCC is not very well documented and the information you can find on it is scattered about the web with various levels of completeness.
TCC for the User
From a user’s perspective, they see TCC in action when an application wants access to one of the features protected by TCC. When this happens the user is prompted with a dialog asking them whether they want to allow access or not. This response is then stored in the TCC database.
Users can also use the System Preferences to manipulate TCC.
The TCC Database(s)
The TCC database is just a sqlite3 database, which makes the task of investigating it much simpler. There are two different databases, a global one in /Library/Application Support/com.apple.TCC/TCC.db and a per-user one located in /Users/<username>/Library/Application Support/com.apple.TCC/TCC.db. These databases are protected from editing with SIP(System Integrity Protection), but you can read them by granting terminal(or your editor) full disk access.
TCC Database Schema
As TCC has evolved over the years the database schema has changed as well. The database contains a few tables but the one we’re most interested in is the access table. Dumping the schema with sqlite gives us the following:
CREATE TABLE access (
service TEXT NOT NULL,
client TEXT NOT NULL,
client_type INTEGER NOT NULL,
-- allowed INTEGER NOT NULL, -- Removed in Big Sur
-- prompt_count INTEGER NOT NULL, -- Removed in Big Sur
auth_value INTEGER NOT NULL, -- Added in Big Sur
auth_reason INTEGER NOT NULL, -- Added in Big Sur
auth_version INTEGER NOT NULL, -- Added in Big Sur
-- Added in Mojave
indirect_object_identifier TEXT NOT NULL DEFAULT "UNUSED",
last_modified INTEGER NOT NULL DEFAULT (CAST(strftime('%s','now') AS INTEGER))
Lets take a look at these fields and what they actually mean:
service - What service access is being restricted to. E.g. kTCCServiceMicrophone. See below for a full list of services.
client - Bundle Identifier or absolute path to the program that wants to use service (e.g. com.apple.finder or /usr/libexec/sshd-keygen-wrapper)
client_type - For the previous value, whether it’s a Bundle Identifier(0) or an absolute path(1)
allowed - (Prior to big sur) Whether to allow access(1) to this service or deny it(0)
prompt_count - (Prior to big sur) How many times the user has been prompted about this access. Programs can repeatedly prompt if they are not granted access the first time so this can be used to track if that’s happening.
auth_value - Whether the access is denied(0), unknown(1), allowed(2), or limited(3). An example for limited access: an application might be allowed ask the user to select some photos, but without being granted access to the User’s entire Photo library. It’s unclear if this is actually implemented in macOS or if this is a carryover from iOS.
auth_version - Always 1. Since these auth_* fields are new with macOS Big Sur, this seems expected. Presumably this will change with future macOS releases.
csreq - Binary code signing requirement blob that the client must satisfy in order for access to be granted. This is used to prevent spoofing/impersonation if another program uses the same bundle identifier. There’s an excellent stack overflow answer(written by yours truly) that covers how this field can be decoded(or generated).
policy_id - I believe this is related to MDM(Mobile Device Management) policies, which can be used by organizations to allow TCC access for some applications at a global level. Policies are not able to automatically grant camera or microphone access however. One tool that can generate these profiles is github.com/carlashley/tccprofile.
indirect_object_identifier - For some services (kTCCServiceAppleEvents) this is what the client is asking to interact with. It’s an absolute path or bundle identifier just like client. This will be set to UNUSED in cases where it doesn’t make sense.
indirect_object_identifier_type - For the previous value, whether it’s a Bundle Identifier(0) or an absolute path(1)
indirect_object_code_identity - Same as csreq, but for the indirect_object_identifier instead of client.
flags - I wasn’t able to find any documentation on this, and it always seems to be 0. I believe it is likely used along with the MDM policies.
last_modified - The last time this entry was modified(seconds since the start of the unix epoch)
Simple summary of the above
Each row in the table basically says:
The program client identified by csreq is allowed/disallowed/limited/unknown [set by auth_value] to use service [with a target of indirect_object_identifier identified by indirect_object_code_identity]
An example entry
This is what you might find in the database if you granted Terminal “Full Disk Access”:
com.apple.terminal is allowed (2) access to kTCCServiceSystemPolicyAllFiles(Full Disk Access) because “User Set”(3).
The fade0c... represents the csreq blob, and decoded it would read: identifier "com.apple.Terminal" and anchor apple (Refer to this stack overflow answer for how to decode this). This means that the application needs to have the bundle identifier com.apple.Terminal and it needs to be signed by Apple. This prevents anyone from creating their own application with that bundle identifier and gaining access to everything the user has granted to terminal.
Understanding the TCC database allows numerous possibilities. It becomes trivial to audit what access has been granted. It also allows one to manipulate the database to authorize permissions without requiring user interaction(e.g. during testing).
At RainforestQA, we use this functionality when configuring our macOS machines to authorize access for our command and control scripts. This allows us to completely automate the installation and maintenance of our macOS fleet, saving us countless hours and making upgrades and maintenance a simple task.
The following is a complete list of possible values for auth_reason and service.
I was unable to find any documentation around auth_value or auth_reason. Using the demo version of Hopper Dissassembler I loaded up /System/Library/PrivateFrameworks/TCC.framework/Versions/A/Resources/tccd and found some references to these fields that gave me clues as to what the possible values are.
auth_reason can take the following values: 1 - Error 2 - User Consent 3 - User Set 4 - System Set 5 - Service Policy 6 - MDM Policy 7 - Override Policy 8 - Missing usage string 9 - Prompt Timeout 10 - Preflight Unknown 11 - Entitled 12 - App Type Policy
It is possible to inspect the localizable strings for the tcc framework to determine what (some) of the valid services are. Using this command:
...gives us the following list of services along with what the user will be prompted with when access is requested.
kTCCServiceAddressBook - client would like to access your contacts.
kTCCServiceAppleEvents - client wants access to control indirect_object. Allowing control will provide access to documents and data in indirect_object, and to perform actions within that app.
kTCCServiceBluetoothAlways - client would like to use Bluetooth.
kTCCServiceCalendar - client would like to access your calendar.
kTCCServiceCamera - client would like to access the camera.
kTCCServiceContactsFull - client would like to access all of your contacts information.
kTCCServiceContactsLimited - client would like to access your contacts basic information.
kTCCServiceFileProviderDomain - client wants to access files managed by indirect_object.
kTCCServiceFileProviderPresence - Do you want to allow client to see when you are using files managed by it? It will see which applications are used to access files and whether you are actively using them. It will not see when files that are not managed by it are accessed.
kTCCServiceLocation - client would like to use your current location.
kTCCServiceMediaLibrary - client would like to access Apple Music, your music and video activity, and your media library.
kTCCServiceMicrophone - client would like to access the microphone.
kTCCServiceMotion - client Would Like to Access Your Motion & Fitness Activity.
kTCCServicePhotos - client Would Like to Access Your Photos
kTCCServicePhotosAdd - client Would Like to Add to your Photos
kTCCServicePrototype3Rights - client Would Like Authorization to Test Service Proto3Right.
kTCCServicePrototype4Rights - client Would Like Authorization to Test Service Proto4Right.
kTCCServiceReminders - client would like to access your reminders.
kTCCServiceScreenCapture - client would like to capture the contents of the system display.
kTCCServiceSiri - Would You Like to Use client with Siri?
kTCCServiceSpeechRecognition - client Would Like to Access Speech Recognition.
kTCCServiceSystemPolicyDesktopFolder - client would like to access files in your Desktop folder.
kTCCServiceSystemPolicyDeveloperFiles - client would like to access a file used in Software Development.
kTCCServiceSystemPolicyDocumentsFolder - client would like to access files in your Documents folder.
kTCCServiceSystemPolicyDownloadsFolder - client would like to access files in your Downloads folder.
kTCCServiceSystemPolicyNetworkVolumes - client would like to access files on a network volume.
kTCCServiceSystemPolicyRemovableVolumes - client would like to access files on a removable volume.
kTCCServiceSystemPolicySysAdminFiles - client would like to administer your computer. Administration can include modifying passwords, networking, and system settings.
kTCCServiceWillow - client would like to access your Home data.
Some other values(from running strings on tccd binary, observation, and other places online):
kTCCServiceSystemPolicyAllFiles - Full Disk Access
kTCCServiceAccessibility - Allows app to control your computer
kTCCServicePostEvent - Allows to send keystrokes
kTCCServiceListenEvent - Input Monitoring; to monitor input from your keyboard
kTCCServiceDeveloperTool - Allows app to run software locally that do not meet the system’s security policy
These seem to be carry-overs from iOS, and may not apply on macOS:
kTCCServiceLiverpool - Related to location services
kTCCServiceUbiquity - Related to iCloud
kTCCServiceShareKit - Related to the share feature(presumably from iOS)(ShareKit)
There’s also some for specific social networks; again I suspect this is a carry-over from iOS.
We’ve been using Heroku extensively at Rainforest QA since early 2012 to run our automated QA testing service. It’s stable, it makes economic sense, and it precisely suits our needs. Here are the main arguments I hear against Heroku, and why I think they are (mostly) fallacious.