Busy and Cancel logics (#33)
author강용구/Security&Privacy팀(SR)/삼성전자 <ygace.kang@samsung.com>
Tue, 9 Jan 2024 08:02:13 +0000 (17:02 +0900)
committerGitHub Enterprise <noreply-CODE@samsung.com>
Tue, 9 Jan 2024 08:02:13 +0000 (17:02 +0900)
srcs/client/client-request.h
srcs/client/client.cpp
srcs/common/wauth-error.cpp
srcs/server/service.cpp
srcs/server/service.h

index eee3387..928fbd7 100644 (file)
@@ -115,6 +115,13 @@ public:
         return recv();
     }
 
+    ClientRequest &sendRequest()
+    {
+        if (send().failed())
+            return *this;
+        return recv();
+    }
+
 private:
     bool m_sent = false;
     int m_status = WAUTHN_ERROR_NONE;
index 46679c4..42a4f26 100644 (file)
@@ -56,17 +56,15 @@ int wauthn_make_credential( const wauthn_client_data_s *client_data,
                             const wauthn_pubkey_cred_creation_options_s *options,
                             wauthn_mc_callbacks_s *callbacks)
 {
-    
     if (client_data == nullptr || options == nullptr || callbacks == nullptr ||
         callbacks->response_callback == nullptr)
         return WAUTHN_ERROR_INVALID_PARAMETER;
 
     return try_catch([&]() -> int {
-        
         std::shared_ptr<ClientRequest> request 
             = std::make_shared<ClientRequest>(WebAuthnCall::MAKE_CREDENTIAL);
 
-        LogDebug("sendRequest");
+        LogDebug("Calling to make credential..");
         // TODO: send client_data, options 
         //if (request->sendRequest(client_data, options)).failed())
         if (request->sendRequest(std::string("sendRequest(MC) to server")).failed())
@@ -77,7 +75,6 @@ int wauthn_make_credential( const wauthn_client_data_s *client_data,
         std::thread worker([request, callbacks, cred]{cb_worker(request, callbacks, cred);});
         worker.detach();
         LogDebug("Main thread OUT");
-
         return WAUTHN_ERROR_NONE;
     });
 }
@@ -86,7 +83,6 @@ int wauthn_get_assertion( const wauthn_client_data_s *client_data,
                           const wauthn_pubkey_cred_request_options_s *options,
                           wauthn_ga_callbacks_s *callbacks)
 {
-    
     if (client_data == nullptr || options == nullptr || callbacks == nullptr ||
         callbacks->response_callback == nullptr)
         return WAUTHN_ERROR_INVALID_PARAMETER;
@@ -95,7 +91,7 @@ int wauthn_get_assertion( const wauthn_client_data_s *client_data,
         std::shared_ptr<ClientRequest> request 
             = std::make_shared<ClientRequest>(WebAuthnCall::GET_ASSERTION);
 
-        LogDebug("getAssertion");
+        LogDebug("Calling to get assertion..");
         /* TODO: send client_data, options */
         //if (request->sendRequest(client_data, options)).failed())
         if (request->sendRequest(std::string("getAssertion(GA) to server")).failed())
@@ -105,7 +101,6 @@ int wauthn_get_assertion( const wauthn_client_data_s *client_data,
         wauthn_pubkey_credential_assertion_s *cred = NULL;
         std::thread worker([request, callbacks, cred]{cb_worker(request, callbacks, cred);});
         worker.detach();
-        
         LogDebug("Main thread OUT");
         return WAUTHN_ERROR_NONE;
     });
@@ -113,6 +108,12 @@ int wauthn_get_assertion( const wauthn_client_data_s *client_data,
 
 int wauthn_cancel()
 {
-    // TODO
-    return WAUTHN_ERROR_NONE;
+    return try_catch([&]() -> int {
+        std::shared_ptr<ClientRequest> request 
+            = std::make_shared<ClientRequest>(WebAuthnCall::CANCEL);
+        LogDebug("Calling to cancel..");
+        if (request->sendRequest().failed())
+            LogError("Error on cancel request, RET: " << wauthn_error_to_string(request->getStatus()));
+        return request->getStatus();
+    });
 }
\ No newline at end of file
index 51a8025..832d9a0 100644 (file)
@@ -38,6 +38,7 @@ const char * wauthn_error_to_string(int error) {
         WAUTHN_CODE_DESCRIBE(WAUTHN_ERROR_NO_SUCH_SERVICE);
         WAUTHN_CODE_DESCRIBE(WAUTHN_ERROR_ACCESS_DENIED);
         WAUTHN_CODE_DESCRIBE(WAUTHN_ERROR_MEMORY);
+        WAUTHN_CODE_DESCRIBE(WAUTHN_ERROR_CANCELLED);
         default: return "Code not defined";
     }
 }
index 5d04f66..807d1d7 100644 (file)
@@ -19,7 +19,6 @@
  */
 
 
-#include <sys/socket.h>
 #include <webauthn-log.h>
 #include <serialization.h>
 #include <protocols.h>
@@ -27,6 +26,7 @@
 #include <unistd.h>
 #include <webauthn-hal.h>
 #include <webauthn-types.h>
+#define SMACK_LABEL_LEN 255
 
 /* Test code start */
 void wah_make_credential(const wauthn_client_data_s *client_data,
@@ -38,9 +38,9 @@ void wah_make_credential(const wauthn_client_data_s *client_data,
     if (options == NULL)
         LogError("options is null");
 
-    sleep(3);
+    sleep(2);
     callbacks->qrcode_callback(std::string("FIDO:/..mc....").c_str(), callbacks->user_data);
-    sleep(3);
+    sleep(2);
     callbacks->response_callback(NULL, WAUTHN_ERROR_NONE, callbacks->user_data);
 }
 
@@ -53,11 +53,16 @@ void wah_get_assertion(const wauthn_client_data_s *client_data,
     if (options == NULL)
         LogError("options is null");
 
-    sleep(3);
+    sleep(2);
     callbacks->qrcode_callback(std::string("FIDO:/..ga....").c_str(), callbacks->user_data);
-    sleep(3);
+    sleep(2);
     callbacks->response_callback(NULL, WAUTHN_ERROR_NONE, callbacks->user_data);
 }
+
+int wah_cancel()
+{
+    return WAUTHN_ERROR_NONE;
+}
 /* Test code end */
 
 namespace WA {
@@ -115,6 +120,7 @@ void cb_mc_on_response(const wauthn_pubkey_credential_attestaion_s *pubkey_cred,
     
     LogDebug("Writing response with sock: " << userData->connectionID.sock);
     userData->service->getSocketmanager()->Write(userData->connectionID, std::move(buffer));
+    userData->service->unsetBusy();
 }
 
 void cb_ga_on_response(const wauthn_pubkey_credential_assertion_s *pubkey_cred,
@@ -143,6 +149,7 @@ void cb_ga_on_response(const wauthn_pubkey_credential_assertion_s *pubkey_cred,
     
     LogDebug("Writing response with sock: " << userData->connectionID.sock);
     userData->service->getSocketmanager()->Write(userData->connectionID, std::move(buffer));
+    userData->service->unsetBusy();
 }
 
 Service::Service(){}
@@ -154,10 +161,7 @@ SocketManager *Service::getSocketmanager()
 
 void Service::mcWorker(SocketManager::ConnectionID connectionID)
 {
-    LogDebug("IN mcWorker thread, connectionID: " << connectionID.sock);
-
-    //sleep(3);
-    
+    LogDebug("IN mcWorker thread, connectionID: " << connectionID.sock);    
     wauthn_mc_callbacks_s *callbacks = NULL;
     callbacks = (wauthn_mc_callbacks_s*) calloc(1, sizeof(wauthn_mc_callbacks_s));
     callbacks->qrcode_callback = cb_display_qrcode;
@@ -169,17 +173,12 @@ void Service::mcWorker(SocketManager::ConnectionID connectionID)
     callbacks->user_data = user_data;
 
     wah_make_credential(NULL, NULL, callbacks);
-
-    //sleep(3);
     LogDebug("Worker thread OUT");
 }
 
 void Service::gaWorker(SocketManager::ConnectionID connectionID)
 {
     LogDebug("IN gaWorker thread, connectionID: " << connectionID.sock);
-
-    //sleep(3);
-    
     wauthn_ga_callbacks_s *callbacks = NULL;
     callbacks = (wauthn_ga_callbacks_s*) calloc(1, sizeof(wauthn_ga_callbacks_s));
     callbacks->qrcode_callback = cb_display_qrcode;
@@ -191,8 +190,6 @@ void Service::gaWorker(SocketManager::ConnectionID connectionID)
     callbacks->user_data = user_data;
 
     wah_get_assertion(NULL, NULL, callbacks);
-
-    //sleep(3);
     LogDebug("Worker thread OUT");
 }
 
@@ -223,8 +220,6 @@ void Service::processEvent(Event &&msg)
                 Throw(ServiceException::InvalidAction);
         }
         // if we reach this point, the protocol is OK
-        //LogDebug("Closing socket after the protocol is Done.");
-        //return m_serviceManager->Close(msg.connectionID);
         LogDebug("Protocol is Done.");
         return;
     } Catch(MessageBuffer::Exception::Base) {
@@ -236,45 +231,46 @@ void Service::processEvent(Event &&msg)
     } catch (...) {
         LogError("Unknown exception");
     }
-
-    //LogError("Closing socket because of error");
-    //m_serviceManager->Close(msg.connectionID);
 }
 
 void Service::processMakeCredential(
     SocketManager::ConnectionID connectionID, 
     MessageBuffer &buffer)
 {
-    /* Test Code Start */
-    pid_t pid = getpid();
-    
-    LogDebug("PID: " << pid);
-
-    ucred clientCred;
-    socklen_t length = sizeof(ucred);
-    if (0 > getsockopt(connectionID.sock, SOL_SOCKET, SO_PEERCRED, &clientCred, &length)) {
-        LogError("getsockopt failed");
-        //return -1;
-    }
-    LogDebug("Client PID: " << clientCred.pid);
-
-
+    // busy check
+    // cred setting
 
     std::string recvStr;
     Deserialization::Deserialize(buffer, recvStr);
     LogDebug("Receive :" << recvStr);
+    // TODO: recv client_data, options 
 
     buffer.ModeStreaming();
     int ret = WAUTHN_ERROR_NONE;
+    int isBusy = checkBusyAndSet(connectionID);
+
+    if (-1 == isBusy)
+    {
+        LogError("Error on checkBusyAndSet");
+        ret = WAUTHN_ERROR_UNKNOWN;
+    }
+    else if (1 == isBusy)
+    {
+        LogError("Server is Busy");
+        ret = WAUTHN_ERROR_NOT_ALLOWED;
+    }
+
     Serialization::Serialize(buffer, ret);
     LogDebug("Writing ret");
     m_serviceManager->Write(connectionID, std::move(buffer));
     
-    std::thread worker(&Service::mcWorker, this, connectionID);
-    worker.detach();
-    LogDebug("Main thread Done");
-    
-    /* Test Code End */
+    if (0 == isBusy)
+    {
+        LogDebug("Creating worker thread..");
+        std::thread worker(&Service::mcWorker, this, connectionID);
+        worker.detach();
+        LogDebug("Main thread is Done");
+    }
 }
 
 void Service::processGetAssertion(SocketManager::ConnectionID connectionID, 
@@ -285,27 +281,143 @@ void Service::processGetAssertion(SocketManager::ConnectionID connectionID,
     std::string recvStr;
     Deserialization::Deserialize(buffer, recvStr);
     LogDebug("Receive :" << recvStr);
+    // TODO: recv client_data, options 
 
     buffer.ModeStreaming();
     int ret = WAUTHN_ERROR_NONE;
+    int isBusy = checkBusyAndSet(connectionID);
+
+    if (-1 == isBusy)
+    {
+        LogError("Error on checkBusyAndSet");
+        ret = WAUTHN_ERROR_UNKNOWN;
+    }
+    else if (1 == isBusy)
+    {
+        LogError("Server is Busy");
+        ret = WAUTHN_ERROR_NOT_ALLOWED;
+    }
+
     Serialization::Serialize(buffer, ret);
     LogDebug("Writing ret");
     m_serviceManager->Write(connectionID, std::move(buffer));
     
-    std::thread worker(&Service::gaWorker, this, connectionID);
-    worker.detach();
-    LogDebug("Main thread Done");
-    
-    /* Test Code End */
+    if (0 == isBusy)
+    {
+        LogDebug("Creating worker thread..");
+        std::thread worker(&Service::gaWorker, this, connectionID);
+        worker.detach();
+        LogDebug("Main thread is Done");
+    }
 }
 
 void Service::processCancel(SocketManager::ConnectionID connectionID, 
     MessageBuffer &buffer)
 {
-    /* Test Code Start */
     LogDebug("socket: " << connectionID.sock);
     buffer.ModeStreaming();
-    /* Test Code End */
+    int ret = WAUTHN_ERROR_NONE;
+    int isBusy = checkBusyAndCred(connectionID);
+    if (-1 == isBusy)
+    {
+        LogError("Error on checkBusyAndCred");
+        ret = WAUTHN_ERROR_UNKNOWN;
+    }
+    else if (1 == isBusy)
+    {
+        LogDebug("Calling HAL for cancel");
+        ret = wah_cancel(); 
+    }
+    else
+    {
+        LogError("The cancellation request is not allowed");
+        ret = WAUTHN_ERROR_NOT_ALLOWED;
+    }
+
+    Serialization::Serialize(buffer, ret);
+    LogDebug("Writing ret");
+    m_serviceManager->Write(connectionID, std::move(buffer));
+}
+
+int Service::checkBusyAndCred(SocketManager::ConnectionID connectionID)
+{
+    std::lock_guard<std::mutex> ulock(m_isBusyMutex);
+    if (isBusy)
+    {
+        Cred nowCreds;
+        int ret = getCredentials(connectionID, &nowCreds);
+        if (-1 == ret)
+        {
+            LogError("Error on get credentials");
+            return -1;
+        }
+        if (credentials.smack == nowCreds.smack && credentials.cred.pid == nowCreds.cred.pid)
+        {
+            LogDebug("Service is Busy and Credentials are matched");
+            return 1;
+        }
+        else
+        {
+            LogError("Credentials are not matched");
+            return 0;
+        }
+    }
+    else
+    {
+        LogError("Server is not Busy");
+        return 0;
+    }
+}
+
+int Service::checkBusyAndSet(SocketManager::ConnectionID connectionID)
+{
+    std::lock_guard<std::mutex> ulock(m_isBusyMutex);
+    if (isBusy)
+        return 1;
+    else{
+        isBusy = true;
+        int ret = setCredentials(connectionID);
+        if (-1 == ret)
+        {
+            LogError("Error on set credentials");
+            return -1;
+        }
+        LogDebug("Return not Busy after Set Busy");
+        return 0;
+    }
+}
+
+void Service::unsetBusy()
+{
+    std::lock_guard<std::mutex> ulock(m_isBusyMutex);
+    isBusy = false;
+    LogDebug("Set not Busy");
+}
+
+int Service::setCredentials(SocketManager::ConnectionID connectionID)
+{
+    return getCredentials(connectionID, &credentials);
+}
+
+int Service::getCredentials(SocketManager::ConnectionID connectionID, Cred *creds)
+{
+    socklen_t length = sizeof(ucred);
+    if (0 > getsockopt(connectionID.sock, SOL_SOCKET, SO_PEERCRED, &creds->cred, &length)) {
+        LogError("getsockopt for get pid failed");
+        return -1;
+    }
+    LogDebug("Client PID: " << creds->cred.pid);
+
+    std::vector<char> result(SMACK_LABEL_LEN + 1);
+    length = SMACK_LABEL_LEN;
+    if (0 != getsockopt(connectionID.sock, SOL_SOCKET, SO_PEERSEC, result.data(), &length))
+    {
+        return -1;
+        LogError("getsockopt for get smack label failed");
+    }
+    creds->smack.assign(result.data(), length);
+    LogDebug("Client Smack: " << creds->smack);
+    return 0;
 }
 
 } // namespace WebAuthn
index 5c87ab6..67c03c8 100644 (file)
 
 #pragma once
 
+#include <sys/socket.h>
 #include <message-buffer.h>
 #include <socket-manager.h>
 #include <protocols.h>
+#include <mutex>
 
 namespace WA {
 
@@ -30,6 +32,10 @@ struct Event {
     SocketManager::ConnectionID connectionID;
     MessageBuffer buffer;
 };
+struct Cred {
+    std::string smack;
+    ucred cred;
+};
 
 class Service final
 {
@@ -47,17 +53,18 @@ public:
     /**
      * Handle request from a client
      *
-     * @param  conn Socket connection information
      * @param  msg  A message
      */
     void processEvent(Event &&msg);
     SocketManager *getSocketmanager();
+    void unsetBusy();
     
     //void Service::cbQRCode(const char *qr_contents, void *user_data);
 
 private:
     /**
      * Process making credential
+     * @param connectionID Socket information for the connection
      * @param buffer Input/output message buffer
      */
     void processMakeCredential(
@@ -66,6 +73,7 @@ private:
 
     /**
      * Process getting assertion
+     * @param connectionID Socket information for the connection
      * @param buffer Input/output message buffer
      */
     void processGetAssertion(
@@ -74,14 +82,33 @@ private:
 
     /**
      * Process cancelling current event
+     * @param connectionID Socket information for the connection
      * @param buffer Input/output message buffer
      */
     void processCancel(
         SocketManager::ConnectionID connectionID,
         MessageBuffer &buffer);
 
+    /**
+     * Worker thread for make credential request
+     * @param connectionID Socket information for the connection
+     */ 
     void mcWorker(SocketManager::ConnectionID connectionID);
+
+    /**
+     * Worker thread for get assertion request
+     * @param connectionID Socket information for the connection
+     */ 
     void gaWorker(SocketManager::ConnectionID connectionID);
+
+    int checkBusyAndSet(SocketManager::ConnectionID connectionID);
+    int checkBusyAndCred(SocketManager::ConnectionID connectionID);
+    int setCredentials(SocketManager::ConnectionID connectionID);
+    int getCredentials(SocketManager::ConnectionID connectionID, Cred *creds);
+
+    bool isBusy = false;
+    std::mutex m_isBusyMutex;
+    Cred credentials;
 };
 
 } // namespace WebAuthn