void parse_conf(jail_conf_t *jail_conf, uint8_t *buf, size_t len) { struct ucl_parser *parser = ucl_parser_new(UCL_PARSER_NO_TIME); ucl_parser_add_chunk(parser, buf, len); if (ucl_parser_get_error(parser)) die("Config: Could not parse"); // TODO: output the error ucl_object_t *root = ucl_parser_get_object(parser); jail_conf->hostname = NULL; jail_conf->jailname = NULL; jail_conf->net_iface = NULL; jail_conf->script = NULL; jail_conf->securelevel = 3; jail_conf->devfs_ruleset = 4; bzero(jail_conf->ipv4, sizeof(jail_conf->ipv4)); bzero(jail_conf->ipv6, sizeof(jail_conf->ipv6)); bzero(jail_conf->limits, sizeof(jail_conf->limits)); bzero(jail_conf->mounts, sizeof(jail_conf->mounts)); ucl_iterate(root, true, ^(ucl_object_t *cur) { char *key = ucl_object_key(cur); if (strcmp(key, "hostname") == 0) { STR_TO_ARENA(jail_conf->hostname, ucl_object_tostring_forced(cur)); } else if (strcmp(key, "jailname") == 0) { STR_TO_ARENA(jail_conf->jailname, ucl_object_tostring_forced(cur)); } else if (strcmp(key, "script") == 0) { STR_TO_ARENA(jail_conf->script, ucl_object_tostring_forced(cur)); } else if (strcmp(key, "net_iface") == 0) { STR_TO_ARENA(jail_conf->net_iface, ucl_object_tostring_forced(cur)); } else if (strcmp(key, "securelevel") == 0) { int64_t int_val = -1; if (ucl_object_toint_safe(cur, &int_val) != true) die("Config: securelevel is not a number"); jail_conf->securelevel = (int8_t)int_val; } else if (strcmp(key, "devfs_ruleset") == 0) { int64_t int_val = -1; if (ucl_object_toint_safe(cur, &int_val) != true) die("Config: devfs_ruleset is not a number"); jail_conf->devfs_ruleset = (int16_t)int_val; } else if (strcmp(key, "ipv4") == 0) { __block size_t i = 0; ucl_iterate(cur, false, ^(ucl_object_t *val) { if (i > IPV4_ADDRS_LEN) die("Config: Too many IPv4 addresses"); STR_TO_ARENA(jail_conf->ipv4[i], ucl_object_tostring_forced(val)); i++; });
/* * Validate object */ static bool ucl_schema_validate_object (const ucl_object_t *schema, const ucl_object_t *obj, struct ucl_schema_error *err, const ucl_object_t *root) { const ucl_object_t *elt, *prop, *found, *additional_schema = NULL, *required = NULL, *pat, *pelt; ucl_object_iter_t iter = NULL, piter = NULL; bool ret = true, allow_additional = true; int64_t minmax; while (ret && (elt = ucl_iterate_object (schema, &iter, true)) != NULL) { if (elt->type == UCL_OBJECT && strcmp (ucl_object_key (elt), "properties") == 0) { piter = NULL; while (ret && (prop = ucl_iterate_object (elt, &piter, true)) != NULL) { found = ucl_object_find_key (obj, ucl_object_key (prop)); if (found) { ret = ucl_schema_validate (prop, found, true, err, root); } } } else if (strcmp (ucl_object_key (elt), "additionalProperties") == 0) { if (elt->type == UCL_BOOLEAN) { if (!ucl_object_toboolean (elt)) { /* Deny additional fields completely */ allow_additional = false; } } else if (elt->type == UCL_OBJECT) { /* Define validator for additional fields */ additional_schema = elt; } else { ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, elt, "additionalProperties attribute is invalid in schema"); ret = false; break; } } else if (strcmp (ucl_object_key (elt), "required") == 0) { if (elt->type == UCL_ARRAY) { required = elt; } else { ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, elt, "required attribute is invalid in schema"); ret = false; break; } } else if (strcmp (ucl_object_key (elt), "minProperties") == 0 && ucl_object_toint_safe (elt, &minmax)) { if (obj->len < minmax) { ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj, "object has not enough properties: %u, minimum is: %u", obj->len, (unsigned)minmax); ret = false; break; } } else if (strcmp (ucl_object_key (elt), "maxProperties") == 0 && ucl_object_toint_safe (elt, &minmax)) { if (obj->len > minmax) { ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj, "object has too many properties: %u, maximum is: %u", obj->len, (unsigned)minmax); ret = false; break; } } else if (strcmp (ucl_object_key (elt), "patternProperties") == 0) { piter = NULL; while (ret && (prop = ucl_iterate_object (elt, &piter, true)) != NULL) { found = ucl_schema_test_pattern (obj, ucl_object_key (prop)); if (found) { ret = ucl_schema_validate (prop, found, true, err, root); } } } else if (elt->type == UCL_OBJECT && strcmp (ucl_object_key (elt), "dependencies") == 0) { ret = ucl_schema_validate_dependencies (elt, obj, err, root); } } if (ret) { /* Additional properties */ if (!allow_additional || additional_schema != NULL) { /* Check if we have exactly the same properties in schema and object */ iter = NULL; prop = ucl_object_find_key (schema, "properties"); while ((elt = ucl_iterate_object (obj, &iter, true)) != NULL) { found = ucl_object_find_key (prop, ucl_object_key (elt)); if (found == NULL) { /* Try patternProperties */ piter = NULL; pat = ucl_object_find_key (schema, "patternProperties"); while ((pelt = ucl_iterate_object (pat, &piter, true)) != NULL) { found = ucl_schema_test_pattern (obj, ucl_object_key (pelt)); if (found != NULL) { break; } } } if (found == NULL) { if (!allow_additional) { ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj, "object has non-allowed property %s", ucl_object_key (elt)); ret = false; break; } else if (additional_schema != NULL) { if (!ucl_schema_validate (additional_schema, elt, true, err, root)) { ret = false; break; } } } } } /* Required properties */ if (required != NULL) { iter = NULL; while ((elt = ucl_iterate_object (required, &iter, true)) != NULL) { if (ucl_object_find_key (obj, ucl_object_tostring (elt)) == NULL) { ucl_schema_create_error (err, UCL_SCHEMA_MISSING_PROPERTY, obj, "object has missing property %s", ucl_object_tostring (elt)); ret = false; break; } } } } return ret; }