Coverage Report

Created: 2026-06-09 06:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/open62541_15/plugins/ua_config_json.c
Line
Count
Source
1
/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
2
 * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
3
 *
4
 *    Copyright 2023 (c) Fraunhofer IOSB (Author: Noel Graf)
5
 *    Copyright 2025 (c) o6 Automation GmbH (Author: Julius Pfrommer)
6
 */
7
8
#include <open62541/plugin/log.h>
9
#include <open62541/server_config_file_based.h>
10
#include "cj5.h"
11
#include "open62541/server_config_default.h"
12
#ifdef UA_ENABLE_ENCRYPTION
13
#include "open62541/plugin/certificategroup_default.h"
14
#endif
15
16
2.51k
#define MAX_TOKENS 1024
17
18
typedef struct {
19
    const char *json;
20
    const cj5_token *tokens;
21
    size_t tokensSize;
22
    size_t index;
23
    UA_Byte depth;
24
    cj5_result result;
25
26
    UA_Logger *logging;
27
} ParsingCtx;
28
29
static UA_ByteString
30
129
getJsonPart(cj5_token tok, const char *json) {
31
129
    UA_ByteString bs;
32
129
    UA_ByteString_init(&bs);
33
129
    if(tok.type == CJ5_TOKEN_STRING) {
34
0
        bs.data = (UA_Byte*)(uintptr_t)(json + tok.start - 1);
35
0
        bs.length = (tok.end - tok.start) + 3;
36
0
        return bs;
37
129
    } else {
38
129
        bs.data = (UA_Byte*)(uintptr_t)(json + tok.start);
39
129
        bs.length = (tok.end - tok.start) + 1;
40
129
        return bs;
41
129
    }
42
129
}
43
44
/* Forward declarations*/
45
#define PARSE_JSON(TYPE) static UA_StatusCode                   \
46
    TYPE##_parseJson(ParsingCtx *ctx, void *configField, size_t *configFieldSize)
47
48
typedef UA_StatusCode
49
(*parseJsonSignature)(ParsingCtx *ctx, void *configField, size_t *configFieldSize);
50
51
#ifdef UA_ENABLE_ENCRYPTION
52
static UA_ByteString
53
loadCertificateFile(const char *const path);
54
#endif
55
56
/* The DataType "kind" is an internal type classification. It is used to
57
 * dispatch handling to the correct routines. */
58
#define UA_SERVERCONFIGFIELDKINDS 25
59
typedef enum {
60
    /* Basic Types */
61
    UA_SERVERCONFIGFIELD_INT64 = 0,
62
    UA_SERVERCONFIGFIELD_UINT16,
63
    UA_SERVERCONFIGFIELD_UINT32,
64
    UA_SERVERCONFIGFIELD_UINT64,
65
    UA_SERVERCONFIGFIELD_STRING,
66
    UA_SERVERCONFIGFIELD_LOCALIZEDTEXT,
67
    UA_SERVERCONFIGFIELD_DOUBLE,
68
    UA_SERVERCONFIGFIELD_BOOLEAN,
69
    UA_SERVERCONFIGFIELD_DURATION,
70
    UA_SERVERCONFIGFIELD_DURATIONRANGE,
71
    UA_SERVERCONFIGFIELD_UINT32RANGE,
72
73
    /* Advanced Types */
74
    UA_SERVERCONFIGFIELD_BUILDINFO,
75
    UA_SERVERCONFIGFIELD_APPLICATIONDESCRIPTION,
76
    UA_SERVERCONFIGFIELD_STRINGARRAY,
77
    UA_SERVERCONFIGFIELD_UINT32ARRAY,
78
    UA_SERVERCONFIGFIELD_DATETIME,
79
    UA_SERVERCONFIGFIELD_SUBSCRIPTIONCONFIGURATION,
80
    UA_SERVERCONFIGFIELD_TCPCONFIGURATION,
81
    UA_SERVERCONFIGFIELD_PUBSUBCONFIGURATION,
82
    UA_SERVERCONFIGFIELD_HISTORIZINGCONFIGURATION,
83
    UA_SERVERCONFIGFIELD_MDNSCONFIGURATION,
84
    UA_SERVERCONFIGFIELD_SECURITYPOLICIES,
85
    UA_SERVERCONFIGFIELD_SECURITYPKI,
86
87
    /* Enumerations */
88
    UA_SERVERCONFIGFIELD_APPLICATIONTYPE,
89
    UA_SERVERCONFIGFIELD_RULEHANDLING
90
} UA_ServerConfigFieldKind;
91
92
extern const parseJsonSignature parseJsonJumpTable[UA_SERVERCONFIGFIELDKINDS];
93
94
/*----------------------Basic Types------------------------*/
95
0
PARSE_JSON(Int64Field) {
96
0
    cj5_token tok = ctx->tokens[++ctx->index];
97
0
    UA_ByteString buf = getJsonPart(tok, ctx->json);
98
0
    UA_Int64 out;
99
0
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_INT64], NULL);
100
0
    if(retval != UA_STATUSCODE_GOOD)
101
0
        return retval;
102
0
    UA_Int64 *field = (UA_Int64*)configField;
103
0
    *field = out;
104
0
    return retval;
105
0
}
106
2
PARSE_JSON(UInt16Field) {
107
2
    cj5_token tok = ctx->tokens[++ctx->index];
108
2
    UA_ByteString buf = getJsonPart(tok, ctx->json);
109
2
    UA_UInt16 out;
110
2
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_UINT16], NULL);
111
2
    if(retval != UA_STATUSCODE_GOOD)
112
1
        return retval;
113
1
    UA_UInt16 *field = (UA_UInt16*)configField;
114
1
    *field = out;
115
1
    return retval;
116
2
}
117
89
PARSE_JSON(UInt32Field) {
118
89
    cj5_token tok = ctx->tokens[++ctx->index];
119
89
    UA_ByteString buf = getJsonPart(tok, ctx->json);
120
89
    UA_UInt32 out;
121
89
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_UINT32], NULL);
122
89
    if(retval != UA_STATUSCODE_GOOD)
123
76
        return retval;
124
13
    UA_UInt32 *field = (UA_UInt32*)configField;
125
13
    *field = out;
126
13
    return retval;
127
89
}
128
32
PARSE_JSON(UInt64Field) {
129
32
    cj5_token tok = ctx->tokens[++ctx->index];
130
32
    UA_ByteString buf = getJsonPart(tok, ctx->json);
131
32
    UA_UInt64 out;
132
32
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_UINT64], NULL);
133
32
    if(retval != UA_STATUSCODE_GOOD)
134
21
        return retval;
135
11
    UA_UInt64 *field = (UA_UInt64*)configField;
136
11
    *field = out;
137
11
    return retval;
138
32
}
139
0
PARSE_JSON(StringField) {
140
0
    cj5_token tok = ctx->tokens[++ctx->index];
141
0
    UA_ByteString buf = getJsonPart(tok, ctx->json);
142
0
    UA_String out;
143
0
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_STRING], NULL);
144
0
    if(retval != UA_STATUSCODE_GOOD)
145
0
        return retval;
146
0
    UA_String *field = (UA_String*)configField;
147
0
    if(field != NULL) {
148
0
        UA_String_clear(field);
149
0
        *field = out;
150
0
    }
151
0
    return retval;
152
0
}
153
0
PARSE_JSON(LocalizedTextField) {
154
    /*
155
     applicationName: {
156
        locale: "de-DE",
157
        text: "Test text"
158
    }
159
     */
160
0
    cj5_token tok = ctx->tokens[++ctx->index];
161
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
162
0
    UA_String locale = {.length = 0, .data = NULL};
163
0
    UA_String text = {.length = 0, .data = NULL};
164
0
    for(size_t j = tok.size/2; j > 0; j--) {
165
0
        tok = ctx->tokens[++ctx->index];
166
0
        switch (tok.type) {
167
0
        case CJ5_TOKEN_STRING: {
168
0
            char *field = (char*)UA_malloc(tok.size + 1);
169
0
            unsigned int str_len = 0;
170
0
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field, &str_len);
171
172
0
            tok = ctx->tokens[++ctx->index];
173
0
            UA_ByteString buf = getJsonPart(tok, ctx->json);
174
0
            if(strcmp(field, "locale") == 0)
175
0
                retval |= UA_decodeJson(&buf, &locale, &UA_TYPES[UA_TYPES_STRING], NULL);
176
0
            else if(strcmp(field, "text") == 0)
177
0
                retval |= UA_decodeJson(&buf, &text, &UA_TYPES[UA_TYPES_STRING], NULL);
178
0
            else {
179
0
                UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Unknown field name.");
180
0
            }
181
0
            UA_free(field);
182
0
            break;
183
0
        }
184
0
        default:
185
0
            break;
186
0
        }
187
0
    }
188
0
    UA_LocalizedText out;
189
0
    out.locale = locale;
190
0
    out.text = text;
191
0
    if(retval != UA_STATUSCODE_GOOD)
192
0
        return retval;
193
0
    UA_LocalizedText *field = (UA_LocalizedText*)configField;
194
0
    if(field != NULL) {
195
0
        UA_LocalizedText_clear(field);
196
0
        *field = out;
197
0
    }
198
0
    return retval;
199
0
}
200
0
PARSE_JSON(DoubleField) {
201
0
    cj5_token tok = ctx->tokens[++ctx->index];
202
0
    UA_ByteString buf = getJsonPart(tok, ctx->json);
203
0
    UA_Double out;
204
0
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_DOUBLE], NULL);
205
0
    if(retval != UA_STATUSCODE_GOOD)
206
0
        return retval;
207
0
    UA_Double *field = (UA_Double *)configField;
208
0
    *field = out;
209
0
    return retval;
210
0
}
211
6
PARSE_JSON(BooleanField) {
212
6
    cj5_token tok = ctx->tokens[++ctx->index];
213
6
    UA_ByteString buf = getJsonPart(tok, ctx->json);
214
6
    UA_Boolean out;
215
6
    if(tok.type != CJ5_TOKEN_BOOL) {
216
6
        UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Value of type bool expected.");
217
6
        return UA_STATUSCODE_BADTYPEMISMATCH;
218
6
    }
219
0
    UA_String val = UA_STRING("true");
220
0
    if(UA_String_equal(&val, &buf)) {
221
0
        out = true;
222
0
    }else {
223
0
        out = false;
224
0
    }
225
    /* set server config field */
226
0
    UA_Boolean *field = (UA_Boolean *)configField;
227
0
    *field = out;
228
0
    return UA_STATUSCODE_GOOD;
229
6
}
230
0
PARSE_JSON(DurationField) {
231
0
    UA_Double double_value;
232
0
    UA_StatusCode retval = DoubleField_parseJson(ctx, &double_value, NULL);
233
0
    if(retval != UA_STATUSCODE_GOOD)
234
0
        return retval;
235
0
    UA_Duration *field = (UA_Duration*)configField;
236
0
    *field = (UA_Duration)double_value;
237
0
    return retval;
238
0
}
239
0
PARSE_JSON(DurationRangeField) {
240
0
    UA_DurationRange *field = (UA_DurationRange*)configField;
241
0
    cj5_token tok = ctx->tokens[++ctx->index];
242
0
    for(size_t j = tok.size/2; j > 0; j--) {
243
0
        tok = ctx->tokens[++ctx->index];
244
0
        switch (tok.type) {
245
0
        case CJ5_TOKEN_STRING: {
246
0
            char *field_str = (char*)UA_malloc(tok.size + 1);
247
0
            unsigned int str_len = 0;
248
0
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
249
0
            if(strcmp(field_str, "min") == 0)
250
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_DURATION](ctx, &field->min, NULL);
251
0
            else if(strcmp(field_str, "max") == 0)
252
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_DURATION](ctx, &field->max, NULL);
253
0
            else {
254
0
                UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Unknown field name.");
255
0
            }
256
0
            UA_free(field_str);
257
0
            break;
258
0
        }
259
0
        default:
260
0
            break;
261
0
        }
262
0
    }
263
0
    return UA_STATUSCODE_GOOD;
264
0
}
265
0
PARSE_JSON(UInt32RangeField) {
266
0
    UA_UInt32Range *field = (UA_UInt32Range*)configField;
267
0
    cj5_token tok = ctx->tokens[++ctx->index];
268
0
    for(size_t j = tok.size/2; j > 0; j--) {
269
0
        tok = ctx->tokens[++ctx->index];
270
0
        switch (tok.type) {
271
0
        case CJ5_TOKEN_STRING: {
272
0
            char *field_str = (char*)UA_malloc(tok.size + 1);
273
0
            unsigned int str_len = 0;
274
0
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
275
0
            if(strcmp(field_str, "min") == 0)
276
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &field->min, NULL);
277
0
            else if(strcmp(field_str, "max") == 0)
278
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &field->max, NULL);
279
0
            else {
280
0
                UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Unknown field name.");
281
0
            }
282
0
            UA_free(field_str);
283
0
            break;
284
0
        }
285
0
        default:
286
0
            break;
287
0
        }
288
0
    }
289
0
    return UA_STATUSCODE_GOOD;
290
0
}
291
292
/*----------------------Advanced Types------------------------*/
293
31
PARSE_JSON(BuildInfo) {
294
31
    UA_BuildInfo *field = (UA_BuildInfo*)configField;
295
31
    cj5_token tok = ctx->tokens[++ctx->index];
296
1.66k
    for(size_t j = tok.size/2; j > 0; j--) {
297
1.63k
        tok = ctx->tokens[++ctx->index];
298
1.63k
        switch (tok.type) {
299
381
        case CJ5_TOKEN_STRING: {
300
381
            char *field_str = (char*)UA_malloc(tok.size + 1);
301
381
            unsigned int str_len = 0;
302
381
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
303
381
            if(strcmp(field_str, "productUri") == 0)
304
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->productUri, NULL);
305
381
            else if(strcmp(field_str, "manufacturerName") == 0)
306
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->manufacturerName, NULL);
307
381
            else if(strcmp(field_str, "productName") == 0)
308
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->productName, NULL);
309
381
            else if(strcmp(field_str, "softwareVersion") == 0)
310
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->softwareVersion, NULL);
311
381
            else if(strcmp(field_str, "buildNumber") == 0)
312
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->buildNumber, NULL);
313
381
            else if(strcmp(field_str, "buildDate") == 0)
314
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_DATETIME](ctx, &field->buildDate, NULL);
315
381
            else {
316
381
                UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Unknown field name.");
317
381
            }
318
381
            UA_free(field_str);
319
381
            break;
320
0
        }
321
1.25k
        default:
322
1.25k
            break;
323
1.63k
        }
324
1.63k
    }
325
31
    return UA_STATUSCODE_GOOD;
326
31
}
327
0
PARSE_JSON(ApplicationDescriptionField) {
328
0
    UA_ApplicationDescription *field = (UA_ApplicationDescription*)configField;
329
0
    cj5_token tok = ctx->tokens[++ctx->index];
330
0
    for(size_t j = tok.size/2; j > 0; j--) {
331
0
        tok = ctx->tokens[++ctx->index];
332
0
        switch (tok.type) {
333
0
        case CJ5_TOKEN_STRING: {
334
0
            char *field_str = (char*)UA_malloc(tok.size + 1);
335
0
            unsigned int str_len = 0;
336
0
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
337
0
            if(strcmp(field_str, "applicationUri") == 0)
338
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->applicationUri, NULL);
339
0
            else if(strcmp(field_str, "productUri") == 0)
340
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->productUri, NULL);
341
0
            else if(strcmp(field_str, "applicationName") == 0)
342
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_LOCALIZEDTEXT](ctx, &field->applicationName, NULL);
343
0
            else if(strcmp(field_str, "applicationType") == 0)
344
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_APPLICATIONTYPE](ctx, &field->applicationType, NULL);
345
0
            else if(strcmp(field_str, "gatewayServerUri") == 0)
346
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->gatewayServerUri, NULL);
347
0
            else if(strcmp(field_str, "discoveryProfileUri") == 0)
348
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->discoveryProfileUri, NULL);
349
0
            else if(strcmp(field_str, "discoveryUrls") == 0)
350
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRINGARRAY](ctx, &field->discoveryUrls, &field->discoveryUrlsSize);
351
0
            else {
352
0
                UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Unknown field name.");
353
0
            }
354
0
            UA_free(field_str);
355
0
            break;
356
0
        }
357
0
        default:
358
0
            break;
359
0
        }
360
0
    }
361
0
    return UA_STATUSCODE_GOOD;
362
0
}
363
0
PARSE_JSON(StringArrayField) {
364
0
    if(configFieldSize == NULL) {
365
0
        UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Pointer to the array size is not set.");
366
0
        return UA_STATUSCODE_BADARGUMENTSMISSING;
367
0
    }
368
0
    cj5_token tok = ctx->tokens[++ctx->index];
369
0
    UA_String *stringArray = (UA_String*)UA_malloc(sizeof(UA_String) * tok.size);
370
0
    size_t stringArraySize = 0;
371
0
    for(size_t j = tok.size; j > 0; j--) {
372
0
        UA_String out = {.length = 0, .data = NULL};
373
0
        parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &out, NULL);
374
0
        UA_String_copy(&out, &stringArray[stringArraySize++]);
375
0
        UA_String_clear(&out);
376
0
    }
377
    /* Add to the config */
378
0
    UA_String **field = (UA_String**)configField;
379
0
    if(*configFieldSize > 0) {
380
0
        UA_Array_delete(*field, *configFieldSize,
381
0
                        &UA_TYPES[UA_TYPES_STRING]);
382
0
        *field = NULL;
383
0
        *configFieldSize = 0;
384
0
    }
385
0
    UA_StatusCode retval =
386
0
        UA_Array_copy(stringArray, stringArraySize,
387
0
                      (void**)field, &UA_TYPES[UA_TYPES_STRING]);
388
0
    *configFieldSize = stringArraySize;
389
390
    /* Clean up */
391
0
    UA_Array_delete(stringArray, stringArraySize, &UA_TYPES[UA_TYPES_STRING]);
392
0
    return retval;
393
0
}
394
0
PARSE_JSON(UInt32ArrayField) {
395
0
    if(configFieldSize == NULL) {
396
0
        UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Pointer to the array size is not set.");
397
0
        return UA_STATUSCODE_BADARGUMENTSMISSING;
398
0
    }
399
0
    cj5_token tok = ctx->tokens[++ctx->index];
400
0
    UA_UInt32 *numberArray = (UA_UInt32*)UA_malloc(sizeof(UA_UInt32) * tok.size);
401
0
    size_t numberArraySize = 0;
402
0
    for(size_t j = tok.size; j > 0; j--) {
403
0
        UA_UInt32 value;
404
0
        UA_StatusCode retval = UInt32Field_parseJson(ctx, &value, NULL);
405
0
        if(retval != UA_STATUSCODE_GOOD)
406
0
            continue;
407
0
        numberArray[numberArraySize++] = value;
408
0
    }
409
    /* Add to the config */
410
0
    UA_UInt32 **field = (UA_UInt32**)configField;
411
0
    if(*configFieldSize > 0) {
412
0
        UA_Array_delete(*field, *configFieldSize,
413
0
                        &UA_TYPES[UA_TYPES_UINT32]);
414
0
        *field = NULL;
415
0
        *configFieldSize = 0;
416
0
    }
417
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
418
0
    if(numberArraySize > 0) {
419
0
        retval = UA_Array_copy(numberArray, numberArraySize,
420
0
                          (void **)field, &UA_TYPES[UA_TYPES_UINT32]);
421
0
        *configFieldSize = numberArraySize;
422
0
    }
423
    /* Clean up */
424
0
    UA_Array_delete(numberArray, numberArraySize, &UA_TYPES[UA_TYPES_UINT32]);
425
0
    return retval;
426
0
}
427
0
PARSE_JSON(DateTimeField) {
428
0
    cj5_token tok = ctx->tokens[++ctx->index];
429
0
    UA_ByteString buf = getJsonPart(tok, ctx->json);
430
0
    UA_DateTime out;
431
0
    UA_DateTime_init(&out);
432
0
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_DATETIME], NULL);
433
0
    if(retval != UA_STATUSCODE_GOOD)
434
0
        return retval;
435
0
    UA_DateTime *field = (UA_DateTime*)configField;
436
0
    *field = out;
437
0
    return retval;
438
0
}
439
440
663
PARSE_JSON(MdnsConfigurationField) {
441
663
#ifdef UA_ENABLE_DISCOVERY_MULTICAST
442
663
    UA_ServerConfig *config = (UA_ServerConfig*)configField;
443
663
    cj5_token tok = ctx->tokens[++ctx->index];
444
3.91k
    for(size_t j = tok.size/2; j > 0; j--) {
445
3.24k
        tok = ctx->tokens[++ctx->index];
446
3.24k
        switch (tok.type) {
447
1.79k
        case CJ5_TOKEN_STRING: {
448
1.79k
            char *field_str = (char*)UA_malloc(tok.size + 1);
449
1.79k
            unsigned int str_len = 0;
450
1.79k
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
451
1.79k
            if(strcmp(field_str, "mdnsServerName") == 0)
452
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &config->mdnsConfig.mdnsServerName, NULL);
453
1.79k
            else if(strcmp(field_str, "serverCapabilities") == 0)
454
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRINGARRAY](ctx, &config->mdnsConfig.serverCapabilities, &config->mdnsConfig.serverCapabilitiesSize);
455
1.79k
#ifdef UA_ENABLE_DISCOVERY_MULTICAST_MDNSD
456
1.79k
            else if(strcmp(field_str, "mdnsInterfaceIP") == 0)
457
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &config->mdnsInterfaceIP, NULL);
458
            /* mdnsIpAddressList and mdnsIpAddressListSize are only available if UA_HAS_GETIFADDR is not defined: */
459
# if !defined(UA_HAS_GETIFADDR)
460
            else if(strcmp(field_str, "mdnsIpAddressList") == 0)
461
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32ARRAY](ctx, &config->mdnsIpAddressList, &config->mdnsIpAddressListSize);
462
# endif
463
1.79k
#endif
464
1.79k
            else {
465
1.79k
                UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Unknown field name.");
466
1.79k
            }
467
1.79k
            UA_free(field_str);
468
1.79k
            break;
469
0
        }
470
1.45k
        default:
471
1.45k
        break;
472
3.24k
        }
473
3.24k
    }
474
663
#endif
475
663
    return UA_STATUSCODE_GOOD;
476
663
}
477
478
0
PARSE_JSON(SubscriptionConfigurationField) {
479
0
#ifdef UA_ENABLE_SUBSCRIPTIONS
480
0
    UA_ServerConfig *config = (UA_ServerConfig*)configField;
481
0
    cj5_token tok = ctx->tokens[++ctx->index];
482
0
    for(size_t j = tok.size/2; j > 0; j--) {
483
0
        tok = ctx->tokens[++ctx->index];
484
0
        switch (tok.type) {
485
0
        case CJ5_TOKEN_STRING: {
486
0
            char *field_str = (char*)UA_malloc(tok.size + 1);
487
0
            unsigned int str_len = 0;
488
0
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
489
0
            if(strcmp(field_str, "maxSubscriptions") == 0)
490
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxSubscriptions, NULL);
491
0
            else if(strcmp(field_str, "maxSubscriptionsPerSession") == 0)
492
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxSubscriptionsPerSession, NULL);
493
0
            else if(strcmp(field_str, "publishingIntervalLimits") == 0)
494
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_DURATIONRANGE](ctx, &config->publishingIntervalLimits, NULL);
495
0
            else if(strcmp(field_str, "lifeTimeCountLimits") == 0)
496
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32RANGE](ctx, &config->lifeTimeCountLimits, NULL);
497
0
            else if(strcmp(field_str, "keepAliveCountLimits") == 0)
498
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32RANGE](ctx, &config->keepAliveCountLimits, NULL);
499
0
            else if(strcmp(field_str, "maxNotificationsPerPublish") == 0)
500
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxNotificationsPerPublish, NULL);
501
0
            else if(strcmp(field_str, "enableRetransmissionQueue") == 0)
502
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->enableRetransmissionQueue, NULL);
503
0
            else if(strcmp(field_str, "maxRetransmissionQueueSize") == 0)
504
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxRetransmissionQueueSize, NULL);
505
0
# ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
506
0
            else if(strcmp(field_str, "maxEventsPerNode") == 0)
507
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxEventsPerNode, NULL);
508
0
# endif
509
0
            else if(strcmp(field_str, "maxMonitoredItems") == 0)
510
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxMonitoredItems, NULL);
511
0
            else if(strcmp(field_str, "maxMonitoredItemsPerSubscription") == 0)
512
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxMonitoredItemsPerSubscription, NULL);
513
0
            else if(strcmp(field_str, "samplingIntervalLimits") == 0)
514
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_DURATIONRANGE](ctx, &config->samplingIntervalLimits, NULL);
515
0
            else if(strcmp(field_str, "queueSizeLimits") == 0)
516
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32RANGE](ctx, &config->queueSizeLimits, NULL);
517
0
            else if(strcmp(field_str, "maxPublishReqPerSession") == 0)
518
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxPublishReqPerSession, NULL);
519
0
            else {
520
0
                UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Unknown field name.");
521
0
            }
522
0
            UA_free(field_str);
523
0
            break;
524
0
        }
525
0
        default:
526
0
            break;
527
0
        }
528
0
    }
529
0
#endif
530
0
    return UA_STATUSCODE_GOOD;
531
0
}
532
533
27
PARSE_JSON(TcpConfigurationField) {
534
27
    UA_ServerConfig *config = (UA_ServerConfig*)configField;
535
27
    cj5_token tok = ctx->tokens[++ctx->index];
536
1.59k
    for(size_t j = tok.size/2; j > 0; j--) {
537
1.56k
        tok = ctx->tokens[++ctx->index];
538
1.56k
        switch (tok.type) {
539
349
        case CJ5_TOKEN_STRING: {
540
349
            char *field_str = (char*)UA_malloc(tok.size + 1);
541
349
            unsigned int str_len = 0;
542
349
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
543
349
            if(strcmp(field_str, "tcpBufSize") == 0)
544
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->tcpBufSize, NULL);
545
349
            else if(strcmp(field_str, "tcpMaxMsgSize") == 0)
546
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->tcpMaxMsgSize, NULL);
547
349
            else if(strcmp(field_str, "tcpMaxChunks") == 0)
548
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->tcpMaxChunks, NULL);
549
349
            else {
550
349
                UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Unknown field name.");
551
349
            }
552
349
            UA_free(field_str);
553
349
            break;
554
0
        }
555
1.21k
        default:
556
1.21k
            break;
557
1.56k
        }
558
1.56k
    }
559
27
    return UA_STATUSCODE_GOOD;
560
27
}
561
562
16
PARSE_JSON(PubsubConfigurationField) {
563
16
#ifdef UA_ENABLE_PUBSUB
564
16
    UA_PubSubConfiguration *field = (UA_PubSubConfiguration*)configField;
565
16
    cj5_token tok = ctx->tokens[++ctx->index];
566
36
    for(size_t j = tok.size/2; j > 0; j--) {
567
20
        tok = ctx->tokens[++ctx->index];
568
20
        switch (tok.type) {
569
12
        case CJ5_TOKEN_STRING: {
570
12
            char *field_str = (char*)UA_malloc(tok.size + 1);
571
12
            unsigned int str_len = 0;
572
12
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
573
12
            if(strcmp(field_str, "enableDeltaFrames") == 0)
574
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &field->enableDeltaFrames, NULL);
575
12
#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
576
12
            else if(strcmp(field_str, "enableInformationModelMethods") == 0)
577
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &field->enableInformationModelMethods, NULL);
578
12
#endif
579
12
            else {
580
12
                UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Unknown field name.");
581
12
            }
582
12
            UA_free(field_str);
583
12
            break;
584
0
        }
585
8
        default:
586
8
            break;
587
20
        }
588
20
    }
589
16
#endif
590
16
    return UA_STATUSCODE_GOOD;
591
16
}
592
593
1
PARSE_JSON(HistorizingConfigurationField) {
594
1
#ifdef UA_ENABLE_HISTORIZING
595
1
    UA_ServerConfig *config = (UA_ServerConfig*)configField;
596
1
    cj5_token tok = ctx->tokens[++ctx->index];
597
2
    for(size_t j = tok.size/2; j > 0; j--) {
598
1
        tok = ctx->tokens[++ctx->index];
599
1
        switch (tok.type) {
600
1
        case CJ5_TOKEN_STRING: {
601
1
            char *field_str = (char*)UA_malloc(tok.size + 1);
602
1
            unsigned int str_len = 0;
603
1
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
604
1
            if(strcmp(field_str, "accessHistoryDataCapability") == 0)
605
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->accessHistoryDataCapability, NULL);
606
1
            else if(strcmp(field_str, "maxReturnDataValues") == 0)
607
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxReturnDataValues, NULL);
608
1
            else if(strcmp(field_str, "accessHistoryEventsCapability") == 0)
609
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->accessHistoryEventsCapability, NULL);
610
1
            else if(strcmp(field_str, "maxReturnEventValues") == 0)
611
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxReturnEventValues, NULL);
612
1
            else if(strcmp(field_str, "insertDataCapability") == 0)
613
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->insertDataCapability, NULL);
614
1
            else if(strcmp(field_str, "insertEventCapability") == 0)
615
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->insertEventCapability, NULL);
616
1
            else if(strcmp(field_str, "insertAnnotationsCapability") == 0)
617
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->insertAnnotationsCapability, NULL);
618
1
            else if(strcmp(field_str, "replaceDataCapability") == 0)
619
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->replaceDataCapability, NULL);
620
1
            else if(strcmp(field_str, "replaceEventCapability") == 0)
621
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->replaceEventCapability, NULL);
622
1
            else if(strcmp(field_str, "updateDataCapability") == 0)
623
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->updateDataCapability, NULL);
624
1
            else if(strcmp(field_str, "updateEventCapability") == 0)
625
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->updateEventCapability, NULL);
626
1
            else if(strcmp(field_str, "deleteRawCapability") == 0)
627
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->deleteRawCapability, NULL);
628
1
            else if(strcmp(field_str, "deleteEventCapability") == 0)
629
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->deleteEventCapability, NULL);
630
1
            else if(strcmp(field_str, "deleteAtTimeDataCapability") == 0)
631
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->deleteAtTimeDataCapability, NULL);
632
1
            else {
633
1
                UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Unknown field name.");
634
1
            }
635
1
            UA_free(field_str);
636
1
            break;
637
0
        }
638
0
        default:
639
0
            break;
640
1
        }
641
1
    }
642
1
#endif
643
1
    return UA_STATUSCODE_GOOD;
644
1
}
645
646
0
PARSE_JSON(SecurityPolciesField) {
647
0
#ifdef UA_ENABLE_ENCRYPTION
648
0
    UA_ServerConfig *config = (UA_ServerConfig*)configField;
649
650
0
    UA_String noneuri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None");
651
0
    UA_String basic128Rsa15uri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15");
652
0
    UA_String basic256uri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Basic256");
653
0
    UA_String basic256Sha256uri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256");
654
0
    UA_String aes128sha256rsaoaepuri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Aes128_Sha256_RsaOaep");
655
0
    UA_String aes256sha256rsapssuri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Aes256_Sha256_RsaPss");
656
657
0
    cj5_token tok = ctx->tokens[++ctx->index];
658
0
    for(size_t j = tok.size; j > 0; j--) {
659
660
0
        UA_String policy = {.length = 0, .data = NULL};
661
0
        UA_ByteString certificate = {.length = 0, .data = NULL};
662
0
        UA_ByteString privateKey = {.length = 0, .data = NULL};
663
664
0
        tok = ctx->tokens[++ctx->index];
665
0
        for(size_t i = tok.size / 2; i > 0; i--) {
666
0
            tok = ctx->tokens[++ctx->index];
667
0
            switch(tok.type) {
668
0
            case CJ5_TOKEN_STRING: {
669
0
                char *field_str = (char *)UA_malloc(tok.size + 1);
670
0
                unsigned int str_len = 0;
671
0
                cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
672
0
                if(strcmp(field_str, "certificate") == 0) {
673
0
                    UA_String out = {.length = 0, .data = NULL};
674
0
                    parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &out, NULL);
675
676
0
                    if(out.length > 0) {
677
0
                        char *certfile = (char *)UA_malloc(out.length + 1);
678
0
                        memcpy(certfile, out.data, out.length);
679
0
                        certfile[out.length] = '\0';
680
0
                        certificate = loadCertificateFile(certfile);
681
0
                        UA_String_clear(&out);
682
0
                        UA_free(certfile);
683
0
                    }
684
0
                } else if(strcmp(field_str, "privateKey") == 0) {
685
0
                    UA_String out = {.length = 0, .data = NULL};
686
0
                    parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &out, NULL);
687
688
0
                    if(out.length > 0) {
689
0
                        char *keyfile = (char *)UA_malloc(out.length + 1);
690
0
                        memcpy(keyfile, out.data, out.length);
691
0
                        keyfile[out.length] = '\0';
692
0
                        privateKey = loadCertificateFile(keyfile);
693
0
                        UA_String_clear(&out);
694
0
                        UA_free(keyfile);
695
0
                    }
696
0
                } else if(strcmp(field_str, "policy") == 0) {
697
0
                    parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &policy, NULL);
698
0
                } else {
699
0
                    UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Unknown field name.");
700
0
                }
701
0
                UA_free(field_str);
702
0
                break;
703
0
            }
704
0
            default:
705
0
                break;
706
0
            }
707
0
        }
708
709
0
        if(certificate.length == 0 || privateKey.length == 0) {
710
0
            UA_LOG_WARNING(ctx->logging, UA_LOGCATEGORY_APPLICATION,
711
0
                           "Certificate and PrivateKey must be set for every policy.");
712
0
            if(policy.length > 0)
713
0
                UA_String_clear(&policy);
714
0
            if(certificate.length > 0)
715
0
                UA_ByteString_clear(&certificate);
716
0
            if(privateKey.length > 0)
717
0
                UA_ByteString_clear(&privateKey);
718
0
            return UA_STATUSCODE_BADINTERNALERROR;
719
0
        }
720
0
        UA_StatusCode retval = UA_STATUSCODE_GOOD;
721
0
        if(UA_String_equal(&policy, &noneuri)) {
722
            /* Nothing to do! */
723
0
        } else if(UA_String_equal(&policy, &basic128Rsa15uri)) {
724
0
            retval = UA_ServerConfig_addSecurityPolicyBasic128Rsa15(config, &certificate, &privateKey);
725
0
            if(retval != UA_STATUSCODE_GOOD) {
726
0
                UA_LOG_WARNING(ctx->logging, UA_LOGCATEGORY_APPLICATION,
727
0
                               "Could not add SecurityPolicy#Basic128Rsa15 with error code %s",
728
0
                               UA_StatusCode_name(retval));
729
0
            }
730
0
        } else if(UA_String_equal(&policy, &basic256uri)) {
731
0
            retval = UA_ServerConfig_addSecurityPolicyBasic256(config, &certificate, &privateKey);
732
0
            if(retval != UA_STATUSCODE_GOOD) {
733
0
                UA_LOG_WARNING(ctx->logging, UA_LOGCATEGORY_APPLICATION,
734
0
                               "Could not add SecurityPolicy#Basic256 with error code %s",
735
0
                               UA_StatusCode_name(retval));
736
0
            }
737
0
        } else if(UA_String_equal(&policy, &basic256Sha256uri)) {
738
0
            retval = UA_ServerConfig_addSecurityPolicyBasic256Sha256(config, &certificate, &privateKey);
739
0
            if(retval != UA_STATUSCODE_GOOD) {
740
0
                UA_LOG_WARNING(ctx->logging, UA_LOGCATEGORY_APPLICATION,
741
0
                               "Could not add SecurityPolicy#Basic256Sha256 with error code %s",
742
0
                               UA_StatusCode_name(retval));
743
0
            }
744
0
        } else if(UA_String_equal(&policy, &aes128sha256rsaoaepuri)) {
745
0
            retval = UA_ServerConfig_addSecurityPolicyAes128Sha256RsaOaep(config, &certificate, &privateKey);
746
0
            if(retval != UA_STATUSCODE_GOOD) {
747
0
                UA_LOG_WARNING(ctx->logging, UA_LOGCATEGORY_APPLICATION,
748
0
                               "Could not add SecurityPolicy#Aes128Sha256RsaOaep with error code %s",
749
0
                               UA_StatusCode_name(retval));
750
0
            }
751
0
        } else if(UA_String_equal(&policy, &aes256sha256rsapssuri)) {
752
0
             retval = UA_ServerConfig_addSecurityPolicyAes256Sha256RsaPss(config, &certificate, &privateKey);
753
0
             if(retval != UA_STATUSCODE_GOOD) {
754
0
                 UA_LOG_WARNING(ctx->logging, UA_LOGCATEGORY_APPLICATION,
755
0
                                "Could not add SecurityPolicy#Aes256Sha256RsaPss with error code %s",
756
0
                               UA_StatusCode_name(retval));
757
0
            }
758
0
        } else {
759
0
            UA_LOG_WARNING(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Unknown Security Policy.");
760
0
        }
761
762
        /* Add all Endpoints */
763
0
        UA_ServerConfig_addAllEndpoints(config);
764
765
0
        if(policy.length > 0)
766
0
            UA_String_clear(&policy);
767
0
        if(certificate.length > 0)
768
0
            UA_ByteString_clear(&certificate);
769
0
        if(privateKey.length > 0)
770
0
            UA_ByteString_clear(&privateKey);
771
0
    }
772
0
#endif
773
0
    return UA_STATUSCODE_GOOD;
774
0
}
775
776
0
PARSE_JSON(SecurityPkiField) {
777
0
#ifdef UA_ENABLE_ENCRYPTION
778
0
    UA_ServerConfig *config = (UA_ServerConfig*)configField;
779
0
    UA_String pkiFolder = {.length = 0, .data = NULL};
780
781
0
    cj5_token tok = ctx->tokens[++ctx->index];
782
0
    UA_ByteString buf = getJsonPart(tok, ctx->json);
783
0
    UA_StatusCode retval = UA_decodeJson(&buf, &pkiFolder, &UA_TYPES[UA_TYPES_STRING], NULL);
784
0
    if(retval != UA_STATUSCODE_GOOD)
785
0
        return retval;
786
787
0
#if defined(__linux__) || defined(UA_ARCHITECTURE_WIN32)
788
    /* Set up the parameters for the filestore certificate store */
789
0
    UA_KeyValuePair params[2];
790
0
    size_t paramsSize = 2;
791
792
0
    params[0].key = UA_QUALIFIEDNAME(0, "max-trust-listsize");
793
0
    UA_Variant_setScalar(&params[0].value, &config->maxTrustListSize, &UA_TYPES[UA_TYPES_UINT32]);
794
0
    params[1].key = UA_QUALIFIEDNAME(0, "max-rejected-listsize");
795
0
    UA_Variant_setScalar(&params[1].value, &config->maxRejectedListSize, &UA_TYPES[UA_TYPES_UINT32]);
796
797
0
    UA_KeyValueMap paramsMap;
798
0
    paramsMap.map = params;
799
0
    paramsMap.mapSize = paramsSize;
800
801
    /* set server config field */
802
0
    UA_NodeId defaultApplicationGroup =
803
0
           UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
804
0
    retval = UA_CertificateGroup_Filestore(&config->secureChannelPKI, &defaultApplicationGroup,
805
0
                                           pkiFolder, config->logging, &paramsMap);
806
0
    if(retval != UA_STATUSCODE_GOOD) {
807
0
        UA_String_clear(&pkiFolder);
808
0
        return retval;
809
0
    }
810
811
0
    UA_NodeId defaultUserTokenGroup =
812
0
            UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTUSERTOKENGROUP);
813
0
    retval = UA_CertificateGroup_Filestore(&config->sessionPKI, &defaultUserTokenGroup,
814
0
                                            pkiFolder, config->logging, &paramsMap);
815
0
    if(retval != UA_STATUSCODE_GOOD) {
816
0
        UA_String_clear(&pkiFolder);
817
0
        return retval;
818
0
    }
819
820
    /* Clean up */
821
0
    UA_String_clear(&pkiFolder);
822
#else
823
    (void)config;
824
    UA_LOG_WARNING(ctx->logging, UA_LOGCATEGORY_APPLICATION,
825
                   "pkiFolder is not supported on this platform. "
826
                   "Trusted clients will not be verified.");
827
#endif
828
#else
829
    UA_LOG_WARNING(ctx->logging, UA_LOGCATEGORY_APPLICATION,
830
                   "pkiFolder is set in the config but UA_ENABLE_ENCRYPTION "
831
                   "is not enabled. Trusted clients will not be verified.");
832
#endif
833
0
    return UA_STATUSCODE_GOOD;
834
0
}
835
836
/*----------------------Enumerations------------------------*/
837
0
PARSE_JSON(ApplicationTypeField) {
838
0
    UA_UInt32 enum_value;
839
0
    UA_StatusCode retval = UInt32Field_parseJson(ctx, &enum_value, NULL);
840
0
    if(retval != UA_STATUSCODE_GOOD)
841
0
        return retval;
842
0
    UA_ApplicationType *field = (UA_ApplicationType*)configField;
843
0
    *field = (UA_ApplicationType)enum_value;
844
0
    return retval;
845
0
}
846
3
PARSE_JSON(RuleHandlingField) {
847
3
    UA_UInt32 enum_value;
848
3
    UA_StatusCode retval = UInt32Field_parseJson(ctx, &enum_value, NULL);
849
3
    if(retval != UA_STATUSCODE_GOOD)
850
1
        return retval;
851
2
    UA_RuleHandling *field = (UA_RuleHandling*)configField;
852
2
    *field = (UA_RuleHandling)enum_value;
853
2
    return retval;
854
3
}
855
856
const parseJsonSignature parseJsonJumpTable[UA_SERVERCONFIGFIELDKINDS] = {
857
    /* Basic Types */
858
    (parseJsonSignature)Int64Field_parseJson,
859
    (parseJsonSignature)UInt16Field_parseJson,
860
    (parseJsonSignature)UInt32Field_parseJson,
861
    (parseJsonSignature)UInt64Field_parseJson,
862
    (parseJsonSignature)StringField_parseJson,
863
    (parseJsonSignature)LocalizedTextField_parseJson,
864
    (parseJsonSignature)DoubleField_parseJson,
865
    (parseJsonSignature)BooleanField_parseJson,
866
    (parseJsonSignature)DurationField_parseJson,
867
    (parseJsonSignature)DurationRangeField_parseJson,
868
    (parseJsonSignature)UInt32RangeField_parseJson,
869
870
    /* Advanced Types */
871
    (parseJsonSignature)BuildInfo_parseJson,
872
    (parseJsonSignature)ApplicationDescriptionField_parseJson,
873
    (parseJsonSignature)StringArrayField_parseJson,
874
    (parseJsonSignature)UInt32ArrayField_parseJson,
875
    (parseJsonSignature)DateTimeField_parseJson,
876
    (parseJsonSignature)SubscriptionConfigurationField_parseJson,
877
    (parseJsonSignature)TcpConfigurationField_parseJson,
878
    (parseJsonSignature)PubsubConfigurationField_parseJson,
879
    (parseJsonSignature)HistorizingConfigurationField_parseJson,
880
    (parseJsonSignature)MdnsConfigurationField_parseJson,
881
    (parseJsonSignature)SecurityPolciesField_parseJson,
882
    (parseJsonSignature)SecurityPkiField_parseJson,
883
884
    /* Enumerations */
885
    (parseJsonSignature)ApplicationTypeField_parseJson,
886
    (parseJsonSignature)RuleHandlingField_parseJson,
887
};
888
889
/* Skips unknown item (simple, object or array) in config file. 
890
* Unknown items may happen if we don't support some features. 
891
* E.g. if  UA_ENABLE_ENCRYPTION is not defined and config file 
892
* contains "securityPolicies" entry.
893
*/
894
static void
895
7.61k
skipUnknownItem(ParsingCtx* ctx) {
896
7.61k
    unsigned int end = ctx->tokens[ctx->index].end;
897
11.3k
    do {
898
11.3k
        ctx->index++;
899
11.3k
    } while (ctx->index < ctx->tokensSize &&
900
9.49k
        ctx->tokens[ctx->index].start < end);
901
7.61k
}
902
903
static UA_StatusCode
904
2.51k
parseJSONConfig(UA_ServerConfig *config, UA_ByteString json_config) {
905
    // Parsing json config
906
2.51k
    const char *json = (const char*)json_config.data;
907
2.51k
    cj5_token tokens[MAX_TOKENS];
908
2.51k
    cj5_result r = cj5_parse(json, (unsigned int)json_config.length, tokens, MAX_TOKENS, NULL);
909
910
    /* Validate the parse result: must succeed and produce a root object
911
     * with at least one key-value pair (i.e. >= 2 tokens). */
912
2.51k
    if(r.error != CJ5_ERROR_NONE || r.num_tokens < 2 ||
913
1.79k
       r.tokens[0].type != CJ5_TOKEN_OBJECT)
914
724
        return UA_STATUSCODE_BADDECODINGERROR;
915
916
1.79k
    ParsingCtx ctx;
917
1.79k
    ctx.json = json;
918
1.79k
    ctx.result = r;
919
1.79k
    ctx.tokens = r.tokens;
920
1.79k
    ctx.tokensSize = r.num_tokens;
921
1.79k
    ctx.index = 1; // The first token is ignored because it is known and not needed.
922
923
1.79k
    ctx.logging = config->logging;
924
925
1.79k
    size_t serverConfigSize = 0;
926
1.79k
    if(ctx.tokens)
927
1.79k
        serverConfigSize = (ctx.tokens[ctx.index-1].size/2);
928
1.79k
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
929
11.5k
    for (size_t j = serverConfigSize; j > 0; j--) {
930
9.83k
        cj5_token tok = ctx.tokens[ctx.index];
931
9.83k
        switch (tok.type) {
932
8.40k
            case CJ5_TOKEN_STRING: {
933
8.40k
                char *field = (char*)UA_malloc(tok.size + 1);
934
8.40k
                unsigned int str_len = 0;
935
8.40k
                cj5_get_str(&ctx.result, (unsigned int)ctx.index, field, &str_len);
936
8.40k
                if(strcmp(field, "buildInfo") == 0)
937
31
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_BUILDINFO](&ctx, &config->buildInfo, NULL);
938
8.37k
                else if(strcmp(field, "applicationDescription") == 0)
939
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_APPLICATIONDESCRIPTION](&ctx, &config->applicationDescription, NULL);
940
8.37k
                else if(strcmp(field, "shutdownDelay") == 0)
941
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_DOUBLE](&ctx, &config->shutdownDelay, NULL);
942
8.37k
                else if(strcmp(field, "verifyRequestTimestamp") == 0)
943
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_RULEHANDLING](&ctx, &config->verifyRequestTimestamp, NULL);
944
8.37k
                else if(strcmp(field, "allowEmptyVariables") == 0)
945
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_RULEHANDLING](&ctx, &config->allowEmptyVariables, NULL);
946
8.37k
                else if(strcmp(field, "serverUrls") == 0)
947
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRINGARRAY](&ctx, &config->serverUrls, &config->serverUrlsSize);
948
8.37k
                else if(strcmp(field, "tcpEnabled") == 0)
949
1
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](&ctx, &config->tcpEnabled, NULL);
950
8.37k
                else if(strcmp(field, "tcp") == 0)
951
27
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_TCPCONFIGURATION](&ctx, config, NULL);
952
8.34k
                else if(strcmp(field, "securityPolicyNoneDiscoveryOnly") == 0)
953
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](&ctx, &config->securityPolicyNoneDiscoveryOnly, NULL);
954
8.34k
                else if(strcmp(field, "modellingRulesOnInstances") == 0)
955
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](&ctx, &config->modellingRulesOnInstances, NULL);
956
8.34k
                else if(strcmp(field, "maxSecureChannels") == 0)
957
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT16](&ctx, &config->maxSecureChannels, NULL);
958
8.34k
                else if(strcmp(field, "maxSecurityTokenLifetime") == 0)
959
54
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxSecurityTokenLifetime, NULL);
960
8.29k
                else if(strcmp(field, "maxSessions") == 0)
961
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT16](&ctx, &config->maxSessions, NULL);
962
8.29k
                else if(strcmp(field, "maxSessionTimeout") == 0)
963
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_DOUBLE](&ctx, &config->maxSessionTimeout, NULL);
964
8.29k
                else if(strcmp(field, "maxNodesPerRead") == 0)
965
1
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxNodesPerRead, NULL);
966
8.29k
                else if(strcmp(field, "maxNodesPerWrite") == 0)
967
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxNodesPerWrite, NULL);
968
8.29k
                else if(strcmp(field, "maxNodesPerMethodCall") == 0)
969
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxNodesPerMethodCall, NULL);
970
8.29k
                else if(strcmp(field, "maxNodesPerBrowse") == 0)
971
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxNodesPerBrowse, NULL);
972
8.29k
                else if(strcmp(field, "maxNodesPerRegisterNodes") == 0)
973
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxNodesPerRegisterNodes, NULL);
974
8.29k
                else if(strcmp(field, "maxNodesPerTranslateBrowsePathsToNodeIds") == 0)
975
1
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxNodesPerTranslateBrowsePathsToNodeIds, NULL);
976
8.29k
                else if(strcmp(field, "maxNodesPerNodeManagement") == 0)
977
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxNodesPerNodeManagement, NULL);
978
8.29k
                else if(strcmp(field, "maxMonitoredItemsPerCall") == 0)
979
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxMonitoredItemsPerCall, NULL);
980
8.29k
                else if(strcmp(field, "maxReferencesPerNode") == 0)
981
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxReferencesPerNode, NULL);
982
8.29k
                else if(strcmp(field, "reverseReconnectInterval") == 0)
983
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->reverseReconnectInterval, NULL);
984
985
8.29k
#if UA_MULTITHREADING >= 100
986
8.29k
                else if(strcmp(field, "asyncOperationTimeout") == 0)
987
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_DOUBLE](&ctx, &config->asyncOperationTimeout, NULL);
988
8.29k
                else if(strcmp(field, "maxAsyncOperationQueueSize") == 0)
989
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT64](&ctx, &config->maxAsyncOperationQueueSize, NULL);
990
8.29k
#endif
991
992
8.29k
#ifdef UA_ENABLE_DISCOVERY
993
8.29k
                else if(strcmp(field, "discoveryCleanupTimeout") == 0)
994
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->discoveryCleanupTimeout, NULL);
995
8.29k
#ifdef UA_ENABLE_DISCOVERY_MULTICAST
996
8.29k
                else if(strcmp(field, "mdnsEnabled") == 0)
997
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](&ctx, &config->mdnsEnabled, NULL);
998
8.29k
                else if(strcmp(field, "mdns") == 0)
999
663
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_MDNSCONFIGURATION](&ctx, config, NULL);
1000
7.62k
#endif
1001
7.62k
#endif
1002
1003
7.62k
#ifdef UA_ENABLE_SUBSCRIPTIONS
1004
7.62k
                else if(strcmp(field, "subscriptionsEnabled") == 0)
1005
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](&ctx, &config->subscriptionsEnabled, NULL);
1006
7.62k
                else if(strcmp(field, "subscriptions") == 0)
1007
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_SUBSCRIPTIONCONFIGURATION](&ctx, config, NULL);
1008
7.62k
# endif
1009
1010
7.62k
#ifdef UA_ENABLE_HISTORIZING
1011
7.62k
                else if(strcmp(field, "historizingEnabled") == 0)
1012
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](&ctx, &config->historizingEnabled, NULL);
1013
7.62k
                else if(strcmp(field, "historizing") == 0)
1014
1
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_HISTORIZINGCONFIGURATION](&ctx, config, NULL);
1015
7.62k
#endif
1016
1017
7.62k
#ifdef UA_ENABLE_PUBSUB
1018
7.62k
                else if(strcmp(field, "pubsubEnabled") == 0)
1019
1
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](&ctx, &config->pubsubEnabled, NULL);
1020
7.62k
                else if(strcmp(field, "pubsub") == 0)
1021
16
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_PUBSUBCONFIGURATION](&ctx, &config->pubSubConfig, NULL);
1022
7.61k
#endif
1023
7.61k
#ifdef UA_ENABLE_ENCRYPTION
1024
7.61k
                else if(strcmp(field, "securityPolicies") == 0)
1025
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_SECURITYPOLICIES](&ctx, config, NULL);
1026
7.61k
                else if(strcmp(field, "pkiFolder") == 0)
1027
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_SECURITYPKI](&ctx, config, NULL);
1028
7.61k
#endif
1029
7.61k
                else {
1030
7.61k
                    UA_LOG_WARNING(ctx.logging, UA_LOGCATEGORY_APPLICATION,
1031
7.61k
                                   "Field name '%s' unknown or misspelled. Maybe the feature is not enabled either.", field);
1032
                    /* skip the name of item */
1033
7.61k
                    ++ctx.index;
1034
                    /* skip value of unknown item */
1035
7.61k
                    skipUnknownItem(&ctx);
1036
                    /* after skipUnknownItem() ctx->index points to the name of the following item.
1037
                       We must decrement index in oder following increment will
1038
                       still set index to the right position (name of the following item) */
1039
7.61k
                    --ctx.index;
1040
7.61k
                }
1041
8.40k
                UA_free(field);
1042
8.40k
                if(retval != UA_STATUSCODE_GOOD) {
1043
53
                    UA_LOG_ERROR(ctx.logging, UA_LOGCATEGORY_APPLICATION, "An error occurred while parsing the configuration file.");
1044
53
                    return retval;
1045
53
                }
1046
8.35k
                break;
1047
8.40k
            }
1048
8.35k
            default:
1049
1.42k
                break;
1050
9.83k
        }
1051
9.77k
        ctx.index += 1;
1052
9.77k
    }
1053
1.74k
    return retval;
1054
1.79k
}
1055
1056
UA_Server *
1057
5.51k
UA_Server_newFromFile(const UA_ByteString json_config) {
1058
5.51k
    UA_ServerConfig config;
1059
5.51k
    memset(&config, 0, sizeof(UA_ServerConfig));
1060
5.51k
    UA_StatusCode res = UA_ServerConfig_setDefault(&config);
1061
5.51k
    res |= parseJSONConfig(&config, json_config);
1062
5.51k
    if(res != UA_STATUSCODE_GOOD) {
1063
1.53k
        UA_ServerConfig_clear(&config);
1064
1.53k
        return NULL;
1065
1.53k
    }
1066
3.97k
    return UA_Server_newWithConfig(&config);
1067
5.51k
}
1068
1069
UA_StatusCode
1070
0
UA_ServerConfig_updateFromFile(UA_ServerConfig *config, const UA_ByteString json_config) {
1071
0
    UA_StatusCode res = parseJSONConfig(config, json_config);
1072
0
    return res;
1073
0
}
1074
1075
#ifdef UA_ENABLE_ENCRYPTION
1076
static UA_ByteString
1077
0
loadCertificateFile(const char *const path) {
1078
0
    UA_ByteString fileContents = UA_BYTESTRING_NULL;
1079
1080
    /* Open the file */
1081
0
    FILE *fp = fopen(path, "rb");
1082
0
    if(!fp) {
1083
0
        errno = 0; /* We read errno also from the tcp layer... */
1084
0
        return fileContents;
1085
0
    }
1086
1087
    /* Get the file length, allocate the data and read */
1088
0
    if(fseek(fp, 0, SEEK_END) != 0) {
1089
0
        fclose(fp);
1090
0
        errno = 0;
1091
0
        return fileContents;
1092
0
    }
1093
1094
0
    long length = ftell(fp);
1095
0
    if(length < 0) {
1096
0
        fclose(fp);
1097
0
        errno = 0;
1098
0
        return fileContents;
1099
0
    }
1100
1101
0
    fileContents.length = (size_t)length;
1102
0
    fileContents.data = (UA_Byte *)UA_malloc(fileContents.length * sizeof(UA_Byte));
1103
0
    if(fileContents.data) {
1104
0
        if(fseek(fp, 0, SEEK_SET) != 0) {
1105
0
            fclose(fp);
1106
0
            UA_ByteString_clear(&fileContents);
1107
0
            errno = 0;
1108
0
            return fileContents;
1109
0
        }
1110
0
        size_t read = fread(fileContents.data, sizeof(UA_Byte), fileContents.length, fp);
1111
0
        if(read != fileContents.length)
1112
0
            UA_ByteString_clear(&fileContents);
1113
0
    } else {
1114
0
        fileContents.length = 0;
1115
0
    }
1116
0
    fclose(fp);
1117
1118
0
    return fileContents;
1119
0
}
1120
#endif