When building a Content Filter System extension for Mac OS, the instance of NEFilterFlow
you receive in your NEFilterDataProvider
class doesn't have much information (apart from the not-to-be-relied-upon flow.description
string). Deriving useful data from these objects is tricky, and poorly documented.
One thing I wanted to know was how to trace the flow back to a user on the system. The flow has a process id (at least, the description shows that it knows about the pid), so this info should be derivable. Turns out there is another almost entirely undocumented low-level function you can call into to get this info: audit_token_to_ruid()
. Thanks to Quinn and Matt on this thread for pointing me in the right direction. Here's some working code from my implementation, using the sourceAppAuditToken
of the NEFilterFlow
instance to derive the user id:
import Foundation protocol SourceAppAuditor { func userId(fromAuditToken auditToken: Data?) -> uid_t? } class CachingSourceAppAuditor: SourceAppAuditor { private var userIdMap: [Data: uid_t] = [:] func userId(fromAuditToken auditToken: Data?) -> uid_t? { guard let auditToken = auditToken else { return nil } if let cached = userIdMap[auditToken] { return cached } guard auditToken.count == MemoryLayout<audit_token_t>.size else { return nil } let tokenT: audit_token_t? = auditToken.withUnsafeBytes { buf in guard let baseAddress = buf.baseAddress else { return nil } return baseAddress.assumingMemoryBound(to: audit_token_t.self).pointee } guard let token = tokenT else { return nil } let userId = audit_token_to_ruid(token) userIdMap[auditToken] = userId return userId } }
A couple of notes:
uid_t
is a #define
typedef for UInt32
(at least on Catalina). It represents a numeric user id.500
. This was a useful bit of errata, for my case.[Data: uid_t]
dictionary, which Quinn says in some thread, is a reasonable thing to do, as the same apps will keep providing the same source app audit token.The Gertrude mac app helps you protect your kids online with strict internet filtering that you can manage from your own computer or phone, plus remote monitoring of screenshots and keylogging. $5/mo, with a 60 day free trial.