Coverage Report

Created: 2026-08-31 06:58

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
0
#define MAX_TOKENS 1024
24
25
#define LOG_UNKNOWN_FIELD(ctx, field) \
26
0
    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
0
getJsonPart(cj5_token tok, const char *json) {
39
0
    UA_ByteString bs;
40
0
    UA_ByteString_init(&bs);
41
0
    if(tok.type == CJ5_TOKEN_STRING) {
42
0
        bs.data = (UA_Byte*)(uintptr_t)(json + tok.start - 1);
43
0
        bs.length = (tok.end - tok.start) + 3;
44
0
        return bs;
45
0
    } else {
46
0
        bs.data = (UA_Byte*)(uintptr_t)(json + tok.start);
47
0
        bs.length = (tok.end - tok.start) + 1;
48
0
        return bs;
49
0
    }
50
0
}
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
0
nextToken(ParsingCtx *ctx) {
56
0
    if(!ctx->result.tokens || ctx->index + 1 >= ctx->result.num_tokens) {
57
0
        ctx->index = ctx->result.num_tokens;
58
0
        cj5_token empty;
59
0
        memset(&empty, 0, sizeof(empty));
60
0
        return empty;
61
0
    }
62
0
    ctx->index++;
63
0
    return ctx->result.tokens[ctx->index];
64
0
}
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
0
PARSE_JSON(UInt16Field) {
102
0
    cj5_token tok = nextToken(ctx);
103
0
    UA_ByteString buf = getJsonPart(tok, ctx->json);
104
0
    UA_UInt16 out;
105
0
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_UINT16], NULL);
106
0
    if(retval != UA_STATUSCODE_GOOD)
107
0
        return retval;
108
0
    UA_UInt16 *field = (UA_UInt16*)configField;
109
0
    *field = out;
110
0
    return retval;
111
0
}
112
0
PARSE_JSON(UInt32Field) {
113
0
    cj5_token tok = nextToken(ctx);
114
0
    UA_ByteString buf = getJsonPart(tok, ctx->json);
115
0
    UA_UInt32 out;
116
0
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_UINT32], NULL);
117
0
    if(retval != UA_STATUSCODE_GOOD)
118
0
        return retval;
119
0
    UA_UInt32 *field = (UA_UInt32*)configField;
120
0
    *field = out;
121
0
    return retval;
122
0
}
123
0
PARSE_JSON(UInt64Field) {
124
0
    cj5_token tok = nextToken(ctx);
125
0
    UA_ByteString buf = getJsonPart(tok, ctx->json);
126
0
    UA_UInt64 out;
127
0
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_UINT64], NULL);
128
0
    if(retval != UA_STATUSCODE_GOOD)
129
0
        return retval;
130
0
    UA_UInt64 *field = (UA_UInt64*)configField;
131
0
    *field = out;
132
0
    return retval;
133
0
}
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
0
PARSE_JSON(StringField) {
146
0
    cj5_token tok = nextToken(ctx);
147
0
    UA_ByteString buf = getJsonPart(tok, ctx->json);
148
0
    UA_String out;
149
0
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_STRING], NULL);
150
0
    if(retval != UA_STATUSCODE_GOOD)
151
0
        return retval;
152
0
    UA_String *field = (UA_String*)configField;
153
0
    if(field != NULL) {
154
0
        UA_String_clear(field);
155
0
        *field = out;
156
0
    }
157
0
    return retval;
158
0
}
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
0
PARSE_JSON(LocalizedTextField) {
171
    /*
172
     applicationName: {
173
        locale: "de-DE",
174
        text: "Test text"
175
    }
176
     */
177
0
    cj5_token tok = nextToken(ctx);
178
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
179
0
    UA_String locale = {.length = 0, .data = NULL};
180
0
    UA_String text = {.length = 0, .data = NULL};
181
0
    for(size_t j = tok.size/2; j > 0; j--) {
182
0
        tok = nextToken(ctx);
183
0
        switch (tok.type) {
184
0
        case CJ5_TOKEN_STRING: {
185
0
            char *field = (char*)UA_malloc(tok.size + 1);
186
0
            unsigned int str_len = 0;
187
0
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field, &str_len);
188
189
0
            tok = nextToken(ctx);
190
0
            UA_ByteString buf = getJsonPart(tok, ctx->json);
191
0
            if(strcmp(field, "locale") == 0)
192
0
                retval |= UA_decodeJson(&buf, &locale, &UA_TYPES[UA_TYPES_STRING], NULL);
193
0
            else if(strcmp(field, "text") == 0)
194
0
                retval |= UA_decodeJson(&buf, &text, &UA_TYPES[UA_TYPES_STRING], NULL);
195
0
            else {
196
0
                LOG_UNKNOWN_FIELD(ctx, field);
197
0
            }
198
0
            UA_free(field);
199
0
            break;
200
0
        }
201
0
        default:
202
0
            break;
203
0
        }
204
0
    }
205
0
    UA_LocalizedText out;
206
0
    out.locale = locale;
207
0
    out.text = text;
208
0
    if(retval != UA_STATUSCODE_GOOD)
209
0
        return retval;
210
0
    UA_LocalizedText *field = (UA_LocalizedText*)configField;
211
0
    if(field != NULL) {
212
0
        UA_LocalizedText_clear(field);
213
0
        *field = out;
214
0
    }
215
0
    return retval;
216
0
}
217
0
PARSE_JSON(DoubleField) {
218
0
    cj5_token tok = nextToken(ctx);
219
0
    UA_ByteString buf = getJsonPart(tok, ctx->json);
220
0
    UA_Double out;
221
0
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_DOUBLE], NULL);
222
0
    if(retval != UA_STATUSCODE_GOOD)
223
0
        return retval;
224
0
    UA_Double *field = (UA_Double *)configField;
225
0
    *field = out;
226
0
    return retval;
227
0
}
228
0
PARSE_JSON(BooleanField) {
229
0
    cj5_token tok = nextToken(ctx);
230
0
    UA_ByteString buf = getJsonPart(tok, ctx->json);
231
0
    UA_Boolean out;
232
0
    if(tok.type != CJ5_TOKEN_BOOL) {
233
0
        UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Value of type bool expected.");
234
0
        return UA_STATUSCODE_BADTYPEMISMATCH;
235
0
    }
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
0
}
247
#ifdef UA_ENABLE_SUBSCRIPTIONS
248
0
PARSE_JSON(DurationField) {
249
0
    UA_Double double_value;
250
0
    UA_StatusCode retval = DoubleField_parseJson(ctx, &double_value, NULL);
251
0
    if(retval != UA_STATUSCODE_GOOD)
252
0
        return retval;
253
0
    UA_Duration *field = (UA_Duration*)configField;
254
0
    *field = (UA_Duration)double_value;
255
0
    return retval;
256
0
}
257
0
PARSE_JSON(DurationRangeField) {
258
0
    UA_DurationRange *field = (UA_DurationRange*)configField;
259
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
260
0
    cj5_token tok = nextToken(ctx);
261
0
    for(size_t j = tok.size/2; j > 0; j--) {
262
0
        tok = nextToken(ctx);
263
0
        switch (tok.type) {
264
0
        case CJ5_TOKEN_STRING: {
265
0
            char *field_str = (char*)UA_malloc(tok.size + 1);
266
0
            unsigned int str_len = 0;
267
0
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
268
0
            if(strcmp(field_str, "min") == 0)
269
0
                retval = DurationField_parseJson(ctx, &field->min, NULL);
270
0
            else if(strcmp(field_str, "max") == 0)
271
0
                retval = DurationField_parseJson(ctx, &field->max, NULL);
272
0
            else {
273
0
                LOG_UNKNOWN_FIELD(ctx, field_str);
274
0
            }
275
0
            UA_free(field_str);
276
0
            if(retval != UA_STATUSCODE_GOOD) {
277
0
                return retval;
278
0
            }
279
0
            break;
280
0
        }
281
0
        default:
282
0
            break;
283
0
        }
284
0
    }
285
0
    return UA_STATUSCODE_GOOD;
286
0
}
287
0
PARSE_JSON(UInt32RangeField) {
288
0
    UA_UInt32Range *field = (UA_UInt32Range*)configField;
289
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
290
0
    cj5_token tok = nextToken(ctx);
291
0
    for(size_t j = tok.size/2; j > 0; j--) {
292
0
        tok = nextToken(ctx);
293
0
        switch (tok.type) {
294
0
        case CJ5_TOKEN_STRING: {
295
0
            char *field_str = (char*)UA_malloc(tok.size + 1);
296
0
            unsigned int str_len = 0;
297
0
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
298
0
            if(strcmp(field_str, "min") == 0)
299
0
                retval = UInt32Field_parseJson(ctx, &field->min, NULL);
300
0
            else if(strcmp(field_str, "max") == 0)
301
0
                retval = UInt32Field_parseJson(ctx, &field->max, NULL);
302
0
            else {
303
0
                LOG_UNKNOWN_FIELD(ctx, field_str);
304
0
            }
305
0
            UA_free(field_str);
306
0
            if(retval != UA_STATUSCODE_GOOD) {
307
0
                return retval;
308
0
            }
309
0
            break;
310
0
        }
311
0
        default:
312
0
            break;
313
0
        }
314
0
    }
315
0
    return UA_STATUSCODE_GOOD;
316
0
}
317
#endif
318
319
/*----------------------Advanced Types------------------------*/
320
0
PARSE_JSON(StringArrayField) {
321
0
    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
0
    cj5_token tok = nextToken(ctx);
326
0
    UA_String *stringArray = (UA_String*)UA_malloc(sizeof(UA_String) * tok.size);
327
0
    size_t stringArraySize = 0;
328
0
    for(size_t j = tok.size; j > 0; j--) {
329
0
        UA_String out = {.length = 0, .data = NULL};
330
0
        UA_StatusCode retval = StringField_parseJson(ctx, &out, NULL);
331
0
        if(retval != UA_STATUSCODE_GOOD) {
332
0
            UA_String_clear(&out);
333
0
            UA_Array_delete(stringArray, stringArraySize, &UA_TYPES[UA_TYPES_STRING]);
334
0
            return retval;
335
0
        }
336
0
        UA_String_copy(&out, &stringArray[stringArraySize++]);
337
0
        UA_String_clear(&out);
338
0
    }
339
    /* Add to the config */
340
0
    UA_String **field = (UA_String**)configField;
341
0
    if(*configFieldSize > 0) {
342
0
        UA_Array_delete(*field, *configFieldSize,
343
0
                        &UA_TYPES[UA_TYPES_STRING]);
344
0
        *field = NULL;
345
0
        *configFieldSize = 0;
346
0
    }
347
0
    UA_StatusCode retval =
348
0
        UA_Array_copy(stringArray, stringArraySize,
349
0
                      (void**)field, &UA_TYPES[UA_TYPES_STRING]);
350
0
    *configFieldSize = stringArraySize;
351
352
    /* Clean up */
353
0
    UA_Array_delete(stringArray, stringArraySize, &UA_TYPES[UA_TYPES_STRING]);
354
0
    return retval;
355
0
}
356
0
PARSE_JSON(DateTimeField) {
357
0
    cj5_token tok = nextToken(ctx);
358
0
    UA_ByteString buf = getJsonPart(tok, ctx->json);
359
0
    UA_DateTime out;
360
0
    UA_DateTime_init(&out);
361
0
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_DATETIME], NULL);
362
0
    if(retval != UA_STATUSCODE_GOOD)
363
0
        return retval;
364
0
    UA_DateTime *field = (UA_DateTime*)configField;
365
0
    *field = out;
366
0
    return retval;
367
0
}
368
0
PARSE_JSON(BuildInfo) {
369
0
    UA_BuildInfo *field = (UA_BuildInfo*)configField;
370
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
371
0
    cj5_token tok = nextToken(ctx);
372
0
    for(size_t j = tok.size/2; j > 0; j--) {
373
0
        tok = nextToken(ctx);
374
0
        switch (tok.type) {
375
0
        case CJ5_TOKEN_STRING: {
376
0
            char *field_str = (char*)UA_malloc(tok.size + 1);
377
0
            unsigned int str_len = 0;
378
0
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
379
0
            if(strcmp(field_str, "productUri") == 0)
380
0
                retval = StringField_parseJson(ctx, &field->productUri, NULL);
381
0
            else if(strcmp(field_str, "manufacturerName") == 0)
382
0
                retval = StringField_parseJson(ctx, &field->manufacturerName, NULL);
383
0
            else if(strcmp(field_str, "productName") == 0)
384
0
                retval = StringField_parseJson(ctx, &field->productName, NULL);
385
0
            else if(strcmp(field_str, "softwareVersion") == 0)
386
0
                retval = StringField_parseJson(ctx, &field->softwareVersion, NULL);
387
0
            else if(strcmp(field_str, "buildNumber") == 0)
388
0
                retval = StringField_parseJson(ctx, &field->buildNumber, NULL);
389
0
            else if(strcmp(field_str, "buildDate") == 0)
390
0
                retval = DateTimeField_parseJson(ctx, &field->buildDate, NULL);
391
0
            else {
392
0
                LOG_UNKNOWN_FIELD(ctx, field_str);
393
0
            }
394
0
            UA_free(field_str);
395
0
            if(retval != UA_STATUSCODE_GOOD) {
396
0
                return retval;
397
0
            }
398
0
            break;
399
0
        }
400
0
        default:
401
0
            break;
402
0
        }
403
0
    }
404
0
    return UA_STATUSCODE_GOOD;
405
0
}
406
407
0
PARSE_JSON(ApplicationTypeField) {
408
0
    cj5_token tok = nextToken(ctx);
409
0
    UA_ByteString rawToken = getJsonPart(tok, ctx->json);
410
0
    UA_ApplicationType *field = (UA_ApplicationType*)configField;
411
0
    char *fieldStr = (char*)UA_malloc(tok.size + 1);
412
0
    unsigned int strLen = 0;
413
414
0
    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
0
    UA_free(fieldStr);
433
434
    /* Try numeric fallback */
435
0
    UA_UInt32 enumValue;
436
0
    UA_StatusCode retval = UA_decodeJson(&rawToken, &enumValue, &UA_TYPES[UA_TYPES_UINT32], NULL);
437
0
    if(retval != UA_STATUSCODE_GOOD) {
438
0
        UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION,
439
0
                    "Unknown ApplicationType '%S'", rawToken);
440
0
        return retval;
441
0
    }
442
0
    *field = (UA_ApplicationType)enumValue;
443
0
    return UA_STATUSCODE_GOOD;
444
0
}
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
0
{
455
0
    UA_ApplicationDescription *field = (UA_ApplicationDescription*)configField;
456
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
457
0
    cj5_token tok = nextToken(ctx);
458
0
    for(size_t j = tok.size/2; j > 0; j--) {
459
0
        tok = nextToken(ctx);
460
0
        switch (tok.type) {
461
0
        case CJ5_TOKEN_STRING: {
462
0
            char *field_str = (char*)UA_malloc(tok.size + 1);
463
0
            unsigned int str_len = 0;
464
0
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
465
0
            if(strcmp(field_str, "applicationUri") == 0)
466
0
                retval = StringField_parseJson(ctx, &field->applicationUri, NULL);
467
0
            else if(strcmp(field_str, "productUri") == 0)
468
0
                retval = StringField_parseJson(ctx, &field->productUri, NULL);
469
0
            else if(strcmp(field_str, "applicationName") == 0)
470
0
                retval = LocalizedTextField_parseJson(ctx, &field->applicationName, NULL);
471
0
            else if(strcmp(field_str, "applicationType") == 0 &&
472
0
                    type != GENERICAPPLICATIONTYPE_CLIENT) {
473
0
                retval = ApplicationTypeField_parseJson(ctx, &field->applicationType, NULL);
474
0
            }
475
0
            else if(strcmp(field_str, "gatewayServerUri") == 0 &&
476
0
                    type != GENERICAPPLICATIONTYPE_CLIENT)
477
0
                retval = StringField_parseJson(ctx, &field->gatewayServerUri, NULL);
478
0
            else if(strcmp(field_str, "discoveryProfileUri") == 0 &&
479
0
                    type != GENERICAPPLICATIONTYPE_CLIENT)
480
0
                retval = StringField_parseJson(ctx, &field->discoveryProfileUri, NULL);
481
0
            else if(strcmp(field_str, "discoveryUrls") == 0)
482
0
                retval = StringArrayField_parseJson(ctx, &field->discoveryUrls, &field->discoveryUrlsSize);
483
0
            else {
484
0
                LOG_UNKNOWN_FIELD(ctx, field_str);
485
0
            }
486
0
            UA_free(field_str);
487
0
            if(retval != UA_STATUSCODE_GOOD) {
488
0
                return retval;
489
0
            }
490
0
            break;
491
0
        }
492
0
        default:
493
0
            break;
494
0
        }
495
0
    }
496
0
    if(type == GENERICAPPLICATIONTYPE_CLIENT) {
497
0
        field->applicationType = UA_APPLICATIONTYPE_CLIENT;
498
0
        field->discoveryUrlsSize = 0;
499
0
        field->discoveryUrls = NULL;
500
0
    }
501
0
    return UA_STATUSCODE_GOOD;
502
0
}
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
0
PARSE_JSON(SubscriptionConfigurationField) {
545
0
    UA_ServerConfig *config = (UA_ServerConfig*)configField;
546
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
547
0
    cj5_token tok = nextToken(ctx);
548
0
    for(size_t j = tok.size/2; j > 0; j--) {
549
0
        tok = nextToken(ctx);
550
0
        switch (tok.type) {
551
0
        case CJ5_TOKEN_STRING: {
552
0
            char *field_str = (char*)UA_malloc(tok.size + 1);
553
0
            unsigned int str_len = 0;
554
0
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
555
0
            if(strcmp(field_str, "maxSubscriptions") == 0)
556
0
                retval = UInt32Field_parseJson(ctx, &config->maxSubscriptions, NULL);
557
0
            else if(strcmp(field_str, "maxSubscriptionsPerSession") == 0)
558
0
                retval = UInt32Field_parseJson(ctx, &config->maxSubscriptionsPerSession, NULL);
559
0
            else if(strcmp(field_str, "publishingIntervalLimits") == 0)
560
0
                retval = DurationRangeField_parseJson(ctx, &config->publishingIntervalLimits, NULL);
561
0
            else if(strcmp(field_str, "lifeTimeCountLimits") == 0)
562
0
                retval = UInt32RangeField_parseJson(ctx, &config->lifeTimeCountLimits, NULL);
563
0
            else if(strcmp(field_str, "keepAliveCountLimits") == 0)
564
0
                retval = UInt32RangeField_parseJson(ctx, &config->keepAliveCountLimits, NULL);
565
0
            else if(strcmp(field_str, "maxNotificationsPerPublish") == 0)
566
0
                retval = UInt32Field_parseJson(ctx, &config->maxNotificationsPerPublish, NULL);
567
0
            else if(strcmp(field_str, "enableRetransmissionQueue") == 0)
568
0
                retval = BooleanField_parseJson(ctx, &config->enableRetransmissionQueue, NULL);
569
0
            else if(strcmp(field_str, "maxRetransmissionQueueSize") == 0)
570
0
                retval = UInt32Field_parseJson(ctx, &config->maxRetransmissionQueueSize, NULL);
571
0
# ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
572
0
            else if(strcmp(field_str, "maxEventsPerNode") == 0)
573
0
                retval = UInt32Field_parseJson(ctx, &config->maxEventsPerNode, NULL);
574
0
# endif
575
0
            else if(strcmp(field_str, "maxMonitoredItems") == 0)
576
0
                retval = UInt32Field_parseJson(ctx, &config->maxMonitoredItems, NULL);
577
0
            else if(strcmp(field_str, "maxMonitoredItemsPerSubscription") == 0)
578
0
                retval = UInt32Field_parseJson(ctx, &config->maxMonitoredItemsPerSubscription, NULL);
579
0
            else if(strcmp(field_str, "samplingIntervalLimits") == 0)
580
0
                retval = DurationRangeField_parseJson(ctx, &config->samplingIntervalLimits, NULL);
581
0
            else if(strcmp(field_str, "queueSizeLimits") == 0)
582
0
                retval = UInt32RangeField_parseJson(ctx, &config->queueSizeLimits, NULL);
583
0
            else if(strcmp(field_str, "maxPublishReqPerSession") == 0)
584
0
                retval = UInt32Field_parseJson(ctx, &config->maxPublishReqPerSession, NULL);
585
0
            else {
586
0
                LOG_UNKNOWN_FIELD(ctx, field_str);
587
0
            }
588
0
            UA_free(field_str);
589
0
            if(retval != UA_STATUSCODE_GOOD) {
590
0
                return retval;
591
0
            }
592
0
            break;
593
0
        }
594
0
        default:
595
0
            break;
596
0
        }
597
0
    }
598
0
    return UA_STATUSCODE_GOOD;
599
0
}
600
#endif
601
602
0
PARSE_JSON(TcpConfigurationField) {
603
0
    UA_ServerConfig *config = (UA_ServerConfig*)configField;
604
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
605
0
    cj5_token tok = nextToken(ctx);
606
0
    for(size_t j = tok.size/2; j > 0; j--) {
607
0
        tok = nextToken(ctx);
608
0
        switch (tok.type) {
609
0
        case CJ5_TOKEN_STRING: {
610
0
            char *field_str = (char*)UA_malloc(tok.size + 1);
611
0
            unsigned int str_len = 0;
612
0
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
613
0
            if(strcmp(field_str, "tcpBufSize") == 0)
614
0
                retval = UInt32Field_parseJson(ctx, &config->tcpBufSize, NULL);
615
0
            else if(strcmp(field_str, "tcpMaxMsgSize") == 0)
616
0
                retval = UInt32Field_parseJson(ctx, &config->tcpMaxMsgSize, NULL);
617
0
            else if(strcmp(field_str, "tcpMaxChunks") == 0)
618
0
                retval = UInt32Field_parseJson(ctx, &config->tcpMaxChunks, NULL);
619
0
            else {
620
0
                LOG_UNKNOWN_FIELD(ctx, field_str);
621
0
            }
622
0
            UA_free(field_str);
623
0
            if(retval != UA_STATUSCODE_GOOD) {
624
0
                return retval;
625
0
            }
626
0
            break;
627
0
        }
628
0
        default:
629
0
            break;
630
0
        }
631
0
    }
632
0
    return UA_STATUSCODE_GOOD;
633
0
}
634
635
#ifdef UA_ENABLE_PUBSUB
636
0
PARSE_JSON(PubsubConfigurationField) {
637
0
    UA_PubSubConfiguration *field = (UA_PubSubConfiguration*)configField;
638
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
639
0
    cj5_token tok = nextToken(ctx);
640
0
    for(size_t j = tok.size/2; j > 0; j--) {
641
0
        tok = nextToken(ctx);
642
0
        switch (tok.type) {
643
0
        case CJ5_TOKEN_STRING: {
644
0
            char *field_str = (char*)UA_malloc(tok.size + 1);
645
0
            unsigned int str_len = 0;
646
0
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
647
0
            if(strcmp(field_str, "enableDeltaFrames") == 0)
648
0
                retval = BooleanField_parseJson(ctx, &field->enableDeltaFrames, NULL);
649
0
#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
650
0
            else if(strcmp(field_str, "enableInformationModelMethods") == 0)
651
0
                retval = BooleanField_parseJson(ctx, &field->enableInformationModelMethods, NULL);
652
0
#endif
653
0
            else {
654
0
                LOG_UNKNOWN_FIELD(ctx, field_str);
655
0
            }
656
0
            UA_free(field_str);
657
0
            if(retval != UA_STATUSCODE_GOOD) {
658
0
                return retval;
659
0
            }
660
0
            break;
661
0
        }
662
0
        default:
663
0
            break;
664
0
        }
665
0
    }
666
0
    return UA_STATUSCODE_GOOD;
667
0
}
668
#endif
669
670
#ifdef UA_ENABLE_HISTORIZING
671
0
PARSE_JSON(HistorizingConfigurationField) {
672
0
    UA_ServerConfig *config = (UA_ServerConfig*)configField;
673
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
674
0
    cj5_token tok = nextToken(ctx);
675
0
    for(size_t j = tok.size/2; j > 0; j--) {
676
0
        tok = nextToken(ctx);
677
0
        switch (tok.type) {
678
0
        case CJ5_TOKEN_STRING: {
679
0
            char *field_str = (char*)UA_malloc(tok.size + 1);
680
0
            unsigned int str_len = 0;
681
0
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
682
0
            if(strcmp(field_str, "accessHistoryDataCapability") == 0)
683
0
                retval = BooleanField_parseJson(ctx, &config->accessHistoryDataCapability, NULL);
684
0
            else if(strcmp(field_str, "maxReturnDataValues") == 0)
685
0
                retval = UInt32Field_parseJson(ctx, &config->maxReturnDataValues, NULL);
686
0
            else if(strcmp(field_str, "accessHistoryEventsCapability") == 0)
687
0
                retval = BooleanField_parseJson(ctx, &config->accessHistoryEventsCapability, NULL);
688
0
            else if(strcmp(field_str, "maxReturnEventValues") == 0)
689
0
                retval = UInt32Field_parseJson(ctx, &config->maxReturnEventValues, NULL);
690
0
            else if(strcmp(field_str, "insertDataCapability") == 0)
691
0
                retval = BooleanField_parseJson(ctx, &config->insertDataCapability, NULL);
692
0
            else if(strcmp(field_str, "insertEventCapability") == 0)
693
0
                retval = BooleanField_parseJson(ctx, &config->insertEventCapability, NULL);
694
0
            else if(strcmp(field_str, "insertAnnotationsCapability") == 0)
695
0
                retval = BooleanField_parseJson(ctx, &config->insertAnnotationsCapability, NULL);
696
0
            else if(strcmp(field_str, "replaceDataCapability") == 0)
697
0
                retval = BooleanField_parseJson(ctx, &config->replaceDataCapability, NULL);
698
0
            else if(strcmp(field_str, "replaceEventCapability") == 0)
699
0
                retval = BooleanField_parseJson(ctx, &config->replaceEventCapability, NULL);
700
0
            else if(strcmp(field_str, "updateDataCapability") == 0)
701
0
                retval = BooleanField_parseJson(ctx, &config->updateDataCapability, NULL);
702
0
            else if(strcmp(field_str, "updateEventCapability") == 0)
703
0
                retval = BooleanField_parseJson(ctx, &config->updateEventCapability, NULL);
704
0
            else if(strcmp(field_str, "deleteRawCapability") == 0)
705
0
                retval = BooleanField_parseJson(ctx, &config->deleteRawCapability, NULL);
706
0
            else if(strcmp(field_str, "deleteEventCapability") == 0)
707
0
                retval = BooleanField_parseJson(ctx, &config->deleteEventCapability, NULL);
708
0
            else if(strcmp(field_str, "deleteAtTimeDataCapability") == 0)
709
0
                retval = BooleanField_parseJson(ctx, &config->deleteAtTimeDataCapability, NULL);
710
0
            else {
711
0
                LOG_UNKNOWN_FIELD(ctx, field_str);
712
0
            }
713
0
            UA_free(field_str);
714
0
            if(retval != UA_STATUSCODE_GOOD) {
715
0
                return retval;
716
0
            }
717
0
            break;
718
0
        }
719
0
        default:
720
0
            break;
721
0
        }
722
0
    }
723
0
    return UA_STATUSCODE_GOOD;
724
0
}
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
0
                            const UA_Logger *logger) {
735
0
    if(!policy || !policyUri)
736
0
        return UA_STATUSCODE_BADINVALIDARGUMENT;
737
738
0
    UA_ByteString certificate = UA_BYTESTRING_NULL;
739
0
    if(localCertificate)
740
0
    certificate = *localCertificate;
741
0
#ifdef UA_ENABLE_ENCRYPTION
742
0
    UA_ByteString privateKey = UA_BYTESTRING_NULL;
743
0
    if(localPrivateKey)
744
0
        privateKey = *localPrivateKey;
745
0
#endif
746
747
0
    if(UA_String_equal(policyUri, &UA_SECURITY_POLICY_NONE_URI))
748
0
        return UA_SecurityPolicy_None(policy, certificate, logger);
749
750
0
#ifdef UA_ENABLE_ENCRYPTION
751
0
    static const UA_String basic128Rsa15Uri =
752
0
        UA_STRING_STATIC("http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15");
753
0
    static const UA_String basic256Uri =
754
0
        UA_STRING_STATIC("http://opcfoundation.org/UA/SecurityPolicy#Basic256");
755
0
    static const UA_String basic256Sha256Uri =
756
0
        UA_STRING_STATIC("http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256");
757
0
    static const UA_String aes128Sha256RsaOaepUri =
758
0
        UA_STRING_STATIC("http://opcfoundation.org/UA/SecurityPolicy#Aes128_Sha256_RsaOaep");
759
0
    static const UA_String aes256Sha256RsaPssUri =
760
0
        UA_STRING_STATIC("http://opcfoundation.org/UA/SecurityPolicy#Aes256_Sha256_RsaPss");
761
0
#if defined(UA_ENABLE_ENCRYPTION_OPENSSL)
762
0
    static const UA_String eccNistP256Uri =
763
0
        UA_STRING_STATIC("http://opcfoundation.org/UA/SecurityPolicy#EccNistP256");
764
0
#endif
765
766
0
    if(UA_String_equal(policyUri, &basic128Rsa15Uri))
767
0
        return UA_SecurityPolicy_Basic128Rsa15(policy, certificate, privateKey, logger);
768
0
    if(UA_String_equal(policyUri, &basic256Uri))
769
0
        return UA_SecurityPolicy_Basic256(policy, certificate, privateKey, logger);
770
0
    if(UA_String_equal(policyUri, &basic256Sha256Uri))
771
0
        return UA_SecurityPolicy_Basic256Sha256(policy, certificate, privateKey, logger);
772
0
    if(UA_String_equal(policyUri, &aes128Sha256RsaOaepUri))
773
0
        return UA_SecurityPolicy_Aes128Sha256RsaOaep(policy, certificate, privateKey, logger);
774
0
    if(UA_String_equal(policyUri, &aes256Sha256RsaPssUri))
775
0
        return UA_SecurityPolicy_Aes256Sha256RsaPss(policy, certificate, privateKey, logger);
776
0
#if defined(UA_ENABLE_ENCRYPTION_OPENSSL)
777
0
    if(UA_String_equal(policyUri, &eccNistP256Uri))
778
0
        return UA_SecurityPolicy_EccNistP256(policy, applicationType, certificate,
779
0
                                             privateKey, logger);
780
0
#endif
781
0
#endif
782
783
0
    return UA_STATUSCODE_BADNOTSUPPORTED;
784
0
}
785
786
0
PARSE_JSON(CertificateFileField) {
787
0
    UA_ByteString *certificate = (UA_ByteString*)configField;
788
0
    UA_ByteString_init(certificate);
789
0
    UA_String filename = {.length = 0, .data = NULL};
790
791
0
    UA_StatusCode retval = StringField_parseJson(ctx, &filename, NULL);
792
0
    if(retval == UA_STATUSCODE_GOOD) {
793
0
        if (filename.length > 0) {
794
0
            char *certfile = (char *)UA_malloc(filename.length + 1);
795
0
            memcpy(certfile, filename.data, filename.length);
796
0
            certfile[filename.length] = '\0';
797
0
            *certificate = loadCertificateFile((char const *)certfile);
798
0
            UA_free(certfile);
799
0
            UA_ByteString_clear(&filename);
800
0
        } else {
801
0
            UA_LOG_WARNING(ctx->logging, UA_LOGCATEGORY_APPLICATION,
802
0
                            "Certificate file path is empty.");
803
0
            retval = UA_STATUSCODE_BADINTERNALERROR;
804
0
        }
805
0
    }
806
0
    return retval;
807
0
}
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
0
PARSE_JSON(HttpConfigurationField) {
858
0
    UA_ServerConfig *config = (UA_ServerConfig*)configField;
859
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
860
0
    cj5_token tok = nextToken(ctx);
861
0
    for(size_t j = tok.size / 2; j > 0; j--) {
862
0
        tok = nextToken(ctx);
863
0
        if(tok.type != CJ5_TOKEN_STRING)
864
0
            continue;
865
0
        char *field = (char*)UA_malloc(tok.size + 1);
866
0
        if(!field)
867
0
            return UA_STATUSCODE_BADOUTOFMEMORY;
868
0
        unsigned int strLen = 0;
869
0
        cj5_get_str(&ctx->result, (unsigned int)ctx->index, field, &strLen);
870
0
        if(strcmp(field, "maxMsgSize") == 0) {
871
0
            retval = UInt32Field_parseJson(ctx, &config->httpMaxMsgSize, NULL);
872
0
        } else if(strcmp(field, "maxDecompressedMsgSize") == 0) {
873
0
            retval = UInt32Field_parseJson(
874
0
                ctx, &config->httpMaxDecompressedMsgSize, NULL);
875
0
        } else if(strcmp(field, "timeout") == 0) {
876
0
            retval = UInt16Field_parseJson(ctx, &config->httpTimeout, NULL);
877
0
        } 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
0
        } 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
0
        } else if(strcmp(field, "privateKey") == 0) {
886
0
            UA_ByteString_clear(&config->httpPrivateKey);
887
0
            retval = CertificateFileField_parseJson(
888
0
                ctx, &config->httpPrivateKey, NULL);
889
0
        } else if(strcmp(field, "privateKeyPassword") == 0) {
890
0
            UA_String_clear(&config->httpPrivateKeyPassword);
891
0
            retval = StringField_parseJson(
892
0
                ctx, &config->httpPrivateKeyPassword, NULL);
893
0
        } else {
894
0
            LOG_UNKNOWN_FIELD(ctx, field);
895
0
        }
896
0
        UA_free(field);
897
0
        if(retval != UA_STATUSCODE_GOOD)
898
0
            return retval;
899
0
    }
900
0
    return UA_STATUSCODE_GOOD;
901
0
}
902
903
static UA_StatusCode
904
SecurityPolicyField_parseJson(ParsingCtx *ctx, UA_SecurityPolicy *field,
905
                              UA_ApplicationType applicationType,
906
0
                              const UA_Logger *logger) {
907
0
    UA_String policy = {.length = 0, .data = NULL};
908
0
    UA_ByteString certificate = {.length = 0, .data = NULL};
909
0
    UA_ByteString privateKey = {.length = 0, .data = NULL};
910
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
911
912
0
    cj5_token tok = nextToken(ctx);
913
0
    for(size_t i = tok.size / 2; i > 0 && retval == UA_STATUSCODE_GOOD; i--) {
914
0
        tok = nextToken(ctx);
915
0
        switch(tok.type) {
916
0
        case CJ5_TOKEN_STRING: {
917
0
            char *field_str = (char *)UA_malloc(tok.size + 1);
918
0
            unsigned int str_len = 0;
919
0
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
920
0
            if(strcmp(field_str, "certificate") == 0) {
921
0
                retval = CertificateFileField_parseJson(ctx, &certificate, NULL);
922
0
            } else if(strcmp(field_str, "privateKey") == 0) {
923
0
                retval = CertificateFileField_parseJson(ctx, &privateKey, NULL);
924
0
            } else if(strcmp(field_str, "policy") == 0) {
925
0
                retval = StringField_parseJson(ctx, &policy, NULL);
926
0
            } else {
927
0
                LOG_UNKNOWN_FIELD(ctx, field_str);
928
0
            }
929
0
            UA_free(field_str);
930
0
            break;
931
0
        }
932
0
        default:
933
0
            break;
934
0
        }
935
0
    }
936
937
0
    if(retval == UA_STATUSCODE_GOOD) {
938
0
        retval = UA_SecurityPolicy_initByUri(field, applicationType, &policy,
939
0
                                             &certificate, &privateKey, logger);
940
0
    }
941
942
0
    if(policy.length > 0)
943
0
        UA_String_clear(&policy);
944
0
    if(certificate.length > 0)
945
0
        UA_ByteString_clear(&certificate);
946
0
    if(privateKey.length > 0)
947
0
        UA_ByteString_clear(&privateKey);
948
949
0
    return retval;
950
0
}
951
952
static UA_StatusCode
953
SecurityPoliciesField_parseJson(ParsingCtx *ctx, void *configField, size_t *configFieldSize, UA_ApplicationType applicationType,
954
0
                                const UA_Logger *logger) {
955
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
956
0
    UA_SecurityPolicy **securityPoliciesField = (UA_SecurityPolicy**)configField;
957
958
0
    cj5_token tok = nextToken(ctx);
959
0
    for(size_t j = tok.size; j > 0; j--) {
960
0
        UA_SecurityPolicy *tmp = (UA_SecurityPolicy*)
961
0
            UA_realloc(*securityPoliciesField, sizeof(UA_SecurityPolicy) * (*configFieldSize + 1));
962
0
        if(!tmp) {
963
0
            retval = UA_STATUSCODE_BADOUTOFMEMORY;
964
0
            break;
965
0
        }
966
0
        *securityPoliciesField = tmp;
967
0
        retval = SecurityPolicyField_parseJson(ctx, &tmp[*configFieldSize],
968
0
                                               applicationType, logger);
969
0
        if(retval != UA_STATUSCODE_GOOD) {
970
0
            if(*configFieldSize == 0) {
971
0
                UA_free(*securityPoliciesField);
972
0
                *securityPoliciesField = NULL;
973
0
            }
974
0
            break;
975
0
        }
976
0
        (*configFieldSize)++;
977
0
    }
978
0
    return retval;
979
0
}
980
981
#ifdef UA_ENABLE_ENCRYPTION
982
0
PARSE_JSON(SecurityPkiField) {
983
0
    UA_ServerConfig *config = (UA_ServerConfig*)configField;
984
0
    UA_String pkiFolder = {.length = 0, .data = NULL};
985
986
0
    cj5_token tok = nextToken(ctx);
987
0
    UA_ByteString buf = getJsonPart(tok, ctx->json);
988
0
    UA_StatusCode retval = UA_decodeJson(&buf, &pkiFolder, &UA_TYPES[UA_TYPES_STRING], NULL);
989
0
    if(retval != UA_STATUSCODE_GOOD)
990
0
        return retval;
991
992
0
#if defined(__linux__) || defined(UA_ARCHITECTURE_WIN32) || defined(__APPLE__) || defined(__OpenBSD__)
993
    /* Set up the parameters for the filestore certificate store */
994
0
    UA_KeyValuePair params[2];
995
0
    size_t paramsSize = 2;
996
997
0
    params[0].key = UA_QUALIFIEDNAME(0, "max-trust-listsize");
998
0
    UA_Variant_setScalar(&params[0].value, &config->maxTrustListSize, &UA_TYPES[UA_TYPES_UINT32]);
999
0
    params[1].key = UA_QUALIFIEDNAME(0, "max-rejected-listsize");
1000
0
    UA_Variant_setScalar(&params[1].value, &config->maxRejectedListSize, &UA_TYPES[UA_TYPES_UINT32]);
1001
1002
0
    UA_KeyValueMap paramsMap;
1003
0
    paramsMap.map = params;
1004
0
    paramsMap.mapSize = paramsSize;
1005
1006
    /* set server config field */
1007
0
    UA_NodeId defaultApplicationGroup =
1008
0
           UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
1009
0
    retval = UA_CertificateGroup_Filestore(&config->secureChannelPKI, &defaultApplicationGroup,
1010
0
                                           pkiFolder, config->logging, &paramsMap);
1011
0
    if(retval != UA_STATUSCODE_GOOD) {
1012
0
        UA_String_clear(&pkiFolder);
1013
0
        return retval;
1014
0
    }
1015
1016
0
    UA_NodeId defaultUserTokenGroup =
1017
0
            UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTUSERTOKENGROUP);
1018
0
    retval = UA_CertificateGroup_Filestore(&config->sessionPKI, &defaultUserTokenGroup,
1019
0
                                            pkiFolder, config->logging, &paramsMap);
1020
0
    if(retval != UA_STATUSCODE_GOOD) {
1021
0
        UA_String_clear(&pkiFolder);
1022
0
        return retval;
1023
0
    }
1024
1025
    /* Clean up */
1026
0
    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
0
    return UA_STATUSCODE_GOOD;
1034
0
}
1035
#endif
1036
1037
0
PARSE_JSON(RuleHandlingField) {
1038
0
    UA_UInt32 enum_value;
1039
0
    UA_StatusCode retval = UInt32Field_parseJson(ctx, &enum_value, NULL);
1040
0
    if(retval != UA_STATUSCODE_GOOD)
1041
0
        return retval;
1042
0
    UA_RuleHandling *field = (UA_RuleHandling*)configField;
1043
0
    *field = (UA_RuleHandling)enum_value;
1044
0
    return retval;
1045
0
}
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
0
skipUnknownItem(ParsingCtx* ctx) {
1054
0
    cj5_skip(&ctx->result, &ctx->index);
1055
0
}
1056
1057
static UA_StatusCode
1058
0
parseJSONServerConfig(UA_ServerConfig *config, UA_ByteString json_config) {
1059
    // Parsing json config
1060
0
    const char *json = (const char*)json_config.data;
1061
0
    cj5_token tokens[MAX_TOKENS];
1062
0
    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
0
    if(r.error != CJ5_ERROR_NONE || r.num_tokens < 2 ||
1067
0
       r.tokens[0].type != CJ5_TOKEN_OBJECT)
1068
0
        return UA_STATUSCODE_BADDECODINGERROR;
1069
1070
0
    ParsingCtx ctx;
1071
0
    ctx.json = json;
1072
0
    ctx.result = r;
1073
0
    ctx.index = 1; // The first token is ignored because it is known and not needed.
1074
1075
0
    ctx.logging = config->logging;
1076
1077
    /* Buffer for the field name */
1078
0
    char field[256];
1079
1080
0
    size_t serverConfigSize = 0;
1081
0
    if(ctx.result.tokens)
1082
0
        serverConfigSize = (ctx.result.tokens[ctx.index-1].size/2);
1083
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
1084
0
    for (size_t j = serverConfigSize; j > 0 && ctx.index < ctx.result.num_tokens; j--) {
1085
0
        cj5_token tok = ctx.result.tokens[ctx.index];
1086
0
        switch (tok.type) {
1087
0
            case CJ5_TOKEN_STRING: {
1088
0
                if(tok.size >= 255) {
1089
0
                    UA_LOG_WARNING(ctx.logging, UA_LOGCATEGORY_APPLICATION,
1090
0
                                   "Configuration field name too long");
1091
0
                    continue;
1092
0
                }
1093
0
                unsigned int str_len = 0;
1094
0
                cj5_error_code res = cj5_get_str(&ctx.result, (unsigned int)ctx.index, field, &str_len);
1095
0
                if(res != CJ5_ERROR_NONE) {
1096
0
                    UA_LOG_WARNING(ctx.logging, UA_LOGCATEGORY_APPLICATION,
1097
0
                                   "Configuration field name not a valid string");
1098
0
                    continue;
1099
0
                }
1100
0
                if(strcmp(field, "buildInfo") == 0)
1101
0
                    retval = BuildInfo_parseJson(&ctx, &config->buildInfo, NULL);
1102
0
                else if(strcmp(field, "applicationDescription") == 0)
1103
0
                    retval = GenericApplicationDescriptionField_parseJson(&ctx, &config->applicationDescription, NULL, GENERICAPPLICATIONTYPE_SERVER);
1104
0
                else if(strcmp(field, "shutdownDelay") == 0)
1105
0
                    retval = DoubleField_parseJson(&ctx, &config->shutdownDelay, NULL);
1106
0
                else if(strcmp(field, "verifyRequestTimestamp") == 0)
1107
0
                    retval = RuleHandlingField_parseJson(&ctx, &config->verifyRequestTimestamp, NULL);
1108
0
                else if(strcmp(field, "allowEmptyVariables") == 0)
1109
0
                    retval = RuleHandlingField_parseJson(&ctx, &config->allowEmptyVariables, NULL);
1110
0
                else if(strcmp(field, "certificateEkuRule") == 0)
1111
0
                    retval = RuleHandlingField_parseJson(&ctx, &config->certificateEkuRule, NULL);
1112
0
                else if(strcmp(field, "serverUrls") == 0)
1113
0
                    retval = StringArrayField_parseJson(&ctx, &config->serverUrls, &config->serverUrlsSize);
1114
0
                else if(strcmp(field, "tcpEnabled") == 0)
1115
0
                    retval = BooleanField_parseJson(&ctx, &config->tcpEnabled, NULL);
1116
0
                else if(strcmp(field, "tcp") == 0)
1117
0
                    retval = TcpConfigurationField_parseJson(&ctx, config, NULL);
1118
#ifdef UA_ENABLE_LWS
1119
                else if(strcmp(field, "webSocketEnabled") == 0)
1120
                    retval = BooleanField_parseJson(&ctx, &config->webSocketEnabled, NULL);
1121
                else if(strcmp(field, "webSocket") == 0)
1122
                    retval = WebSocketConfigurationField_parseJson(&ctx, config, NULL);
1123
#endif
1124
0
                else if(strcmp(field, "httpEnabled") == 0)
1125
0
                    retval = BooleanField_parseJson(&ctx, &config->httpEnabled, NULL);
1126
0
                else if(strcmp(field, "httpAllowUnencrypted") == 0)
1127
0
                    retval = BooleanField_parseJson(&ctx, &config->httpAllowUnencrypted, NULL);
1128
0
                else if(strcmp(field, "http") == 0)
1129
0
                    retval = HttpConfigurationField_parseJson(&ctx, config, NULL);
1130
0
                else if(strcmp(field, "securityPolicyNoneDiscoveryOnly") == 0)
1131
0
                    retval = BooleanField_parseJson(&ctx, &config->securityPolicyNoneDiscoveryOnly, NULL);
1132
0
                else if(strcmp(field, "modellingRulesOnInstances") == 0)
1133
0
                    retval = BooleanField_parseJson(&ctx, &config->modellingRulesOnInstances, NULL);
1134
0
                else if(strcmp(field, "copyMethodsOnInstances") == 0)
1135
0
                    retval = BooleanField_parseJson(&ctx, &config->copyMethodsOnInstances, NULL);
1136
0
                else if(strcmp(field, "maxSecureChannels") == 0)
1137
0
                    retval = UInt16Field_parseJson(&ctx, &config->maxSecureChannels, NULL);
1138
0
                else if(strcmp(field, "maxSecurityTokenLifetime") == 0)
1139
0
                    retval = UInt32Field_parseJson(&ctx, &config->maxSecurityTokenLifetime, NULL);
1140
0
                else if(strcmp(field, "maxSessions") == 0)
1141
0
                    retval = UInt16Field_parseJson(&ctx, &config->maxSessions, NULL);
1142
0
                else if(strcmp(field, "maxSessionTimeout") == 0)
1143
0
                    retval = DoubleField_parseJson(&ctx, &config->maxSessionTimeout, NULL);
1144
0
                else if(strcmp(field, "maxNodesPerRead") == 0)
1145
0
                    retval = UInt32Field_parseJson(&ctx, &config->maxNodesPerRead, NULL);
1146
0
                else if(strcmp(field, "maxNodesPerWrite") == 0)
1147
0
                    retval = UInt32Field_parseJson(&ctx, &config->maxNodesPerWrite, NULL);
1148
0
                else if(strcmp(field, "maxNodesPerMethodCall") == 0)
1149
0
                    retval = UInt32Field_parseJson(&ctx, &config->maxNodesPerMethodCall, NULL);
1150
0
                else if(strcmp(field, "maxNodesPerBrowse") == 0)
1151
0
                    retval = UInt32Field_parseJson(&ctx, &config->maxNodesPerBrowse, NULL);
1152
0
                else if(strcmp(field, "maxNodesPerRegisterNodes") == 0)
1153
0
                    retval = UInt32Field_parseJson(&ctx, &config->maxNodesPerRegisterNodes, NULL);
1154
0
                else if(strcmp(field, "maxNodesPerTranslateBrowsePathsToNodeIds") == 0)
1155
0
                    retval = UInt32Field_parseJson(&ctx, &config->maxNodesPerTranslateBrowsePathsToNodeIds, NULL);
1156
0
                else if(strcmp(field, "maxNodesPerNodeManagement") == 0)
1157
0
                    retval = UInt32Field_parseJson(&ctx, &config->maxNodesPerNodeManagement, NULL);
1158
0
                else if(strcmp(field, "maxMonitoredItemsPerCall") == 0)
1159
0
                    retval = UInt32Field_parseJson(&ctx, &config->maxMonitoredItemsPerCall, NULL);
1160
0
                else if(strcmp(field, "maxReferencesPerNode") == 0)
1161
0
                    retval = UInt32Field_parseJson(&ctx, &config->maxReferencesPerNode, NULL);
1162
0
                else if(strcmp(field, "reverseReconnectInterval") == 0)
1163
0
                    retval = UInt32Field_parseJson(&ctx, &config->reverseReconnectInterval, NULL);
1164
1165
0
#if UA_MULTITHREADING >= 100
1166
0
                else if(strcmp(field, "asyncOperationTimeout") == 0)
1167
0
                    retval = DoubleField_parseJson(&ctx, &config->asyncOperationTimeout, NULL);
1168
0
                else if(strcmp(field, "maxAsyncOperationQueueSize") == 0)
1169
0
                    retval = UInt64Field_parseJson(&ctx, &config->maxAsyncOperationQueueSize, NULL);
1170
0
#endif
1171
1172
0
#ifdef UA_ENABLE_DISCOVERY
1173
0
                else if(strcmp(field, "registeredServersEnabled") == 0)
1174
0
                    retval = BooleanField_parseJson(&ctx, &config->registeredServersEnabled, NULL);
1175
0
                else if(strcmp(field, "registeredServerCleanupTimeout") == 0)
1176
0
                    retval = UInt32Field_parseJson(&ctx, &config->registeredServerCleanupTimeout, NULL);
1177
0
                else if(strcmp(field, "serversOnNetworkEnabled") == 0)
1178
0
                    retval = BooleanField_parseJson(&ctx, &config->serversOnNetworkEnabled, NULL);
1179
0
#endif
1180
1181
0
#ifdef UA_ENABLE_SUBSCRIPTIONS
1182
0
                else if(strcmp(field, "subscriptionsEnabled") == 0)
1183
0
                    retval = BooleanField_parseJson(&ctx, &config->subscriptionsEnabled, NULL);
1184
0
                else if(strcmp(field, "subscriptions") == 0)
1185
0
                    retval = SubscriptionConfigurationField_parseJson(&ctx, config, NULL);
1186
0
# endif
1187
1188
0
#ifdef UA_ENABLE_HISTORIZING
1189
0
                else if(strcmp(field, "historizingEnabled") == 0)
1190
0
                    retval = BooleanField_parseJson(&ctx, &config->historizingEnabled, NULL);
1191
0
                else if(strcmp(field, "historizing") == 0)
1192
0
                    retval = HistorizingConfigurationField_parseJson(&ctx, config, NULL);
1193
0
#endif
1194
1195
0
#ifdef UA_ENABLE_PUBSUB
1196
0
                else if(strcmp(field, "pubsubEnabled") == 0)
1197
0
                    retval = BooleanField_parseJson(&ctx, &config->pubsubEnabled, NULL);
1198
0
                else if(strcmp(field, "pubsub") == 0)
1199
0
                    retval = PubsubConfigurationField_parseJson(&ctx, &config->pubSubConfig, NULL);
1200
0
#endif
1201
0
#ifdef UA_ENABLE_ENCRYPTION
1202
0
                else if(strcmp(field, "securityPolicies") == 0)
1203
0
                    retval = SecurityPoliciesField_parseJson(&ctx, &config->securityPolicies, &config->securityPoliciesSize, UA_APPLICATIONTYPE_SERVER, config->logging);
1204
0
                else if(strcmp(field, "pkiFolder") == 0)
1205
0
                    retval = SecurityPkiField_parseJson(&ctx, config, NULL);
1206
0
#endif
1207
0
                else {
1208
0
                    UA_LOG_WARNING(ctx.logging, UA_LOGCATEGORY_APPLICATION,
1209
0
                                   "Field name '%s' unknown or misspelled. Maybe the feature is not enabled.", field);
1210
                    /* skip the name of item */
1211
0
                    ++ctx.index;
1212
                    /* skip value of unknown item */
1213
0
                    skipUnknownItem(&ctx);
1214
                    /* after skipUnknownItem() ctx->index points to the name of the following item.
1215
                       We must decrement index in oder following increment will
1216
                       still set index to the right position (name of the following item) */
1217
0
                    --ctx.index;
1218
0
                }
1219
0
                if(retval != UA_STATUSCODE_GOOD) {
1220
0
                    UA_LOG_ERROR(ctx.logging, UA_LOGCATEGORY_APPLICATION,
1221
0
                                 "An error occurred while parsing the configuration field %s", field);
1222
0
                    return retval;
1223
0
                }
1224
0
                break;
1225
0
            }
1226
0
            default:
1227
0
                break;
1228
0
        }
1229
0
        ctx.index += 1;
1230
0
    }
1231
0
    return retval;
1232
0
}
1233
1234
UA_Server *
1235
0
UA_Server_newFromFile(const UA_ByteString jsonConfig) {
1236
0
    UA_ServerConfig config;
1237
0
    UA_StatusCode res = UA_ServerConfig_loadFromFile(&config, jsonConfig);
1238
0
    if(res != UA_STATUSCODE_GOOD)
1239
0
        return NULL;
1240
0
    return UA_Server_newWithConfig(&config);
1241
0
}
1242
1243
UA_StatusCode
1244
0
UA_ServerConfig_loadFromFile(UA_ServerConfig *config, const UA_ByteString jsonConfig) {
1245
0
    memset(config, 0, sizeof(UA_ServerConfig));
1246
0
    UA_StatusCode res = UA_ServerConfig_setDefault(config);
1247
0
    if (res == UA_STATUSCODE_GOOD) {
1248
0
        res = parseJSONServerConfig(config, jsonConfig);
1249
0
        if (UA_StatusCode_isBad(res)) {
1250
0
            UA_ServerConfig_clear(config);
1251
0
        }
1252
0
    }
1253
0
    return res;
1254
0
}
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, "tcpReuseAddr") == 0)
1695
0
                    retval = BooleanField_parseJson(&ctx, &config->tcpReuseAddr, NULL);
1696
#ifdef UA_ENABLE_LWS
1697
                else if(strcmp(field, "webSocketMaxQueueSize") == 0)
1698
                    retval = UInt32Field_parseJson(
1699
                        &ctx, &config->webSocketMaxQueueSize, NULL);
1700
                else if(strcmp(field, "webSocketCaCertificate") == 0) {
1701
                    UA_ByteString_clear(&config->webSocketCaCertificate);
1702
                    retval = CertificateFileField_parseJson(
1703
                        &ctx, &config->webSocketCaCertificate, NULL);
1704
                }
1705
#endif
1706
0
                else if(strcmp(field, "httpAllowUnencrypted") == 0)
1707
0
                    retval = BooleanField_parseJson(
1708
0
                        &ctx, &config->httpAllowUnencrypted, NULL);
1709
0
                else if(strcmp(field, "httpCaCertificate") == 0) {
1710
0
                    UA_ByteString_clear(&config->httpCaCertificate);
1711
0
                    retval = CertificateFileField_parseJson(
1712
0
                        &ctx, &config->httpCaCertificate, NULL);
1713
0
                }
1714
0
                else if(strcmp(field, "httpClientCertificate") == 0) {
1715
0
                    UA_ByteString_clear(&config->httpClientCertificate);
1716
0
                    retval = CertificateFileField_parseJson(
1717
0
                        &ctx, &config->httpClientCertificate, NULL);
1718
0
                }
1719
0
                else if(strcmp(field, "httpClientPrivateKey") == 0) {
1720
0
                    UA_ByteString_clear(&config->httpClientPrivateKey);
1721
0
                    retval = CertificateFileField_parseJson(
1722
0
                        &ctx, &config->httpClientPrivateKey, NULL);
1723
0
                }
1724
0
                else if(strcmp(field, "httpClientPrivateKeyPassword") == 0) {
1725
0
                    UA_String_clear(&config->httpClientPrivateKeyPassword);
1726
0
                    retval = StringField_parseJson(
1727
0
                        &ctx, &config->httpClientPrivateKeyPassword, NULL);
1728
0
                }
1729
0
                else if(strcmp(field, "httpTimeout") == 0)
1730
0
                    retval = UInt16Field_parseJson(&ctx, &config->httpTimeout, NULL);
1731
0
                else if(strcmp(field, "httpMaxMsgSize") == 0)
1732
0
                    retval = UInt32Field_parseJson(&ctx, &config->httpMaxMsgSize, NULL);
1733
0
                else if(strcmp(field, "httpMaxDecompressedMsgSize") == 0)
1734
0
                    retval = UInt32Field_parseJson(
1735
0
                        &ctx, &config->httpMaxDecompressedMsgSize, NULL);
1736
0
                else if(strcmp(field, "endpoint") == 0)
1737
0
                    retval = EndpointDescription_parseJson(&ctx, &config->endpoint, NULL);
1738
0
                else if(strcmp(field, "userTokenPolicy") == 0)
1739
0
                    retval = UserTokenPolicy_parseJson(&ctx, &config->userTokenPolicy, NULL);
1740
0
                else if(strcmp(field, "applicationUri") == 0)
1741
0
                    retval = StringField_parseJson(&ctx, &config->applicationUri, NULL);
1742
0
                else if(strcmp(field, "securityMode") == 0)
1743
0
                    retval = MessageSecurityMode_parseJson(&ctx, &config->securityMode, NULL);
1744
0
                else if(strcmp(field, "securityPolicyUri") == 0)
1745
0
                    retval = StringField_parseJson(&ctx, &config->securityPolicyUri, NULL);
1746
0
                else if(strcmp(field, "authSecurityPolicyUri") == 0)
1747
0
                    retval = StringField_parseJson(&ctx, &config->authSecurityPolicyUri, NULL);
1748
0
                else if(strcmp(field, "securityPolicies") == 0)
1749
0
                    retval = SecurityPoliciesField_parseJson(&ctx, &config->securityPolicies, &config->securityPoliciesSize, UA_APPLICATIONTYPE_CLIENT, config->logging);
1750
0
                else if(strcmp(field, "authSecurityPolicies") == 0)
1751
0
                    retval = SecurityPoliciesField_parseJson(&ctx, &config->authSecurityPolicies, &config->authSecurityPoliciesSize, UA_APPLICATIONTYPE_CLIENT, config->logging);
1752
0
                else if(strcmp(field, "allowNonePolicyPassword") == 0)
1753
0
                    retval = BooleanField_parseJson(&ctx, &config->allowNonePolicyPassword, NULL);
1754
0
#ifdef UA_ENABLE_ENCRYPTION
1755
0
                else if(strcmp(field, "maxTrustListSize") == 0)
1756
0
                    retval = UInt32Field_parseJson(&ctx, &config->maxTrustListSize, NULL);
1757
0
                else if(strcmp(field, "maxRejectedListSize") == 0)
1758
0
                    retval = UInt32Field_parseJson(&ctx, &config->maxRejectedListSize, NULL);
1759
0
#endif
1760
0
                else if(strcmp(field, "namespaces") == 0)
1761
0
                    retval = StringArrayField_parseJson(&ctx, &config->namespaces, &config->namespacesSize);
1762
0
                else if(strcmp(field, "outStandingPublishRequests") == 0)
1763
0
                    retval = UInt16Field_parseJson(&ctx, &config->outStandingPublishRequests, NULL);
1764
0
                else {
1765
0
                    UA_LOG_WARNING(ctx.logging, UA_LOGCATEGORY_APPLICATION,
1766
0
                                   "Field name '%s' unknown or misspelled. Maybe the feature is not enabled either.", field);
1767
                    /* skip the name of item */
1768
0
                    ++ctx.index;
1769
                    /* skip value of unknown item */
1770
0
                    skipUnknownItem(&ctx);
1771
                    /* after skipUnknownItem() ctx->index points to the name of the following item.
1772
                       We must decrement index in oder following increment will
1773
                       still set index to the right position (name of the following item) */
1774
0
                    --ctx.index;
1775
0
                }
1776
0
                UA_free(field);
1777
0
                if(retval != UA_STATUSCODE_GOOD) {
1778
0
                    UA_LOG_ERROR(ctx.logging, UA_LOGCATEGORY_APPLICATION, "An error occurred while parsing the configuration file.");
1779
0
                    return retval;
1780
0
                }
1781
0
                break;
1782
0
            }
1783
0
            default:
1784
0
                break;
1785
0
        }
1786
0
        ctx.index += 1;
1787
0
    }
1788
0
    return retval;
1789
0
}
1790
1791
UA_Client *
1792
UA_Client_newFromFile(const UA_ByteString jsonConfig)
1793
0
{
1794
0
    UA_ClientConfig config;
1795
0
    UA_StatusCode res = UA_ClientConfig_loadFromFile(&config, jsonConfig);
1796
0
    if(res != UA_STATUSCODE_GOOD)
1797
0
        return NULL;
1798
0
    return UA_Client_newWithConfig(&config);
1799
0
}
1800
1801
UA_StatusCode
1802
UA_ClientConfig_loadFromFile(UA_ClientConfig *config, const UA_ByteString jsonConfig)
1803
0
{
1804
0
    memset(config, 0, sizeof(UA_ClientConfig));
1805
0
    UA_StatusCode res = UA_ClientConfig_setDefault(config);
1806
0
    if (res == UA_STATUSCODE_GOOD) {
1807
0
        res = parseJSONClientConfig(config, jsonConfig);
1808
0
        if (UA_StatusCode_isBad(res)) {
1809
0
            UA_ClientConfig_clear(config);
1810
0
        }
1811
0
    }
1812
0
    return res;
1813
0
}
1814
1815
static UA_ByteString
1816
0
loadCertificateFile(const char *const path) {
1817
0
    UA_ByteString fileContents = UA_BYTESTRING_NULL;
1818
1819
    /* Open the file */
1820
0
    FILE *fp = fopen(path, "rb");
1821
0
    if(!fp) {
1822
0
        errno = 0; /* We read errno also from the tcp layer... */
1823
0
        return fileContents;
1824
0
    }
1825
1826
    /* Get the file length, allocate the data and read */
1827
0
    if(fseek(fp, 0, SEEK_END) != 0) {
1828
0
        fclose(fp);
1829
0
        errno = 0;
1830
0
        return fileContents;
1831
0
    }
1832
1833
0
    long length = ftell(fp);
1834
0
    if(length < 0) {
1835
0
        fclose(fp);
1836
0
        errno = 0;
1837
0
        return fileContents;
1838
0
    }
1839
1840
0
    fileContents.length = (size_t)length;
1841
0
    fileContents.data = (UA_Byte *)UA_malloc(fileContents.length * sizeof(UA_Byte));
1842
0
    if(fileContents.data) {
1843
0
        if(fseek(fp, 0, SEEK_SET) != 0) {
1844
0
            fclose(fp);
1845
0
            UA_ByteString_clear(&fileContents);
1846
0
            errno = 0;
1847
0
            return fileContents;
1848
0
        }
1849
0
        size_t read = fread(fileContents.data, sizeof(UA_Byte), fileContents.length, fp);
1850
0
        if(read != fileContents.length)
1851
0
            UA_ByteString_clear(&fileContents);
1852
0
    } else {
1853
0
        fileContents.length = 0;
1854
0
    }
1855
0
    fclose(fp);
1856
1857
0
    return fileContents;
1858
0
}