La tabla access de TCC en las versiones de macOS
Cómo cambió la tabla access de TCC.db de Mojave a Big Sur y Sonoma: allowed y prompt_count, auth_value y auth_reason, pid y last_reminded, y las demás tablas.
Resumen. La tabla access de TCC.db tiene tres formatos principales. Mojave y Catalina: allowed (0/1) y prompt_count. Big Sur (11) y posteriores: auth_value, auth_reason y auth_version las sustituyen, e indirect_object_identifier pasa a ser TEXT NOT NULL DEFAULT 'UNUSED'. Sonoma (14) y posteriores: se añaden pid, pid_version, boot_uuid y last_reminded. Ejecute .schema access en cada copia antes de consultarla. TCC Parser lee los nombres de columna del esquema de cada archivo, así que la misma vista funciona en todas las versiones.
Por qué importa el esquema
Las consultas y los parsers fallan sin avisar cuando el formato no es el esperado. Un script escrito para Big Sur que selecciona auth_value falla con una base de datos de Catalina; uno escrito para Catalina que filtra por allowed = 1 no encuentra nada en Sonoma. El plugin macostcc de Plaso, por ejemplo, requiere las columnas allowed y prompt_count anteriores a Big Sur, así que está pensado para bases de datos de Mojave y Catalina. MacOS.System.TCC de Velociraptor se escribió para Big Sur. Compruébelo primero:
sqlite3 TCC.db '.tables'
sqlite3 TCC.db '.schema access'
Mojave y Catalina (10.14, 10.15)
Según documenta el plugin macostcc de Plaso, la tabla access tiene:
| Columna | Notas |
|---|---|
service | Identificador del servicio TCC |
client | Bundle ID o ruta absoluta |
client_type | 0 bundle ID, 1 ruta absoluta |
allowed | 1 permitido, 0 no permitido |
prompt_count | Cuántas veces se mostró la solicitud al usuario |
csreq | Requisito de código compilado del cliente |
policy_id | Enlace a policies.id en las filas derivadas de una política |
indirect_object_identifier_type, indirect_object_identifier, indirect_object_code_identity | Destino de la concesión (Automatización) |
flags | No documentado |
last_modified | DEFAULT CAST(strftime('%s','now') AS INTEGER), es decir, segundos Unix en UTC |
La clave primaria es (service, client, client_type, indirect_object_identifier). Esa clave explica un comportamiento importante: hay una fila por cliente, servicio y destino, y una decisión nueva sustituye a la fila anterior en lugar de añadir otra. La base de datos guarda el estado actual, no un historial.
Big Sur (11) y posteriores
Big Sur sustituyó allowed y prompt_count por tres columnas:
| Columna | Valores |
|---|---|
auth_value | 0 denegado, 1 desconocido, 2 permitido, 3 limitado |
auth_reason | Por qué se tomó la decisión (ver más abajo) |
auth_version | Versión del formato del registro de autorización |
indirect_object_identifier pasó a ser TEXT NOT NULL DEFAULT 'UNUSED', así que las filas sin destino contienen ahora la cadena literal UNUSED en lugar de un nulo. Tenga en cuenta ese valor al filtrar cuando busque destinos de Automatización.
auth_reason
Apple no documenta estos valores. La correspondencia siguiente está documentada por la comunidad y se usa mucho; léala como una hipótesis y confírmela en un Mac de prueba con la misma versión, o con las entradas de com.apple.TCC del registro unificado, antes de incluirla en un informe.
| auth_reason | Interpretación de la comunidad |
|---|---|
| 1 | Error |
| 2 | Consentimiento del usuario (respondió a una solicitud) |
| 3 | Fijado por el usuario (cambiado en Ajustes del Sistema) |
| 4 | Fijado por el sistema |
| 5 | Política del servicio |
| 6 | Política MDM |
| 7 | Política de anulación |
| 8 | Falta la cadena de uso |
| 9 | Tiempo de espera de la solicitud agotado |
| 10 | Preflight desconocido |
| 11 | Con entitlement |
| 12 | Política por tipo de app |
En la mayoría de los casos, la distinción útil es entre motivos originados por el usuario (2, 3), por una política (5, 6, 7) o por el sistema (4, 11, 12). Glosario: auth_value, auth_reason.
Sonoma (14) y posteriores
Sonoma añadió cuatro columnas:
| Columna | Notas |
|---|---|
pid | Un ID de proceso asociado a la fila |
pid_version | Acompaña a pid |
boot_uuid | Identifica una sesión de arranque |
last_reminded | Segundos de época Unix; valor por defecto en el esquema strftime('%s','now') |
Los nombres sugieren el proceso y la sesión de arranque implicados en la decisión, pero su semántica exacta no está documentada públicamente. Aun así, boot_uuid resulta práctico: permite agrupar filas por sesión de arranque y compararlas con otros artefactos que registran un UUID de arranque. last_reminded es una segunda marca de tiempo para la cronología; en TCC Parser puede cambiar el campo de tiempo entre Last modified, Last reminded y Expired at.
Versiones más recientes
No conocemos documentación pública de cambios en el esquema de access posteriores a Sonoma, incluido macOS 26 Tahoe. Precisamente por eso TCC Parser se guía por el esquema: lee la lista de columnas de cada archivo y decodifica las que reconoce, en lugar de suponer un formato fijo por versión. Si encuentra una columna que este artículo no menciona, compruébela en un sistema de prueba antes de interpretarla.
Las demás tablas
La tabla access se lleva toda la atención, pero la base de datos contiene más. En el esquema de Mojave/Catalina documentado por Plaso:
| Tabla | Columnas | Para qué sirve |
|---|---|---|
admin | key, value | Pequeño almacén clave/valor; contenido no documentado |
policies | id, bundle_id, uuid, display | Políticas referenciadas por access.policy_id (por ejemplo, MDM) |
active_policy | client, client_type, policy_id | Qué política se aplica a qué cliente |
access_overrides | service (clave primaria) | Anulaciones por servicio; función no documentada |
expired | service, client, client_type, csreq, last_modified, expired_at | Concesiones que caducaron, con el momento en que lo hicieron |
Enumere las tablas de su propia copia con .tables: las versiones posteriores pueden diferir. La tabla expired merece una revisión en todos los casos, porque conserva clientes que ya no aparecen en access. Su expired_at está en segundos Unix, igual que last_modified. TCC Parser vincula policy_id con la tabla policies y con MDMOverrides.plist, y muestra REG.db y cualquier otro archivo SQLite de la carpeta com.apple.TCC como tablas en bruto.
Una consulta por formato
Mojave y Catalina:
SELECT service, client, client_type, allowed, prompt_count,
datetime(last_modified, 'unixepoch') AS changed_utc
FROM access ORDER BY last_modified DESC;
Big Sur y posteriores (añada last_reminded en Sonoma y posteriores):
SELECT service, client, client_type, auth_value, auth_reason,
NULLIF(indirect_object_identifier, 'UNUSED') AS target,
datetime(last_modified, 'unixepoch') AS changed_utc
FROM access ORDER BY last_modified DESC;
Ambas devuelven los blobs (csreq, indirect_object_code_identity) como bytes en bruto; su decodificación se explica en decodificar los requisitos de código csreq.
Marcas de tiempo
Todas las marcas de tiempo de TCC.db están en segundos de época Unix, UTC: last_modified, last_reminded y expired.expired_at. No están en Mac absolute time, que usan muchas otras bases de datos de Apple. last_modified es la última escritura en la fila: una solicitud respondida, un interruptor cambiado, una política aplicada. No es la primera concesión.
Preguntas frecuentes
¿Qué versión de macOS sustituyó allowed por auth_value en TCC.db?
macOS 11 Big Sur. Las bases de datos de Mojave y Catalina tienen las columnas allowed y prompt_count; Big Sur y posteriores tienen en su lugar auth_value, auth_reason y auth_version.
¿Qué columnas añadió Sonoma a la tabla access?
macOS 14 Sonoma añadió pid, pid_version, boot_uuid y last_reminded. last_reminded está en segundos de época Unix, igual que last_modified.
¿Apple documenta los valores de auth_reason?
No. La correspondencia de uso común (1 error, 2 consentimiento del usuario, 3 fijado por el usuario, 4 fijado por el sistema, 5 política del servicio, 6 política MDM, 7 política de anulación, 8 falta la cadena de uso, 9 tiempo de espera de la solicitud agotado, 10 preflight desconocido, 11 con entitlement, 12 política por tipo de app) procede de la investigación de la comunidad. Confírmela en un sistema de prueba antes de apoyarse en ella.
¿Por qué falla mi consulta en un TCC.db antiguo?
Porque la columna que seleccionó no existe en ese esquema. Ejecute primero .schema access y escriba la consulta con las columnas que realmente existen.