Coverage Report

Created: 2026-08-13 06:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/open62541/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
 *    Copyright 2026 (c) o6 Automation GmbH (Author: Moritz Bruder)
7
 */
8
9
#include <open62541/plugin/log.h>
10
#include <open62541/server.h>
11
#include <open62541/client.h>
12
#include "cj5.h"
13
#include "open62541/server_config_default.h"
14
#include "open62541/client_config_default.h"
15
#include "open62541/plugin/securitypolicy_default.h"
16
#ifdef UA_ENABLE_ENCRYPTION
17
#include "open62541/plugin/certificategroup_default.h"
18
#endif
19
#if defined(UA_ENABLE_ENCRYPTION) || defined(UA_ENABLE_LWS)
20
#include <stdio.h>
21
#include <errno.h>
22
#endif
23
24
5.72k
#define MAX_TOKENS 1024
25
26
#define LOG_UNKNOWN_FIELD(ctx, field) \
27
5.62k
    UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Unknown field name '%s'.", field)
28
29
typedef struct {
30
    const char *json;
31
    unsigned int index;
32
    UA_Byte depth;
33
    cj5_result result;
34
35
    UA_Logger *logging;
36
} ParsingCtx;
37
38
static UA_ByteString
39
42.6k
getJsonPart(cj5_token tok, const char *json) {
40
42.6k
    UA_ByteString bs;
41
42.6k
    UA_ByteString_init(&bs);
42
42.6k
    if(tok.type == CJ5_TOKEN_STRING) {
43
4.66k
        bs.data = (UA_Byte*)(uintptr_t)(json + tok.start - 1);
44
4.66k
        bs.length = (tok.end - tok.start) + 3;
45
4.66k
        return bs;
46
37.9k
    } else {
47
37.9k
        bs.data = (UA_Byte*)(uintptr_t)(json + tok.start);
48
37.9k
        bs.length = (tok.end - tok.start) + 1;
49
37.9k
        return bs;
50
37.9k
    }
51
42.6k
}
52
53
/* Advance to the next token without reading beyond the parser output. A
54
 * malformed child count can otherwise desynchronize the token walk. */
55
static cj5_token
56
391k
nextToken(ParsingCtx *ctx) {
57
391k
    if(!ctx->result.tokens || ctx->index + 1 >= ctx->result.num_tokens) {
58
370k
        ctx->index = ctx->result.num_tokens;
59
370k
        cj5_token empty;
60
370k
        memset(&empty, 0, sizeof(empty));
61
370k
        return empty;
62
370k
    }
63
21.1k
    ctx->index++;
64
21.1k
    return ctx->result.tokens[ctx->index];
65
391k
}
66
67
/* Forward declarations*/
68
#define PARSE_JSON(TYPE) static UA_StatusCode                   \
69
    TYPE##_parseJson(ParsingCtx *ctx, void *configField, size_t *configFieldSize)
70
71
typedef UA_StatusCode
72
(*parseJsonSignature)(ParsingCtx *ctx, void *configField, size_t *configFieldSize);
73
74
#if defined(UA_ENABLE_ENCRYPTION) || defined(UA_ENABLE_LWS)
75
static UA_ByteString
76
loadCertificateFile(const char *const path);
77
#endif
78
79
/*----------------------Basic Types------------------------*/
80
#if 0
81
PARSE_JSON(Int64Field) {
82
    cj5_token tok = nextToken(ctx);
83
    UA_ByteString buf = getJsonPart(tok, ctx->json);
84
    UA_Int64 out;
85
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_INT64], NULL);
86
    if(retval != UA_STATUSCODE_GOOD)
87
        return retval;
88
    UA_Int64 *field = (UA_Int64*)configField;
89
    *field = out;
90
    return retval;
91
}
92
#endif
93
0
PARSE_JSON(ByteField) {
94
0
    cj5_token tok = nextToken(ctx);
95
0
    UA_ByteString buf = getJsonPart(tok, ctx->json);
96
0
    UA_Byte out;
97
0
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_BYTE], NULL);
98
0
    if(retval != UA_STATUSCODE_GOOD)
99
0
        return retval;
100
0
    UA_Byte *field = (UA_Byte*)configField;
101
0
    *field = out;
102
0
    return retval;
103
0
}
104
145
PARSE_JSON(UInt16Field) {
105
145
    cj5_token tok = nextToken(ctx);
106
145
    UA_ByteString buf = getJsonPart(tok, ctx->json);
107
145
    UA_UInt16 out;
108
145
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_UINT16], NULL);
109
145
    if(retval != UA_STATUSCODE_GOOD)
110
120
        return retval;
111
25
    UA_UInt16 *field = (UA_UInt16*)configField;
112
25
    *field = out;
113
25
    return retval;
114
145
}
115
166
PARSE_JSON(UInt32Field) {
116
166
    cj5_token tok = nextToken(ctx);
117
166
    UA_ByteString buf = getJsonPart(tok, ctx->json);
118
166
    UA_UInt32 out;
119
166
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_UINT32], NULL);
120
166
    if(retval != UA_STATUSCODE_GOOD)
121
83
        return retval;
122
83
    UA_UInt32 *field = (UA_UInt32*)configField;
123
83
    *field = out;
124
83
    return retval;
125
166
}
126
36
PARSE_JSON(UInt64Field) {
127
36
    cj5_token tok = nextToken(ctx);
128
36
    UA_ByteString buf = getJsonPart(tok, ctx->json);
129
36
    UA_UInt64 out;
130
36
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_UINT64], NULL);
131
36
    if(retval != UA_STATUSCODE_GOOD)
132
19
        return retval;
133
17
    UA_UInt64 *field = (UA_UInt64*)configField;
134
17
    *field = out;
135
17
    return retval;
136
36
}
137
0
PARSE_JSON(Int32Field) {
138
0
    cj5_token tok = nextToken(ctx);
139
0
    UA_ByteString buf = getJsonPart(tok, ctx->json);
140
0
    UA_Int32 out;
141
0
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_INT32], NULL);
142
0
    if(retval != UA_STATUSCODE_GOOD)
143
0
        return retval;
144
0
    UA_Int32 *field = (UA_Int32*)configField;
145
0
    *field = out;
146
0
    return retval;
147
0
}
148
38.0k
PARSE_JSON(StringField) {
149
38.0k
    cj5_token tok = nextToken(ctx);
150
38.0k
    UA_ByteString buf = getJsonPart(tok, ctx->json);
151
38.0k
    UA_String out;
152
38.0k
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_STRING], NULL);
153
38.0k
    if(retval != UA_STATUSCODE_GOOD)
154
37.5k
        return retval;
155
567
    UA_String *field = (UA_String*)configField;
156
567
    if(field != NULL) {
157
567
        UA_String_clear(field);
158
567
        *field = out;
159
567
    }
160
567
    return retval;
161
38.0k
}
162
0
PARSE_JSON(ByteStringField) {
163
0
    cj5_token tok = nextToken(ctx);
164
0
    UA_ByteString buf = getJsonPart(tok, ctx->json);
165
0
    UA_ByteString out;
166
0
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_BYTESTRING], NULL);
167
0
    if(retval != UA_STATUSCODE_GOOD)
168
0
        return retval;
169
0
    UA_ByteString *field = (UA_ByteString*)configField;
170
0
    *field = out;
171
0
    return retval;
172
0
}
173
0
PARSE_JSON(LocalizedTextField) {
174
    /*
175
     applicationName: {
176
        locale: "de-DE",
177
        text: "Test text"
178
    }
179
     */
180
0
    cj5_token tok = nextToken(ctx);
181
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
182
0
    UA_String locale = {.length = 0, .data = NULL};
183
0
    UA_String text = {.length = 0, .data = NULL};
184
0
    for(size_t j = tok.size/2; j > 0; j--) {
185
0
        tok = nextToken(ctx);
186
0
        switch (tok.type) {
187
0
        case CJ5_TOKEN_STRING: {
188
0
            char *field = (char*)UA_malloc(tok.size + 1);
189
0
            unsigned int str_len = 0;
190
0
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field, &str_len);
191
192
0
            tok = nextToken(ctx);
193
0
            UA_ByteString buf = getJsonPart(tok, ctx->json);
194
0
            if(strcmp(field, "locale") == 0)
195
0
                retval |= UA_decodeJson(&buf, &locale, &UA_TYPES[UA_TYPES_STRING], NULL);
196
0
            else if(strcmp(field, "text") == 0)
197
0
                retval |= UA_decodeJson(&buf, &text, &UA_TYPES[UA_TYPES_STRING], NULL);
198
0
            else {
199
0
                LOG_UNKNOWN_FIELD(ctx, field);
200
0
            }
201
0
            UA_free(field);
202
0
            break;
203
0
        }
204
0
        default:
205
0
            break;
206
0
        }
207
0
    }
208
0
    UA_LocalizedText out;
209
0
    out.locale = locale;
210
0
    out.text = text;
211
0
    if(retval != UA_STATUSCODE_GOOD)
212
0
        return retval;
213
0
    UA_LocalizedText *field = (UA_LocalizedText*)configField;
214
0
    if(field != NULL) {
215
0
        UA_LocalizedText_clear(field);
216
0
        *field = out;
217
0
    }
218
0
    return retval;
219
0
}
220
132
PARSE_JSON(DoubleField) {
221
132
    cj5_token tok = nextToken(ctx);
222
132
    UA_ByteString buf = getJsonPart(tok, ctx->json);
223
132
    UA_Double out;
224
132
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_DOUBLE], NULL);
225
132
    if(retval != UA_STATUSCODE_GOOD)
226
17
        return retval;
227
115
    UA_Double *field = (UA_Double *)configField;
228
115
    *field = out;
229
115
    return retval;
230
132
}
231
10
PARSE_JSON(BooleanField) {
232
10
    cj5_token tok = nextToken(ctx);
233
10
    UA_ByteString buf = getJsonPart(tok, ctx->json);
234
10
    UA_Boolean out;
235
10
    if(tok.type != CJ5_TOKEN_BOOL) {
236
10
        UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Value of type bool expected.");
237
10
        return UA_STATUSCODE_BADTYPEMISMATCH;
238
10
    }
239
0
    const UA_String val = UA_STRING_STATIC("true");
240
0
    if(UA_String_equal(&val, &buf)) {
241
0
        out = true;
242
0
    }else {
243
0
        out = false;
244
0
    }
245
    /* set server config field */
246
0
    UA_Boolean *field = (UA_Boolean *)configField;
247
0
    *field = out;
248
0
    return UA_STATUSCODE_GOOD;
249
10
}
250
#ifdef UA_ENABLE_SUBSCRIPTIONS
251
0
PARSE_JSON(DurationField) {
252
0
    UA_Double double_value;
253
0
    UA_StatusCode retval = DoubleField_parseJson(ctx, &double_value, NULL);
254
0
    if(retval != UA_STATUSCODE_GOOD)
255
0
        return retval;
256
0
    UA_Duration *field = (UA_Duration*)configField;
257
0
    *field = (UA_Duration)double_value;
258
0
    return retval;
259
0
}
260
66
PARSE_JSON(DurationRangeField) {
261
66
    UA_DurationRange *field = (UA_DurationRange*)configField;
262
66
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
263
66
    cj5_token tok = nextToken(ctx);
264
964
    for(size_t j = tok.size/2; j > 0; j--) {
265
898
        tok = nextToken(ctx);
266
898
        switch (tok.type) {
267
285
        case CJ5_TOKEN_STRING: {
268
285
            char *field_str = (char*)UA_malloc(tok.size + 1);
269
285
            unsigned int str_len = 0;
270
285
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
271
285
            if(strcmp(field_str, "min") == 0)
272
0
                retval = DurationField_parseJson(ctx, &field->min, NULL);
273
285
            else if(strcmp(field_str, "max") == 0)
274
0
                retval = DurationField_parseJson(ctx, &field->max, NULL);
275
285
            else {
276
285
                LOG_UNKNOWN_FIELD(ctx, field_str);
277
285
            }
278
285
            UA_free(field_str);
279
285
            if(retval != UA_STATUSCODE_GOOD) {
280
0
                return retval;
281
0
            }
282
285
            break;
283
285
        }
284
613
        default:
285
613
            break;
286
898
        }
287
898
    }
288
66
    return UA_STATUSCODE_GOOD;
289
66
}
290
164
PARSE_JSON(UInt32RangeField) {
291
164
    UA_UInt32Range *field = (UA_UInt32Range*)configField;
292
164
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
293
164
    cj5_token tok = nextToken(ctx);
294
968
    for(size_t j = tok.size/2; j > 0; j--) {
295
805
        tok = nextToken(ctx);
296
805
        switch (tok.type) {
297
226
        case CJ5_TOKEN_STRING: {
298
226
            char *field_str = (char*)UA_malloc(tok.size + 1);
299
226
            unsigned int str_len = 0;
300
226
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
301
226
            if(strcmp(field_str, "min") == 0)
302
0
                retval = UInt32Field_parseJson(ctx, &field->min, NULL);
303
226
            else if(strcmp(field_str, "max") == 0)
304
1
                retval = UInt32Field_parseJson(ctx, &field->max, NULL);
305
225
            else {
306
225
                LOG_UNKNOWN_FIELD(ctx, field_str);
307
225
            }
308
226
            UA_free(field_str);
309
226
            if(retval != UA_STATUSCODE_GOOD) {
310
1
                return retval;
311
1
            }
312
225
            break;
313
226
        }
314
579
        default:
315
579
            break;
316
805
        }
317
805
    }
318
163
    return UA_STATUSCODE_GOOD;
319
164
}
320
#endif
321
322
/*----------------------Advanced Types------------------------*/
323
26
PARSE_JSON(StringArrayField) {
324
26
    if(configFieldSize == NULL) {
325
0
        UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Pointer to the array size is not set.");
326
0
        return UA_STATUSCODE_BADARGUMENTSMISSING;
327
0
    }
328
26
    cj5_token tok = nextToken(ctx);
329
26
    UA_String *stringArray = (UA_String*)UA_malloc(sizeof(UA_String) * tok.size);
330
26
    size_t stringArraySize = 0;
331
51
    for(size_t j = tok.size; j > 0; j--) {
332
28
        UA_String out = {.length = 0, .data = NULL};
333
28
        UA_StatusCode retval = StringField_parseJson(ctx, &out, NULL);
334
28
        if(retval != UA_STATUSCODE_GOOD) {
335
3
            UA_String_clear(&out);
336
3
            UA_Array_delete(stringArray, stringArraySize, &UA_TYPES[UA_TYPES_STRING]);
337
3
            return retval;
338
3
        }
339
25
        UA_String_copy(&out, &stringArray[stringArraySize++]);
340
25
        UA_String_clear(&out);
341
25
    }
342
    /* Add to the config */
343
23
    UA_String **field = (UA_String**)configField;
344
23
    if(*configFieldSize > 0) {
345
23
        UA_Array_delete(*field, *configFieldSize,
346
23
                        &UA_TYPES[UA_TYPES_STRING]);
347
23
        *field = NULL;
348
23
        *configFieldSize = 0;
349
23
    }
350
23
    UA_StatusCode retval =
351
23
        UA_Array_copy(stringArray, stringArraySize,
352
23
                      (void**)field, &UA_TYPES[UA_TYPES_STRING]);
353
23
    *configFieldSize = stringArraySize;
354
355
    /* Clean up */
356
23
    UA_Array_delete(stringArray, stringArraySize, &UA_TYPES[UA_TYPES_STRING]);
357
23
    return retval;
358
26
}
359
2
PARSE_JSON(DateTimeField) {
360
2
    cj5_token tok = nextToken(ctx);
361
2
    UA_ByteString buf = getJsonPart(tok, ctx->json);
362
2
    UA_DateTime out;
363
2
    UA_DateTime_init(&out);
364
2
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_DATETIME], NULL);
365
2
    if(retval != UA_STATUSCODE_GOOD)
366
2
        return retval;
367
0
    UA_DateTime *field = (UA_DateTime*)configField;
368
0
    *field = out;
369
0
    return retval;
370
2
}
371
122
PARSE_JSON(BuildInfo) {
372
122
    UA_BuildInfo *field = (UA_BuildInfo*)configField;
373
122
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
374
122
    cj5_token tok = nextToken(ctx);
375
7.14k
    for(size_t j = tok.size/2; j > 0; j--) {
376
7.02k
        tok = nextToken(ctx);
377
7.02k
        switch (tok.type) {
378
453
        case CJ5_TOKEN_STRING: {
379
453
            char *field_str = (char*)UA_malloc(tok.size + 1);
380
453
            unsigned int str_len = 0;
381
453
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
382
453
            if(strcmp(field_str, "productUri") == 0)
383
1
                retval = StringField_parseJson(ctx, &field->productUri, NULL);
384
452
            else if(strcmp(field_str, "manufacturerName") == 0)
385
0
                retval = StringField_parseJson(ctx, &field->manufacturerName, NULL);
386
452
            else if(strcmp(field_str, "productName") == 0)
387
0
                retval = StringField_parseJson(ctx, &field->productName, NULL);
388
452
            else if(strcmp(field_str, "softwareVersion") == 0)
389
0
                retval = StringField_parseJson(ctx, &field->softwareVersion, NULL);
390
452
            else if(strcmp(field_str, "buildNumber") == 0)
391
4
                retval = StringField_parseJson(ctx, &field->buildNumber, NULL);
392
448
            else if(strcmp(field_str, "buildDate") == 0)
393
2
                retval = DateTimeField_parseJson(ctx, &field->buildDate, NULL);
394
446
            else {
395
446
                LOG_UNKNOWN_FIELD(ctx, field_str);
396
446
            }
397
453
            UA_free(field_str);
398
453
            if(retval != UA_STATUSCODE_GOOD) {
399
7
                return retval;
400
7
            }
401
446
            break;
402
453
        }
403
6.57k
        default:
404
6.57k
            break;
405
7.02k
        }
406
7.02k
    }
407
115
    return UA_STATUSCODE_GOOD;
408
122
}
409
410
1
PARSE_JSON(ApplicationTypeField) {
411
1
    cj5_token tok = nextToken(ctx);
412
1
    UA_ByteString rawToken = getJsonPart(tok, ctx->json);
413
1
    UA_ApplicationType *field = (UA_ApplicationType*)configField;
414
1
    char *fieldStr = (char*)UA_malloc(tok.size + 1);
415
1
    unsigned int strLen = 0;
416
417
1
    if(cj5_get_str(&ctx->result, (unsigned int)ctx->index, fieldStr, &strLen) == CJ5_ERROR_NONE) {
418
0
        if(strcmp("Client", fieldStr) == 0)
419
0
            *field = UA_APPLICATIONTYPE_CLIENT;
420
0
        else if(strcmp("Server", fieldStr) == 0)
421
0
            *field = UA_APPLICATIONTYPE_SERVER;
422
0
        else if(strcmp("ClientAndServer", fieldStr) == 0)
423
0
            *field = UA_APPLICATIONTYPE_CLIENTANDSERVER;
424
0
        else if(strcmp("DiscoveryServer", fieldStr) == 0)
425
0
            *field = UA_APPLICATIONTYPE_DISCOVERYSERVER;
426
0
        else {
427
0
            UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION,
428
0
                        "Unknown ApplicationType '%s'", fieldStr);
429
0
            UA_free(fieldStr);
430
0
            return UA_STATUSCODE_BAD;
431
0
        }
432
0
        UA_free(fieldStr);
433
0
        return UA_STATUSCODE_GOOD;
434
0
    }
435
1
    UA_free(fieldStr);
436
437
    /* Try numeric fallback */
438
1
    UA_UInt32 enumValue;
439
1
    UA_StatusCode retval = UA_decodeJson(&rawToken, &enumValue, &UA_TYPES[UA_TYPES_UINT32], NULL);
440
1
    if(retval != UA_STATUSCODE_GOOD) {
441
1
        UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION,
442
1
                    "Unknown ApplicationType '%S'", rawToken);
443
1
        return retval;
444
1
    }
445
0
    *field = (UA_ApplicationType)enumValue;
446
0
    return UA_STATUSCODE_GOOD;
447
1
}
448
449
typedef enum {
450
    GENERICAPPLICATIONTYPE_CLIENT,
451
    GENERICAPPLICATIONTYPE_SERVER,
452
    GENERICAPPLICATIONTYPE_ANY
453
} GenericApplicationType;
454
455
static UA_StatusCode
456
GenericApplicationDescriptionField_parseJson(ParsingCtx *ctx, void *configField, size_t *configFieldSize, GenericApplicationType type)
457
515
{
458
515
    UA_ApplicationDescription *field = (UA_ApplicationDescription*)configField;
459
515
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
460
515
    cj5_token tok = nextToken(ctx);
461
4.77k
    for(size_t j = tok.size/2; j > 0; j--) {
462
4.26k
        tok = nextToken(ctx);
463
4.26k
        switch (tok.type) {
464
1.13k
        case CJ5_TOKEN_STRING: {
465
1.13k
            char *field_str = (char*)UA_malloc(tok.size + 1);
466
1.13k
            unsigned int str_len = 0;
467
1.13k
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
468
1.13k
            if(strcmp(field_str, "applicationUri") == 0)
469
0
                retval = StringField_parseJson(ctx, &field->applicationUri, NULL);
470
1.13k
            else if(strcmp(field_str, "productUri") == 0)
471
1
                retval = StringField_parseJson(ctx, &field->productUri, NULL);
472
1.13k
            else if(strcmp(field_str, "applicationName") == 0)
473
0
                retval = LocalizedTextField_parseJson(ctx, &field->applicationName, NULL);
474
1.13k
            else if(strcmp(field_str, "applicationType") == 0 &&
475
1
                    type != GENERICAPPLICATIONTYPE_CLIENT) {
476
1
                retval = ApplicationTypeField_parseJson(ctx, &field->applicationType, NULL);
477
1
            }
478
1.13k
            else if(strcmp(field_str, "gatewayServerUri") == 0 &&
479
1
                    type != GENERICAPPLICATIONTYPE_CLIENT)
480
1
                retval = StringField_parseJson(ctx, &field->gatewayServerUri, NULL);
481
1.13k
            else if(strcmp(field_str, "discoveryProfileUri") == 0 &&
482
0
                    type != GENERICAPPLICATIONTYPE_CLIENT)
483
0
                retval = StringField_parseJson(ctx, &field->discoveryProfileUri, NULL);
484
1.13k
            else if(strcmp(field_str, "discoveryUrls") == 0)
485
0
                retval = StringArrayField_parseJson(ctx, &field->discoveryUrls, &field->discoveryUrlsSize);
486
1.13k
            else {
487
1.13k
                LOG_UNKNOWN_FIELD(ctx, field_str);
488
1.13k
            }
489
1.13k
            UA_free(field_str);
490
1.13k
            if(retval != UA_STATUSCODE_GOOD) {
491
3
                return retval;
492
3
            }
493
1.13k
            break;
494
1.13k
        }
495
3.13k
        default:
496
3.13k
            break;
497
4.26k
        }
498
4.26k
    }
499
512
    if(type == GENERICAPPLICATIONTYPE_CLIENT) {
500
0
        field->applicationType = UA_APPLICATIONTYPE_CLIENT;
501
0
        field->discoveryUrlsSize = 0;
502
0
        field->discoveryUrls = NULL;
503
0
    }
504
512
    return UA_STATUSCODE_GOOD;
505
515
}
506
507
0
PARSE_JSON(MessageSecurityMode) {
508
0
    size_t index = ++ctx->index;
509
0
    cj5_token tok = ctx->result.tokens[index];
510
0
    UA_ByteString rawToken = getJsonPart(tok, ctx->json);
511
0
    UA_MessageSecurityMode *field = (UA_MessageSecurityMode*)configField;
512
0
    char *fieldStr = (char*)UA_malloc(tok.size + 1);
513
0
    unsigned int strLen = 0;
514
515
0
    if(cj5_get_str(&ctx->result, (unsigned int)ctx->index, fieldStr, &strLen) == CJ5_ERROR_NONE) {
516
0
        if(strcmp("Invalid", fieldStr) == 0)
517
0
            *field = UA_MESSAGESECURITYMODE_INVALID;
518
0
        else if(strcmp("None", fieldStr) == 0)
519
0
            *field = UA_MESSAGESECURITYMODE_NONE;
520
0
        else if(strcmp("Sign", fieldStr) == 0)
521
0
            *field = UA_MESSAGESECURITYMODE_SIGN;
522
0
        else if(strcmp("SignAndEncrypt", fieldStr) == 0)
523
0
            *field = UA_MESSAGESECURITYMODE_SIGNANDENCRYPT;
524
0
        else {
525
0
            UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION,
526
0
                         "Unknown MessageSecurityMode '%.*s'", (int)strLen, fieldStr);
527
0
            UA_free(fieldStr);
528
0
            return UA_STATUSCODE_BAD;
529
0
        }
530
0
        UA_free(fieldStr);
531
0
        return UA_STATUSCODE_GOOD;
532
0
    }
533
0
    UA_free(fieldStr);
534
    /* Try numeric fallback */
535
0
    UA_UInt32 enumValue;
536
0
    UA_StatusCode retval = UA_decodeJson(&rawToken, &enumValue, &UA_TYPES[UA_TYPES_UINT32], NULL);
537
0
    if(retval == UA_STATUSCODE_GOOD) {
538
0
        *field = (UA_MessageSecurityMode)enumValue;
539
0
        return UA_STATUSCODE_GOOD;
540
0
    }
541
0
    UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION,
542
0
                    "Unknown MessageSecurityMode '%S'", rawToken);
543
0
    return UA_STATUSCODE_BAD;
544
0
}
545
546
#ifdef UA_ENABLE_SUBSCRIPTIONS
547
1.29k
PARSE_JSON(SubscriptionConfigurationField) {
548
1.29k
    UA_ServerConfig *config = (UA_ServerConfig*)configField;
549
1.29k
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
550
1.29k
    cj5_token tok = nextToken(ctx);
551
204k
    for(size_t j = tok.size/2; j > 0; j--) {
552
203k
        tok = nextToken(ctx);
553
203k
        switch (tok.type) {
554
2.28k
        case CJ5_TOKEN_STRING: {
555
2.28k
            char *field_str = (char*)UA_malloc(tok.size + 1);
556
2.28k
            unsigned int str_len = 0;
557
2.28k
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
558
2.28k
            if(strcmp(field_str, "maxSubscriptions") == 0)
559
1
                retval = UInt32Field_parseJson(ctx, &config->maxSubscriptions, NULL);
560
2.28k
            else if(strcmp(field_str, "maxSubscriptionsPerSession") == 0)
561
0
                retval = UInt32Field_parseJson(ctx, &config->maxSubscriptionsPerSession, NULL);
562
2.28k
            else if(strcmp(field_str, "publishingIntervalLimits") == 0)
563
19
                retval = DurationRangeField_parseJson(ctx, &config->publishingIntervalLimits, NULL);
564
2.26k
            else if(strcmp(field_str, "lifeTimeCountLimits") == 0)
565
162
                retval = UInt32RangeField_parseJson(ctx, &config->lifeTimeCountLimits, NULL);
566
2.10k
            else if(strcmp(field_str, "keepAliveCountLimits") == 0)
567
1
                retval = UInt32RangeField_parseJson(ctx, &config->keepAliveCountLimits, NULL);
568
2.09k
            else if(strcmp(field_str, "maxNotificationsPerPublish") == 0)
569
1
                retval = UInt32Field_parseJson(ctx, &config->maxNotificationsPerPublish, NULL);
570
2.09k
            else if(strcmp(field_str, "enableRetransmissionQueue") == 0)
571
0
                retval = BooleanField_parseJson(ctx, &config->enableRetransmissionQueue, NULL);
572
2.09k
            else if(strcmp(field_str, "maxRetransmissionQueueSize") == 0)
573
0
                retval = UInt32Field_parseJson(ctx, &config->maxRetransmissionQueueSize, NULL);
574
2.09k
# ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
575
2.09k
            else if(strcmp(field_str, "maxEventsPerNode") == 0)
576
0
                retval = UInt32Field_parseJson(ctx, &config->maxEventsPerNode, NULL);
577
2.09k
# endif
578
2.09k
            else if(strcmp(field_str, "maxMonitoredItems") == 0)
579
2
                retval = UInt32Field_parseJson(ctx, &config->maxMonitoredItems, NULL);
580
2.09k
            else if(strcmp(field_str, "maxMonitoredItemsPerSubscription") == 0)
581
0
                retval = UInt32Field_parseJson(ctx, &config->maxMonitoredItemsPerSubscription, NULL);
582
2.09k
            else if(strcmp(field_str, "samplingIntervalLimits") == 0)
583
47
                retval = DurationRangeField_parseJson(ctx, &config->samplingIntervalLimits, NULL);
584
2.04k
            else if(strcmp(field_str, "queueSizeLimits") == 0)
585
1
                retval = UInt32RangeField_parseJson(ctx, &config->queueSizeLimits, NULL);
586
2.04k
            else if(strcmp(field_str, "maxPublishReqPerSession") == 0)
587
0
                retval = UInt32Field_parseJson(ctx, &config->maxPublishReqPerSession, NULL);
588
2.04k
            else {
589
2.04k
                LOG_UNKNOWN_FIELD(ctx, field_str);
590
2.04k
            }
591
2.28k
            UA_free(field_str);
592
2.28k
            if(retval != UA_STATUSCODE_GOOD) {
593
5
                return retval;
594
5
            }
595
2.27k
            break;
596
2.28k
        }
597
201k
        default:
598
201k
            break;
599
203k
        }
600
203k
    }
601
1.29k
    return UA_STATUSCODE_GOOD;
602
1.29k
}
603
#endif
604
605
77
PARSE_JSON(TcpConfigurationField) {
606
77
    UA_ServerConfig *config = (UA_ServerConfig*)configField;
607
77
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
608
77
    cj5_token tok = nextToken(ctx);
609
6.74k
    for(size_t j = tok.size/2; j > 0; j--) {
610
6.66k
        tok = nextToken(ctx);
611
6.66k
        switch (tok.type) {
612
431
        case CJ5_TOKEN_STRING: {
613
431
            char *field_str = (char*)UA_malloc(tok.size + 1);
614
431
            unsigned int str_len = 0;
615
431
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
616
431
            if(strcmp(field_str, "tcpBufSize") == 0)
617
0
                retval = UInt32Field_parseJson(ctx, &config->tcpBufSize, NULL);
618
431
            else if(strcmp(field_str, "tcpMaxMsgSize") == 0)
619
1
                retval = UInt32Field_parseJson(ctx, &config->tcpMaxMsgSize, NULL);
620
430
            else if(strcmp(field_str, "tcpMaxChunks") == 0)
621
0
                retval = UInt32Field_parseJson(ctx, &config->tcpMaxChunks, NULL);
622
430
            else {
623
430
                LOG_UNKNOWN_FIELD(ctx, field_str);
624
430
            }
625
431
            UA_free(field_str);
626
431
            if(retval != UA_STATUSCODE_GOOD) {
627
1
                return retval;
628
1
            }
629
430
            break;
630
431
        }
631
6.23k
        default:
632
6.23k
            break;
633
6.66k
        }
634
6.66k
    }
635
76
    return UA_STATUSCODE_GOOD;
636
77
}
637
638
#ifdef UA_ENABLE_PUBSUB
639
71
PARSE_JSON(PubsubConfigurationField) {
640
71
    UA_PubSubConfiguration *field = (UA_PubSubConfiguration*)configField;
641
71
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
642
71
    cj5_token tok = nextToken(ctx);
643
1.50k
    for(size_t j = tok.size/2; j > 0; j--) {
644
1.43k
        tok = nextToken(ctx);
645
1.43k
        switch (tok.type) {
646
393
        case CJ5_TOKEN_STRING: {
647
393
            char *field_str = (char*)UA_malloc(tok.size + 1);
648
393
            unsigned int str_len = 0;
649
393
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
650
393
            if(strcmp(field_str, "enableDeltaFrames") == 0)
651
0
                retval = BooleanField_parseJson(ctx, &field->enableDeltaFrames, NULL);
652
393
#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
653
393
            else if(strcmp(field_str, "enableInformationModelMethods") == 0)
654
0
                retval = BooleanField_parseJson(ctx, &field->enableInformationModelMethods, NULL);
655
393
#endif
656
393
            else {
657
393
                LOG_UNKNOWN_FIELD(ctx, field_str);
658
393
            }
659
393
            UA_free(field_str);
660
393
            if(retval != UA_STATUSCODE_GOOD) {
661
0
                return retval;
662
0
            }
663
393
            break;
664
393
        }
665
1.04k
        default:
666
1.04k
            break;
667
1.43k
        }
668
1.43k
    }
669
71
    return UA_STATUSCODE_GOOD;
670
71
}
671
#endif
672
673
#ifdef UA_ENABLE_HISTORIZING
674
211
PARSE_JSON(HistorizingConfigurationField) {
675
211
    UA_ServerConfig *config = (UA_ServerConfig*)configField;
676
211
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
677
211
    cj5_token tok = nextToken(ctx);
678
5.93k
    for(size_t j = tok.size/2; j > 0; j--) {
679
5.72k
        tok = nextToken(ctx);
680
5.72k
        switch (tok.type) {
681
452
        case CJ5_TOKEN_STRING: {
682
452
            char *field_str = (char*)UA_malloc(tok.size + 1);
683
452
            unsigned int str_len = 0;
684
452
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
685
452
            if(strcmp(field_str, "accessHistoryDataCapability") == 0)
686
0
                retval = BooleanField_parseJson(ctx, &config->accessHistoryDataCapability, NULL);
687
452
            else if(strcmp(field_str, "maxReturnDataValues") == 0)
688
0
                retval = UInt32Field_parseJson(ctx, &config->maxReturnDataValues, NULL);
689
452
            else if(strcmp(field_str, "accessHistoryEventsCapability") == 0)
690
0
                retval = BooleanField_parseJson(ctx, &config->accessHistoryEventsCapability, NULL);
691
452
            else if(strcmp(field_str, "maxReturnEventValues") == 0)
692
0
                retval = UInt32Field_parseJson(ctx, &config->maxReturnEventValues, NULL);
693
452
            else if(strcmp(field_str, "insertDataCapability") == 0)
694
0
                retval = BooleanField_parseJson(ctx, &config->insertDataCapability, NULL);
695
452
            else if(strcmp(field_str, "insertEventCapability") == 0)
696
1
                retval = BooleanField_parseJson(ctx, &config->insertEventCapability, NULL);
697
451
            else if(strcmp(field_str, "insertAnnotationsCapability") == 0)
698
0
                retval = BooleanField_parseJson(ctx, &config->insertAnnotationsCapability, NULL);
699
451
            else if(strcmp(field_str, "replaceDataCapability") == 0)
700
0
                retval = BooleanField_parseJson(ctx, &config->replaceDataCapability, NULL);
701
451
            else if(strcmp(field_str, "replaceEventCapability") == 0)
702
0
                retval = BooleanField_parseJson(ctx, &config->replaceEventCapability, NULL);
703
451
            else if(strcmp(field_str, "updateDataCapability") == 0)
704
0
                retval = BooleanField_parseJson(ctx, &config->updateDataCapability, NULL);
705
451
            else if(strcmp(field_str, "updateEventCapability") == 0)
706
0
                retval = BooleanField_parseJson(ctx, &config->updateEventCapability, NULL);
707
451
            else if(strcmp(field_str, "deleteRawCapability") == 0)
708
0
                retval = BooleanField_parseJson(ctx, &config->deleteRawCapability, NULL);
709
451
            else if(strcmp(field_str, "deleteEventCapability") == 0)
710
0
                retval = BooleanField_parseJson(ctx, &config->deleteEventCapability, NULL);
711
451
            else if(strcmp(field_str, "deleteAtTimeDataCapability") == 0)
712
0
                retval = BooleanField_parseJson(ctx, &config->deleteAtTimeDataCapability, NULL);
713
451
            else {
714
451
                LOG_UNKNOWN_FIELD(ctx, field_str);
715
451
            }
716
452
            UA_free(field_str);
717
452
            if(retval != UA_STATUSCODE_GOOD) {
718
1
                return retval;
719
1
            }
720
451
            break;
721
452
        }
722
5.27k
        default:
723
5.27k
            break;
724
5.72k
        }
725
5.72k
    }
726
210
    return UA_STATUSCODE_GOOD;
727
211
}
728
#endif
729
730
static
731
UA_StatusCode
732
UA_SecurityPolicy_initByUri(UA_SecurityPolicy *policy,
733
                            UA_ApplicationType applicationType,
734
                            const UA_String *policyUri,
735
                            const UA_ByteString *localCertificate,
736
                            const UA_ByteString *localPrivateKey,
737
50
                            const UA_Logger *logger) {
738
50
    if(!policy || !policyUri)
739
0
        return UA_STATUSCODE_BADINVALIDARGUMENT;
740
741
50
    UA_ByteString certificate = UA_BYTESTRING_NULL;
742
50
    if(localCertificate)
743
50
    certificate = *localCertificate;
744
50
#ifdef UA_ENABLE_ENCRYPTION
745
50
    UA_ByteString privateKey = UA_BYTESTRING_NULL;
746
50
    if(localPrivateKey)
747
50
        privateKey = *localPrivateKey;
748
50
#endif
749
750
50
    if(UA_String_equal(policyUri, &UA_SECURITY_POLICY_NONE_URI))
751
0
        return UA_SecurityPolicy_None(policy, certificate, logger);
752
753
50
#ifdef UA_ENABLE_ENCRYPTION
754
50
    static const UA_String basic128Rsa15Uri =
755
50
        UA_STRING_STATIC("http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15");
756
50
    static const UA_String basic256Uri =
757
50
        UA_STRING_STATIC("http://opcfoundation.org/UA/SecurityPolicy#Basic256");
758
50
    static const UA_String basic256Sha256Uri =
759
50
        UA_STRING_STATIC("http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256");
760
50
    static const UA_String aes128Sha256RsaOaepUri =
761
50
        UA_STRING_STATIC("http://opcfoundation.org/UA/SecurityPolicy#Aes128_Sha256_RsaOaep");
762
50
    static const UA_String aes256Sha256RsaPssUri =
763
50
        UA_STRING_STATIC("http://opcfoundation.org/UA/SecurityPolicy#Aes256_Sha256_RsaPss");
764
50
#if defined(UA_ENABLE_ENCRYPTION_OPENSSL)
765
50
    static const UA_String eccNistP256Uri =
766
50
        UA_STRING_STATIC("http://opcfoundation.org/UA/SecurityPolicy#EccNistP256");
767
50
#endif
768
769
50
    if(UA_String_equal(policyUri, &basic128Rsa15Uri))
770
0
        return UA_SecurityPolicy_Basic128Rsa15(policy, certificate, privateKey, logger);
771
50
    if(UA_String_equal(policyUri, &basic256Uri))
772
0
        return UA_SecurityPolicy_Basic256(policy, certificate, privateKey, logger);
773
50
    if(UA_String_equal(policyUri, &basic256Sha256Uri))
774
0
        return UA_SecurityPolicy_Basic256Sha256(policy, certificate, privateKey, logger);
775
50
    if(UA_String_equal(policyUri, &aes128Sha256RsaOaepUri))
776
0
        return UA_SecurityPolicy_Aes128Sha256RsaOaep(policy, certificate, privateKey, logger);
777
50
    if(UA_String_equal(policyUri, &aes256Sha256RsaPssUri))
778
0
        return UA_SecurityPolicy_Aes256Sha256RsaPss(policy, certificate, privateKey, logger);
779
50
#if defined(UA_ENABLE_ENCRYPTION_OPENSSL)
780
50
    if(UA_String_equal(policyUri, &eccNistP256Uri))
781
0
        return UA_SecurityPolicy_EccNistP256(policy, applicationType, certificate,
782
0
                                             privateKey, logger);
783
50
#endif
784
50
#endif
785
786
50
    return UA_STATUSCODE_BADNOTSUPPORTED;
787
50
}
788
789
2
PARSE_JSON(CertificateFileField) {
790
2
    UA_ByteString *certificate = (UA_ByteString*)configField;
791
2
    UA_ByteString_init(certificate);
792
2
    UA_String filename = {.length = 0, .data = NULL};
793
794
2
    UA_StatusCode retval = StringField_parseJson(ctx, &filename, NULL);
795
2
    if(retval == UA_STATUSCODE_GOOD) {
796
0
        if (filename.length > 0) {
797
0
#if defined(UA_ENABLE_ENCRYPTION) || defined(UA_ENABLE_LWS)
798
0
            char *certfile = (char *)UA_malloc(filename.length + 1);
799
0
            memcpy(certfile, filename.data, filename.length);
800
0
            certfile[filename.length] = '\0';
801
0
            *certificate = loadCertificateFile((char const *)certfile);
802
0
            UA_free(certfile);
803
0
#endif
804
0
            UA_ByteString_clear(&filename);
805
0
        } else {
806
0
            UA_LOG_WARNING(ctx->logging, UA_LOGCATEGORY_APPLICATION,
807
0
                            "Certificate file path is empty.");
808
0
            retval = UA_STATUSCODE_BADINTERNALERROR;
809
0
        }
810
0
    }
811
2
    return retval;
812
2
}
813
814
#ifdef UA_ENABLE_LWS
815
PARSE_JSON(WebSocketConfigurationField) {
816
    UA_ServerConfig *config = (UA_ServerConfig*)configField;
817
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
818
    cj5_token tok = nextToken(ctx);
819
    for(size_t j = tok.size / 2; j > 0; j--) {
820
        tok = nextToken(ctx);
821
        if(tok.type != CJ5_TOKEN_STRING)
822
            continue;
823
824
        char *field = (char*)UA_malloc(tok.size + 1);
825
        if(!field)
826
            return UA_STATUSCODE_BADOUTOFMEMORY;
827
        unsigned int strLen = 0;
828
        cj5_get_str(&ctx->result, (unsigned int)ctx->index, field, &strLen);
829
830
        if(strcmp(field, "webSocketBufSize") == 0) {
831
            retval = UInt32Field_parseJson(ctx, &config->webSocketBufSize, NULL);
832
        } else if(strcmp(field, "webSocketMaxMsgSize") == 0) {
833
            retval = UInt32Field_parseJson(ctx, &config->webSocketMaxMsgSize, NULL);
834
        } else if(strcmp(field, "webSocketMaxChunks") == 0) {
835
            retval = UInt32Field_parseJson(ctx, &config->webSocketMaxChunks, NULL);
836
        } else if(strcmp(field, "webSocketMaxQueueSize") == 0) {
837
            retval = UInt32Field_parseJson(ctx, &config->webSocketMaxQueueSize, NULL);
838
        } else if(strcmp(field, "certificate") == 0) {
839
            UA_ByteString_clear(&config->webSocketCertificate);
840
            retval = CertificateFileField_parseJson(
841
                ctx, &config->webSocketCertificate, NULL);
842
        } else if(strcmp(field, "privateKey") == 0) {
843
            UA_ByteString_clear(&config->webSocketPrivateKey);
844
            retval = CertificateFileField_parseJson(
845
                ctx, &config->webSocketPrivateKey, NULL);
846
        } else if(strcmp(field, "privateKeyPassword") == 0) {
847
            UA_String_clear(&config->webSocketPrivateKeyPassword);
848
            retval = StringField_parseJson(
849
                ctx, &config->webSocketPrivateKeyPassword, NULL);
850
        } else {
851
            LOG_UNKNOWN_FIELD(ctx, field);
852
        }
853
        UA_free(field);
854
        if(retval != UA_STATUSCODE_GOOD)
855
            return retval;
856
    }
857
    return UA_STATUSCODE_GOOD;
858
}
859
#endif
860
861
static UA_StatusCode
862
SecurityPolicyField_parseJson(ParsingCtx *ctx, UA_SecurityPolicy *field,
863
                              UA_ApplicationType applicationType,
864
52
                              const UA_Logger *logger) {
865
52
    UA_String policy = {.length = 0, .data = NULL};
866
52
    UA_ByteString certificate = {.length = 0, .data = NULL};
867
52
    UA_ByteString privateKey = {.length = 0, .data = NULL};
868
52
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
869
870
52
    cj5_token tok = nextToken(ctx);
871
910
    for(size_t i = tok.size / 2; i > 0 && retval == UA_STATUSCODE_GOOD; i--) {
872
858
        tok = nextToken(ctx);
873
858
        switch(tok.type) {
874
218
        case CJ5_TOKEN_STRING: {
875
218
            char *field_str = (char *)UA_malloc(tok.size + 1);
876
218
            unsigned int str_len = 0;
877
218
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
878
218
            if(strcmp(field_str, "certificate") == 0) {
879
0
                retval = CertificateFileField_parseJson(ctx, &certificate, NULL);
880
218
            } else if(strcmp(field_str, "privateKey") == 0) {
881
2
                retval = CertificateFileField_parseJson(ctx, &privateKey, NULL);
882
216
            } else if(strcmp(field_str, "policy") == 0) {
883
0
                retval = StringField_parseJson(ctx, &policy, NULL);
884
216
            } else {
885
216
                LOG_UNKNOWN_FIELD(ctx, field_str);
886
216
            }
887
218
            UA_free(field_str);
888
218
            break;
889
0
        }
890
640
        default:
891
640
            break;
892
858
        }
893
858
    }
894
895
52
    if(retval == UA_STATUSCODE_GOOD) {
896
50
        retval = UA_SecurityPolicy_initByUri(field, applicationType, &policy,
897
50
                                             &certificate, &privateKey, logger);
898
50
    }
899
900
52
    if(policy.length > 0)
901
0
        UA_String_clear(&policy);
902
52
    if(certificate.length > 0)
903
0
        UA_ByteString_clear(&certificate);
904
52
    if(privateKey.length > 0)
905
0
        UA_ByteString_clear(&privateKey);
906
907
52
    return retval;
908
52
}
909
910
static UA_StatusCode
911
SecurityPoliciesField_parseJson(ParsingCtx *ctx, void *configField, size_t *configFieldSize, UA_ApplicationType applicationType,
912
52
                                const UA_Logger *logger) {
913
52
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
914
52
    UA_SecurityPolicy **securityPoliciesField = (UA_SecurityPolicy**)configField;
915
916
52
    cj5_token tok = nextToken(ctx);
917
52
    for(size_t j = tok.size; j > 0; j--) {
918
52
        UA_SecurityPolicy *tmp = (UA_SecurityPolicy*)
919
52
            UA_realloc(*securityPoliciesField, sizeof(UA_SecurityPolicy) * (*configFieldSize + 1));
920
52
        if(!tmp) {
921
0
            retval = UA_STATUSCODE_BADOUTOFMEMORY;
922
0
            break;
923
0
        }
924
52
        *securityPoliciesField = tmp;
925
52
        retval = SecurityPolicyField_parseJson(ctx, &tmp[*configFieldSize],
926
52
                                               applicationType, logger);
927
52
        if(retval != UA_STATUSCODE_GOOD) {
928
52
            if(*configFieldSize == 0) {
929
0
                UA_free(*securityPoliciesField);
930
0
                *securityPoliciesField = NULL;
931
0
            }
932
52
            break;
933
52
        }
934
0
        (*configFieldSize)++;
935
0
    }
936
52
    return retval;
937
52
}
938
939
#ifdef UA_ENABLE_ENCRYPTION
940
4.08k
PARSE_JSON(SecurityPkiField) {
941
4.08k
    UA_ServerConfig *config = (UA_ServerConfig*)configField;
942
4.08k
    UA_String pkiFolder = {.length = 0, .data = NULL};
943
944
4.08k
    cj5_token tok = nextToken(ctx);
945
4.08k
    UA_ByteString buf = getJsonPart(tok, ctx->json);
946
4.08k
    UA_StatusCode retval = UA_decodeJson(&buf, &pkiFolder, &UA_TYPES[UA_TYPES_STRING], NULL);
947
4.08k
    if(retval != UA_STATUSCODE_GOOD)
948
21
        return retval;
949
950
4.06k
#if defined(__linux__) || defined(UA_ARCHITECTURE_WIN32) || defined(__APPLE__) || defined(__OpenBSD__)
951
    /* Set up the parameters for the filestore certificate store */
952
4.06k
    UA_KeyValuePair params[2];
953
4.06k
    size_t paramsSize = 2;
954
955
4.06k
    params[0].key = UA_QUALIFIEDNAME(0, "max-trust-listsize");
956
4.06k
    UA_Variant_setScalar(&params[0].value, &config->maxTrustListSize, &UA_TYPES[UA_TYPES_UINT32]);
957
4.06k
    params[1].key = UA_QUALIFIEDNAME(0, "max-rejected-listsize");
958
4.06k
    UA_Variant_setScalar(&params[1].value, &config->maxRejectedListSize, &UA_TYPES[UA_TYPES_UINT32]);
959
960
4.06k
    UA_KeyValueMap paramsMap;
961
4.06k
    paramsMap.map = params;
962
4.06k
    paramsMap.mapSize = paramsSize;
963
964
    /* set server config field */
965
4.06k
    UA_NodeId defaultApplicationGroup =
966
4.06k
           UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
967
4.06k
    retval = UA_CertificateGroup_Filestore(&config->secureChannelPKI, &defaultApplicationGroup,
968
4.06k
                                           pkiFolder, config->logging, &paramsMap);
969
4.06k
    if(retval != UA_STATUSCODE_GOOD) {
970
96
        UA_String_clear(&pkiFolder);
971
96
        return retval;
972
96
    }
973
974
3.96k
    UA_NodeId defaultUserTokenGroup =
975
3.96k
            UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTUSERTOKENGROUP);
976
3.96k
    retval = UA_CertificateGroup_Filestore(&config->sessionPKI, &defaultUserTokenGroup,
977
3.96k
                                            pkiFolder, config->logging, &paramsMap);
978
3.96k
    if(retval != UA_STATUSCODE_GOOD) {
979
2
        UA_String_clear(&pkiFolder);
980
2
        return retval;
981
2
    }
982
983
    /* Clean up */
984
3.96k
    UA_String_clear(&pkiFolder);
985
#else
986
    (void)config;
987
    UA_LOG_WARNING(ctx->logging, UA_LOGCATEGORY_APPLICATION,
988
                   "pkiFolder is not supported on this platform. "
989
                   "Trusted clients will not be verified.");
990
#endif
991
3.96k
    return UA_STATUSCODE_GOOD;
992
3.96k
}
993
#endif
994
995
57
PARSE_JSON(RuleHandlingField) {
996
57
    UA_UInt32 enum_value;
997
57
    UA_StatusCode retval = UInt32Field_parseJson(ctx, &enum_value, NULL);
998
57
    if(retval != UA_STATUSCODE_GOOD)
999
43
        return retval;
1000
14
    UA_RuleHandling *field = (UA_RuleHandling*)configField;
1001
14
    *field = (UA_RuleHandling)enum_value;
1002
14
    return retval;
1003
57
}
1004
1005
/* Skips unknown item (simple, object or array) in config file.
1006
* Unknown items may happen if we don't support some features.
1007
* E.g. if  UA_ENABLE_ENCRYPTION is not defined and config file
1008
* contains "securityPolicies" entry.
1009
*/
1010
static void
1011
5.59k
skipUnknownItem(ParsingCtx* ctx) {
1012
5.59k
    cj5_skip(&ctx->result, &ctx->index);
1013
5.59k
}
1014
1015
static UA_StatusCode
1016
5.72k
parseJSONServerConfig(UA_ServerConfig *config, UA_ByteString json_config) {
1017
    // Parsing json config
1018
5.72k
    const char *json = (const char*)json_config.data;
1019
5.72k
    cj5_token tokens[MAX_TOKENS];
1020
5.72k
    cj5_result r = cj5_parse(json, (unsigned int)json_config.length, tokens, MAX_TOKENS, NULL);
1021
1022
    /* Validate the parse result: must succeed and produce a root object
1023
     * with at least one key-value pair (i.e. >= 2 tokens). */
1024
5.72k
    if(r.error != CJ5_ERROR_NONE || r.num_tokens < 2 ||
1025
5.07k
       r.tokens[0].type != CJ5_TOKEN_OBJECT)
1026
674
        return UA_STATUSCODE_BADDECODINGERROR;
1027
1028
5.04k
    ParsingCtx ctx;
1029
5.04k
    ctx.json = json;
1030
5.04k
    ctx.result = r;
1031
5.04k
    ctx.index = 1; // The first token is ignored because it is known and not needed.
1032
1033
5.04k
    ctx.logging = config->logging;
1034
1035
    /* Buffer for the field name */
1036
5.04k
    char field[256];
1037
1038
5.04k
    size_t serverConfigSize = 0;
1039
5.04k
    if(ctx.result.tokens)
1040
5.04k
        serverConfigSize = (ctx.result.tokens[ctx.index-1].size/2);
1041
5.04k
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
1042
22.3k
    for (size_t j = serverConfigSize; j > 0 && ctx.index < ctx.result.num_tokens; j--) {
1043
17.7k
        cj5_token tok = ctx.result.tokens[ctx.index];
1044
17.7k
        switch (tok.type) {
1045
17.3k
            case CJ5_TOKEN_STRING: {
1046
17.3k
                if(tok.size >= 255) {
1047
295
                    UA_LOG_WARNING(ctx.logging, UA_LOGCATEGORY_APPLICATION,
1048
295
                                   "Configuration field name too long");
1049
295
                    continue;
1050
295
                }
1051
17.0k
                unsigned int str_len = 0;
1052
17.0k
                cj5_error_code res = cj5_get_str(&ctx.result, (unsigned int)ctx.index, field, &str_len);
1053
17.0k
                if(res != CJ5_ERROR_NONE) {
1054
4.58k
                    UA_LOG_WARNING(ctx.logging, UA_LOGCATEGORY_APPLICATION,
1055
4.58k
                                   "Configuration field name not a valid string");
1056
4.58k
                    continue;
1057
4.58k
                }
1058
12.5k
                if(strcmp(field, "buildInfo") == 0)
1059
122
                    retval = BuildInfo_parseJson(&ctx, &config->buildInfo, NULL);
1060
12.3k
                else if(strcmp(field, "applicationDescription") == 0)
1061
515
                    retval = GenericApplicationDescriptionField_parseJson(&ctx, &config->applicationDescription, NULL, GENERICAPPLICATIONTYPE_SERVER);
1062
11.8k
                else if(strcmp(field, "shutdownDelay") == 0)
1063
120
                    retval = DoubleField_parseJson(&ctx, &config->shutdownDelay, NULL);
1064
11.7k
                else if(strcmp(field, "verifyRequestTimestamp") == 0)
1065
46
                    retval = RuleHandlingField_parseJson(&ctx, &config->verifyRequestTimestamp, NULL);
1066
11.7k
                else if(strcmp(field, "allowEmptyVariables") == 0)
1067
11
                    retval = RuleHandlingField_parseJson(&ctx, &config->allowEmptyVariables, NULL);
1068
11.7k
                else if(strcmp(field, "certificateEkuRule") == 0)
1069
0
                    retval = RuleHandlingField_parseJson(&ctx, &config->certificateEkuRule, NULL);
1070
11.7k
                else if(strcmp(field, "serverUrls") == 0)
1071
26
                    retval = StringArrayField_parseJson(&ctx, &config->serverUrls, &config->serverUrlsSize);
1072
11.6k
                else if(strcmp(field, "tcpEnabled") == 0)
1073
1
                    retval = BooleanField_parseJson(&ctx, &config->tcpEnabled, NULL);
1074
11.6k
                else if(strcmp(field, "tcp") == 0)
1075
77
                    retval = TcpConfigurationField_parseJson(&ctx, config, NULL);
1076
#ifdef UA_ENABLE_LWS
1077
                else if(strcmp(field, "webSocketEnabled") == 0)
1078
                    retval = BooleanField_parseJson(&ctx, &config->webSocketEnabled, NULL);
1079
                else if(strcmp(field, "webSocket") == 0)
1080
                    retval = WebSocketConfigurationField_parseJson(&ctx, config, NULL);
1081
#endif
1082
11.6k
                else if(strcmp(field, "securityPolicyNoneDiscoveryOnly") == 0)
1083
1
                    retval = BooleanField_parseJson(&ctx, &config->securityPolicyNoneDiscoveryOnly, NULL);
1084
11.5k
                else if(strcmp(field, "modellingRulesOnInstances") == 0)
1085
1
                    retval = BooleanField_parseJson(&ctx, &config->modellingRulesOnInstances, NULL);
1086
11.5k
                else if(strcmp(field, "copyMethodsOnInstances") == 0)
1087
1
                    retval = BooleanField_parseJson(&ctx, &config->copyMethodsOnInstances, NULL);
1088
11.5k
                else if(strcmp(field, "maxSecureChannels") == 0)
1089
2
                    retval = UInt16Field_parseJson(&ctx, &config->maxSecureChannels, NULL);
1090
11.5k
                else if(strcmp(field, "maxSecurityTokenLifetime") == 0)
1091
2
                    retval = UInt32Field_parseJson(&ctx, &config->maxSecurityTokenLifetime, NULL);
1092
11.5k
                else if(strcmp(field, "maxSessions") == 0)
1093
143
                    retval = UInt16Field_parseJson(&ctx, &config->maxSessions, NULL);
1094
11.4k
                else if(strcmp(field, "maxSessionTimeout") == 0)
1095
10
                    retval = DoubleField_parseJson(&ctx, &config->maxSessionTimeout, NULL);
1096
11.4k
                else if(strcmp(field, "maxNodesPerRead") == 0)
1097
1
                    retval = UInt32Field_parseJson(&ctx, &config->maxNodesPerRead, NULL);
1098
11.4k
                else if(strcmp(field, "maxNodesPerWrite") == 0)
1099
3
                    retval = UInt32Field_parseJson(&ctx, &config->maxNodesPerWrite, NULL);
1100
11.4k
                else if(strcmp(field, "maxNodesPerMethodCall") == 0)
1101
1
                    retval = UInt32Field_parseJson(&ctx, &config->maxNodesPerMethodCall, NULL);
1102
11.4k
                else if(strcmp(field, "maxNodesPerBrowse") == 0)
1103
2
                    retval = UInt32Field_parseJson(&ctx, &config->maxNodesPerBrowse, NULL);
1104
11.4k
                else if(strcmp(field, "maxNodesPerRegisterNodes") == 0)
1105
1
                    retval = UInt32Field_parseJson(&ctx, &config->maxNodesPerRegisterNodes, NULL);
1106
11.4k
                else if(strcmp(field, "maxNodesPerTranslateBrowsePathsToNodeIds") == 0)
1107
1
                    retval = UInt32Field_parseJson(&ctx, &config->maxNodesPerTranslateBrowsePathsToNodeIds, NULL);
1108
11.4k
                else if(strcmp(field, "maxNodesPerNodeManagement") == 0)
1109
1
                    retval = UInt32Field_parseJson(&ctx, &config->maxNodesPerNodeManagement, NULL);
1110
11.4k
                else if(strcmp(field, "maxMonitoredItemsPerCall") == 0)
1111
1
                    retval = UInt32Field_parseJson(&ctx, &config->maxMonitoredItemsPerCall, NULL);
1112
11.4k
                else if(strcmp(field, "maxReferencesPerNode") == 0)
1113
75
                    retval = UInt32Field_parseJson(&ctx, &config->maxReferencesPerNode, NULL);
1114
11.3k
                else if(strcmp(field, "reverseReconnectInterval") == 0)
1115
1
                    retval = UInt32Field_parseJson(&ctx, &config->reverseReconnectInterval, NULL);
1116
1117
11.3k
#if UA_MULTITHREADING >= 100
1118
11.3k
                else if(strcmp(field, "asyncOperationTimeout") == 0)
1119
1
                    retval = DoubleField_parseJson(&ctx, &config->asyncOperationTimeout, NULL);
1120
11.3k
                else if(strcmp(field, "maxAsyncOperationQueueSize") == 0)
1121
36
                    retval = UInt64Field_parseJson(&ctx, &config->maxAsyncOperationQueueSize, NULL);
1122
11.3k
#endif
1123
1124
11.3k
#ifdef UA_ENABLE_DISCOVERY
1125
11.3k
                else if(strcmp(field, "registeredServersEnabled") == 0)
1126
1
                    retval = BooleanField_parseJson(&ctx, &config->registeredServersEnabled, NULL);
1127
11.3k
                else if(strcmp(field, "registeredServerCleanupTimeout") == 0)
1128
1
                    retval = UInt32Field_parseJson(&ctx, &config->registeredServerCleanupTimeout, NULL);
1129
11.3k
                else if(strcmp(field, "serversOnNetworkEnabled") == 0)
1130
1
                    retval = BooleanField_parseJson(&ctx, &config->serversOnNetworkEnabled, NULL);
1131
11.3k
#endif
1132
1133
11.3k
#ifdef UA_ENABLE_SUBSCRIPTIONS
1134
11.3k
                else if(strcmp(field, "subscriptionsEnabled") == 0)
1135
1
                    retval = BooleanField_parseJson(&ctx, &config->subscriptionsEnabled, NULL);
1136
11.3k
                else if(strcmp(field, "subscriptions") == 0)
1137
1.29k
                    retval = SubscriptionConfigurationField_parseJson(&ctx, config, NULL);
1138
10.0k
# endif
1139
1140
10.0k
#ifdef UA_ENABLE_HISTORIZING
1141
10.0k
                else if(strcmp(field, "historizingEnabled") == 0)
1142
1
                    retval = BooleanField_parseJson(&ctx, &config->historizingEnabled, NULL);
1143
10.0k
                else if(strcmp(field, "historizing") == 0)
1144
211
                    retval = HistorizingConfigurationField_parseJson(&ctx, config, NULL);
1145
9.80k
#endif
1146
1147
9.80k
#ifdef UA_ENABLE_PUBSUB
1148
9.80k
                else if(strcmp(field, "pubsubEnabled") == 0)
1149
1
                    retval = BooleanField_parseJson(&ctx, &config->pubsubEnabled, NULL);
1150
9.80k
                else if(strcmp(field, "pubsub") == 0)
1151
71
                    retval = PubsubConfigurationField_parseJson(&ctx, &config->pubSubConfig, NULL);
1152
9.72k
#endif
1153
9.72k
#ifdef UA_ENABLE_ENCRYPTION
1154
9.72k
                else if(strcmp(field, "securityPolicies") == 0)
1155
52
                    retval = SecurityPoliciesField_parseJson(&ctx, &config->securityPolicies, &config->securityPoliciesSize, UA_APPLICATIONTYPE_SERVER, config->logging);
1156
9.67k
                else if(strcmp(field, "pkiFolder") == 0)
1157
4.08k
                    retval = SecurityPkiField_parseJson(&ctx, config, NULL);
1158
5.59k
#endif
1159
5.59k
                else {
1160
5.59k
                    UA_LOG_WARNING(ctx.logging, UA_LOGCATEGORY_APPLICATION,
1161
5.59k
                                   "Field name '%s' unknown or misspelled. Maybe the feature is not enabled.", field);
1162
                    /* skip the name of item */
1163
5.59k
                    ++ctx.index;
1164
                    /* skip value of unknown item */
1165
5.59k
                    skipUnknownItem(&ctx);
1166
                    /* after skipUnknownItem() ctx->index points to the name of the following item.
1167
                       We must decrement index in oder following increment will
1168
                       still set index to the right position (name of the following item) */
1169
5.59k
                    --ctx.index;
1170
5.59k
                }
1171
12.5k
                if(retval != UA_STATUSCODE_GOOD) {
1172
419
                    UA_LOG_ERROR(ctx.logging, UA_LOGCATEGORY_APPLICATION,
1173
419
                                 "An error occurred while parsing the configuration field %s", field);
1174
419
                    return retval;
1175
419
                }
1176
12.0k
                break;
1177
12.5k
            }
1178
12.0k
            default:
1179
352
                break;
1180
17.7k
        }
1181
12.4k
        ctx.index += 1;
1182
12.4k
    }
1183
4.63k
    return retval;
1184
5.04k
}
1185
1186
UA_Server *
1187
5.99k
UA_Server_newFromFile(const UA_ByteString jsonConfig) {
1188
5.99k
    UA_ServerConfig config;
1189
5.99k
    UA_StatusCode res = UA_ServerConfig_loadFromFile(&config, jsonConfig);
1190
5.99k
    if(res != UA_STATUSCODE_GOOD)
1191
1.29k
        return NULL;
1192
4.70k
    return UA_Server_newWithConfig(&config);
1193
5.99k
}
1194
1195
UA_StatusCode
1196
5.72k
UA_ServerConfig_loadFromFile(UA_ServerConfig *config, const UA_ByteString jsonConfig) {
1197
5.72k
    memset(config, 0, sizeof(UA_ServerConfig));
1198
5.72k
    UA_StatusCode res = UA_ServerConfig_setDefault(config);
1199
5.72k
    if (res == UA_STATUSCODE_GOOD) {
1200
5.72k
        res = parseJSONServerConfig(config, jsonConfig);
1201
5.72k
        if (UA_StatusCode_isBad(res)) {
1202
1.09k
            UA_ServerConfig_clear(config);
1203
1.09k
        }
1204
5.72k
    }
1205
5.72k
    return res;
1206
5.72k
}
1207
1208
0
PARSE_JSON(ConnectionConfig) {
1209
0
    UA_ConnectionConfig *field = (UA_ConnectionConfig*)configField;
1210
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
1211
0
    cj5_token tok = nextToken(ctx);
1212
0
    for(size_t j = tok.size/2; j > 0; j--) {
1213
0
        tok = nextToken(ctx);
1214
0
        switch (tok.type) {
1215
0
        case CJ5_TOKEN_STRING: {
1216
0
            char *field_str = (char*)UA_malloc(tok.size + 1);
1217
0
            unsigned int str_len = 0;
1218
0
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
1219
0
            if(strcmp(field_str, "protocolVersion") == 0)
1220
0
                retval = UInt32Field_parseJson(ctx, &field->protocolVersion, NULL);
1221
0
            else if(strcmp(field_str, "recvBufferSize") == 0)
1222
0
                retval = UInt32Field_parseJson(ctx, &field->recvBufferSize, NULL);
1223
0
            else if(strcmp(field_str, "sendBufferSize") == 0)
1224
0
                retval = UInt32Field_parseJson(ctx, &field->sendBufferSize, NULL);
1225
0
            else if(strcmp(field_str, "localMaxMessageSize") == 0)
1226
0
                retval = UInt32Field_parseJson(ctx, &field->localMaxMessageSize, NULL);
1227
0
            else if(strcmp(field_str, "remoteMaxMessageSize") == 0)
1228
0
                retval = UInt32Field_parseJson(ctx, &field->remoteMaxMessageSize, NULL);
1229
0
            else if(strcmp(field_str, "localMaxChunkCount") == 0)
1230
0
                retval = UInt32Field_parseJson(ctx, &field->localMaxChunkCount, NULL);
1231
0
            else if(strcmp(field_str, "remoteMaxChunkCount") == 0)
1232
0
                retval = UInt32Field_parseJson(ctx, &field->remoteMaxChunkCount, NULL);
1233
0
            else {
1234
0
                LOG_UNKNOWN_FIELD(ctx, field_str);
1235
0
            }
1236
0
            UA_free(field_str);
1237
0
            if(retval != UA_STATUSCODE_GOOD) {
1238
0
                return retval;
1239
0
            }
1240
0
            break;
1241
0
        }
1242
0
        default:
1243
0
            break;
1244
0
        }
1245
0
    }
1246
0
    return UA_STATUSCODE_GOOD;
1247
0
}
1248
1249
0
PARSE_JSON(UserTokenType) {
1250
0
    cj5_token tok = nextToken(ctx);
1251
0
    UA_ByteString rawToken = getJsonPart(tok, ctx->json);
1252
0
    UA_UserTokenType *field = (UA_UserTokenType*)configField;
1253
0
    char *fieldStr = (char*)UA_malloc(tok.size + 1);
1254
0
    unsigned int strLen = 0;
1255
1256
0
    if(cj5_get_str(&ctx->result, (unsigned int)ctx->index, fieldStr, &strLen) == CJ5_ERROR_NONE) {
1257
0
        if(strcmp("Anonymous", fieldStr) == 0)
1258
0
            *field = UA_USERTOKENTYPE_ANONYMOUS;
1259
0
        else if(strcmp("UserName", fieldStr) == 0)
1260
0
            *field = UA_USERTOKENTYPE_USERNAME;
1261
0
        else if(strcmp("Certificate", fieldStr) == 0)
1262
0
            *field = UA_USERTOKENTYPE_CERTIFICATE;
1263
0
        else if(strcmp("IssuedToken", fieldStr) == 0)
1264
0
            *field = UA_USERTOKENTYPE_ISSUEDTOKEN;
1265
0
        else {
1266
0
            UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION,
1267
0
                        "Unknown UserTokenType '%s'", fieldStr);
1268
0
            UA_free(fieldStr);
1269
0
            return UA_STATUSCODE_BAD;
1270
0
        }
1271
0
        UA_free(fieldStr);
1272
0
        return UA_STATUSCODE_GOOD;
1273
0
    }
1274
0
    UA_free(fieldStr);
1275
1276
    /* Try numeric fallback */
1277
0
    UA_UInt32 enumValue;
1278
0
    UA_StatusCode retval = UA_decodeJson(&rawToken, &enumValue, &UA_TYPES[UA_TYPES_UINT32], NULL);
1279
0
    if(retval != UA_STATUSCODE_GOOD) {
1280
0
        UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION,
1281
0
                    "Unknown UserTokenType '%S'", rawToken);
1282
0
        return retval;
1283
0
    }
1284
0
    *field = (UA_UserTokenType)enumValue;
1285
0
    return UA_STATUSCODE_GOOD;
1286
0
}
1287
1288
/* Parse the userIdentityToken field. This creates an ExtensionObject containing
1289
 * one of three token types: Anonymous, Username, or Certificate.
1290
 * The type can be explicitly specified via the "type" field, or inferred by
1291
 * the presence of other fields. */
1292
0
PARSE_JSON(UserIdentityToken) {
1293
0
    UA_ExtensionObject *field = (UA_ExtensionObject*)configField;
1294
0
    cj5_token tok = nextToken(ctx);
1295
1296
    /* Variables to track which fields are encountered */
1297
0
    UA_Int32 detectedType = -1; /* -1 indicates no type detected yet */
1298
0
    UA_Boolean typeExplicitlySet = false;
1299
1300
    /* Temporary storage for token fields */
1301
0
    UA_AnonymousIdentityToken anonToken;
1302
0
    UA_UserNameIdentityToken userNameToken;
1303
0
    UA_X509IdentityToken certToken;
1304
1305
0
    UA_AnonymousIdentityToken_init(&anonToken);
1306
0
    UA_UserNameIdentityToken_init(&userNameToken);
1307
0
    UA_X509IdentityToken_init(&certToken);
1308
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
1309
1310
0
    for(size_t j = tok.size/2; j > 0 && retval == UA_STATUSCODE_GOOD; j--) {
1311
0
        tok = nextToken(ctx);
1312
0
        switch (tok.type) {
1313
0
        case CJ5_TOKEN_STRING: {
1314
0
            char *field_str = (char*)UA_malloc(tok.size + 1);
1315
0
            unsigned int str_len = 0;
1316
0
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
1317
1318
0
            if(strcmp(field_str, "type") == 0) {
1319
1320
0
                if (detectedType != -1) {
1321
0
                    UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION,
1322
0
                                 "Inconsistent type information in userIdentityToken. Type was "
1323
0
                                 "already detected as %d, but 'type' field is set to a different "
1324
0
                                 "value.",
1325
0
                                 detectedType);
1326
0
                    retval = UA_STATUSCODE_BAD;
1327
0
                }
1328
1329
0
                if (retval == UA_STATUSCODE_GOOD) {
1330
                    /* Parse the type field */
1331
0
                    cj5_token typeToken = nextToken(ctx);
1332
0
                    char *typeStr = (char*)UA_malloc(typeToken.size + 1);
1333
0
                    unsigned int typeLen = 0;
1334
1335
0
                    if(cj5_get_str(&ctx->result, (unsigned int)ctx->index, typeStr, &typeLen) == CJ5_ERROR_NONE) {
1336
0
                        if(strcmp("Anonymous", typeStr) == 0) {
1337
0
                            detectedType = UA_USERTOKENTYPE_ANONYMOUS;
1338
0
                            typeExplicitlySet = true;
1339
0
                        } else if(strcmp("UserName", typeStr) == 0) {
1340
0
                            detectedType = UA_USERTOKENTYPE_USERNAME;
1341
0
                            typeExplicitlySet = true;
1342
0
                        } else if(strcmp("Certificate", typeStr) == 0) {
1343
0
                            detectedType = UA_USERTOKENTYPE_CERTIFICATE;
1344
0
                            typeExplicitlySet = true;
1345
0
                        } else {
1346
0
                            UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION,
1347
0
                                        "Unknown userIdentityToken type '%s'", typeStr);
1348
0
                            retval = UA_STATUSCODE_BAD;
1349
0
                        }
1350
0
                    } else {
1351
0
                        UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION,
1352
0
                                    "Failed to parse userIdentityToken type field");
1353
0
                        retval = UA_STATUSCODE_BAD;
1354
0
                    }
1355
0
                    UA_free(typeStr);
1356
0
                }
1357
0
            }
1358
0
            else if(strcmp(field_str, "userName") == 0) {
1359
                /* This field locks in UserName token type */
1360
0
                if(!typeExplicitlySet && detectedType == -1) {
1361
0
                    detectedType = UA_USERTOKENTYPE_USERNAME;
1362
0
                }
1363
0
                if(detectedType != UA_USERTOKENTYPE_USERNAME) {
1364
0
                    UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION,
1365
0
                                "Field 'userName' can only be used with UserName token type");
1366
0
                    retval = UA_STATUSCODE_BAD;
1367
0
                }
1368
0
                else {
1369
0
                    retval = StringField_parseJson(ctx, &userNameToken.userName, NULL);
1370
0
                }
1371
0
            }
1372
0
            else if(strcmp(field_str, "password") == 0) {
1373
                /* This field locks in UserName token type */
1374
0
                if(!typeExplicitlySet && detectedType == -1) {
1375
0
                    detectedType = UA_USERTOKENTYPE_USERNAME;
1376
0
                }
1377
0
                if(detectedType != UA_USERTOKENTYPE_USERNAME) {
1378
0
                    UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION,
1379
0
                                "Field 'password' can only be used with UserName token type");
1380
0
                    retval = UA_STATUSCODE_BAD;
1381
0
                } else {
1382
0
                    retval = ByteStringField_parseJson(ctx, &userNameToken.password, NULL);
1383
0
                }
1384
0
            }
1385
0
            else if(strcmp(field_str, "encryptionAlgorithm") == 0) {
1386
                /* This field can be used with UserName token type */
1387
0
                if(!typeExplicitlySet && detectedType == -1) {
1388
0
                    detectedType = UA_USERTOKENTYPE_USERNAME;
1389
0
                }
1390
0
                if(detectedType != UA_USERTOKENTYPE_USERNAME) {
1391
0
                    UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION,
1392
0
                                "Field 'encryptionAlgorithm' can only be used with UserName token type");
1393
0
                    retval = UA_STATUSCODE_BAD;
1394
0
                }
1395
0
                else {
1396
0
                    retval = StringField_parseJson(ctx, &userNameToken.encryptionAlgorithm, NULL);
1397
0
                }
1398
0
            }
1399
0
            else if(strcmp(field_str, "certificateData") == 0) {
1400
                /* This field locks in Certificate token type */
1401
0
                if(!typeExplicitlySet && detectedType == -1) {
1402
0
                    detectedType = UA_USERTOKENTYPE_CERTIFICATE;
1403
0
                }
1404
0
                if(detectedType != UA_USERTOKENTYPE_CERTIFICATE) {
1405
0
                    UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION,
1406
0
                                "Field 'certificateData' can only be used with Certificate token type");
1407
0
                    retval = UA_STATUSCODE_BAD;
1408
0
                }
1409
0
                else {
1410
0
                    retval = CertificateFileField_parseJson(ctx, &certToken.certificateData, NULL);
1411
0
                }
1412
0
            }
1413
0
            else {
1414
0
                LOG_UNKNOWN_FIELD(ctx, field_str);
1415
0
            }
1416
0
            UA_free(field_str);
1417
0
            break;
1418
0
        }
1419
0
        default:
1420
0
            break;
1421
0
        }
1422
0
    }
1423
1424
0
    if(retval == UA_STATUSCODE_GOOD) {
1425
        /* If no type was detected, default to Anonymous */
1426
0
        if(detectedType == -1) {
1427
0
            detectedType = UA_USERTOKENTYPE_ANONYMOUS;
1428
0
        }
1429
1430
        /* Create the ExtensionObject with the appropriate token type */
1431
0
        if(detectedType == UA_USERTOKENTYPE_ANONYMOUS) {
1432
0
            retval = UA_ExtensionObject_setValueCopy(field, &anonToken,
1433
0
                                                    &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN]);
1434
0
        } else if(detectedType == UA_USERTOKENTYPE_USERNAME) {
1435
0
            retval = UA_ExtensionObject_setValueCopy(field, &userNameToken,
1436
0
                                                    &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN]);
1437
0
        } else if(detectedType == UA_USERTOKENTYPE_CERTIFICATE) {
1438
0
            retval = UA_ExtensionObject_setValueCopy(field, &certToken,
1439
0
                                                    &UA_TYPES[UA_TYPES_X509IDENTITYTOKEN]);
1440
0
        } else {
1441
0
            UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION,
1442
0
                        "Invalid userIdentityToken type");
1443
0
            retval = UA_STATUSCODE_BAD;
1444
0
        }
1445
0
    }
1446
1447
0
    UA_AnonymousIdentityToken_clear(&anonToken);
1448
0
    UA_UserNameIdentityToken_clear(&userNameToken);
1449
0
    UA_X509IdentityToken_clear(&certToken);
1450
0
    return retval;
1451
0
}
1452
1453
0
PARSE_JSON(UserTokenPolicy) {
1454
0
    UA_Boolean issuedTokenTypeFieldsUsed = false;
1455
1456
0
    UA_UserTokenPolicy *field = (UA_UserTokenPolicy*)configField;
1457
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
1458
0
    cj5_token tok = nextToken(ctx);
1459
0
    for(size_t j = tok.size/2; j > 0; j--) {
1460
0
        tok = nextToken(ctx);
1461
0
        switch (tok.type) {
1462
0
        case CJ5_TOKEN_STRING: {
1463
0
            char *field_str = (char*)UA_malloc(tok.size + 1);
1464
0
            unsigned int str_len = 0;
1465
0
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
1466
0
            if(strcmp(field_str, "policyId") == 0)
1467
0
                retval = StringField_parseJson(ctx, &field->policyId, NULL);
1468
0
            else if(strcmp(field_str, "tokenType") == 0)
1469
0
                retval = UserTokenType_parseJson(ctx, &field->tokenType, NULL);
1470
0
            else if(strcmp(field_str, "issuedTokenType") == 0) {
1471
0
                issuedTokenTypeFieldsUsed = true;
1472
0
                retval = StringField_parseJson(ctx, &field->issuedTokenType, NULL);
1473
0
            }
1474
0
            else if(strcmp(field_str, "issuerEndpointUrl") == 0) {
1475
0
                issuedTokenTypeFieldsUsed = true;
1476
0
                retval = StringField_parseJson(ctx, &field->issuerEndpointUrl, NULL);
1477
0
            }
1478
0
            else if(strcmp(field_str, "securityPolicyUri") == 0)
1479
0
                retval = StringField_parseJson(ctx, &field->securityPolicyUri, NULL);
1480
0
            else {
1481
0
                LOG_UNKNOWN_FIELD(ctx, field_str);
1482
0
            }
1483
0
            UA_free(field_str);
1484
0
            if(retval != UA_STATUSCODE_GOOD) {
1485
0
                return retval;
1486
0
            }
1487
0
            break;
1488
0
        }
1489
0
        default:
1490
0
            break;
1491
0
        }
1492
0
    }
1493
0
    if(issuedTokenTypeFieldsUsed && field->tokenType != UA_USERTOKENTYPE_ISSUEDTOKEN) {
1494
0
        UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION,
1495
0
                    "Fields 'issuedTokenType' and 'issuerEndpointUrl' can only be used if tokenType is 'IssuedToken'.");
1496
0
        return UA_STATUSCODE_BAD;
1497
0
    }
1498
1499
0
    return UA_STATUSCODE_GOOD;
1500
0
}
1501
1502
0
PARSE_JSON(UserTokenPolicyArrayField) {
1503
0
    if(configFieldSize == NULL) {
1504
0
        UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Pointer to the array size is not set.");
1505
0
        return UA_STATUSCODE_BADARGUMENTSMISSING;
1506
0
    }
1507
0
    cj5_token tok = nextToken(ctx);
1508
0
    UA_UserTokenPolicy *policyArray = (UA_UserTokenPolicy*)UA_malloc(sizeof(UA_UserTokenPolicy) * tok.size);
1509
0
    size_t policyArraySize = 0;
1510
0
    for(size_t j = tok.size; j > 0; j--) {
1511
        /* initialize element to zeros so clear functions are safe */
1512
0
        memset(&policyArray[policyArraySize], 0, sizeof(UA_UserTokenPolicy));
1513
0
        UA_StatusCode retval = UserTokenPolicy_parseJson(ctx, &policyArray[policyArraySize], NULL);
1514
0
        if(retval != UA_STATUSCODE_GOOD) {
1515
0
            UA_Array_delete(policyArray, policyArraySize, &UA_TYPES[UA_TYPES_USERTOKENPOLICY]);
1516
0
            return retval;
1517
0
        }
1518
0
        policyArraySize++;
1519
0
    }
1520
    /* Add to the config */
1521
0
    UA_UserTokenPolicy **field = (UA_UserTokenPolicy**)configField;
1522
0
    if(*configFieldSize > 0) {
1523
0
        UA_Array_delete(*field, *configFieldSize,
1524
0
                        &UA_TYPES[UA_TYPES_USERTOKENPOLICY]);
1525
0
        *field = NULL;
1526
0
        *configFieldSize = 0;
1527
0
    }
1528
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
1529
0
    if(policyArraySize > 0) {
1530
0
        retval = UA_Array_copy(policyArray, policyArraySize,
1531
0
                               (void **)field, &UA_TYPES[UA_TYPES_USERTOKENPOLICY]);
1532
0
        *configFieldSize = policyArraySize;
1533
0
    }
1534
1535
    /* Clean up */
1536
0
    UA_Array_delete(policyArray, policyArraySize, &UA_TYPES[UA_TYPES_USERTOKENPOLICY]);
1537
0
    return retval;
1538
0
}
1539
1540
1541
0
PARSE_JSON(EndpointDescription) {
1542
0
    UA_EndpointDescription *field = (UA_EndpointDescription*)configField;
1543
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
1544
0
    cj5_token tok = nextToken(ctx);
1545
0
    for(size_t j = tok.size/2; j > 0; j--) {
1546
0
        tok = nextToken(ctx);
1547
0
        switch (tok.type) {
1548
0
        case CJ5_TOKEN_STRING: {
1549
0
            char *field_str = (char*)UA_malloc(tok.size + 1);
1550
0
            unsigned int str_len = 0;
1551
0
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
1552
0
            if(strcmp(field_str, "endpointUrl") == 0)
1553
0
                retval = StringField_parseJson(ctx, &field->endpointUrl, NULL);
1554
0
            else if(strcmp(field_str, "server") == 0)
1555
0
                retval = GenericApplicationDescriptionField_parseJson(ctx, &field->server, NULL, GENERICAPPLICATIONTYPE_ANY);
1556
0
            else if(strcmp(field_str, "serverCertificate") == 0)
1557
0
                retval = CertificateFileField_parseJson(ctx, &field->serverCertificate, NULL);
1558
0
            else if(strcmp(field_str, "securityMode") == 0)
1559
0
                retval = MessageSecurityMode_parseJson(ctx, &field->securityMode, NULL);
1560
0
            else if(strcmp(field_str, "securityPolicyUri") == 0)
1561
0
                retval = StringField_parseJson(ctx, &field->securityPolicyUri, NULL);
1562
0
            else if(strcmp(field_str, "userIdentityTokens") == 0)
1563
0
                retval = UserTokenPolicyArrayField_parseJson(ctx, &field->userIdentityTokens, &field->userIdentityTokensSize);
1564
0
            else if(strcmp(field_str, "transportProfileUri") == 0)
1565
0
                retval = StringField_parseJson(ctx, &field->transportProfileUri, NULL);
1566
0
            else if(strcmp(field_str, "securityLevel") == 0)
1567
0
                retval = ByteField_parseJson(ctx, &field->securityLevel, NULL);
1568
0
            else {
1569
0
                LOG_UNKNOWN_FIELD(ctx, field_str);
1570
0
            }
1571
0
            UA_free(field_str);
1572
0
            if(retval != UA_STATUSCODE_GOOD) {
1573
0
                return retval;
1574
0
            }
1575
0
            break;
1576
0
        }
1577
0
        default:
1578
0
            break;
1579
0
        }
1580
0
    }
1581
0
    return UA_STATUSCODE_GOOD;
1582
0
}
1583
1584
static UA_StatusCode
1585
0
parseJSONClientConfig(UA_ClientConfig *config, UA_ByteString json_config) {
1586
    // Parsing json config
1587
0
    const char *json = (const char*)json_config.data;
1588
0
    cj5_token tokens[MAX_TOKENS];
1589
0
    cj5_result r = cj5_parse(json, (unsigned int)json_config.length, tokens, MAX_TOKENS, NULL);
1590
1591
0
    if(r.error != CJ5_ERROR_NONE || r.num_tokens < 2 ||
1592
0
       r.tokens[0].type != CJ5_TOKEN_OBJECT)
1593
0
        return UA_STATUSCODE_BADDECODINGERROR;
1594
1595
0
    ParsingCtx ctx;
1596
0
    ctx.json = json;
1597
0
    ctx.result = r;
1598
0
    ctx.index = 1; // The first token is ignored because it is known and not needed.
1599
1600
0
    ctx.logging = config->logging;
1601
1602
0
    size_t clientConfigSize = 0;
1603
0
    if(ctx.result.tokens)
1604
0
        clientConfigSize = (ctx.result.tokens[ctx.index-1].size/2);
1605
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
1606
0
    for (size_t j = clientConfigSize; j > 0 && ctx.index < ctx.result.num_tokens; j--) {
1607
0
        cj5_token tok = ctx.result.tokens[ctx.index];
1608
0
        switch (tok.type) {
1609
0
            case CJ5_TOKEN_STRING: {
1610
0
                char *field = (char*)UA_malloc(tok.size + 1);
1611
0
                unsigned int str_len = 0;
1612
0
                cj5_get_str(&ctx.result, (unsigned int)ctx.index, field, &str_len);
1613
0
                if(strcmp(field, "timeout") == 0)
1614
0
                    retval = Int32Field_parseJson(&ctx, &config->timeout, NULL);
1615
0
                else if(strcmp(field, "applicationDescription") == 0)
1616
0
                    retval = GenericApplicationDescriptionField_parseJson(&ctx, &config->clientDescription, NULL, GENERICAPPLICATIONTYPE_CLIENT);
1617
0
                else if(strcmp(field, "endpointUrl") == 0)
1618
0
                    retval = StringField_parseJson(&ctx, &config->endpointUrl, NULL);
1619
0
                else if (strcmp(field, "userIdentityToken") == 0)
1620
0
                    retval = UserIdentityToken_parseJson(&ctx, &config->userIdentityToken, NULL);
1621
0
                else if(strcmp(field, "sessionName") == 0)
1622
0
                    retval = StringField_parseJson(&ctx, &config->sessionName, NULL);
1623
0
                else if(strcmp(field, "sessionLocaleIds") == 0)
1624
                    /* UA_LocaleId is an alias of UA_String */
1625
0
                    retval = StringArrayField_parseJson(&ctx, &config->sessionLocaleIds, &config->sessionLocaleIdsSize);
1626
0
                else if(strcmp(field, "noSession") == 0)
1627
0
                    retval = BooleanField_parseJson(&ctx, &config->noSession, NULL);
1628
0
                else if(strcmp(field, "noReconnect") == 0)
1629
0
                    retval = BooleanField_parseJson(&ctx, &config->noReconnect, NULL);
1630
0
                else if(strcmp(field, "noNewSession") == 0)
1631
0
                    retval = BooleanField_parseJson(&ctx, &config->noNewSession, NULL);
1632
0
                else if(strcmp(field, "secureChannelLifeTime") == 0)
1633
0
                    retval = UInt32Field_parseJson(&ctx, &config->secureChannelLifeTime, NULL);
1634
0
                else if(strcmp(field, "requestedSessionTimeout") == 0)
1635
0
                    retval = UInt32Field_parseJson(&ctx, &config->requestedSessionTimeout, NULL);
1636
0
                else if(strcmp(field, "localConnectionConfig") == 0)
1637
0
                    retval = ConnectionConfig_parseJson(&ctx, &config->localConnectionConfig, NULL);
1638
0
                else if(strcmp(field, "connectivityCheckInterval") == 0)
1639
0
                    retval = UInt32Field_parseJson(&ctx, &config->connectivityCheckInterval, NULL);
1640
0
                else if(strcmp(field, "maxAsyncServiceCalls") == 0)
1641
0
                    retval = UInt32Field_parseJson(&ctx, &config->maxAsyncServiceCalls, NULL);
1642
0
                else if(strcmp(field, "asyncServiceCallRule") == 0)
1643
0
                    retval = RuleHandlingField_parseJson(&ctx, &config->asyncServiceCallRule, NULL);
1644
0
                else if(strcmp(field, "certificateEkuRule") == 0)
1645
0
                    retval = RuleHandlingField_parseJson(&ctx, &config->certificateEkuRule, NULL);
1646
0
                else if(strcmp(field, "tcpReuseAddr") == 0)
1647
0
                    retval = BooleanField_parseJson(&ctx, &config->tcpReuseAddr, NULL);
1648
#ifdef UA_ENABLE_LWS
1649
                else if(strcmp(field, "webSocketMaxQueueSize") == 0)
1650
                    retval = UInt32Field_parseJson(
1651
                        &ctx, &config->webSocketMaxQueueSize, NULL);
1652
                else if(strcmp(field, "webSocketCaCertificate") == 0) {
1653
                    UA_ByteString_clear(&config->webSocketCaCertificate);
1654
                    retval = CertificateFileField_parseJson(
1655
                        &ctx, &config->webSocketCaCertificate, NULL);
1656
                }
1657
#endif
1658
0
                else if(strcmp(field, "endpoint") == 0)
1659
0
                    retval = EndpointDescription_parseJson(&ctx, &config->endpoint, NULL);
1660
0
                else if(strcmp(field, "userTokenPolicy") == 0)
1661
0
                    retval = UserTokenPolicy_parseJson(&ctx, &config->userTokenPolicy, NULL);
1662
0
                else if(strcmp(field, "applicationUri") == 0)
1663
0
                    retval = StringField_parseJson(&ctx, &config->applicationUri, NULL);
1664
0
                else if(strcmp(field, "securityMode") == 0)
1665
0
                    retval = MessageSecurityMode_parseJson(&ctx, &config->securityMode, NULL);
1666
0
                else if(strcmp(field, "securityPolicyUri") == 0)
1667
0
                    retval = StringField_parseJson(&ctx, &config->securityPolicyUri, NULL);
1668
0
                else if(strcmp(field, "authSecurityPolicyUri") == 0)
1669
0
                    retval = StringField_parseJson(&ctx, &config->authSecurityPolicyUri, NULL);
1670
0
                else if(strcmp(field, "securityPolicies") == 0)
1671
0
                    retval = SecurityPoliciesField_parseJson(&ctx, &config->securityPolicies, &config->securityPoliciesSize, UA_APPLICATIONTYPE_CLIENT, config->logging);
1672
0
                else if(strcmp(field, "authSecurityPolicies") == 0)
1673
0
                    retval = SecurityPoliciesField_parseJson(&ctx, &config->authSecurityPolicies, &config->authSecurityPoliciesSize, UA_APPLICATIONTYPE_CLIENT, config->logging);
1674
0
                else if(strcmp(field, "allowNonePolicyPassword") == 0)
1675
0
                    retval = BooleanField_parseJson(&ctx, &config->allowNonePolicyPassword, NULL);
1676
0
#ifdef UA_ENABLE_ENCRYPTION
1677
0
                else if(strcmp(field, "maxTrustListSize") == 0)
1678
0
                    retval = UInt32Field_parseJson(&ctx, &config->maxTrustListSize, NULL);
1679
0
                else if(strcmp(field, "maxRejectedListSize") == 0)
1680
0
                    retval = UInt32Field_parseJson(&ctx, &config->maxRejectedListSize, NULL);
1681
0
#endif
1682
0
                else if(strcmp(field, "namespaces") == 0)
1683
0
                    retval = StringArrayField_parseJson(&ctx, &config->namespaces, &config->namespacesSize);
1684
0
                else if(strcmp(field, "outStandingPublishRequests") == 0)
1685
0
                    retval = UInt16Field_parseJson(&ctx, &config->outStandingPublishRequests, NULL);
1686
0
                else {
1687
0
                    UA_LOG_WARNING(ctx.logging, UA_LOGCATEGORY_APPLICATION,
1688
0
                                   "Field name '%s' unknown or misspelled. Maybe the feature is not enabled either.", field);
1689
                    /* skip the name of item */
1690
0
                    ++ctx.index;
1691
                    /* skip value of unknown item */
1692
0
                    skipUnknownItem(&ctx);
1693
                    /* after skipUnknownItem() ctx->index points to the name of the following item.
1694
                       We must decrement index in oder following increment will
1695
                       still set index to the right position (name of the following item) */
1696
0
                    --ctx.index;
1697
0
                }
1698
0
                UA_free(field);
1699
0
                if(retval != UA_STATUSCODE_GOOD) {
1700
0
                    UA_LOG_ERROR(ctx.logging, UA_LOGCATEGORY_APPLICATION, "An error occurred while parsing the configuration file.");
1701
0
                    return retval;
1702
0
                }
1703
0
                break;
1704
0
            }
1705
0
            default:
1706
0
                break;
1707
0
        }
1708
0
        ctx.index += 1;
1709
0
    }
1710
0
    return retval;
1711
0
}
1712
1713
UA_Client *
1714
UA_Client_newFromFile(const UA_ByteString jsonConfig)
1715
0
{
1716
0
    UA_ClientConfig config;
1717
0
    UA_StatusCode res = UA_ClientConfig_loadFromFile(&config, jsonConfig);
1718
0
    if(res != UA_STATUSCODE_GOOD)
1719
0
        return NULL;
1720
0
    return UA_Client_newWithConfig(&config);
1721
0
}
1722
1723
UA_StatusCode
1724
UA_ClientConfig_loadFromFile(UA_ClientConfig *config, const UA_ByteString jsonConfig)
1725
0
{
1726
0
    memset(config, 0, sizeof(UA_ClientConfig));
1727
0
    UA_StatusCode res = UA_ClientConfig_setDefault(config);
1728
0
    if (res == UA_STATUSCODE_GOOD) {
1729
0
        res = parseJSONClientConfig(config, jsonConfig);
1730
0
        if (UA_StatusCode_isBad(res)) {
1731
0
            UA_ClientConfig_clear(config);
1732
0
        }
1733
0
    }
1734
0
    return res;
1735
0
}
1736
1737
#if defined(UA_ENABLE_ENCRYPTION) || defined(UA_ENABLE_LWS)
1738
static UA_ByteString
1739
0
loadCertificateFile(const char *const path) {
1740
0
    UA_ByteString fileContents = UA_BYTESTRING_NULL;
1741
1742
    /* Open the file */
1743
0
    FILE *fp = fopen(path, "rb");
1744
0
    if(!fp) {
1745
0
        errno = 0; /* We read errno also from the tcp layer... */
1746
0
        return fileContents;
1747
0
    }
1748
1749
    /* Get the file length, allocate the data and read */
1750
0
    if(fseek(fp, 0, SEEK_END) != 0) {
1751
0
        fclose(fp);
1752
0
        errno = 0;
1753
0
        return fileContents;
1754
0
    }
1755
1756
0
    long length = ftell(fp);
1757
0
    if(length < 0) {
1758
0
        fclose(fp);
1759
0
        errno = 0;
1760
0
        return fileContents;
1761
0
    }
1762
1763
0
    fileContents.length = (size_t)length;
1764
0
    fileContents.data = (UA_Byte *)UA_malloc(fileContents.length * sizeof(UA_Byte));
1765
0
    if(fileContents.data) {
1766
0
        if(fseek(fp, 0, SEEK_SET) != 0) {
1767
0
            fclose(fp);
1768
0
            UA_ByteString_clear(&fileContents);
1769
0
            errno = 0;
1770
0
            return fileContents;
1771
0
        }
1772
0
        size_t read = fread(fileContents.data, sizeof(UA_Byte), fileContents.length, fp);
1773
0
        if(read != fileContents.length)
1774
0
            UA_ByteString_clear(&fileContents);
1775
0
    } else {
1776
0
        fileContents.length = 0;
1777
0
    }
1778
0
    fclose(fp);
1779
1780
0
    return fileContents;
1781
0
}
1782
#endif