mirror of https://git.48k.eu/ogserver
1404 lines
38 KiB
C
1404 lines
38 KiB
C
/*
|
|
* Copyright (C) 2020-2021 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; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*/
|
|
|
|
#include "ogAdmServer.h"
|
|
#include "cfg.h"
|
|
#include "dbi.h"
|
|
#include "utils.h"
|
|
#include "list.h"
|
|
#include "rest.h"
|
|
#include "json.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_LEGACY_OGAGENT_LOG_FILE "/opt/opengnsys/log/ogagent.log"
|
|
#define OG_CLIENT_SESSION_EVENT_LOGIN "logged in"
|
|
#define OG_CLIENT_SESSION_EVENT_LOGOUT "logged out"
|
|
#define OG_CLIENT_SESSION_OS_LINUX "Linux"
|
|
#define OG_CLIENT_SESSION_OS_WINDOWS "Windows"
|
|
#define OG_CLIENT_SESSION_TIMEDATE_LEN 20
|
|
|
|
static struct {
|
|
const char *name;
|
|
uint32_t id;
|
|
} og_fs[] = {
|
|
{ "EMPTY", 1 },
|
|
{ "CACHE", 2 },
|
|
{ "BTRFS", 3 },
|
|
{ "EXT3", 5 },
|
|
{ "EXT4", 6 },
|
|
{ "FAT32", 9 },
|
|
{ "HFS", 10 },
|
|
{ "HFSPLUS", 11 },
|
|
{ "NTFS", 13 },
|
|
{ "EXFAT", 18 },
|
|
{ "LINUX-SWAP", 19 },
|
|
{ "SWAP", 22 },
|
|
{ NULL, 0 },
|
|
};
|
|
|
|
static uint32_t get_filesystem_id(const char *fs_name)
|
|
{
|
|
uint32_t i;
|
|
|
|
if (strlen(fs_name) == 0)
|
|
return 0;
|
|
|
|
for (i = 0; og_fs[i].name != NULL; i++) {
|
|
if (!strcmp(og_fs[i].name, fs_name))
|
|
return og_fs[i].id;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void og_status_session_log(const struct og_client *cli,
|
|
const char *type, const char* user,
|
|
const char *os)
|
|
{
|
|
char date[OG_CLIENT_SESSION_TIMEDATE_LEN];
|
|
char client_ip[INET_ADDRSTRLEN];
|
|
time_t now;
|
|
FILE *fp;
|
|
|
|
time(&now);
|
|
strftime(date, OG_CLIENT_SESSION_TIMEDATE_LEN, "%FT%T", gmtime(&now));
|
|
|
|
inet_ntop(AF_INET, &(cli->addr.sin_addr), client_ip, INET_ADDRSTRLEN);
|
|
|
|
fp = fopen(OG_LEGACY_OGAGENT_LOG_FILE, "a");
|
|
if (fp) {
|
|
fprintf(fp, "%s: User %s: ip=%s, user=%s, lang=en, os=%s:%s.\n",
|
|
date, type, client_ip, user, os, os);
|
|
fclose(fp);
|
|
}
|
|
}
|
|
|
|
static int og_status_session_start(struct og_client *cli, const char *user)
|
|
{
|
|
switch (cli->status) {
|
|
case OG_CLIENT_STATUS_LINUX:
|
|
cli->status = OG_CLIENT_STATUS_LINUX_SESSION;
|
|
og_status_session_log(cli, OG_CLIENT_SESSION_EVENT_LOGIN, user,
|
|
OG_CLIENT_SESSION_OS_LINUX);
|
|
break;
|
|
case OG_CLIENT_STATUS_WIN:
|
|
cli->status = OG_CLIENT_STATUS_WIN_SESSION;
|
|
og_status_session_log(cli, OG_CLIENT_SESSION_EVENT_LOGIN, user,
|
|
OG_CLIENT_SESSION_OS_WINDOWS);
|
|
break;
|
|
default:
|
|
syslog(LOG_ERR, "%s:%d: invalid session start for status %d\n",
|
|
__FILE__, __LINE__, cli->status);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int og_status_session_stop(struct og_client *cli, const char *user)
|
|
{
|
|
switch (cli->status) {
|
|
case OG_CLIENT_STATUS_WIN_SESSION:
|
|
cli->status = OG_CLIENT_STATUS_WIN;
|
|
og_status_session_log(cli, OG_CLIENT_SESSION_EVENT_LOGOUT, user,
|
|
OG_CLIENT_SESSION_OS_WINDOWS);
|
|
break;
|
|
case OG_CLIENT_STATUS_LINUX_SESSION:
|
|
cli->status = OG_CLIENT_STATUS_LINUX;
|
|
og_status_session_log(cli, OG_CLIENT_SESSION_EVENT_LOGOUT, user,
|
|
OG_CLIENT_SESSION_OS_LINUX);
|
|
break;
|
|
default:
|
|
syslog(LOG_ERR, "%s:%d: invalid session stop for status %d\n",
|
|
__FILE__, __LINE__, cli->status);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int og_resp_early_hints(struct og_client *cli, json_t *data)
|
|
{
|
|
const char *event, *action, *user;
|
|
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, "event")) {
|
|
err = og_json_parse_string(value, &event);
|
|
if (err < 0)
|
|
return err;
|
|
} else if (!strcmp(key, "action")) {
|
|
err = og_json_parse_string(value, &action);
|
|
if (err < 0)
|
|
return err;
|
|
} else if (!strcmp(key, "user")) {
|
|
err = og_json_parse_string(value, &user);
|
|
if (err < 0)
|
|
return err;
|
|
}
|
|
}
|
|
|
|
syslog(LOG_INFO, "Received event %s %s %s\n", event, action, user);
|
|
|
|
if (strncmp(event, "session", strlen("session")))
|
|
return -1;
|
|
|
|
if (!strncmp(action, "start", strlen("start")))
|
|
return og_status_session_start(cli, user);
|
|
if (!strncmp(action, "stop", strlen("stop")))
|
|
return og_status_session_stop(cli, user);
|
|
|
|
syslog(LOG_ERR, "Invalid action for event %s %s %s\n", event, action, user);
|
|
return -1;
|
|
}
|
|
|
|
static int og_resp_shell_run(struct og_client *cli, json_t *data)
|
|
{
|
|
const char *cmd = NULL, *output = NULL;
|
|
uint32_t retcode = 0;
|
|
const char *key;
|
|
json_t *value;
|
|
int err = -1;
|
|
|
|
if (json_typeof(data) != JSON_OBJECT)
|
|
return -1;
|
|
|
|
json_object_foreach(data, key, value) {
|
|
if (!strcmp(key, "cmd")) {
|
|
err = og_json_parse_string(value, &cmd);
|
|
if (err < 0)
|
|
return err;
|
|
} else if (!strcmp(key, "out")) {
|
|
err = og_json_parse_string(value, &output);
|
|
if (err < 0)
|
|
return err;
|
|
} else if (!strcmp(key, "retcode")) {
|
|
err = og_json_parse_uint(value, &retcode);
|
|
if (err < 0)
|
|
return err;
|
|
}
|
|
|
|
}
|
|
|
|
if (!cmd || !output) {
|
|
syslog(LOG_ERR, "%s:%d: malformed json response\n",
|
|
__FILE__, __LINE__);
|
|
return -1;
|
|
}
|
|
|
|
free((void *)cli->shell.cmd);
|
|
free((void *)cli->shell.output);
|
|
cli->shell.tstamp = time(NULL);
|
|
cli->shell.cmd = strdup(cmd);
|
|
cli->shell.output = strdup(output);
|
|
cli->shell.retcode = retcode;
|
|
|
|
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 = {};
|
|
struct og_computer computer = {};
|
|
const char *hardware = 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, "hardware")) {
|
|
err = og_json_parse_string(value, &hardware);
|
|
if (err < 0)
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if (!hardware) {
|
|
syslog(LOG_ERR, "malformed response json\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;
|
|
}
|
|
|
|
err = og_dbi_get_computer_info(dbi, &computer, cli->addr.sin_addr);
|
|
if (err < 0) {
|
|
og_dbi_close(dbi);
|
|
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);
|
|
|
|
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[32768];
|
|
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 = {};
|
|
struct og_computer computer = {};
|
|
const char *partition = NULL;
|
|
const char *software = 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);
|
|
|
|
if (err < 0)
|
|
return -1;
|
|
}
|
|
|
|
if (!software || !partition) {
|
|
syslog(LOG_ERR, "malformed response json\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;
|
|
}
|
|
|
|
err = og_dbi_get_computer_info(dbi, &computer, cli->addr.sin_addr);
|
|
if (err < 0) {
|
|
og_dbi_close(dbi);
|
|
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);
|
|
|
|
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 | \
|
|
OG_PARAM_PART_FREE_SIZE)
|
|
|
|
static int og_json_parse_partition_array(json_t *value,
|
|
struct og_partition *partitions,
|
|
uint32_t *num_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;
|
|
}
|
|
*num_partitions = i;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int og_update_cache_info(struct og_dbi *dbi, struct og_cache_data *cache_data, int clientid)
|
|
{
|
|
struct og_cache_image *cache_image;
|
|
const char *msglog;
|
|
dbi_result result;
|
|
|
|
/* Remove old cache image info */
|
|
result = dbi_conn_queryf(dbi->conn,
|
|
"DELETE FROM cache WHERE clientid=%d;", clientid);
|
|
|
|
if (!result) {
|
|
dbi_conn_error(dbi->conn, &msglog);
|
|
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
|
|
__func__, __LINE__, msglog);
|
|
return false;
|
|
}
|
|
dbi_result_free(result);
|
|
|
|
/* Add new cache image info */
|
|
list_for_each_entry(cache_image, &cache_data->image_list, list) {
|
|
result = dbi_conn_queryf(dbi->conn,
|
|
"INSERT INTO cache (clientid, imagename, size, checksum)"
|
|
"VALUES (%d, '%s', %lu, '%s')",
|
|
clientid,
|
|
cache_image->name,
|
|
cache_image->size,
|
|
cache_image->checksum);
|
|
|
|
if (!result) {
|
|
dbi_conn_error(dbi->conn, &msglog);
|
|
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
|
|
__func__, __LINE__, msglog);
|
|
return false;
|
|
}
|
|
dbi_result_free(result);
|
|
}
|
|
|
|
/* Update partition sizes */
|
|
result = dbi_conn_queryf(dbi->conn,
|
|
"UPDATE ordenadores_particiones SET used_size = %lu, free_size = %lu"
|
|
" WHERE idordenador = %d AND codpar = %d",
|
|
cache_data->used_size,
|
|
cache_data->free_size,
|
|
clientid,
|
|
202);
|
|
|
|
if (!result) {
|
|
dbi_conn_error(dbi->conn, &msglog);
|
|
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
|
|
__func__, __LINE__, msglog);
|
|
return false;
|
|
}
|
|
dbi_result_free(result);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int og_update_boot_entries(struct og_dbi *dbi, struct list_head *boot_entry_list, int client_id)
|
|
{
|
|
struct og_boot_entry *boot_entry;
|
|
const char *msglog;
|
|
dbi_result result;
|
|
|
|
/* Remove old boot entries */
|
|
result = dbi_conn_queryf(dbi->conn,
|
|
"DELETE FROM boot_entries WHERE client_id=%d;", client_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);
|
|
/* Add new boot entries */
|
|
list_for_each_entry(boot_entry, boot_entry_list, list) {
|
|
result = dbi_conn_queryf(dbi->conn,
|
|
"INSERT INTO boot_entries (client_id, name, active, description, entry_order)"
|
|
"VALUES (%d, '%s', %d, '%s', %d)",
|
|
client_id,
|
|
boot_entry->name,
|
|
boot_entry->active ? 1 : 0,
|
|
boot_entry->description,
|
|
boot_entry->order == UINT64_MAX ? -1 : boot_entry->order);
|
|
|
|
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_resp_update_cache(json_t *data, struct og_client *cli)
|
|
{
|
|
struct og_cache_data cache_data = {};
|
|
struct og_computer computer = {};
|
|
json_t *value, *cache = NULL;
|
|
struct og_dbi *dbi;
|
|
const char *key;
|
|
int err = 0;
|
|
|
|
og_cache_data_init(&cache_data);
|
|
|
|
if (json_typeof(data) != JSON_OBJECT) {
|
|
og_cache_data_free(&cache_data);
|
|
return -1;
|
|
}
|
|
|
|
json_object_foreach(data, key, value) {
|
|
if (!strcmp(key, "cache")) {
|
|
err = og_json_parse_cache(value, &cache_data);
|
|
cache = value;
|
|
}
|
|
|
|
if (err < 0) {
|
|
og_cache_data_free(&cache_data);
|
|
return err;
|
|
}
|
|
}
|
|
|
|
if (!cache) {
|
|
og_cache_data_free(&cache_data);
|
|
return 0;
|
|
}
|
|
|
|
dbi = og_dbi_open(&ogconfig.db);
|
|
if (!dbi) {
|
|
og_cache_data_free(&cache_data);
|
|
syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
|
|
__func__, __LINE__);
|
|
return -1;
|
|
}
|
|
|
|
err = og_dbi_get_computer_info(dbi, &computer, cli->addr.sin_addr);
|
|
if (err < 0) {
|
|
og_cache_data_free(&cache_data);
|
|
og_dbi_close(dbi);
|
|
return -1;
|
|
}
|
|
|
|
err = og_update_cache_info(dbi, &cache_data, computer.id);
|
|
if (err < 0) {
|
|
og_cache_data_free(&cache_data);
|
|
og_dbi_close(dbi);
|
|
return -1;
|
|
}
|
|
|
|
og_cache_data_free(&cache_data);
|
|
og_dbi_close(dbi);
|
|
return 0;
|
|
}
|
|
|
|
struct og_disk {
|
|
uint64_t size;
|
|
};
|
|
|
|
struct og_part {
|
|
uint32_t filesystem;
|
|
uint32_t os;
|
|
uint32_t code;
|
|
uint64_t size;
|
|
uint64_t used_size;
|
|
uint64_t free_size;
|
|
};
|
|
|
|
static bool og_update_client_disk_info(struct og_dbi *dbi,
|
|
const struct og_client *cli,
|
|
int computer_id,
|
|
const struct og_partition *disks,
|
|
uint32_t num_disks,
|
|
const struct og_partition *partitions,
|
|
uint32_t num_partitions,
|
|
const char *serial_number)
|
|
{
|
|
struct og_disk cur_disk = {}, reported_disk = {};
|
|
struct og_part cur_part = {}, reported_part = {};
|
|
dbi_result result, result_update;
|
|
int disk_part_len = 0;
|
|
char disk_part[1024];
|
|
const char *msglog;
|
|
int i;
|
|
|
|
if (serial_number && strlen(serial_number) > 0) {
|
|
result = dbi_conn_queryf(dbi->conn,
|
|
"UPDATE ordenadores SET numserie='%s'"
|
|
" WHERE idordenador=%d AND numserie IS NULL",
|
|
serial_number, computer_id);
|
|
if (!result) {
|
|
dbi_conn_error(dbi->conn, &msglog);
|
|
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
|
|
__func__, __LINE__, msglog);
|
|
return false;
|
|
}
|
|
dbi_result_free(result);
|
|
}
|
|
|
|
for (i = 0; i < num_disks; i++) {
|
|
disk_part_len += snprintf(&disk_part[disk_part_len],
|
|
sizeof(disk_part) - disk_part_len,
|
|
"(%s, 0),", disks[i].disk);
|
|
|
|
result = dbi_conn_queryf(dbi->conn,
|
|
"SELECT tamano "
|
|
" FROM ordenadores_particiones"
|
|
" WHERE idordenador=%d AND numdisk=%s AND numpar=0",
|
|
computer_id, disks[i].disk);
|
|
if (!result) {
|
|
dbi_conn_error(dbi->conn, &msglog);
|
|
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
|
|
__func__, __LINE__, msglog);
|
|
return false;
|
|
}
|
|
|
|
if (!dbi_result_next_row(result)) {
|
|
result_update = dbi_conn_queryf(dbi->conn,
|
|
"INSERT INTO ordenadores_particiones("
|
|
"idordenador, numdisk, numpar, codpar, tamano, uso, "
|
|
"idsistemafichero, idnombreso, disk_type, idimagen,"
|
|
"used_size, free_size)"
|
|
" VALUES(%d,%s,0,0x%s,%s,0,0,0,'%s',0,0,0)",
|
|
computer_id,
|
|
disks[i].disk,
|
|
disks[i].code,
|
|
disks[i].size,
|
|
disks[i].disk_type);
|
|
if (!result_update) {
|
|
dbi_conn_error(dbi->conn, &msglog);
|
|
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
|
|
__func__, __LINE__, msglog);
|
|
return false;
|
|
}
|
|
dbi_result_free(result_update);
|
|
dbi_result_free(result);
|
|
|
|
syslog(LOG_INFO, "adding disk %u with size %s to client %s\n",
|
|
i, disks[i].size, inet_ntoa(cli->addr.sin_addr));
|
|
|
|
continue;
|
|
}
|
|
|
|
reported_disk.size = strtoull(disks[i].size, NULL, 0);
|
|
cur_disk.size = dbi_result_get_longlong(result, "tamano");
|
|
|
|
dbi_result_free(result);
|
|
|
|
result_update = dbi_conn_queryf(dbi->conn,
|
|
"UPDATE ordenadores_particiones SET tamano=%s,"
|
|
" codpar=%s, disk_type='%s' "
|
|
" WHERE idordenador=%d AND numdisk=%s AND numpar=0",
|
|
disks[i].size, disks[i].code, disks[i].disk_type, computer_id, disks[i].disk);
|
|
if (!result_update) {
|
|
dbi_conn_error(dbi->conn, &msglog);
|
|
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
|
|
__func__, __LINE__, msglog);
|
|
return false;
|
|
}
|
|
dbi_result_free(result_update);
|
|
|
|
if (cur_disk.size != reported_disk.size)
|
|
syslog(LOG_INFO, "disk %s in client %s has changed size, before %lu after %lu bytes\n",
|
|
disks[i].disk, inet_ntoa(cli->addr.sin_addr), cur_disk.size, reported_disk.size);
|
|
|
|
continue;
|
|
}
|
|
|
|
for (i = 0; i < num_partitions; i++) {
|
|
disk_part_len += snprintf(&disk_part[disk_part_len],
|
|
sizeof(disk_part) - disk_part_len,
|
|
"(%s, %s),",
|
|
partitions[i].disk, partitions[i].number);
|
|
|
|
result = dbi_conn_queryf(dbi->conn,
|
|
"SELECT numdisk, numpar, tamano, idsistemafichero, idnombreso, "
|
|
" codpar, used_size, free_size"
|
|
" FROM ordenadores_particiones"
|
|
" WHERE idordenador=%d AND numdisk=%s AND numpar=%s",
|
|
computer_id, partitions[i].disk, partitions[i].number);
|
|
if (!result) {
|
|
dbi_conn_error(dbi->conn, &msglog);
|
|
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
|
|
__func__, __LINE__, msglog);
|
|
return false;
|
|
}
|
|
|
|
reported_part.size = strtoull(partitions[i].size, NULL, 0);
|
|
reported_part.code = strtoul(partitions[i].code, NULL, 16);
|
|
reported_part.filesystem = get_filesystem_id(partitions[i].filesystem);
|
|
reported_part.used_size = partitions[i].used_size;
|
|
reported_part.free_size = partitions[i].free_size;
|
|
|
|
if (og_dbi_get_os_id(dbi, partitions[i].os, &reported_part.os) < 0) {
|
|
return false;
|
|
}
|
|
|
|
if (!dbi_result_next_row(result)) {
|
|
result_update = dbi_conn_queryf(dbi->conn,
|
|
"INSERT INTO ordenadores_particiones("
|
|
"idordenador, numdisk, numpar, codpar, tamano, uso, "
|
|
"idsistemafichero, idnombreso, idimagen, "
|
|
"used_size, free_size)"
|
|
" VALUES(%d,%s,%s,0x%d,%s,0,%d,%d,0,%lu,%lu)",
|
|
computer_id,
|
|
partitions[i].disk,
|
|
partitions[i].number,
|
|
reported_part.code,
|
|
partitions[i].size,
|
|
reported_part.filesystem,
|
|
reported_part.os,
|
|
partitions[i].used_size,
|
|
partitions[i].free_size);
|
|
if (!result_update) {
|
|
dbi_conn_error(dbi->conn, &msglog);
|
|
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
|
|
__func__, __LINE__, msglog);
|
|
return false;
|
|
}
|
|
dbi_result_free(result_update);
|
|
dbi_result_free(result);
|
|
|
|
syslog(LOG_INFO, "new partition %s in disk %s client %s\n",
|
|
partitions[i].number, partitions[i].disk, inet_ntoa(cli->addr.sin_addr));
|
|
|
|
continue;
|
|
}
|
|
|
|
cur_part.size = dbi_result_get_longlong(result, "tamano");
|
|
cur_part.code = dbi_result_get_int(result, "codpar");
|
|
cur_part.filesystem = dbi_result_get_uint(result, "idsistemafichero");
|
|
cur_part.os = dbi_result_get_uint(result, "idnombreso");
|
|
cur_part.used_size = dbi_result_get_longlong(result, "used_size");
|
|
cur_part.free_size = dbi_result_get_longlong(result, "free_size");
|
|
dbi_result_free(result);
|
|
|
|
if (cur_part.size != reported_part.size ||
|
|
cur_part.code != reported_part.code ||
|
|
cur_part.filesystem != reported_part.filesystem ||
|
|
cur_part.os != reported_part.os) {
|
|
result_update = dbi_conn_queryf(dbi->conn,
|
|
"UPDATE ordenadores_particiones SET "
|
|
" codpar=0x%s,"
|
|
" tamano=%s,"
|
|
" idsistemafichero=%d,"
|
|
" idnombreso=%d,"
|
|
" idimagen=0,"
|
|
" idperfilsoft=0,"
|
|
" fechadespliegue=NULL"
|
|
" WHERE idordenador=%d AND numdisk=%s AND numpar=%s",
|
|
partitions[i].code, partitions[i].size,
|
|
reported_part.filesystem, reported_part.os, computer_id,
|
|
partitions[i].disk, partitions[i].number);
|
|
|
|
if (!result_update) {
|
|
dbi_conn_error(dbi->conn, &msglog);
|
|
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
|
|
__func__, __LINE__, msglog);
|
|
return false;
|
|
}
|
|
|
|
dbi_result_free(result_update);
|
|
|
|
syslog(LOG_INFO, "Disk %s partition %s in client %s has changed\n",
|
|
partitions[i].disk, partitions[i].number, inet_ntoa(cli->addr.sin_addr));
|
|
|
|
continue;
|
|
}
|
|
|
|
if (cur_part.used_size == reported_part.used_size)
|
|
continue;
|
|
|
|
result_update = dbi_conn_queryf(dbi->conn,
|
|
"UPDATE ordenadores_particiones SET "
|
|
" uso=0, used_size=%lu, free_size=%lu"
|
|
" WHERE idordenador=%d AND numdisk=%s AND numpar=%s",
|
|
partitions[i].used_size, partitions[i].free_size, computer_id,
|
|
partitions[i].disk, partitions[i].number);
|
|
if (!result_update) {
|
|
dbi_conn_error(dbi->conn, &msglog);
|
|
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
|
|
__func__, __LINE__, msglog);
|
|
return false;
|
|
}
|
|
dbi_result_free(result_update);
|
|
|
|
syslog(LOG_INFO, "partition usage in disk %s partition %s client %s has changed\n",
|
|
partitions[i].disk, partitions[i].number, inet_ntoa(cli->addr.sin_addr));
|
|
}
|
|
/* remove trailing comma */
|
|
disk_part[disk_part_len - 1] = '\0';
|
|
|
|
result_update = dbi_conn_queryf(dbi->conn,
|
|
"DELETE FROM ordenadores_particiones WHERE idordenador=%d AND (numdisk, numpar) NOT IN (%s)",
|
|
computer_id, disk_part);
|
|
if (!result_update) {
|
|
dbi_conn_error(dbi->conn, &msglog);
|
|
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
|
|
__func__, __LINE__, msglog);
|
|
return false;
|
|
}
|
|
dbi_result_free(result_update);
|
|
|
|
return true;
|
|
}
|
|
|
|
static int og_resp_refresh(json_t *data, struct og_client *cli)
|
|
{
|
|
struct og_partition partitions[OG_PARTITION_MAX] = {};
|
|
struct og_partition disks[OG_DISK_MAX] = {};
|
|
uint32_t num_disks = 0, num_partitions = 0;
|
|
struct og_cache_data cache_data = {};
|
|
const char *serial_number = NULL;
|
|
struct og_computer computer = {};
|
|
const char *status = NULL;
|
|
LIST_HEAD(boot_entry_list);
|
|
json_t *value = NULL;
|
|
struct og_dbi *dbi;
|
|
uint32_t link = 0;
|
|
const char *key;
|
|
int err = 0;
|
|
bool res;
|
|
|
|
og_cache_data_init(&cache_data);
|
|
|
|
if (json_typeof(data) != JSON_OBJECT)
|
|
goto err_out;
|
|
|
|
json_object_foreach(data, key, value) {
|
|
if (!strcmp(key, "disk_setup")) {
|
|
err = og_json_parse_partition_array(value, disks,
|
|
&num_disks);
|
|
} else if (!strcmp(key, "partition_setup")) {
|
|
err = og_json_parse_partition_array(value, partitions,
|
|
&num_partitions);
|
|
} else if (!strcmp(key, "serial_number")) {
|
|
err = og_json_parse_string(value, &serial_number);
|
|
} else if (!strcmp(key, "status")) {
|
|
err = og_json_parse_string(value, &status);
|
|
} else if (!strcmp(key, "link")) {
|
|
err = og_json_parse_uint(value, &link);
|
|
} else if (!strcmp(key, "efi")) {
|
|
err = og_json_parse_efi(value, &boot_entry_list);
|
|
} else if (!strcmp(key, "cache")) {
|
|
err = og_json_parse_cache(value, &cache_data);
|
|
}
|
|
|
|
if (err < 0)
|
|
goto err_out;
|
|
}
|
|
|
|
if (link)
|
|
cli->speed = link;
|
|
|
|
/*
|
|
* status is the only received field when the response is coming from a
|
|
* client using linux/windows mode.
|
|
*/
|
|
if (status) {
|
|
if (!strncmp(status, "LINUX", strlen("LINUX"))) {
|
|
cli->status = OG_CLIENT_STATUS_LINUX;
|
|
} else if (!strncmp(status, "WIN", strlen("WIN"))) {
|
|
cli->status = OG_CLIENT_STATUS_WIN;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
dbi = og_dbi_open(&ogconfig.db);
|
|
if (!dbi) {
|
|
syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
|
|
__func__, __LINE__);
|
|
goto err_out;
|
|
}
|
|
|
|
err = og_dbi_get_computer_info(dbi, &computer, cli->addr.sin_addr);
|
|
if (err < 0) {
|
|
og_dbi_close(dbi);
|
|
goto err_out;
|
|
}
|
|
|
|
if (og_update_cache_info(dbi, &cache_data, computer.id) < 0) {
|
|
og_dbi_close(dbi);
|
|
goto err_out;
|
|
}
|
|
|
|
res = og_update_boot_entries(dbi, &boot_entry_list, computer.id);
|
|
if (err < 0) {
|
|
og_dbi_close(dbi);
|
|
goto err_out;
|
|
}
|
|
|
|
res = og_update_client_disk_info(dbi, cli, computer.id, disks, num_disks,
|
|
partitions, num_partitions,
|
|
serial_number);
|
|
og_dbi_close(dbi);
|
|
|
|
if (!res) {
|
|
syslog(LOG_ERR, "Problem updating client configuration\n");
|
|
goto err_out;
|
|
}
|
|
|
|
og_cache_data_free(&cache_data);
|
|
og_boot_entry_free(&boot_entry_list);
|
|
return 0;
|
|
err_out:
|
|
syslog(LOG_ERR, "Failed to refresh info from client %s\n",
|
|
inet_ntoa(cli->addr.sin_addr));
|
|
og_cache_data_free(&cache_data);
|
|
og_boot_entry_free(&boot_entry_list);
|
|
return -1;
|
|
}
|
|
|
|
static bool og_dbi_update_image(struct og_dbi *dbi,
|
|
const struct og_image_legacy *img_info,
|
|
const char *computer_id)
|
|
{
|
|
int repo_id, sw_id, repo_alias;
|
|
const char *msglog;
|
|
dbi_result result;
|
|
uint32_t revision;
|
|
|
|
/* find repository identifier by repository ip and computer ID. */
|
|
result = dbi_conn_queryf(dbi->conn,
|
|
"SELECT repositorios.idrepositorio, repositorios.alias"
|
|
" FROM repositorios"
|
|
" LEFT JOIN ordenadores USING (idrepositorio)"
|
|
" WHERE repositorios.ip='%s' AND ordenadores.idordenador=%s",
|
|
img_info->repo, computer_id);
|
|
if (!result) {
|
|
dbi_conn_error(dbi->conn, &msglog);
|
|
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
|
|
__func__, __LINE__, msglog);
|
|
return false;
|
|
}
|
|
if (!dbi_result_next_row(result)) {
|
|
syslog(LOG_ERR,
|
|
"repository does not exist in database (%s:%d)\n",
|
|
__func__, __LINE__);
|
|
dbi_result_free(result);
|
|
return false;
|
|
}
|
|
repo_alias = dbi_result_get_uint(result, "alias");
|
|
if (repo_alias)
|
|
repo_id = repo_alias;
|
|
else
|
|
repo_id = dbi_result_get_uint(result, "idrepositorio");
|
|
|
|
dbi_result_free(result);
|
|
|
|
/* find software id by computer ID, disk number and partition. */
|
|
result = dbi_conn_queryf(dbi->conn,
|
|
"SELECT idperfilsoft"
|
|
" FROM ordenadores_particiones"
|
|
" WHERE idordenador=%s AND numdisk=%s AND numpar=%s",
|
|
computer_id, img_info->disk, img_info->part);
|
|
if (!result) {
|
|
dbi_conn_error(dbi->conn, &msglog);
|
|
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
|
|
__func__, __LINE__, msglog);
|
|
return false;
|
|
}
|
|
if (!dbi_result_next_row(result)) {
|
|
syslog(LOG_ERR,
|
|
"software profile does not exist in database (%s:%d)\n",
|
|
__func__, __LINE__);
|
|
dbi_result_free(result);
|
|
return false;
|
|
}
|
|
sw_id = dbi_result_get_uint(result, "idperfilsoft");
|
|
dbi_result_free(result);
|
|
|
|
/* update image table with this new image. */
|
|
result = dbi_conn_queryf(dbi->conn,
|
|
"UPDATE imagenes"
|
|
" SET idordenador=%s, numdisk=%s, numpar=%s, codpar=%s,"
|
|
" idperfilsoft=%d, idrepositorio=%d,"
|
|
" fechacreacion=NOW(), revision=revision+1"
|
|
" WHERE idimagen=%s",
|
|
computer_id, img_info->disk, img_info->part, img_info->code,
|
|
sw_id, repo_id, img_info->image_id);
|
|
|
|
if (!result) {
|
|
dbi_conn_error(dbi->conn, &msglog);
|
|
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
|
|
__func__, __LINE__, msglog);
|
|
return false;
|
|
}
|
|
dbi_result_free(result);
|
|
|
|
result = dbi_conn_queryf(dbi->conn,
|
|
"SELECT revision FROM imagenes WHERE idimagen=%s",
|
|
img_info->image_id);
|
|
if (!result) {
|
|
dbi_conn_error(dbi->conn, &msglog);
|
|
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
|
|
__func__, __LINE__, msglog);
|
|
return false;
|
|
}
|
|
|
|
if (!dbi_result_next_row(result)) {
|
|
syslog(LOG_ERR,
|
|
"no image found with id '%s' database (%s:%d)\n",
|
|
img_info->image_id, __func__, __LINE__);
|
|
dbi_result_free(result);
|
|
return false;
|
|
}
|
|
revision = dbi_result_get_uint(result, "revision");
|
|
dbi_result_free(result);
|
|
|
|
/* attach image to partition. */
|
|
result = dbi_conn_queryf(dbi->conn,
|
|
"UPDATE ordenadores_particiones"
|
|
" SET idimagen=%s, revision=%u, fechadespliegue=NOW()"
|
|
" WHERE idordenador=%s AND numdisk=%s AND numpar=%s",
|
|
img_info->image_id, revision,
|
|
computer_id, img_info->disk, img_info->part);
|
|
if (!result) {
|
|
dbi_conn_error(dbi->conn, &msglog);
|
|
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
|
|
__func__, __LINE__, msglog);
|
|
return false;
|
|
}
|
|
dbi_result_free(result);
|
|
|
|
return true;
|
|
}
|
|
|
|
static int update_image_info(struct og_dbi *dbi, const char *image_id,
|
|
const char *clonator, const char *compressor,
|
|
const char *filesystem, const uint64_t datasize,
|
|
uint64_t size, uint64_t lastupdate, uint32_t perms,
|
|
const char *checksum)
|
|
{
|
|
const char *msglog;
|
|
dbi_result result;
|
|
|
|
result = dbi_conn_queryf(dbi->conn,
|
|
"UPDATE imagenes"
|
|
" SET clonator='%s', compressor='%s',"
|
|
" filesystem='%s', datasize=%lld, "
|
|
" size=%lld, lastupdate=%lld, permissions=%u, checksum='%s' "
|
|
" WHERE idimagen=%s", clonator, compressor, filesystem,
|
|
datasize, size, lastupdate, perms, checksum, image_id);
|
|
|
|
if (!result) {
|
|
dbi_conn_error(dbi->conn, &msglog);
|
|
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
|
|
__func__, __LINE__, msglog);
|
|
return -1;
|
|
}
|
|
dbi_result_free(result);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int og_resp_image_create(json_t *data, struct og_client *cli)
|
|
{
|
|
uint64_t datasize = 0, size = 0, lastupdate = 0;
|
|
struct og_software_legacy soft_legacy;
|
|
struct og_image_legacy img_legacy;
|
|
struct og_computer computer = {};
|
|
const char *compressor = NULL;
|
|
const char *filesystem = NULL;
|
|
const char *partition = NULL;
|
|
const char *checksum = NULL;
|
|
const char *software = NULL;
|
|
const char *image_id = NULL;
|
|
const char *clonator = NULL;
|
|
const char *disk = NULL;
|
|
const char *code = NULL;
|
|
const char *name = NULL;
|
|
const char *repo = NULL;
|
|
uint32_t perms = 0;
|
|
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 if (!strcmp(key, "clonator"))
|
|
err = og_json_parse_string(value, &clonator);
|
|
else if (!strcmp(key, "compressor"))
|
|
err = og_json_parse_string(value, &compressor);
|
|
else if (!strcmp(key, "filesystem"))
|
|
err = og_json_parse_string(value, &filesystem);
|
|
else if (!strcmp(key, "datasize"))
|
|
err = og_json_parse_uint64(value, &datasize);
|
|
else if (!strcmp(key, "size"))
|
|
err = og_json_parse_uint64(value, &size);
|
|
else if (!strcmp(key, "lastupdate"))
|
|
err = og_json_parse_uint64(value, &lastupdate);
|
|
else if (!strcmp(key, "perms"))
|
|
err = og_json_parse_uint(value, &perms);
|
|
else if (!strcmp(key, "checksum"))
|
|
err = og_json_parse_string(value, &checksum);
|
|
|
|
if (err < 0)
|
|
return err;
|
|
}
|
|
|
|
if (!software || !partition || !disk || !code || !image_id || !name ||
|
|
!repo || !clonator || !compressor || !filesystem || !datasize) {
|
|
syslog(LOG_ERR, "malformed response json\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;
|
|
}
|
|
|
|
err = og_dbi_get_computer_info(dbi, &computer, cli->addr.sin_addr);
|
|
if (err < 0) {
|
|
og_dbi_close(dbi);
|
|
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);
|
|
|
|
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 = og_dbi_update_image(dbi, &img_legacy, soft_legacy.id);
|
|
if (!res) {
|
|
og_dbi_close(dbi);
|
|
syslog(LOG_ERR, "Problem updating client configuration\n");
|
|
return -1;
|
|
}
|
|
|
|
res = update_image_info(dbi, image_id, clonator, compressor,
|
|
filesystem, datasize, size, lastupdate, perms,
|
|
checksum);
|
|
og_dbi_close(dbi);
|
|
|
|
if (res) {
|
|
syslog(LOG_ERR, "Problem updating image info\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;
|
|
struct og_computer computer = {};
|
|
const char *partition = NULL;
|
|
const char *image_id = NULL;
|
|
const char *disk = NULL;
|
|
const char *msglog;
|
|
struct og_dbi *dbi;
|
|
dbi_result result;
|
|
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, "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);
|
|
|
|
if (err < 0)
|
|
return err;
|
|
}
|
|
|
|
if (!partition || !disk || !image_id) {
|
|
syslog(LOG_ERR, "malformed response json\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 idperfilsoft FROM imagenes "
|
|
" WHERE idimagen='%s'", image_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, "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(result, "idperfilsoft"));
|
|
dbi_result_free(result);
|
|
|
|
err = og_dbi_get_computer_info(dbi, &computer, cli->addr.sin_addr);
|
|
if (err < 0) {
|
|
og_dbi_close(dbi);
|
|
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);
|
|
|
|
result = dbi_conn_queryf(dbi->conn,
|
|
"UPDATE ordenadores_particiones"
|
|
" SET idimagen=%s, idperfilsoft=%s, fechadespliegue=NOW(),"
|
|
" revision=(SELECT revision FROM imagenes WHERE idimagen=%s),"
|
|
" idnombreso=IFNULL((SELECT idnombreso FROM perfilessoft WHERE idperfilsoft=%s),0)"
|
|
" WHERE idordenador=%s AND numdisk=%s AND numpar=%s",
|
|
img_legacy.image_id, img_legacy.software_id,
|
|
img_legacy.image_id, img_legacy.software_id,
|
|
soft_legacy.id, img_legacy.disk, img_legacy.part);
|
|
if (!result) {
|
|
dbi_conn_error(dbi->conn, &msglog);
|
|
syslog(LOG_ERR, "failed to update 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_agent_http_response_code(const char *buf)
|
|
{
|
|
if (!strncmp(buf, "HTTP/1.0 200 OK", strlen("HTTP/1.0 200 OK"))) {
|
|
return 200;
|
|
} else if (!strncmp(buf, "HTTP/1.0 202 Accepted",
|
|
strlen("HTTP/1.0 202 Accepted"))) {
|
|
return 202;
|
|
} else if (!strncmp(buf, "HTTP/1.0 400 Bad Request",
|
|
strlen("HTTP/1.0 400 Bad Request"))) {
|
|
return 400;
|
|
} else if (!strncmp(buf, "HTTP/1.0 500 Internal Server Error",
|
|
strlen("HTTP/1.0 500 Internal Server Error"))) {
|
|
return 500;
|
|
} else if (!strncmp(buf, "HTTP/1.0 503 Service Unavailable",
|
|
strlen("HTTP/1.0 503 Service Unavailable"))) {
|
|
return 503;
|
|
} else if (!strncmp(buf, "HTTP/1.0 103 Early Hints",
|
|
strlen("HTTP/1.0 103 Early Hints"))) {
|
|
return 103;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
int og_agent_state_process_response(struct og_client *cli)
|
|
{
|
|
int ret, err = -1, code;
|
|
json_error_t json_err;
|
|
bool success;
|
|
json_t *root;
|
|
char *body;
|
|
|
|
code = og_agent_http_response_code(cli->buf);
|
|
switch (code) {
|
|
case 103:
|
|
case 200:
|
|
ret = 0;
|
|
success = true;
|
|
break;
|
|
case 202:
|
|
ret = 1;
|
|
success = true;
|
|
break;
|
|
case 400:
|
|
ret = -1;
|
|
success = false;
|
|
syslog(LOG_ERR, "Client %s:%hu reports malformed HTTP request from server\n",
|
|
inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
|
|
break;
|
|
case 500:
|
|
ret = 0;
|
|
success = false;
|
|
cli->last_cmd = OG_CMD_UNSPEC;
|
|
syslog(LOG_ERR, "Client %s:%hu reports failure to process command\n",
|
|
inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
|
|
/* ... cancel pending actions related to this task for this client here */
|
|
break;
|
|
case 503:
|
|
ret = 1;
|
|
success = false;
|
|
syslog(LOG_ERR, "Client %s:%hu is busy to process command\n",
|
|
inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
|
|
break;
|
|
default:
|
|
ret = -1;
|
|
success = false;
|
|
syslog(LOG_ERR, "Client %s:%hu reports unknown HTTP response code\n",
|
|
inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
|
|
break;
|
|
}
|
|
|
|
if (success)
|
|
cli->last_cmd_result = OG_SUCCESS;
|
|
else
|
|
cli->last_cmd_result = OG_FAILURE;
|
|
|
|
if (code != 200 && code != 103) {
|
|
cli->last_cmd_id = 0;
|
|
return ret;
|
|
}
|
|
|
|
if (!cli->content_length) {
|
|
cli->last_cmd_id = 0;
|
|
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;
|
|
}
|
|
|
|
if (code == 103) {
|
|
err = og_resp_early_hints(cli, root);
|
|
json_decref(root);
|
|
return err;
|
|
}
|
|
|
|
switch (cli->last_cmd) {
|
|
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);
|
|
if (!err)
|
|
err = og_resp_update_cache(root, cli);
|
|
break;
|
|
case OG_CMD_CACHE_DELETE:
|
|
err = og_resp_update_cache(root, cli);
|
|
break;
|
|
case OG_CMD_CACHE_FETCH:
|
|
err = og_resp_update_cache(root, cli);
|
|
break;
|
|
default:
|
|
err = -1;
|
|
break;
|
|
}
|
|
|
|
json_decref(root);
|
|
|
|
if (err < 0) {
|
|
err = 0;
|
|
success = false;
|
|
cli->last_cmd_result = OG_FAILURE;
|
|
/* ... cancel pending actions related to this task for this client here */
|
|
}
|
|
|
|
cli->last_cmd_id = 0;
|
|
cli->last_cmd = OG_CMD_UNSPEC;
|
|
|
|
return err;
|
|
}
|