Issue
When using the nio-ssh library to execute ssh commands in a daemonized context (built executable launched using launchctl with a config in /Library/LaunchDaemons) a ChannelError (operationUnsupported) is thrown.
I'm unsure if this is a problem just with nio-ssh or nio in general. Could it be that certain network operations aren't permitted from within a daemon?
Any information/help on this matter is greatly appreciated!
Related issue in the nio-ssh repository: https://github.com/apple/swift-nio-ssh/issues/166
Unfortunately there are no specific tags for these libraries (nio, nio-ssh) or for daemons, so I have used the Network tag instead.
Reproduction
Reproduction can be found here: https://github.com/eliaSchenker/nio-ssh-daemon-issue/tree/main
To run the reproduction follow these steps:
- Build using Xcode (Product > Build)
- Find the executable in the build folder (Product > Show Build Folder in Finder)
- Move the executable to
/Library/PrivilegedHelperTools
- Create a daemon configuration in
/Library/LaunchDaemons/nio-ssh-daemon.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>nio-ssh-daemon</string>
<key>ProgramArguments</key>
<array>
<string>/Library/PrivilegedHelperTools/nio-ssh-daemon</string>
<string>username:password@host</string>
<string>ls -la</string>
</array>
<key>KeepAlive</key>
<true/>
<key>ProcessType</key>
<string>Interactive</string>
<key>StandardOutPath</key>
<string>/Library/Logs/nio-ssh-daemon.out.log</string>
<key>StandardErrorPath</key>
<string>/Library/Logs/nio-ssh-daemon.err.log</string>
</dict>
</plist>
making sure to adjust the program arguments to include an host with username and password.
- Load the daemon using
sudo launchctl load nio-ssh-daemon.plist
- When opening
Console.app
, navigating toLog Reports
and openingnio-ssh-daemon.out.log
the logged error will be shown:
Creating bootstrap
Connecting channel
Creating child channel
Waiting for connection to close
Error in pipeline: operationUnsupported
An error occurred: commandExecFailed
If the executable is run manually without a daemon it will work correctly:
./nio.ssh-daemon username:password@host
The reproduction is a copy of the example in the repository (https://github.com/apple/swift-nio-ssh/tree/main/Sources/NIOSSHClient) with slight modifications to log errors instead of using try!
.
With some help from a contributor (Lukasa) I was able to adjust the example to work on a daemon. The problem was that the example binds itself to the stdout (writing the response of the ssh command to it). As the stdout is bound to a file in a daemon and the bootstrap includes a check that the output is not a file, an error would occur.
For anyone else experiencing this issue in the future, I've updated the reproduction to include the solution: https://github.com/eliaSchenker/nio-ssh-daemon-issue/tree/main