1

I'm trying to run pluginkit (The executable that manages extensions on OS X) from a launch daemon running as root.

/usr/bin/pluginkit -m -i "<identifier>" fails with an output of match: Connection invalid. This is not terribly unexpected, since extension settings are handled on a per-user basis.

However, I've tried to use su to run pluginkit as a normal user, and it still doesn't work.

su <username> -l -c "/usr/bin/pluginkit -m -i "<identifier>" also fails with an output of match: Connection invalid.

Somehow the environment that pluginkit is running in is still different enough from a normal user that it doesn't work properly. Is there anyway to run pluginkit as root? Or is there any other way to launch a process as another user that might provide a more complete environment?

I'm testing this with a command line tool written in Swift:

main.swift

import Foundation

let task = NSTask()

// Option 1: Run pluginkit directly
task.launchPath="/usr/bin/pluginkit"
task.arguments = ["-m", "-i", "com.example.findersyncext"]

// Option 2: Run pluginkit as <username> using 'su'
//task.launchPath="/usr/bin/su"
//task.arguments = ["<username>", "-l", "-c", "/usr/bin/pluginkit -m -i \"com.example.findersyncext\""]

// Option 3: Run pluginkit as <username> using 'sudo'
//task.launchPath="/usr/bin/sudo"
//task.arguments = ["-u", "<username>", "/usr/bin/pluginkit", "-m", "-i", "com.example.findersyncext"]

task.standardOutput = NSPipe()
task.standardError = NSPipe()
task.launch()
task.waitUntilExit()

NSLog("Exit code: \(task.terminationStatus)")
let output = NSString(data: (task.standardOutput!.fileHandleForReading.readDataToEndOfFile()), encoding: NSUTF8StringEncoding)
NSLog("Output: \(output)")

let error = NSString(data: (task.standardError!.fileHandleForReading.readDataToEndOfFile()), encoding: NSUTF8StringEncoding)
NSLog("Error: \(error)")

/Library/LaunchDaemons/com.example.PluginKitTest.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.example.PluginKitTest</string>
    <key>Program</key>
    <string>/path/to/PluginKitTest</string>
    <key>RunAtLoad</key>
    <true/>
    <key>StandardErrorPath</key>
    <string>/Users/<username>/Desktop/pluginkit-error.log</string>
    <key>StandardOutPath</key>
    <string>/Users/<username>/Desktop/pluginkit-out.log</string>
</dict>
</plist>
Chris Vasselli
  • 13,064
  • 4
  • 46
  • 49

1 Answers1

1

It turns out that there is additional user context that is not set by the su command, that needs to be set by using the command launchctl asuser. So, I was able to solve my problem by updating my command to invoke both launchctl asuser and su to update all aspects of the context:

launchctl asuser $USER_UID su $USER_UID -c "<command>"

According to the documentation of launchctl asuser:

Adopted attributes include the Mach bootstrap namespace, exception server and security audit session.

I'm not familiar enough with these concepts to tell you exactly what these do, but it was enough to get pluginkit working.

Chris Vasselli
  • 13,064
  • 4
  • 46
  • 49
  • Thanks a bunch for the mention, trying it out in a few hours. Curious what did you search for just before finding it? – StefanS Aug 11 '17 at 04:27
  • Did you enable the root user programatically? https://support.apple.com/en-us/HT204012 Because the su command fails by default "Sorry". – StefanS Aug 11 '17 at 09:39
  • No, I never did anything like that. I just setup the command to run as a launch daemon. I don't remember ever encountering an issue where su responds "sorry". Sorry I can't give any more help! – Chris Vasselli Aug 13 '17 at 20:01
  • It's fine, figured it out, thanks a bunch for the help! Who knows how much time you saved me. Regards – StefanS Aug 13 '17 at 20:02