Coverage Report

Created: 2026-08-05 06:43

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.21k
#define MAX_TOKENS 1024
25
26
#define LOG_UNKNOWN_FIELD(ctx, field) \
27
5.43k
    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
7.63k
getJsonPart(cj5_token tok, const char *json) {
40
7.63k
    UA_ByteString bs;
41
7.63k
    UA_ByteString_init(&bs);
42
7.63k
    if(tok.type == CJ5_TOKEN_STRING) {
43
4.88k
        bs.data = (UA_Byte*)(uintptr_t)(json + tok.start - 1);
44
4.88k
        bs.length = (tok.end - tok.start) + 3;
45
4.88k
        return bs;
46
4.88k
    } else {
47
2.74k
        bs.data = (UA_Byte*)(uintptr_t)(json + tok.start);
48
2.74k
        bs.length = (tok.end - tok.start) + 1;
49
2.74k
        return bs;
50
2.74k
    }
51
7.63k
}
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
367k
nextToken(ParsingCtx *ctx) {
57
367k
    if(!ctx->result.tokens || ctx->index + 1 >= ctx->result.num_tokens) {
58
346k
        ctx->index = ctx->result.num_tokens;
59
346k
        cj5_token empty;
60
346k
        memset(&empty, 0, sizeof(empty));
61
346k
        return empty;
62
346k
    }
63
20.5k
    ctx->index++;
64
20.5k
    return ctx->result.tokens[ctx->index];
65
367k
}
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
151
PARSE_JSON(UInt16Field) {
105
151
    cj5_token tok = nextToken(ctx);
106
151
    UA_ByteString buf = getJsonPart(tok, ctx->json);
107
151
    UA_UInt16 out;
108
151
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_UINT16], NULL);
109
151
    if(retval != UA_STATUSCODE_GOOD)
110
125
        return retval;
111
26
    UA_UInt16 *field = (UA_UInt16*)configField;
112
26
    *field = out;
113
26
    return retval;
114
151
}
115
150
PARSE_JSON(UInt32Field) {
116
150
    cj5_token tok = nextToken(ctx);
117
150
    UA_ByteString buf = getJsonPart(tok, ctx->json);
118
150
    UA_UInt32 out;
119
150
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_UINT32], NULL);
120
150
    if(retval != UA_STATUSCODE_GOOD)
121
71
        return retval;
122
79
    UA_UInt32 *field = (UA_UInt32*)configField;
123
79
    *field = out;
124
79
    return retval;
125
150
}
126
45
PARSE_JSON(UInt64Field) {
127
45
    cj5_token tok = nextToken(ctx);
128
45
    UA_ByteString buf = getJsonPart(tok, ctx->json);
129
45
    UA_UInt64 out;
130
45
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_UINT64], NULL);
131
45
    if(retval != UA_STATUSCODE_GOOD)
132
19
        return retval;
133
26
    UA_UInt64 *field = (UA_UInt64*)configField;
134
26
    *field = out;
135
26
    return retval;
136
45
}
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
3.00k
PARSE_JSON(StringField) {
149
3.00k
    cj5_token tok = nextToken(ctx);
150
3.00k
    UA_ByteString buf = getJsonPart(tok, ctx->json);
151
3.00k
    UA_String out;
152
3.00k
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_STRING], NULL);
153
3.00k
    if(retval != UA_STATUSCODE_GOOD)
154
2.38k
        return retval;
155
621
    UA_String *field = (UA_String*)configField;
156
621
    if(field != NULL) {
157
621
        UA_String_clear(field);
158
621
        *field = out;
159
621
    }
160
621
    return retval;
161
3.00k
}
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
22
PARSE_JSON(DoubleField) {
221
22
    cj5_token tok = nextToken(ctx);
222
22
    UA_ByteString buf = getJsonPart(tok, ctx->json);
223
22
    UA_Double out;
224
22
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_DOUBLE], NULL);
225
22
    if(retval != UA_STATUSCODE_GOOD)
226
12
        return retval;
227
10
    UA_Double *field = (UA_Double *)configField;
228
10
    *field = out;
229
10
    return retval;
230
22
}
231
8
PARSE_JSON(BooleanField) {
232
8
    cj5_token tok = nextToken(ctx);
233
8
    UA_ByteString buf = getJsonPart(tok, ctx->json);
234
8
    UA_Boolean out;
235
8
    if(tok.type != CJ5_TOKEN_BOOL) {
236
8
        UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Value of type bool expected.");
237
8
        return UA_STATUSCODE_BADTYPEMISMATCH;
238
8
    }
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
8
}
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
65
PARSE_JSON(DurationRangeField) {
261
65
    UA_DurationRange *field = (UA_DurationRange*)configField;
262
65
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
263
65
    cj5_token tok = nextToken(ctx);
264
1.25k
    for(size_t j = tok.size/2; j > 0; j--) {
265
1.19k
        tok = nextToken(ctx);
266
1.19k
        switch (tok.type) {
267
375
        case CJ5_TOKEN_STRING: {
268
375
            char *field_str = (char*)UA_malloc(tok.size + 1);
269
375
            unsigned int str_len = 0;
270
375
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
271
375
            if(strcmp(field_str, "min") == 0)
272
0
                retval = DurationField_parseJson(ctx, &field->min, NULL);
273
375
            else if(strcmp(field_str, "max") == 0)
274
0
                retval = DurationField_parseJson(ctx, &field->max, NULL);
275
375
            else {
276
375
                LOG_UNKNOWN_FIELD(ctx, field_str);
277
375
            }
278
375
            UA_free(field_str);
279
375
            if(retval != UA_STATUSCODE_GOOD) {
280
0
                return retval;
281
0
            }
282
375
            break;
283
375
        }
284
819
        default:
285
819
            break;
286
1.19k
        }
287
1.19k
    }
288
65
    return UA_STATUSCODE_GOOD;
289
65
}
290
112
PARSE_JSON(UInt32RangeField) {
291
112
    UA_UInt32Range *field = (UA_UInt32Range*)configField;
292
112
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
293
112
    cj5_token tok = nextToken(ctx);
294
922
    for(size_t j = tok.size/2; j > 0; j--) {
295
810
        tok = nextToken(ctx);
296
810
        switch (tok.type) {
297
126
        case CJ5_TOKEN_STRING: {
298
126
            char *field_str = (char*)UA_malloc(tok.size + 1);
299
126
            unsigned int str_len = 0;
300
126
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
301
126
            if(strcmp(field_str, "min") == 0)
302
0
                retval = UInt32Field_parseJson(ctx, &field->min, NULL);
303
126
            else if(strcmp(field_str, "max") == 0)
304
0
                retval = UInt32Field_parseJson(ctx, &field->max, NULL);
305
126
            else {
306
126
                LOG_UNKNOWN_FIELD(ctx, field_str);
307
126
            }
308
126
            UA_free(field_str);
309
126
            if(retval != UA_STATUSCODE_GOOD) {
310
0
                return retval;
311
0
            }
312
126
            break;
313
126
        }
314
684
        default:
315
684
            break;
316
810
        }
317
810
    }
318
112
    return UA_STATUSCODE_GOOD;
319
112
}
320
#endif
321
322
/*----------------------Advanced Types------------------------*/
323
2
PARSE_JSON(StringArrayField) {
324
2
    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
2
    cj5_token tok = nextToken(ctx);
329
2
    UA_String *stringArray = (UA_String*)UA_malloc(sizeof(UA_String) * tok.size);
330
2
    size_t stringArraySize = 0;
331
3
    for(size_t j = tok.size; j > 0; j--) {
332
2
        UA_String out = {.length = 0, .data = NULL};
333
2
        UA_StatusCode retval = StringField_parseJson(ctx, &out, NULL);
334
2
        if(retval != UA_STATUSCODE_GOOD) {
335
1
            UA_String_clear(&out);
336
1
            UA_Array_delete(stringArray, stringArraySize, &UA_TYPES[UA_TYPES_STRING]);
337
1
            return retval;
338
1
        }
339
1
        UA_String_copy(&out, &stringArray[stringArraySize++]);
340
1
        UA_String_clear(&out);
341
1
    }
342
    /* Add to the config */
343
1
    UA_String **field = (UA_String**)configField;
344
1
    if(*configFieldSize > 0) {
345
1
        UA_Array_delete(*field, *configFieldSize,
346
1
                        &UA_TYPES[UA_TYPES_STRING]);
347
1
        *field = NULL;
348
1
        *configFieldSize = 0;
349
1
    }
350
1
    UA_StatusCode retval =
351
1
        UA_Array_copy(stringArray, stringArraySize,
352
1
                      (void**)field, &UA_TYPES[UA_TYPES_STRING]);
353
1
    *configFieldSize = stringArraySize;
354
355
    /* Clean up */
356
1
    UA_Array_delete(stringArray, stringArraySize, &UA_TYPES[UA_TYPES_STRING]);
357
1
    return retval;
358
2
}
359
1
PARSE_JSON(DateTimeField) {
360
1
    cj5_token tok = nextToken(ctx);
361
1
    UA_ByteString buf = getJsonPart(tok, ctx->json);
362
1
    UA_DateTime out;
363
1
    UA_DateTime_init(&out);
364
1
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_DATETIME], NULL);
365
1
    if(retval != UA_STATUSCODE_GOOD)
366
1
        return retval;
367
0
    UA_DateTime *field = (UA_DateTime*)configField;
368
0
    *field = out;
369
0
    return retval;
370
1
}
371
51
PARSE_JSON(BuildInfo) {
372
51
    UA_BuildInfo *field = (UA_BuildInfo*)configField;
373
51
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
374
51
    cj5_token tok = nextToken(ctx);
375
6.25k
    for(size_t j = tok.size/2; j > 0; j--) {
376
6.20k
        tok = nextToken(ctx);
377
6.20k
        switch (tok.type) {
378
221
        case CJ5_TOKEN_STRING: {
379
221
            char *field_str = (char*)UA_malloc(tok.size + 1);
380
221
            unsigned int str_len = 0;
381
221
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
382
221
            if(strcmp(field_str, "productUri") == 0)
383
1
                retval = StringField_parseJson(ctx, &field->productUri, NULL);
384
220
            else if(strcmp(field_str, "manufacturerName") == 0)
385
0
                retval = StringField_parseJson(ctx, &field->manufacturerName, NULL);
386
220
            else if(strcmp(field_str, "productName") == 0)
387
0
                retval = StringField_parseJson(ctx, &field->productName, NULL);
388
220
            else if(strcmp(field_str, "softwareVersion") == 0)
389
0
                retval = StringField_parseJson(ctx, &field->softwareVersion, NULL);
390
220
            else if(strcmp(field_str, "buildNumber") == 0)
391
0
                retval = StringField_parseJson(ctx, &field->buildNumber, NULL);
392
220
            else if(strcmp(field_str, "buildDate") == 0)
393
1
                retval = DateTimeField_parseJson(ctx, &field->buildDate, NULL);
394
219
            else {
395
219
                LOG_UNKNOWN_FIELD(ctx, field_str);
396
219
            }
397
221
            UA_free(field_str);
398
221
            if(retval != UA_STATUSCODE_GOOD) {
399
2
                return retval;
400
2
            }
401
219
            break;
402
221
        }
403
5.98k
        default:
404
5.98k
            break;
405
6.20k
        }
406
6.20k
    }
407
49
    return UA_STATUSCODE_GOOD;
408
51
}
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
483
{
458
483
    UA_ApplicationDescription *field = (UA_ApplicationDescription*)configField;
459
483
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
460
483
    cj5_token tok = nextToken(ctx);
461
5.49k
    for(size_t j = tok.size/2; j > 0; j--) {
462
5.01k
        tok = nextToken(ctx);
463
5.01k
        switch (tok.type) {
464
1.24k
        case CJ5_TOKEN_STRING: {
465
1.24k
            char *field_str = (char*)UA_malloc(tok.size + 1);
466
1.24k
            unsigned int str_len = 0;
467
1.24k
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
468
1.24k
            if(strcmp(field_str, "applicationUri") == 0)
469
0
                retval = StringField_parseJson(ctx, &field->applicationUri, NULL);
470
1.24k
            else if(strcmp(field_str, "productUri") == 0)
471
4
                retval = StringField_parseJson(ctx, &field->productUri, NULL);
472
1.23k
            else if(strcmp(field_str, "applicationName") == 0)
473
0
                retval = LocalizedTextField_parseJson(ctx, &field->applicationName, NULL);
474
1.23k
            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.23k
            else if(strcmp(field_str, "gatewayServerUri") == 0 &&
479
1
                    type != GENERICAPPLICATIONTYPE_CLIENT)
480
1
                retval = StringField_parseJson(ctx, &field->gatewayServerUri, NULL);
481
1.23k
            else if(strcmp(field_str, "discoveryProfileUri") == 0 &&
482
0
                    type != GENERICAPPLICATIONTYPE_CLIENT)
483
0
                retval = StringField_parseJson(ctx, &field->discoveryProfileUri, NULL);
484
1.23k
            else if(strcmp(field_str, "discoveryUrls") == 0)
485
0
                retval = StringArrayField_parseJson(ctx, &field->discoveryUrls, &field->discoveryUrlsSize);
486
1.23k
            else {
487
1.23k
                LOG_UNKNOWN_FIELD(ctx, field_str);
488
1.23k
            }
489
1.24k
            UA_free(field_str);
490
1.24k
            if(retval != UA_STATUSCODE_GOOD) {
491
6
                return retval;
492
6
            }
493
1.23k
            break;
494
1.24k
        }
495
3.77k
        default:
496
3.77k
            break;
497
5.01k
        }
498
5.01k
    }
499
477
    if(type == GENERICAPPLICATIONTYPE_CLIENT) {
500
0
        field->applicationType = UA_APPLICATIONTYPE_CLIENT;
501
0
        field->discoveryUrlsSize = 0;
502
0
        field->discoveryUrls = NULL;
503
0
    }
504
477
    return UA_STATUSCODE_GOOD;
505
483
}
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
790
PARSE_JSON(SubscriptionConfigurationField) {
548
790
    UA_ServerConfig *config = (UA_ServerConfig*)configField;
549
790
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
550
790
    cj5_token tok = nextToken(ctx);
551
295k
    for(size_t j = tok.size/2; j > 0; j--) {
552
294k
        tok = nextToken(ctx);
553
294k
        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
18
                retval = DurationRangeField_parseJson(ctx, &config->publishingIntervalLimits, NULL);
564
2.26k
            else if(strcmp(field_str, "lifeTimeCountLimits") == 0)
565
110
                retval = UInt32RangeField_parseJson(ctx, &config->lifeTimeCountLimits, NULL);
566
2.15k
            else if(strcmp(field_str, "keepAliveCountLimits") == 0)
567
1
                retval = UInt32RangeField_parseJson(ctx, &config->keepAliveCountLimits, NULL);
568
2.15k
            else if(strcmp(field_str, "maxNotificationsPerPublish") == 0)
569
1
                retval = UInt32Field_parseJson(ctx, &config->maxNotificationsPerPublish, NULL);
570
2.15k
            else if(strcmp(field_str, "enableRetransmissionQueue") == 0)
571
0
                retval = BooleanField_parseJson(ctx, &config->enableRetransmissionQueue, NULL);
572
2.15k
            else if(strcmp(field_str, "maxRetransmissionQueueSize") == 0)
573
0
                retval = UInt32Field_parseJson(ctx, &config->maxRetransmissionQueueSize, NULL);
574
2.15k
# ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
575
2.15k
            else if(strcmp(field_str, "maxEventsPerNode") == 0)
576
0
                retval = UInt32Field_parseJson(ctx, &config->maxEventsPerNode, NULL);
577
2.15k
# endif
578
2.15k
            else if(strcmp(field_str, "maxMonitoredItems") == 0)
579
1
                retval = UInt32Field_parseJson(ctx, &config->maxMonitoredItems, NULL);
580
2.15k
            else if(strcmp(field_str, "maxMonitoredItemsPerSubscription") == 0)
581
0
                retval = UInt32Field_parseJson(ctx, &config->maxMonitoredItemsPerSubscription, NULL);
582
2.15k
            else if(strcmp(field_str, "samplingIntervalLimits") == 0)
583
47
                retval = DurationRangeField_parseJson(ctx, &config->samplingIntervalLimits, NULL);
584
2.10k
            else if(strcmp(field_str, "queueSizeLimits") == 0)
585
1
                retval = UInt32RangeField_parseJson(ctx, &config->queueSizeLimits, NULL);
586
2.10k
            else if(strcmp(field_str, "maxPublishReqPerSession") == 0)
587
0
                retval = UInt32Field_parseJson(ctx, &config->maxPublishReqPerSession, NULL);
588
2.10k
            else {
589
2.10k
                LOG_UNKNOWN_FIELD(ctx, field_str);
590
2.10k
            }
591
2.28k
            UA_free(field_str);
592
2.28k
            if(retval != UA_STATUSCODE_GOOD) {
593
3
                return retval;
594
3
            }
595
2.28k
            break;
596
2.28k
        }
597
292k
        default:
598
292k
            break;
599
294k
        }
600
294k
    }
601
787
    return UA_STATUSCODE_GOOD;
602
790
}
603
#endif
604
605
42
PARSE_JSON(TcpConfigurationField) {
606
42
    UA_ServerConfig *config = (UA_ServerConfig*)configField;
607
42
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
608
42
    cj5_token tok = nextToken(ctx);
609
6.34k
    for(size_t j = tok.size/2; j > 0; j--) {
610
6.30k
        tok = nextToken(ctx);
611
6.30k
        switch (tok.type) {
612
363
        case CJ5_TOKEN_STRING: {
613
363
            char *field_str = (char*)UA_malloc(tok.size + 1);
614
363
            unsigned int str_len = 0;
615
363
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
616
363
            if(strcmp(field_str, "tcpBufSize") == 0)
617
0
                retval = UInt32Field_parseJson(ctx, &config->tcpBufSize, NULL);
618
363
            else if(strcmp(field_str, "tcpMaxMsgSize") == 0)
619
2
                retval = UInt32Field_parseJson(ctx, &config->tcpMaxMsgSize, NULL);
620
361
            else if(strcmp(field_str, "tcpMaxChunks") == 0)
621
0
                retval = UInt32Field_parseJson(ctx, &config->tcpMaxChunks, NULL);
622
361
            else {
623
361
                LOG_UNKNOWN_FIELD(ctx, field_str);
624
361
            }
625
363
            UA_free(field_str);
626
363
            if(retval != UA_STATUSCODE_GOOD) {
627
2
                return retval;
628
2
            }
629
361
            break;
630
363
        }
631
5.94k
        default:
632
5.94k
            break;
633
6.30k
        }
634
6.30k
    }
635
40
    return UA_STATUSCODE_GOOD;
636
42
}
637
638
#ifdef UA_ENABLE_PUBSUB
639
55
PARSE_JSON(PubsubConfigurationField) {
640
55
    UA_PubSubConfiguration *field = (UA_PubSubConfiguration*)configField;
641
55
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
642
55
    cj5_token tok = nextToken(ctx);
643
2.09k
    for(size_t j = tok.size/2; j > 0; j--) {
644
2.03k
        tok = nextToken(ctx);
645
2.03k
        switch (tok.type) {
646
426
        case CJ5_TOKEN_STRING: {
647
426
            char *field_str = (char*)UA_malloc(tok.size + 1);
648
426
            unsigned int str_len = 0;
649
426
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
650
426
            if(strcmp(field_str, "enableDeltaFrames") == 0)
651
0
                retval = BooleanField_parseJson(ctx, &field->enableDeltaFrames, NULL);
652
426
#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
653
426
            else if(strcmp(field_str, "enableInformationModelMethods") == 0)
654
0
                retval = BooleanField_parseJson(ctx, &field->enableInformationModelMethods, NULL);
655
426
#endif
656
426
            else {
657
426
                LOG_UNKNOWN_FIELD(ctx, field_str);
658
426
            }
659
426
            UA_free(field_str);
660
426
            if(retval != UA_STATUSCODE_GOOD) {
661
0
                return retval;
662
0
            }
663
426
            break;
664
426
        }
665
1.61k
        default:
666
1.61k
            break;
667
2.03k
        }
668
2.03k
    }
669
55
    return UA_STATUSCODE_GOOD;
670
55
}
671
#endif
672
673
#ifdef UA_ENABLE_HISTORIZING
674
144
PARSE_JSON(HistorizingConfigurationField) {
675
144
    UA_ServerConfig *config = (UA_ServerConfig*)configField;
676
144
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
677
144
    cj5_token tok = nextToken(ctx);
678
6.19k
    for(size_t j = tok.size/2; j > 0; j--) {
679
6.05k
        tok = nextToken(ctx);
680
6.05k
        switch (tok.type) {
681
440
        case CJ5_TOKEN_STRING: {
682
440
            char *field_str = (char*)UA_malloc(tok.size + 1);
683
440
            unsigned int str_len = 0;
684
440
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
685
440
            if(strcmp(field_str, "accessHistoryDataCapability") == 0)
686
0
                retval = BooleanField_parseJson(ctx, &config->accessHistoryDataCapability, NULL);
687
440
            else if(strcmp(field_str, "maxReturnDataValues") == 0)
688
0
                retval = UInt32Field_parseJson(ctx, &config->maxReturnDataValues, NULL);
689
440
            else if(strcmp(field_str, "accessHistoryEventsCapability") == 0)
690
0
                retval = BooleanField_parseJson(ctx, &config->accessHistoryEventsCapability, NULL);
691
440
            else if(strcmp(field_str, "maxReturnEventValues") == 0)
692
0
                retval = UInt32Field_parseJson(ctx, &config->maxReturnEventValues, NULL);
693
440
            else if(strcmp(field_str, "insertDataCapability") == 0)
694
0
                retval = BooleanField_parseJson(ctx, &config->insertDataCapability, NULL);
695
440
            else if(strcmp(field_str, "insertEventCapability") == 0)
696
1
                retval = BooleanField_parseJson(ctx, &config->insertEventCapability, NULL);
697
439
            else if(strcmp(field_str, "insertAnnotationsCapability") == 0)
698
0
                retval = BooleanField_parseJson(ctx, &config->insertAnnotationsCapability, NULL);
699
439
            else if(strcmp(field_str, "replaceDataCapability") == 0)
700
0
                retval = BooleanField_parseJson(ctx, &config->replaceDataCapability, NULL);
701
439
            else if(strcmp(field_str, "replaceEventCapability") == 0)
702
0
                retval = BooleanField_parseJson(ctx, &config->replaceEventCapability, NULL);
703
439
            else if(strcmp(field_str, "updateDataCapability") == 0)
704
0
                retval = BooleanField_parseJson(ctx, &config->updateDataCapability, NULL);
705
439
            else if(strcmp(field_str, "updateEventCapability") == 0)
706
0
                retval = BooleanField_parseJson(ctx, &config->updateEventCapability, NULL);
707
439
            else if(strcmp(field_str, "deleteRawCapability") == 0)
708
0
                retval = BooleanField_parseJson(ctx, &config->deleteRawCapability, NULL);
709
439
            else if(strcmp(field_str, "deleteEventCapability") == 0)
710
0
                retval = BooleanField_parseJson(ctx, &config->deleteEventCapability, NULL);
711
439
            else if(strcmp(field_str, "deleteAtTimeDataCapability") == 0)
712
0
                retval = BooleanField_parseJson(ctx, &config->deleteAtTimeDataCapability, NULL);
713
439
            else {
714
439
                LOG_UNKNOWN_FIELD(ctx, field_str);
715
439
            }
716
440
            UA_free(field_str);
717
440
            if(retval != UA_STATUSCODE_GOOD) {
718
1
                return retval;
719
1
            }
720
439
            break;
721
440
        }
722
5.61k
        default:
723
5.61k
            break;
724
6.05k
        }
725
6.05k
    }
726
143
    return UA_STATUSCODE_GOOD;
727
144
}
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
41
                            const UA_Logger *logger) {
738
41
    if(!policy || !policyUri)
739
0
        return UA_STATUSCODE_BADINVALIDARGUMENT;
740
741
41
    UA_ByteString certificate = UA_BYTESTRING_NULL;
742
41
    if(localCertificate)
743
41
    certificate = *localCertificate;
744
41
#ifdef UA_ENABLE_ENCRYPTION
745
41
    UA_ByteString privateKey = UA_BYTESTRING_NULL;
746
41
    if(localPrivateKey)
747
41
        privateKey = *localPrivateKey;
748
41
#endif
749
750
41
    if(UA_String_equal(policyUri, &UA_SECURITY_POLICY_NONE_URI))
751
0
        return UA_SecurityPolicy_None(policy, certificate, logger);
752
753
41
#ifdef UA_ENABLE_ENCRYPTION
754
41
    static const UA_String basic128Rsa15Uri =
755
41
        UA_STRING_STATIC("http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15");
756
41
    static const UA_String basic256Uri =
757
41
        UA_STRING_STATIC("http://opcfoundation.org/UA/SecurityPolicy#Basic256");
758
41
    static const UA_String basic256Sha256Uri =
759
41
        UA_STRING_STATIC("http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256");
760
41
    static const UA_String aes128Sha256RsaOaepUri =
761
41
        UA_STRING_STATIC("http://opcfoundation.org/UA/SecurityPolicy#Aes128_Sha256_RsaOaep");
762
41
    static const UA_String aes256Sha256RsaPssUri =
763
41
        UA_STRING_STATIC("http://opcfoundation.org/UA/SecurityPolicy#Aes256_Sha256_RsaPss");
764
#if defined(UA_ENABLE_ENCRYPTION_OPENSSL)
765
    static const UA_String eccNistP256Uri =
766
        UA_STRING_STATIC("http://opcfoundation.org/UA/SecurityPolicy#EccNistP256");
767
#endif
768
769
41
    if(UA_String_equal(policyUri, &basic128Rsa15Uri))
770
0
        return UA_SecurityPolicy_Basic128Rsa15(policy, certificate, privateKey, logger);
771
41
    if(UA_String_equal(policyUri, &basic256Uri))
772
0
        return UA_SecurityPolicy_Basic256(policy, certificate, privateKey, logger);
773
41
    if(UA_String_equal(policyUri, &basic256Sha256Uri))
774
0
        return UA_SecurityPolicy_Basic256Sha256(policy, certificate, privateKey, logger);
775
41
    if(UA_String_equal(policyUri, &aes128Sha256RsaOaepUri))
776
0
        return UA_SecurityPolicy_Aes128Sha256RsaOaep(policy, certificate, privateKey, logger);
777
41
    if(UA_String_equal(policyUri, &aes256Sha256RsaPssUri))
778
0
        return UA_SecurityPolicy_Aes256Sha256RsaPss(policy, certificate, privateKey, logger);
779
#if defined(UA_ENABLE_ENCRYPTION_OPENSSL)
780
    if(UA_String_equal(policyUri, &eccNistP256Uri))
781
        return UA_SecurityPolicy_EccNistP256(policy, applicationType, certificate,
782
                                             privateKey, logger);
783
#endif
784
41
#endif
785
786
41
    return UA_STATUSCODE_BADNOTSUPPORTED;
787
41
}
788
789
1
PARSE_JSON(CertificateFileField) {
790
1
    UA_ByteString *certificate = (UA_ByteString*)configField;
791
1
    UA_ByteString_init(certificate);
792
1
    UA_String filename = {.length = 0, .data = NULL};
793
794
1
    UA_StatusCode retval = StringField_parseJson(ctx, &filename, NULL);
795
1
    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
1
    return retval;
812
1
}
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
42
                              const UA_Logger *logger) {
865
42
    UA_String policy = {.length = 0, .data = NULL};
866
42
    UA_ByteString certificate = {.length = 0, .data = NULL};
867
42
    UA_ByteString privateKey = {.length = 0, .data = NULL};
868
42
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
869
870
42
    cj5_token tok = nextToken(ctx);
871
830
    for(size_t i = tok.size / 2; i > 0 && retval == UA_STATUSCODE_GOOD; i--) {
872
788
        tok = nextToken(ctx);
873
788
        switch(tok.type) {
874
150
        case CJ5_TOKEN_STRING: {
875
150
            char *field_str = (char *)UA_malloc(tok.size + 1);
876
150
            unsigned int str_len = 0;
877
150
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
878
150
            if(strcmp(field_str, "certificate") == 0) {
879
0
                retval = CertificateFileField_parseJson(ctx, &certificate, NULL);
880
150
            } else if(strcmp(field_str, "privateKey") == 0) {
881
1
                retval = CertificateFileField_parseJson(ctx, &privateKey, NULL);
882
149
            } else if(strcmp(field_str, "policy") == 0) {
883
0
                retval = StringField_parseJson(ctx, &policy, NULL);
884
149
            } else {
885
149
                LOG_UNKNOWN_FIELD(ctx, field_str);
886
149
            }
887
150
            UA_free(field_str);
888
150
            break;
889
0
        }
890
638
        default:
891
638
            break;
892
788
        }
893
788
    }
894
895
42
    if(retval == UA_STATUSCODE_GOOD) {
896
41
        retval = UA_SecurityPolicy_initByUri(field, applicationType, &policy,
897
41
                                             &certificate, &privateKey, logger);
898
41
    }
899
900
42
    if(policy.length > 0)
901
0
        UA_String_clear(&policy);
902
42
    if(certificate.length > 0)
903
0
        UA_ByteString_clear(&certificate);
904
42
    if(privateKey.length > 0)
905
0
        UA_ByteString_clear(&privateKey);
906
907
42
    return retval;
908
42
}
909
910
static UA_StatusCode
911
SecurityPoliciesField_parseJson(ParsingCtx *ctx, void *configField, size_t *configFieldSize, UA_ApplicationType applicationType,
912
42
                                const UA_Logger *logger) {
913
42
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
914
42
    UA_SecurityPolicy **securityPoliciesField = (UA_SecurityPolicy**)configField;
915
916
42
    cj5_token tok = nextToken(ctx);
917
42
    for(size_t j = tok.size; j > 0; j--) {
918
42
        UA_SecurityPolicy *tmp = (UA_SecurityPolicy*)
919
42
            UA_realloc(*securityPoliciesField, sizeof(UA_SecurityPolicy) * (*configFieldSize + 1));
920
42
        if(!tmp) {
921
0
            retval = UA_STATUSCODE_BADOUTOFMEMORY;
922
0
            break;
923
0
        }
924
42
        *securityPoliciesField = tmp;
925
42
        retval = SecurityPolicyField_parseJson(ctx, &tmp[*configFieldSize],
926
42
                                               applicationType, logger);
927
42
        if(retval != UA_STATUSCODE_GOOD) {
928
42
            if(*configFieldSize == 0) {
929
0
                UA_free(*securityPoliciesField);
930
0
                *securityPoliciesField = NULL;
931
0
            }
932
42
            break;
933
42
        }
934
0
        (*configFieldSize)++;
935
0
    }
936
42
    return retval;
937
42
}
938
939
#ifdef UA_ENABLE_ENCRYPTION
940
4.25k
PARSE_JSON(SecurityPkiField) {
941
4.25k
    UA_ServerConfig *config = (UA_ServerConfig*)configField;
942
4.25k
    UA_String pkiFolder = {.length = 0, .data = NULL};
943
944
4.25k
    cj5_token tok = nextToken(ctx);
945
4.25k
    UA_ByteString buf = getJsonPart(tok, ctx->json);
946
4.25k
    UA_StatusCode retval = UA_decodeJson(&buf, &pkiFolder, &UA_TYPES[UA_TYPES_STRING], NULL);
947
4.25k
    if(retval != UA_STATUSCODE_GOOD)
948
38
        return retval;
949
950
4.21k
#if defined(__linux__) || defined(UA_ARCHITECTURE_WIN32) || defined(__APPLE__) || defined(__OpenBSD__)
951
    /* Set up the parameters for the filestore certificate store */
952
4.21k
    UA_KeyValuePair params[2];
953
4.21k
    size_t paramsSize = 2;
954
955
4.21k
    params[0].key = UA_QUALIFIEDNAME(0, "max-trust-listsize");
956
4.21k
    UA_Variant_setScalar(&params[0].value, &config->maxTrustListSize, &UA_TYPES[UA_TYPES_UINT32]);
957
4.21k
    params[1].key = UA_QUALIFIEDNAME(0, "max-rejected-listsize");
958
4.21k
    UA_Variant_setScalar(&params[1].value, &config->maxRejectedListSize, &UA_TYPES[UA_TYPES_UINT32]);
959
960
4.21k
    UA_KeyValueMap paramsMap;
961
4.21k
    paramsMap.map = params;
962
4.21k
    paramsMap.mapSize = paramsSize;
963
964
    /* set server config field */
965
4.21k
    UA_NodeId defaultApplicationGroup =
966
4.21k
           UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
967
4.21k
    retval = UA_CertificateGroup_Filestore(&config->secureChannelPKI, &defaultApplicationGroup,
968
4.21k
                                           pkiFolder, config->logging, &paramsMap);
969
4.21k
    if(retval != UA_STATUSCODE_GOOD) {
970
72
        UA_String_clear(&pkiFolder);
971
72
        return retval;
972
72
    }
973
974
4.14k
    UA_NodeId defaultUserTokenGroup =
975
4.14k
            UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTUSERTOKENGROUP);
976
4.14k
    retval = UA_CertificateGroup_Filestore(&config->sessionPKI, &defaultUserTokenGroup,
977
4.14k
                                            pkiFolder, config->logging, &paramsMap);
978
4.14k
    if(retval != UA_STATUSCODE_GOOD) {
979
0
        UA_String_clear(&pkiFolder);
980
0
        return retval;
981
0
    }
982
983
    /* Clean up */
984
4.14k
    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
4.14k
    return UA_STATUSCODE_GOOD;
992
4.14k
}
993
#endif
994
995
49
PARSE_JSON(RuleHandlingField) {
996
49
    UA_UInt32 enum_value;
997
49
    UA_StatusCode retval = UInt32Field_parseJson(ctx, &enum_value, NULL);
998
49
    if(retval != UA_STATUSCODE_GOOD)
999
34
        return retval;
1000
15
    UA_RuleHandling *field = (UA_RuleHandling*)configField;
1001
15
    *field = (UA_RuleHandling)enum_value;
1002
15
    return retval;
1003
49
}
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
4.64k
skipUnknownItem(ParsingCtx* ctx) {
1012
4.64k
    cj5_skip(&ctx->result, &ctx->index);
1013
4.64k
}
1014
1015
static UA_StatusCode
1016
5.21k
parseJSONServerConfig(UA_ServerConfig *config, UA_ByteString json_config) {
1017
    // Parsing json config
1018
5.21k
    const char *json = (const char*)json_config.data;
1019
5.21k
    cj5_token tokens[MAX_TOKENS];
1020
5.21k
    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.21k
    if(r.error != CJ5_ERROR_NONE || r.num_tokens < 2 ||
1025
4.55k
       r.tokens[0].type != CJ5_TOKEN_OBJECT)
1026
683
        return UA_STATUSCODE_BADDECODINGERROR;
1027
1028
4.52k
    ParsingCtx ctx;
1029
4.52k
    ctx.json = json;
1030
4.52k
    ctx.result = r;
1031
4.52k
    ctx.index = 1; // The first token is ignored because it is known and not needed.
1032
1033
4.52k
    ctx.logging = config->logging;
1034
1035
    /* Buffer for the field name */
1036
4.52k
    char field[256];
1037
1038
4.52k
    size_t serverConfigSize = 0;
1039
4.52k
    if(ctx.result.tokens)
1040
4.52k
        serverConfigSize = (ctx.result.tokens[ctx.index-1].size/2);
1041
4.52k
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
1042
22.8k
    for (size_t j = serverConfigSize; j > 0 && ctx.index < ctx.result.num_tokens; j--) {
1043
18.7k
        cj5_token tok = ctx.result.tokens[ctx.index];
1044
18.7k
        switch (tok.type) {
1045
18.5k
            case CJ5_TOKEN_STRING: {
1046
18.5k
                if(tok.size >= 255) {
1047
963
                    UA_LOG_WARNING(ctx.logging, UA_LOGCATEGORY_APPLICATION,
1048
963
                                   "Configuration field name too long");
1049
963
                    continue;
1050
963
                }
1051
17.5k
                unsigned int str_len = 0;
1052
17.5k
                cj5_error_code res = cj5_get_str(&ctx.result, (unsigned int)ctx.index, field, &str_len);
1053
17.5k
                if(res != CJ5_ERROR_NONE) {
1054
6.68k
                    UA_LOG_WARNING(ctx.logging, UA_LOGCATEGORY_APPLICATION,
1055
6.68k
                                   "Configuration field name not a valid string");
1056
6.68k
                    continue;
1057
6.68k
                }
1058
10.8k
                if(strcmp(field, "buildInfo") == 0)
1059
51
                    retval = BuildInfo_parseJson(&ctx, &config->buildInfo, NULL);
1060
10.8k
                else if(strcmp(field, "applicationDescription") == 0)
1061
483
                    retval = GenericApplicationDescriptionField_parseJson(&ctx, &config->applicationDescription, NULL, GENERICAPPLICATIONTYPE_SERVER);
1062
10.3k
                else if(strcmp(field, "shutdownDelay") == 0)
1063
8
                    retval = DoubleField_parseJson(&ctx, &config->shutdownDelay, NULL);
1064
10.3k
                else if(strcmp(field, "verifyRequestTimestamp") == 0)
1065
47
                    retval = RuleHandlingField_parseJson(&ctx, &config->verifyRequestTimestamp, NULL);
1066
10.2k
                else if(strcmp(field, "allowEmptyVariables") == 0)
1067
2
                    retval = RuleHandlingField_parseJson(&ctx, &config->allowEmptyVariables, NULL);
1068
10.2k
                else if(strcmp(field, "serverUrls") == 0)
1069
2
                    retval = StringArrayField_parseJson(&ctx, &config->serverUrls, &config->serverUrlsSize);
1070
10.2k
                else if(strcmp(field, "tcpEnabled") == 0)
1071
1
                    retval = BooleanField_parseJson(&ctx, &config->tcpEnabled, NULL);
1072
10.2k
                else if(strcmp(field, "tcp") == 0)
1073
42
                    retval = TcpConfigurationField_parseJson(&ctx, config, NULL);
1074
#ifdef UA_ENABLE_LWS
1075
                else if(strcmp(field, "webSocketEnabled") == 0)
1076
                    retval = BooleanField_parseJson(&ctx, &config->webSocketEnabled, NULL);
1077
                else if(strcmp(field, "webSocket") == 0)
1078
                    retval = WebSocketConfigurationField_parseJson(&ctx, config, NULL);
1079
#endif
1080
10.2k
                else if(strcmp(field, "securityPolicyNoneDiscoveryOnly") == 0)
1081
1
                    retval = BooleanField_parseJson(&ctx, &config->securityPolicyNoneDiscoveryOnly, NULL);
1082
10.2k
                else if(strcmp(field, "modellingRulesOnInstances") == 0)
1083
0
                    retval = BooleanField_parseJson(&ctx, &config->modellingRulesOnInstances, NULL);
1084
10.2k
                else if(strcmp(field, "copyMethodsOnInstances") == 0)
1085
0
                    retval = BooleanField_parseJson(&ctx, &config->copyMethodsOnInstances, NULL);
1086
10.2k
                else if(strcmp(field, "maxSecureChannels") == 0)
1087
2
                    retval = UInt16Field_parseJson(&ctx, &config->maxSecureChannels, NULL);
1088
10.2k
                else if(strcmp(field, "maxSecurityTokenLifetime") == 0)
1089
4
                    retval = UInt32Field_parseJson(&ctx, &config->maxSecurityTokenLifetime, NULL);
1090
10.2k
                else if(strcmp(field, "maxSessions") == 0)
1091
149
                    retval = UInt16Field_parseJson(&ctx, &config->maxSessions, NULL);
1092
10.0k
                else if(strcmp(field, "maxSessionTimeout") == 0)
1093
13
                    retval = DoubleField_parseJson(&ctx, &config->maxSessionTimeout, NULL);
1094
10.0k
                else if(strcmp(field, "maxNodesPerRead") == 0)
1095
1
                    retval = UInt32Field_parseJson(&ctx, &config->maxNodesPerRead, NULL);
1096
10.0k
                else if(strcmp(field, "maxNodesPerWrite") == 0)
1097
2
                    retval = UInt32Field_parseJson(&ctx, &config->maxNodesPerWrite, NULL);
1098
10.0k
                else if(strcmp(field, "maxNodesPerMethodCall") == 0)
1099
1
                    retval = UInt32Field_parseJson(&ctx, &config->maxNodesPerMethodCall, NULL);
1100
10.0k
                else if(strcmp(field, "maxNodesPerBrowse") == 0)
1101
2
                    retval = UInt32Field_parseJson(&ctx, &config->maxNodesPerBrowse, NULL);
1102
10.0k
                else if(strcmp(field, "maxNodesPerRegisterNodes") == 0)
1103
1
                    retval = UInt32Field_parseJson(&ctx, &config->maxNodesPerRegisterNodes, NULL);
1104
10.0k
                else if(strcmp(field, "maxNodesPerTranslateBrowsePathsToNodeIds") == 0)
1105
1
                    retval = UInt32Field_parseJson(&ctx, &config->maxNodesPerTranslateBrowsePathsToNodeIds, NULL);
1106
10.0k
                else if(strcmp(field, "maxNodesPerNodeManagement") == 0)
1107
1
                    retval = UInt32Field_parseJson(&ctx, &config->maxNodesPerNodeManagement, NULL);
1108
10.0k
                else if(strcmp(field, "maxMonitoredItemsPerCall") == 0)
1109
1
                    retval = UInt32Field_parseJson(&ctx, &config->maxMonitoredItemsPerCall, NULL);
1110
10.0k
                else if(strcmp(field, "maxReferencesPerNode") == 0)
1111
67
                    retval = UInt32Field_parseJson(&ctx, &config->maxReferencesPerNode, NULL);
1112
9.97k
                else if(strcmp(field, "reverseReconnectInterval") == 0)
1113
1
                    retval = UInt32Field_parseJson(&ctx, &config->reverseReconnectInterval, NULL);
1114
1115
9.97k
#if UA_MULTITHREADING >= 100
1116
9.97k
                else if(strcmp(field, "asyncOperationTimeout") == 0)
1117
1
                    retval = DoubleField_parseJson(&ctx, &config->asyncOperationTimeout, NULL);
1118
9.97k
                else if(strcmp(field, "maxAsyncOperationQueueSize") == 0)
1119
45
                    retval = UInt64Field_parseJson(&ctx, &config->maxAsyncOperationQueueSize, NULL);
1120
9.92k
#endif
1121
1122
9.92k
#ifdef UA_ENABLE_DISCOVERY
1123
9.92k
                else if(strcmp(field, "registeredServersEnabled") == 0)
1124
1
                    retval = BooleanField_parseJson(&ctx, &config->registeredServersEnabled, NULL);
1125
9.92k
                else if(strcmp(field, "registeredServerCleanupTimeout") == 0)
1126
1
                    retval = UInt32Field_parseJson(&ctx, &config->registeredServerCleanupTimeout, NULL);
1127
9.92k
                else if(strcmp(field, "serversOnNetworkEnabled") == 0)
1128
1
                    retval = BooleanField_parseJson(&ctx, &config->serversOnNetworkEnabled, NULL);
1129
9.92k
#endif
1130
1131
9.92k
#ifdef UA_ENABLE_SUBSCRIPTIONS
1132
9.92k
                else if(strcmp(field, "subscriptionsEnabled") == 0)
1133
1
                    retval = BooleanField_parseJson(&ctx, &config->subscriptionsEnabled, NULL);
1134
9.92k
                else if(strcmp(field, "subscriptions") == 0)
1135
790
                    retval = SubscriptionConfigurationField_parseJson(&ctx, config, NULL);
1136
9.13k
# endif
1137
1138
9.13k
#ifdef UA_ENABLE_HISTORIZING
1139
9.13k
                else if(strcmp(field, "historizingEnabled") == 0)
1140
1
                    retval = BooleanField_parseJson(&ctx, &config->historizingEnabled, NULL);
1141
9.13k
                else if(strcmp(field, "historizing") == 0)
1142
144
                    retval = HistorizingConfigurationField_parseJson(&ctx, config, NULL);
1143
8.99k
#endif
1144
1145
8.99k
#ifdef UA_ENABLE_PUBSUB
1146
8.99k
                else if(strcmp(field, "pubsubEnabled") == 0)
1147
1
                    retval = BooleanField_parseJson(&ctx, &config->pubsubEnabled, NULL);
1148
8.98k
                else if(strcmp(field, "pubsub") == 0)
1149
55
                    retval = PubsubConfigurationField_parseJson(&ctx, &config->pubSubConfig, NULL);
1150
8.93k
#endif
1151
8.93k
#ifdef UA_ENABLE_ENCRYPTION
1152
8.93k
                else if(strcmp(field, "securityPolicies") == 0)
1153
42
                    retval = SecurityPoliciesField_parseJson(&ctx, &config->securityPolicies, &config->securityPoliciesSize, UA_APPLICATIONTYPE_SERVER, config->logging);
1154
8.89k
                else if(strcmp(field, "pkiFolder") == 0)
1155
4.25k
                    retval = SecurityPkiField_parseJson(&ctx, config, NULL);
1156
4.64k
#endif
1157
4.64k
                else {
1158
4.64k
                    UA_LOG_WARNING(ctx.logging, UA_LOGCATEGORY_APPLICATION,
1159
4.64k
                                   "Field name '%s' unknown or misspelled. Maybe the feature is not enabled.", field);
1160
                    /* skip the name of item */
1161
4.64k
                    ++ctx.index;
1162
                    /* skip value of unknown item */
1163
4.64k
                    skipUnknownItem(&ctx);
1164
                    /* after skipUnknownItem() ctx->index points to the name of the following item.
1165
                       We must decrement index in oder following increment will
1166
                       still set index to the right position (name of the following item) */
1167
4.64k
                    --ctx.index;
1168
4.64k
                }
1169
10.8k
                if(retval != UA_STATUSCODE_GOOD) {
1170
383
                    UA_LOG_ERROR(ctx.logging, UA_LOGCATEGORY_APPLICATION,
1171
383
                                 "An error occurred while parsing the configuration field %s", field);
1172
383
                    return retval;
1173
383
                }
1174
10.4k
                break;
1175
10.8k
            }
1176
10.4k
            default:
1177
226
                break;
1178
18.7k
        }
1179
10.7k
        ctx.index += 1;
1180
10.7k
    }
1181
4.14k
    return retval;
1182
4.52k
}
1183
1184
UA_Server *
1185
5.49k
UA_Server_newFromFile(const UA_ByteString jsonConfig) {
1186
5.49k
    UA_ServerConfig config;
1187
5.49k
    UA_StatusCode res = UA_ServerConfig_loadFromFile(&config, jsonConfig);
1188
5.49k
    if(res != UA_STATUSCODE_GOOD)
1189
1.27k
        return NULL;
1190
4.21k
    return UA_Server_newWithConfig(&config);
1191
5.49k
}
1192
1193
UA_StatusCode
1194
5.21k
UA_ServerConfig_loadFromFile(UA_ServerConfig *config, const UA_ByteString jsonConfig) {
1195
5.21k
    memset(config, 0, sizeof(UA_ServerConfig));
1196
5.21k
    UA_StatusCode res = UA_ServerConfig_setDefault(config);
1197
5.21k
    if (res == UA_STATUSCODE_GOOD) {
1198
5.21k
        res = parseJSONServerConfig(config, jsonConfig);
1199
5.21k
        if (UA_StatusCode_isBad(res)) {
1200
1.06k
            UA_ServerConfig_clear(config);
1201
1.06k
        }
1202
5.21k
    }
1203
5.21k
    return res;
1204
5.21k
}
1205
1206
0
PARSE_JSON(ConnectionConfig) {
1207
0
    UA_ConnectionConfig *field = (UA_ConnectionConfig*)configField;
1208
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
1209
0
    cj5_token tok = nextToken(ctx);
1210
0
    for(size_t j = tok.size/2; j > 0; j--) {
1211
0
        tok = nextToken(ctx);
1212
0
        switch (tok.type) {
1213
0
        case CJ5_TOKEN_STRING: {
1214
0
            char *field_str = (char*)UA_malloc(tok.size + 1);
1215
0
            unsigned int str_len = 0;
1216
0
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
1217
0
            if(strcmp(field_str, "protocolVersion") == 0)
1218
0
                retval = UInt32Field_parseJson(ctx, &field->protocolVersion, NULL);
1219
0
            else if(strcmp(field_str, "recvBufferSize") == 0)
1220
0
                retval = UInt32Field_parseJson(ctx, &field->recvBufferSize, NULL);
1221
0
            else if(strcmp(field_str, "sendBufferSize") == 0)
1222
0
                retval = UInt32Field_parseJson(ctx, &field->sendBufferSize, NULL);
1223
0
            else if(strcmp(field_str, "localMaxMessageSize") == 0)
1224
0
                retval = UInt32Field_parseJson(ctx, &field->localMaxMessageSize, NULL);
1225
0
            else if(strcmp(field_str, "remoteMaxMessageSize") == 0)
1226
0
                retval = UInt32Field_parseJson(ctx, &field->remoteMaxMessageSize, NULL);
1227
0
            else if(strcmp(field_str, "localMaxChunkCount") == 0)
1228
0
                retval = UInt32Field_parseJson(ctx, &field->localMaxChunkCount, NULL);
1229
0
            else if(strcmp(field_str, "remoteMaxChunkCount") == 0)
1230
0
                retval = UInt32Field_parseJson(ctx, &field->remoteMaxChunkCount, NULL);
1231
0
            else {
1232
0
                LOG_UNKNOWN_FIELD(ctx, field_str);
1233
0
            }
1234
0
            UA_free(field_str);
1235
0
            if(retval != UA_STATUSCODE_GOOD) {
1236
0
                return retval;
1237
0
            }
1238
0
            break;
1239
0
        }
1240
0
        default:
1241
0
            break;
1242
0
        }
1243
0
    }
1244
0
    return UA_STATUSCODE_GOOD;
1245
0
}
1246
1247
0
PARSE_JSON(UserTokenType) {
1248
0
    cj5_token tok = nextToken(ctx);
1249
0
    UA_ByteString rawToken = getJsonPart(tok, ctx->json);
1250
0
    UA_UserTokenType *field = (UA_UserTokenType*)configField;
1251
0
    char *fieldStr = (char*)UA_malloc(tok.size + 1);
1252
0
    unsigned int strLen = 0;
1253
1254
0
    if(cj5_get_str(&ctx->result, (unsigned int)ctx->index, fieldStr, &strLen) == CJ5_ERROR_NONE) {
1255
0
        if(strcmp("Anonymous", fieldStr) == 0)
1256
0
            *field = UA_USERTOKENTYPE_ANONYMOUS;
1257
0
        else if(strcmp("UserName", fieldStr) == 0)
1258
0
            *field = UA_USERTOKENTYPE_USERNAME;
1259
0
        else if(strcmp("Certificate", fieldStr) == 0)
1260
0
            *field = UA_USERTOKENTYPE_CERTIFICATE;
1261
0
        else if(strcmp("IssuedToken", fieldStr) == 0)
1262
0
            *field = UA_USERTOKENTYPE_ISSUEDTOKEN;
1263
0
        else {
1264
0
            UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION,
1265
0
                        "Unknown UserTokenType '%s'", fieldStr);
1266
0
            UA_free(fieldStr);
1267
0
            return UA_STATUSCODE_BAD;
1268
0
        }
1269
0
        UA_free(fieldStr);
1270
0
        return UA_STATUSCODE_GOOD;
1271
0
    }
1272
0
    UA_free(fieldStr);
1273
1274
    /* Try numeric fallback */
1275
0
    UA_UInt32 enumValue;
1276
0
    UA_StatusCode retval = UA_decodeJson(&rawToken, &enumValue, &UA_TYPES[UA_TYPES_UINT32], NULL);
1277
0
    if(retval != UA_STATUSCODE_GOOD) {
1278
0
        UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION,
1279
0
                    "Unknown UserTokenType '%S'", rawToken);
1280
0
        return retval;
1281
0
    }
1282
0
    *field = (UA_UserTokenType)enumValue;
1283
0
    return UA_STATUSCODE_GOOD;
1284
0
}
1285
1286
/* Parse the userIdentityToken field. This creates an ExtensionObject containing
1287
 * one of three token types: Anonymous, Username, or Certificate.
1288
 * The type can be explicitly specified via the "type" field, or inferred by
1289
 * the presence of other fields. */
1290
0
PARSE_JSON(UserIdentityToken) {
1291
0
    UA_ExtensionObject *field = (UA_ExtensionObject*)configField;
1292
0
    cj5_token tok = nextToken(ctx);
1293
1294
    /* Variables to track which fields are encountered */
1295
0
    UA_Int32 detectedType = -1; /* -1 indicates no type detected yet */
1296
0
    UA_Boolean typeExplicitlySet = false;
1297
1298
    /* Temporary storage for token fields */
1299
0
    UA_AnonymousIdentityToken anonToken;
1300
0
    UA_UserNameIdentityToken userNameToken;
1301
0
    UA_X509IdentityToken certToken;
1302
1303
0
    UA_AnonymousIdentityToken_init(&anonToken);
1304
0
    UA_UserNameIdentityToken_init(&userNameToken);
1305
0
    UA_X509IdentityToken_init(&certToken);
1306
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
1307
1308
0
    for(size_t j = tok.size/2; j > 0 && retval == UA_STATUSCODE_GOOD; j--) {
1309
0
        tok = nextToken(ctx);
1310
0
        switch (tok.type) {
1311
0
        case CJ5_TOKEN_STRING: {
1312
0
            char *field_str = (char*)UA_malloc(tok.size + 1);
1313
0
            unsigned int str_len = 0;
1314
0
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
1315
1316
0
            if(strcmp(field_str, "type") == 0) {
1317
1318
0
                if (detectedType != -1) {
1319
0
                    UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION,
1320
0
                                 "Inconsistent type information in userIdentityToken. Type was "
1321
0
                                 "already detected as %d, but 'type' field is set to a different "
1322
0
                                 "value.",
1323
0
                                 detectedType);
1324
0
                    retval = UA_STATUSCODE_BAD;
1325
0
                }
1326
1327
0
                if (retval == UA_STATUSCODE_GOOD) {
1328
                    /* Parse the type field */
1329
0
                    cj5_token typeToken = nextToken(ctx);
1330
0
                    char *typeStr = (char*)UA_malloc(typeToken.size + 1);
1331
0
                    unsigned int typeLen = 0;
1332
1333
0
                    if(cj5_get_str(&ctx->result, (unsigned int)ctx->index, typeStr, &typeLen) == CJ5_ERROR_NONE) {
1334
0
                        if(strcmp("Anonymous", typeStr) == 0) {
1335
0
                            detectedType = UA_USERTOKENTYPE_ANONYMOUS;
1336
0
                            typeExplicitlySet = true;
1337
0
                        } else if(strcmp("UserName", typeStr) == 0) {
1338
0
                            detectedType = UA_USERTOKENTYPE_USERNAME;
1339
0
                            typeExplicitlySet = true;
1340
0
                        } else if(strcmp("Certificate", typeStr) == 0) {
1341
0
                            detectedType = UA_USERTOKENTYPE_CERTIFICATE;
1342
0
                            typeExplicitlySet = true;
1343
0
                        } else {
1344
0
                            UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION,
1345
0
                                        "Unknown userIdentityToken type '%s'", typeStr);
1346
0
                            retval = UA_STATUSCODE_BAD;
1347
0
                        }
1348
0
                    } else {
1349
0
                        UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION,
1350
0
                                    "Failed to parse userIdentityToken type field");
1351
0
                        retval = UA_STATUSCODE_BAD;
1352
0
                    }
1353
0
                    UA_free(typeStr);
1354
0
                }
1355
0
            }
1356
0
            else if(strcmp(field_str, "userName") == 0) {
1357
                /* This field locks in UserName token type */
1358
0
                if(!typeExplicitlySet && detectedType == -1) {
1359
0
                    detectedType = UA_USERTOKENTYPE_USERNAME;
1360
0
                }
1361
0
                if(detectedType != UA_USERTOKENTYPE_USERNAME) {
1362
0
                    UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION,
1363
0
                                "Field 'userName' can only be used with UserName token type");
1364
0
                    retval = UA_STATUSCODE_BAD;
1365
0
                }
1366
0
                else {
1367
0
                    retval = StringField_parseJson(ctx, &userNameToken.userName, NULL);
1368
0
                }
1369
0
            }
1370
0
            else if(strcmp(field_str, "password") == 0) {
1371
                /* This field locks in UserName token type */
1372
0
                if(!typeExplicitlySet && detectedType == -1) {
1373
0
                    detectedType = UA_USERTOKENTYPE_USERNAME;
1374
0
                }
1375
0
                if(detectedType != UA_USERTOKENTYPE_USERNAME) {
1376
0
                    UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION,
1377
0
                                "Field 'password' can only be used with UserName token type");
1378
0
                    retval = UA_STATUSCODE_BAD;
1379
0
                } else {
1380
0
                    retval = ByteStringField_parseJson(ctx, &userNameToken.password, NULL);
1381
0
                }
1382
0
            }
1383
0
            else if(strcmp(field_str, "encryptionAlgorithm") == 0) {
1384
                /* This field can be used with UserName token type */
1385
0
                if(!typeExplicitlySet && detectedType == -1) {
1386
0
                    detectedType = UA_USERTOKENTYPE_USERNAME;
1387
0
                }
1388
0
                if(detectedType != UA_USERTOKENTYPE_USERNAME) {
1389
0
                    UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION,
1390
0
                                "Field 'encryptionAlgorithm' can only be used with UserName token type");
1391
0
                    retval = UA_STATUSCODE_BAD;
1392
0
                }
1393
0
                else {
1394
0
                    retval = StringField_parseJson(ctx, &userNameToken.encryptionAlgorithm, NULL);
1395
0
                }
1396
0
            }
1397
0
            else if(strcmp(field_str, "certificateData") == 0) {
1398
                /* This field locks in Certificate token type */
1399
0
                if(!typeExplicitlySet && detectedType == -1) {
1400
0
                    detectedType = UA_USERTOKENTYPE_CERTIFICATE;
1401
0
                }
1402
0
                if(detectedType != UA_USERTOKENTYPE_CERTIFICATE) {
1403
0
                    UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION,
1404
0
                                "Field 'certificateData' can only be used with Certificate token type");
1405
0
                    retval = UA_STATUSCODE_BAD;
1406
0
                }
1407
0
                else {
1408
0
                    retval = CertificateFileField_parseJson(ctx, &certToken.certificateData, NULL);
1409
0
                }
1410
0
            }
1411
0
            else {
1412
0
                LOG_UNKNOWN_FIELD(ctx, field_str);
1413
0
            }
1414
0
            UA_free(field_str);
1415
0
            break;
1416
0
        }
1417
0
        default:
1418
0
            break;
1419
0
        }
1420
0
    }
1421
1422
0
    if(retval == UA_STATUSCODE_GOOD) {
1423
        /* If no type was detected, default to Anonymous */
1424
0
        if(detectedType == -1) {
1425
0
            detectedType = UA_USERTOKENTYPE_ANONYMOUS;
1426
0
        }
1427
1428
        /* Create the ExtensionObject with the appropriate token type */
1429
0
        if(detectedType == UA_USERTOKENTYPE_ANONYMOUS) {
1430
0
            retval = UA_ExtensionObject_setValueCopy(field, &anonToken,
1431
0
                                                    &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN]);
1432
0
        } else if(detectedType == UA_USERTOKENTYPE_USERNAME) {
1433
0
            retval = UA_ExtensionObject_setValueCopy(field, &userNameToken,
1434
0
                                                    &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN]);
1435
0
        } else if(detectedType == UA_USERTOKENTYPE_CERTIFICATE) {
1436
0
            retval = UA_ExtensionObject_setValueCopy(field, &certToken,
1437
0
                                                    &UA_TYPES[UA_TYPES_X509IDENTITYTOKEN]);
1438
0
        } else {
1439
0
            UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION,
1440
0
                        "Invalid userIdentityToken type");
1441
0
            retval = UA_STATUSCODE_BAD;
1442
0
        }
1443
0
    }
1444
1445
0
    UA_AnonymousIdentityToken_clear(&anonToken);
1446
0
    UA_UserNameIdentityToken_clear(&userNameToken);
1447
0
    UA_X509IdentityToken_clear(&certToken);
1448
0
    return retval;
1449
0
}
1450
1451
0
PARSE_JSON(UserTokenPolicy) {
1452
0
    UA_Boolean issuedTokenTypeFieldsUsed = false;
1453
1454
0
    UA_UserTokenPolicy *field = (UA_UserTokenPolicy*)configField;
1455
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
1456
0
    cj5_token tok = nextToken(ctx);
1457
0
    for(size_t j = tok.size/2; j > 0; j--) {
1458
0
        tok = nextToken(ctx);
1459
0
        switch (tok.type) {
1460
0
        case CJ5_TOKEN_STRING: {
1461
0
            char *field_str = (char*)UA_malloc(tok.size + 1);
1462
0
            unsigned int str_len = 0;
1463
0
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
1464
0
            if(strcmp(field_str, "policyId") == 0)
1465
0
                retval = StringField_parseJson(ctx, &field->policyId, NULL);
1466
0
            else if(strcmp(field_str, "tokenType") == 0)
1467
0
                retval = UserTokenType_parseJson(ctx, &field->tokenType, NULL);
1468
0
            else if(strcmp(field_str, "issuedTokenType") == 0) {
1469
0
                issuedTokenTypeFieldsUsed = true;
1470
0
                retval = StringField_parseJson(ctx, &field->issuedTokenType, NULL);
1471
0
            }
1472
0
            else if(strcmp(field_str, "issuerEndpointUrl") == 0) {
1473
0
                issuedTokenTypeFieldsUsed = true;
1474
0
                retval = StringField_parseJson(ctx, &field->issuerEndpointUrl, NULL);
1475
0
            }
1476
0
            else if(strcmp(field_str, "securityPolicyUri") == 0)
1477
0
                retval = StringField_parseJson(ctx, &field->securityPolicyUri, NULL);
1478
0
            else {
1479
0
                LOG_UNKNOWN_FIELD(ctx, field_str);
1480
0
            }
1481
0
            UA_free(field_str);
1482
0
            if(retval != UA_STATUSCODE_GOOD) {
1483
0
                return retval;
1484
0
            }
1485
0
            break;
1486
0
        }
1487
0
        default:
1488
0
            break;
1489
0
        }
1490
0
    }
1491
0
    if(issuedTokenTypeFieldsUsed && field->tokenType != UA_USERTOKENTYPE_ISSUEDTOKEN) {
1492
0
        UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION,
1493
0
                    "Fields 'issuedTokenType' and 'issuerEndpointUrl' can only be used if tokenType is 'IssuedToken'.");
1494
0
        return UA_STATUSCODE_BAD;
1495
0
    }
1496
1497
0
    return UA_STATUSCODE_GOOD;
1498
0
}
1499
1500
0
PARSE_JSON(UserTokenPolicyArrayField) {
1501
0
    if(configFieldSize == NULL) {
1502
0
        UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Pointer to the array size is not set.");
1503
0
        return UA_STATUSCODE_BADARGUMENTSMISSING;
1504
0
    }
1505
0
    cj5_token tok = nextToken(ctx);
1506
0
    UA_UserTokenPolicy *policyArray = (UA_UserTokenPolicy*)UA_malloc(sizeof(UA_UserTokenPolicy) * tok.size);
1507
0
    size_t policyArraySize = 0;
1508
0
    for(size_t j = tok.size; j > 0; j--) {
1509
        /* initialize element to zeros so clear functions are safe */
1510
0
        memset(&policyArray[policyArraySize], 0, sizeof(UA_UserTokenPolicy));
1511
0
        UA_StatusCode retval = UserTokenPolicy_parseJson(ctx, &policyArray[policyArraySize], NULL);
1512
0
        if(retval != UA_STATUSCODE_GOOD) {
1513
0
            UA_Array_delete(policyArray, policyArraySize, &UA_TYPES[UA_TYPES_USERTOKENPOLICY]);
1514
0
            return retval;
1515
0
        }
1516
0
        policyArraySize++;
1517
0
    }
1518
    /* Add to the config */
1519
0
    UA_UserTokenPolicy **field = (UA_UserTokenPolicy**)configField;
1520
0
    if(*configFieldSize > 0) {
1521
0
        UA_Array_delete(*field, *configFieldSize,
1522
0
                        &UA_TYPES[UA_TYPES_USERTOKENPOLICY]);
1523
0
        *field = NULL;
1524
0
        *configFieldSize = 0;
1525
0
    }
1526
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
1527
0
    if(policyArraySize > 0) {
1528
0
        retval = UA_Array_copy(policyArray, policyArraySize,
1529
0
                               (void **)field, &UA_TYPES[UA_TYPES_USERTOKENPOLICY]);
1530
0
        *configFieldSize = policyArraySize;
1531
0
    }
1532
1533
    /* Clean up */
1534
0
    UA_Array_delete(policyArray, policyArraySize, &UA_TYPES[UA_TYPES_USERTOKENPOLICY]);
1535
0
    return retval;
1536
0
}
1537
1538
1539
0
PARSE_JSON(EndpointDescription) {
1540
0
    UA_EndpointDescription *field = (UA_EndpointDescription*)configField;
1541
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
1542
0
    cj5_token tok = nextToken(ctx);
1543
0
    for(size_t j = tok.size/2; j > 0; j--) {
1544
0
        tok = nextToken(ctx);
1545
0
        switch (tok.type) {
1546
0
        case CJ5_TOKEN_STRING: {
1547
0
            char *field_str = (char*)UA_malloc(tok.size + 1);
1548
0
            unsigned int str_len = 0;
1549
0
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
1550
0
            if(strcmp(field_str, "endpointUrl") == 0)
1551
0
                retval = StringField_parseJson(ctx, &field->endpointUrl, NULL);
1552
0
            else if(strcmp(field_str, "server") == 0)
1553
0
                retval = GenericApplicationDescriptionField_parseJson(ctx, &field->server, NULL, GENERICAPPLICATIONTYPE_ANY);
1554
0
            else if(strcmp(field_str, "serverCertificate") == 0)
1555
0
                retval = CertificateFileField_parseJson(ctx, &field->serverCertificate, NULL);
1556
0
            else if(strcmp(field_str, "securityMode") == 0)
1557
0
                retval = MessageSecurityMode_parseJson(ctx, &field->securityMode, NULL);
1558
0
            else if(strcmp(field_str, "securityPolicyUri") == 0)
1559
0
                retval = StringField_parseJson(ctx, &field->securityPolicyUri, NULL);
1560
0
            else if(strcmp(field_str, "userIdentityTokens") == 0)
1561
0
                retval = UserTokenPolicyArrayField_parseJson(ctx, &field->userIdentityTokens, &field->userIdentityTokensSize);
1562
0
            else if(strcmp(field_str, "transportProfileUri") == 0)
1563
0
                retval = StringField_parseJson(ctx, &field->transportProfileUri, NULL);
1564
0
            else if(strcmp(field_str, "securityLevel") == 0)
1565
0
                retval = ByteField_parseJson(ctx, &field->securityLevel, NULL);
1566
0
            else {
1567
0
                LOG_UNKNOWN_FIELD(ctx, field_str);
1568
0
            }
1569
0
            UA_free(field_str);
1570
0
            if(retval != UA_STATUSCODE_GOOD) {
1571
0
                return retval;
1572
0
            }
1573
0
            break;
1574
0
        }
1575
0
        default:
1576
0
            break;
1577
0
        }
1578
0
    }
1579
0
    return UA_STATUSCODE_GOOD;
1580
0
}
1581
1582
static UA_StatusCode
1583
0
parseJSONClientConfig(UA_ClientConfig *config, UA_ByteString json_config) {
1584
    // Parsing json config
1585
0
    const char *json = (const char*)json_config.data;
1586
0
    cj5_token tokens[MAX_TOKENS];
1587
0
    cj5_result r = cj5_parse(json, (unsigned int)json_config.length, tokens, MAX_TOKENS, NULL);
1588
1589
0
    if(r.error != CJ5_ERROR_NONE || r.num_tokens < 2 ||
1590
0
       r.tokens[0].type != CJ5_TOKEN_OBJECT)
1591
0
        return UA_STATUSCODE_BADDECODINGERROR;
1592
1593
0
    ParsingCtx ctx;
1594
0
    ctx.json = json;
1595
0
    ctx.result = r;
1596
0
    ctx.index = 1; // The first token is ignored because it is known and not needed.
1597
1598
0
    ctx.logging = config->logging;
1599
1600
0
    size_t clientConfigSize = 0;
1601
0
    if(ctx.result.tokens)
1602
0
        clientConfigSize = (ctx.result.tokens[ctx.index-1].size/2);
1603
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
1604
0
    for (size_t j = clientConfigSize; j > 0 && ctx.index < ctx.result.num_tokens; j--) {
1605
0
        cj5_token tok = ctx.result.tokens[ctx.index];
1606
0
        switch (tok.type) {
1607
0
            case CJ5_TOKEN_STRING: {
1608
0
                char *field = (char*)UA_malloc(tok.size + 1);
1609
0
                unsigned int str_len = 0;
1610
0
                cj5_get_str(&ctx.result, (unsigned int)ctx.index, field, &str_len);
1611
0
                if(strcmp(field, "timeout") == 0)
1612
0
                    retval = Int32Field_parseJson(&ctx, &config->timeout, NULL);
1613
0
                else if(strcmp(field, "applicationDescription") == 0)
1614
0
                    retval = GenericApplicationDescriptionField_parseJson(&ctx, &config->clientDescription, NULL, GENERICAPPLICATIONTYPE_CLIENT);
1615
0
                else if(strcmp(field, "endpointUrl") == 0)
1616
0
                    retval = StringField_parseJson(&ctx, &config->endpointUrl, NULL);
1617
0
                else if (strcmp(field, "userIdentityToken") == 0)
1618
0
                    retval = UserIdentityToken_parseJson(&ctx, &config->userIdentityToken, NULL);
1619
0
                else if(strcmp(field, "sessionName") == 0)
1620
0
                    retval = StringField_parseJson(&ctx, &config->sessionName, NULL);
1621
0
                else if(strcmp(field, "sessionLocaleIds") == 0)
1622
                    /* UA_LocaleId is an alias of UA_String */
1623
0
                    retval = StringArrayField_parseJson(&ctx, &config->sessionLocaleIds, &config->sessionLocaleIdsSize);
1624
0
                else if(strcmp(field, "noSession") == 0)
1625
0
                    retval = BooleanField_parseJson(&ctx, &config->noSession, NULL);
1626
0
                else if(strcmp(field, "noReconnect") == 0)
1627
0
                    retval = BooleanField_parseJson(&ctx, &config->noReconnect, NULL);
1628
0
                else if(strcmp(field, "noNewSession") == 0)
1629
0
                    retval = BooleanField_parseJson(&ctx, &config->noNewSession, NULL);
1630
0
                else if(strcmp(field, "secureChannelLifeTime") == 0)
1631
0
                    retval = UInt32Field_parseJson(&ctx, &config->secureChannelLifeTime, NULL);
1632
0
                else if(strcmp(field, "requestedSessionTimeout") == 0)
1633
0
                    retval = UInt32Field_parseJson(&ctx, &config->requestedSessionTimeout, NULL);
1634
0
                else if(strcmp(field, "localConnectionConfig") == 0)
1635
0
                    retval = ConnectionConfig_parseJson(&ctx, &config->localConnectionConfig, NULL);
1636
0
                else if(strcmp(field, "connectivityCheckInterval") == 0)
1637
0
                    retval = UInt32Field_parseJson(&ctx, &config->connectivityCheckInterval, NULL);
1638
0
                else if(strcmp(field, "maxAsyncServiceCalls") == 0)
1639
0
                    retval = UInt32Field_parseJson(&ctx, &config->maxAsyncServiceCalls, NULL);
1640
0
                else if(strcmp(field, "asyncServiceCallRule") == 0)
1641
0
                    retval = RuleHandlingField_parseJson(&ctx, &config->asyncServiceCallRule, NULL);
1642
0
                else if(strcmp(field, "tcpReuseAddr") == 0)
1643
0
                    retval = BooleanField_parseJson(&ctx, &config->tcpReuseAddr, NULL);
1644
#ifdef UA_ENABLE_LWS
1645
                else if(strcmp(field, "webSocketMaxQueueSize") == 0)
1646
                    retval = UInt32Field_parseJson(
1647
                        &ctx, &config->webSocketMaxQueueSize, NULL);
1648
                else if(strcmp(field, "webSocketCaCertificate") == 0) {
1649
                    UA_ByteString_clear(&config->webSocketCaCertificate);
1650
                    retval = CertificateFileField_parseJson(
1651
                        &ctx, &config->webSocketCaCertificate, NULL);
1652
                }
1653
#endif
1654
0
                else if(strcmp(field, "endpoint") == 0)
1655
0
                    retval = EndpointDescription_parseJson(&ctx, &config->endpoint, NULL);
1656
0
                else if(strcmp(field, "userTokenPolicy") == 0)
1657
0
                    retval = UserTokenPolicy_parseJson(&ctx, &config->userTokenPolicy, NULL);
1658
0
                else if(strcmp(field, "applicationUri") == 0)
1659
0
                    retval = StringField_parseJson(&ctx, &config->applicationUri, NULL);
1660
0
                else if(strcmp(field, "securityMode") == 0)
1661
0
                    retval = MessageSecurityMode_parseJson(&ctx, &config->securityMode, NULL);
1662
0
                else if(strcmp(field, "securityPolicyUri") == 0)
1663
0
                    retval = StringField_parseJson(&ctx, &config->securityPolicyUri, NULL);
1664
0
                else if(strcmp(field, "authSecurityPolicyUri") == 0)
1665
0
                    retval = StringField_parseJson(&ctx, &config->authSecurityPolicyUri, NULL);
1666
0
                else if(strcmp(field, "securityPolicies") == 0)
1667
0
                    retval = SecurityPoliciesField_parseJson(&ctx, &config->securityPolicies, &config->securityPoliciesSize, UA_APPLICATIONTYPE_CLIENT, config->logging);
1668
0
                else if(strcmp(field, "authSecurityPolicies") == 0)
1669
0
                    retval = SecurityPoliciesField_parseJson(&ctx, &config->authSecurityPolicies, &config->authSecurityPoliciesSize, UA_APPLICATIONTYPE_CLIENT, config->logging);
1670
0
                else if(strcmp(field, "allowNonePolicyPassword") == 0)
1671
0
                    retval = BooleanField_parseJson(&ctx, &config->allowNonePolicyPassword, NULL);
1672
0
#ifdef UA_ENABLE_ENCRYPTION
1673
0
                else if(strcmp(field, "maxTrustListSize") == 0)
1674
0
                    retval = UInt32Field_parseJson(&ctx, &config->maxTrustListSize, NULL);
1675
0
                else if(strcmp(field, "maxRejectedListSize") == 0)
1676
0
                    retval = UInt32Field_parseJson(&ctx, &config->maxRejectedListSize, NULL);
1677
0
#endif
1678
0
                else if(strcmp(field, "namespaces") == 0)
1679
0
                    retval = StringArrayField_parseJson(&ctx, &config->namespaces, &config->namespacesSize);
1680
0
                else if(strcmp(field, "outStandingPublishRequests") == 0)
1681
0
                    retval = UInt16Field_parseJson(&ctx, &config->outStandingPublishRequests, NULL);
1682
0
                else {
1683
0
                    UA_LOG_WARNING(ctx.logging, UA_LOGCATEGORY_APPLICATION,
1684
0
                                   "Field name '%s' unknown or misspelled. Maybe the feature is not enabled either.", field);
1685
                    /* skip the name of item */
1686
0
                    ++ctx.index;
1687
                    /* skip value of unknown item */
1688
0
                    skipUnknownItem(&ctx);
1689
                    /* after skipUnknownItem() ctx->index points to the name of the following item.
1690
                       We must decrement index in oder following increment will
1691
                       still set index to the right position (name of the following item) */
1692
0
                    --ctx.index;
1693
0
                }
1694
0
                UA_free(field);
1695
0
                if(retval != UA_STATUSCODE_GOOD) {
1696
0
                    UA_LOG_ERROR(ctx.logging, UA_LOGCATEGORY_APPLICATION, "An error occurred while parsing the configuration file.");
1697
0
                    return retval;
1698
0
                }
1699
0
                break;
1700
0
            }
1701
0
            default:
1702
0
                break;
1703
0
        }
1704
0
        ctx.index += 1;
1705
0
    }
1706
0
    return retval;
1707
0
}
1708
1709
UA_Client *
1710
UA_Client_newFromFile(const UA_ByteString jsonConfig)
1711
0
{
1712
0
    UA_ClientConfig config;
1713
0
    UA_StatusCode res = UA_ClientConfig_loadFromFile(&config, jsonConfig);
1714
0
    if(res != UA_STATUSCODE_GOOD)
1715
0
        return NULL;
1716
0
    return UA_Client_newWithConfig(&config);
1717
0
}
1718
1719
UA_StatusCode
1720
UA_ClientConfig_loadFromFile(UA_ClientConfig *config, const UA_ByteString jsonConfig)
1721
0
{
1722
0
    memset(config, 0, sizeof(UA_ClientConfig));
1723
0
    UA_StatusCode res = UA_ClientConfig_setDefault(config);
1724
0
    if (res == UA_STATUSCODE_GOOD) {
1725
0
        res = parseJSONClientConfig(config, jsonConfig);
1726
0
        if (UA_StatusCode_isBad(res)) {
1727
0
            UA_ClientConfig_clear(config);
1728
0
        }
1729
0
    }
1730
0
    return res;
1731
0
}
1732
1733
#if defined(UA_ENABLE_ENCRYPTION) || defined(UA_ENABLE_LWS)
1734
static UA_ByteString
1735
0
loadCertificateFile(const char *const path) {
1736
0
    UA_ByteString fileContents = UA_BYTESTRING_NULL;
1737
1738
    /* Open the file */
1739
0
    FILE *fp = fopen(path, "rb");
1740
0
    if(!fp) {
1741
0
        errno = 0; /* We read errno also from the tcp layer... */
1742
0
        return fileContents;
1743
0
    }
1744
1745
    /* Get the file length, allocate the data and read */
1746
0
    if(fseek(fp, 0, SEEK_END) != 0) {
1747
0
        fclose(fp);
1748
0
        errno = 0;
1749
0
        return fileContents;
1750
0
    }
1751
1752
0
    long length = ftell(fp);
1753
0
    if(length < 0) {
1754
0
        fclose(fp);
1755
0
        errno = 0;
1756
0
        return fileContents;
1757
0
    }
1758
1759
0
    fileContents.length = (size_t)length;
1760
0
    fileContents.data = (UA_Byte *)UA_malloc(fileContents.length * sizeof(UA_Byte));
1761
0
    if(fileContents.data) {
1762
0
        if(fseek(fp, 0, SEEK_SET) != 0) {
1763
0
            fclose(fp);
1764
0
            UA_ByteString_clear(&fileContents);
1765
0
            errno = 0;
1766
0
            return fileContents;
1767
0
        }
1768
0
        size_t read = fread(fileContents.data, sizeof(UA_Byte), fileContents.length, fp);
1769
0
        if(read != fileContents.length)
1770
0
            UA_ByteString_clear(&fileContents);
1771
0
    } else {
1772
0
        fileContents.length = 0;
1773
0
    }
1774
0
    fclose(fp);
1775
1776
0
    return fileContents;
1777
0
}
1778
#endif