Allow disabling SSH

The intent behind this commit is to add the dropbear service, monitor
the Enabled and Running properties, and then update the
dropbear.socket to allow disabling/enabling SSH.

Tested:
1.
busctl introspect xyz.openbmc_project.Control.Service.Manager /xyz/openbmc_project/control/service/dropbear
 xyz.openbmc_project.Control.Service.Attributes       interface
 .Enabled                property  b    false  emits-change writable
 .Masked                 property  b    false  emits-change writable
 .Running                property  b    true   emits-change writable

 Open a new SSH connection:
 sudo ssh username@<IP>
 Successfully connected

2.
busctl set-property xyz.openbmc_project.Control.Service.Manager /xyz/openbmc_project/control/service/dropbear xyz.openbmc_project.Control.Service.Attributes Running b false

busctl introspect xyz.openbmc_project.Control.Service.Manager /xyz/openbmc_project/control/service/dropbear
 xyz.openbmc_project.Control.Service.Attributes       interface
 .Enabled                property  b    false  emits-change writable
 .Masked                 property  b    false  emits-change writable
 .Running                property  b    false  emits-change writable

 Open a new SSH connection:
 sudo ssh username@<IP>
 ssh: connect to host <IP> port 22: Connection refused

Signed-off-by: George Liu <liuxiwei@inspur.com>
Change-Id: I5d004f7f49c25fc90b93dabd124fe0d3d93ca822
diff --git a/src/srvcfg_manager.cpp b/src/srvcfg_manager.cpp
index 038d11a..bd23b44 100644
--- a/src/srvcfg_manager.cpp
+++ b/src/srvcfg_manager.cpp
@@ -96,7 +96,8 @@
     if (subStateIt != propertyMap.end())
     {
         subStateValue = std::get<std::string>(subStateIt->second);
-        if (subStateValue == subStateRunning)
+        if (subStateValue == subStateRunning ||
+            subStateValue == subStateListening)
         {
             unitRunningState = true;
         }
@@ -111,6 +112,13 @@
 
 void ServiceConfig::queryAndUpdateProperties()
 {
+    std::string objectPath =
+        isDropBearService ? socketObjectPath : serviceObjectPath;
+    if (objectPath.empty())
+    {
+        return;
+    }
+
     conn->async_method_call(
         [this](boost::system::error_code ec,
                const boost::container::flat_map<std::string, VariantType>&
@@ -173,8 +181,7 @@
                 return;
             }
         },
-        sysdService, serviceObjectPath, dBusPropIntf, dBusGetAllMethod,
-        sysdUnitIntf);
+        sysdService, objectPath, dBusPropIntf, dBusGetAllMethod, sysdUnitIntf);
     return;
 }
 
@@ -213,6 +220,10 @@
     instanceName(instanceName_), serviceObjectPath(serviceObjPath_),
     socketObjectPath(socketObjPath_)
 {
+    if (baseUnitName == "dropbear")
+    {
+        isDropBearService = true;
+    }
     instantiatedUnitName = baseUnitName + addInstanceName(instanceName, "@");
     updatedFlag = 0;
     queryAndUpdateProperties();
@@ -247,13 +258,45 @@
     phosphor::logging::log<phosphor::logging::level::INFO>(
         "Applying new settings.",
         phosphor::logging::entry("OBJPATH=%s", objPath.c_str()));
-    if (subStateValue == "running")
+    if (subStateValue == subStateRunning || subStateValue == subStateListening)
     {
         if (!socketObjectPath.empty())
         {
             systemdUnitAction(conn, yield, getSocketUnitName(), sysdStopUnit);
         }
-        systemdUnitAction(conn, yield, getServiceUnitName(), sysdStopUnit);
+        if (!isDropBearService)
+        {
+            systemdUnitAction(conn, yield, getServiceUnitName(), sysdStopUnit);
+        }
+        else
+        {
+            // Get the ListUnits property, find all the services of
+            // `dropbear@<ip><port>.service` and stop the service through
+            // the systemdUnitAction method
+            boost::system::error_code ec;
+            auto listUnits =
+                conn->yield_method_call<std::vector<ListUnitsType>>(
+                    yield, ec, sysdService, sysdObjPath, sysdMgrIntf,
+                    "ListUnits");
+
+            checkAndThrowInternalFailure(
+                ec, "yield_method_call error: ListUnits failed");
+
+            for (const auto& unit : listUnits)
+            {
+                const auto& service =
+                    std::get<static_cast<int>(ListUnitElements::name)>(unit);
+                const auto& status =
+                    std::get<static_cast<int>(ListUnitElements::subState)>(
+                        unit);
+                if (service.find("dropbear@") != std::string::npos &&
+                    service.find(".service") != std::string::npos &&
+                    status == subStateRunning)
+                {
+                    systemdUnitAction(conn, yield, service, sysdStopUnit);
+                }
+            }
+        }
     }
 
     if (updatedFlag & (1 << static_cast<uint8_t>(UpdatedProp::port)))
@@ -297,6 +340,10 @@
         {
             unitFiles = {getServiceUnitName()};
         }
+        else if (!socketObjectPath.empty() && isDropBearService)
+        {
+            unitFiles = {getSocketUnitName()};
+        }
         else
         {
             unitFiles = {getSocketUnitName(), getServiceUnitName()};
@@ -321,7 +368,11 @@
             systemdUnitAction(conn, yield, getSocketUnitName(),
                               sysdRestartUnit);
         }
-        systemdUnitAction(conn, yield, getServiceUnitName(), sysdRestartUnit);
+        if (!isDropBearService)
+        {
+            systemdUnitAction(conn, yield, getServiceUnitName(),
+                              sysdRestartUnit);
+        }
     }
 
     // Reset the flag