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. $10/mo, with a 21 day free trial.