Coverage Report

Created: 2026-10-03 06:33

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