Allow sensor value override in mfg mode only

Issue: User is able to override sensor value even though system is not
in manufacturing mode

Fix: Code changes are done to patch sensor values when system is only
in manufacturing Mode.

Tested:
1. Redfish validator - passed for this new change

Case 1:
1. Enable manufacturing mode by pressing power button while bmc booting
2. Patch sensor values from Redfish.
Redfish URI:
PATCH https://<BMC-IP>/redfish/v1/Chassis/WC_Baseboard/Thermal
Body:
{
    "Temperatures": [
    {
        "MemberId": "SSB_Temp",
        "ReadingCelsius":112
    }
]
}

Response:
{
  "@odata.id": "/redfish/v1/Chassis/WC_Baseboard/Thermal",
  "@odata.type": "#Thermal.v1_4_0.Thermal",
  "Fans": [],
  "Id": "Thermal",
  "Name": "Thermal",
  "Temperatures": []
}

3. Sensor value Overridden successfully

Case 2: Varified for ValidationUnsecure mode.
Case 3: Tested without SpecialMode mode
1. Stop the specialmodemgr.service service
2. Patch sensor values from Redfish.
3. Sensor value Overridden successfully

Case 4:
1. Disable manufacturing mode
Command: ipmitool raw 0x30 0xB4 3 0
Response:            //Success
2. Patch sensor values from Redfish.
Redfish URI:
PATCH https://<BMC-IP>/redfish/v1/Chassis/WC_Baseboard/Thermal
Body:
{
    "Temperatures": [
    {
        "MemberId": "SSB_Temp",
        "ReadingCelsius":112
    }
]
}

3. Returning proper error.
Response :
{
  "error": {
    "@Message.ExtendedInfo": [
      {
        "@odata.type": "/redfish/v1/$metadata#Message.v1_0_0.Message",
        "Message": "The action Overriding of Sensor Value for
            non manufacturing mode is not supported by the resource.",
        "MessageArgs": [
          "Overriding of Sensor Value for non manufacturing mode"
        ],
        "MessageId": "Base.1.4.0.ActionNotSupported",
        "Resolution": "The action supplied cannot be resubmitted to
           the implementation.  Perhaps the action was invalid, the
           wrong resource was the target or the implementation
           documentation may be of assistance.",
        "Severity": "Critical"
      }
    ],
    "code": "Base.1.4.0.ActionNotSupported",
    "message": "The action Overriding of Sensor Value for
            non manufacturing mode is not supported by the resource."
  }
}

Signed-off-by: jayaprakash Mutyala <mutyalax.jayaprakash@intel.com>
Change-Id: I34cd53fba939fb367310c531a050792ef749dd70
diff --git a/redfish-core/lib/sensors.hpp b/redfish-core/lib/sensors.hpp
index adcdc25..6c1f830 100644
--- a/redfish-core/lib/sensors.hpp
+++ b/redfish-core/lib/sensors.hpp
@@ -2598,15 +2598,15 @@
  * @param res   response object
  * @param allCollections   Collections extract from sensors' request patch info
  * @param typeList   TypeList of sensors for the resource queried
- * @param chassisSubNode   Chassis Node for which the query has to happen
+ * @param chassisSubNode  Chassis Node for which the query has to happen
  */
-void setSensorOverride(
+void setSensorsOverride(
     std::shared_ptr<SensorsAsyncResp> sensorAsyncResp,
     std::unordered_map<std::string, std::vector<nlohmann::json>>&
         allCollections,
     const std::string& chassisName, const std::vector<const char*> typeList)
 {
-    BMCWEB_LOG_INFO << "setSensorOverride for subNode"
+    BMCWEB_LOG_INFO << "setSensorsOverride for subNode"
                     << sensorAsyncResp->chassisSubNode << "\n";
 
     const char* propertyValueName;
@@ -2726,6 +2726,138 @@
     getChassis(sensorAsyncResp, std::move(getChassisSensorListCb));
 }
 
+bool isOverridingAllowed(const std::string& manufacturingModeStatus)
+{
+    if (manufacturingModeStatus ==
+        "xyz.openbmc_project.Control.Security.SpecialMode.Modes.Manufacturing")
+    {
+        return true;
+    }
+
+#ifdef BMCWEB_ENABLE_VALIDATION_UNSECURE_FEATURE
+    if (manufacturingModeStatus == "xyz.openbmc_project.Control.Security."
+                                   "SpecialMode.Modes.ValidationUnsecure")
+    {
+        return true;
+    }
+
+#endif
+
+    return false;
+}
+
+/**
+ * @brief Entry point for Checking the manufacturing mode before doing sensor
+ * override values of given sensor
+ *
+ * @param res   response object
+ * @param allCollections   Collections extract from sensors' request patch info
+ * @param typeList   TypeList of sensors for the resource queried
+ * @param chassisSubNode  Chassis Node for which the query has to happen
+ */
+void checkAndDoSensorsOverride(
+    std::shared_ptr<SensorsAsyncResp> sensorAsyncResp,
+    std::unordered_map<std::string, std::vector<nlohmann::json>>& allCollect,
+    const std::string& chassisName, const std::vector<const char*> typeList)
+{
+    BMCWEB_LOG_INFO << "checkAndDoSensorsOverride for subnode"
+                    << sensorAsyncResp->chassisSubNode << "\n";
+
+    const std::array<std::string, 1> interfaces = {
+        "xyz.openbmc_project.Security.SpecialMode"};
+
+    crow::connections::systemBus->async_method_call(
+        [sensorAsyncResp, allCollect, chassisName,
+         typeList](const boost::system::error_code ec,
+                   const GetSubTreeType& resp) mutable {
+            if (ec)
+            {
+                BMCWEB_LOG_DEBUG
+                    << "Error in querying GetSubTree with Object Mapper. "
+                    << ec;
+                messages::internalError(sensorAsyncResp->res);
+                return;
+            }
+            if (!resp.size())
+            {
+                // Special mode manager doesn't exist, proceed with sensor
+                // override
+                setSensorsOverride(sensorAsyncResp, allCollect, chassisName,
+                                   typeList);
+                return;
+            }
+
+            if (resp.size() != 1)
+            {
+                BMCWEB_LOG_DEBUG << "Queried object count mismatch. ";
+                messages::internalError(sensorAsyncResp->res);
+                return;
+            }
+            const std::string& path = resp[0].first;
+            const std::string& serviceName = resp[0].second.begin()->first;
+
+            if (path.empty() || serviceName.empty())
+            {
+                BMCWEB_LOG_DEBUG
+                    << "Path or service name is returned as empty. ";
+                messages::internalError(sensorAsyncResp->res);
+                return;
+            }
+
+            // Sensor override is allowed only in manufacturing mode or
+            // validation unsecure mode .
+            crow::connections::systemBus->async_method_call(
+                [sensorAsyncResp, allCollect, chassisName, typeList,
+                 path](const boost::system::error_code ec,
+                       std::variant<std::string>& getManufactMode) mutable {
+                    if (ec)
+                    {
+                        BMCWEB_LOG_DEBUG
+                            << "Error in querying Special mode property " << ec;
+                        messages::internalError(sensorAsyncResp->res);
+                        return;
+                    }
+
+                    const std::string* manufacturingModeStatus =
+                        std::get_if<std::string>(&getManufactMode);
+
+                    if (nullptr == manufacturingModeStatus)
+                    {
+                        BMCWEB_LOG_DEBUG << "Sensor override mode is not "
+                                            "Enabled. Returning ... ";
+                        messages::internalError(sensorAsyncResp->res);
+                        return;
+                    }
+
+                    if (isOverridingAllowed(*manufacturingModeStatus))
+                    {
+                        BMCWEB_LOG_INFO << "Manufacturing mode is Enabled. "
+                                           "Proceeding further... ";
+                        setSensorsOverride(sensorAsyncResp, allCollect,
+                                           chassisName, typeList);
+                    }
+                    else
+                    {
+                        BMCWEB_LOG_WARNING
+                            << "Manufacturing mode is not Enabled...can't "
+                               "Override the sensor value. ";
+
+                        messages::actionNotSupported(
+                            sensorAsyncResp->res,
+                            "Overriding of Sensor Value for non "
+                            "manufacturing mode");
+                        return;
+                    }
+                },
+                serviceName, path, "org.freedesktop.DBus.Properties", "Get",
+                "xyz.openbmc_project.Security.SpecialMode", "SpecialMode");
+        },
+
+        "xyz.openbmc_project.ObjectMapper",
+        "/xyz/openbmc_project/object_mapper",
+        "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", 5, interfaces);
+}
+
 class SensorCollection : public Node
 {
   public: