Support username for IPMI default user account

The current support in IPMI is for the nameless account, which has
no username and only password associated with the account. In
ipmitool for the nameless account -U option is not needed. There are
management scripts which take a parameter for -U option and fails
if -U option is not supported by ipmitool option. This patch is to
support "admin" username for the default account. Once full fledged
user account management is in place, this change can be removed.

Change-Id: Idad73c0d04f189af66f2365424a68a637fe0e476
Signed-off-by: Tom Joseph <tomjoseph@in.ibm.com>
diff --git a/auth_algo.cpp b/auth_algo.cpp
index 94a8c91..b658d6a 100644
--- a/auth_algo.cpp
+++ b/auth_algo.cpp
@@ -12,6 +12,8 @@
 namespace rakp_auth
 {
 
+const std::string userName = "admin";
+
 std::vector<uint8_t> AlgoSHA1::generateHMAC(
         const std::vector<uint8_t>& input) const
 {
diff --git a/auth_algo.hpp b/auth_algo.hpp
index 682c091..6bd32d0 100644
--- a/auth_algo.hpp
+++ b/auth_algo.hpp
@@ -9,10 +9,10 @@
 {
 namespace rakp_auth
 {
-
 constexpr size_t USER_KEY_MAX_LENGTH = 20;
 constexpr size_t BMC_RANDOM_NUMBER_LEN = 16;
 constexpr size_t REMOTE_CONSOLE_RANDOM_NUMBER_LEN = 16;
+extern const std::string userName;
 
 /**
  * @enum RAKP Authentication Algorithms
diff --git a/command/rakp12.cpp b/command/rakp12.cpp
index 5963cef..c52d188 100644
--- a/command/rakp12.cpp
+++ b/command/rakp12.cpp
@@ -3,6 +3,7 @@
 #include <openssl/rand.h>
 
 #include <algorithm>
+#include <cstring>
 #include <iomanip>
 #include <iostream>
 
@@ -45,6 +46,29 @@
         return outPayload;
     }
 
+    auto rakp1Size = sizeof(RAKP1request) -
+            (userNameMaxLen - request->user_name_len);
+
+    // Validate user name length in the message
+    if (request->user_name_len > userNameMaxLen ||
+        inPayload.size() !=  rakp1Size)
+    {
+        response->rmcpStatusCode =
+            static_cast<uint8_t>(RAKP_ReturnCode::INVALID_NAME_LENGTH);
+        return outPayload;
+    }
+
+    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();
 
@@ -70,7 +94,8 @@
                  cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN +
                  cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN +
                  BMC_GUID_LEN + sizeof(request->req_max_privilege_level) +
-                 sizeof(request->user_name_len));
+                 sizeof(request->user_name_len) +
+                 session->userName.size());
 
     auto iter = input.begin();
 
@@ -127,6 +152,9 @@
     // User Name Length Byte
     std::copy_n(&(request->user_name_len), sizeof(request->user_name_len),
                 iter);
+    std::advance(iter, sizeof(request->user_name_len));
+
+    std::copy_n(session->userName.data(), session->userName.size(), iter);
 
     // Generate Key Exchange Authentication Code - RAKP2
     auto output = authAlgo->generateHMAC(input);
diff --git a/command/rakp12.hpp b/command/rakp12.hpp
index fb9a499..189b5e5 100644
--- a/command/rakp12.hpp
+++ b/command/rakp12.hpp
@@ -8,6 +8,8 @@
 namespace command
 {
 
+constexpr size_t userNameMaxLen = 16;
+
 /**
  * @struct RAKP1request
  *
@@ -23,7 +25,7 @@
     uint8_t req_max_privilege_level;
     uint16_t reserved3;
     uint8_t user_name_len;
-    char user_name[16];
+    char user_name[userNameMaxLen];
 } __attribute__((packed));
 
 /**
diff --git a/command/rakp34.cpp b/command/rakp34.cpp
index 71b1e52..37335a8 100644
--- a/command/rakp34.cpp
+++ b/command/rakp34.cpp
@@ -125,12 +125,12 @@
     auto sessPrivLevel = static_cast<uint8_t>(session->curPrivLevel);
 
     // User Name Length Byte
-    uint8_t userLength = 0;
+    auto userLength = static_cast<uint8_t>(session->userName.size());
 
     std::vector<uint8_t> input;
     input.resize(cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN +
                  sizeof(rcSessionID) + sizeof(sessPrivLevel) +
-                 sizeof(userLength));
+                 sizeof(userLength) + userLength);
 
     auto iter = input.begin();
 
@@ -151,6 +151,9 @@
 
     // User Name Length Byte
     std::copy_n(&userLength, sizeof(userLength), iter);
+    std::advance(iter, sizeof(userLength));
+
+    std::copy_n(session->userName.data(), userLength, iter);
 
     // Generate Key Exchange Authentication Code - RAKP2
     auto output = authAlgo->generateHMAC(input);
@@ -187,7 +190,7 @@
 
     input.resize(cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN +
                  cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN +
-                 sizeof(sessPrivLevel) + sizeof(userLength));
+                 sizeof(sessPrivLevel) + sizeof(userLength) + userLength);
     iter = input.begin();
 
     // Remote Console Random Number
@@ -207,6 +210,9 @@
 
     // User Name Length Byte
     std::copy_n(&userLength, sizeof(userLength), iter);
+    std::advance(iter, sizeof(userLength));
+
+    std::copy_n(session->userName.data(), userLength, iter);
 
     // Generate Session Integrity Key
     auto sikOutput = authAlgo->generateHMAC(input);
diff --git a/session.hpp b/session.hpp
index feef2d4..f010a49 100644
--- a/session.hpp
+++ b/session.hpp
@@ -247,7 +247,7 @@
 
         SequenceNumbers sequenceNums; // Session Sequence Numbers
         State state = State::INACTIVE; // Session State
-        std::vector<char> userName; // User Name
+        std::string userName {}; // User Name
 
         /** @brief Socket channel for communicating with the remote client.*/
         std::shared_ptr<udpsocket::Channel> channelPtr;