Przeglądaj źródła

temporary fix: allow only one session per securechannel

Julius Pfrommer 9 lat temu
rodzic
commit
d5fb8f9eb4

+ 53 - 35
src/server/ua_securechannel_manager.c

@@ -28,46 +28,62 @@ void UA_SecureChannelManager_deleteMembers(UA_SecureChannelManager *cm) {
     }
 }
 
+void UA_SecureChannelManager_cleanupTimedOut(UA_SecureChannelManager *cm, UA_DateTime now) {
+    channel_list_entry *entry = LIST_FIRST(&cm->channels);
+    /* remove channels that were not renewed or who have no connection attached */
+    while(entry) {
+        if(entry->channel.securityToken.createdAt +
+            (10000 * entry->channel.securityToken.revisedLifetime) > now &&
+            entry->channel.connection) {
+            entry = LIST_NEXT(entry, pointers);
+        }
+        else {
+            channel_list_entry *next = LIST_NEXT(entry, pointers);
+            LIST_REMOVE(entry, pointers);
+            UA_Connection *c = entry->channel.connection;
+            if(c) {
+                UA_Connection_detachSecureChannel(c);
+                c->close(c);
+            }
+            UA_SecureChannel_detachSession(&entry->channel);
+            UA_SecureChannel_deleteMembers(&entry->channel);
+            UA_free(entry);
+            entry = next;
+        }
+    }
+}
+
+
 UA_StatusCode UA_SecureChannelManager_open(UA_SecureChannelManager *cm, UA_Connection *conn,
                                            const UA_OpenSecureChannelRequest *request,
-                                           UA_OpenSecureChannelResponse *response)
-{
+                                           UA_OpenSecureChannelResponse *response) {
     switch(request->securityMode) {
+    case UA_MESSAGESECURITYMODE_NONE:
+        break;
     case UA_MESSAGESECURITYMODE_INVALID:
-        response->responseHeader.serviceResult = UA_STATUSCODE_BADSECURITYMODEREJECTED;
-        return response->responseHeader.serviceResult;
-
-        // fall through and handle afterwards
-    /* case UA_MESSAGESECURITYMODE_NONE: */
-    /*     UA_ByteString_copy(&request->clientNonce, &entry->channel.clientNonce); */
-    /*     break; */
-
     case UA_MESSAGESECURITYMODE_SIGN:
     case UA_MESSAGESECURITYMODE_SIGNANDENCRYPT:
+    default:
         response->responseHeader.serviceResult = UA_STATUSCODE_BADSECURITYMODEREJECTED;
         return response->responseHeader.serviceResult;
-
-    default:
-        // do nothing
-        break;
     }
 
     channel_list_entry *entry = UA_malloc(sizeof(channel_list_entry));
-    if(!entry) return UA_STATUSCODE_BADOUTOFMEMORY;
-    UA_SecureChannel_init(&entry->channel);
+    if(!entry)
+        return UA_STATUSCODE_BADOUTOFMEMORY;
 
+    UA_SecureChannel_init(&entry->channel);
     response->responseHeader.stringTableSize = 0;
     response->responseHeader.timestamp       = UA_DateTime_now();
+    response->serverProtocolVersion = 0;
 
-    entry->channel.connection = conn;
-    conn->channel = &entry->channel;
     entry->channel.securityToken.channelId       = cm->lastChannelId++;
     entry->channel.securityToken.tokenId         = cm->lastTokenId++;
     entry->channel.securityToken.createdAt       = UA_DateTime_now();
     entry->channel.securityToken.revisedLifetime = (request->requestedLifetime > cm->maxChannelLifetime) ?
                                                    cm->maxChannelLifetime : request->requestedLifetime;
     //FIXME: pragmatic workaround to get clients requesting lifetime of 0 working
-    if(entry->channel.securityToken.revisedLifetime == 0){
+    if(entry->channel.securityToken.revisedLifetime == 0) {
         entry->channel.securityToken.revisedLifetime = cm->maxChannelLifetime;
         //FIXME: I'd log it, but there is no pointer to the logger
         // printf("Warning: client requests token lifetime of 0 in OpenSecureChannelRequest setting it to %llu\n", cm->maxChannelLifetime);
@@ -76,13 +92,13 @@ UA_StatusCode UA_SecureChannelManager_open(UA_SecureChannelManager *cm, UA_Conne
     UA_ByteString_copy(&request->clientNonce, &entry->channel.clientNonce);
     entry->channel.serverAsymAlgSettings.securityPolicyUri =
         UA_STRING_ALLOC("http://opcfoundation.org/UA/SecurityPolicy#None");
-    LIST_INSERT_HEAD(&cm->channels, entry, pointers);
 
-    response->serverProtocolVersion = 0;
     UA_SecureChannel_generateNonce(&entry->channel.serverNonce);
     UA_ByteString_copy(&entry->channel.serverNonce, &response->serverNonce);
     UA_ChannelSecurityToken_copy(&entry->channel.securityToken, &response->securityToken);
-    conn->channel = &entry->channel;
+
+    UA_Connection_attachSecureChannel(conn, &entry->channel);
+    LIST_INSERT_HEAD(&cm->channels, entry, pointers);
 
     return UA_STATUSCODE_GOOD;
 }
@@ -128,18 +144,20 @@ UA_StatusCode UA_SecureChannelManager_close(UA_SecureChannelManager *cm, UA_UInt
     // TODO lock access
     channel_list_entry *entry;
     LIST_FOREACH(entry, &cm->channels, pointers) {
-        if(entry->channel.securityToken.channelId == channelId) {
-            UA_Connection *c = entry->channel.connection;
-            if(c) {
-                UA_Connection_detachSecureChannel(c);
-                c->close(c);
-            }
-            entry->channel.session = UA_NULL;
-            UA_SecureChannel_deleteMembers(&entry->channel);
-            LIST_REMOVE(entry, pointers);
-            UA_free(entry);
-            return UA_STATUSCODE_GOOD;
-        }
+        if(entry->channel.securityToken.channelId == channelId)
+            break;
     }
-    return UA_STATUSCODE_BADINTERNALERROR;
+    if(!entry)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    LIST_REMOVE(entry, pointers);
+    UA_Connection *c = entry->channel.connection;
+    if(c) {
+        UA_Connection_detachSecureChannel(c);
+        c->close(c);
+    }
+    UA_SecureChannel_detachSession(&entry->channel);
+    UA_SecureChannel_deleteMembers(&entry->channel);
+    UA_free(entry);
+    return UA_STATUSCODE_GOOD;
 }

+ 1 - 0
src/server/ua_securechannel_manager.h

@@ -25,6 +25,7 @@ UA_StatusCode UA_SecureChannelManager_init(UA_SecureChannelManager *cm, UA_UInt3
                                            UA_UInt32 tokenLifetime, UA_UInt32 startChannelId,
                                            UA_UInt32 startTokenId);
 void UA_SecureChannelManager_deleteMembers(UA_SecureChannelManager *cm);
+void UA_SecureChannelManager_cleanupTimedOut(UA_SecureChannelManager *cm, UA_DateTime now);
 UA_StatusCode UA_SecureChannelManager_open(UA_SecureChannelManager *cm, UA_Connection *conn,
                                            const UA_OpenSecureChannelRequest *request,
                                            UA_OpenSecureChannelResponse *response);

+ 3 - 40
src/server/ua_server.c

@@ -113,48 +113,11 @@ void UA_Server_delete(UA_Server *server) {
     UA_free(server);
 }
 
-/**
- * Recurring cleanup. Removing unused and timed-out channels and sessions
- * Todo: make this thread-safe
- */
+/* Recurring cleanup. Removing unused and timed-out channels and sessions */
 static void UA_Server_cleanup(UA_Server *server, void *nothing) {
     UA_DateTime now = UA_DateTime_now();
-    channel_list_entry *entry = LIST_FIRST(&server->secureChannelManager.channels);
-    /* remove channels that were not renewed or who have no connection attached */
-    while(entry) {
-        if(entry->channel.securityToken.createdAt +
-           (10000 * entry->channel.securityToken.revisedLifetime) > now &&
-           entry->channel.connection) {
-            entry = LIST_NEXT(entry, pointers);
-        } else {
-            channel_list_entry *next = LIST_NEXT(entry, pointers);
-            LIST_REMOVE(entry, pointers);
-            UA_Connection *c = entry->channel.connection;
-            if (c) {
-                UA_Connection_detachSecureChannel(c);
-                c->close(c);
-            }
-            UA_SecureChannel_detachSession(&entry->channel);
-            UA_SecureChannel_deleteMembers(&entry->channel);
-            UA_free(entry);
-            entry = next;
-        }
-    }
-
-    session_list_entry *sentry = LIST_FIRST(&server->sessionManager.sessions);
-    while(sentry) {
-        if(sentry->session.validTill < now) {
-            session_list_entry *next = LIST_NEXT(sentry, pointers);
-            LIST_REMOVE(sentry, pointers);
-            if(sentry->session.channel)
-                UA_SecureChannel_detachSession(sentry->session.channel);
-            UA_Session_deleteMembers(&sentry->session);
-            UA_free(sentry);
-            sentry = next;
-        } else {
-            sentry = LIST_NEXT(sentry, pointers);
-        }
-    }
+    UA_SessionManager_cleanupTimedOut(&server->sessionManager, now);
+    UA_SecureChannelManager_cleanupTimedOut(&server->secureChannelManager, now);
 }
 
 static UA_StatusCode readStatus(void *handle, UA_Boolean sourceTimeStamp, UA_DataValue *value) {

+ 25 - 6
src/server/ua_session_manager.c

@@ -24,15 +24,31 @@ void UA_SessionManager_deleteMembers(UA_SessionManager *sessionManager) {
         current = next;
         next = LIST_NEXT(current, pointers);
         LIST_REMOVE(current, pointers);
-        //if(current->session.channel)
-        //    current->session.channel->session = UA_NULL; // the channel is no longer attached to a session
+        if(current->session.channel)
+            UA_SecureChannel_detachSession(current->session.channel);
         UA_Session_deleteMembers(&current->session);
         UA_free(current);
     }
 }
 
-UA_Session * UA_SessionManager_getSession(UA_SessionManager *sessionManager,
-                                          const UA_NodeId *token) {
+void UA_SessionManager_cleanupTimedOut(UA_SessionManager *sessionManager, UA_DateTime now) {
+    session_list_entry *sentry = LIST_FIRST(&sessionManager->sessions);
+    while(sentry) {
+        if(sentry->session.validTill < now) {
+            session_list_entry *next = LIST_NEXT(sentry, pointers);
+            LIST_REMOVE(sentry, pointers);
+            if(sentry->session.channel)
+                UA_SecureChannel_detachSession(sentry->session.channel);
+            UA_Session_deleteMembers(&sentry->session);
+            UA_free(sentry);
+            sentry = next;
+        } else {
+            sentry = LIST_NEXT(sentry, pointers);
+        }
+    }
+}
+
+UA_Session * UA_SessionManager_getSession(UA_SessionManager *sessionManager, const UA_NodeId *token) {
     session_list_entry *current = UA_NULL;
     LIST_FOREACH(current, &sessionManager->sessions, pointers) {
         if(UA_NodeId_equal(&current->session.authenticationToken, token))
@@ -51,6 +67,9 @@ UA_SessionManager_createSession(UA_SessionManager *sessionManager, UA_SecureChan
     if(sessionManager->currentSessionCount >= sessionManager->maxSessionCount)
         return UA_STATUSCODE_BADTOOMANYSESSIONS;
 
+    if(channel->session != UA_NULL)
+        return UA_STATUSCODE_BADTOOMANYSESSIONS;
+
     session_list_entry *newentry = UA_malloc(sizeof(session_list_entry));
     if(!newentry)
         return UA_STATUSCODE_BADOUTOFMEMORY;
@@ -74,7 +93,7 @@ UA_SessionManager_createSession(UA_SessionManager *sessionManager, UA_SecureChan
 UA_StatusCode
 UA_SessionManager_removeSession(UA_SessionManager *sessionManager, const UA_NodeId *sessionId)
 {
-    session_list_entry *current = UA_NULL;
+    session_list_entry *current;
     LIST_FOREACH(current, &sessionManager->sessions, pointers) {
         if(UA_NodeId_equal(&current->session.sessionId, sessionId))
             break;
@@ -88,4 +107,4 @@ UA_SessionManager_removeSession(UA_SessionManager *sessionManager, const UA_Node
     UA_Session_deleteMembers(&current->session);
     UA_free(current);
     return UA_STATUSCODE_GOOD;
-}
+}

+ 2 - 0
src/server/ua_session_manager.h

@@ -24,6 +24,8 @@ UA_StatusCode UA_SessionManager_init(UA_SessionManager *sessionManager, UA_UInt3
 
 void UA_SessionManager_deleteMembers(UA_SessionManager *sessionManager);
 
+void UA_SessionManager_cleanupTimedOut(UA_SessionManager *sessionManager, UA_DateTime now);
+
 UA_StatusCode UA_SessionManager_createSession(UA_SessionManager *sessionManager,
                                               UA_SecureChannel *channel, const UA_CreateSessionRequest *request, UA_Session **session);