/* * Copyright (C) 2020-2021 Soleta Networks * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Affero General Public License as published by the * Free Software Foundation; either version 3 of the License, or * (at your option) any later version. */ #include "ogAdmServer.h" #include "dbi.h" #include "utils.h" #include "list.h" #include "rest.h" #include "core.h" #include "wol.h" #include "cfg.h" #include "schedule.h" #include "legacy.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct ev_loop *og_loop; #define OG_REST_PARAM_ADDR (1UL << 0) #define OG_REST_PARAM_MAC (1UL << 1) #define OG_REST_PARAM_WOL_TYPE (1UL << 2) #define OG_REST_PARAM_RUN_CMD (1UL << 3) #define OG_REST_PARAM_DISK (1UL << 4) #define OG_REST_PARAM_PARTITION (1UL << 5) #define OG_REST_PARAM_REPO (1UL << 6) #define OG_REST_PARAM_NAME (1UL << 7) #define OG_REST_PARAM_ID (1UL << 8) #define OG_REST_PARAM_CODE (1UL << 9) #define OG_REST_PARAM_TYPE (1UL << 10) #define OG_REST_PARAM_PROFILE (1UL << 11) #define OG_REST_PARAM_CACHE (1UL << 12) #define OG_REST_PARAM_CACHE_SIZE (1UL << 13) #define OG_REST_PARAM_PART_0 (1UL << 14) #define OG_REST_PARAM_PART_1 (1UL << 15) #define OG_REST_PARAM_PART_2 (1UL << 16) #define OG_REST_PARAM_PART_3 (1UL << 17) #define OG_REST_PARAM_SYNC_SYNC (1UL << 18) #define OG_REST_PARAM_SYNC_DIFF (1UL << 19) #define OG_REST_PARAM_SYNC_REMOVE (1UL << 20) #define OG_REST_PARAM_SYNC_COMPRESS (1UL << 21) #define OG_REST_PARAM_SYNC_CLEANUP (1UL << 22) #define OG_REST_PARAM_SYNC_CACHE (1UL << 23) #define OG_REST_PARAM_SYNC_CLEANUP_CACHE (1UL << 24) #define OG_REST_PARAM_SYNC_REMOVE_DST (1UL << 25) #define OG_REST_PARAM_SYNC_DIFF_ID (1UL << 26) #define OG_REST_PARAM_SYNC_DIFF_NAME (1UL << 27) #define OG_REST_PARAM_SYNC_PATH (1UL << 28) #define OG_REST_PARAM_SYNC_METHOD (1UL << 29) #define OG_REST_PARAM_ECHO (1UL << 30) #define OG_REST_PARAM_TASK (1UL << 31) #define OG_REST_PARAM_TIME_YEARS (1UL << 32) #define OG_REST_PARAM_TIME_MONTHS (1UL << 33) #define OG_REST_PARAM_TIME_WEEKS (1UL << 34) #define OG_REST_PARAM_TIME_WEEK_DAYS (1UL << 35) #define OG_REST_PARAM_TIME_DAYS (1UL << 36) #define OG_REST_PARAM_TIME_HOURS (1UL << 37) #define OG_REST_PARAM_TIME_AM_PM (1UL << 38) #define OG_REST_PARAM_TIME_MINUTES (1UL << 39) #define OG_REST_PARAM_NETMASK (1UL << 40) #define OG_REST_PARAM_SCOPE (1UL << 41) #define OG_REST_PARAM_MODE (1UL << 42) #define OG_REST_PARAM_CENTER (1UL << 43) #define OG_REST_PARAM_BACKUP (1UL << 44) static LIST_HEAD(client_list); static LIST_HEAD(client_wol_list); void og_client_add(struct og_client *cli) { list_add(&cli->list, &client_list); } struct og_client *__og_client_find(const struct in_addr *addr) { struct og_client *client; list_for_each_entry(client, &client_list, list) { if (!client->agent) continue; if (client->addr.sin_addr.s_addr == addr->s_addr) return client; } return NULL; } static struct og_client *og_client_find(const char *ip) { struct in_addr addr; int res; res = inet_aton(ip, &addr); if (!res) { syslog(LOG_ERR, "Invalid IP string: %s\n", ip); return NULL; } return __og_client_find(&addr); } static const char *og_client_status(const struct og_client *cli) { switch (cli->last_cmd) { case OG_CMD_UNSPEC: case OG_CMD_PROBE: break; default: return "BSY"; } switch (cli->status) { case OG_CLIENT_STATUS_BUSY: return "BSY"; case OG_CLIENT_STATUS_OGLIVE: return "OPG"; case OG_CLIENT_STATUS_VIRTUAL: return "VDI"; case OG_CLIENT_STATUS_LINUX: return "LNX"; case OG_CLIENT_STATUS_LINUX_SESSION: return "LNXS"; case OG_CLIENT_STATUS_WIN: return "WIN"; case OG_CLIENT_STATUS_WIN_SESSION: return "WINS"; default: return "OFF"; } } static bool og_msg_params_validate(const struct og_msg_params *params, const uint64_t flags) { return (params->flags & flags) == flags; } static bool og_flags_validate(const uint64_t flags, const uint64_t required_flags) { return (flags & required_flags) == required_flags; } static int og_json_parse_clients(json_t *element, struct og_msg_params *params) { 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_STRING) return -1; params->ips_array[params->ips_array_len++] = json_string_value(k); params->flags |= OG_REST_PARAM_ADDR; } return 0; } int og_json_parse_partition_setup(json_t *element, struct og_msg_params *params) { unsigned int i; json_t *k; if (json_typeof(element) != JSON_ARRAY) return -1; for (i = 0; i < json_array_size(element) && i < OG_PARTITION_MAX; ++i) { k = json_array_get(element, i); if (json_typeof(k) != JSON_OBJECT) return -1; if (og_json_parse_partition(k, ¶ms->partition_setup[i], OG_PARAM_PART_NUMBER | OG_PARAM_PART_CODE | OG_PARAM_PART_FILESYSTEM | OG_PARAM_PART_SIZE | OG_PARAM_PART_FORMAT) < 0) return -1; params->flags |= (OG_REST_PARAM_PART_0 << i); } return 0; } static int og_json_parse_time_params(json_t *element, struct og_msg_params *params) { const char *key; json_t *value; int err = 0; json_object_foreach(element, key, value) { if (!strcmp(key, "years")) { err = og_json_parse_uint(value, ¶ms->time.years); params->flags |= OG_REST_PARAM_TIME_YEARS; } else if (!strcmp(key, "months")) { err = og_json_parse_uint(value, ¶ms->time.months); params->flags |= OG_REST_PARAM_TIME_MONTHS; } else if (!strcmp(key, "weeks")) { err = og_json_parse_uint(value, ¶ms->time.weeks); params->flags |= OG_REST_PARAM_TIME_WEEKS; } else if (!strcmp(key, "week_days")) { err = og_json_parse_uint(value, ¶ms->time.week_days); params->flags |= OG_REST_PARAM_TIME_WEEK_DAYS; } else if (!strcmp(key, "days")) { err = og_json_parse_uint(value, ¶ms->time.days); params->flags |= OG_REST_PARAM_TIME_DAYS; } else if (!strcmp(key, "hours")) { err = og_json_parse_uint(value, ¶ms->time.hours); params->flags |= OG_REST_PARAM_TIME_HOURS; } else if (!strcmp(key, "am_pm")) { err = og_json_parse_uint(value, ¶ms->time.am_pm); params->flags |= OG_REST_PARAM_TIME_AM_PM; } else if (!strcmp(key, "minutes")) { err = og_json_parse_uint(value, ¶ms->time.minutes); params->flags |= OG_REST_PARAM_TIME_MINUTES; } if (err != 0) return err; } return err; } static const char *og_cmd_to_uri[OG_CMD_MAX] = { [OG_CMD_WOL] = "wol", [OG_CMD_PROBE] = "probe", [OG_CMD_SHELL_RUN] = "shell/run", [OG_CMD_SESSION] = "session", [OG_CMD_POWEROFF] = "poweroff", [OG_CMD_REFRESH] = "refresh", [OG_CMD_REBOOT] = "reboot", [OG_CMD_STOP] = "stop", [OG_CMD_HARDWARE] = "hardware", [OG_CMD_SOFTWARE] = "software", [OG_CMD_IMAGE_CREATE] = "image/create", [OG_CMD_IMAGE_RESTORE] = "image/restore", [OG_CMD_SETUP] = "setup", [OG_CMD_RUN_SCHEDULE] = "run/schedule", [OG_CMD_IMAGES] = "images", }; static bool og_client_is_busy(const struct og_client *cli, enum og_cmd_type type) { switch (type) { case OG_CMD_REBOOT: case OG_CMD_POWEROFF: case OG_CMD_STOP: break; default: if (cli->last_cmd != OG_CMD_UNSPEC) return true; break; } return false; } int og_send_request(enum og_rest_method method, enum og_cmd_type type, const struct og_msg_params *params, const json_t *data) { const char *content_type = "Content-Type: application/json"; char content [OG_MSG_REQUEST_MAXLEN - 700] = {}; char buf[OG_MSG_REQUEST_MAXLEN] = {}; unsigned int content_length; char method_str[5] = {}; struct og_client *cli; const char *uri; unsigned int i; int client_sd; bool has_seq; if (method == OG_METHOD_GET) snprintf(method_str, 5, "GET"); else if (method == OG_METHOD_POST) snprintf(method_str, 5, "POST"); else return -1; if (!data) content_length = 0; else content_length = json_dumpb(data, content, OG_MSG_REQUEST_MAXLEN - 700, JSON_COMPACT); uri = og_cmd_to_uri[type]; switch (type) { case OG_CMD_POWEROFF: case OG_CMD_REBOOT: case OG_CMD_STOP: has_seq = false; break; default: has_seq = true; break; } for (i = 0; i < params->ips_array_len; i++) { cli = og_client_find(params->ips_array[i]); if (!cli) continue; if (og_client_is_busy(cli, type)) continue; client_sd = cli->io.fd; if (client_sd < 0) { syslog(LOG_INFO, "Client %s not conected\n", params->ips_array[i]); continue; } if (++cli->seq == 0) cli->seq++; snprintf(buf, OG_MSG_REQUEST_MAXLEN, "%s /%s HTTP/1.1\r\nContent-Length: %d\r\nX-Sequence: %u\r\n%s\r\n\r\n%s", method_str, uri, content_length, has_seq ? cli->seq : 0, content_type, content); if (send(client_sd, buf, strlen(buf), 0) < 0) continue; cli->last_cmd = type; } json_decref((json_t *)data); return 0; } static int og_cmd_post_clients(json_t *element, struct og_msg_params *params) { 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, "clients")) err = og_json_parse_clients(value, params); if (err < 0) return err; } if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR)) return -1; return og_send_request(OG_METHOD_POST, OG_CMD_PROBE, params, NULL); } struct og_buffer { char *data; int len; }; #define OG_MSG_RESPONSE_MAXLEN 262144 static int og_json_dump_clients(const char *buffer, size_t size, void *data) { struct og_buffer *og_buffer = (struct og_buffer *)data; if (size >= OG_MSG_RESPONSE_MAXLEN - og_buffer->len) { syslog(LOG_ERR, "Response JSON body is too large\n"); return -1; } memcpy(og_buffer->data + og_buffer->len, buffer, size); og_buffer->len += size; return 0; } static const char *og_cmd_result_str_array[] = { [OG_UNKNOWN] = "unknown", [OG_FAILURE] = "failure", [OG_SUCCESS] = "success", }; static const char *og_cmd_result_str(const enum og_cmd_result result) { if (result > OG_SUCCESS) return "unknown"; return og_cmd_result_str_array[result]; } static json_t *og_json_client_cmd_result(const enum og_cmd_result result) { const char *result_str; json_t *last_cmd; last_cmd = json_object(); result_str = og_cmd_result_str(result); json_object_set_new(last_cmd, "result", json_string(result_str)); return last_cmd; } static int og_json_client_append(json_t *array, struct og_client *client) { json_t *addr, *state, *last_cmd, *object; object = json_object(); if (!object) return -1; addr = json_string(inet_ntoa(client->addr.sin_addr)); if (!addr) { json_decref(object); return -1; } json_object_set_new(object, "addr", addr); state = json_string(og_client_status(client)); if (!state) { json_decref(object); return -1; } json_object_set_new(object, "state", state); json_object_set_new(object, "speed", json_integer(client->speed)); last_cmd = og_json_client_cmd_result(client->last_cmd_result); json_object_set_new(object, "last_cmd", last_cmd); json_array_append_new(array, object); return 0; } static int og_json_client_wol_append(json_t *array, struct og_client_wol *cli_wol) { json_t *addr, *state, *last_cmd, *object; object = json_object(); if (!object) return -1; addr = json_string(inet_ntoa(cli_wol->addr)); if (!addr) { json_decref(object); return -1; } json_object_set_new(object, "addr", addr); state = json_string(og_client_wol_status(cli_wol)); if (!state) { json_decref(object); return -1; } json_object_set_new(object, "state", state); last_cmd = og_json_client_cmd_result(OG_UNKNOWN); json_object_set_new(object, "last_cmd", last_cmd); json_array_append_new(array, object); return 0; } static int og_cmd_get_clients(json_t *element, struct og_msg_params *params, char *buffer_reply) { struct og_buffer og_buffer = { .data = buffer_reply, }; struct og_client_wol *cli_wol; struct og_client *client; json_t *array, *root; array = json_array(); if (!array) return -1; list_for_each_entry(cli_wol, &client_wol_list, list) { if (og_json_client_wol_append(array, cli_wol) < 0) { json_decref(array); return -1; } } list_for_each_entry(client, &client_list, list) { if (!client->agent) continue; if (og_json_client_append(array, client) < 0) { json_decref(array); return -1; } } root = json_pack("{s:o}", "clients", array); if (!root) { json_decref(array); return -1; } if (json_dump_callback(root, og_json_dump_clients, &og_buffer, 0)) { json_decref(root); return -1; } json_decref(root); return 0; } static int og_json_parse_type(json_t *element, struct og_msg_params *params) { const char *type; if (json_typeof(element) != JSON_STRING) return -1; params->wol_type = json_string_value(element); type = json_string_value(element); if (!strcmp(type, "unicast")) params->wol_type = "2"; else if (!strcmp(type, "broadcast")) params->wol_type = "1"; params->flags |= OG_REST_PARAM_WOL_TYPE; return 0; } struct og_client_wol *og_client_wol_find(const struct in_addr *addr) { struct og_client_wol *cli_wol; list_for_each_entry(cli_wol, &client_wol_list, list) { if (cli_wol->addr.s_addr == addr->s_addr) return cli_wol; } return NULL; } static int og_cmd_wol(json_t *element, struct og_msg_params *params) { char ips_str[(OG_DB_IP_MAXLEN + 1) * OG_CLIENTS_MAX + 1] = {}; struct og_msg_params new_params = {}; struct og_client_wol *cli_wol; struct in_addr addr, netmask; int ips_str_len = 0; const char *msglog; struct og_dbi *dbi; int err = 0, i = 0; dbi_result result; const char *key; json_t *value; int sd; if (json_typeof(element) != JSON_OBJECT) return -1; json_object_foreach(element, key, value) { if (!strcmp(key, "clients")) { err = og_json_parse_clients(value, params); } else if (!strcmp(key, "type")) { err = og_json_parse_type(value, params); } if (err < 0) return err; } if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR | OG_REST_PARAM_WOL_TYPE)) return -1; for (i = 0; i < params->ips_array_len; ++i) { ips_str_len += snprintf(ips_str + ips_str_len, sizeof(ips_str) - ips_str_len, "'%s',", params->ips_array[i]); } ips_str[ips_str_len - 1] = '\0'; dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", __func__, __LINE__); return -1; } result = dbi_conn_queryf(dbi->conn, "SELECT ordenadores.ip, ordenadores.mac, " "aulas.netmask " "FROM ordenadores " "INNER JOIN aulas " "ON ordenadores.idaula = aulas.idaula " "WHERE ordenadores.ip IN (%s)", ips_str); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); og_dbi_close(dbi); return -1; } for (i = 0; dbi_result_next_row(result); i++) { if (i >= OG_CLIENTS_MAX) { syslog(LOG_ERR, "too many IPs in WoL (%s:%d)\n", __func__, __LINE__); dbi_result_free(result); og_dbi_close(dbi); goto err_free_params; } new_params.ips_array[i] = dbi_result_get_string_copy(result, "ip"); new_params.mac_array[i] = dbi_result_get_string_copy(result, "mac"); new_params.netmask_array[i] = dbi_result_get_string_copy(result, "netmask"); } new_params.ips_array_len = i; dbi_result_free(result); og_dbi_close(dbi); if (i == 0) return 0; sd = wol_socket_open(); if (sd < 0) { syslog(LOG_ERR, "cannot open wol socket (%s:%d)\n", __func__, __LINE__); goto err_free_params; } for (i = 0; i < new_params.ips_array_len; i++) { if (og_client_find(new_params.ips_array[i])) continue; if (inet_aton(new_params.ips_array[i], &addr) < 0) continue; cli_wol = og_client_wol_find(&addr); if (cli_wol) { og_client_wol_refresh(cli_wol); continue; } cli_wol = og_client_wol_create(&addr); if (!cli_wol) goto err_out; list_add_tail(&cli_wol->list, &client_wol_list); if (inet_aton(new_params.netmask_array[i], &netmask) < 0) continue; if (wake_up(sd, &addr, &netmask, new_params.mac_array[i], atoi(params->wol_type)) < 0) { syslog(LOG_ERR, "Failed to send wol packet to %s\n", new_params.ips_array[i]); continue; } } err_out: close(sd); err_free_params: for (i = 0; i < new_params.ips_array_len; ++i) { free((void *)new_params.ips_array[i]); free((void *)new_params.mac_array[i]); free((void *)new_params.netmask_array[i]); } return 0; } static int og_json_parse_run(json_t *element, struct og_msg_params *params) { if (json_typeof(element) != JSON_STRING) return -1; snprintf(params->run_cmd, sizeof(params->run_cmd), "%s", json_string_value(element)); params->flags |= OG_REST_PARAM_RUN_CMD; return 0; } static int og_cmd_run_post(json_t *element, struct og_msg_params *params) { json_t *value, *clients; const char *key; int err = 0; if (json_typeof(element) != JSON_OBJECT) return -1; json_object_foreach(element, key, value) { if (!strcmp(key, "clients")) err = og_json_parse_clients(value, params); else if (!strcmp(key, "run")) err = og_json_parse_run(value, params); else if (!strcmp(key, "echo")) { err = og_json_parse_bool(value, ¶ms->echo); params->flags |= OG_REST_PARAM_ECHO; } if (err < 0) return err; } if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR | OG_REST_PARAM_RUN_CMD | OG_REST_PARAM_ECHO)) return -1; clients = json_copy(element); json_object_del(clients, "clients"); return og_send_request(OG_METHOD_POST, OG_CMD_SHELL_RUN, params, clients); } static int og_cmd_run_get(json_t *element, struct og_msg_params *params, char *buffer_reply) { struct og_buffer og_buffer = { .data = buffer_reply, }; json_t *root, *value, *array; const char *key; unsigned int i; int err = 0; if (json_typeof(element) != JSON_OBJECT) return -1; json_object_foreach(element, key, value) { if (!strcmp(key, "clients")) err = og_json_parse_clients(value, params); if (err < 0) return err; } if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR)) return -1; array = json_array(); if (!array) return -1; for (i = 0; i < params->ips_array_len; i++) { json_t *object, *output, *addr; struct og_client *cli; cli = og_client_find(params->ips_array[i]); if (!cli) continue; object = json_object(); if (!object) { json_decref(array); return -1; } addr = json_string(params->ips_array[i]); if (!addr) { json_decref(object); json_decref(array); return -1; } json_object_set_new(object, "addr", addr); output = json_string(cli->shell_output); if (!output) { json_decref(object); json_decref(array); return -1; } json_object_set_new(object, "output", output); json_array_append_new(array, object); } root = json_pack("{s:o}", "clients", array); if (!root) return -1; if (json_dump_callback(root, og_json_dump_clients, &og_buffer, 0)) { json_decref(root); return -1; } json_decref(root); return 0; } static int og_cmd_session(json_t *element, struct og_msg_params *params) { json_t *clients, *value; const char *key; int err = 0; if (json_typeof(element) != JSON_OBJECT) return -1; json_object_foreach(element, key, value) { if (!strcmp(key, "clients")) { err = og_json_parse_clients(value, params); } else if (!strcmp(key, "disk")) { err = og_json_parse_string(value, ¶ms->disk); params->flags |= OG_REST_PARAM_DISK; } else if (!strcmp(key, "partition")) { err = og_json_parse_string(value, ¶ms->partition); params->flags |= OG_REST_PARAM_PARTITION; } if (err < 0) return err; } if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR | OG_REST_PARAM_DISK | OG_REST_PARAM_PARTITION)) return -1; clients = json_copy(element); json_object_del(clients, "clients"); return og_send_request(OG_METHOD_POST, OG_CMD_SESSION, params, clients); } static int og_cmd_get_session(json_t *element, struct og_msg_params *params, char *buffer_reply) { json_t *value, *root, *array, *item; const char *key, *msglog, *os_name; unsigned int disk, partition; struct og_dbi *dbi; dbi_result result; int err = 0; struct og_buffer og_buffer = { .data = buffer_reply }; json_object_foreach(element, key, value) { if (!strcmp(key, "client")) err = og_json_parse_clients(value, params); else err = -1; if (err < 0) return err; } if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR)) return -1; dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", __func__, __LINE__); return -1; } result = dbi_conn_queryf(dbi->conn, "SELECT op.numdisk, op.numpar, nom.nombreso " "FROM ordenadores o " "INNER JOIN ordenadores_particiones op " " ON o.idordenador = op.idordenador " "INNER JOIN nombresos nom " " ON op.idnombreso = nom.idnombreso " "WHERE o.ip = '%s'", params->ips_array[0]); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); og_dbi_close(dbi); return -1; } array = json_array(); if (!array) { dbi_result_free(result); og_dbi_close(dbi); return -1; } while (dbi_result_next_row(result)) { item = json_object(); if (!item) { dbi_result_free(result); og_dbi_close(dbi); json_decref(array); return -1; } disk = dbi_result_get_uint(result, "numdisk"); partition = dbi_result_get_uint(result, "numpar"); os_name = dbi_result_get_string(result, "nombreso"); json_object_set_new(item, "disk", json_integer(disk)); json_object_set_new(item, "partition", json_integer(partition)); json_object_set_new(item, "name", json_string(os_name)); json_array_append_new(array, item); } dbi_result_free(result); og_dbi_close(dbi); root = json_object(); if (!root){ json_decref(array); return -1; } json_object_set_new(root, "sessions", array); if (json_dump_callback(root, og_json_dump_clients, &og_buffer, 0)) { json_decref(root); return -1; } json_decref(root); return 0; } static int og_cmd_poweroff(json_t *element, struct og_msg_params *params) { 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, "clients")) err = og_json_parse_clients(value, params); if (err < 0) return err; } if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR)) return -1; return og_send_request(OG_METHOD_POST, OG_CMD_POWEROFF, params, NULL); } static int og_cmd_refresh(json_t *element, struct og_msg_params *params) { 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, "clients")) err = og_json_parse_clients(value, params); if (err < 0) return err; } if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR)) return -1; return og_send_request(OG_METHOD_GET, OG_CMD_REFRESH, params, NULL); } static int og_cmd_reboot(json_t *element, struct og_msg_params *params) { 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, "clients")) err = og_json_parse_clients(value, params); if (err < 0) return err; } if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR)) return -1; return og_send_request(OG_METHOD_POST, OG_CMD_REBOOT, params, NULL); } #define OG_TFTP_TMPL_PATH_UEFI "/opt/opengnsys/tftpboot/grub/templates" #define OG_TFTP_TMPL_PATH "/opt/opengnsys/tftpboot/menu.lst/templates" struct og_boot_mode { struct list_head list; char name[FILENAME_MAX]; }; static void og_boot_mode_free(struct list_head *boot_mode_list) { struct og_boot_mode *mode, *tmp; list_for_each_entry_safe(mode, tmp, boot_mode_list, list) { list_del(&mode->list); free(mode); } } static int og_get_boot_modes(struct list_head *boot_mode_list) { struct og_boot_mode *mode; struct dirent *dent; DIR *d; d = opendir(OG_TFTP_TMPL_PATH); if (!d) { syslog(LOG_ERR, "Cannot open directory %s (%s:%d)\n", OG_TFTP_TMPL_PATH, __func__, __LINE__); return -1; } dent = readdir(d); while (dent) { if (dent->d_type != DT_REG) { dent = readdir(d); continue; } mode = calloc(1, sizeof(struct og_boot_mode)); if (!mode) { closedir(d); og_boot_mode_free(boot_mode_list); return -1; } snprintf(mode->name, FILENAME_MAX, "%s", dent->d_name); list_add_tail(&mode->list, boot_mode_list); dent = readdir(d); } closedir(d); return 0; } static int og_cmd_get_modes(json_t *element, struct og_msg_params *params, char *buffer_reply) { struct og_buffer og_buffer = { .data = buffer_reply }; struct og_boot_mode *mode; LIST_HEAD(boot_mode_list); json_t *root, *modes; int ret; root = json_object(); if (!root) return -1; modes = json_array(); if (!modes) { json_decref(root); return -1; } if (og_get_boot_modes(&boot_mode_list) < 0) { json_decref(modes); json_decref(root); return -1; } list_for_each_entry(mode, &boot_mode_list, list) json_array_append_new(modes, json_string(mode->name)); og_boot_mode_free(&boot_mode_list); json_object_set_new(root, "modes", modes); ret = json_dump_callback(root, og_json_dump_clients, &og_buffer, 0); json_decref(root); return ret; } static int og_change_db_mode(struct og_dbi *dbi, const char *mac, const char * mode) { const char *msglog; dbi_result result; result = dbi_conn_queryf(dbi->conn, "UPDATE ordenadores SET arranque='%s' " "WHERE mac='%s'", mode, mac); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } dbi_result_free(result); return 0; } static bool og_boot_mode_is_valid(const char *name) { struct og_boot_mode *mode; LIST_HEAD(boot_mode_list); bool found = false; if (og_get_boot_modes(&boot_mode_list) < 0) { syslog(LOG_ERR, "failed to get boot mode list (%s:%d)\n", __FILE__, __LINE__); return false; } list_for_each_entry(mode, &boot_mode_list, list) { if (!strncmp(name, mode->name, FILENAME_MAX)) { found = true; break; } } og_boot_mode_free(&boot_mode_list); return found; } static int og_set_client_mode(struct og_dbi *dbi, const char *mac, const char *mode) { char filename[PATH_MAX + 1] = "/tmp/mode_params_XXXXXX"; char cmd_params[16384] = {}; char params[4096] = "\0"; const char *msglog; dbi_result result; unsigned int i; int numbytes; int status; int fd; if (!og_boot_mode_is_valid(mode)) { syslog(LOG_ERR, "invalid boot mode in client (%s:%d)\n", __FILE__, __LINE__); return -1; } result = dbi_conn_queryf(dbi->conn, "SELECT ' LANG=%s', " "' ip=', CONCAT_WS(':', ordenadores.ip, (@serverip:=entornos.ipserveradm), aulas.router, aulas.netmask, ordenadores.nombreordenador, ordenadores.netiface, 'none'), " "' group=', REPLACE(TRIM(aulas.nombreaula), ' ', '_'), " "' ogrepo=', (@repoip:=IFNULL(repositorios.ip, '')), " "' oglive=', @serverip, " "' oglog=', @serverip, " "' ogshare=', @serverip, " "' oglivedir=', ordenadores.oglivedir, " "' ogprof=', IF(ordenadores.idordenador=aulas.idordprofesor, 'true', 'false'), " "' server=', @serverip, " "IF(perfileshard.descripcion<>'', CONCAT(' hardprofile=', REPLACE(TRIM(perfileshard.descripcion), ' ', '_')), ''), " "IF(aulas.ntp<>'', CONCAT(' ogntp=', aulas.ntp), ''), " "IF(aulas.dns<>'', CONCAT(' ogdns=', aulas.dns), ''), " "IF(aulas.proxy<>'', CONCAT(' ogproxy=', aulas.proxy), ''), " "IF(entidades.ogunit=1 AND NOT centros.directorio='', CONCAT(' ogunit=', centros.directorio), ''), " "CASE WHEN menus.resolucion IS NULL THEN '' " "WHEN menus.resolucion <= '999' THEN CONCAT(' vga=', menus.resolucion) " "WHEN menus.resolucion LIKE '%:%' THEN CONCAT(' video=', menus.resolucion) " "ELSE menus.resolucion END " "FROM ordenadores " "JOIN aulas USING(idaula) " "JOIN centros USING(idcentro) " "JOIN entidades USING(identidad) " "JOIN entornos USING(identorno) " "LEFT JOIN repositorios USING(idrepositorio) " "LEFT JOIN perfileshard USING(idperfilhard) " "LEFT JOIN menus USING(idmenu) " "WHERE ordenadores.mac='%s'", getenv("LANG"), mac); if (dbi_result_get_numrows(result) != 1) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __FILE__, __LINE__, msglog); dbi_result_free(result); return -1; } dbi_result_next_row(result); for (i = 1; i <= dbi_result_get_numfields(result); ++i) strcat(params, dbi_result_get_string_idx(result, i)); dbi_result_free(result); snprintf(cmd_params, sizeof(cmd_params), "MODE_FILE='%s'\nMAC='%s'\nDATA='%s'\nMODE='PERM'", mode, mac, params); fd = mkstemp(filename); if (fd < 0) { syslog(LOG_ERR, "cannot generate temp file (%s:%d)\n", __func__, __LINE__); return -1; } numbytes = write(fd, cmd_params, strlen(cmd_params) + 1); close(fd); if (numbytes < 0) { syslog(LOG_ERR, "cannot write file\n"); unlink(filename); return -1; } if (fork() == 0) { execlp("/bin/bash", "/bin/bash", "/opt/opengnsys/bin/setclientmode", filename, NULL); syslog(LOG_ERR, "failed script execution (%s:%d)\n", __func__, __LINE__); exit(EXIT_FAILURE); } else { wait(&status); } unlink(filename); if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { syslog(LOG_ERR, "failed script execution (%s:%d)\n", __func__, __LINE__); return -1; } if (og_change_db_mode(dbi, mac, mode) < 0) { syslog(LOG_ERR, "failed to change db mode (%s:%d)\n", __func__, __LINE__); return -1; } return 0; } static int og_cmd_post_modes(json_t *element, struct og_msg_params *params) { char ips_str[(OG_DB_IP_MAXLEN + 1) * OG_CLIENTS_MAX + 1] = {}; const char *mode_str, *mac; int ips_str_len = 0; struct og_dbi *dbi; uint64_t flags = 0; dbi_result result; const char *key; json_t *value; int err = 0; int i; json_object_foreach(element, key, value) { if (!strcmp(key, "clients")) { err = og_json_parse_clients(value, params); } else if (!strcmp(key, "mode")) { err = og_json_parse_string(value, &mode_str); flags |= OG_REST_PARAM_MODE; } else { err = -1; } if (err < 0) return err; } if (!og_flags_validate(flags, OG_REST_PARAM_MODE) || !og_msg_params_validate(params, OG_REST_PARAM_ADDR)) return -1; for (i = 0; i < params->ips_array_len; ++i) { ips_str_len += snprintf(ips_str + ips_str_len, sizeof(ips_str) - ips_str_len, "'%s',", params->ips_array[i]); } ips_str[ips_str_len - 1] = '\0'; dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", __func__, __LINE__); return -1; } result = dbi_conn_queryf(dbi->conn, "SELECT mac FROM ordenadores " "WHERE ip IN (%s)", ips_str); while (dbi_result_next_row(result)) { mac = dbi_result_get_string(result, "mac"); err = og_set_client_mode(dbi, mac, mode_str); if (err != 0) { dbi_result_free(result); og_dbi_close(dbi); return -1; } } dbi_result_free(result); og_dbi_close(dbi); return 0; } static int og_cmd_get_client_setup(json_t *element, struct og_msg_params *params, char *buffer_reply) { json_t *value, *root, *partitions_array, *partition_json; const char *key, *msglog; unsigned int len_part; struct og_dbi *dbi; dbi_result result; int err = 0; struct og_buffer og_buffer = { .data = buffer_reply }; struct { int disk; int number; int code; uint64_t size; int filesystem; int format; int os; int used_size; int image; int software; } partition; json_object_foreach(element, key, value) { if (!strcmp(key, "client")) { err = og_json_parse_clients(value, params); } if (err < 0) return err; } if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR)) return -1; if (params->ips_array_len != 1) return -1; root = json_object(); if (!root) return -1; partitions_array = json_array(); if (!partitions_array) { json_decref(root); return -1; } json_object_set_new(root, "partitions", partitions_array); dbi = og_dbi_open(&ogconfig.db); if (!dbi) { json_decref(root); syslog(LOG_ERR, "cannot open conection database (%s:%d)\n", __func__, __LINE__); return -1; } result = dbi_conn_queryf(dbi->conn, "SELECT numdisk, numpar, codpar, tamano, " " uso, idsistemafichero, idnombreso, " " idimagen, idperfilsoft " "FROM ordenadores_particiones " "INNER JOIN ordenadores " "ON ordenadores.idordenador = ordenadores_particiones.idordenador " "WHERE ordenadores.ip='%s'", params->ips_array[0]); if (!result) { json_decref(root); dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); og_dbi_close(dbi); return -1; } len_part = 0; /* partition 0 represents the full disk, hence OG_PARTITION_MAX + 1. */ while (dbi_result_next_row(result) && len_part < OG_PARTITION_MAX + 1) { partition.disk = dbi_result_get_int(result, "numdisk"); partition.number = dbi_result_get_int(result, "numpar"); partition.code = dbi_result_get_int(result, "codpar"); partition.size = dbi_result_get_longlong(result, "tamano"); partition.used_size = dbi_result_get_int(result, "uso"); partition.filesystem = dbi_result_get_int(result, "idsistemafichero"); partition.os = dbi_result_get_int(result, "idnombreso"); partition.image = dbi_result_get_int(result, "idimagen"); partition.software = dbi_result_get_int(result, "idperfilsoft"); partition_json = json_object(); if (!partition_json) { json_decref(root); dbi_result_free(result); og_dbi_close(dbi); return -1; } json_object_set_new(partition_json, "disk", json_integer(partition.disk)); json_object_set_new(partition_json, "partition", json_integer(partition.number)); json_object_set_new(partition_json, "code", json_integer(partition.code)); json_object_set_new(partition_json, "size", json_integer(partition.size)); json_object_set_new(partition_json, "used_size", json_integer(partition.used_size)); json_object_set_new(partition_json, "filesystem", json_integer(partition.filesystem)); json_object_set_new(partition_json, "os", json_integer(partition.os)); json_object_set_new(partition_json, "image", json_integer(partition.image)); json_object_set_new(partition_json, "software", json_integer(partition.software)); json_array_append_new(partitions_array, partition_json); ++len_part; } dbi_result_free(result); og_dbi_close(dbi); if (json_dump_callback(root, og_json_dump_clients, &og_buffer, 0)) { json_decref(root); return -1; } json_decref(root); return 0; } static int og_dbi_update_client_entorno(struct og_dbi *dbi, const char *mac, const char *server_id) { const char *msglog; dbi_result result; result = dbi_conn_queryf(dbi->conn, "UPDATE ordenadores SET identorno=%s " "WHERE mac='%s'", server_id, mac); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to update client's server (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } dbi_result_free(result); return 0; } static int og_dbi_update_client_repo(struct og_dbi *dbi, const char *mac, const char *repo_id) { const char *msglog; dbi_result result; result = dbi_conn_queryf(dbi->conn, "UPDATE ordenadores SET idrepositorio=%s " "WHERE mac='%s'", repo_id, mac); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to update client's server (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } dbi_result_free(result); return 0; } static int og_cmd_post_client_repo(json_t *element, struct og_msg_params *params, char *buffer_reply) { char ips_str[(OG_DB_IP_MAXLEN + 1) * OG_CLIENTS_MAX + 1] = {}; const char *key, *msglog, *mac; int ips_str_len = 0; struct og_dbi *dbi; dbi_result result; int err = 0, i; json_t *value; json_object_foreach(element, key, value) { if (!strcmp(key, "clients")) { err = og_json_parse_clients(value, params); } else if (!strcmp(key, "id")) { err = og_json_parse_string(value, ¶ms->id); params->flags |= OG_REST_PARAM_ID; } if (err < 0) return err; } if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR | OG_REST_PARAM_ID)) return -1; dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open conection database (%s:%d)\n", __func__, __LINE__); return -1; } for (i = 0; i < params->ips_array_len; ++i) { ips_str_len += snprintf(ips_str + ips_str_len, sizeof(ips_str) - ips_str_len, "'%s',", params->ips_array[i]); } ips_str[ips_str_len - 1] = '\0'; result = dbi_conn_queryf(dbi->conn, "SELECT mac FROM ordenadores " "WHERE ip IN (%s)", ips_str); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); og_dbi_close(dbi); return -1; } while (dbi_result_next_row(result)) { mac = dbi_result_get_string(result, "mac"); err = og_dbi_update_client_repo(dbi, mac, params->id); if (err != 0) { dbi_result_free(result); og_dbi_close(dbi); return -1; } } dbi_result_free(result); og_dbi_close(dbi); return 0; } static int og_cmd_post_client_server(json_t *element, struct og_msg_params *params, char *buffer_reply) { char ips_str[(OG_DB_IP_MAXLEN + 1) * OG_CLIENTS_MAX + 1] = {}; const char *key, *msglog, *mac; int ips_str_len = 0; struct og_dbi *dbi; dbi_result result; int err = 0, i; json_t *value; json_object_foreach(element, key, value) { if (!strcmp(key, "clients")) { err = og_json_parse_clients(value, params); } else if (!strcmp(key, "id")) { err = og_json_parse_string(value, ¶ms->id); params->flags |= OG_REST_PARAM_ID; } if (err < 0) return err; } if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR | OG_REST_PARAM_ID)) return -1; dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open conection database (%s:%d)\n", __func__, __LINE__); return -1; } for (i = 0; i < params->ips_array_len; ++i) { ips_str_len += snprintf(ips_str + ips_str_len, sizeof(ips_str) - ips_str_len, "'%s',", params->ips_array[i]); } ips_str[ips_str_len - 1] = '\0'; result = dbi_conn_queryf(dbi->conn, "SELECT mac FROM ordenadores " "WHERE ip IN (%s)", ips_str); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); og_dbi_close(dbi); return -1; } while (dbi_result_next_row(result)) { mac = dbi_result_get_string(result, "mac"); err = og_dbi_update_client_entorno(dbi, mac, params->id); if (err != 0) { dbi_result_free(result); og_dbi_close(dbi); return -1; } } dbi_result_free(result); og_dbi_close(dbi); return 0; } static int og_cmd_get_client_info(json_t *element, struct og_msg_params *params, char *buffer_reply) { struct og_computer computer = {}; json_t *value, *root; struct in_addr addr; struct og_dbi *dbi; const char *key; int err = 0; struct og_buffer og_buffer = { .data = buffer_reply }; json_object_foreach(element, key, value) { if (!strcmp(key, "client")) { err = og_json_parse_clients(value, params); } if (err < 0) return err; } if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR)) return -1; if (params->ips_array_len != 1) return -1; if (inet_aton(params->ips_array[0], &addr) == 0) return -1; dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open conection database (%s:%d)\n", __func__, __LINE__); return -1; } if (og_dbi_get_computer_info(dbi, &computer, addr)) { og_dbi_close(dbi); return -1; } og_dbi_close(dbi); root = json_object(); if (!root) return -1; json_object_set_new(root, "serial_number", json_string(computer.serial_number)); json_object_set_new(root, "hardware_id", json_integer(computer.hardware_id)); json_object_set_new(root, "server_id", json_integer(computer.server_id)); json_object_set_new(root, "netdriver", json_string(computer.netdriver)); json_object_set_new(root, "maintenance", json_boolean(computer.maintenance)); json_object_set_new(root, "netiface", json_string(computer.netiface)); json_object_set_new(root, "repo_id", json_integer(computer.repo_id)); json_object_set_new(root, "livedir", json_string(computer.livedir)); json_object_set_new(root, "netmask", json_string(computer.netmask)); json_object_set_new(root, "center", json_integer(computer.center)); json_object_set_new(root, "remote", json_boolean(computer.remote)); json_object_set_new(root, "room", json_integer(computer.room)); json_object_set_new(root, "name", json_string(computer.name)); json_object_set_new(root, "boot", json_string(computer.boot)); json_object_set_new(root, "mac", json_string(computer.mac)); json_object_set_new(root, "id", json_integer(computer.id)); json_object_set_new(root, "ip", json_string(computer.ip)); if (json_dump_callback(root, og_json_dump_clients, &og_buffer, 0)) { json_decref(root); return -1; } json_decref(root); return 0; } static int og_cmd_post_client_update(json_t *element, struct og_msg_params *params, char *buffer_reply) { struct og_computer computer = {}; const char *key, *msglog; struct og_dbi *dbi; dbi_result result; json_t *value; int err = 0; json_object_foreach(element, key, value) { if (!strcmp(key, "ip")) { err = og_json_parse_string_copy(value, computer.ip, sizeof(computer.ip)); params->flags |= OG_REST_PARAM_ADDR; } else if (!strcmp(key, "serial_number")) { err = og_json_parse_string_copy(value, computer.serial_number, sizeof(computer.serial_number)); } else if (!strcmp(key, "netdriver")) { err = og_json_parse_string_copy(value, computer.netdriver, sizeof(computer.netdriver)); } else if (!strcmp(key, "maintenance")) { err = og_json_parse_bool(value, &computer.maintenance); } else if (!strcmp(key, "netiface")) { err = og_json_parse_string_copy(value, computer.netiface, sizeof(computer.netiface)); } else if (!strcmp(key, "repo_id")) { err = og_json_parse_uint(value, &computer.repo_id); } else if (!strcmp(key, "netmask")) { err = og_json_parse_string_copy(value, computer.netmask, sizeof(computer.netmask)); } else if (!strcmp(key, "remote")) { err = og_json_parse_bool(value, &computer.remote); } else if (!strcmp(key, "room")) { err = og_json_parse_uint(value, &computer.room); } else if (!strcmp(key, "name")) { err = og_json_parse_string_copy(value, computer.name, sizeof(computer.name)); } else if (!strcmp(key, "mac")) { err = og_json_parse_string_copy(value, computer.mac, sizeof(computer.mac)); } if (err < 0) return err; } if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR)) return -1; dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open conection database (%s:%d)\n", __func__, __LINE__); return -1; } result = dbi_conn_queryf(dbi->conn, "SELECT ip FROM ordenadores WHERE ip='%s'", computer.ip); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); og_dbi_close(dbi); return -1; } if (dbi_result_get_numrows(result) == 0) { syslog(LOG_ERR, "client with that IP does not exist: %s\n", computer.ip); dbi_result_free(result); og_dbi_close(dbi); return -1; } result = dbi_conn_queryf(dbi->conn, "UPDATE ordenadores" " SET numserie='%s'," " netdriver='%s'," " maintenance=%u," " netiface='%s'," " idrepositorio=%u," " mascara='%s'," " inremotepc=%u," " idaula=%u," " nombreordenador='%s'," " mac='%s'" " WHERE ip='%s';", computer.serial_number, computer.netdriver, computer.maintenance, computer.netiface, computer.repo_id, computer.netmask, computer.remote, computer.room, computer.name, computer.mac, computer.ip); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to update client in database (%s:%d) %s\n", __func__, __LINE__, msglog); og_dbi_close(dbi); return -1; } dbi_result_free(result); og_dbi_close(dbi); return 0; } static int og_cmd_post_client_add(json_t *element, struct og_msg_params *params, char *buffer_reply) { struct og_computer computer = {}; const char *key, *msglog; struct og_dbi *dbi; dbi_result result; json_t *value; int err = 0; json_object_foreach(element, key, value) { if (!strcmp(key, "serial_number")) { err = og_json_parse_string_copy(value, computer.serial_number, sizeof(computer.serial_number)); } else if (!strcmp(key, "hardware_id")) { err = og_json_parse_uint(value, &computer.hardware_id); } else if (!strcmp(key, "netdriver")) { err = og_json_parse_string_copy(value, computer.netdriver, sizeof(computer.netdriver)); } else if (!strcmp(key, "maintenance")) { err = og_json_parse_bool(value, &computer.maintenance); } else if (!strcmp(key, "netiface")) { err = og_json_parse_string_copy(value, computer.netiface, sizeof(computer.netiface)); } else if (!strcmp(key, "repo_id")) { err = og_json_parse_uint(value, &computer.repo_id); } else if (!strcmp(key, "livedir")) { err = og_json_parse_string_copy(value, computer.livedir, sizeof(computer.livedir)); } else if (!strcmp(key, "netmask")) { err = og_json_parse_string_copy(value, computer.netmask, sizeof(computer.netmask)); } else if (!strcmp(key, "remote")) { err = og_json_parse_bool(value, &computer.remote); } else if (!strcmp(key, "room")) { err = og_json_parse_uint(value, &computer.room); } else if (!strcmp(key, "name")) { err = og_json_parse_string_copy(value, computer.name, sizeof(computer.name)); } else if (!strcmp(key, "boot")) { err = og_json_parse_string_copy(value, computer.boot, sizeof(computer.boot)); } else if (!strcmp(key, "mac")) { err = og_json_parse_string_copy(value, computer.mac, sizeof(computer.mac)); } else if (!strcmp(key, "ip")) { err = og_json_parse_string_copy(value, computer.ip, sizeof(computer.ip)); } if (err < 0) return err; } dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open conection database (%s:%d)\n", __func__, __LINE__); return -1; } result = dbi_conn_queryf(dbi->conn, "SELECT ip FROM ordenadores WHERE ip='%s'", computer.ip); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); og_dbi_close(dbi); return -1; } if (dbi_result_get_numrows(result) > 0) { syslog(LOG_ERR, "client with the same IP already exists: %s\n", computer.ip); dbi_result_free(result); og_dbi_close(dbi); return -1; } dbi_result_free(result); result = dbi_conn_queryf(dbi->conn, "INSERT INTO ordenadores(" " nombreordenador," " numserie," " ip," " mac," " idaula," " grupoid," " idperfilhard," " idrepositorio," " mascara," " arranque," " netiface," " netdriver," " oglivedir," " inremotepc," " maintenance" ") VALUES ('%s', '%s', '%s', '%s', %u, 0, %u," " %u, '%s', '%s', '%s', '%s'," " '%s', %u, %u)", computer.name, computer.serial_number, computer.ip, computer.mac, computer.room, computer.hardware_id, computer.repo_id, computer.netmask, computer.boot, computer.netiface, computer.netdriver, computer.livedir, computer.remote, computer.maintenance); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to add client to database (%s:%d) %s\n", __func__, __LINE__, msglog); og_dbi_close(dbi); return -1; } dbi_result_free(result); if (og_set_client_mode(dbi, computer.mac, computer.boot)) { syslog(LOG_ERR, "failed to set client boot mode (%s:%d)\n", __func__, __LINE__); og_dbi_close(dbi); return -1; } og_dbi_close(dbi); return 0; } static int og_cmd_post_client_delete(json_t *element, struct og_msg_params *params) { const char *key, *msglog; struct og_dbi *dbi; dbi_result result; unsigned int i; json_t *value; int err = 0; json_object_foreach(element, key, value) { if (!strcmp(key, "clients")) err = og_json_parse_clients(value, params); if (err < 0) return err; } if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR)) return -1; dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open conection database (%s:%d)\n", __func__, __LINE__); return -1; } for (i = 0; i < params->ips_array_len; i++) { result = dbi_conn_queryf(dbi->conn, "DELETE FROM ordenadores WHERE ip='%s'", params->ips_array[i]); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); og_dbi_close(dbi); return -1; } if (dbi_result_get_numrows_affected(result) < 1) { dbi_result_free(result); og_dbi_close(dbi); return -1; } dbi_result_free(result); } og_dbi_close(dbi); return 0; } static int og_cmd_get_room_info(json_t *element, struct og_msg_params *params, char *buffer_reply) { struct og_room room = {}; json_t *value, *root; struct og_dbi *dbi; uint32_t room_id; const char *key; int err = 0; struct og_buffer og_buffer = { .data = buffer_reply }; json_object_foreach(element, key, value) { if (!strcmp(key, "id")) { err = og_json_parse_uint(value, &room_id); params->flags |= OG_REST_PARAM_ID; } if (err < 0) return err; } if (!og_msg_params_validate(params, OG_REST_PARAM_ID)) return -1; dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open conection database (%s:%d)\n", __func__, __LINE__); return -1; } if (og_dbi_get_room_info(dbi, &room, room_id)) { og_dbi_close(dbi); return -1; } og_dbi_close(dbi); root = json_object(); if (!root) return -1; json_object_set_new(root, "id", json_integer(room.id)); json_object_set_new(root, "name", json_string(room.name)); json_object_set_new(root, "gateway", json_string(room.gateway)); json_object_set_new(root, "netmask", json_string(room.netmask)); if (json_dump_callback(root, og_json_dump_clients, &og_buffer, 0)) { json_decref(root); return -1; } json_decref(root); return 0; } static int og_cmd_stop(json_t *element, struct og_msg_params *params) { 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, "clients")) err = og_json_parse_clients(value, params); if (err < 0) return err; } if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR)) return -1; return og_send_request(OG_METHOD_POST, OG_CMD_STOP, params, NULL); } static int og_cmd_hardware(json_t *element, struct og_msg_params *params) { 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, "clients")) err = og_json_parse_clients(value, params); if (err < 0) return err; } if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR)) return -1; return og_send_request(OG_METHOD_GET, OG_CMD_HARDWARE, params, NULL); } static int og_cmd_get_hardware(json_t *element, struct og_msg_params *params, char *buffer_reply) { const char *key, *msglog, *hw_item, *hw_type; json_t *value, *root, *array, *item; struct og_dbi *dbi; dbi_result result; int err = 0; struct og_buffer og_buffer = { .data = buffer_reply }; json_object_foreach(element, key, value) { if (!strcmp(key, "client")) err = og_json_parse_clients(value, params); if (err < 0) return err; } if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR)) return -1; dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", __func__, __LINE__); return -1; } result = dbi_conn_queryf(dbi->conn, "SELECT hardwares.descripcion AS item, " " tipohardwares.descripcion AS type " "FROM hardwares " "INNER JOIN perfileshard_hardwares " " ON hardwares.idhardware = perfileshard_hardwares.idhardware " "INNER JOIN ordenadores " " ON perfileshard_hardwares.idperfilhard = ordenadores.idperfilhard " "INNER JOIN tipohardwares " " ON hardwares.idtipohardware = tipohardwares.idtipohardware " "WHERE ordenadores.ip = '%s'", params->ips_array[0]); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); og_dbi_close(dbi); return -1; } array = json_array(); if (!array) { dbi_result_free(result); og_dbi_close(dbi); return -1; } while (dbi_result_next_row(result)) { item = json_object(); if (!item) { dbi_result_free(result); og_dbi_close(dbi); json_decref(array); return -1; } hw_item = dbi_result_get_string(result, "item"); hw_type = dbi_result_get_string(result, "type"); json_object_set_new(item, "type", json_string(hw_type)); json_object_set_new(item, "description", json_string(hw_item)); json_array_append_new(array, item); } dbi_result_free(result); og_dbi_close(dbi); root = json_object(); if (!root){ json_decref(array); return -1; } json_object_set_new(root, "hardware", array); if (json_dump_callback(root, og_json_dump_clients, &og_buffer, 0)) { json_decref(root); return -1; } json_decref(root); return 0; } static int og_cmd_software(json_t *element, struct og_msg_params *params) { json_t *clients, *value; const char *key; int err = 0; if (json_typeof(element) != JSON_OBJECT) return -1; json_object_foreach(element, key, value) { if (!strcmp(key, "clients")) err = og_json_parse_clients(value, params); else if (!strcmp(key, "disk")) { err = og_json_parse_string(value, ¶ms->disk); params->flags |= OG_REST_PARAM_DISK; } else if (!strcmp(key, "partition")) { err = og_json_parse_string(value, ¶ms->partition); params->flags |= OG_REST_PARAM_PARTITION; } if (err < 0) return err; } if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR | OG_REST_PARAM_DISK | OG_REST_PARAM_PARTITION)) return -1; clients = json_copy(element); json_object_del(clients, "clients"); return og_send_request(OG_METHOD_GET, OG_CMD_SOFTWARE, params, clients); } static int og_cmd_get_software(json_t *element, struct og_msg_params *params, char *buffer_reply) { json_t *value, *software, *root; const char *key, *msglog, *name; uint64_t disk, partition; uint64_t flags = 0; struct og_dbi *dbi; dbi_result result; int err = 0; struct og_buffer og_buffer = { .data = buffer_reply }; if (json_typeof(element) != JSON_OBJECT) return -1; json_object_foreach(element, key, value) { if (!strcmp(key, "client")) { err = og_json_parse_clients(value, params); } else if (!strcmp(key, "disk")) { err = og_json_parse_uint64(value, &disk); flags |= OG_REST_PARAM_DISK; } else if (!strcmp(key, "partition")) { err = og_json_parse_uint64(value, &partition); flags |= OG_REST_PARAM_PARTITION; } if (err < 0) return err; } if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR) || !og_flags_validate(flags, OG_REST_PARAM_DISK | OG_REST_PARAM_PARTITION)) return -1; dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open conection database (%s:%d)\n", __func__, __LINE__); return -1; } result = dbi_conn_queryf(dbi->conn, "SELECT s.descripcion " "FROM softwares s " "INNER JOIN perfilessoft_softwares pss " "ON s.idsoftware = pss.idsoftware " "INNER JOIN ordenadores_particiones op " "ON pss.idperfilsoft = op.idperfilsoft " "INNER JOIN ordenadores o " "ON o.idordenador = op.idordenador " "WHERE o.ip='%s' AND " " op.numdisk=%lu AND " " op.numpar=%lu", params->ips_array[0], disk, partition); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } software = json_array(); if (!software) { dbi_result_free(result); og_dbi_close(dbi); return -1; } while (dbi_result_next_row(result)) { name = dbi_result_get_string(result, "descripcion"); json_array_append_new(software, json_string(name)); } dbi_result_free(result); og_dbi_close(dbi); root = json_object(); if (!root) { json_decref(software); return -1; } json_object_set_new(root, "software", software); if (json_dump_callback(root, og_json_dump_clients, &og_buffer, 0)) { json_decref(root); return -1; } json_decref(root); return 0; } static const int og_cmd_get_repositories(char *buffer_reply) { json_t *root, *repositories, *repository, *id, *ip, *name; struct og_buffer og_buffer = { .data = buffer_reply, }; struct og_dbi *dbi; dbi_result result; dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", __func__, __LINE__); return -1; } result = dbi_conn_queryf(dbi->conn, "SELECT idrepositorio, ip, nombrerepositorio " "FROM repositorios"); repositories = json_array(); while (dbi_result_next_row(result)) { repository = json_object(); id = json_integer(dbi_result_get_ulonglong(result, "idrepositorio")); ip = json_string(dbi_result_get_string(result, "ip")); name = json_string(dbi_result_get_string(result, "nombrerepositorio")); json_object_set_new(repository, "id", id); json_object_set_new(repository, "ip", ip); json_object_set_new(repository, "name", name); json_array_append_new(repositories, repository); } dbi_result_free(result); og_dbi_close(dbi); root = json_object(); json_object_set_new(root, "repositories", repositories); if (json_dump_callback(root, og_json_dump_clients, &og_buffer, 0)) { json_decref(root); return -1; } json_decref(root); return 0; } #define OG_IMAGE_TYPE_MAXLEN 4 static json_t *og_json_disk_alloc() { const char *dir = ogconfig.repo.dir; struct statvfs buffer; json_t *disk_json; int ret; ret = statvfs(dir, &buffer); if (ret) return NULL; disk_json = json_object(); if (!disk_json) return NULL; json_object_set_new(disk_json, "total", json_integer(buffer.f_blocks * buffer.f_frsize)); json_object_set_new(disk_json, "free", json_integer(buffer.f_bfree * buffer.f_frsize)); return disk_json; } #define OG_PERMS_IRWX (S_IRWXU | S_IRWXG | S_IRWXO) #define OG_PERMS_MAXLEN 4 static json_t *og_json_image_alloc(struct og_image *image) { char perms_string[OG_PERMS_MAXLEN]; json_t *image_json; char *modified; image_json = json_object(); if (!image_json) return NULL; snprintf(perms_string, sizeof(perms_string), "%o", image->perms); modified = ctime(&image->lastupdate); modified[strlen(modified) - 1] = '\0'; json_object_set_new(image_json, "name", json_string(image->name)); json_object_set_new(image_json, "datasize", json_integer(image->datasize)); json_object_set_new(image_json, "size", json_integer(image->size)); json_object_set_new(image_json, "modified", json_string(modified)); json_object_set_new(image_json, "permissions", json_string(perms_string)); json_object_set_new(image_json, "software_id", json_integer(image->software_id)); json_object_set_new(image_json, "type", json_integer(image->type)); json_object_set_new(image_json, "id", json_integer(image->id)); json_object_set_new(image_json, "repo_id", json_integer(image->repo_id)); json_object_set_new(image_json, "description", json_string(image->description)); return image_json; } static int og_cmd_images(char *buffer_reply) { json_t *root, *images, *image_json, *disk_json; struct og_buffer og_buffer = { .data = buffer_reply }; struct og_image image; struct og_dbi *dbi; dbi_result result; root = json_object(); if (!root) return -1; images = json_array(); if (!images) { json_decref(root); return -1; } json_object_set_new(root, "images", images); dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", __func__, __LINE__); json_decref(root); return -1; } result = dbi_conn_queryf(dbi->conn, "SELECT i.nombreca, o.nombreordenador, " " i.clonator, i.compressor, " " i.filesystem, i.datasize, i.size, " " i.lastupdate, i.permissions, " " i.idperfilsoft, i.tipo, " " i.idimagen, i.idrepositorio, " " i.descripcion " "FROM imagenes i " "LEFT JOIN ordenadores o " "ON i.idordenador = o.idordenador "); while (dbi_result_next_row(result)) { image = (struct og_image){0}; image.datasize = dbi_result_get_ulonglong(result, "datasize"); image.size = dbi_result_get_ulonglong(result, "size"); image.lastupdate = dbi_result_get_ulonglong(result, "lastupdate"); image.perms = dbi_result_get_uint(result, "permissions"); image.software_id = dbi_result_get_ulonglong(result, "idperfilsoft"); image.type = dbi_result_get_ulonglong(result, "tipo"); image.id = dbi_result_get_ulonglong(result, "idimagen"); image.repo_id = dbi_result_get_ulonglong(result, "idrepositorio"); snprintf(image.name, sizeof(image.name), "%s", dbi_result_get_string(result, "nombreca")); snprintf(image.description, sizeof(image.description), "%s", dbi_result_get_string(result, "descripcion")); image_json = og_json_image_alloc(&image); if (!image_json) { dbi_result_free(result); og_dbi_close(dbi); json_decref(root); return -1; } json_array_append_new(images, image_json); } dbi_result_free(result); og_dbi_close(dbi); disk_json = og_json_disk_alloc(); if (!disk_json) { syslog(LOG_ERR, "cannot allocate disk json"); json_decref(root); return -1; } json_object_set_new(root, "disk", disk_json); if (json_dump_callback(root, og_json_dump_clients, &og_buffer, 0)) { json_decref(root); return -1; } json_decref(root); return 0; } int og_json_parse_create_image(json_t *element, struct og_msg_params *params) { 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, "disk")) { err = og_json_parse_string(value, ¶ms->disk); params->flags |= OG_REST_PARAM_DISK; } else if (!strcmp(key, "partition")) { err = og_json_parse_string(value, ¶ms->partition); params->flags |= OG_REST_PARAM_PARTITION; } else if (!strcmp(key, "name")) { err = og_json_parse_string_copy(value, (char *)¶ms->image.name, sizeof(params->image.name)); params->flags |= OG_REST_PARAM_NAME; } else if (!strcmp(key, "repository_id")) { err = og_json_parse_uint64(value, ¶ms->image.repo_id); params->flags |= OG_REST_PARAM_REPO; } else if (!strcmp(key, "clients")) { err = og_json_parse_clients(value, params); } else if (!strcmp(key, "id")) { err = og_json_parse_string(value, ¶ms->id); params->flags |= OG_REST_PARAM_ID; } else if (!strcmp(key, "code")) { err = og_json_parse_string(value, ¶ms->code); params->flags |= OG_REST_PARAM_CODE; } else if (!strcmp(key, "description")) { err = og_json_parse_string_copy(value, (char *)¶ms->image.description, sizeof(params->image.description)); } else if (!strcmp(key, "group_id")) { err = og_json_parse_uint64(value, ¶ms->image.group_id); } else if (!strcmp(key, "center_id")) { err = og_json_parse_uint64(value, ¶ms->image.center_id); } else if (!strcmp(key, "backup")) { err = og_json_parse_bool(value, ¶ms->backup); params->flags |= OG_REST_PARAM_BACKUP; } if (err < 0) return err; } if (!og_msg_params_validate(params, OG_REST_PARAM_BACKUP)) params->backup = true; return 0; } static int og_cmd_create_image(json_t *element, struct og_msg_params *params) { char repository_ip[OG_DB_IP_MAXLEN + 1]; char new_image_id[OG_DB_INT_MAXLEN + 1]; struct og_dbi *dbi; json_t *clients; int err = 0; err = og_json_parse_create_image(element, params); if (err < 0) return err; if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR | OG_REST_PARAM_DISK | OG_REST_PARAM_PARTITION | OG_REST_PARAM_CODE | OG_REST_PARAM_ID | OG_REST_PARAM_NAME)) return -1; dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", __func__, __LINE__); return -1; } /* If there is a description, this means the image is not in the DB. */ if (params->image.description[0]) { if (!og_msg_params_validate(params, OG_REST_PARAM_REPO)) { og_dbi_close(dbi); return -1; } err = og_dbi_add_image(dbi, ¶ms->image); if (err < 0) { og_dbi_close(dbi); return err; } snprintf(new_image_id, sizeof(new_image_id), "%u", err); params->id = new_image_id; json_object_set_new(element, "id", json_string(params->id)); } clients = json_copy(element); json_object_del(clients, "clients"); err = og_dbi_get_repository_ip(dbi, atoll(params->id), repository_ip); og_dbi_close(dbi); if (err < 0) return err; json_object_set_new(clients ,"repository", json_string(repository_ip)); json_object_set_new(clients ,"backup", json_boolean(params->backup)); return og_send_request(OG_METHOD_POST, OG_CMD_IMAGE_CREATE, params, clients); } int og_json_parse_restore_image(json_t *element, struct og_msg_params *params) { 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, "disk")) { err = og_json_parse_string(value, ¶ms->disk); params->flags |= OG_REST_PARAM_DISK; } else if (!strcmp(key, "partition")) { err = og_json_parse_string(value, ¶ms->partition); params->flags |= OG_REST_PARAM_PARTITION; } else if (!strcmp(key, "name")) { err = og_json_parse_string(value, ¶ms->name); params->flags |= OG_REST_PARAM_NAME; } else if (!strcmp(key, "repository")) { err = og_json_parse_string(value, ¶ms->repository); params->flags |= OG_REST_PARAM_REPO; } else if (!strcmp(key, "clients")) { err = og_json_parse_clients(value, params); } else if (!strcmp(key, "type")) { err = og_json_parse_string(value, ¶ms->type); params->flags |= OG_REST_PARAM_TYPE; } else if (!strcmp(key, "profile")) { err = og_json_parse_string(value, ¶ms->profile); params->flags |= OG_REST_PARAM_PROFILE; } else if (!strcmp(key, "id")) { err = og_json_parse_string(value, ¶ms->id); params->flags |= OG_REST_PARAM_ID; } if (err < 0) return err; } return 0; } static int og_cmd_restore_image(json_t *element, struct og_msg_params *params) { json_t *clients; int err = 0; err = og_json_parse_restore_image(element, params); if (err < 0) return err; if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR | OG_REST_PARAM_DISK | OG_REST_PARAM_PARTITION | OG_REST_PARAM_NAME | OG_REST_PARAM_REPO | OG_REST_PARAM_TYPE | OG_REST_PARAM_PROFILE | OG_REST_PARAM_ID)) return -1; clients = json_copy(element); json_object_del(clients, "clients"); return og_send_request(OG_METHOD_POST, OG_CMD_IMAGE_RESTORE, params, clients); } static int og_cmd_delete_image(json_t *element, struct og_msg_params *params) { char filename[PATH_MAX + 1]; const char *key, *image; struct og_dbi *dbi; dbi_result result; int rval, err = 0; json_t *value; if (json_typeof(element) != JSON_OBJECT) return -1; json_object_foreach(element, key, value) { if (!strcmp(key, "image")) { err = og_json_parse_string(value, ¶ms->id); params->flags |= OG_REST_PARAM_ID; } if (err < 0) return err; } if (!og_msg_params_validate(params, OG_REST_PARAM_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; } result = dbi_conn_queryf(dbi->conn, "SELECT nombreca FROM imagenes " "WHERE idimagen='%s'", params->id); if (!result) { og_dbi_close(dbi); syslog(LOG_ERR, "failed to query database\n"); return -1; } if (!dbi_result_next_row(result)) { dbi_result_free(result); og_dbi_close(dbi); syslog(LOG_ERR, "image does not exist in database\n"); return -1; } image = dbi_result_get_string(result, "nombreca"); snprintf(filename, sizeof(filename), "%s/%s.img", ogconfig.repo.dir, image); dbi_result_free(result); result = dbi_conn_queryf(dbi->conn, "DELETE FROM imagenes " "WHERE idimagen='%s'", params->id); if (!result) { og_dbi_close(dbi); syslog(LOG_ERR, "failed to query database\n"); return -1; } if (dbi_result_get_numrows_affected(result) < 1) { dbi_result_free(result); og_dbi_close(dbi); return -1; } dbi_result_free(result); rval = unlink(filename); if (rval) { og_dbi_close(dbi); syslog(LOG_ERR, "cannot delete image %s: %s\n", image, strerror(errno)); return -1; } og_dbi_close(dbi); return 0; } static int og_cmd_setup(json_t *element, struct og_msg_params *params) { json_t *value, *clients; const char *key; int err = 0; if (json_typeof(element) != JSON_OBJECT) return -1; json_object_foreach(element, key, value) { if (!strcmp(key, "clients")) { err = og_json_parse_clients(value, params); } else if (!strcmp(key, "type")) { err = og_json_parse_string(value, ¶ms->type); params->flags |= OG_REST_PARAM_TYPE; } else if (!strcmp(key, "disk")) { err = og_json_parse_string(value, ¶ms->disk); params->flags |= OG_REST_PARAM_DISK; } else if (!strcmp(key, "cache")) { err = og_json_parse_string(value, ¶ms->cache); params->flags |= OG_REST_PARAM_CACHE; } else if (!strcmp(key, "cache_size")) { err = og_json_parse_string(value, ¶ms->cache_size); params->flags |= OG_REST_PARAM_CACHE_SIZE; } else if (!strcmp(key, "partition_setup")) { err = og_json_parse_partition_setup(value, params); } if (err < 0) return err; } if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR | OG_REST_PARAM_TYPE | OG_REST_PARAM_DISK | OG_REST_PARAM_CACHE | OG_REST_PARAM_CACHE_SIZE | OG_REST_PARAM_PART_0 | OG_REST_PARAM_PART_1 | OG_REST_PARAM_PART_2 | OG_REST_PARAM_PART_3)) return -1; clients = json_copy(element); json_object_del(clients, "clients"); return og_send_request(OG_METHOD_POST, OG_CMD_SETUP, params, clients); } static int og_cmd_run_schedule(json_t *element, struct og_msg_params *params) { const char *key; json_t *value; int err = 0; json_object_foreach(element, key, value) { if (!strcmp(key, "clients")) err = og_json_parse_clients(value, params); if (err < 0) return err; } if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR)) return -1; return og_send_request(OG_METHOD_GET, OG_CMD_RUN_SCHEDULE, params, NULL); } static LIST_HEAD(cmd_list); const struct og_cmd *og_cmd_find(const char *client_ip) { struct og_cmd *cmd, *next; list_for_each_entry_safe(cmd, next, &cmd_list, list) { if (strcmp(cmd->ip, client_ip)) continue; list_del(&cmd->list); return cmd; } return NULL; } void og_cmd_free(const struct og_cmd *cmd) { struct og_msg_params *params = (struct og_msg_params *)&cmd->params; int i; for (i = 0; i < params->ips_array_len; i++) { free((void *)params->netmask_array[i]); free((void *)params->ips_array[i]); free((void *)params->mac_array[i]); } free((void *)params->wol_type); if (cmd->json) json_decref(cmd->json); free((void *)cmd->ip); free((void *)cmd->mac); free((void *)cmd); } static void og_cmd_init(struct og_cmd *cmd, enum og_rest_method method, enum og_cmd_type type, json_t *root) { cmd->type = type; cmd->method = method; cmd->params.ips_array[0] = strdup(cmd->ip); cmd->params.ips_array_len = 1; cmd->json = root; gettimeofday(&cmd->tv, NULL); } static int og_cmd_legacy_wol(const char *input, struct og_cmd *cmd) { char wol_type[2] = {}; const char *msglog; struct og_dbi *dbi; dbi_result result; if (sscanf(input, "mar=%s", wol_type) != 1) { syslog(LOG_ERR, "malformed database legacy input\n"); return -1; } dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", __func__, __LINE__); return -1; } result = dbi_conn_queryf(dbi->conn, "SELECT aulas.netmask " "FROM ordenadores " "INNER JOIN aulas " "ON ordenadores.idaula = aulas.idaula " "WHERE ordenadores.ip = '%s'", cmd->ip); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); og_dbi_close(dbi); return -1; } dbi_result_next_row(result); og_cmd_init(cmd, OG_METHOD_NO_HTTP, OG_CMD_WOL, NULL); cmd->params.netmask_array[0] = dbi_result_get_string_copy(result, "netmask"); cmd->params.mac_array[0] = strdup(cmd->mac); cmd->params.wol_type = strdup(wol_type); dbi_result_free(result); og_dbi_close(dbi); return 0; } static int og_cmd_legacy_shell_run(const char *input, struct og_cmd *cmd) { json_t *root, *script, *echo; script = json_string(input + 4); echo = json_boolean(false); root = json_object(); if (!root) return -1; json_object_set_new(root, "run", script); json_object_set_new(root, "echo", echo); og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_SHELL_RUN, root); return 0; } static int og_cmd_legacy_session(const char *input, struct og_cmd *cmd) { char part_str[OG_DB_SMALLINT_MAXLEN + 1]; char disk_str[OG_DB_SMALLINT_MAXLEN + 1]; json_t *root, *disk, *partition; if (sscanf(input, "dsk=%s\rpar=%s\r", disk_str, part_str) != 2) return -1; partition = json_string(part_str); disk = json_string(disk_str); root = json_object(); if (!root) return -1; json_object_set_new(root, "partition", partition); json_object_set_new(root, "disk", disk); og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_SESSION, root); return 0; } static int og_cmd_legacy_poweroff(const char *input, struct og_cmd *cmd) { og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_POWEROFF, NULL); return 0; } static int og_cmd_legacy_refresh(const char *input, struct og_cmd *cmd) { og_cmd_init(cmd, OG_METHOD_GET, OG_CMD_REFRESH, NULL); return 0; } static int og_cmd_legacy_reboot(const char *input, struct og_cmd *cmd) { og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_REBOOT, NULL); return 0; } static int og_cmd_legacy_stop(const char *input, struct og_cmd *cmd) { og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_STOP, NULL); return 0; } static int og_cmd_legacy_hardware(const char *input, struct og_cmd *cmd) { og_cmd_init(cmd, OG_METHOD_GET, OG_CMD_HARDWARE, NULL); return 0; } static int og_cmd_legacy_software(const char *input, struct og_cmd *cmd) { char part_str[OG_DB_SMALLINT_MAXLEN + 1]; char disk_str[OG_DB_SMALLINT_MAXLEN + 1]; json_t *root, *disk, *partition; if (sscanf(input, "dsk=%s\rpar=%s\r", disk_str, part_str) != 2) return -1; partition = json_string(part_str); disk = json_string(disk_str); root = json_object(); if (!root) return -1; json_object_set_new(root, "partition", partition); json_object_set_new(root, "disk", disk); og_cmd_init(cmd, OG_METHOD_GET, OG_CMD_SOFTWARE, root); return 0; } static int og_cmd_legacy_image_create(const char *input, struct og_cmd *cmd) { json_t *root, *disk, *partition, *code, *image_id, *name, *repo; struct og_image_legacy img = {}; if (sscanf(input, "dsk=%s\rpar=%s\rcpt=%s\ridi=%s\rnci=%s\ripr=%s\r", img.disk, img.part, img.code, img.image_id, img.name, img.repo) != 6) return -1; image_id = json_string(img.image_id); partition = json_string(img.part); code = json_string(img.code); name = json_string(img.name); repo = json_string(img.repo); disk = json_string(img.disk); root = json_object(); if (!root) return -1; json_object_set_new(root, "partition", partition); json_object_set_new(root, "repository", repo); json_object_set_new(root, "id", image_id); json_object_set_new(root, "code", code); json_object_set_new(root, "name", name); json_object_set_new(root, "disk", disk); og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_IMAGE_CREATE, root); return 0; } #define OG_DB_RESTORE_TYPE_MAXLEN 64 static int og_cmd_legacy_image_restore(const char *input, struct og_cmd *cmd) { json_t *root, *disk, *partition, *image_id, *name, *repo; char restore_type_str[OG_DB_RESTORE_TYPE_MAXLEN + 1] = {}; char software_id_str[OG_DB_INT_MAXLEN + 1] = {}; json_t *software_id, *restore_type; struct og_image_legacy img = {}; if (sscanf(input, "dsk=%s\rpar=%s\ridi=%s\rnci=%s\r" "ipr=%s\rifs=%s\rptc=%[^\r]\r", img.disk, img.part, img.image_id, img.name, img.repo, software_id_str, restore_type_str) != 7) return -1; restore_type = json_string(restore_type_str); software_id = json_string(software_id_str); image_id = json_string(img.image_id); partition = json_string(img.part); name = json_string(img.name); repo = json_string(img.repo); disk = json_string(img.disk); root = json_object(); if (!root) return -1; json_object_set_new(root, "profile", software_id); json_object_set_new(root, "partition", partition); json_object_set_new(root, "type", restore_type); json_object_set_new(root, "repository", repo); json_object_set_new(root, "id", image_id); json_object_set_new(root, "name", name); json_object_set_new(root, "disk", disk); og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_IMAGE_RESTORE, root); return 0; } #define OG_PARTITION_TABLE_TYPE_MAXLEN 5 static int og_cmd_legacy_setup(const char *input, struct og_cmd *cmd) { json_t *root, *disk, *cache, *cache_size, *partition_setup, *object; char part_table_type_str[OG_PARTITION_TABLE_TYPE_MAXLEN + 1]; struct og_legacy_partition part_cfg[OG_PARTITION_MAX] = {}; json_t *part_table_type, *part, *code, *fs, *size, *format; char cache_size_str [OG_DB_INT_MAXLEN + 1]; char disk_str [OG_DB_SMALLINT_MAXLEN + 1]; unsigned int partition_len = 0; const char *in_ptr; char cache_str[2]; if (sscanf(input, "ttp=%s\rdsk=%s\rcfg=dis=%*[^*]*che=%[^*]*tch=%[^!]!", part_table_type_str, disk_str, cache_str, cache_size_str) != 4) return -1; in_ptr = strstr(input, "!") + 1; while (strlen(in_ptr) > 0) { if(sscanf(in_ptr, "par=%[^*]*cpt=%[^*]*sfi=%[^*]*tam=%[^*]*ope=%[^%%]%%", part_cfg[partition_len].partition, part_cfg[partition_len].code, part_cfg[partition_len].filesystem, part_cfg[partition_len].size, part_cfg[partition_len].format) != 5) return -1; in_ptr = strstr(in_ptr, "%") + 1; partition_len++; } root = json_object(); if (!root) return -1; part_table_type = json_string(part_table_type_str); cache_size = json_string(cache_size_str); cache = json_string(cache_str); partition_setup = json_array(); disk = json_string(disk_str); for (unsigned int i = 0; i < partition_len; ++i) { object = json_object(); if (!object) { json_decref(root); return -1; } part = json_string(part_cfg[i].partition); fs = json_string(part_cfg[i].filesystem); format = json_string(part_cfg[i].format); code = json_string(part_cfg[i].code); size = json_string(part_cfg[i].size); json_object_set_new(object, "partition", part); json_object_set_new(object, "filesystem", fs); json_object_set_new(object, "format", format); json_object_set_new(object, "code", code); json_object_set_new(object, "size", size); json_array_append_new(partition_setup, object); } json_object_set_new(root, "partition_setup", partition_setup); json_object_set_new(root, "cache_size", cache_size); json_object_set_new(root, "type", part_table_type); json_object_set_new(root, "cache", cache); json_object_set_new(root, "disk", disk); og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_SETUP, root); return 0; } static int og_cmd_legacy_run_schedule(const char *input, struct og_cmd *cmd) { og_cmd_init(cmd, OG_METHOD_GET, OG_CMD_RUN_SCHEDULE, NULL); return 0; } static int og_cmd_legacy(const char *input, struct og_cmd *cmd) { char legacy_cmd[32] = {}; int err = -1; if (sscanf(input, "nfn=%31s\r", legacy_cmd) != 1) { syslog(LOG_ERR, "malformed database legacy input\n"); return -1; } input = strchr(input, '\r') + 1; if (!strcmp(legacy_cmd, "Arrancar")) { err = og_cmd_legacy_wol(input, cmd); } else if (!strcmp(legacy_cmd, "EjecutarScript")) { err = og_cmd_legacy_shell_run(input, cmd); } else if (!strcmp(legacy_cmd, "IniciarSesion")) { err = og_cmd_legacy_session(input, cmd); } else if (!strcmp(legacy_cmd, "Apagar")) { err = og_cmd_legacy_poweroff(input, cmd); } else if (!strcmp(legacy_cmd, "Actualizar")) { err = og_cmd_legacy_refresh(input, cmd); } else if (!strcmp(legacy_cmd, "Reiniciar")) { err = og_cmd_legacy_reboot(input, cmd); } else if (!strcmp(legacy_cmd, "Purgar")) { err = og_cmd_legacy_stop(input, cmd); } else if (!strcmp(legacy_cmd, "InventarioHardware")) { err = og_cmd_legacy_hardware(input, cmd); } else if (!strcmp(legacy_cmd, "InventarioSoftware")) { err = og_cmd_legacy_software(input, cmd); } else if (!strcmp(legacy_cmd, "CrearImagen")) { err = og_cmd_legacy_image_create(input, cmd); } else if (!strcmp(legacy_cmd, "RestaurarImagen")) { err = og_cmd_legacy_image_restore(input, cmd); } else if (!strcmp(legacy_cmd, "Configurar")) { err = og_cmd_legacy_setup(input, cmd); } else if (!strcmp(legacy_cmd, "EjecutaComandosPendientes") || !strcmp(legacy_cmd, "Actualizar")) { err = og_cmd_legacy_run_schedule(input, cmd); } return err; } static int og_dbi_add_action(const struct og_dbi *dbi, struct og_task *task, struct og_cmd *cmd) { char start_date_string[24]; struct tm *start_date; const char *msglog; dbi_result result; time_t now; time(&now); start_date = localtime(&now); sprintf(start_date_string, "%hu/%hhu/%hhu %hhu:%hhu:%hhu", start_date->tm_year + 1900, start_date->tm_mon + 1, start_date->tm_mday, start_date->tm_hour, start_date->tm_min, start_date->tm_sec); result = dbi_conn_queryf(dbi->conn, "INSERT INTO acciones (idordenador, " "tipoaccion, idtipoaccion, descriaccion, ip, " "sesion, idcomando, parametros, fechahorareg, " "estado, resultado, ambito, idambito, " "restrambito, idprocedimiento, idcentro, " "idprogramacion) " "VALUES (%d, %d, %d, '%s', '%s', %d, %d, '%s', " "'%s', %d, %d, %d, %d, '%s', %d, %d, %d)", cmd->client_id, EJECUCION_TAREA, task->task_id, "", cmd->ip, task->session, task->command_id, task->params, start_date_string, ACCION_INICIADA, ACCION_SINRESULTADO, task->type_scope, task->scope, "", task->procedure_id, task->center_id, task->schedule_id); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } cmd->id = dbi_conn_sequence_last(dbi->conn, NULL); if (!task->session) { task->session = cmd->id; dbi_result_free(result); result = dbi_conn_queryf(dbi->conn, "UPDATE acciones SET sesion=%d " "WHERE idaccion=%d", task->session, cmd->id); } dbi_result_free(result); return 0; } static int og_queue_task_command(struct og_dbi *dbi, struct og_task *task, char *query) { struct og_cmd *cmd; const char *msglog; dbi_result result; result = dbi_conn_queryf(dbi->conn, query); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } while (dbi_result_next_row(result)) { cmd = (struct og_cmd *)calloc(1, sizeof(struct og_cmd)); if (!cmd) { dbi_result_free(result); return -1; } cmd->client_id = dbi_result_get_uint(result, "idordenador"); cmd->ip = strdup(dbi_result_get_string(result, "ip")); cmd->mac = strdup(dbi_result_get_string(result, "mac")); og_cmd_legacy(task->params, cmd); if (task->procedure_id) { if (og_dbi_add_action(dbi, task, cmd)) { dbi_result_free(result); return -1; } } else { cmd->id = task->task_id; } list_add_tail(&cmd->list, &cmd_list); } dbi_result_free(result); return 0; } static int og_queue_task_group_clients(struct og_dbi *dbi, struct og_task *task, char *query) { const char *msglog; dbi_result result; result = dbi_conn_queryf(dbi->conn, query); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } while (dbi_result_next_row(result)) { uint32_t group_id = dbi_result_get_uint(result, "idgrupo"); sprintf(query, "SELECT idgrupo FROM gruposordenadores " "WHERE grupoid=%d", group_id); if (og_queue_task_group_clients(dbi, task, query)) { dbi_result_free(result); return -1; } sprintf(query,"SELECT ip, mac, idordenador FROM ordenadores " "WHERE grupoid=%d", group_id); if (og_queue_task_command(dbi, task, query)) { dbi_result_free(result); return -1; } } dbi_result_free(result); return 0; } static int og_queue_task_group_classrooms(struct og_dbi *dbi, struct og_task *task, char *query) { const char *msglog; dbi_result result; result = dbi_conn_queryf(dbi->conn, query); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } while (dbi_result_next_row(result)) { uint32_t group_id = dbi_result_get_uint(result, "idgrupo"); sprintf(query, "SELECT idgrupo FROM grupos " "WHERE grupoid=%d AND tipo=%d", group_id, AMBITO_GRUPOSAULAS); if (og_queue_task_group_classrooms(dbi, task, query)) { dbi_result_free(result); return -1; } sprintf(query, "SELECT ip,mac,idordenador " "FROM ordenadores INNER JOIN aulas " "WHERE ordenadores.idaula=aulas.idaula " "AND aulas.grupoid=%d", group_id); if (og_queue_task_command(dbi, task, query)) { dbi_result_free(result); return -1; } } dbi_result_free(result); return 0; } static int og_queue_task_clients(struct og_dbi *dbi, struct og_task *task) { char query[4096]; switch (task->type_scope) { case AMBITO_CENTROS: sprintf(query, "SELECT ip,mac,idordenador " "FROM ordenadores INNER JOIN aulas " "WHERE ordenadores.idaula=aulas.idaula " "AND idcentro=%d", task->scope); return og_queue_task_command(dbi, task, query); case AMBITO_GRUPOSAULAS: sprintf(query, "SELECT idgrupo FROM grupos " "WHERE idgrupo=%i AND tipo=%d", task->scope, AMBITO_GRUPOSAULAS); return og_queue_task_group_classrooms(dbi, task, query); case AMBITO_AULAS: sprintf(query, "SELECT ip,mac,idordenador FROM ordenadores " "WHERE idaula=%d", task->scope); return og_queue_task_command(dbi, task, query); case AMBITO_GRUPOSORDENADORES: sprintf(query, "SELECT idgrupo FROM gruposordenadores " "WHERE idgrupo = %d", task->scope); return og_queue_task_group_clients(dbi, task, query); case AMBITO_ORDENADORES: sprintf(query, "SELECT ip, mac, idordenador FROM ordenadores " "WHERE idordenador = %d", task->scope); return og_queue_task_command(dbi, task, query); } return 0; } int og_dbi_queue_procedure(struct og_dbi *dbi, struct og_task *task) { uint32_t procedure_id; const char *msglog; dbi_result result; result = dbi_conn_queryf(dbi->conn, "SELECT parametros, procedimientoid, idcomando " "FROM procedimientos_acciones " "WHERE idprocedimiento=%d ORDER BY orden", task->procedure_id); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } while (dbi_result_next_row(result)) { procedure_id = dbi_result_get_uint(result, "procedimientoid"); if (procedure_id > 0) { task->procedure_id = procedure_id; if (og_dbi_queue_procedure(dbi, task)) return -1; continue; } task->params = dbi_result_get_string(result, "parametros"); task->command_id = dbi_result_get_uint(result, "idcomando"); if (og_queue_task_clients(dbi, task)) return -1; } dbi_result_free(result); return 0; } static int og_dbi_queue_task(struct og_dbi *dbi, uint32_t task_id, uint32_t schedule_id) { struct og_task task = {}; uint32_t task_id_next; const char *msglog; dbi_result result; task.schedule_id = schedule_id; result = dbi_conn_queryf(dbi->conn, "SELECT tareas_acciones.orden, " "tareas_acciones.idprocedimiento, " "tareas_acciones.tareaid, " "tareas.idtarea, " "tareas.idcentro, " "tareas.ambito, " "tareas.idambito, " "tareas.restrambito " " FROM tareas" " INNER JOIN tareas_acciones ON tareas_acciones.idtarea=tareas.idtarea" " WHERE tareas_acciones.idtarea=%u ORDER BY tareas_acciones.orden ASC", task_id); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } while (dbi_result_next_row(result)) { task_id_next = dbi_result_get_uint(result, "tareaid"); if (task_id_next > 0) { if (og_dbi_queue_task(dbi, task_id_next, schedule_id)) return -1; continue; } task.task_id = dbi_result_get_uint(result, "idtarea"); task.center_id = dbi_result_get_uint(result, "idcentro"); task.procedure_id = dbi_result_get_uint(result, "idprocedimiento"); task.type_scope = dbi_result_get_uint(result, "ambito"); task.scope = dbi_result_get_uint(result, "idambito"); task.filtered_scope = dbi_result_get_string(result, "restrambito"); og_dbi_queue_procedure(dbi, &task); } dbi_result_free(result); return 0; } static int og_dbi_queue_command(struct og_dbi *dbi, uint32_t task_id, uint32_t schedule_id) { struct og_task task = {}; const char *msglog; dbi_result result; char query[4096]; result = dbi_conn_queryf(dbi->conn, "SELECT idaccion, idcentro, idordenador, parametros " "FROM acciones " "WHERE sesion = %u", task_id); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } while (dbi_result_next_row(result)) { task.task_id = dbi_result_get_uint(result, "idaccion"); task.center_id = dbi_result_get_uint(result, "idcentro"); task.scope = dbi_result_get_uint(result, "idordenador"); task.params = dbi_result_get_string(result, "parametros"); sprintf(query, "SELECT ip, mac, idordenador FROM ordenadores " "WHERE idordenador = %d", task.scope); if (og_queue_task_command(dbi, &task, query)) { dbi_result_free(result); return -1; } } dbi_result_free(result); return 0; } int og_dbi_update_action(uint32_t id, bool success) { char end_date_string[24]; struct tm *end_date; const char *msglog; struct og_dbi *dbi; uint8_t status = 2; dbi_result result; time_t now; if (!id) return 0; dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", __func__, __LINE__); return -1; } time(&now); end_date = localtime(&now); sprintf(end_date_string, "%hu/%hhu/%hhu %hhu:%hhu:%hhu", end_date->tm_year + 1900, end_date->tm_mon + 1, end_date->tm_mday, end_date->tm_hour, end_date->tm_min, end_date->tm_sec); result = dbi_conn_queryf(dbi->conn, "UPDATE acciones SET fechahorafin='%s', " "estado=%d, resultado=%d WHERE idaccion=%d", end_date_string, ACCION_FINALIZADA, status - success, id); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); og_dbi_close(dbi); return -1; } dbi_result_free(result); og_dbi_close(dbi); return 0; } void og_schedule_run(unsigned int task_id, unsigned int schedule_id, enum og_schedule_type type) { struct og_msg_params params = {}; struct in_addr addr, netmask; struct og_cmd *cmd, *next; bool duplicated = false; struct og_dbi *dbi; unsigned int i; int sd; dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", __func__, __LINE__); return; } switch (type) { case OG_SCHEDULE_TASK: og_dbi_queue_task(dbi, task_id, schedule_id); break; case OG_SCHEDULE_PROCEDURE: case OG_SCHEDULE_COMMAND: og_dbi_queue_command(dbi, task_id, schedule_id); break; } og_dbi_close(dbi); list_for_each_entry(cmd, &cmd_list, list) { for (i = 0; i < params.ips_array_len; i++) { if (!strncmp(cmd->ip, params.ips_array[i], OG_DB_IP_MAXLEN)) { duplicated = true; break; } } if (!duplicated) params.ips_array[params.ips_array_len++] = strdup(cmd->ip); else duplicated = false; } sd = wol_socket_open(); if (sd < 0) { syslog(LOG_ERR, "cannot open wol socket (%s:%d)\n", __func__, __LINE__); goto err_out; } list_for_each_entry_safe(cmd, next, &cmd_list, list) { if (cmd->type != OG_CMD_WOL) continue; for (i = 0; i < cmd->params.ips_array_len; i++) { if (inet_aton(cmd->params.ips_array[i], &addr) < 0) continue; if (inet_aton(cmd->params.netmask_array[i], &netmask) < 0) continue; if (wake_up(sd, &addr, &netmask, cmd->params.mac_array[i], atoi(cmd->params.wol_type)) < 0) { syslog(LOG_ERR, "Failed to send wol packet to %s\n", params.ips_array[i]); continue; } og_dbi_update_action(cmd->id, true); } list_del(&cmd->list); og_cmd_free(cmd); } close(sd); og_send_request(OG_METHOD_GET, OG_CMD_RUN_SCHEDULE, ¶ms, NULL); err_out: for (i = 0; i < params.ips_array_len; i++) free((void *)params.ips_array[i]); } static int og_cmd_task_post(json_t *element, struct og_msg_params *params) { struct og_cmd *cmd; struct og_dbi *dbi; 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, "task")) { err = og_json_parse_string(value, ¶ms->task_id); params->flags |= OG_REST_PARAM_TASK; } if (err < 0) return err; } if (!og_msg_params_validate(params, OG_REST_PARAM_TASK)) return -1; dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", __func__, __LINE__); return -1; } og_schedule_run(atoi(params->task_id), 0, OG_SCHEDULE_TASK); og_dbi_close(dbi); list_for_each_entry(cmd, &cmd_list, list) params->ips_array[params->ips_array_len++] = cmd->ip; return og_send_request(OG_METHOD_GET, OG_CMD_RUN_SCHEDULE, params, NULL); } #define OG_QUERY_MAXLEN 4096 static int og_dbi_scope_get_computer(const struct og_dbi *dbi, json_t *array, const char* query) { const char *computer_name, *computer_ip; uint32_t computer_id; const char *msglog; dbi_result result; json_t *computer; result = dbi_conn_queryf(dbi->conn, query); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } while (dbi_result_next_row(result)) { computer_id = dbi_result_get_uint(result, "idordenador"); computer_name = dbi_result_get_string(result, "nombreordenador"); computer_ip = dbi_result_get_string(result, "ip"); computer = json_object(); if (!computer) { dbi_result_free(result); return -1; } json_object_set_new(computer, "name", json_string(computer_name)); json_object_set_new(computer, "type", json_string("computer")); json_object_set_new(computer, "id", json_integer(computer_id)); json_object_set_new(computer, "scope", json_array()); json_object_set_new(computer, "ip", json_string(computer_ip)); json_array_append(array, computer); json_decref(computer); } dbi_result_free(result); return 0; } static int og_dbi_scope_get_computer_from_room(const struct og_dbi *dbi, json_t *array, char *query, const uint32_t room_id) { int ret = snprintf(query, OG_QUERY_MAXLEN, "SELECT idordenador, nombreordenador, ip " "FROM ordenadores WHERE idaula=%d and grupoid=0", room_id); if (ret <= 0 || ret >= OG_QUERY_MAXLEN) return -1; return og_dbi_scope_get_computer(dbi, array, query); } static int og_dbi_scope_get_computer_from_computers(const struct og_dbi *dbi, json_t *array, char *query, const uint32_t computers_id) { int ret = snprintf(query, OG_QUERY_MAXLEN, "SELECT idordenador, nombreordenador, ip " "FROM ordenadores WHERE grupoid=%d", computers_id); if (ret <= 0 || ret >= OG_QUERY_MAXLEN) return -1; return og_dbi_scope_get_computer(dbi, array, query); } static int og_dbi_scope_get_computers_from_computers(const struct og_dbi *dbi, json_t *array, char *query, const uint32_t group_id); static int og_dbi_scope_get_computers(const struct og_dbi *dbi, json_t *array, char *query) { const char *msglog, *computers_name; json_t *computers, *scope_array; uint32_t computers_id; dbi_result result; result = dbi_conn_queryf(dbi->conn, query); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } while (dbi_result_next_row(result)) { computers_id = dbi_result_get_uint(result, "idgrupo"); computers_name = dbi_result_get_string(result, "nombregrupoordenador"); computers = json_object(); if (!computers) { dbi_result_free(result); return -1; } json_object_set_new(computers, "name", json_string(computers_name)); json_object_set_new(computers, "type", json_string("folder")); json_object_set_new(computers, "id", json_integer(computers_id)); json_object_set_new(computers, "scope", json_array()); json_array_append(array, computers); json_decref(computers); scope_array = json_object_get(computers, "scope"); if (!scope_array) { dbi_result_free(result); return -1; } if (og_dbi_scope_get_computers_from_computers(dbi, scope_array, query, computers_id)) { dbi_result_free(result); return -1; } if (og_dbi_scope_get_computer_from_computers(dbi, scope_array, query, computers_id)) { dbi_result_free(result); return -1; } } dbi_result_free(result); return 0; } static int og_dbi_scope_get_computers_from_room(const struct og_dbi *dbi, json_t *array, char *query, const uint32_t room_id) { int ret = snprintf(query, OG_QUERY_MAXLEN, "SELECT idgrupo, nombregrupoordenador " "FROM gruposordenadores " "WHERE idaula=%d AND grupoid=0", room_id); if (ret <= 0 || ret >= OG_QUERY_MAXLEN) return -1; return og_dbi_scope_get_computers(dbi, array, query); } static int og_dbi_scope_get_computers_from_computers(const struct og_dbi *dbi, json_t *array, char *query, const uint32_t group_id) { int ret = snprintf(query, OG_QUERY_MAXLEN, "SELECT idgrupo, nombregrupoordenador " "FROM gruposordenadores WHERE grupoid=%d", group_id); if (ret <= 0 || ret >= OG_QUERY_MAXLEN) return -1; return og_dbi_scope_get_computers(dbi, array, query); } static int og_dbi_scope_get_room(const struct og_dbi *dbi, json_t *array, char *query) { const char *msglog, *room_name; json_t *room, *scope_array; dbi_result result; uint32_t room_id; result = dbi_conn_queryf(dbi->conn, query); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } while (dbi_result_next_row(result)) { room_id = dbi_result_get_uint(result, "idaula"); room_name = dbi_result_get_string(result, "nombreaula"); room = json_object(); if (!room) { dbi_result_free(result); return -1; } json_object_set_new(room, "name", json_string(room_name)); json_object_set_new(room, "type", json_string("room")); json_object_set_new(room, "id", json_integer(room_id)); json_object_set_new(room, "scope", json_array()); json_array_append(array, room); json_decref(room); scope_array = json_object_get(room, "scope"); if (!scope_array) { dbi_result_free(result); return -1; } if (og_dbi_scope_get_computers_from_room(dbi, scope_array, query, room_id)) { dbi_result_free(result); return -1; } if (og_dbi_scope_get_computer_from_room(dbi, scope_array, query, room_id)) { dbi_result_free(result); return -1; } } dbi_result_free(result); return 0; } static int og_dbi_scope_get_room_from_group(const struct og_dbi *dbi, json_t *array, char *query, const uint32_t group_id) { int ret = snprintf(query, OG_QUERY_MAXLEN, "SELECT idaula, nombreaula " "FROM aulas WHERE grupoid=%d", group_id); if (ret <= 0 || ret >= OG_QUERY_MAXLEN) return -1; return og_dbi_scope_get_room(dbi, array, query); } static int og_dbi_scope_get_room_from_center(const struct og_dbi *dbi, json_t *array, char *query, const uint32_t center_id) { int ret = snprintf(query, OG_QUERY_MAXLEN, "SELECT idaula, nombreaula " "FROM aulas WHERE idcentro=%d AND grupoid=0", center_id); if (ret <= 0 || ret >= OG_QUERY_MAXLEN) return -1; return og_dbi_scope_get_room(dbi, array, query); } static int og_dbi_scope_get_group_from_group(const struct og_dbi *dbi, json_t *array, char *query, const uint32_t group_id); static int og_dbi_scope_get_group(const struct og_dbi *dbi, json_t *array, char *query) { const char *msglog, *group_name; json_t *group, *scope_array; dbi_result result; uint32_t group_id; result = dbi_conn_queryf(dbi->conn, query); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } while (dbi_result_next_row(result)) { group_id = dbi_result_get_uint(result, "idgrupo"); group_name = dbi_result_get_string(result, "nombregrupo"); group = json_object(); if (!group) { dbi_result_free(result); return -1; } json_object_set_new(group, "name", json_string(group_name)); json_object_set_new(group, "type", json_string("folder")); json_object_set_new(group, "id", json_integer(group_id)); json_object_set_new(group, "scope", json_array()); json_array_append(array, group); json_decref(group); scope_array = json_object_get(group, "scope"); if (!scope_array) { dbi_result_free(result); return -1; } if (og_dbi_scope_get_group_from_group(dbi, scope_array, query, group_id)) { dbi_result_free(result); return -1; } if (og_dbi_scope_get_room_from_group(dbi, scope_array, query, group_id)) { dbi_result_free(result); return -1; } } dbi_result_free(result); return 0; } static int og_dbi_scope_get_group_from_group(const struct og_dbi *dbi, json_t *array, char *query, const uint32_t group_id) { int ret = snprintf(query, OG_QUERY_MAXLEN, "SELECT idgrupo, nombregrupo " "FROM grupos WHERE grupoid=%d", group_id); if (ret <= 0 || ret >= OG_QUERY_MAXLEN) return -1; return og_dbi_scope_get_group(dbi, array, query); } static int og_dbi_scope_get_group_from_center(const struct og_dbi *dbi, json_t *array, char *query, const uint32_t center_id) { int group_type_room = 2; int ret = snprintf(query, OG_QUERY_MAXLEN, "SELECT idgrupo, nombregrupo " "FROM grupos " "WHERE idcentro=%d AND grupoid=0 AND tipo=%d", center_id, group_type_room); if (ret <= 0 || ret >= OG_QUERY_MAXLEN) return -1; return og_dbi_scope_get_group(dbi, array, query); } static int og_dbi_scope_get(struct og_dbi *dbi, json_t *array) { const char *msglog, *center_name; json_t *center, *scope_array; char query[OG_QUERY_MAXLEN]; uint32_t center_id; dbi_result result; result = dbi_conn_queryf(dbi->conn, "SELECT nombrecentro, idcentro FROM centros"); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } while (dbi_result_next_row(result)) { center_id = dbi_result_get_uint(result, "idcentro"); center_name = dbi_result_get_string(result, "nombrecentro"); center = json_object(); if (!center) { dbi_result_free(result); return -1; } scope_array = json_array(); if (!scope_array) { dbi_result_free(result); json_decref(center); return -1; } json_object_set_new(center, "name", json_string(center_name)); json_object_set_new(center, "type", json_string("center")); json_object_set_new(center, "id", json_integer(center_id)); json_object_set_new(center, "scope", scope_array); json_array_append(array, center); json_decref(center); if (og_dbi_scope_get_group_from_center(dbi, scope_array, query, center_id)) { dbi_result_free(result); return -1; } if (og_dbi_scope_get_room_from_center(dbi, scope_array, query, center_id)) { dbi_result_free(result); return -1; } } dbi_result_free(result); return 0; } static int og_cmd_scope_get(json_t *element, struct og_msg_params *params, char *buffer_reply) { struct og_buffer og_buffer = { .data = buffer_reply }; json_t *root, *array; struct og_dbi *dbi; root = json_object(); if (!root) return -1; array = json_array(); if (!array) { json_decref(root); return -1; } json_object_set_new(root, "scope", array); dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", __func__, __LINE__); json_decref(root); return -1; } if (og_dbi_scope_get(dbi, array)) { og_dbi_close(dbi); json_decref(root); return -1; } og_dbi_close(dbi); if (json_dump_callback(root, og_json_dump_clients, &og_buffer, 0)) { json_decref(root); return -1; } json_decref(root); return 0; } int og_dbi_schedule_get(void) { uint32_t schedule_id, task_id; struct og_schedule_time time; struct og_dbi *dbi; const char *msglog; dbi_result result; dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", __func__, __LINE__); return -1; } result = dbi_conn_queryf(dbi->conn, "SELECT idprogramacion, tipoaccion, identificador, " "sesion, annos, meses, diario, dias, semanas, horas, " "ampm, minutos FROM programaciones " "WHERE suspendida = 0"); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); og_dbi_close(dbi); return -1; } while (dbi_result_next_row(result)) { memset(&time, 0, sizeof(time)); schedule_id = dbi_result_get_uint(result, "idprogramacion"); task_id = dbi_result_get_uint(result, "identificador"); time.years = dbi_result_get_uint(result, "annos"); time.months = dbi_result_get_uint(result, "meses"); time.weeks = dbi_result_get_uint(result, "semanas"); time.week_days = dbi_result_get_uint(result, "dias"); time.days = dbi_result_get_uint(result, "diario"); time.hours = dbi_result_get_uint(result, "horas"); time.am_pm = dbi_result_get_uint(result, "ampm"); time.minutes = dbi_result_get_uint(result, "minutos"); time.check_stale = true; og_schedule_create(schedule_id, task_id, OG_SCHEDULE_TASK, &time); } dbi_result_free(result); og_dbi_close(dbi); return 0; } static int og_dbi_schedule_create(struct og_dbi *dbi, struct og_msg_params *params, uint32_t *schedule_id, enum og_schedule_type schedule_type) { uint8_t suspended = 0; uint32_t session = 0; const char *msglog; dbi_result result; uint8_t type; switch (schedule_type) { case OG_SCHEDULE_TASK: type = 3; break; case OG_SCHEDULE_PROCEDURE: type = 2; break; case OG_SCHEDULE_COMMAND: session = atoi(params->task_id); type = 1; break; } result = dbi_conn_queryf(dbi->conn, "INSERT INTO programaciones (tipoaccion," " identificador, nombrebloque, annos, meses," " semanas, dias, diario, horas, ampm, minutos," " suspendida, sesion) VALUES (%d, %s, '%s'," " %d, %d, %d, %d, %d, %d, %d, %d, %d, %d)", type, params->task_id, params->name, params->time.years, params->time.months, params->time.weeks, params->time.week_days, params->time.days, params->time.hours, params->time.am_pm, params->time.minutes, suspended, session); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } dbi_result_free(result); *schedule_id = dbi_conn_sequence_last(dbi->conn, NULL); return 0; } static int og_dbi_schedule_update(struct og_dbi *dbi, struct og_msg_params *params) { const char *msglog; dbi_result result; uint8_t type = 3; result = dbi_conn_queryf(dbi->conn, "UPDATE programaciones SET tipoaccion=%d, " "identificador='%s', nombrebloque='%s', " "annos=%d, meses=%d, " "diario=%d, horas=%d, ampm=%d, minutos=%d " "WHERE idprogramacion='%s'", type, params->task_id, params->name, params->time.years, params->time.months, params->time.days, params->time.hours, params->time.am_pm, params->time.minutes, params->id); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } dbi_result_free(result); return 0; } static int og_dbi_schedule_delete(struct og_dbi *dbi, uint32_t id) { const char *msglog; dbi_result result; result = dbi_conn_queryf(dbi->conn, "DELETE FROM programaciones WHERE idprogramacion=%d", id); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } dbi_result_free(result); return 0; } struct og_db_schedule { uint32_t id; uint32_t task_id; const char *name; struct og_schedule_time time; uint32_t week_days; uint32_t weeks; uint32_t suspended; uint32_t session; }; static int og_dbi_schedule_get_json(struct og_dbi *dbi, json_t *root, const char *task_id, const char *schedule_id) { struct og_db_schedule schedule; json_t *obj, *array; const char *msglog; dbi_result result; int err = 0; if (task_id) { result = dbi_conn_queryf(dbi->conn, "SELECT idprogramacion," " identificador, nombrebloque," " annos, meses, diario, dias," " semanas, horas, ampm," " minutos,suspendida, sesion " "FROM programaciones " "WHERE identificador=%d", atoi(task_id)); } else if (schedule_id) { result = dbi_conn_queryf(dbi->conn, "SELECT idprogramacion," " identificador, nombrebloque," " annos, meses, diario, dias," " semanas, horas, ampm," " minutos,suspendida, sesion " "FROM programaciones " "WHERE idprogramacion=%d", atoi(schedule_id)); } else { result = dbi_conn_queryf(dbi->conn, "SELECT idprogramacion," " identificador, nombrebloque," " annos, meses, diario, dias," " semanas, horas, ampm," " minutos,suspendida, sesion " "FROM programaciones"); } if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } array = json_array(); if (!array) return -1; while (dbi_result_next_row(result)) { schedule.id = dbi_result_get_uint(result, "idprogramacion"); schedule.task_id = dbi_result_get_uint(result, "identificador"); schedule.name = dbi_result_get_string(result, "nombrebloque"); schedule.time.years = dbi_result_get_uint(result, "annos"); schedule.time.months = dbi_result_get_uint(result, "meses"); schedule.time.days = dbi_result_get_uint(result, "diario"); schedule.time.hours = dbi_result_get_uint(result, "horas"); schedule.time.am_pm = dbi_result_get_uint(result, "ampm"); schedule.time.minutes = dbi_result_get_uint(result, "minutos"); schedule.week_days = dbi_result_get_uint(result, "dias"); schedule.weeks = dbi_result_get_uint(result, "semanas"); schedule.suspended = dbi_result_get_uint(result, "suspendida"); schedule.session = dbi_result_get_uint(result, "sesion"); obj = json_object(); if (!obj) { err = -1; break; } json_object_set_new(obj, "id", json_integer(schedule.id)); json_object_set_new(obj, "task", json_integer(schedule.task_id)); json_object_set_new(obj, "name", json_string(schedule.name)); json_object_set_new(obj, "years", json_integer(schedule.time.years)); json_object_set_new(obj, "months", json_integer(schedule.time.months)); json_object_set_new(obj, "days", json_integer(schedule.time.days)); json_object_set_new(obj, "hours", json_integer(schedule.time.hours)); json_object_set_new(obj, "am_pm", json_integer(schedule.time.am_pm)); json_object_set_new(obj, "minutes", json_integer(schedule.time.minutes)); json_object_set_new(obj, "week_days", json_integer(schedule.week_days)); json_object_set_new(obj, "weeks", json_integer(schedule.weeks)); json_object_set_new(obj, "suspended", json_integer(schedule.suspended)); json_object_set_new(obj, "session", json_integer(schedule.session)); json_array_append_new(array, obj); } json_object_set_new(root, "schedule", array); dbi_result_free(result); return err; } static int og_task_schedule_create(struct og_msg_params *params) { enum og_schedule_type type; uint32_t schedule_id; struct og_dbi *dbi; int err; if (!strcmp(params->type, "task")) type = OG_SCHEDULE_TASK; else if (!strcmp(params->type, "procedure")) type = OG_SCHEDULE_PROCEDURE; else if (!strcmp(params->type, "command")) type = OG_SCHEDULE_COMMAND; else return -1; dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", __func__, __LINE__); return -1; } err = og_dbi_schedule_create(dbi, params, &schedule_id, type); if (err < 0) { og_dbi_close(dbi); return -1; } og_schedule_create(schedule_id, atoi(params->task_id), type, ¶ms->time); og_schedule_refresh(og_loop); og_dbi_close(dbi); return 0; } static uint32_t og_tm_years_mask(struct tm *tm) { int i, j = 0; for (i = 2010; i < 2026; i++, j++) { if (tm->tm_year + 1900 == i) break; } return (1 << j); } static uint32_t og_tm_months_mask(struct tm *tm) { return 1 << tm->tm_mon; } static uint16_t og_tm_hours_mask(struct tm *tm) { return tm->tm_hour >= 12 ? 1 << (tm->tm_hour - 12) : 1 << tm->tm_hour; } static uint32_t og_tm_ampm(struct tm *tm) { return tm->tm_hour < 12 ? 0 : 1; } static uint32_t og_tm_days_mask(struct tm *tm) { return 1 << (tm->tm_mday - 1); } static void og_schedule_time_now(struct og_schedule_time *ogtime) { struct tm *tm; time_t now; now = time(NULL); tm = localtime(&now); ogtime->years = og_tm_years_mask(tm); ogtime->months = og_tm_months_mask(tm); ogtime->weeks = 0; ogtime->week_days = 0; ogtime->days = og_tm_days_mask(tm); ogtime->hours = og_tm_hours_mask(tm); ogtime->am_pm = og_tm_ampm(tm); ogtime->minutes = tm->tm_min; } static int og_cmd_schedule_create(json_t *element, struct og_msg_params *params) { bool when = false; 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, "task")) { err = og_json_parse_string(value, ¶ms->task_id); params->flags |= OG_REST_PARAM_TASK; } else if (!strcmp(key, "name")) { err = og_json_parse_string(value, ¶ms->name); params->flags |= OG_REST_PARAM_NAME; } else if (!strcmp(key, "when")) { err = og_json_parse_time_params(value, params); when = true; } else if (!strcmp(key, "type")) { err = og_json_parse_string(value, ¶ms->type); params->flags |= OG_REST_PARAM_TYPE; } if (err < 0) return err; } if (!when) { params->time.check_stale = false; og_schedule_time_now(¶ms->time); params->flags |= OG_REST_PARAM_TIME_YEARS | OG_REST_PARAM_TIME_MONTHS | OG_REST_PARAM_TIME_WEEKS | OG_REST_PARAM_TIME_WEEK_DAYS | OG_REST_PARAM_TIME_DAYS | OG_REST_PARAM_TIME_HOURS | OG_REST_PARAM_TIME_AM_PM | OG_REST_PARAM_TIME_MINUTES; } else { params->time.check_stale = true; } if (!og_msg_params_validate(params, OG_REST_PARAM_TASK | OG_REST_PARAM_NAME | OG_REST_PARAM_TIME_YEARS | OG_REST_PARAM_TIME_MONTHS | OG_REST_PARAM_TIME_WEEKS | OG_REST_PARAM_TIME_WEEK_DAYS | OG_REST_PARAM_TIME_DAYS | OG_REST_PARAM_TIME_HOURS | OG_REST_PARAM_TIME_MINUTES | OG_REST_PARAM_TIME_AM_PM | OG_REST_PARAM_TYPE)) return -1; return og_task_schedule_create(params); } static int og_cmd_schedule_update(json_t *element, struct og_msg_params *params) { struct og_dbi *dbi; bool when = false; 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, "id")) { err = og_json_parse_string(value, ¶ms->id); params->flags |= OG_REST_PARAM_ID; } else if (!strcmp(key, "task")) { err = og_json_parse_string(value, ¶ms->task_id); params->flags |= OG_REST_PARAM_TASK; } else if (!strcmp(key, "name")) { err = og_json_parse_string(value, ¶ms->name); params->flags |= OG_REST_PARAM_NAME; } else if (!strcmp(key, "when")) { err = og_json_parse_time_params(value, params); when = true; } if (err < 0) return err; } if (!when) { params->time.check_stale = false; og_schedule_time_now(¶ms->time); params->flags |= OG_REST_PARAM_TIME_YEARS | OG_REST_PARAM_TIME_MONTHS | OG_REST_PARAM_TIME_WEEKS | OG_REST_PARAM_TIME_WEEK_DAYS | OG_REST_PARAM_TIME_DAYS | OG_REST_PARAM_TIME_HOURS | OG_REST_PARAM_TIME_AM_PM | OG_REST_PARAM_TIME_MINUTES; } else { params->time.check_stale = true; } if (!og_msg_params_validate(params, OG_REST_PARAM_ID | OG_REST_PARAM_TASK | OG_REST_PARAM_NAME | OG_REST_PARAM_TIME_YEARS | OG_REST_PARAM_TIME_MONTHS | OG_REST_PARAM_TIME_DAYS | OG_REST_PARAM_TIME_HOURS | OG_REST_PARAM_TIME_MINUTES | OG_REST_PARAM_TIME_AM_PM)) return -1; dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", __func__, __LINE__); return -1; } err = og_dbi_schedule_update(dbi, params); og_dbi_close(dbi); if (err < 0) return err; og_schedule_update(og_loop, atoi(params->id), atoi(params->task_id), ¶ms->time); og_schedule_refresh(og_loop); return err; } static int og_cmd_schedule_delete(json_t *element, struct og_msg_params *params) { struct og_dbi *dbi; 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, "id")) { err = og_json_parse_string(value, ¶ms->id); params->flags |= OG_REST_PARAM_ID; } if (err < 0) return err; } if (!og_msg_params_validate(params, OG_REST_PARAM_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; } err = og_dbi_schedule_delete(dbi, atoi(params->id)); og_dbi_close(dbi); og_schedule_delete(og_loop, atoi(params->id)); return err; } static int og_cmd_schedule_get(json_t *element, struct og_msg_params *params, char *buffer_reply) { struct og_buffer og_buffer = { .data = buffer_reply, }; json_t *schedule_root; struct og_dbi *dbi; const char *key; json_t *value; int err = 0; if (element) { if (json_typeof(element) != JSON_OBJECT) return -1; json_object_foreach(element, key, value) { if (!strcmp(key, "task")) { err = og_json_parse_string(value, ¶ms->task_id); } else if (!strcmp(key, "id")) { err = og_json_parse_string(value, ¶ms->id); } if (err < 0) return err; } } dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", __func__, __LINE__); return -1; } schedule_root = json_object(); if (!schedule_root) { og_dbi_close(dbi); return -1; } err = og_dbi_schedule_get_json(dbi, schedule_root, params->task_id, params->id); og_dbi_close(dbi); if (err >= 0) err = json_dump_callback(schedule_root, og_json_dump_clients, &og_buffer, 0); json_decref(schedule_root); return err; } #define OG_LIVE_JSON_FILE_PATH "/opt/opengnsys/etc/ogliveinfo.json" static int og_cmd_oglive_list(char *buffer_reply) { struct og_buffer og_buffer = { .data = buffer_reply }; json_error_t json_err; json_t *root; root = json_load_file(OG_LIVE_JSON_FILE_PATH, 0, &json_err); if (!root) { syslog(LOG_ERR, "malformed json line %d: %s\n", json_err.line, json_err.text); return -1; } if (json_dump_callback(root, og_json_dump_clients, &og_buffer, 0)) { json_decref(root); return -1; } json_decref(root); return 0; } static int og_cmd_post_center_add(json_t *element, struct og_msg_params *params, char *buffer_reply) { const char *key, *msglog; struct og_dbi *dbi; dbi_result result; json_t *value; int err = 0; json_object_foreach(element, key, value) { if (!strcmp(key, "name")) { err = og_json_parse_string(value, ¶ms->name); params->flags |= OG_REST_PARAM_NAME; } else if (!strcmp(key, "comment")) { err = og_json_parse_string(value, ¶ms->comment); } if (err < 0) return err; } if (!og_msg_params_validate(params, OG_REST_PARAM_NAME)) return -1; if (!params->comment) params->comment = ""; dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open conection database (%s:%d)\n", __func__, __LINE__); return -1; } result = dbi_conn_queryf(dbi->conn, "SELECT nombrecentro FROM centros WHERE nombrecentro='%s'", params->name); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); og_dbi_close(dbi); return -1; } if (dbi_result_get_numrows(result) > 0) { syslog(LOG_ERR, "Center with name %s already exists\n", params->name); dbi_result_free(result); og_dbi_close(dbi); return -1; } dbi_result_free(result); result = dbi_conn_queryf(dbi->conn, "INSERT INTO centros(" " nombrecentro," " comentarios," " identidad) VALUES (" "'%s', '%s', 1)", params->name, params->comment); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to add center to database (%s:%d) %s\n", __func__, __LINE__, msglog); og_dbi_close(dbi); return -1; } dbi_result_free(result); og_dbi_close(dbi); return 0; } static int og_cmd_post_center_delete(json_t *element, struct og_msg_params *params) { const char *key, *msglog; struct og_dbi *dbi; dbi_result result; json_t *value; int err = 0; json_object_foreach(element, key, value) { if (!strcmp(key, "id")) { err = og_json_parse_string(value, ¶ms->id); params->flags |= OG_REST_PARAM_ID; } if (err < 0) return err; } if (!og_msg_params_validate(params, OG_REST_PARAM_ID)) return -1; dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open conection database (%s:%d)\n", __func__, __LINE__); return -1; } result = dbi_conn_queryf(dbi->conn, "DELETE FROM centros WHERE idcentro=%s", params->id); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); og_dbi_close(dbi); return -1; } if (dbi_result_get_numrows_affected(result) < 1) { dbi_result_free(result); og_dbi_close(dbi); return -1; } dbi_result_free(result); og_dbi_close(dbi); return 0; } int og_procedure_add_steps(struct og_dbi *dbi, struct og_procedure *proc) { struct og_procedure_step *step; const char *legacy_params; const char *msglog; dbi_result result; int i; for (i = 0; i < proc->num_steps; i++) { step = &proc->steps[i]; switch (step->type) { case OG_STEP_COMMAND: legacy_params = og_msg_params_to_legacy(&step->cmd); if (!legacy_params) { og_dbi_close(dbi); return -1; } result = dbi_conn_queryf(dbi->conn, "INSERT INTO procedimientos_acciones " "(idprocedimiento, orden, parametros) " "VALUES (%d, %d, '%s')", proc->id, step->position, legacy_params); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to add procedure command to database (%s:%d) %s\n", __func__, __LINE__, msglog); og_dbi_close(dbi); free((char *)legacy_params); return -1; } dbi_result_free(result); free((char *)legacy_params); break; case OG_STEP_PROCEDURE: result = dbi_conn_queryf(dbi->conn, "INSERT INTO procedimientos_acciones " "(idprocedimiento, orden, procedimientoid) " "VALUES (%d, %d, %d)", proc->id, step->position, step->procedure.id); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to add procedure child to database (%s:%d) %s\n", __func__, __LINE__, msglog); og_dbi_close(dbi); return -1; } dbi_result_free(result); break; case OG_STEP_TASK: syslog(LOG_ERR, "Procedures can not include tasks. " "Invalid step: %d\n", step->position); return -1; break; } } return 0; } static int og_cmd_post_procedure_add(json_t *element, struct og_msg_params *params) { struct og_procedure proc = {}; const char *key, *msglog; struct og_dbi *dbi; dbi_result result; json_t *value; int err = 0; json_object_foreach(element, key, value) { if (!strcmp(key, "center")) { err = og_json_parse_string(value, ¶ms->id); params->flags |= OG_REST_PARAM_ID; } else if (!strcmp(key, "name")) { err = og_json_parse_string(value, ¶ms->name); params->flags |= OG_REST_PARAM_NAME; } else if (!strcmp(key, "description")) { err = og_json_parse_string(value, ¶ms->comment); } else if (!strcmp(key, "steps")) { err = og_json_parse_procedure(value, &proc); } if (err < 0) return err; } if (!og_msg_params_validate(params, OG_REST_PARAM_ID | OG_REST_PARAM_NAME)) return -1; dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open conection database (%s:%d)\n", __func__, __LINE__); return -1; } result = dbi_conn_queryf(dbi->conn, "SELECT descripcion FROM procedimientos " "WHERE descripcion='%s' AND idcentro=%s", params->name, params->id); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); og_dbi_close(dbi); return -1; } if (dbi_result_get_numrows(result) > 0) { syslog(LOG_ERR, "Procedure with name %s already exists in the " "center with id %s\n", params->name, params->id); dbi_result_free(result); og_dbi_close(dbi); return -1; } dbi_result_free(result); result = dbi_conn_queryf(dbi->conn, "INSERT INTO procedimientos(" "idcentro, descripcion, comentarios) " "VALUES (%s, '%s', '%s')", params->id, params->name, params->comment); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to add procedure to database (%s:%d) %s\n", __func__, __LINE__, msglog); og_dbi_close(dbi); return -1; } dbi_result_free(result); proc.id = dbi_conn_sequence_last(dbi->conn, NULL); err = og_procedure_add_steps(dbi, &proc); og_dbi_close(dbi); return err; } static int og_cmd_post_procedure_delete(json_t *element, struct og_msg_params *params) { const char *key, *msglog; struct og_dbi *dbi; dbi_result result; json_t *value; int err = 0; json_object_foreach(element, key, value) { if (!strcmp(key, "id")) { err = og_json_parse_string(value, ¶ms->id); params->flags |= OG_REST_PARAM_ID; } if (err < 0) return err; } if (!og_msg_params_validate(params, OG_REST_PARAM_ID)) return -1; dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open conection database (%s:%d)\n", __func__, __LINE__); return -1; } result = dbi_conn_queryf(dbi->conn, "DELETE FROM procedimientos WHERE idprocedimiento=%s", params->id); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); og_dbi_close(dbi); return -1; } else if (dbi_result_get_numrows_affected(result) < 1) { syslog(LOG_ERR, "delete did not modify any row (%s:%d)\n", __func__, __LINE__); } dbi_result_free(result); og_dbi_close(dbi); return 0; } static int og_cmd_post_procedure_update(json_t *element, struct og_msg_params *params) { struct og_procedure proc = {}; const char *key, *msglog; struct og_dbi *dbi; dbi_result result; json_t *value; int err = 0; json_object_foreach(element, key, value) { if (!strcmp(key, "procedure")) { err = og_json_parse_string(value, ¶ms->task_id); params->flags |= OG_REST_PARAM_TASK; } else if (!strcmp(key, "center")) { err = og_json_parse_string(value, ¶ms->id); params->flags |= OG_REST_PARAM_ID; } else if (!strcmp(key, "name")) { err = og_json_parse_string(value, ¶ms->name); params->flags |= OG_REST_PARAM_NAME; } else if (!strcmp(key, "description")) { err = og_json_parse_string(value, ¶ms->comment); } else if (!strcmp(key, "steps")) { err = og_json_parse_procedure(value, &proc); } if (err < 0) return err; } if (!og_msg_params_validate(params, OG_REST_PARAM_TASK | OG_REST_PARAM_ID | OG_REST_PARAM_NAME)) return -1; dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open conection database (%s:%d)\n", __func__, __LINE__); return -1; } result = dbi_conn_queryf(dbi->conn, "SELECT descripcion FROM procedimientos " "WHERE descripcion = '%s' AND idcentro = %s " "AND idprocedimiento <> %s", params->name, params->id, params->task_id); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); og_dbi_close(dbi); return -1; } if (dbi_result_get_numrows(result) > 0) { syslog(LOG_ERR, "Procedure with name %s already exists in the " "center with id %s\n", params->name, params->id); dbi_result_free(result); og_dbi_close(dbi); return -1; } dbi_result_free(result); result = dbi_conn_queryf(dbi->conn, "UPDATE procedimientos SET idcentro = %s, " "descripcion = '%s', comentarios = '%s' " "WHERE idprocedimiento = %s", params->id, params->name, params->comment, params->task_id); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to update procedure %s (%s:%d) %s\n", params->task_id, __func__, __LINE__, msglog); og_dbi_close(dbi); return -1; } dbi_result_free(result); result = dbi_conn_queryf(dbi->conn, "DELETE FROM procedimientos_acciones " "WHERE idprocedimiento = %s", params->task_id); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to delete old procedure %s steps (%s:%d) %s\n", params->task_id, __func__, __LINE__, msglog); og_dbi_close(dbi); return -1; } dbi_result_free(result); proc.id = atoll(params->task_id); err = og_procedure_add_steps(dbi, &proc); og_dbi_close(dbi); return err; } static int og_task_add_steps(struct og_dbi *dbi, struct og_procedure *task) { struct og_procedure_step *step; const char *msglog; dbi_result result; int i; for (i = 0; i < task->num_steps; i++) { step = &task->steps[i]; switch (step->type) { case OG_STEP_COMMAND: syslog(LOG_ERR, "Tasks can not include commands. " "Invalid step: %d\n", step->position); return -1; break; case OG_STEP_PROCEDURE: result = dbi_conn_queryf(dbi->conn, "INSERT INTO tareas_acciones " "(idtarea, orden, idprocedimiento) " "VALUES (%d, %d, %d)", task->id, step->position, step->procedure.id); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to add procedure child to database (%s:%d) %s\n", __func__, __LINE__, msglog); og_dbi_close(dbi); return -1; } dbi_result_free(result); break; case OG_STEP_TASK: result = dbi_conn_queryf(dbi->conn, "INSERT INTO tareas_acciones " "(idtarea, orden, tareaid) " "VALUES (%d, %d, %d)", task->id, step->position, step->procedure.id); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to add task child to database (%s:%d) %s\n", __func__, __LINE__, msglog); og_dbi_close(dbi); return -1; } dbi_result_free(result); break; } } return 0; } static int og_cmd_post_task_add(json_t *element, struct og_msg_params *params) { struct og_procedure task = {}; const char *key, *msglog; struct og_dbi *dbi; dbi_result result; json_t *value; int err = 0; json_object_foreach(element, key, value) { if (!strcmp(key, "center")) { err = og_json_parse_string(value, ¶ms->id); params->flags |= OG_REST_PARAM_ID; } else if (!strcmp(key, "name")) { err = og_json_parse_string(value, ¶ms->name); params->flags |= OG_REST_PARAM_NAME; } else if (!strcmp(key, "description")) { err = og_json_parse_string(value, ¶ms->comment); } else if (!strcmp(key, "steps")) { err = og_json_parse_procedure(value, &task); } if (err < 0) return err; } if (!og_msg_params_validate(params, OG_REST_PARAM_ID | OG_REST_PARAM_NAME)) return -1; dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open conection database (%s:%d)\n", __func__, __LINE__); return -1; } result = dbi_conn_queryf(dbi->conn, "SELECT descripcion FROM tareas " "WHERE descripcion='%s' AND idcentro=%s", params->name, params->id); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); og_dbi_close(dbi); return -1; } if (dbi_result_get_numrows(result) > 0) { syslog(LOG_ERR, "Task with name %s already exists in the " "center with id %s\n", params->name, params->id); dbi_result_free(result); og_dbi_close(dbi); return -1; } dbi_result_free(result); result = dbi_conn_queryf(dbi->conn, "INSERT INTO tareas(" "idcentro, descripcion, comentarios) " "VALUES (%s, '%s', '%s')", params->id, params->name, params->comment); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to add task to database (%s:%d) %s\n", __func__, __LINE__, msglog); og_dbi_close(dbi); return -1; } dbi_result_free(result); task.id = dbi_conn_sequence_last(dbi->conn, NULL); err = og_task_add_steps(dbi, &task); og_dbi_close(dbi); return err; } static int og_cmd_post_repository_update(json_t *element, struct og_msg_params *params, char *buffer_reply) { struct og_repository repo = {}; const char *key, *msglog; unsigned int repo_id; struct og_dbi *dbi; dbi_result result; json_t *value; int err = 0; json_object_foreach(element, key, value) { if (!strcmp(key, "repo_id")) { err = og_json_parse_uint(value, &repo_id); params->flags |= OG_REST_PARAM_ID; } if (!strcmp(key, "name")) { err = og_json_parse_string_copy(value, repo.name, sizeof(repo.name)); } else if (!strcmp(key, "ip")) { err = og_json_parse_string_copy(value, repo.ip, sizeof(repo.ip)); } else if (!strcmp(key, "center")) { err = og_json_parse_uint(value, &repo.center); } if (err < 0) return err; } if (!og_msg_params_validate(params, OG_REST_PARAM_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; } result = dbi_conn_queryf(dbi->conn, "UPDATE repositorios" " SET nombrerepositorio='%s'," " ip='%s'," " idcentro=%u" " WHERE idrepositorio=%u;", repo.name, repo.ip, repo.center, repo_id); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to update repository in database (%s:%d) %s\n", __func__, __LINE__, msglog); og_dbi_close(dbi); return -1; } if (!dbi_result_get_numrows_affected(result)) { syslog(LOG_ERR, "repository with id %u does not exist (%s:%d)\n", repo_id, __func__, __LINE__); dbi_result_free(result); og_dbi_close(dbi); return -1; } dbi_result_free(result); og_dbi_close(dbi); return err; } static int og_cmd_post_repository_add(json_t *element, struct og_msg_params *params, char *buffer_reply) { struct og_repository repo = { .center = 1, /* never used, set it to 1. */ }; const char *key, *msglog; struct in_addr addr; struct og_dbi *dbi; dbi_result result; json_t *value; int err = 0; json_object_foreach(element, key, value) { if (!strcmp(key, "name")) { err = og_json_parse_string_copy(value, repo.name, sizeof(repo.name)); params->flags |= OG_REST_PARAM_NAME; } else if (!strcmp(key, "ip")) { err = og_json_parse_string_copy(value, repo.ip, sizeof(repo.ip)); params->flags |= OG_REST_PARAM_ADDR; } else if (!strcmp(key, "center")) { err = og_json_parse_uint(value, &repo.center); } if (err < 0) return err; } if (!og_msg_params_validate(params, OG_REST_PARAM_NAME | OG_REST_PARAM_ADDR)) return -1; if (inet_pton(AF_INET, repo.ip, &addr) <= 0) { syslog(LOG_ERR, "invalid server ip address (%s:%d)\n", __func__, __LINE__); return -1; } dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open conection database (%s:%d)\n", __func__, __LINE__); return -1; } result = dbi_conn_queryf(dbi->conn, "INSERT INTO repositorios(" "nombrerepositorio, ip, idcentro, grupoid) VALUES " "('%s', '%s', %u, 0)", repo.name, repo.ip, repo.center); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to add repository to database (%s:%d) %s\n", __func__, __LINE__, msglog); og_dbi_close(dbi); return -1; } dbi_result_free(result); og_dbi_close(dbi); return err; } static int og_cmd_post_repository_delete(json_t *element, struct og_msg_params *params) { const char *key, *msglog; struct og_dbi *dbi; dbi_result result; json_t *value; int err = 0; json_object_foreach(element, key, value) { if (!strcmp(key, "id")) { err = og_json_parse_string(value, ¶ms->id); params->flags |= OG_REST_PARAM_ID; } if (err < 0) return err; } if (!og_msg_params_validate(params, OG_REST_PARAM_ID)) return -1; dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open conection database (%s:%d)\n", __func__, __LINE__); return -1; } result = dbi_conn_queryf(dbi->conn, "DELETE FROM repositorios " "WHERE idrepositorio=%s", params->id); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to delete repository from database " "(%s:%d) %s\n", __func__, __LINE__, msglog); og_dbi_close(dbi); return -1; } if (dbi_result_get_numrows_affected(result) < 1) { dbi_result_free(result); og_dbi_close(dbi); return -1; } dbi_result_free(result); og_dbi_close(dbi); return 0; } static int og_cmd_post_room_add(json_t *element, struct og_msg_params *params) { struct og_room room = {}; const char *key, *msglog; struct og_dbi *dbi; dbi_result result; json_t *value; int err = 0; json_object_foreach(element, key, value) { if (!strcmp(key, "name")) { err = og_json_parse_string_copy(value, room.name, sizeof(room.name)); params->flags |= OG_REST_PARAM_NAME; } else if (!strcmp(key, "location")) { err = og_json_parse_string_copy(value, room.location, sizeof(room.location)); } else if (!strcmp(key, "gateway")) { err = og_json_parse_string_copy(value, room.gateway, sizeof(room.gateway)); } else if (!strcmp(key, "netmask")) { err = og_json_parse_string_copy(value, room.netmask, sizeof(room.netmask)); params->flags |= OG_REST_PARAM_NETMASK; } else if (!strcmp(key, "ntp")) { err = og_json_parse_string_copy(value, room.ntp, sizeof(room.ntp)); } else if (!strcmp(key, "dns")) { err = og_json_parse_string_copy(value, room.dns, sizeof(room.dns)); } else if (!strcmp(key, "center")) { err = og_json_parse_uint(value, &room.center); params->flags |= OG_REST_PARAM_CENTER; } else if (!strcmp(key, "group")) { err = og_json_parse_uint(value, &room.group); } else if (!strcmp(key, "remote")) { err = og_json_parse_bool(value, &room.remote); } if (err < 0) return err; } if (!og_msg_params_validate(params, OG_REST_PARAM_NAME | OG_REST_PARAM_NETMASK | OG_REST_PARAM_CENTER)) return -1; dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open conection database (%s:%d)\n", __func__, __LINE__); return -1; } result = dbi_conn_queryf(dbi->conn, "SELECT nombreaula FROM aulas " "WHERE nombreaula='%s' AND idcentro=%d", room.name, room.center); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); og_dbi_close(dbi); return -1; } if (dbi_result_get_numrows(result) > 0) { syslog(LOG_ERR, "Room with name %s already exists in the " "center with id %d\n", room.name, room.center); dbi_result_free(result); og_dbi_close(dbi); return -1; } dbi_result_free(result); result = dbi_conn_queryf(dbi->conn, "INSERT INTO aulas(" " idcentro," " nombreaula," " netmask," " grupoid," " ubicacion," " router," " dns," " ntp," " inremotepc) VALUES (" "%d, '%s', '%s', %d, '%s', " "'%s', '%s', '%s', %d)", room.center, room.name, room.netmask, room.group, room.location, room.gateway, room.dns, room.ntp, room.remote); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to add room to database (%s:%d) %s\n", __func__, __LINE__, msglog); og_dbi_close(dbi); return -1; } dbi_result_free(result); og_dbi_close(dbi); return 0; } static int og_cmd_post_room_delete(json_t *element, struct og_msg_params *params) { const char *key, *msglog; struct og_dbi *dbi; dbi_result result; json_t *value; int err = 0; json_object_foreach(element, key, value) { if (!strcmp(key, "id")) { err = og_json_parse_string(value, ¶ms->id); params->flags |= OG_REST_PARAM_ID; } if (err < 0) return err; } if (!og_msg_params_validate(params, OG_REST_PARAM_ID)) return -1; dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open conection database (%s:%d)\n", __func__, __LINE__); return -1; } result = dbi_conn_queryf(dbi->conn, "DELETE FROM aulas WHERE idaula=%s", params->id); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); og_dbi_close(dbi); return -1; } if (dbi_result_get_numrows_affected(result) < 1) { dbi_result_free(result); og_dbi_close(dbi); return -1; } dbi_result_free(result); og_dbi_close(dbi); return 0; } enum { OG_SCHEDULE_CMD_TYPE = 0, OG_SCHEDULE_CMD_PARAMS, }; static bool og_cmd_validate(const struct og_cmd_json *cmd, const uint64_t flags) { return (cmd->flags & flags) == flags; } static int og_cmd_post_schedule_command(json_t *element, struct og_msg_params *params) { char *centerid_query = "SELECT o.idordenador, c.idcentro " "FROM `ordenadores` AS o " "INNER JOIN aulas AS a ON o.idaula = a.idaula " "INNER JOIN centros AS c ON a.idcentro = c.idcentro " "WHERE o.ip = '%s';"; uint32_t sequence, session = 0; int center_id, client_id, len; struct og_cmd_json cmd = {}; const char *legacy_params; const char *key, *msglog; struct og_dbi *dbi; char task_id[128]; bool when = false; dbi_result result; json_t *value; int err = 0, i; json_object_foreach(element, key, value) { if (!strcmp(key, "clients")) { err = og_json_parse_clients(value, params); } else if (!strcmp(key, "command")) { err = og_json_parse_string(value, &cmd.type); cmd.flags |= OG_SCHEDULE_CMD_TYPE; } else if (!strcmp(key, "params")) { cmd.json = value; cmd.flags |= OG_SCHEDULE_CMD_PARAMS; } else if (!strcmp(key, "when")) { err = og_json_parse_time_params(value, params); when = true; } if (err < 0) return err; } if (!og_cmd_validate(&cmd, OG_SCHEDULE_CMD_TYPE | OG_SCHEDULE_CMD_PARAMS)) return -1; if (!when) { params->time.check_stale = false; og_schedule_time_now(¶ms->time); params->flags |= OG_REST_PARAM_TIME_YEARS | OG_REST_PARAM_TIME_MONTHS | OG_REST_PARAM_TIME_WEEKS | OG_REST_PARAM_TIME_WEEK_DAYS | OG_REST_PARAM_TIME_DAYS | OG_REST_PARAM_TIME_HOURS | OG_REST_PARAM_TIME_AM_PM | OG_REST_PARAM_TIME_MINUTES; } else { params->time.check_stale = true; } if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR | OG_REST_PARAM_TIME_YEARS | OG_REST_PARAM_TIME_MONTHS | OG_REST_PARAM_TIME_WEEKS | OG_REST_PARAM_TIME_WEEK_DAYS | OG_REST_PARAM_TIME_DAYS | OG_REST_PARAM_TIME_HOURS | OG_REST_PARAM_TIME_MINUTES | OG_REST_PARAM_TIME_AM_PM)) return -1; params->type = "command"; dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open conection database (%s:%d)\n", __func__, __LINE__); goto err_dbi_open; } legacy_params = og_msg_params_to_legacy(&cmd); if (!legacy_params) goto err_legacy_params; /* ips_array -> ids */ for (i = 0; i < params->ips_array_len; i++) { result = dbi_conn_queryf(dbi->conn, centerid_query, params->ips_array[i]); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); goto err_dbi_result; } if (dbi_result_get_numrows(result) != 1) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "client not found (%s:%d) %s\n", __func__, __LINE__, msglog); goto err_dbi; } if (!dbi_result_next_row(result)) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to get idcentro (%s:%d) %s\n", __func__, __LINE__, msglog); goto err_dbi; } center_id = dbi_result_get_uint(result, "idcentro"); if (!center_id) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to get idcentro (%s:%d) %s\n", __func__, __LINE__, msglog); goto err_dbi; } client_id = dbi_result_get_uint(result, "idordenador"); dbi_result_free(result); result = dbi_conn_queryf(dbi->conn, "INSERT INTO acciones (idordenador, " "idcentro, parametros)" "VALUES (%d, %d, '%s')", client_id, center_id, legacy_params); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); goto err_dbi_result; } dbi_result_free(result); sequence = dbi_conn_sequence_last(dbi->conn, NULL); /* This 'session' ID allows us to correlate the schedule with * the commands after expansion. */ if (!session) session = dbi_conn_sequence_last(dbi->conn, NULL); result = dbi_conn_queryf(dbi->conn, "UPDATE acciones SET idordenador=%d, " "idcentro=%d, parametros='%s', sesion=%d" "WHERE idaccion=%d", client_id, center_id, legacy_params, session, sequence); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); goto err_dbi_result; } dbi_result_free(result); } len = snprintf(task_id, sizeof(session), "%d", session); if (len >= (int)sizeof(task_id)) { syslog(LOG_ERR, "truncated snprintf (%s:%d)\n", __func__, __LINE__); goto err_dbi_result; } params->task_id = task_id; og_task_schedule_create(params); free((char *)legacy_params); og_dbi_close(dbi); return 0; err_dbi: dbi_result_free(result); err_dbi_result: free((char *)legacy_params); err_legacy_params: og_dbi_close(dbi); err_dbi_open: return -1; } static int og_cmd_post_procedure_run(json_t *element, struct og_msg_params *params) { const char *centerid_query = "SELECT o.idordenador, c.idcentro " "FROM `ordenadores` AS o " "INNER JOIN aulas AS a " "ON o.idaula = a.idaula " "INNER JOIN centros AS c " "ON a.idcentro = c.idcentro " "WHERE o.ip = '%s';"; struct og_task task = {}; const char *key, *msglog; struct og_dbi *dbi; dbi_result result; int i, err = 0; json_t *value; json_object_foreach(element, key, value) { if (!strcmp(key, "clients")) { err = og_json_parse_clients(value, params); } else if (!strcmp(key, "procedure")) { err = og_json_parse_string(value, ¶ms->id); params->flags |= OG_REST_PARAM_ID; } if (err < 0) goto err_return; } if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR | OG_REST_PARAM_ID )) goto err_return; task.type_scope = AMBITO_ORDENADORES; task.procedure_id = atoi(params->id); dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open conection database (%s:%d)\n", __func__, __LINE__); goto err_return; } for (i = 0; i < params->ips_array_len; i++) { result = dbi_conn_queryf(dbi->conn, centerid_query, params->ips_array[i]); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); goto err_close_dbi; } if (dbi_result_get_numrows(result) != 1 || !dbi_result_next_row(result) || !dbi_result_get_uint(result, "idcentro") || !dbi_result_get_uint(result, "idordenador")) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to get query data (%s:%d) %s\n", __func__, __LINE__, msglog); goto err_free_result; } task.center_id = dbi_result_get_uint(result, "idcentro"); task.scope = dbi_result_get_uint(result, "idordenador"); dbi_result_free(result); if (og_dbi_queue_procedure(dbi, &task)) goto err_close_dbi; } og_dbi_close(dbi); return og_send_request(OG_METHOD_GET, OG_CMD_RUN_SCHEDULE, params, NULL); err_free_result: dbi_result_free(result); err_close_dbi: og_dbi_close(dbi); err_return: return -1; } static int og_cmd_get_servers(char *buffer_reply) { json_t *root, *servers, *address; struct og_buffer og_buffer = { .data = buffer_reply, }; char ipaddr[50] = {}; struct og_dbi *dbi; dbi_result result; int id, ret; root = json_object(); if (!root) return -1; servers = json_array(); if (!servers) { json_decref(root); return -1; } dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", __func__, __LINE__); json_decref(root); return -1; } result = dbi_conn_queryf(dbi->conn, "SELECT identorno, ipserveradm " "FROM entornos"); while (dbi_result_next_row(result)) { address = json_object(); id = dbi_result_get_int(result, "identorno"); snprintf(ipaddr, sizeof(ipaddr), "%s", dbi_result_get_string(result, "ipserveradm")); json_object_set_new(address, "id", json_integer(id)); json_object_set_new(address, "address", json_string(ipaddr)); json_array_append_new(servers, address); } json_object_set_new(root, "servers", servers); dbi_result_free(result); og_dbi_close(dbi); ret = json_dump_callback(root, og_json_dump_clients, &og_buffer, 0); json_decref(root); return ret; } static int og_cmd_post_server(json_t *element, struct og_msg_params *params, char *buffer_reply) { struct og_buffer og_buffer = { .data = buffer_reply, }; const char *key, *msglog; json_t *value, *root; int err = 0, id, ret; struct in_addr addr; struct og_dbi *dbi; dbi_result result; json_object_foreach(element, key, value) { if (!strcmp(key, "address")) { err = og_json_parse_string(value, ¶ms->name); params->flags |= OG_REST_PARAM_NAME; } if (err < 0) return err; } if (!og_msg_params_validate(params, OG_REST_PARAM_NAME)) return -1; if (inet_pton(AF_INET, params->name, &addr) <= 0) { syslog(LOG_ERR, "invalid server ip address (%s:%d)\n", __func__, __LINE__); return -1; } dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open conection database (%s:%d)\n", __func__, __LINE__); return -1; } result = dbi_conn_queryf(dbi->conn, "SELECT identorno FROM entornos WHERE ipserveradm='%s'", params->name); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); og_dbi_close(dbi); return -1; } if (dbi_result_get_numrows(result) > 0) { syslog(LOG_ERR, "Address %s already exists\n", params->name); dbi_result_free(result); og_dbi_close(dbi); return -1; } dbi_result_free(result); result = dbi_conn_queryf(dbi->conn, "INSERT INTO entornos(" " ipserveradm," " protoclonacion) VALUES (" "'%s', 'UNICAST')", params->name); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to add new ogserver address to database (%s:%d) %s\n", __func__, __LINE__, msglog); og_dbi_close(dbi); return -1; } root = json_object(); if (!root) { syslog(LOG_ERR, "Cannot allocate JSON object (%s:%d)\n", __func__, __LINE__); dbi_result_free(result); og_dbi_close(dbi); return -1; } id = dbi_conn_sequence_last(dbi->conn, NULL); json_object_set_new(root, "id", json_integer(id)); ret = json_dump_callback(root, og_json_dump_clients, &og_buffer, 0); json_decref(root); dbi_result_free(result); og_dbi_close(dbi); return ret; } static int og_cmd_delete_server(json_t *element, struct og_msg_params *params) { const char *key, *msglog; struct og_dbi *dbi; dbi_result result; json_t *value; int err = 0; json_object_foreach(element, key, value) { if (!strcmp(key, "id")) { err = og_json_parse_string(value, ¶ms->id); params->flags |= OG_REST_PARAM_ID; } if (err < 0) return err; } if (!og_msg_params_validate(params, OG_REST_PARAM_ID)) return -1; dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open conection database (%s:%d)\n", __func__, __LINE__); return -1; } result = dbi_conn_queryf(dbi->conn, "DELETE FROM entornos WHERE identorno='%s'", params->id); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to delete server (%s:%d) %s\n", __func__, __LINE__, msglog); og_dbi_close(dbi); return -1; } if (dbi_result_get_numrows_affected(result) < 1) { dbi_result_free(result); og_dbi_close(dbi); return -1; } dbi_result_free(result); og_dbi_close(dbi); return 0; } static int og_dbi_update_oglive(struct og_dbi *dbi, const char *mac, const char * oglive) { const char *msglog; dbi_result result; result = dbi_conn_queryf(dbi->conn, "UPDATE ordenadores SET oglivedir='%s' " "WHERE mac='%s'", oglive, mac); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "failed to query database (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } dbi_result_free(result); return 0; } static int og_cmd_oglive_set(json_t *element, struct og_msg_params *params) { char ips_str[(OG_DB_IP_MAXLEN + 1) * OG_CLIENTS_MAX + 1] = {}; const char legacy_default_oglive_str[] = "ogLive"; const char *oglive_str, *mac, *mode_str; int ips_str_len = 0; struct og_dbi *dbi; uint64_t flags = 0; dbi_result result; const char *key; json_t *value; int err = 0; int i; json_object_foreach(element, key, value) { if (!strcmp(key, "clients")) { err = og_json_parse_clients(value, params); } else if (!strcmp(key, "name")) { err = og_json_parse_string(value, &oglive_str); flags |= OG_REST_PARAM_NAME; } else { err = -1; } if (err < 0) return err; } if (!og_flags_validate(flags, OG_REST_PARAM_NAME) || !og_msg_params_validate(params, OG_REST_PARAM_ADDR)) return -1; if (!strcmp(oglive_str, "default")) oglive_str = legacy_default_oglive_str; for (i = 0; i < params->ips_array_len; ++i) { ips_str_len += snprintf(ips_str + ips_str_len, sizeof(ips_str) - ips_str_len, "'%s',", params->ips_array[i]); } ips_str[ips_str_len - 1] = '\0'; dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", __func__, __LINE__); return -1; } result = dbi_conn_queryf(dbi->conn, "SELECT mac, arranque FROM ordenadores " "WHERE ip IN (%s)", ips_str); while (dbi_result_next_row(result)) { mac = dbi_result_get_string(result, "mac"); mode_str = dbi_result_get_string(result, "arranque"); err = og_dbi_update_oglive(dbi, mac, oglive_str); if (err != 0) { syslog(LOG_ERR, "failed to change db oglive (%s:%d)\n", __func__, __LINE__); dbi_result_free(result); og_dbi_close(dbi); return -1; } err = og_set_client_mode(dbi, mac, mode_str); if (err != 0) { dbi_result_free(result); og_dbi_close(dbi); return -1; } } dbi_result_free(result); og_dbi_close(dbi); return 0; } static int og_cmd_get_server_stats(char *buffer_reply) { json_t *root, *time_obj, *memory, *swap; struct og_buffer og_buffer = { .data = buffer_reply }; struct sysinfo stats; time_t now; sysinfo(&stats); root = json_object(); if (!root) return -1; time_obj = json_object(); if (!time_obj) { json_decref(root); return -1; } memory = json_object(); if (!memory) { json_decref(root); json_decref(time_obj); return -1; } swap = json_object(); if (!swap) { json_decref(root); json_decref(time_obj); json_decref(memory); return -1; } now = time(NULL); json_object_set_new(time_obj, "now", json_integer(now)); json_object_set_new(time_obj, "boot", json_integer(stats.uptime)); json_object_set_new(time_obj, "start", json_integer(now - start_time)); json_object_set_new(root, "time", time_obj); json_object_set_new(memory, "size", json_integer(stats.totalram)); json_object_set_new(memory, "free", json_integer(stats.freeram)); json_object_set_new(root, "memory", memory); json_object_set_new(swap, "size", json_integer(stats.totalswap)); json_object_set_new(swap, "free", json_integer(stats.freeswap)); json_object_set_new(root, "swap", swap); if (json_dump_callback(root, og_json_dump_clients, &og_buffer, 0)) { json_decref(root); return -1; } json_decref(root); return 0; } static int og_client_method_not_found(struct og_client *cli) { /* To meet RFC 7231, this function MUST generate an Allow header field * containing the correct methods. For example: "Allow: POST\r\n" */ char buf[] = "HTTP/1.1 405 Method Not Allowed\r\n" "Content-Length: 0\r\n\r\n"; send(og_client_socket(cli), buf, strlen(buf), 0); return -1; } static int og_client_bad_request(struct og_client *cli) { char buf[] = "HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\n\r\n"; send(og_client_socket(cli), buf, strlen(buf), 0); return -1; } static int og_client_not_found(struct og_client *cli) { char buf[] = "HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n"; send(og_client_socket(cli), buf, strlen(buf), 0); return -1; } static int og_client_not_authorized(struct og_client *cli) { char buf[] = "HTTP/1.1 401 Unauthorized\r\n" "WWW-Authenticate: Basic\r\n" "Content-Length: 0\r\n\r\n"; send(og_client_socket(cli), buf, strlen(buf), 0); return -1; } static int og_server_internal_error(struct og_client *cli) { char buf[] = "HTTP/1.1 500 Internal Server Error\r\n" "Content-Length: 0\r\n\r\n"; send(og_client_socket(cli), buf, strlen(buf), 0); return -1; } static int og_client_ok(struct og_client *cli, char *buf_reply) { char buf[OG_MSG_RESPONSE_MAXLEN] = {}; int len; len = snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\r\nContent-Length: %ld\r\n\r\n%s", strlen(buf_reply), buf_reply); if (len >= (int)sizeof(buf)) { syslog(LOG_ERR, "HTTP response to %s:%hu is too large\n", inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port)); return og_server_internal_error(cli); } send(og_client_socket(cli), buf, strlen(buf), 0); return 0; } static const char *og_method_str[] = { [OG_METHOD_GET] = "GET", [OG_METHOD_POST] = "POST", [OG_METHOD_DELETE] = "DELETE", [OG_METHOD_NO_HTTP] = "NOHTTP", }; static const char *og_method(enum og_rest_method method) { if (method > OG_METHOD_NO_HTTP) return "UNKNOWN"; return og_method_str[method]; } struct { const char *uri; } og_uri_handler[] = { [OG_URI_UNKNOWN] = { "unknown", }, [OG_URI_CLIENTS] = { "clients", }, [OG_URI_CLIENT_REPO] = { "client/repo", }, [OG_URI_CLIENT_SETUP] = { "client/setup", }, [OG_URI_CLIENT_SERVER] = { "client/server", }, [OG_URI_CLIENT_INFO] = { "client/info", }, [OG_URI_CLIENT_ADD] = { "client/add", }, [OG_URI_CLIENT_UPDATE] = { "client/update", }, [OG_URI_CLIENT_DELETE] = { "client/delete", }, [OG_URI_WOL] = { "wol", }, [OG_URI_SHELL_RUN] = { "shell/run", }, [OG_URI_SHELL_OUTPUT] = { "shell/output", }, [OG_URI_SESSION] = { "session", }, [OG_URI_SCOPES] = { "scopes", }, [OG_URI_POWEROFF] = { "poweroff", }, [OG_URI_REBOOT] = { "reboot", }, [OG_URI_BOOT_MODE] = { "mode", }, [OG_URI_STOP] = { "stop", }, [OG_URI_REFRESH] = { "refresh", }, [OG_URI_HARDWARE] = { "hardware", }, [OG_URI_SOFTWARE] = { "software", }, [OG_URI_REPO] = { "repositories", }, [OG_URI_REPO_ADD] = { "repository/add", }, [OG_URI_REPO_UPDATE] = { "repository/update", }, [OG_URI_REPO_DELETE] = { "repository/delete", }, [OG_URI_IMAGES] = { "images", }, [OG_URI_IMAGE_CREATE] = { "image/create" }, [OG_URI_IMAGE_RESTORE] = { "image/restore", }, [OG_URI_IMAGE_DELETE] = { "image/delete", }, [OG_URI_PART_SETUP] = { "setup", }, [OG_URI_RUN_SCHEDULE] = { "run/schedule", }, [OG_URI_TASK_RUN] = { "task/run", }, [OG_URI_SCHEDULE_CREATE] = { "schedule/create", }, [OG_URI_SCHEDULE_DELETE] = { "schedule/delete", }, [OG_URI_SCHEDULE_UPDATE] = { "schedule/update", }, [OG_URI_SCHEDULE_GET] = { "schedule/get", }, [OG_URI_OGLIVE_LIST] = { "oglive/list", }, [OG_URI_OGLIVE_SET] = { "oglive/set", }, [OG_URI_CENTER_ADD] = { "center/add", }, [OG_URI_CENTER_DELETE] = { "center/delete", }, [OG_URI_ROOM_ADD] = { "room/add", }, [OG_URI_ROOM_DELETE] = { "room/delete", }, [OG_URI_ROOM_INFO] = { "room/info", }, [OG_URI_PROC_ADD] = { "procedure/add", }, [OG_URI_PROC_UPDATE] = { "procedure/update", }, [OG_URI_PROC_RUN] = { "procedure/run", }, [OG_URI_SCHEDULE_RUN] = { "schedule/command", }, [OG_URI_PROC_DEL] = { "procedure/delete", }, [OG_URI_TASK_ADD] = { "task/add", }, [OG_URI_SERVER] = { "server", }, [OG_URI_STATS] = { "stats", }, }; static const char *og_uri(enum og_rest_uri uri) { if (uri >= OG_URI_MAX) return "unknown"; return og_uri_handler[uri].uri; } static enum og_rest_uri og_str_to_uri(const char *uri) { int i; for (i = 0; i < OG_URI_MAX; i++) { if (!strncmp(og_uri_handler[i].uri, uri, strlen(og_uri_handler[i].uri))) return i; } return OG_URI_UNKNOWN; } static void og_rest_log(const struct og_client *cli, enum og_rest_method method, enum og_rest_uri uri, const struct og_msg_params *params) { char log_buf[(16 * OG_CLIENTS_MAX) + 4096] = {}; int i, ret; switch (uri) { case OG_URI_SCOPES: case OG_URI_CLIENTS: /* very spammy, do not log these. */ return; default: break; } ret = snprintf(log_buf, sizeof(log_buf), "%s:%hu %s /%s ", inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port), og_method(method), og_uri(uri)); if (params->ips_array_len > 0) { ret += snprintf(&log_buf[ret], sizeof(log_buf) - ret, "clients="); if (ret > sizeof(log_buf)) return; for (i = 0; i < params->ips_array_len - 1; i++) { ret += snprintf(&log_buf[ret], sizeof(log_buf) - ret, "%s,", params->ips_array[i]); if (ret > sizeof(log_buf)) return; } ret += snprintf(&log_buf[ret], sizeof(log_buf) - ret, "%s", params->ips_array[i]); if (ret > sizeof(log_buf)) return; } syslog(LOG_INFO, "%s", log_buf); } int og_client_state_process_payload_rest(struct og_client *cli) { char buf_reply[OG_MSG_RESPONSE_MAXLEN] = {}; struct og_msg_params params = {}; enum og_rest_method method; const char *cmd, *body; json_error_t json_err; enum og_rest_uri uri; json_t *root = NULL; int err = 0; if (!strncmp(cli->buf, "GET", strlen("GET"))) { method = OG_METHOD_GET; cmd = cli->buf + strlen("GET") + 2; } else if (!strncmp(cli->buf, "POST", strlen("POST"))) { method = OG_METHOD_POST; cmd = cli->buf + strlen("POST") + 2; } else if (!strncmp(cli->buf, "DELETE", strlen("DELETE"))) { method = OG_METHOD_DELETE; cmd = cli->buf + strlen("DELETE") + 2; } else return og_client_method_not_found(cli); body = strstr(cli->buf, "\r\n\r\n") + 4; if (strcmp(cli->auth_token, ogconfig.rest.api_token)) { syslog(LOG_ERR, "wrong Authentication key\n"); return og_client_not_authorized(cli); } if (cli->content_length) { root = json_loads(body, 0, &json_err); if (!root) { syslog(LOG_ERR, "malformed json line %d: %s\n", json_err.line, json_err.text); return og_client_not_found(cli); } } uri = og_str_to_uri(cmd); if (!strncmp(cmd, "clients", strlen("clients"))) { if (method != OG_METHOD_POST && method != OG_METHOD_GET) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (method == OG_METHOD_POST && !root) { syslog(LOG_ERR, "command clients with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } switch (method) { case OG_METHOD_POST: err = og_cmd_post_clients(root, ¶ms); break; case OG_METHOD_GET: err = og_cmd_get_clients(root, ¶ms, buf_reply); break; default: err = og_client_method_not_found(cli); goto err_process_rest_payload; } } else if (!strncmp(cmd, "client/repo", strlen("client/repo"))) { switch (method) { case OG_METHOD_POST: if (!root) { syslog(LOG_ERR, "client post repo command with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_post_client_repo(root, ¶ms, buf_reply); break; default: err = og_client_method_not_found(cli); goto err_process_rest_payload; } } else if (!strncmp(cmd, "client/setup", strlen("client/setup"))) { if (method != OG_METHOD_GET) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (!root) { syslog(LOG_ERR, "command client partitions with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_get_client_setup(root, ¶ms, buf_reply); } else if (!strncmp(cmd, "client/server", strlen("client/server"))) { switch (method) { case OG_METHOD_POST: if (!root) { syslog(LOG_ERR, "client post server command with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_post_client_server(root, ¶ms, buf_reply); break; default: err = og_client_method_not_found(cli); goto err_process_rest_payload; } } else if (!strncmp(cmd, "client/info", strlen("client/info"))) { if (method != OG_METHOD_GET) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (!root) { syslog(LOG_ERR, "command client info with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_get_client_info(root, ¶ms, buf_reply); } else if (!strncmp(cmd, "client/add", strlen("client/add"))) { if (method != OG_METHOD_POST) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (!root) { syslog(LOG_ERR, "command client info with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_post_client_add(root, ¶ms, buf_reply); } else if (!strncmp(cmd, "client/update", strlen("client/update"))) { if (method != OG_METHOD_POST) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (!root) { syslog(LOG_ERR, "command client info with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_post_client_update(root, ¶ms, buf_reply); } else if (!strncmp(cmd, "client/delete", strlen("client/delete"))) { if (method != OG_METHOD_POST) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (!root) { syslog(LOG_ERR, "command client delete with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_post_client_delete(root, ¶ms); } else if (!strncmp(cmd, "wol", strlen("wol"))) { if (method != OG_METHOD_POST) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (!root) { syslog(LOG_ERR, "command wol with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_wol(root, ¶ms); } else if (!strncmp(cmd, "shell/run", strlen("shell/run"))) { if (method != OG_METHOD_POST) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (!root) { syslog(LOG_ERR, "command run with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_run_post(root, ¶ms); } else if (!strncmp(cmd, "shell/output", strlen("shell/output"))) { if (method != OG_METHOD_POST) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (!root) { syslog(LOG_ERR, "command output with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_run_get(root, ¶ms, buf_reply); } else if (!strncmp(cmd, "session", strlen("session"))) { if (method != OG_METHOD_POST && method != OG_METHOD_GET) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (!root) { syslog(LOG_ERR, "command session with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } if (method == OG_METHOD_POST) err = og_cmd_session(root, ¶ms); else err = og_cmd_get_session(root, ¶ms, buf_reply); } else if (!strncmp(cmd, "scopes", strlen("scopes"))) { if (method != OG_METHOD_GET) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (root) { syslog(LOG_ERR, "command scopes with payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_scope_get(root, ¶ms, buf_reply); } else if (!strncmp(cmd, "poweroff", strlen("poweroff"))) { if (method != OG_METHOD_POST) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (!root) { syslog(LOG_ERR, "command poweroff with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_poweroff(root, ¶ms); } else if (!strncmp(cmd, "reboot", strlen("reboot"))) { if (method != OG_METHOD_POST) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (!root) { syslog(LOG_ERR, "command reboot with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_reboot(root, ¶ms); } else if (!strncmp(cmd, "mode", strlen("mode"))) { if (method != OG_METHOD_GET && method != OG_METHOD_POST) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (method == OG_METHOD_POST && !root) { syslog(LOG_ERR, "command mode with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } if (method == OG_METHOD_GET) err = og_cmd_get_modes(root, ¶ms, buf_reply); else if (method == OG_METHOD_POST) err = og_cmd_post_modes(root, ¶ms); } else if (!strncmp(cmd, "stop", strlen("stop"))) { if (method != OG_METHOD_POST) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (!root) { syslog(LOG_ERR, "command stop with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_stop(root, ¶ms); } else if (!strncmp(cmd, "refresh", strlen("refresh"))) { if (method != OG_METHOD_POST) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (!root) { syslog(LOG_ERR, "command refresh with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_refresh(root, ¶ms); } else if (!strncmp(cmd, "hardware", strlen("hardware"))) { if (method != OG_METHOD_GET && method != OG_METHOD_POST) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (!root) { syslog(LOG_ERR, "command hardware with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } if (method == OG_METHOD_GET) err = og_cmd_get_hardware(root, ¶ms, buf_reply); else if (method == OG_METHOD_POST) err = og_cmd_hardware(root, ¶ms); } else if (!strncmp(cmd, "software", strlen("software"))) { if (method != OG_METHOD_POST && method != OG_METHOD_GET) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (!root) { syslog(LOG_ERR, "command software with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } if (method == OG_METHOD_POST) err = og_cmd_software(root, ¶ms); else err = og_cmd_get_software(root, ¶ms, buf_reply); } else if (!strncmp(cmd, "repositories", strlen("repositories"))) { if (method != OG_METHOD_GET) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (root) { err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_get_repositories(buf_reply); } else if (!strncmp(cmd, "repository/add", strlen("repository/add"))) { if (method != OG_METHOD_POST) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (!root) { syslog(LOG_ERR, "command repository add with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_post_repository_add(root, ¶ms, buf_reply); } else if (!strncmp(cmd, "repository/update", strlen("repository/update"))) { if (method != OG_METHOD_POST) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (!root) { syslog(LOG_ERR, "command repository add with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_post_repository_update(root, ¶ms, buf_reply); } else if (!strncmp(cmd, "repository/delete", strlen("repository/delete"))) { if (method != OG_METHOD_POST) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (!root) { syslog(LOG_ERR, "command repository delete with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_post_repository_delete(root, ¶ms); } else if (!strncmp(cmd, "images", strlen("images"))) { if (method != OG_METHOD_GET) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (root) { err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_images(buf_reply); } else if (!strncmp(cmd, "image/create", strlen("image/create"))) { if (method != OG_METHOD_POST) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (!root) { syslog(LOG_ERR, "command create with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_create_image(root, ¶ms); } else if (!strncmp(cmd, "image/restore", strlen("image/restore"))) { if (method != OG_METHOD_POST) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (!root) { syslog(LOG_ERR, "command create with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_restore_image(root, ¶ms); } else if (!strncmp(cmd, "image/delete", strlen("image/delete"))) { if (method != OG_METHOD_POST) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (!root) { syslog(LOG_ERR, "command image delete with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_delete_image(root, ¶ms); } else if (!strncmp(cmd, "setup", strlen("setup"))) { if (method != OG_METHOD_POST) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (!root) { syslog(LOG_ERR, "command create with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_setup(root, ¶ms); } else if (!strncmp(cmd, "run/schedule", strlen("run/schedule"))) { if (method != OG_METHOD_POST) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (!root) { syslog(LOG_ERR, "command create with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_run_schedule(root, ¶ms); } else if (!strncmp(cmd, "task/run", strlen("task/run"))) { if (method != OG_METHOD_POST) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (!root) { syslog(LOG_ERR, "command task with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_task_post(root, ¶ms); } else if (!strncmp(cmd, "schedule/create", strlen("schedule/create"))) { if (method != OG_METHOD_POST) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (!root) { syslog(LOG_ERR, "command task with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_schedule_create(root, ¶ms); } else if (!strncmp(cmd, "schedule/delete", strlen("schedule/delete"))) { if (method != OG_METHOD_POST) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (!root) { syslog(LOG_ERR, "command task with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_schedule_delete(root, ¶ms); } else if (!strncmp(cmd, "schedule/update", strlen("schedule/update"))) { if (method != OG_METHOD_POST) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (!root) { syslog(LOG_ERR, "command task with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_schedule_update(root, ¶ms); } else if (!strncmp(cmd, "schedule/get", strlen("schedule/get"))) { if (method != OG_METHOD_POST) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } err = og_cmd_schedule_get(root, ¶ms, buf_reply); } else if (!strncmp(cmd, "oglive/list", strlen("oglive/list"))) { if (method != OG_METHOD_GET) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } err = og_cmd_oglive_list(buf_reply); } else if (!strncmp(cmd, "oglive/set", strlen("oglive/set"))) { if (method != OG_METHOD_POST) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (!root) { syslog(LOG_ERR, "command oglive set with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_oglive_set(root, ¶ms); } else if (!strncmp(cmd, "center/add", strlen("center/add"))) { if (method != OG_METHOD_POST) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } err = og_cmd_post_center_add(root, ¶ms, buf_reply); } else if (!strncmp(cmd, "center/delete", strlen("center/delete"))) { if (method != OG_METHOD_POST) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (!root) { syslog(LOG_ERR, "command center delete with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_post_center_delete(root, ¶ms); } else if (!strncmp(cmd, "room/add", strlen("room/add"))) { if (method != OG_METHOD_POST) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (!root) { syslog(LOG_ERR, "command task with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_post_room_add(root, ¶ms); } else if (!strncmp(cmd, "room/delete", strlen("room/delete"))) { if (method != OG_METHOD_POST) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (!root) { syslog(LOG_ERR, "command room delete with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_post_room_delete(root, ¶ms); } else if (!strncmp(cmd, "room/info", strlen("room/info"))) { if (method != OG_METHOD_GET) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (!root) { syslog(LOG_ERR, "command room info with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_get_room_info(root, ¶ms, buf_reply); } else if (!strncmp(cmd, "procedure/add", strlen("procedure/add"))) { if (method != OG_METHOD_POST) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (!root) { syslog(LOG_ERR, "command procedure add with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_post_procedure_add(root, ¶ms); } else if (!strncmp(cmd, "procedure/update", strlen("procedure/update"))) { if (method != OG_METHOD_POST) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (!root) { syslog(LOG_ERR, "command procedure update with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_post_procedure_update(root, ¶ms); } else if (!strncmp(cmd, "procedure/run", strlen("procedure/run"))) { if (method != OG_METHOD_POST) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (!root) { syslog(LOG_ERR, "command procedure run with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_post_procedure_run(root, ¶ms); } else if (!strncmp(cmd, "schedule/command", strlen("schedule/command"))) { if (method != OG_METHOD_POST) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (!root) { syslog(LOG_ERR, "command schedule action with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_post_schedule_command(root, ¶ms); } else if (!strncmp(cmd, "procedure/delete", strlen("schedule/command"))) { if (method != OG_METHOD_POST) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (!root) { syslog(LOG_ERR, "command procedure delete with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_post_procedure_delete(root, ¶ms); } else if (!strncmp(cmd, "task/add", strlen("task/add"))) { if (method != OG_METHOD_POST) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } if (!root) { syslog(LOG_ERR, "command task add with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_post_task_add(root, ¶ms); } else if (!strncmp(cmd, "server", strlen("server"))) { switch (method) { case OG_METHOD_GET: err = og_cmd_get_servers(buf_reply); break; case OG_METHOD_DELETE: err = og_cmd_delete_server(root, ¶ms); break; case OG_METHOD_POST: if (!root) { syslog(LOG_ERR, "address add command with no payload\n"); err = og_client_bad_request(cli); goto err_process_rest_payload; } err = og_cmd_post_server(root, ¶ms, buf_reply); break; default: err = og_client_method_not_found(cli); goto err_process_rest_payload; } } else if (!strncmp(cmd, "stats", strlen("stats"))) { if (method != OG_METHOD_GET) { err = og_client_method_not_found(cli); goto err_process_rest_payload; } err = og_cmd_get_server_stats(buf_reply); } else { syslog(LOG_ERR, "unknown command: %.32s ...\n", cmd); err = og_client_not_found(cli); } og_rest_log(cli, method, uri, ¶ms); json_decref(root); if (err < 0) return og_client_bad_request(cli); return og_client_ok(cli, buf_reply); err_process_rest_payload: syslog(LOG_ERR, "%s:%hu %.32s ...\n", inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port), cli->buf); json_decref(root); return err; }