;;; Sandbox rules for Contacts.framework clients
;;; 
;;; Usage:
;;; (import "contacts.sb")
;;; ...
;;; (contacts-client <HOME> <DARWINDIR>)

(version 3)

;;; Parameters:
;;; 1. _home  : string containing the (realpath'ed) home directory
;;; 2. _darwin: string containing a (realpath'ed) Darwin user directory
;;;             (doesn't matter which one, as long as it contains the Darwin base directory)
;;;
;;; Usage:
;;; (contacts-client (param "HOME") (param "DARWIN_TEMP_DIR"))
(define (contacts-client _home _darwin)
  
  ;; All clients need to check access with TCC
  (allow mach-lookup (global-name "com.apple.tccd"))

  ;; Does not require clients to have TCC access granted
  (allow mach-lookup (global-name "com.apple.contactsd.contact-provider"
                                  "com.apple.contactsd.support.contact-provider"))
  
  ;; Requires clients to have TCC access granted
  (with-filter (extension "com.apple.tcc.kTCCServiceAddressBook")
    
    (allow mach-lookup
           (global-name "com.apple.AddressBook.abd"
                        "com.apple.AddressBook.AddressBookApplicationFrameworkIPC"
                        "com.apple.AddressBook.AssistantService"
                        "com.apple.AddressBook.ContactsAccountsService"
                        "com.apple.AddressBook.SourceSync"
                        "com.apple.contacts.account-caching"
                        "com.apple.contacts.poster.api"
                        "com.apple.ContactsAgent.addressbook"
                        "com.apple.contactsd.bookkeeping"
                        "com.apple.contactsd.persistence"
                        "com.apple.contactsd.support"))

    ;; Because Contacts soft links IMCore, duplicating some of
    ;; IMCore's sandbox-on-link logic, allowing access to imagent's
    ;; mach ports if we have one of the relevant entitlements
    (with-filter (require-any (require-entitlement "com.apple.imagent")
                              (require-entitlement "com.apple.private.imagent")
                              (require-entitlement "com.apple.private.imcore.imagent")
                              (require-entitlement "com.apple.imagent.av")
                              (require-entitlement "com.apple.imagent.chat"))
      (allow mach-lookup
        (global-name "com.apple.imagent.desktop.auth"
                     "com.apple.imagent.embedded.auth")))

    (allow user-preference-read user-preference-write
           (preference-domain "com.apple.AddressBook"))
    
    ; Home directory
    (let
      ((_home-subpath
        (lambda (home-rel-subpath)
          (subpath (string-append _home home-rel-subpath))))
       (_home-regex
        (lambda (home-relative-regex)
         (regex (string-append "^" (regex-quote _home) home-relative-regex)))))
        (allow file-read* file-write*
             (_home-subpath "/Library/Application Support/AddressBook/Metadata/.info")
             (_home-regex "/Library/Application Support/AddressBook/Sources/[A-Fa-f0-9-]*/Metadata/.info")
             (_home-subpath "/Library/Images/People"))
        (with-filter
              (require-entitlement "com.apple.private.contacts.disable-remote-database-access")
              (allow file-read*
                     file-write*
                     (_home-subpath "/Library/Application Support/AddressBook")))
      (allow file-issue-extension
             (require-all
               (_home-subpath "/Library/Images/People")
               (extension-class "com.apple.app-sandbox.read"
                                "com.apple.app-sandbox.read-write"))))
    
    ; Darwin ==> AddressBook locks directory
    (let*
      ; 1. Darwin user base directory: /private/var/folders/xx/yyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
      ; 2. AddressBook locks         : /private/var/folders/xx/yyyyyyyyyyyyyyyyyyyyyyyyyyyyyy/T/.AddressBookLocks
      ((darwin-base-dir (substring _darwin 0 54))
       (ab-locks-dir (string-append darwin-base-dir "/T/.AddressBookLocks")))
      ; Expand (allow-read-write-directory-contents ab-locks-dir)
      (with-filter (subpath ab-locks-dir)
        (allow file-read*)
        (allow file-issue-extension (extension-class "com.apple.app-sandbox.read")))
      (with-filter (regex (string-append #"^" (regex-quote ab-locks-dir) "/"))
        (allow file-write*)
        (allow file-issue-extension (extension-class "com.apple.app-sandbox.read-write")))
      (with-filter (vnode-type DIRECTORY)
        (allow file-write-create file-write-data
               (literal ab-locks-dir))))
    
    (with-filter
      (require-any
        (subpath "/Library/Images/People")
        (subpath "/System/Library/Images/People")
        (subpath "/Network/Library/Images/People"))
      (allow file-read*)  
      (allow file-issue-extension (extension-class "com.apple.app-sandbox.read")))
    
    ;; Access to plug-in executables
    (allow file-map-executable (subpath "/System/Library/Address Book Plug-Ins/"))
  )

  ;; Prevent apps from persisting access to TCC-protected content via hardlinks.
  (deny file-link
        (subpath "/Library/Images/People")
        (subpath "/System/Library/Images/People")
        (subpath "/Network/Library/Images/People"))

)
