Repository: ubuntu/WSL (language: go)

Issue:
Disable SSHD service in Ubuntu 20.04
Focal is shipped with OpenSSH server, whose systemd service fails to start because the setup process doesn’t setup the host key. This short-term solution disables the service, and the long-term solution will be to remove the openssh package from the seed.

UDENG-286


Discussion / hints:
> Also, this is cross-releases, so we will have that issue spread across all releases?

It only affects 18.04.

>  but what will happen if someone wants then to install/reconfigure openssh-server later on?

That is a good point. Maybe we should just take the slow approach and fix it on the rootfs directly.

> > Also, this is cross-releases, so we will have that issue spread across all releases?
> 
> It only affects 18.04.
> 

Actually it affects 20.04.

> > but what will happen if someone wants then to install/reconfigure openssh-server later on?
> 
> That is a good point. Maybe we should just take the slow approach and fix it on the rootfs directly.

We can patch the system file (`/lib/systemd/system/ssh.service`) to disable the service completely. Whenever apt installs or reinstalls the package, the file will be overwritten by whatever comes with the package. Here's an example (but it doesn't have to be exactly that).

```
u@Zero01:~$ sudo bash -ec 'echo -e "[boot]\nsystemd=true" > /etc/wsl.conf'
u@Zero01:~$ sudo sed -i '5i ConditionVirtualization=!container' /lib/systemd/system/ssh.service
u@Zero01:~$ cat /lib/systemd/system/ssh.service
[Unit]
Description=OpenBSD Secure Shell server
Documentation=man:sshd(8) man:sshd_config(5)
After=network.target auditd.service
ConditionVirtualization=!container
ConditionPathExists=!/etc/ssh/sshd_not_to_be_run

[Service]
EnvironmentFile=-/etc/default/ssh
ExecStartPre=/usr/sbin/sshd -t
ExecStart=/usr/sbin/sshd -D $SSHD_OPTS
ExecReload=/usr/sbin/sshd -t
ExecReload=/bin/kill -HUP $MAINPID
u@Zero01:~$ exit

POWESHELL:>$ ubuntu2004.exe                                                                                                                                                                        
u@Zero01:~$ systemctl status ssh
● ssh.service - OpenBSD Secure Shell server
     Loaded: loaded (/lib/systemd/system/ssh.service; enabled; vendor preset: enabled)
     Active: inactive (dead)
  Condition: start condition failed at Wed 2023-05-10 12:00:12 -03; 11s ago
       Docs: man:sshd(8)
             man:sshd_config(5)

May 10 12:00:12 Zero01 systemd[1]: Condition check resulted in OpenBSD Secure Shell server being skipped.

u@Zero01:~$ sudo apt install --reinstall openssh-server
[sudo] password for u:
Reading package lists... Done
Building dependency tree
Reading state information... Done
0 upgraded, 0 newly installed, 1 reinstalled, 0 to remove and 0 not upgraded.
Need to get 377 kB of archives.
After this operation, 0 B of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 openssh-server amd64 1:8.2p1-4ubuntu0.5 [377 kB]
Fetched 377 kB in 2s (239 kB/s)
Preconfiguring packages ...
(Reading database ... 32685 files and directories currently installed.)
Preparing to unpack .../openssh-server_1%3a8.2p1-4ubuntu0.5_amd64.deb ...
Unpacking openssh-server (1:8.2p1-4ubuntu0.5) over (1:8.2p1-4ubuntu0.5) ...
Setting up openssh-server (1:8.2p1-4ubuntu0.5) ...
Creating SSH2 RSA key; this may take some time ...
3072 SHA256:0Ank/ryU7F4ET95RlPwBgE8F/iAWGdZCTov+RbszkZg root@Zero01 (RSA)
Creating SSH2 ECDSA key; this may take some time ...
256 SHA256:r5eH8Mylyu6Ndukb4fISs9jRw0dIhVVarbPDfDj78D8 root@Zero01 (ECDSA)
Creating SSH2 ED25519 key; this may take some time ...
256 SHA256:KNZPY2JUvcg3wKurdllEEuEMHS9PgKQmrPsHhO+T9ZE root@Zero01 (ED25519)
rescue-ssh.target is a disabled or a static unit, not starting it.
Processing triggers for systemd (245.4-4ubuntu3.21) ...
Processing triggers for man-db (2.9.1-1) ...
Processing triggers for ufw (0.36-6ubuntu1) ...
u@Zero01:~$ systemctl status ssh
● ssh.service - OpenBSD Secure Shell server
     Loaded: loaded (/lib/systemd/system/ssh.service; enabled; vendor preset: enabled)
     Active: active (running) since Wed 2023-05-10 12:00:42 -03; 4s ago
       Docs: man:sshd(8)
             man:sshd_config(5)
   Main PID: 1592 (sshd)
      Tasks: 1 (limit: 19098)
     Memory: 2.2M
     CGroup: /system.slice/ssh.service
             └─1592 sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups

May 10 12:00:42 Zero01 systemd[1]: Starting OpenBSD Secure Shell server...
May 10 12:00:42 Zero01 sshd[1592]: Server listening on 0.0.0.0 port 22.
May 10 12:00:42 Zero01 sshd[1592]: Server listening on :: port 22.
May 10 12:00:42 Zero01 systemd[1]: Started OpenBSD Secure Shell server.
u@Zero01:~$
```
Notice that on (re)install, the host key is created, so the service won't fail anymore.
> Focal (the one affected by the SSH issue) is 20.04 (18.04 is bionic) :)

Yeah I got confused about which one is affected 😓

In the end I chose to append the `ConditionVirtualization=!container` line at the end of the service file.
Looks like the latest Flutter release is breaking the CI. :(

Fix patch:
diff --git a/DistroLauncher/ApplyConfigPatches.cpp b/DistroLauncher/ConfigRootFs.cpp
similarity index 65%
rename from DistroLauncher/ApplyConfigPatches.cpp
rename to DistroLauncher/ConfigRootFs.cpp
index 32685d0f8..6334cc359 100644
--- a/DistroLauncher/ApplyConfigPatches.cpp
+++ b/DistroLauncher/ConfigRootFs.cpp
@@ -17,10 +17,22 @@
 
 #include "stdafx.h"
 #include "Patch.h"
-#include "ApplyConfigPatches.h"
+#include "ConfigRootFs.h"
 
 namespace Ubuntu
 {
+    void ConfigRootFs(const std::wstring& DistroName, WslApiLoader& wsl)
+    {
+        ApplyConfigPatches(DistroName);
+        // Currently the only systemd unit mapped for explicit disablement is ssh on 20.04.
+        // If other cases appear, we should follow some strategy similar to the ApplyConfigPatches
+        // to properly select which units to disable for which distro release. The selection should still
+        // be internal, i.e. non visible from DistroLauncher.cpp.
+        if (DistroName == L"Ubuntu-20.04") {
+            DisableSystemdUnits(wsl);
+        }
+    }
+
     void ApplyConfigPatches(std::wstring_view DistroName)
     {
         // I think the WslPathPrefix no longer belongs to Oobe namespace. But let's leave that for later.
@@ -43,4 +55,10 @@ namespace Ubuntu
             patch.apply(pathPrefix);
         }
     }
+
+    void DisableSystemdUnits(WslApiLoader& wsl)
+    {
+        DWORD exitCode;
+        wsl.WslLaunchInteractive(L"systemctl disable ssh &>/dev/null", TRUE, &exitCode);
+    }
 }
diff --git a/DistroLauncher/ApplyConfigPatches.h b/DistroLauncher/ConfigRootFs.h
similarity index 79%
rename from DistroLauncher/ApplyConfigPatches.h
rename to DistroLauncher/ConfigRootFs.h
index 4b275d4ef..ad9760d5e 100644
--- a/DistroLauncher/ApplyConfigPatches.h
+++ b/DistroLauncher/ConfigRootFs.h
@@ -18,6 +18,10 @@
 
 namespace Ubuntu
 {
+    /// Performs post-registration file system configuration and tweaks to optimize the behavior of the distro image to
+    /// WSL. The actions come in two distinct natures: config file patching and systemd unit disabling. See
+    /// [ApplyConfigPatches] and [DisableSystemdUnits] for details.
+    void ConfigRootFs(const std::wstring& DistroName, WslApiLoader& wsl);
     /**
      * The distro launcher is equipped with a simple mechanism to adapt the root filesystem contents to some WSL
      * specificities through patching distro configuration files.
@@ -41,4 +45,7 @@ namespace Ubuntu
 
     /// Applies any relevant patch for the [DistroName].
     void ApplyConfigPatches(std::wstring_view DistroName);
+
+    /// Disables the relevant systemd units by means of running `systemctl disable`.
+    void DisableSystemdUnits(WslApiLoader& wsl);
 }
diff --git a/DistroLauncher/DistroLauncher.cpp b/DistroLauncher/DistroLauncher.cpp
index 465d8e0e6..7d418a834 100644
--- a/DistroLauncher/DistroLauncher.cpp
+++ b/DistroLauncher/DistroLauncher.cpp
@@ -37,7 +37,7 @@ HRESULT InstallDistribution(bool createUser, Oobe::Application<>& app)
         return hr;
     }
 
-    Ubuntu::ApplyConfigPatches(DistributionInfo::Name);
+    Ubuntu::ConfigRootFs(DistributionInfo::Name, g_wslApi);
 
     // Create a user account.
     if (createUser) {
diff --git a/DistroLauncher/DistroLauncher.vcxproj b/DistroLauncher/DistroLauncher.vcxproj
index c5b23b19a..cb8cdd0af 100644
--- a/DistroLauncher/DistroLauncher.vcxproj
+++ b/DistroLauncher/DistroLauncher.vcxproj
@@ -157,7 +157,7 @@
     <ClInclude Include="DistributionInfo.h" />
     <ClInclude Include="Helpers.h" />
     <ClInclude Include="Patch.h" />
-    <ClInclude Include="ApplyConfigPatches.h" />
+    <ClInclude Include="ConfigRootFs.h" />
     <ClInclude Include="ProcessRunner.h" />
     <ClInclude Include="resource.h" />
     <ClInclude Include="SetOnceNamedEvent.h" />
@@ -188,7 +188,7 @@
     <ClCompile Include="named_mutex.cpp" />
     <ClCompile Include="OOBE.cpp" />
     <ClCompile Include="Patch.cpp" />
-    <ClCompile Include="ApplyConfigPatches.cpp" />
+    <ClCompile Include="ConfigRootFs.cpp" />
     <ClCompile Include="ProcessRunner.cpp" />
     <ClCompile Include="ini_find_value.cpp" />
     <ClCompile Include="SetOnceNamedEvent.cpp" />
diff --git a/DistroLauncher/Patch.cpp b/DistroLauncher/Patch.cpp
index e71b33e45..a98608c54 100644
--- a/DistroLauncher/Patch.cpp
+++ b/DistroLauncher/Patch.cpp
@@ -39,11 +39,10 @@ namespace Ubuntu::PatchingFunctions
         return modified;
     }
 
-    bool OverrideUnitVirtualizationContainer(std::istreambuf_iterator<char> input, std::ostream& output)
+    bool OverrideUnitVirtualizationContainer(std::istreambuf_iterator<char> unused, std::ostream& conf)
     {
-        std::copy(input, std::istreambuf_iterator<char>{}, std::ostream_iterator<char>{output});
-        output << "\n[Unit]\nConditionVirtualization=!container\n";
-        return !output.fail();
+        conf << "[Unit]\nConditionVirtualization=!container\n";
+        return !conf.fail();
     }
 
     /**
diff --git a/DistroLauncher/Patch.h b/DistroLauncher/Patch.h
index 5a201d92a..9ba7bb39b 100644
--- a/DistroLauncher/Patch.h
+++ b/DistroLauncher/Patch.h
@@ -156,7 +156,6 @@ namespace Ubuntu
         {
           {"/etc/systemd/system/multipathd.socket.d/00-wsl.conf",
            PatchingFunctions::OverrideUnitVirtualizationContainer},
-          {"/lib/systemd/system/ssh.service", PatchingFunctions::OverrideUnitVirtualizationContainer},
         },
       },
     };
diff --git a/DistroLauncher/stdafx.h b/DistroLauncher/stdafx.h
index 99786df10..b270e82fe 100644
--- a/DistroLauncher/stdafx.h
+++ b/DistroLauncher/stdafx.h
@@ -51,7 +51,7 @@
 #include "OobeDefs.h"
 #include "ExitStatus.h"
 #include "OOBE.h"
-#include "ApplyConfigPatches.h"
+#include "ConfigRootFs.h"
 #include "ProcessRunner.h"
 #include "WSLInfo.h"
 #include "Win32Utils.h"


Test patch: