diff options
author | OpenGnSys Support Team <soporte-og@soleta.eu> | 2020-06-18 18:15:25 +0200 |
---|---|---|
committer | OpenGnSys Support Team <soporte-og@soleta.eu> | 2020-06-18 18:46:48 +0200 |
commit | 04ca20e9f1999d2c780043152cf233bcb1836d18 (patch) | |
tree | cca304b6d34723ec3a2a13e6745a874443ce5704 /sources/client.c | |
parent | 0b9465f783124340d85ff414c2ffb1dc40745f10 (diff) |
#971 split into smaller file
Split ogAdmServer into several files:
* sources/rest.c that implements the server REST API.
* sources/client.c that implements the client REST API.
* sources/json.c that provides a few JSON helpers.
Diffstat (limited to 'sources/client.c')
-rw-r--r-- | sources/client.c | 689 |
1 files changed, 689 insertions, 0 deletions
diff --git a/sources/client.c b/sources/client.c new file mode 100644 index 0000000..ef665fd --- /dev/null +++ b/sources/client.c @@ -0,0 +1,689 @@ +/* + * Copyright (C) 2020 Soleta Networks <info@soleta.eu> + * + * 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, version 3. + */ + +#include "ogAdmServer.h" +#include "dbi.h" +#include "utils.h" +#include "list.h" +#include "rest.h" +#include "json.h" +#include "schedule.h" +#include <syslog.h> +#include <sys/ioctl.h> +#include <ifaddrs.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <jansson.h> +#include <time.h> + +#define OG_COMPUTER_NAME_MAXLEN 100 + +struct og_computer { + unsigned int id; + unsigned int center; + unsigned int room; + char name[OG_COMPUTER_NAME_MAXLEN + 1]; + unsigned int procedure_id; +}; + +static int og_dbi_get_computer_info(struct og_computer *computer, + struct in_addr addr) +{ + const char *msglog; + struct og_dbi *dbi; + dbi_result result; + + dbi = og_dbi_open(&dbi_config); + if (!dbi) { + syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", + __func__, __LINE__); + return -1; + } + result = dbi_conn_queryf(dbi->conn, + "SELECT ordenadores.idordenador," + " ordenadores.nombreordenador," + " ordenadores.idaula," + " ordenadores.idproautoexec," + " centros.idcentro FROM ordenadores " + "INNER JOIN aulas ON aulas.idaula=ordenadores.idaula " + "INNER JOIN centros ON centros.idcentro=aulas.idcentro " + "WHERE ordenadores.ip='%s'", inet_ntoa(addr)); + 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_next_row(result)) { + syslog(LOG_ERR, "client does not exist in database (%s:%d)\n", + __func__, __LINE__); + dbi_result_free(result); + og_dbi_close(dbi); + return -1; + } + + computer->id = dbi_result_get_uint(result, "idordenador"); + computer->center = dbi_result_get_uint(result, "idcentro"); + computer->room = dbi_result_get_uint(result, "idaula"); + computer->procedure_id = dbi_result_get_uint(result, "idproautoexec"); + strncpy(computer->name, + dbi_result_get_string(result, "nombreordenador"), + OG_COMPUTER_NAME_MAXLEN); + + dbi_result_free(result); + og_dbi_close(dbi); + + return 0; +} + +static int og_resp_probe(struct og_client *cli, json_t *data) +{ + const char *status = NULL; + const char *key; + json_t *value; + int err = 0; + + if (json_typeof(data) != JSON_OBJECT) + return -1; + + json_object_foreach(data, key, value) { + if (!strcmp(key, "status")) { + err = og_json_parse_string(value, &status); + if (err < 0) + return err; + } else { + return -1; + } + } + + if (!strcmp(status, "BSY")) + cli->status = OG_CLIENT_STATUS_BUSY; + else if (!strcmp(status, "OPG")) + cli->status = OG_CLIENT_STATUS_OGLIVE; + + return status ? 0 : -1; +} + +static int og_resp_shell_run(struct og_client *cli, json_t *data) +{ + const char *output = NULL; + char filename[4096]; + const char *key; + json_t *value; + int err = -1; + FILE *file; + + if (json_typeof(data) != JSON_OBJECT) + return -1; + + json_object_foreach(data, key, value) { + if (!strcmp(key, "out")) { + err = og_json_parse_string(value, &output); + if (err < 0) + return err; + } else { + return -1; + } + } + + if (!output) { + syslog(LOG_ERR, "%s:%d: malformed json response\n", + __FILE__, __LINE__); + return -1; + } + + sprintf(filename, "/tmp/_Seconsola_%s", inet_ntoa(cli->addr.sin_addr)); + file = fopen(filename, "wt"); + if (!file) { + syslog(LOG_ERR, "cannot open file %s: %s\n", + filename, strerror(errno)); + return -1; + } + + fprintf(file, "%s", output); + fclose(file); + + return 0; +} + +struct og_computer_legacy { + char center[OG_DB_INT_MAXLEN + 1]; + char id[OG_DB_INT_MAXLEN + 1]; + char hardware[8192]; +}; + +static int og_resp_hardware(json_t *data, struct og_client *cli) +{ + struct og_computer_legacy legacy = {}; + const char *hardware = NULL; + struct og_computer computer; + struct og_dbi *dbi; + const char *key; + json_t *value; + int err = 0; + bool res; + + if (json_typeof(data) != JSON_OBJECT) + return -1; + + json_object_foreach(data, key, value) { + if (!strcmp(key, "hardware")) { + err = og_json_parse_string(value, &hardware); + if (err < 0) + return -1; + } else { + return -1; + } + } + + if (!hardware) { + syslog(LOG_ERR, "malformed response json\n"); + return -1; + } + + err = og_dbi_get_computer_info(&computer, cli->addr.sin_addr); + if (err < 0) + return -1; + + snprintf(legacy.center, sizeof(legacy.center), "%d", computer.center); + snprintf(legacy.id, sizeof(legacy.id), "%d", computer.id); + snprintf(legacy.hardware, sizeof(legacy.hardware), "%s", hardware); + + dbi = og_dbi_open(&dbi_config); + if (!dbi) { + syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", + __func__, __LINE__); + return -1; + } + + res = actualizaHardware(dbi, legacy.hardware, legacy.id, computer.name, + legacy.center); + og_dbi_close(dbi); + + if (!res) { + syslog(LOG_ERR, "Problem updating client configuration\n"); + return -1; + } + + return 0; +} + +struct og_software_legacy { + char software[8192]; + char center[OG_DB_INT_MAXLEN + 1]; + char part[OG_DB_SMALLINT_MAXLEN + 1]; + char id[OG_DB_INT_MAXLEN + 1]; +}; + +static int og_resp_software(json_t *data, struct og_client *cli) +{ + struct og_software_legacy legacy = {}; + const char *partition = NULL; + const char *software = NULL; + struct og_computer computer; + struct og_dbi *dbi; + const char *key; + json_t *value; + int err = 0; + bool res; + + if (json_typeof(data) != JSON_OBJECT) + return -1; + + json_object_foreach(data, key, value) { + if (!strcmp(key, "software")) + err = og_json_parse_string(value, &software); + else if (!strcmp(key, "partition")) + err = og_json_parse_string(value, &partition); + else + return -1; + + if (err < 0) + return -1; + } + + if (!software || !partition) { + syslog(LOG_ERR, "malformed response json\n"); + return -1; + } + + err = og_dbi_get_computer_info(&computer, cli->addr.sin_addr); + if (err < 0) + return -1; + + snprintf(legacy.software, sizeof(legacy.software), "%s", software); + snprintf(legacy.part, sizeof(legacy.part), "%s", partition); + snprintf(legacy.id, sizeof(legacy.id), "%d", computer.id); + snprintf(legacy.center, sizeof(legacy.center), "%d", computer.center); + + dbi = og_dbi_open(&dbi_config); + if (!dbi) { + syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", + __func__, __LINE__); + return -1; + } + + res = actualizaSoftware(dbi, legacy.software, legacy.part, legacy.id, + computer.name, legacy.center); + og_dbi_close(dbi); + + if (!res) { + syslog(LOG_ERR, "Problem updating client configuration\n"); + return -1; + } + + return 0; +} + +#define OG_PARAMS_RESP_REFRESH (OG_PARAM_PART_DISK | \ + OG_PARAM_PART_NUMBER | \ + OG_PARAM_PART_CODE | \ + OG_PARAM_PART_FILESYSTEM | \ + OG_PARAM_PART_OS | \ + OG_PARAM_PART_SIZE | \ + OG_PARAM_PART_USED_SIZE) + +static int og_json_parse_partition_array(json_t *value, + struct og_partition *partitions) +{ + json_t *element; + int i, err; + + if (json_typeof(value) != JSON_ARRAY) + return -1; + + for (i = 0; i < json_array_size(value) && i < OG_PARTITION_MAX; i++) { + element = json_array_get(value, i); + + err = og_json_parse_partition(element, &partitions[i], + OG_PARAMS_RESP_REFRESH); + if (err < 0) + return err; + } + + return 0; +} + +static int og_dbi_queue_autorun(uint32_t computer_id, uint32_t proc_id) +{ + struct og_task dummy_task = { + .scope = computer_id, + .type_scope = AMBITO_ORDENADORES, + .procedure_id = proc_id, + }; + struct og_dbi *dbi; + + dbi = og_dbi_open(&dbi_config); + if (!dbi) { + syslog(LOG_ERR, "cannot open connection database " + "(%s:%d)\n", __func__, __LINE__); + return -1; + } + if (og_dbi_queue_procedure(dbi, &dummy_task)) { + og_dbi_close(dbi); + return -1; + } + og_dbi_close(dbi); + + return 0; +} + +static int og_resp_refresh(json_t *data, struct og_client *cli) +{ + struct og_partition partitions[OG_PARTITION_MAX] = {}; + const char *serial_number = NULL; + struct og_computer computer = {}; + struct og_partition disk_setup; + char cfg[1024] = {}; + struct og_dbi *dbi; + const char *key; + unsigned int i; + json_t *value; + int err = 0; + bool res; + + if (json_typeof(data) != JSON_OBJECT) + return -1; + + json_object_foreach(data, key, value) { + if (!strcmp(key, "disk_setup")) { + err = og_json_parse_partition(value, + &disk_setup, + OG_PARAMS_RESP_REFRESH); + } else if (!strcmp(key, "partition_setup")) { + err = og_json_parse_partition_array(value, partitions); + } else if (!strcmp(key, "serial_number")) { + err = og_json_parse_string(value, &serial_number); + } else { + return -1; + } + + if (err < 0) + return err; + } + + err = og_dbi_get_computer_info(&computer, cli->addr.sin_addr); + if (err < 0) + return -1; + + if (strlen(serial_number) > 0) + snprintf(cfg, sizeof(cfg), "ser=%s\n", serial_number); + + if (!disk_setup.disk || !disk_setup.number || !disk_setup.code || + !disk_setup.filesystem || !disk_setup.os || !disk_setup.size || + !disk_setup.used_size) + return -1; + + snprintf(cfg + strlen(cfg), sizeof(cfg) - strlen(cfg), + "disk=%s\tpar=%s\tcpt=%s\tfsi=%s\tsoi=%s\ttam=%s\tuso=%s\n", + disk_setup.disk, disk_setup.number, disk_setup.code, + disk_setup.filesystem, disk_setup.os, disk_setup.size, + disk_setup.used_size); + + for (i = 0; i < OG_PARTITION_MAX; i++) { + if (!partitions[i].disk || !partitions[i].number || + !partitions[i].code || !partitions[i].filesystem || + !partitions[i].os || !partitions[i].size || + !partitions[i].used_size) + continue; + + snprintf(cfg + strlen(cfg), sizeof(cfg) - strlen(cfg), + "disk=%s\tpar=%s\tcpt=%s\tfsi=%s\tsoi=%s\ttam=%s\tuso=%s\n", + partitions[i].disk, partitions[i].number, + partitions[i].code, partitions[i].filesystem, + partitions[i].os, partitions[i].size, + partitions[i].used_size); + } + + dbi = og_dbi_open(&dbi_config); + if (!dbi) { + syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", + __func__, __LINE__); + return -1; + } + res = actualizaConfiguracion(dbi, cfg, computer.id); + og_dbi_close(dbi); + + if (!res) { + syslog(LOG_ERR, "Problem updating client configuration\n"); + return -1; + } + + if (!cli->autorun && computer.procedure_id) { + cli->autorun = true; + + if (og_dbi_queue_autorun(computer.id, computer.procedure_id)) + return -1; + } + + return 0; +} + +static int og_resp_image_create(json_t *data, struct og_client *cli) +{ + struct og_software_legacy soft_legacy; + struct og_image_legacy img_legacy; + const char *partition = NULL; + const char *software = NULL; + const char *image_id = NULL; + struct og_computer computer; + const char *disk = NULL; + const char *code = NULL; + const char *name = NULL; + const char *repo = NULL; + struct og_dbi *dbi; + const char *key; + json_t *value; + int err = 0; + bool res; + + if (json_typeof(data) != JSON_OBJECT) + return -1; + + json_object_foreach(data, key, value) { + if (!strcmp(key, "software")) + err = og_json_parse_string(value, &software); + else if (!strcmp(key, "partition")) + err = og_json_parse_string(value, &partition); + else if (!strcmp(key, "disk")) + err = og_json_parse_string(value, &disk); + else if (!strcmp(key, "code")) + err = og_json_parse_string(value, &code); + else if (!strcmp(key, "id")) + err = og_json_parse_string(value, &image_id); + else if (!strcmp(key, "name")) + err = og_json_parse_string(value, &name); + else if (!strcmp(key, "repository")) + err = og_json_parse_string(value, &repo); + else + return -1; + + if (err < 0) + return err; + } + + if (!software || !partition || !disk || !code || !image_id || !name || + !repo) { + syslog(LOG_ERR, "malformed response json\n"); + return -1; + } + + err = og_dbi_get_computer_info(&computer, cli->addr.sin_addr); + if (err < 0) + return -1; + + snprintf(soft_legacy.center, sizeof(soft_legacy.center), "%d", + computer.center); + snprintf(soft_legacy.software, sizeof(soft_legacy.software), "%s", + software); + snprintf(img_legacy.image_id, sizeof(img_legacy.image_id), "%s", + image_id); + snprintf(soft_legacy.id, sizeof(soft_legacy.id), "%d", computer.id); + snprintf(img_legacy.part, sizeof(img_legacy.part), "%s", partition); + snprintf(img_legacy.disk, sizeof(img_legacy.disk), "%s", disk); + snprintf(img_legacy.code, sizeof(img_legacy.code), "%s", code); + snprintf(img_legacy.name, sizeof(img_legacy.name), "%s", name); + snprintf(img_legacy.repo, sizeof(img_legacy.repo), "%s", repo); + + dbi = og_dbi_open(&dbi_config); + if (!dbi) { + syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", + __func__, __LINE__); + return -1; + } + + res = actualizaSoftware(dbi, + soft_legacy.software, + img_legacy.part, + soft_legacy.id, + computer.name, + soft_legacy.center); + if (!res) { + og_dbi_close(dbi); + syslog(LOG_ERR, "Problem updating client configuration\n"); + return -1; + } + + res = actualizaCreacionImagen(dbi, + img_legacy.image_id, + img_legacy.disk, + img_legacy.part, + img_legacy.code, + img_legacy.repo, + soft_legacy.id); + og_dbi_close(dbi); + + if (!res) { + syslog(LOG_ERR, "Problem updating client configuration\n"); + return -1; + } + + return 0; +} + +static int og_resp_image_restore(json_t *data, struct og_client *cli) +{ + struct og_software_legacy soft_legacy; + struct og_image_legacy img_legacy; + const char *partition = NULL; + const char *image_id = NULL; + struct og_computer computer; + const char *disk = NULL; + dbi_result query_result; + struct og_dbi *dbi; + const char *key; + json_t *value; + int err = 0; + bool res; + + if (json_typeof(data) != JSON_OBJECT) + return -1; + + json_object_foreach(data, key, value) { + if (!strcmp(key, "partition")) + err = og_json_parse_string(value, &partition); + else if (!strcmp(key, "disk")) + err = og_json_parse_string(value, &disk); + else if (!strcmp(key, "image_id")) + err = og_json_parse_string(value, &image_id); + else + return -1; + + if (err < 0) + return err; + } + + if (!partition || !disk || !image_id) { + syslog(LOG_ERR, "malformed response json\n"); + return -1; + } + + err = og_dbi_get_computer_info(&computer, cli->addr.sin_addr); + if (err < 0) + return -1; + + snprintf(img_legacy.image_id, sizeof(img_legacy.image_id), "%s", + image_id); + snprintf(img_legacy.part, sizeof(img_legacy.part), "%s", partition); + snprintf(img_legacy.disk, sizeof(img_legacy.disk), "%s", disk); + snprintf(soft_legacy.id, sizeof(soft_legacy.id), "%d", computer.id); + + dbi = og_dbi_open(&dbi_config); + if (!dbi) { + syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", + __func__, __LINE__); + return -1; + } + + query_result = dbi_conn_queryf(dbi->conn, + "SELECT idperfilsoft FROM imagenes " + " WHERE idimagen='%s'", + image_id); + if (!query_result) { + og_dbi_close(dbi); + syslog(LOG_ERR, "failed to query database\n"); + return -1; + } + if (!dbi_result_next_row(query_result)) { + dbi_result_free(query_result); + og_dbi_close(dbi); + syslog(LOG_ERR, "software profile does not exist in database\n"); + return -1; + } + snprintf(img_legacy.software_id, sizeof(img_legacy.software_id), + "%d", dbi_result_get_uint(query_result, "idperfilsoft")); + dbi_result_free(query_result); + + res = actualizaRestauracionImagen(dbi, + img_legacy.image_id, + img_legacy.disk, + img_legacy.part, + soft_legacy.id, + img_legacy.software_id); + og_dbi_close(dbi); + + if (!res) { + syslog(LOG_ERR, "Problem updating client configuration\n"); + return -1; + } + + return 0; +} + +int og_agent_state_process_response(struct og_client *cli) +{ + json_error_t json_err; + json_t *root; + int err = -1; + char *body; + + if (!strncmp(cli->buf, "HTTP/1.0 202 Accepted", + strlen("HTTP/1.0 202 Accepted"))) { + og_dbi_update_action(cli->last_cmd_id, true); + cli->last_cmd_id = 0; + return 1; + } + + if (strncmp(cli->buf, "HTTP/1.0 200 OK", strlen("HTTP/1.0 200 OK"))) { + og_dbi_update_action(cli->last_cmd_id, false); + cli->last_cmd_id = 0; + return -1; + } + og_dbi_update_action(cli->last_cmd_id, true); + cli->last_cmd_id = 0; + + if (!cli->content_length) { + cli->last_cmd = OG_CMD_UNSPEC; + return 0; + } + + body = strstr(cli->buf, "\r\n\r\n") + 4; + + root = json_loads(body, 0, &json_err); + if (!root) { + syslog(LOG_ERR, "%s:%d: malformed json line %d: %s\n", + __FILE__, __LINE__, json_err.line, json_err.text); + return -1; + } + + switch (cli->last_cmd) { + case OG_CMD_PROBE: + err = og_resp_probe(cli, root); + break; + case OG_CMD_SHELL_RUN: + err = og_resp_shell_run(cli, root); + break; + case OG_CMD_HARDWARE: + err = og_resp_hardware(root, cli); + break; + case OG_CMD_SOFTWARE: + err = og_resp_software(root, cli); + break; + case OG_CMD_REFRESH: + err = og_resp_refresh(root, cli); + break; + case OG_CMD_SETUP: + err = og_resp_refresh(root, cli); + break; + case OG_CMD_IMAGE_CREATE: + err = og_resp_image_create(root, cli); + break; + case OG_CMD_IMAGE_RESTORE: + err = og_resp_image_restore(root, cli); + break; + default: + err = -1; + break; + } + + cli->last_cmd = OG_CMD_UNSPEC; + + return err; +} |