All the following has been validated on MacOS Mojave 10.14.6
While there is a command line preference to accept only local VNC connections, that setting still doesn't prevent the daemon from listening to the wildcard address, and advertise the service on Bonjour. I haven't actually tried to see if it restricted anything in modern versions of the operating system, but here it is for reference:
sudo defaults write /Library/Preferences/com.apple.RemoteManagement.plist VNCOnlyLocalConnections -bool yes
The LaunchDaemon located at /System/Library/LaunchDaemons/com.apple.screensharing.plist
is responsible for both offences:
<key>Sockets</key>
<dict>
<key>Listener</key>
<dict>
<key>Bonjour</key>
<string>rfb</string>
<key>SockServiceName</key>
<string>vnc-server</string>
</dict>
</dict>
Unfortunately editing that file in not possible because System Integrity Protection prevents modifying any files in /System
.
The alternative is to create a new LaunchDaemon in /Library
. Unfortunately the screen sharing agent will not work properly when assigned a different label. That means the daemon has to be "shadowing" the original using the same name. That causes it's own problems because on reboot, the system will load the original in /System
and ignore the modified version in /Library
.
The solution is to disable the LaunchDaemon and use a "launcher" daemon that will forcibly load the modified LaunchDaemon. However care must be taken to still activate Screen Sharing through the preferences orelse it will endup in observe only mode.
- Activate Screen Sharing in the System Preferences
sudo launchctl unload -w /System/Library/LaunchDaemons/com.apple.screensharing.plist
sudo cp /System/Library/LaunchDaemons/com.apple.screensharing.plist /Library/LaunchDaemons/com.apple.screensharing.plist
- In
/Library/LaunchDaemons/com.apple.screensharing.plist
, edit the Sockets section to look like:
<key>Sockets</key>
<dict>
<key>Listener</key>
<dict>
<key>SockNodeName</key>
<string>localhost</string>
<key>SockServiceName</key>
<string>vnc-server</string>
</dict>
</dict>
- Create
/Library/LaunchDaemons/com.apple.screensharing.launcher.plist
with the following content:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.apple.screensharing.launcher</string>
<key>LaunchOnlyOnce</key>
<true/>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<false/>
<key>ProgramArguments</key>
<array>
<string>/bin/launchctl</string>
<string>load</string>
<string>-F</string>
<string>/Library/LaunchDaemons/com.apple.screensharing.plist</string>
</array>
</dict>
</plist>
sudo launchctl load -w /Library/LaunchDaemons/com.apple.screensharing.launcher.plist
The Screen Sharing client prevents connecting to localhost. It's probably to avoid screen sharing recursion. However, MacOS screen sharing is capable of accessing the screen of a user not logged in on the console, but by default we can't take advantage of this to show the loginwindow of another local user, for example on a second monitor.
The solution is to make the agent listen on a different port than the default.
- Replace
vnc-server
by a port number different from the default inSockServiceName
:
<key>SockServiceName</key>
<string>5901</string>
- Open a connection to
vnc://otheruser@localhost:5901
- After entering your password, select
Login as yourself
- Run GUI applications for 2 users at once without switching.