Enable local users in the authentication reset cmd

Along with resetting the password and disabling LDAP,
local users should also be enabled again so one can
ssh into the system with a local user account again.

This is accomplished by setting the UserEnabled property
on every user object.

Tested:  Saw users were enabled when running
         ipmitool raw 0x3a 0x11 from the host.

Change-Id: I5a313cf82e2596cb797b8b9431631a3fe4ffca8d
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
diff --git a/local_users.cpp b/local_users.cpp
new file mode 100644
index 0000000..aa6519c
--- /dev/null
+++ b/local_users.cpp
@@ -0,0 +1,111 @@
+#include "config.h"
+#include "local_users.hpp"
+#include <host-ipmid/ipmid-host-cmd.hpp>
+#include <phosphor-logging/log.hpp>
+
+namespace local
+{
+namespace users
+{
+
+using namespace phosphor::logging;
+
+constexpr auto userIface = "xyz.openbmc_project.User.Attributes";
+constexpr auto propIface = "org.freedesktop.DBus.Properties";
+
+using DbusObjectPath = std::string;
+using DbusService = std::string;
+using DbusInterface = std::string;
+using ObjectTree = std::map<DbusObjectPath,
+                            std::map<DbusService, std::vector<DbusInterface>>>;
+
+/**
+ * @brief Gets a list of all local users in the form of GetSubTree
+ *        results.
+ *
+ * @param[out] users - Filled in with the results of a
+ *                     GetSubTree call that returns all users.
+ */
+void getUsers(ObjectTree& users)
+{
+    auto& bus = ipmid_get_sdbus_plus_handler();
+
+    try
+    {
+        auto method = bus->new_method_call(MAPPER_BUS_NAME,
+                MAPPER_OBJ,
+                MAPPER_IFACE,
+                "GetSubTree");
+        method.append("/xyz/openbmc_project/user/", 0,
+                std::vector<std::string>{userIface});
+
+        auto reply = bus->call(method);
+        if (reply.is_method_error())
+        {
+            throw std::runtime_error("Method error on GetSubTree call");
+        }
+
+        reply.read(users);
+    }
+    catch (sdbusplus::exception::SdBusError& e)
+    {
+        throw std::runtime_error(e.what());
+    }
+}
+
+/**
+ * @brief Enables the user passed in
+ *
+ * @param[in] path - The user object path
+ * @param[in] service - The service hosting the user
+ */
+void enableUser(const std::string& path, const std::string& service)
+{
+    auto& bus = ipmid_get_sdbus_plus_handler();
+
+    try
+    {
+        auto method = bus->new_method_call(service.c_str(),
+                path.c_str(),
+                propIface,
+                "Set");
+        sdbusplus::message::variant<bool> enabled{true};
+        method.append(userIface, "UserEnabled", enabled);
+
+        auto reply = bus->call(method);
+        if (reply.is_method_error())
+        {
+            throw std::runtime_error("Method error on property set call");
+        }
+    }
+    catch (sdbusplus::exception::SdBusError& e)
+    {
+        throw std::runtime_error(e.what());
+    }
+}
+
+ipmi_ret_t enableUsers()
+{
+    ObjectTree users;
+
+    try
+    {
+        getUsers(users);
+
+        for (const auto& user : users)
+        {
+            enableUser(user.first, user.second.begin()->first);
+        }
+    }
+    catch (std::runtime_error& e)
+    {
+        log<level::ERR>("Failed enabling local users",
+                entry("ERROR=%s", e.what()));
+        return IPMI_CC_UNSPECIFIED_ERROR;
+    }
+
+    return IPMI_CC_OK;
+}
+
+}
+}