RMCP+ login support with privilege

Implementation of RMCP login support with appropriate
privilege level.

Unit Test:
1. Verified that user is able to login without any issues
2. Privilege of the user is minimum of requested, user & channel
3. Unable to set higher privilege using Set session commands

Change-Id: I5e9ef21dfc1f1b50aa815562a3a65d90c434877c
Signed-off-by: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com>
diff --git a/command/rakp12.cpp b/command/rakp12.cpp
index b4842b2..5384ab3 100644
--- a/command/rakp12.cpp
+++ b/command/rakp12.cpp
@@ -11,6 +11,8 @@
 #include <cstring>
 #include <iomanip>
 #include <iostream>
+#include <user_channel/channel_layer.hpp>
+#include <user_channel/user_layer.hpp>
 
 namespace command
 {
@@ -61,15 +63,6 @@
 
     session->userName.assign(request->user_name, request->user_name_len);
 
-    // Validate the user name if the username is provided
-    if (request->user_name_len &&
-        (session->userName != cipher::rakp_auth::userName))
-    {
-        response->rmcpStatusCode =
-            static_cast<uint8_t>(RAKP_ReturnCode::UNAUTH_NAME);
-        return outPayload;
-    }
-
     // Update transaction time
     session->updateLastTransactionTime();
 
@@ -129,6 +122,80 @@
         return outPayload;
     }
 
+    session->reqMaxPrivLevel = request->req_max_privilege_level;
+    session->curPrivLevel = static_cast<session::Privilege>(
+        request->req_max_privilege_level & session::reqMaxPrivMask);
+    if (((request->req_max_privilege_level & userNameOnlyLookupMask) !=
+         userNameOnlyLookup) ||
+        (request->user_name_len == 0))
+    {
+        // Skip privilege based lookup for security purpose
+        response->rmcpStatusCode =
+            static_cast<uint8_t>(RAKP_ReturnCode::UNAUTH_NAME);
+        return outPayload;
+    }
+
+    // Perform user name based lookup
+    std::string userName(request->user_name, request->user_name_len);
+    std::string passwd;
+    uint8_t userId = ipmi::ipmiUserGetUserId(userName);
+    if (userId == ipmi::invalidUserId)
+    {
+        response->rmcpStatusCode =
+            static_cast<uint8_t>(RAKP_ReturnCode::UNAUTH_NAME);
+        return outPayload;
+    }
+    // check user is enabled before proceeding.
+    bool userEnabled = false;
+    ipmi::ipmiUserCheckEnabled(userId, userEnabled);
+    if (!userEnabled)
+    {
+        response->rmcpStatusCode =
+            static_cast<uint8_t>(RAKP_ReturnCode::INACTIVE_ROLE);
+        return outPayload;
+    }
+    // Get the user password for RAKP message authenticate
+    passwd = ipmi::ipmiUserGetPassword(userName);
+    if (passwd.empty())
+    {
+        response->rmcpStatusCode =
+            static_cast<uint8_t>(RAKP_ReturnCode::UNAUTH_NAME);
+        return outPayload;
+    }
+    ipmi::PrivAccess userAccess{};
+    ipmi::ChannelAccess chAccess{};
+    // TODO Replace with proper calls.
+    uint8_t chNum = static_cast<uint8_t>(ipmi::EChannelID::chanLan1);
+    // Get channel based access information
+    if ((ipmi::ipmiUserGetPrivilegeAccess(userId, chNum, userAccess) !=
+         IPMI_CC_OK) ||
+        (ipmi::getChannelAccessData(chNum, chAccess) != IPMI_CC_OK))
+    {
+        response->rmcpStatusCode =
+            static_cast<uint8_t>(RAKP_ReturnCode::INACTIVE_ROLE);
+        return outPayload;
+    }
+    session->chNum = chNum;
+    // minimum privilege of Channel / User / requested has to be used
+    // as session current privilege level
+    uint8_t minPriv = 0;
+    if (chAccess.privLimit < userAccess.privilege)
+    {
+        minPriv = chAccess.privLimit;
+    }
+    else
+    {
+        minPriv = userAccess.privilege;
+    }
+    if (session->curPrivLevel > static_cast<session::Privilege>(minPriv))
+    {
+        session->curPrivLevel = static_cast<session::Privilege>(minPriv);
+    }
+
+    std::fill(authAlgo->userKey.data(),
+              authAlgo->userKey.data() + authAlgo->userKey.size(), 0);
+    std::copy_n(passwd.c_str(), passwd.size(), authAlgo->userKey.data());
+
     // Copy the Managed System Random Number to the Authentication Algorithm
     std::copy_n(iter, cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN,
                 authAlgo->bmcRandomNum.begin());
@@ -139,15 +206,10 @@
     std::advance(iter, BMC_GUID_LEN);
 
     // Requested Privilege Level
-    session->curPrivLevel =
-        static_cast<session::Privilege>(request->req_max_privilege_level);
     std::copy_n(&(request->req_max_privilege_level),
                 sizeof(request->req_max_privilege_level), iter);
     std::advance(iter, sizeof(request->req_max_privilege_level));
 
-    // Set Max Privilege to ADMIN
-    session->maxPrivLevel = session::Privilege::ADMIN;
-
     // User Name Length Byte
     std::copy_n(&(request->user_name_len), sizeof(request->user_name_len),
                 iter);