Coverage Report

Created: 2025-08-29 06:18

/src/S2OPC/src/ClientServer/configuration/sopc_toolkit_config.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Licensed to Systerel under one or more contributor license
3
 * agreements. See the NOTICE file distributed with this work
4
 * for additional information regarding copyright ownership.
5
 * Systerel licenses this file to you under the Apache
6
 * License, Version 2.0 (the "License"); you may not use this
7
 * file except in compliance with the License. You may obtain
8
 * a copy of the License at
9
 *
10
 *   http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing,
13
 * software distributed under the License is distributed on an
14
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
 * KIND, either express or implied.  See the License for the
16
 * specific language governing permissions and limitations
17
 * under the License.
18
 */
19
20
#include <inttypes.h>
21
#include <stdio.h>
22
#include <string.h>
23
24
#include "opcua_identifiers.h"
25
#include "sopc_assert.h"
26
#include "sopc_common.h"
27
#include "sopc_date_time.h"
28
#include "sopc_encodeabletype.h"
29
#include "sopc_enum_types.h"
30
#include "sopc_event_timer_manager.h"
31
#include "sopc_filesystem.h"
32
#include "sopc_helper_endianness_cfg.h"
33
#include "sopc_internal_app_dispatcher.h"
34
#include "sopc_logger.h"
35
#include "sopc_macros.h"
36
#include "sopc_mem_alloc.h"
37
#include "sopc_mutexes.h"
38
#include "sopc_secure_channels_api.h"
39
#include "sopc_services_api.h"
40
#include "sopc_singly_linked_list.h"
41
#include "sopc_sockets_api.h"
42
#include "sopc_toolkit_build_info.h"
43
#include "sopc_toolkit_config.h"
44
#include "sopc_toolkit_config_internal.h"
45
#include "sopc_user_app_itf.h"
46
47
#include "address_space_impl.h"
48
#include "util_b2c.h"
49
50
/* Check IEEE-754 compliance */
51
#include "sopc_ieee_check.h"
52
53
static struct
54
{
55
    uint8_t initDone;
56
    uint8_t serverConfigLocked;
57
    SOPC_Mutex mut;
58
    /* Specific client */
59
    SOPC_SecureChannel_Config* scConfigs[SOPC_MAX_SECURE_CONNECTIONS_PLUS_BUFFERED + 1];
60
    const char* reverseEpConfigs[SOPC_MAX_ENDPOINT_DESCRIPTION_CONFIGURATIONS + 1]; // index 0 reserved
61
    SOPC_SecureChannelConfigIdx scConfigIdxMax;
62
    SOPC_ReverseEndpointConfigIdx reverseEpConfigIdxMax;
63
    /* Specific server */
64
    SOPC_SecureChannel_Config* serverScConfigs[SOPC_MAX_SECURE_CONNECTIONS_PLUS_BUFFERED + 1];
65
    SOPC_Endpoint_Config* epConfigs[SOPC_MAX_ENDPOINT_DESCRIPTION_CONFIGURATIONS + 1]; // index 0 reserved
66
    SOPC_SecureChannelConfigIdx serverScLastConfigIdx;
67
    SOPC_EndpointConfigIdx epConfigIdxMax;
68
} // Any change in values below shall be also done in SOPC_Toolkit_Clear
69
tConfig = {.initDone = false,
70
           .serverConfigLocked = false,
71
           .scConfigIdxMax = 0,
72
           .reverseEpConfigIdxMax = 0,
73
           .serverScLastConfigIdx = 0,
74
           .epConfigIdxMax = 0};
75
76
SOPC_ReturnStatus SOPC_Toolkit_Initialize(SOPC_ComEvent_Fct* pAppFct)
77
0
{
78
0
    SOPC_ReturnStatus status = SOPC_STATUS_OK;
79
80
0
    if (NULL == pAppFct)
81
0
    {
82
0
        status = SOPC_STATUS_INVALID_PARAMETERS;
83
0
    }
84
85
0
    bool bRet = SOPC_Common_IsInitialized();
86
0
    if (SOPC_STATUS_OK == status && !bRet)
87
0
    {
88
        /* Initialize with default log configuration */
89
0
        SOPC_Log_Configuration defaultLogConfiguration = SOPC_Common_GetDefaultLogConfiguration();
90
0
        status = SOPC_Common_Initialize(defaultLogConfiguration);
91
0
    }
92
93
0
    if (SOPC_STATUS_OK == status)
94
0
    {
95
0
        if (tConfig.initDone)
96
0
        {
97
0
            status = SOPC_STATUS_INVALID_STATE;
98
0
        }
99
0
        else
100
0
        {
101
0
            SOPC_Mutex_Initialization(&tConfig.mut);
102
0
            SOPC_Mutex_Lock(&tConfig.mut);
103
            // Note: check again the flag to avoid possible concurrency issue detection by static analysis.
104
            //       Nevertheless this function shall never be called concurrently since the mutex is created during
105
            //       call
106
0
            if (!tConfig.initDone)
107
0
            {
108
0
                tConfig.initDone = true;
109
110
0
                sopc_appEventCallback = pAppFct;
111
112
                // Ensure constants cannot be modified later
113
                // Return value is not check as the encoding config could be already set.
114
0
                SOPC_Common_EncodingConstants defEncConst = SOPC_Common_GetDefaultEncodingConstants();
115
0
                bRet = SOPC_Common_SetEncodingConstants(defEncConst);
116
0
                SOPC_Helper_Endianness_Check();
117
118
0
                if (SOPC_STATUS_OK == status)
119
0
                {
120
0
                    memset(tConfig.scConfigs, 0, sizeof(tConfig.scConfigs));
121
0
                    memset((void*) tConfig.reverseEpConfigs, 0, sizeof(tConfig.reverseEpConfigs));
122
0
                    memset(tConfig.serverScConfigs, 0, sizeof(tConfig.serverScConfigs));
123
0
                    memset(tConfig.epConfigs, 0, sizeof(tConfig.epConfigs));
124
0
                    SOPC_App_Initialize();
125
0
                    SOPC_EventTimer_Initialize();
126
0
                    SOPC_Sockets_Initialize();
127
0
                    SOPC_SecureChannels_Initialize(SOPC_Sockets_SetEventHandler);
128
0
                    SOPC_Services_Initialize(SOPC_SecureChannels_SetEventHandler);
129
130
0
                    SOPC_Toolkit_Build_Info toolkitBuildInfo = SOPC_ToolkitConfig_GetBuildInfo();
131
132
                    /* set log level to INFO for version logging, then restore it */
133
0
                    SOPC_Log_Level level = SOPC_Logger_GetTraceLogLevel();
134
0
                    SOPC_Logger_SetTraceLogLevel(SOPC_LOG_LEVEL_INFO);
135
0
                    SOPC_Logger_TraceInfo(SOPC_LOG_MODULE_CLIENTSERVER,
136
0
                                          "Common library DATE='%s' VERSION='%s' SIGNATURE='%s' DOCKER='%s'",
137
0
                                          toolkitBuildInfo.commonBuildInfo.buildBuildDate,
138
0
                                          toolkitBuildInfo.commonBuildInfo.buildVersion,
139
0
                                          toolkitBuildInfo.commonBuildInfo.buildSrcCommit,
140
0
                                          toolkitBuildInfo.commonBuildInfo.buildDockerId);
141
0
                    SOPC_Logger_TraceInfo(
142
0
                        SOPC_LOG_MODULE_CLIENTSERVER,
143
0
                        "Client/Server toolkit library DATE='%s' VERSION='%s' SIGNATURE='%s' DOCKER='%s'",
144
0
                        toolkitBuildInfo.clientServerBuildInfo.buildBuildDate,
145
0
                        toolkitBuildInfo.clientServerBuildInfo.buildVersion,
146
0
                        toolkitBuildInfo.clientServerBuildInfo.buildSrcCommit,
147
0
                        toolkitBuildInfo.clientServerBuildInfo.buildDockerId);
148
0
                    SOPC_Logger_SetTraceLogLevel(level);
149
0
                }
150
0
            }
151
0
            SOPC_Mutex_Unlock(&tConfig.mut);
152
0
        }
153
0
    }
154
155
0
    return status;
156
0
}
157
158
static SOPC_ReturnStatus SOPC_SecurityCheck_UserCredentialsEncrypted(const SOPC_SecurityPolicy* pSecurityPolicy,
159
                                                                     const OpcUa_UserTokenPolicy* pUserTokenPolicies)
160
0
{
161
0
    SOPC_ReturnStatus status = SOPC_STATUS_OK;
162
0
    SOPC_String securityPolicyNoneURI;
163
0
    SOPC_String_Initialize(&securityPolicyNoneURI);
164
0
    status = SOPC_String_AttachFromCstring(&securityPolicyNoneURI, SOPC_SecurityPolicy_None_URI);
165
0
    if (SOPC_STATUS_OK != status)
166
0
    {
167
0
        return SOPC_STATUS_NOK;
168
0
    }
169
170
    // Check if SecurityPolicy "security mode" is "None" AND if "UserToken security policy" is "empty" (default)
171
0
    if (0 != (pSecurityPolicy->securityModes & SOPC_SECURITY_MODE_NONE_MASK) &&
172
0
        pUserTokenPolicies->SecurityPolicyUri.Length <= 0)
173
0
    {
174
0
        SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER,
175
0
                               "Security Check UserCredentials: Failed. Combination not allowed : SecurityPolicy "
176
0
                               "security mode is None and UserToken security policy is empty.\n");
177
0
        status = SOPC_STATUS_INVALID_PARAMETERS;
178
0
    }
179
180
    // Check if SecurityPolicy "security mode" is "None or Sign" AND if "UserToken security policy" is "None"
181
0
    else if (0 != (pSecurityPolicy->securityModes & (SOPC_SECURITY_MODE_SIGN_MASK | SOPC_SECURITY_MODE_NONE_MASK)) &&
182
0
             true == SOPC_String_Equal(&pUserTokenPolicies->SecurityPolicyUri, &securityPolicyNoneURI))
183
0
    {
184
0
        SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER,
185
0
                               "Security Check UserCredentials: Failed. Combination not allowed : SecurityPolicy "
186
0
                               "security mode is None or Sign and UserToken security policy is None.\n");
187
0
        status = SOPC_STATUS_INVALID_PARAMETERS;
188
0
    }
189
0
    return status;
190
0
}
191
192
static SOPC_ReturnStatus SOPC_ToolkitServer_SecurityCheck(void)
193
0
{
194
0
    SOPC_Endpoint_Config* pEpConfig;
195
0
    SOPC_SecurityPolicy* pSecurityPolicy;
196
0
    OpcUa_UserTokenPolicy* pUserTokenPolicies;
197
0
    SOPC_ReturnStatus status = SOPC_STATUS_OK;
198
0
    SOPC_ReturnStatus statusSecurityCheck = SOPC_STATUS_OK;
199
0
    SOPC_String securityPolicyNoneURI;
200
201
0
    SOPC_String_Initialize(&securityPolicyNoneURI);
202
0
    status = SOPC_String_AttachFromCstring(&securityPolicyNoneURI, SOPC_SecurityPolicy_None_URI);
203
0
    if (SOPC_STATUS_OK != status)
204
0
    {
205
0
        return SOPC_STATUS_NOK;
206
0
    }
207
208
0
    for (uint32_t nbEpConfigIndex = 1; nbEpConfigIndex <= tConfig.epConfigIdxMax; nbEpConfigIndex++)
209
0
    {
210
0
        pEpConfig = tConfig.epConfigs[nbEpConfigIndex];
211
212
0
        for (uint8_t nbSecuIndex = 0; nbSecuIndex < pEpConfig->nbSecuConfigs; nbSecuIndex++)
213
0
        {
214
0
            pSecurityPolicy = &pEpConfig->secuConfigurations[nbSecuIndex];
215
216
0
            for (uint8_t nbTokenIndex = 0; nbTokenIndex < pSecurityPolicy->nbOfUserTokenPolicies; nbTokenIndex++)
217
0
            {
218
0
                pUserTokenPolicies = &pSecurityPolicy->userTokenPolicies[nbTokenIndex];
219
220
0
                if (OpcUa_UserTokenType_Anonymous != pUserTokenPolicies->TokenType)
221
0
                {
222
0
                    status = SOPC_SecurityCheck_UserCredentialsEncrypted(pSecurityPolicy, pUserTokenPolicies);
223
0
                    if (SOPC_STATUS_OK != status)
224
0
                    {
225
0
                        statusSecurityCheck = status;
226
0
                    }
227
0
                }
228
0
            }
229
230
            /* Check if SecurityPolicy "security policy URI" is different from "None" AND if SecurityPolicy "security
231
            mode" is "None" */
232
0
            if (false == SOPC_String_Equal(&pSecurityPolicy->securityPolicy, &securityPolicyNoneURI) &&
233
0
                0 != (pSecurityPolicy->securityModes & SOPC_SECURITY_MODE_NONE_MASK))
234
0
            {
235
0
                SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER,
236
0
                                       "Security Check: Failed. Combination not allowed : SecurityPolicy security "
237
0
                                       "policy URI is different from None and SecurityPolicy security mode is None.\n");
238
0
                statusSecurityCheck = SOPC_STATUS_INVALID_PARAMETERS;
239
0
            }
240
0
        }
241
0
    }
242
0
    return statusSecurityCheck;
243
0
}
244
245
SOPC_ReturnStatus SOPC_ToolkitServer_Configured(void)
246
0
{
247
0
    SOPC_ReturnStatus status = SOPC_STATUS_INVALID_STATE;
248
0
    if (tConfig.initDone)
249
0
    {
250
0
        SOPC_Mutex_Lock(&tConfig.mut);
251
0
        if (!tConfig.serverConfigLocked)
252
0
        {
253
            // Check an address space is defined in case a endpoint configuration exists
254
0
            if (tConfig.epConfigIdxMax > 0 && sopc_addressSpace_configured)
255
0
            {
256
0
                tConfig.serverConfigLocked = true;
257
0
                SOPC_AddressSpace_Check_Configured();
258
0
                status = SOPC_ToolkitServer_SecurityCheck();
259
0
            }
260
0
            else
261
0
            {
262
                // No address space defined whereas a server configuration exists
263
0
                status = SOPC_STATUS_INVALID_PARAMETERS;
264
0
            }
265
0
        }
266
0
        SOPC_Mutex_Unlock(&tConfig.mut);
267
0
    }
268
0
    return status;
269
0
}
270
271
static void SOPC_ToolkitServer_ClearScConfig_WithoutLock(uint32_t serverScConfigIdxWithoutOffset)
272
0
{
273
0
    SOPC_SecureChannel_Config* scConfig = tConfig.serverScConfigs[serverScConfigIdxWithoutOffset];
274
0
    if (scConfig != NULL)
275
0
    {
276
0
        SOPC_ASSERT(!scConfig->isClientSc);
277
        // In case of server it is an internally created config
278
        // => only client certificate was specifically allocated
279
        // Exceptional case: configuration added internally and shall be freed on clear call
280
0
        SOPC_KeyCertPair_Delete(&scConfig->peerAppCert);
281
0
        SOPC_Free(scConfig);
282
0
        tConfig.serverScConfigs[serverScConfigIdxWithoutOffset] = NULL;
283
0
    }
284
0
}
285
286
// Deallocate fields allocated on server side only and free all the SC configs
287
static void SOPC_Toolkit_ClearServerScConfigs_WithoutLock(void)
288
0
{
289
    // Index 0 reserved for indet, index = MAX valid
290
0
    for (uint32_t i = 1; i <= SOPC_MAX_SECURE_CONNECTIONS_PLUS_BUFFERED; i++)
291
0
    {
292
0
        SOPC_ToolkitServer_ClearScConfig_WithoutLock(i);
293
0
    }
294
0
}
295
296
void SOPC_Toolkit_Clear(void)
297
0
{
298
0
    if (tConfig.initDone)
299
0
    {
300
        // Services are in charge to gracefully close all connections.
301
        // It must be done before stopping the services
302
0
        SOPC_Services_CloseAllSCs(false);
303
304
        // Ensure no new events are triggered by timers
305
0
        SOPC_EventTimer_PreClear();
306
307
0
        SOPC_Sockets_Clear();
308
0
        SOPC_SecureChannels_Clear();
309
0
        SOPC_Services_Clear();
310
0
        SOPC_App_Clear();
311
0
        SOPC_EventTimer_Clear();
312
313
0
        SOPC_Mutex_Lock(&tConfig.mut);
314
        // Note: check again the flag to avoid possible concurrency issue detection by static analysis.
315
        //       Nevertheless this function shall never be called concurrently since the mutex is destroyed after call.
316
0
        if (tConfig.initDone)
317
0
        {
318
0
            SOPC_Toolkit_ClearServerScConfigs_WithoutLock();
319
0
            sopc_appEventCallback = NULL;
320
0
            sopc_appAddressSpaceNotificationCallback = NULL;
321
0
            address_space_bs__nodes = NULL;
322
0
            sopc_addressSpace_configured = false;
323
            // Reset values to init value
324
0
            tConfig.initDone = false;
325
0
            tConfig.serverConfigLocked = false;
326
0
            tConfig.scConfigIdxMax = 0;
327
0
            tConfig.reverseEpConfigIdxMax = 0;
328
0
            tConfig.serverScLastConfigIdx = 0;
329
0
            tConfig.epConfigIdxMax = 0;
330
0
        }
331
0
        SOPC_Mutex_Unlock(&tConfig.mut);
332
0
        SOPC_Mutex_Clear(&tConfig.mut);
333
0
    }
334
0
    SOPC_Common_Clear();
335
0
}
336
337
static bool SOPC_Internal_CheckClientSecureChannelConfig(const SOPC_SecureChannel_Config* scConfig)
338
0
{
339
0
    bool result = true;
340
0
    if (!scConfig->isClientSc)
341
0
    {
342
0
        SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER, "AddSecureChannelConfig check: isClientSc flag not set");
343
0
        result = false;
344
0
    }
345
0
    if (NULL == scConfig->url)
346
0
    {
347
0
        SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER,
348
0
                               "AddSecureChannelConfig check: server endpoint URL not set");
349
0
        result = false;
350
0
    }
351
0
    if (NULL == scConfig->reqSecuPolicyUri)
352
0
    {
353
0
        SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER,
354
0
                               "AddSecureChannelConfig check: Security Policy URI not set");
355
0
        result = false;
356
0
    }
357
0
    if (scConfig->msgSecurityMode <= OpcUa_MessageSecurityMode_Invalid ||
358
0
        scConfig->msgSecurityMode >= OpcUa_MessageSecurityMode_SizeOf)
359
0
    {
360
0
        SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER, "AddSecureChannelConfig check: Security Mode not set");
361
0
        result = false;
362
0
    }
363
0
    if (scConfig->requestedLifetime < SOPC_MINIMUM_SECURE_CONNECTION_LIFETIME)
364
0
    {
365
0
        SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER,
366
0
                               "AddSecureChannelConfig check: requested lifetime is less than minimum defined: %" PRIu32
367
0
                               " < %" PRIu32,
368
0
                               scConfig->requestedLifetime, (uint32_t) SOPC_MINIMUM_SECURE_CONNECTION_LIFETIME);
369
0
        result = false;
370
0
    }
371
0
    if (NULL == scConfig->clientConfigPtr)
372
0
    {
373
0
        SOPC_Logger_TraceError(
374
0
            SOPC_LOG_MODULE_CLIENTSERVER,
375
0
            "AddSecureChannelConfig check: client application configuration (clientConfigPtr) is not defined.");
376
0
        result = false;
377
0
    }
378
0
    else if ((NULL != scConfig->reqSecuPolicyUri &&
379
0
              (0 != strcmp(scConfig->reqSecuPolicyUri, SOPC_SecurityPolicy_None_URI))) ||
380
0
             scConfig->msgSecurityMode != OpcUa_MessageSecurityMode_None)
381
0
    {
382
0
        if (NULL == scConfig->clientConfigPtr->clientPKI)
383
0
        {
384
0
            SOPC_Logger_TraceError(
385
0
                SOPC_LOG_MODULE_CLIENTSERVER,
386
0
                "AddSecureChannelConfig check: PKI is not defined but is required due to Security policy / mode");
387
0
            result = false;
388
0
        }
389
0
        if (NULL == scConfig->clientConfigPtr->clientKeyCertPair)
390
0
        {
391
0
            SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER,
392
0
                                   "AddSecureChannelConfig check: Client certificate / key pair is not defined but is "
393
0
                                   "required due to Security policy / mode");
394
0
            result = false;
395
0
        }
396
0
        if (NULL == scConfig->peerAppCert)
397
0
        {
398
0
            SOPC_Logger_TraceError(
399
0
                SOPC_LOG_MODULE_CLIENTSERVER,
400
0
                "AddSecureChannelConfig check: Server certificate (peerAppCert) is not defined but is required "
401
0
                "due to Security policy / mode");
402
0
            result = false;
403
0
        }
404
0
    }
405
0
    return result;
406
0
}
407
408
SOPC_SecureChannelConfigIdx SOPC_ToolkitClient_AddSecureChannelConfig(SOPC_SecureChannel_Config* scConfig)
409
0
{
410
0
    SOPC_ASSERT(NULL != scConfig);
411
0
    SOPC_SecureChannelConfigIdx result = 0;
412
413
0
    if (tConfig.initDone && SOPC_Internal_CheckClientSecureChannelConfig(scConfig))
414
0
    {
415
0
        SOPC_Mutex_Lock(&tConfig.mut);
416
0
        if (tConfig.scConfigIdxMax < SOPC_MAX_SECURE_CONNECTIONS_PLUS_BUFFERED)
417
0
        {
418
0
            tConfig.scConfigIdxMax++; // Minimum used == 1 && Maximum used == MAX + 1
419
0
            SOPC_ASSERT(NULL == tConfig.scConfigs[tConfig.scConfigIdxMax]);
420
0
            tConfig.scConfigs[tConfig.scConfigIdxMax] = scConfig;
421
0
            result = tConfig.scConfigIdxMax;
422
0
        }
423
0
        SOPC_Mutex_Unlock(&tConfig.mut);
424
0
    }
425
0
    return result;
426
0
}
427
428
SOPC_SecureChannel_Config* SOPC_ToolkitClient_GetSecureChannelConfig(uint32_t scConfigIdx)
429
0
{
430
0
    SOPC_SecureChannel_Config* res = NULL;
431
0
    if (scConfigIdx > 0 && scConfigIdx <= SOPC_MAX_SECURE_CONNECTIONS_PLUS_BUFFERED)
432
0
    {
433
0
        if (tConfig.initDone)
434
0
        {
435
0
            SOPC_Mutex_Lock(&tConfig.mut);
436
0
            res = tConfig.scConfigs[scConfigIdx];
437
0
            SOPC_Mutex_Unlock(&tConfig.mut);
438
0
        }
439
0
    }
440
0
    return res;
441
0
}
442
443
const char* SOPC_ToolkitClient_GetReverseEndpointURL(SOPC_ReverseEndpointConfigIdx reverseEpCfgIdx)
444
0
{
445
0
    const char* res = NULL;
446
0
    if (SOPC_IS_VALID_REVERSE_EP_CONFIGURATION(reverseEpCfgIdx))
447
0
    {
448
0
        if (tConfig.initDone)
449
0
        {
450
0
            SOPC_Mutex_Lock(&tConfig.mut);
451
0
            res = tConfig.reverseEpConfigs[reverseEpCfgIdx - SOPC_MAX_ENDPOINT_DESCRIPTION_CONFIGURATIONS];
452
0
            SOPC_Mutex_Unlock(&tConfig.mut);
453
0
        }
454
0
    }
455
0
    return res;
456
0
}
457
458
SOPC_SecureChannelConfigIdx SOPC_ToolkitServer_AddSecureChannelConfig(SOPC_SecureChannel_Config* scConfig)
459
0
{
460
0
    SOPC_ASSERT(NULL != scConfig);
461
462
0
    SOPC_SecureChannelConfigIdx lastScIdx = 0;
463
0
    SOPC_SecureChannelConfigIdx idxWithServerOffset = 0;
464
465
    // TODO: check all parameters of scConfig (requested lifetime >= MIN, etc)
466
0
    if (tConfig.initDone)
467
0
    {
468
0
        SOPC_Mutex_Lock(&tConfig.mut);
469
0
        lastScIdx = tConfig.serverScLastConfigIdx;
470
0
        do
471
0
        {
472
0
            if (lastScIdx < SOPC_MAX_SECURE_CONNECTIONS_PLUS_BUFFERED)
473
0
            {
474
0
                lastScIdx++; // Minimum used == 1 && Maximum used == MAX + 1
475
0
                if (NULL == tConfig.serverScConfigs[lastScIdx])
476
0
                {
477
0
                    tConfig.serverScLastConfigIdx = lastScIdx;
478
0
                    tConfig.serverScConfigs[lastScIdx] = scConfig;
479
0
                    idxWithServerOffset = SOPC_MAX_SECURE_CONNECTIONS_PLUS_BUFFERED +
480
0
                                          lastScIdx; // disjoint with SC config indexes for client
481
0
                }
482
0
            }
483
0
            else
484
0
            {
485
0
                lastScIdx = 0; // lastScIdx++ <=> lastScIdx = 1 will be tested next time
486
0
            }
487
0
        } while (0 == idxWithServerOffset && lastScIdx != tConfig.serverScLastConfigIdx);
488
0
        SOPC_Mutex_Unlock(&tConfig.mut);
489
0
    }
490
0
    return idxWithServerOffset;
491
0
}
492
493
static uint32_t SOPC_ToolkitServer_TranslateSecureChannelConfigIdxOffset(uint32_t serverScConfigIdx)
494
2
{
495
2
    uint32_t res = 0;
496
2
    if (serverScConfigIdx > SOPC_MAX_SECURE_CONNECTIONS_PLUS_BUFFERED &&
497
2
        serverScConfigIdx <=
498
0
            2 * SOPC_MAX_SECURE_CONNECTIONS_PLUS_BUFFERED) // disjoint with SC config indexes for client
499
0
    {
500
0
        res = serverScConfigIdx - SOPC_MAX_SECURE_CONNECTIONS_PLUS_BUFFERED;
501
0
    }
502
2
    return res;
503
2
}
504
505
SOPC_SecureChannel_Config* SOPC_ToolkitServer_GetSecureChannelConfig(uint32_t serverScConfigIdx)
506
2
{
507
2
    SOPC_SecureChannel_Config* res = NULL;
508
2
    uint32_t idxWithoutOffset = SOPC_ToolkitServer_TranslateSecureChannelConfigIdxOffset(serverScConfigIdx);
509
2
    if (idxWithoutOffset != 0 && tConfig.initDone)
510
0
    {
511
0
        SOPC_Mutex_Lock(&tConfig.mut);
512
0
        if (tConfig.serverConfigLocked)
513
0
        {
514
0
            res = tConfig.serverScConfigs[idxWithoutOffset];
515
0
        }
516
0
        SOPC_Mutex_Unlock(&tConfig.mut);
517
0
    }
518
2
    return res;
519
2
}
520
521
bool SOPC_ToolkitServer_RemoveSecureChannelConfig(uint32_t serverScConfigIdx)
522
0
{
523
0
    bool res = false;
524
0
    uint32_t idxWithoutOffset = SOPC_ToolkitServer_TranslateSecureChannelConfigIdxOffset(serverScConfigIdx);
525
0
    if (idxWithoutOffset != 0 && tConfig.initDone)
526
0
    {
527
0
        SOPC_Mutex_Lock(&tConfig.mut);
528
0
        if (tConfig.serverConfigLocked)
529
0
        {
530
0
            if (tConfig.serverScConfigs[idxWithoutOffset] != NULL)
531
0
            {
532
0
                res = true;
533
0
                SOPC_ToolkitServer_ClearScConfig_WithoutLock(idxWithoutOffset);
534
0
            }
535
0
        }
536
0
        SOPC_Mutex_Unlock(&tConfig.mut);
537
0
    }
538
0
    return res;
539
0
}
540
541
static bool SOPC_ToolkitServer_AddEndpointConfig_HasOrAddDiscoveryEndpoint(SOPC_Endpoint_Config* epConfig)
542
0
{
543
0
    SOPC_ASSERT(epConfig->nbSecuConfigs <= SOPC_MAX_SECU_POLICIES_CFG);
544
0
    int res = 0;
545
0
    bool hasNoneSecurityConfig = false;
546
0
    for (uint8_t i = 0; i < epConfig->nbSecuConfigs && !hasNoneSecurityConfig; i++)
547
0
    {
548
0
        res = strcmp(SOPC_SecurityPolicy_None_URI,
549
0
                     SOPC_String_GetRawCString(&epConfig->secuConfigurations[i].securityPolicy));
550
0
        hasNoneSecurityConfig = (0 == res);
551
0
    }
552
553
0
    if (!hasNoneSecurityConfig)
554
0
    {
555
0
        if (epConfig->nbSecuConfigs < SOPC_MAX_SECU_POLICIES_CFG)
556
0
        {
557
0
            SOPC_SecurityPolicy* secuPolicy = &epConfig->secuConfigurations[epConfig->nbSecuConfigs];
558
            // No user token policy defined to forbid any session to be activated on discovery endpoint only
559
0
            secuPolicy->nbOfUserTokenPolicies = 0;
560
0
            secuPolicy->securityModes = SOPC_SECURITY_MODE_NONE_MASK;
561
0
            SOPC_String_Initialize(&secuPolicy->securityPolicy);
562
0
            SOPC_ReturnStatus status =
563
0
                SOPC_String_AttachFromCstring(&secuPolicy->securityPolicy, SOPC_SecurityPolicy_None_URI);
564
0
            if (SOPC_STATUS_OK == status)
565
0
            {
566
                // Implicit discovery endpoint added
567
0
                epConfig->nbSecuConfigs++;
568
0
                hasNoneSecurityConfig = true;
569
0
            }
570
0
        } // else: no remaining config to add a discovery endpoint configuration
571
0
    }
572
573
0
    return hasNoneSecurityConfig;
574
0
}
575
576
SOPC_EndpointConfigIdx SOPC_ToolkitServer_AddEndpointConfig(SOPC_Endpoint_Config* epConfig)
577
0
{
578
0
    SOPC_EndpointConfigIdx result = 0;
579
0
    SOPC_ASSERT(NULL != epConfig);
580
0
    SOPC_ASSERT(NULL != epConfig->serverConfigPtr);
581
582
0
    if (epConfig->nbSecuConfigs > SOPC_MAX_SECU_POLICIES_CFG)
583
0
    {
584
0
        return result;
585
0
    }
586
587
0
    if (epConfig->hasDiscoveryEndpoint && !SOPC_ToolkitServer_AddEndpointConfig_HasOrAddDiscoveryEndpoint(epConfig))
588
0
    {
589
0
        return result;
590
0
    }
591
592
    // TODO: check all parameters of epConfig: certificate presence w.r.t. secu policy, app desc (Uris are valid
593
    // w.r.t. part 6), etc.
594
0
    if (tConfig.initDone)
595
0
    {
596
0
        SOPC_Mutex_Lock(&tConfig.mut);
597
0
        if (!tConfig.serverConfigLocked)
598
0
        {
599
0
            if (tConfig.epConfigIdxMax < SOPC_MAX_ENDPOINT_DESCRIPTION_CONFIGURATIONS)
600
0
            {
601
0
                tConfig.epConfigIdxMax++;
602
0
                SOPC_ASSERT(NULL == tConfig.epConfigs[tConfig.epConfigIdxMax]);
603
0
                tConfig.epConfigs[tConfig.epConfigIdxMax] = epConfig;
604
0
                result = tConfig.epConfigIdxMax;
605
0
            }
606
0
        }
607
0
        SOPC_Mutex_Unlock(&tConfig.mut);
608
0
    }
609
0
    return result;
610
0
}
611
612
SOPC_ReverseEndpointConfigIdx SOPC_ToolkitClient_AddReverseEndpointConfig(const char* reverseEndpointURL)
613
0
{
614
0
    SOPC_ReverseEndpointConfigIdx result = 0;
615
0
    SOPC_ASSERT(NULL != reverseEndpointURL);
616
617
0
    if (tConfig.initDone)
618
0
    {
619
0
        SOPC_Mutex_Lock(&tConfig.mut);
620
0
        if (tConfig.reverseEpConfigIdxMax < SOPC_MAX_ENDPOINT_DESCRIPTION_CONFIGURATIONS)
621
0
        {
622
0
            tConfig.reverseEpConfigIdxMax++;
623
0
            SOPC_ASSERT(NULL == tConfig.reverseEpConfigs[tConfig.reverseEpConfigIdxMax]);
624
0
            tConfig.reverseEpConfigs[tConfig.reverseEpConfigIdxMax] = reverseEndpointURL;
625
0
            result = tConfig.reverseEpConfigIdxMax;
626
0
        }
627
0
        SOPC_Mutex_Unlock(&tConfig.mut);
628
0
    }
629
0
    if (0 != result)
630
0
    {
631
        // Make server endpoint and client reverse endpoint configuration indexes disjoint
632
0
        result += SOPC_MAX_ENDPOINT_DESCRIPTION_CONFIGURATIONS;
633
0
    }
634
0
    return result;
635
0
}
636
637
SOPC_Endpoint_Config* SOPC_ToolkitServer_GetEndpointConfig(uint32_t epConfigIdx)
638
7
{
639
7
    SOPC_Endpoint_Config* res = NULL;
640
7
    if (tConfig.initDone)
641
0
    {
642
0
        SOPC_Mutex_Lock(&tConfig.mut);
643
0
        if (tConfig.serverConfigLocked)
644
0
        {
645
0
            res = tConfig.epConfigs[epConfigIdx];
646
0
        }
647
0
        SOPC_Mutex_Unlock(&tConfig.mut);
648
0
    }
649
7
    return res;
650
7
}
651
652
static void SOPC_Internal_ToolkitServer_SetAddressSpaceConfig(SOPC_AddressSpace* addressSpace)
653
0
{
654
0
    SOPC_ASSERT(NULL != addressSpace);
655
0
    address_space_bs__nodes = addressSpace;
656
0
    sopc_addressSpace_configured = true;
657
0
}
658
659
SOPC_ReturnStatus SOPC_ToolkitServer_SetAddressSpaceConfig(SOPC_AddressSpace* addressSpace)
660
0
{
661
0
    SOPC_ReturnStatus status = SOPC_STATUS_INVALID_PARAMETERS;
662
0
    if (addressSpace != NULL)
663
0
    {
664
0
        status = SOPC_STATUS_INVALID_STATE;
665
0
        if (tConfig.initDone)
666
0
        {
667
0
            SOPC_Mutex_Lock(&tConfig.mut);
668
0
            if (!tConfig.serverConfigLocked && !sopc_addressSpace_configured)
669
0
            {
670
0
                status = SOPC_STATUS_OK;
671
0
                SOPC_Internal_ToolkitServer_SetAddressSpaceConfig(addressSpace);
672
0
            }
673
0
            SOPC_Mutex_Unlock(&tConfig.mut);
674
0
        }
675
0
    }
676
0
    return status;
677
0
}
678
679
SOPC_ReturnStatus SOPC_ToolkitServer_SetAddressSpaceNotifCb(SOPC_AddressSpaceNotif_Fct* pAddSpaceNotifFct)
680
0
{
681
0
    SOPC_ReturnStatus status = SOPC_STATUS_INVALID_PARAMETERS;
682
0
    if (pAddSpaceNotifFct != NULL)
683
0
    {
684
0
        status = SOPC_STATUS_INVALID_STATE;
685
0
        if (tConfig.initDone)
686
0
        {
687
0
            SOPC_Mutex_Lock(&tConfig.mut);
688
0
            if (!tConfig.serverConfigLocked && sopc_appAddressSpaceNotificationCallback == NULL)
689
0
            {
690
0
                status = SOPC_STATUS_OK;
691
0
                sopc_appAddressSpaceNotificationCallback = pAddSpaceNotifFct;
692
0
            }
693
0
            SOPC_Mutex_Unlock(&tConfig.mut);
694
0
        }
695
0
    }
696
0
    return status;
697
0
}
698
699
SOPC_Toolkit_Build_Info SOPC_ToolkitConfig_GetBuildInfo(void)
700
0
{
701
0
    return (SOPC_Toolkit_Build_Info){SOPC_Common_GetBuildInfo(), SOPC_ClientServer_GetBuildInfo()};
702
0
}
703
704
void SOPC_ToolkitClient_ClearAllSCs(void)
705
0
{
706
0
    if (!tConfig.initDone)
707
0
    {
708
0
        return;
709
0
    }
710
    // TODO: close all sessions !
711
0
    SOPC_Services_CloseAllSCs(true);
712
0
    SOPC_Mutex_Lock(&tConfig.mut);
713
0
    memset(tConfig.scConfigs, 0, sizeof(tConfig.scConfigs));
714
0
    tConfig.scConfigIdxMax = 0;
715
0
    SOPC_Mutex_Unlock(&tConfig.mut);
716
0
}