From e9a8f467f1d805348df66c6a4bee1d145fdd85db Mon Sep 17 00:00:00 2001 From: OpenGnSys Support Team Date: Wed, 17 Jul 2024 14:19:39 +0200 Subject: rest: add GET,POST /image/restrict Allow to restrict image to scope: POST /image/restrict { "image" : 49, "scopes" : [ 1,3 ] } response: 200 OK This restricts image with ID 49 to scopes 1 and 3. You can also fetch the current list of restrictions: GET /image/restrict { "image" : 49 } response: 200 OK { "image" : 49, "scopes" : [ 1,3 ] } Existing limitations in this interface: - Only restriction of image to center is possible at this moment. - This is only used by ogCP to validate if this is possible, no existing code in the ogserver uses this to restrict POST image/restore. This is a usability feature. --- src/rest.c | 243 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 243 insertions(+) (limited to 'src/rest.c') diff --git a/src/rest.c b/src/rest.c index 32cf757..8563fd2 100644 --- a/src/rest.c +++ b/src/rest.c @@ -3895,6 +3895,230 @@ static int og_cmd_delete_image(json_t *element, struct og_msg_params *params) return 0; } +struct og_scope_image { + struct list_head list; + uint32_t id; +}; + +static void og_scope_image_list_free(struct list_head *scope_list) +{ + struct og_scope_image *scope, *next; + + list_for_each_entry_safe(scope, next, scope_list, list) { + list_del(&scope->list); + free(scope); + } +} + +static int og_json_parse_scope_image_list(json_t *element, struct list_head *scope_list) +{ + struct og_scope_image *scope; + unsigned int i; + json_t *k; + + if (json_typeof(element) != JSON_ARRAY) + return -1; + + for (i = 0; i < json_array_size(element); i++) { + k = json_array_get(element, i); + if (json_typeof(k) != JSON_INTEGER) + goto err_out; + + scope = calloc(1, sizeof(struct og_scope_image)); + if (!scope) + goto err_out; + + scope->id = json_integer_value(k); + + list_add_tail(&scope->list, scope_list); + } + + return 0; +err_out: + og_scope_image_list_free(scope_list); + return -1; +} + +enum { + OG_ATTR_IMAGE_ID = (1 << 0), + OG_ATTR_IMAGE_SCOPE_ID = (1 << 0), +}; + +static int og_cmd_image_scope_update(json_t *element, struct og_msg_params *params) +{ + struct og_scope_image *scope; + LIST_HEAD(scope_list); + struct og_dbi *dbi; + const char *msglog; + uint32_t image_id; + dbi_result result; + const char *key; + json_t *value; + int err = 0; + + if (json_typeof(element) != JSON_OBJECT) + return -1; + + json_object_foreach(element, key, value) { + if (!strcmp(key, "image")) { + err = og_json_parse_uint(value, &image_id); + params->flags |= OG_ATTR_IMAGE_ID; + } else if (!strcmp(key, "scopes")) { + err = og_json_parse_scope_image_list(value, &scope_list); + if (err >= 0 && !list_empty(&scope_list)) + params->flags |= OG_ATTR_IMAGE_SCOPE_ID; + } + + if (err < 0) + return err; + } + + if (!og_msg_params_validate(params, OG_ATTR_IMAGE_ID | + OG_ATTR_IMAGE_SCOPE_ID)) { + og_scope_image_list_free(&scope_list); + return -1; + } + + dbi = og_dbi_open(&ogconfig.db); + if (!dbi) { + syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", + __func__, __LINE__); + og_scope_image_list_free(&scope_list); + return -1; + } + + result = dbi_conn_queryf(dbi->conn, + "DELETE FROM image_scope WHERE image_id=%d", + image_id); + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + goto err_out; + } + dbi_result_free(result); + + list_for_each_entry(scope, &scope_list, list) { + result = dbi_conn_queryf(dbi->conn, + "INSERT INTO image_scope (image_id, scope_id) " + "VALUES (%d, %d)", image_id, scope->id); + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + goto err_out; + } + dbi_result_free(result); + } + + og_dbi_close(dbi); + + og_scope_image_list_free(&scope_list); + + return 0; + +err_out: + og_scope_image_list_free(&scope_list); + og_dbi_close(dbi); + + return -1; +} + +static json_t *og_json_image_scope(struct og_dbi *dbi, uint32_t image_id) +{ + json_t *scope_image, *scope_array; + const char *msglog; + uint32_t scope_id; + dbi_result result; + + result = dbi_conn_queryf(dbi->conn, + "SELECT scope_id FROM image_scope WHERE image_id = '%u'", image_id); + if (!result) { + dbi_conn_error(dbi->conn, &msglog); + syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", + __func__, __LINE__, msglog); + return NULL; + } + + scope_image = json_object(); + if (!scope_image) { + dbi_result_free(result); + return NULL; + } + + json_object_set_new(scope_image, "id", json_integer(image_id)); + + scope_array = json_array(); + if (!scope_array) { + json_decref(scope_image); + dbi_result_free(result); + return NULL; + } + + while (dbi_result_next_row(result)) { + scope_id = dbi_result_get_uint(result, "scope_id"); + json_array_append_new(scope_array, json_integer(scope_id)); + } + dbi_result_free(result); + + json_object_set_new(scope_image, "scopes", scope_array); + + return scope_image; +} + +static int og_cmd_image_scope_list(json_t *element, + struct og_msg_params *params, + char *buffer_reply) +{ + struct og_buffer og_buffer = { + .data = buffer_reply + }; + json_t *value, *scope_image; + struct og_dbi *dbi; + uint32_t image_id; + const char *key; + int err = 0; + + if (json_typeof(element) != JSON_OBJECT) + return -1; + + json_object_foreach(element, key, value) { + if (!strcmp(key, "image")) { + err = og_json_parse_uint(value, &image_id); + params->flags |= OG_ATTR_IMAGE_ID; + } + + if (err < 0) + return err; + } + + if (!og_msg_params_validate(params, OG_ATTR_IMAGE_ID)) + return -1; + + dbi = og_dbi_open(&ogconfig.db); + if (!dbi) { + syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", + __func__, __LINE__); + return -1; + } + + scope_image = og_json_image_scope(dbi, image_id); + + og_dbi_close(dbi); + + if (!scope_image) + return -1; + + if (json_dump_callback(scope_image, og_json_dump_clients, &og_buffer, 0)) { + json_decref(scope_image); + return -1; + } + + json_decref(scope_image); + + return 0; +} + static int og_dbi_client_cache_get(struct og_dbi *dbi, json_t *clients, const char *ip) { const char *img_name, *msglog, *img_checksum; @@ -7934,6 +8158,7 @@ struct { [OG_URI_IMAGE_UPDATE] = { "image/update" }, [OG_URI_IMAGE_RESTORE] = { "image/restore", }, [OG_URI_IMAGE_DELETE] = { "image/delete", }, + [OG_URI_IMAGE_RESTRICT] = { "image/restrict", }, [OG_URI_CACHE_LIST] = { "cache/list", }, [OG_URI_CACHE_DELETE] = { "cache/delete", }, [OG_URI_PART_SETUP] = { "setup", }, @@ -8530,6 +8755,24 @@ int og_client_state_process_payload_rest(struct og_client *cli) goto err_process_rest_payload; } err = og_cmd_delete_image(root, ¶ms); + } else if (!strncmp(cmd, "image/restrict", strlen("image/restrict"))) { + if (!root) { + err = og_client_bad_request(cli); + goto err_process_rest_payload; + } + + switch (method) { + case OG_METHOD_GET: + err = og_cmd_image_scope_list(root, ¶ms, buf_reply); + break; + case OG_METHOD_POST: + err = og_cmd_image_scope_update(root, ¶ms); + break; + default: + err = og_client_method_not_found(cli); + goto err_process_rest_payload; + } + } else if (!strncmp(cmd, "cache/list", strlen("cache/list"))) { if (method != OG_METHOD_GET) { err = og_client_method_not_found(cli); -- cgit v1.2.3-18-g5258