Coverage Report

Created: 2026-02-17 07:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/S2OPC/src/ClientServer/configuration/sopc_toolkit_config.c
Line
Count
Source
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, NULL);
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 / client info 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->clientAuditInfo);
282
0
        SOPC_Free(scConfig);
283
0
        tConfig.serverScConfigs[serverScConfigIdxWithoutOffset] = NULL;
284
0
    }
285
0
}
286
287
// Deallocate fields allocated on server side only and free all the SC configs
288
static void SOPC_Toolkit_ClearServerScConfigs_WithoutLock(void)
289
0
{
290
    // Index 0 reserved for indet, index = MAX valid
291
0
    for (uint32_t i = 1; i <= SOPC_MAX_SECURE_CONNECTIONS_PLUS_BUFFERED; i++)
292
0
    {
293
0
        SOPC_ToolkitServer_ClearScConfig_WithoutLock(i);
294
0
    }
295
0
}
296
297
void SOPC_Toolkit_Clear(void)
298
0
{
299
0
    if (tConfig.initDone)
300
0
    {
301
        // Services are in charge to gracefully close all connections.
302
        // It must be done before stopping the services
303
0
        SOPC_Services_CloseAllSCs(false);
304
305
        // Ensure no new events are triggered by timers
306
0
        SOPC_EventTimer_PreClear();
307
308
0
        SOPC_Sockets_Clear();
309
0
        SOPC_SecureChannels_Clear();
310
0
        SOPC_Services_Clear();
311
0
        SOPC_App_Clear();
312
0
        SOPC_EventTimer_Clear();
313
314
0
        SOPC_Mutex_Lock(&tConfig.mut);
315
        // Note: check again the flag to avoid possible concurrency issue detection by static analysis.
316
        //       Nevertheless this function shall never be called concurrently since the mutex is destroyed after call.
317
0
        if (tConfig.initDone)
318
0
        {
319
0
            SOPC_Toolkit_ClearServerScConfigs_WithoutLock();
320
0
            sopc_appEventCallback = NULL;
321
0
            sopc_appAddressSpaceNotificationCallback = NULL;
322
0
            address_space_bs__nodes = NULL;
323
0
            sopc_addressSpace_configured = false;
324
            // Reset values to init value
325
0
            tConfig.initDone = false;
326
0
            tConfig.serverConfigLocked = false;
327
0
            tConfig.scConfigIdxMax = 0;
328
0
            tConfig.reverseEpConfigIdxMax = 0;
329
0
            tConfig.serverScLastConfigIdx = 0;
330
0
            tConfig.epConfigIdxMax = 0;
331
0
        }
332
0
        SOPC_Mutex_Unlock(&tConfig.mut);
333
0
        SOPC_Mutex_Clear(&tConfig.mut);
334
0
    }
335
0
    SOPC_Common_Clear();
336
0
}
337
338
static bool SOPC_Internal_CheckClientSecureChannelConfig(const SOPC_SecureChannel_Config* scConfig)
339
0
{
340
0
    bool result = true;
341
0
    if (!scConfig->isClientSc)
342
0
    {
343
0
        SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER, "AddSecureChannelConfig check: isClientSc flag not set");
344
0
        result = false;
345
0
    }
346
0
    if (NULL == scConfig->url)
347
0
    {
348
0
        SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER,
349
0
                               "AddSecureChannelConfig check: server endpoint URL not set");
350
0
        result = false;
351
0
    }
352
0
    if (NULL == scConfig->reqSecuPolicyUri)
353
0
    {
354
0
        SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER,
355
0
                               "AddSecureChannelConfig check: Security Policy URI not set");
356
0
        result = false;
357
0
    }
358
0
    if (scConfig->msgSecurityMode <= OpcUa_MessageSecurityMode_Invalid ||
359
0
        scConfig->msgSecurityMode >= OpcUa_MessageSecurityMode_SizeOf)
360
0
    {
361
0
        SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER, "AddSecureChannelConfig check: Security Mode not set");
362
0
        result = false;
363
0
    }
364
0
    if (scConfig->requestedLifetime < SOPC_MINIMUM_SECURE_CONNECTION_LIFETIME)
365
0
    {
366
0
        SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER,
367
0
                               "AddSecureChannelConfig check: requested lifetime is less than minimum defined: %" PRIu32
368
0
                               " < %" PRIu32,
369
0
                               scConfig->requestedLifetime, (uint32_t) SOPC_MINIMUM_SECURE_CONNECTION_LIFETIME);
370
0
        result = false;
371
0
    }
372
0
    if (NULL == scConfig->clientConfigPtr)
373
0
    {
374
0
        SOPC_Logger_TraceError(
375
0
            SOPC_LOG_MODULE_CLIENTSERVER,
376
0
            "AddSecureChannelConfig check: client application configuration (clientConfigPtr) is not defined.");
377
0
        result = false;
378
0
    }
379
0
    else if ((NULL != scConfig->reqSecuPolicyUri &&
380
0
              (0 != strcmp(scConfig->reqSecuPolicyUri, SOPC_SecurityPolicy_None_URI))) ||
381
0
             scConfig->msgSecurityMode != OpcUa_MessageSecurityMode_None)
382
0
    {
383
0
        if (NULL == scConfig->clientConfigPtr->clientPKI)
384
0
        {
385
0
            SOPC_Logger_TraceError(
386
0
                SOPC_LOG_MODULE_CLIENTSERVER,
387
0
                "AddSecureChannelConfig check: PKI is not defined but is required due to Security policy / mode");
388
0
            result = false;
389
0
        }
390
0
        if (NULL == scConfig->clientConfigPtr->clientKeyCertPair)
391
0
        {
392
0
            SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER,
393
0
                                   "AddSecureChannelConfig check: Client certificate / key pair is not defined but is "
394
0
                                   "required due to Security policy / mode");
395
0
            result = false;
396
0
        }
397
0
        if (NULL == scConfig->peerAppCert)
398
0
        {
399
0
            SOPC_Logger_TraceError(
400
0
                SOPC_LOG_MODULE_CLIENTSERVER,
401
0
                "AddSecureChannelConfig check: Server certificate (peerAppCert) is not defined but is required "
402
0
                "due to Security policy / mode");
403
0
            result = false;
404
0
        }
405
0
    }
406
0
    return result;
407
0
}
408
409
SOPC_SecureChannelConfigIdx SOPC_ToolkitClient_AddSecureChannelConfig(SOPC_SecureChannel_Config* scConfig)
410
0
{
411
0
    SOPC_ASSERT(NULL != scConfig);
412
0
    SOPC_SecureChannelConfigIdx result = 0;
413
414
0
    if (tConfig.initDone && SOPC_Internal_CheckClientSecureChannelConfig(scConfig))
415
0
    {
416
0
        SOPC_Mutex_Lock(&tConfig.mut);
417
0
        if (tConfig.scConfigIdxMax < SOPC_MAX_SECURE_CONNECTIONS_PLUS_BUFFERED)
418
0
        {
419
0
            tConfig.scConfigIdxMax++; // Minimum used == 1 && Maximum used == MAX + 1
420
0
            SOPC_ASSERT(NULL == tConfig.scConfigs[tConfig.scConfigIdxMax]);
421
0
            tConfig.scConfigs[tConfig.scConfigIdxMax] = scConfig;
422
0
            result = tConfig.scConfigIdxMax;
423
0
        }
424
0
        SOPC_Mutex_Unlock(&tConfig.mut);
425
0
    }
426
0
    return result;
427
0
}
428
429
SOPC_SecureChannel_Config* SOPC_ToolkitClient_GetSecureChannelConfig(uint32_t scConfigIdx)
430
0
{
431
0
    SOPC_SecureChannel_Config* res = NULL;
432
0
    if (scConfigIdx > 0 && scConfigIdx <= SOPC_MAX_SECURE_CONNECTIONS_PLUS_BUFFERED)
433
0
    {
434
0
        if (tConfig.initDone)
435
0
        {
436
0
            SOPC_Mutex_Lock(&tConfig.mut);
437
0
            res = tConfig.scConfigs[scConfigIdx];
438
0
            SOPC_Mutex_Unlock(&tConfig.mut);
439
0
        }
440
0
    }
441
0
    return res;
442
0
}
443
444
const char* SOPC_ToolkitClient_GetReverseEndpointURL(SOPC_ReverseEndpointConfigIdx reverseEpCfgIdx)
445
0
{
446
0
    const char* res = NULL;
447
0
    if (SOPC_IS_VALID_REVERSE_EP_CONFIGURATION(reverseEpCfgIdx))
448
0
    {
449
0
        if (tConfig.initDone)
450
0
        {
451
0
            SOPC_Mutex_Lock(&tConfig.mut);
452
0
            res = tConfig.reverseEpConfigs[reverseEpCfgIdx - SOPC_MAX_ENDPOINT_DESCRIPTION_CONFIGURATIONS];
453
0
            SOPC_Mutex_Unlock(&tConfig.mut);
454
0
        }
455
0
    }
456
0
    return res;
457
0
}
458
459
SOPC_SecureChannelConfigIdx SOPC_ToolkitServer_AddSecureChannelConfig(SOPC_SecureChannel_Config* scConfig)
460
0
{
461
0
    SOPC_ASSERT(NULL != scConfig);
462
463
0
    SOPC_SecureChannelConfigIdx lastScIdx = 0;
464
0
    SOPC_SecureChannelConfigIdx idxWithServerOffset = 0;
465
466
    // TODO: check all parameters of scConfig (requested lifetime >= MIN, etc)
467
0
    if (tConfig.initDone)
468
0
    {
469
0
        SOPC_Mutex_Lock(&tConfig.mut);
470
0
        lastScIdx = tConfig.serverScLastConfigIdx;
471
0
        do
472
0
        {
473
0
            if (lastScIdx < SOPC_MAX_SECURE_CONNECTIONS_PLUS_BUFFERED)
474
0
            {
475
0
                lastScIdx++; // Minimum used == 1 && Maximum used == MAX + 1
476
0
                if (NULL == tConfig.serverScConfigs[lastScIdx])
477
0
                {
478
0
                    tConfig.serverScLastConfigIdx = lastScIdx;
479
0
                    tConfig.serverScConfigs[lastScIdx] = scConfig;
480
0
                    idxWithServerOffset = SOPC_MAX_SECURE_CONNECTIONS_PLUS_BUFFERED +
481
0
                                          lastScIdx; // disjoint with SC config indexes for client
482
0
                }
483
0
            }
484
0
            else
485
0
            {
486
0
                lastScIdx = 0; // lastScIdx++ <=> lastScIdx = 1 will be tested next time
487
0
            }
488
0
        } while (0 == idxWithServerOffset && lastScIdx != tConfig.serverScLastConfigIdx);
489
0
        SOPC_Mutex_Unlock(&tConfig.mut);
490
0
    }
491
0
    return idxWithServerOffset;
492
0
}
493
494
static uint32_t SOPC_ToolkitServer_TranslateSecureChannelConfigIdxOffset(uint32_t serverScConfigIdx)
495
3
{
496
3
    uint32_t res = 0;
497
3
    if (serverScConfigIdx > SOPC_MAX_SECURE_CONNECTIONS_PLUS_BUFFERED &&
498
0
        serverScConfigIdx <=
499
0
            2 * SOPC_MAX_SECURE_CONNECTIONS_PLUS_BUFFERED) // disjoint with SC config indexes for client
500
0
    {
501
0
        res = serverScConfigIdx - SOPC_MAX_SECURE_CONNECTIONS_PLUS_BUFFERED;
502
0
    }
503
3
    return res;
504
3
}
505
506
SOPC_SecureChannel_Config* SOPC_ToolkitServer_GetSecureChannelConfig(uint32_t serverScConfigIdx)
507
3
{
508
3
    SOPC_SecureChannel_Config* res = NULL;
509
3
    uint32_t idxWithoutOffset = SOPC_ToolkitServer_TranslateSecureChannelConfigIdxOffset(serverScConfigIdx);
510
3
    if (idxWithoutOffset != 0 && tConfig.initDone)
511
0
    {
512
0
        SOPC_Mutex_Lock(&tConfig.mut);
513
0
        if (tConfig.serverConfigLocked)
514
0
        {
515
0
            res = tConfig.serverScConfigs[idxWithoutOffset];
516
0
        }
517
0
        SOPC_Mutex_Unlock(&tConfig.mut);
518
0
    }
519
3
    return res;
520
3
}
521
522
bool SOPC_ToolkitServer_RemoveSecureChannelConfig(uint32_t serverScConfigIdx)
523
0
{
524
0
    bool res = false;
525
0
    uint32_t idxWithoutOffset = SOPC_ToolkitServer_TranslateSecureChannelConfigIdxOffset(serverScConfigIdx);
526
0
    if (idxWithoutOffset != 0 && tConfig.initDone)
527
0
    {
528
0
        SOPC_Mutex_Lock(&tConfig.mut);
529
0
        if (tConfig.serverConfigLocked)
530
0
        {
531
0
            if (tConfig.serverScConfigs[idxWithoutOffset] != NULL)
532
0
            {
533
0
                res = true;
534
0
                SOPC_ToolkitServer_ClearScConfig_WithoutLock(idxWithoutOffset);
535
0
            }
536
0
        }
537
0
        SOPC_Mutex_Unlock(&tConfig.mut);
538
0
    }
539
0
    return res;
540
0
}
541
542
static bool SOPC_ToolkitServer_AddEndpointConfig_HasOrAddDiscoveryEndpoint(SOPC_Endpoint_Config* epConfig)
543
0
{
544
0
    SOPC_ASSERT(epConfig->nbSecuConfigs <= SOPC_MAX_SECU_POLICIES_CFG);
545
0
    int res = 0;
546
0
    bool hasNoneSecurityConfig = false;
547
0
    for (uint8_t i = 0; i < epConfig->nbSecuConfigs && !hasNoneSecurityConfig; i++)
548
0
    {
549
0
        res = strcmp(SOPC_SecurityPolicy_None_URI,
550
0
                     SOPC_String_GetRawCString(&epConfig->secuConfigurations[i].securityPolicy));
551
0
        hasNoneSecurityConfig = (0 == res);
552
0
    }
553
554
0
    if (!hasNoneSecurityConfig)
555
0
    {
556
0
        if (epConfig->nbSecuConfigs < SOPC_MAX_SECU_POLICIES_CFG)
557
0
        {
558
0
            SOPC_SecurityPolicy* secuPolicy = &epConfig->secuConfigurations[epConfig->nbSecuConfigs];
559
            // No user token policy defined to forbid any session to be activated on discovery endpoint only
560
0
            secuPolicy->nbOfUserTokenPolicies = 0;
561
0
            secuPolicy->securityModes = SOPC_SECURITY_MODE_NONE_MASK;
562
0
            SOPC_String_Initialize(&secuPolicy->securityPolicy);
563
0
            SOPC_ReturnStatus status =
564
0
                SOPC_String_AttachFromCstring(&secuPolicy->securityPolicy, SOPC_SecurityPolicy_None_URI);
565
0
            if (SOPC_STATUS_OK == status)
566
0
            {
567
                // Implicit discovery endpoint added
568
0
                epConfig->nbSecuConfigs++;
569
0
                hasNoneSecurityConfig = true;
570
0
            }
571
0
        } // else: no remaining config to add a discovery endpoint configuration
572
0
    }
573
574
0
    return hasNoneSecurityConfig;
575
0
}
576
577
SOPC_EndpointConfigIdx SOPC_ToolkitServer_AddEndpointConfig(SOPC_Endpoint_Config* epConfig)
578
0
{
579
0
    SOPC_EndpointConfigIdx result = 0;
580
0
    SOPC_ASSERT(NULL != epConfig);
581
0
    SOPC_ASSERT(NULL != epConfig->serverConfigPtr);
582
583
0
    if (epConfig->nbSecuConfigs > SOPC_MAX_SECU_POLICIES_CFG)
584
0
    {
585
0
        return result;
586
0
    }
587
588
0
    if (epConfig->hasDiscoveryEndpoint && !SOPC_ToolkitServer_AddEndpointConfig_HasOrAddDiscoveryEndpoint(epConfig))
589
0
    {
590
0
        return result;
591
0
    }
592
593
    // TODO: check all parameters of epConfig: certificate presence w.r.t. secu policy, app desc (Uris are valid
594
    // w.r.t. part 6), etc.
595
0
    if (tConfig.initDone)
596
0
    {
597
0
        SOPC_Mutex_Lock(&tConfig.mut);
598
0
        if (!tConfig.serverConfigLocked)
599
0
        {
600
0
            if (tConfig.epConfigIdxMax < SOPC_MAX_ENDPOINT_DESCRIPTION_CONFIGURATIONS)
601
0
            {
602
0
                tConfig.epConfigIdxMax++;
603
0
                SOPC_ASSERT(NULL == tConfig.epConfigs[tConfig.epConfigIdxMax]);
604
0
                tConfig.epConfigs[tConfig.epConfigIdxMax] = epConfig;
605
0
                result = tConfig.epConfigIdxMax;
606
0
            }
607
0
        }
608
0
        SOPC_Mutex_Unlock(&tConfig.mut);
609
0
    }
610
0
    return result;
611
0
}
612
613
SOPC_ReverseEndpointConfigIdx SOPC_ToolkitClient_AddReverseEndpointConfig(const char* reverseEndpointURL)
614
0
{
615
0
    SOPC_ReverseEndpointConfigIdx result = 0;
616
0
    SOPC_ASSERT(NULL != reverseEndpointURL);
617
618
0
    if (tConfig.initDone)
619
0
    {
620
0
        SOPC_Mutex_Lock(&tConfig.mut);
621
0
        if (tConfig.reverseEpConfigIdxMax < SOPC_MAX_ENDPOINT_DESCRIPTION_CONFIGURATIONS)
622
0
        {
623
0
            tConfig.reverseEpConfigIdxMax++;
624
0
            SOPC_ASSERT(NULL == tConfig.reverseEpConfigs[tConfig.reverseEpConfigIdxMax]);
625
0
            tConfig.reverseEpConfigs[tConfig.reverseEpConfigIdxMax] = reverseEndpointURL;
626
0
            result = tConfig.reverseEpConfigIdxMax;
627
0
        }
628
0
        SOPC_Mutex_Unlock(&tConfig.mut);
629
0
    }
630
0
    if (0 != result)
631
0
    {
632
        // Make server endpoint and client reverse endpoint configuration indexes disjoint
633
0
        result += SOPC_MAX_ENDPOINT_DESCRIPTION_CONFIGURATIONS;
634
0
    }
635
0
    return result;
636
0
}
637
638
SOPC_Endpoint_Config* SOPC_ToolkitServer_GetEndpointConfig(uint32_t epConfigIdx)
639
1
{
640
1
    SOPC_Endpoint_Config* res = NULL;
641
1
    if (tConfig.initDone)
642
0
    {
643
0
        SOPC_Mutex_Lock(&tConfig.mut);
644
0
        if (tConfig.serverConfigLocked)
645
0
        {
646
0
            res = tConfig.epConfigs[epConfigIdx];
647
0
        }
648
0
        SOPC_Mutex_Unlock(&tConfig.mut);
649
0
    }
650
1
    return res;
651
1
}
652
653
static void SOPC_Internal_ToolkitServer_SetAddressSpaceConfig(SOPC_AddressSpace* addressSpace)
654
0
{
655
0
    SOPC_ASSERT(NULL != addressSpace);
656
0
    address_space_bs__nodes = addressSpace;
657
0
    sopc_addressSpace_configured = true;
658
0
}
659
660
SOPC_ReturnStatus SOPC_ToolkitServer_SetAddressSpaceConfig(SOPC_AddressSpace* addressSpace)
661
0
{
662
0
    SOPC_ReturnStatus status = SOPC_STATUS_INVALID_PARAMETERS;
663
0
    if (addressSpace != NULL)
664
0
    {
665
0
        status = SOPC_STATUS_INVALID_STATE;
666
0
        if (tConfig.initDone)
667
0
        {
668
0
            SOPC_Mutex_Lock(&tConfig.mut);
669
0
            if (!tConfig.serverConfigLocked && !sopc_addressSpace_configured)
670
0
            {
671
0
                status = SOPC_STATUS_OK;
672
0
                SOPC_Internal_ToolkitServer_SetAddressSpaceConfig(addressSpace);
673
0
            }
674
0
            SOPC_Mutex_Unlock(&tConfig.mut);
675
0
        }
676
0
    }
677
0
    return status;
678
0
}
679
680
SOPC_ReturnStatus SOPC_ToolkitServer_SetAddressSpaceNotifCb(SOPC_AddressSpaceNotif_Fct* pAddSpaceNotifFct)
681
0
{
682
0
    SOPC_ReturnStatus status = SOPC_STATUS_INVALID_PARAMETERS;
683
0
    if (pAddSpaceNotifFct != NULL)
684
0
    {
685
0
        status = SOPC_STATUS_INVALID_STATE;
686
0
        if (tConfig.initDone)
687
0
        {
688
0
            SOPC_Mutex_Lock(&tConfig.mut);
689
0
            if (!tConfig.serverConfigLocked && sopc_appAddressSpaceNotificationCallback == NULL)
690
0
            {
691
0
                status = SOPC_STATUS_OK;
692
0
                sopc_appAddressSpaceNotificationCallback = pAddSpaceNotifFct;
693
0
            }
694
0
            SOPC_Mutex_Unlock(&tConfig.mut);
695
0
        }
696
0
    }
697
0
    return status;
698
0
}
699
700
SOPC_Toolkit_Build_Info SOPC_ToolkitConfig_GetBuildInfo(void)
701
0
{
702
0
    return (SOPC_Toolkit_Build_Info){SOPC_Common_GetBuildInfo(), SOPC_ClientServer_GetBuildInfo()};
703
0
}
704
705
void SOPC_ToolkitClient_ClearAllSCs(void)
706
0
{
707
0
    if (!tConfig.initDone)
708
0
    {
709
0
        return;
710
0
    }
711
    // TODO: close all sessions !
712
0
    SOPC_Services_CloseAllSCs(true);
713
0
    SOPC_Mutex_Lock(&tConfig.mut);
714
0
    memset(tConfig.scConfigs, 0, sizeof(tConfig.scConfigs));
715
0
    tConfig.scConfigIdxMax = 0;
716
0
    SOPC_Mutex_Unlock(&tConfig.mut);
717
0
}