source: ogServer-Git/sources/ogAdmServer.c @ 87be2ce

Last change on this file since 87be2ce was 87be2ce, checked in by OpenGnSys Support Team <soporte-og@…>, 4 years ago

#980 Change initial probe to refresh

We have observed that an initial refresh is needed when the ogClient (in
ogLive mode) connects with the ogAdmServer, to generate the HTML menu.

This commit changes the probe command that was done at the beginning of
the connection to a refresh command. This way the client first generates
his HTML menu and the show to the user the browser with all the correct
information.

  • Property mode set to 100644
File size: 151.6 KB
Line 
1// *******************************************************************************************************
2// Servicio: ogAdmServer
3// Autor: José Manuel Alonso (E.T.S.I.I.) Universidad de Sevilla
4// Fecha Creación: Marzo-2010
5// Fecha Última modificación: Marzo-2010
6// Nombre del fichero: ogAdmServer.cpp
7// Descripción :Este fichero implementa el servicio de administración general del sistema
8// *******************************************************************************************************
9#include "ogAdmServer.h"
10#include "ogAdmLib.c"
11#include "dbi.h"
12#include "list.h"
13#include "schedule.h"
14#include <ev.h>
15#include <syslog.h>
16#include <sys/ioctl.h>
17#include <ifaddrs.h>
18#include <sys/types.h>
19#include <sys/stat.h>
20#include <fcntl.h>
21#include <jansson.h>
22#include <time.h>
23
24static char usuario[LONPRM]; // Usuario de acceso a la base de datos
25static char pasguor[LONPRM]; // Password del usuario
26static char datasource[LONPRM]; // Dirección IP del gestor de base de datos
27static char catalog[LONPRM]; // Nombre de la base de datos
28static char interface[LONPRM]; // Interface name
29static char auth_token[LONPRM]; // API token
30
31static struct og_dbi_config dbi_config = {
32        .user           = usuario,
33        .passwd         = pasguor,
34        .host           = datasource,
35        .database       = catalog,
36};
37
38//________________________________________________________________________________________________________
39//      Función: tomaConfiguracion
40//
41//      Descripción:
42//              Lee el fichero de configuración del servicio
43//      Parámetros:
44//              filecfg : Ruta completa al fichero de configuración
45//      Devuelve:
46//              true: Si el proceso es correcto
47//              false: En caso de ocurrir algún error
48//________________________________________________________________________________________________________
49static bool tomaConfiguracion(const char *filecfg)
50{
51        char buf[1024], *line;
52        char *key, *value;
53        FILE *fcfg;
54
55        if (filecfg == NULL || strlen(filecfg) == 0) {
56                syslog(LOG_ERR, "No configuration file has been specified\n");
57                return false;
58        }
59
60        fcfg = fopen(filecfg, "rt");
61        if (fcfg == NULL) {
62                syslog(LOG_ERR, "Cannot open configuration file `%s'\n",
63                       filecfg);
64                return false;
65        }
66
67        servidoradm[0] = '\0'; //inicializar variables globales
68
69        line = fgets(buf, sizeof(buf), fcfg);
70        while (line != NULL) {
71                const char *delim = "=";
72
73                line[strlen(line) - 1] = '\0';
74
75                key = strtok(line, delim);
76                value = strtok(NULL, delim);
77
78                if (!strcmp(StrToUpper(key), "SERVIDORADM"))
79                        snprintf(servidoradm, sizeof(servidoradm), "%s", value);
80                else if (!strcmp(StrToUpper(key), "PUERTO"))
81                        snprintf(puerto, sizeof(puerto), "%s", value);
82                else if (!strcmp(StrToUpper(key), "USUARIO"))
83                        snprintf(usuario, sizeof(usuario), "%s", value);
84                else if (!strcmp(StrToUpper(key), "PASSWORD"))
85                        snprintf(pasguor, sizeof(pasguor), "%s", value);
86                else if (!strcmp(StrToUpper(key), "DATASOURCE"))
87                        snprintf(datasource, sizeof(datasource), "%s", value);
88                else if (!strcmp(StrToUpper(key), "CATALOG"))
89                        snprintf(catalog, sizeof(catalog), "%s", value);
90                else if (!strcmp(StrToUpper(key), "INTERFACE"))
91                        snprintf(interface, sizeof(interface), "%s", value);
92                else if (!strcmp(StrToUpper(key), "APITOKEN"))
93                        snprintf(auth_token, sizeof(auth_token), "%s", value);
94
95                line = fgets(buf, sizeof(buf), fcfg);
96        }
97
98        fclose(fcfg);
99
100        if (!servidoradm[0]) {
101                syslog(LOG_ERR, "Missing SERVIDORADM in configuration file\n");
102                return false;
103        }
104        if (!puerto[0]) {
105                syslog(LOG_ERR, "Missing PUERTO in configuration file\n");
106                return false;
107        }
108        if (!usuario[0]) {
109                syslog(LOG_ERR, "Missing USUARIO in configuration file\n");
110                return false;
111        }
112        if (!pasguor[0]) {
113                syslog(LOG_ERR, "Missing PASSWORD in configuration file\n");
114                return false;
115        }
116        if (!datasource[0]) {
117                syslog(LOG_ERR, "Missing DATASOURCE in configuration file\n");
118                return false;
119        }
120        if (!catalog[0]) {
121                syslog(LOG_ERR, "Missing CATALOG in configuration file\n");
122                return false;
123        }
124        if (!interface[0])
125                syslog(LOG_ERR, "Missing INTERFACE in configuration file\n");
126
127        return true;
128}
129
130enum og_client_state {
131        OG_CLIENT_RECEIVING_HEADER      = 0,
132        OG_CLIENT_RECEIVING_PAYLOAD,
133        OG_CLIENT_PROCESSING_REQUEST,
134};
135
136#define OG_MSG_REQUEST_MAXLEN   65536
137#define OG_CMD_MAXLEN           64
138
139/* Shut down connection if there is no complete message after 10 seconds. */
140#define OG_CLIENT_TIMEOUT       10
141
142/* Agent client operation might take longer, shut down after 30 seconds. */
143#define OG_AGENT_CLIENT_TIMEOUT 30
144
145enum og_cmd_type {
146        OG_CMD_UNSPEC,
147        OG_CMD_WOL,
148        OG_CMD_PROBE,
149        OG_CMD_SHELL_RUN,
150        OG_CMD_SESSION,
151        OG_CMD_POWEROFF,
152        OG_CMD_REFRESH,
153        OG_CMD_REBOOT,
154        OG_CMD_STOP,
155        OG_CMD_HARDWARE,
156        OG_CMD_SOFTWARE,
157        OG_CMD_IMAGE_CREATE,
158        OG_CMD_IMAGE_RESTORE,
159        OG_CMD_SETUP,
160        OG_CMD_RUN_SCHEDULE,
161        OG_CMD_MAX
162};
163
164static LIST_HEAD(client_list);
165
166enum og_client_status {
167        OG_CLIENT_STATUS_OGLIVE,
168        OG_CLIENT_STATUS_BUSY,
169};
170
171struct og_client {
172        struct list_head        list;
173        struct ev_io            io;
174        struct ev_timer         timer;
175        struct sockaddr_in      addr;
176        enum og_client_state    state;
177        char                    buf[OG_MSG_REQUEST_MAXLEN];
178        unsigned int            buf_len;
179        unsigned int            msg_len;
180        int                     keepalive_idx;
181        bool                    rest;
182        bool                    agent;
183        int                     content_length;
184        char                    auth_token[64];
185        enum og_client_status   status;
186        enum og_cmd_type        last_cmd;
187};
188
189static inline int og_client_socket(const struct og_client *cli)
190{
191        return cli->io.fd;
192}
193
194static inline const char *og_client_status(const struct og_client *cli)
195{
196        if (cli->last_cmd != OG_CMD_UNSPEC)
197                return "BSY";
198
199        switch (cli->status) {
200        case OG_CLIENT_STATUS_BUSY:
201                return "BSY";
202        case OG_CLIENT_STATUS_OGLIVE:
203                return "OPG";
204        default:
205                return "OFF";
206        }
207}
208
209// ________________________________________________________________________________________________________
210// Función: clienteDisponible
211//
212//      Descripción:
213//              Comprueba la disponibilidad del cliente para recibir comandos interactivos
214//      Parametros:
215//              - ip : La ip del cliente a buscar
216//              - idx: (Salida)  Indice que ocupa el cliente, de estar ya registrado
217//      Devuelve:
218//              true: Si el cliente está disponible
219//              false: En caso contrario
220// ________________________________________________________________________________________________________
221bool clienteDisponible(char *ip, int* idx)
222{
223        int estado;
224
225        if (clienteExistente(ip, idx)) {
226                estado = strcmp(tbsockets[*idx].estado, CLIENTE_OCUPADO); // Cliente ocupado
227                if (estado == 0)
228                        return false;
229
230                estado = strcmp(tbsockets[*idx].estado, CLIENTE_APAGADO); // Cliente apagado
231                if (estado == 0)
232                        return false;
233
234                estado = strcmp(tbsockets[*idx].estado, CLIENTE_INICIANDO); // Cliente en proceso de inclusión
235                if (estado == 0)
236                        return false;
237
238                return true; // En caso contrario el cliente está disponible
239        }
240        return false; // Cliente no está registrado en el sistema
241}
242// ________________________________________________________________________________________________________
243// Función: clienteExistente
244//
245//      Descripción:
246//              Comprueba si el cliente está registrado en la tabla de socket del sistema
247//      Parametros:
248//              - ip : La ip del cliente a buscar
249//              - idx:(Salida)  Indice que ocupa el cliente, de estar ya registrado
250//      Devuelve:
251//              true: Si el cliente está registrado
252//              false: En caso contrario
253// ________________________________________________________________________________________________________
254bool clienteExistente(char *ip, int* idx)
255{
256        int i;
257        for (i = 0; i < MAXIMOS_CLIENTES; i++) {
258                if (contieneIP(ip, tbsockets[i].ip)) { // Si existe la IP en la cadena
259                        *idx = i;
260                        return true;
261                }
262        }
263        return false;
264}
265// ________________________________________________________________________________________________________
266// Función: actualizaConfiguracion
267//
268//      Descripción:
269//              Esta función actualiza la base de datos con la configuracion de particiones de un cliente
270//      Parámetros:
271//              - db: Objeto base de datos (ya operativo)
272//              - tbl: Objeto tabla
273//              - cfg: cadena con una Configuración
274//              - ido: Identificador del ordenador cliente
275//      Devuelve:
276//              true: Si el proceso es correcto
277//              false: En caso de ocurrir algún error
278//      Especificaciones:
279//              Los parametros de la configuración son:
280//                      par= Número de partición
281//                      cpt= Codigo o tipo de partición
282//                      sfi= Sistema de ficheros que está implementado en la partición
283//                      soi= Nombre del sistema de ficheros instalado en la partición
284//                      tam= Tamaño de la partición
285// ________________________________________________________________________________________________________
286bool actualizaConfiguracion(struct og_dbi *dbi, char *cfg, int ido)
287{
288        int lon, p, c,i, dato, swu, idsoi, idsfi,k;
289        char *ptrPar[MAXPAR], *ptrCfg[7], *ptrDual[2], tbPar[LONSTD];
290        char *ser, *disk, *par, *cpt, *sfi, *soi, *tam, *uso; // Parametros de configuración.
291        dbi_result result, result_update;
292        const char *msglog;
293
294        lon = 0;
295        p = splitCadena(ptrPar, cfg, '\n');
296        for (i = 0; i < p; i++) {
297                c = splitCadena(ptrCfg, ptrPar[i], '\t');
298
299                // Si la 1ª línea solo incluye el número de serie del equipo; actualizar BD.
300                if (i == 0 && c == 1) {
301                        splitCadena(ptrDual, ptrCfg[0], '=');
302                        ser = ptrDual[1];
303                        if (strlen(ser) > 0) {
304                                // Solo actualizar si número de serie no existía.
305                                result = dbi_conn_queryf(dbi->conn,
306                                                "UPDATE ordenadores SET numserie='%s'"
307                                                " WHERE idordenador=%d AND numserie IS NULL",
308                                                ser, ido);
309                                if (!result) {
310                                        dbi_conn_error(dbi->conn, &msglog);
311                                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
312                                               __func__, __LINE__, msglog);
313                                        return false;
314                                }
315                                dbi_result_free(result);
316                        }
317                        continue;
318                }
319
320                // Distribución de particionado.
321                disk = par = cpt = sfi = soi = tam = uso = NULL;
322
323                splitCadena(ptrDual, ptrCfg[0], '=');
324                disk = ptrDual[1]; // Número de disco
325
326                splitCadena(ptrDual, ptrCfg[1], '=');
327                par = ptrDual[1]; // Número de partición
328
329                k=splitCadena(ptrDual, ptrCfg[2], '=');
330                if(k==2){
331                        cpt = ptrDual[1]; // Código de partición
332                }else{
333                        cpt = (char*)"0";
334                }
335
336                k=splitCadena(ptrDual, ptrCfg[3], '=');
337                if(k==2){
338                        sfi = ptrDual[1]; // Sistema de ficheros
339                        /* Comprueba existencia del s0xistema de ficheros instalado */
340                        idsfi = checkDato(dbi, sfi, "sistemasficheros", "descripcion","idsistemafichero");
341                }
342                else
343                        idsfi=0;
344
345                k=splitCadena(ptrDual, ptrCfg[4], '=');
346                if(k==2){ // Sistema operativo detecdtado
347                        soi = ptrDual[1]; // Nombre del S.O. instalado
348                        /* Comprueba existencia del sistema operativo instalado */
349                        idsoi = checkDato(dbi, soi, "nombresos", "nombreso", "idnombreso");
350                }
351                else
352                        idsoi=0;
353
354                splitCadena(ptrDual, ptrCfg[5], '=');
355                tam = ptrDual[1]; // Tamaño de la partición
356
357                splitCadena(ptrDual, ptrCfg[6], '=');
358                uso = ptrDual[1]; // Porcentaje de uso del S.F.
359
360                lon += sprintf(tbPar + lon, "(%s, %s),", disk, par);
361
362                result = dbi_conn_queryf(dbi->conn,
363                                "SELECT numdisk, numpar, tamano, uso, idsistemafichero, idnombreso"
364                                "  FROM ordenadores_particiones"
365                                " WHERE idordenador=%d AND numdisk=%s AND numpar=%s",
366                                ido, disk, par);
367                if (!result) {
368                        dbi_conn_error(dbi->conn, &msglog);
369                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
370                               __func__, __LINE__, msglog);
371                        return false;
372                }
373                if (!dbi_result_next_row(result)) {
374                        result_update = dbi_conn_queryf(dbi->conn,
375                                        "INSERT INTO ordenadores_particiones(idordenador,numdisk,numpar,codpar,tamano,uso,idsistemafichero,idnombreso,idimagen)"
376                                        " VALUES(%d,%s,%s,0x%s,%s,%s,%d,%d,0)",
377                                        ido, disk, par, cpt, tam, uso, idsfi, idsoi);
378                        if (!result_update) {
379                                dbi_conn_error(dbi->conn, &msglog);
380                                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
381                                       __func__, __LINE__, msglog);
382                                return false;
383                        }
384                        dbi_result_free(result_update);
385
386                } else { // Existe el registro
387                        swu = true; // Se supone que algún dato ha cambiado
388
389                        dato = dbi_result_get_uint(result, "tamano");
390                        if (atoi(tam) == dato) {// Parámetro tamaño igual al almacenado
391                                dato = dbi_result_get_uint(result, "idsistemafichero");
392                                if (idsfi == dato) {// Parámetro sistema de fichero igual al almacenado
393                                        dato = dbi_result_get_uint(result, "idnombreso");
394                                        if (idsoi == dato) {// Parámetro sistema de fichero distinto al almacenado
395                                                swu = false; // Todos los parámetros de la partición son iguales, no se actualiza
396                                        }
397                                }
398                        }
399                        if (swu) { // Hay que actualizar los parámetros de la partición
400                                result_update = dbi_conn_queryf(dbi->conn,
401                                        "UPDATE ordenadores_particiones SET "
402                                        " codpar=0x%s,"
403                                        " tamano=%s,"
404                                        " uso=%s,"
405                                        " idsistemafichero=%d,"
406                                        " idnombreso=%d,"
407                                        " idimagen=0,"
408                                        " idperfilsoft=0,"
409                                        " fechadespliegue=NULL"
410                                        " WHERE idordenador=%d AND numdisk=%s AND numpar=%s",
411                                        cpt, tam, uso, idsfi, idsoi, ido, disk, par);
412                        } else {  // Actualizar porcentaje de uso.
413                                result_update = dbi_conn_queryf(dbi->conn,
414                                        "UPDATE ordenadores_particiones SET "
415                                        " codpar=0x%s,"
416                                        " uso=%s"
417                                        " WHERE idordenador=%d AND numdisk=%s AND numpar=%s",
418                                        cpt, uso, ido, disk, par);
419                        }
420                        if (!result_update) {
421                                dbi_conn_error(dbi->conn, &msglog);
422                                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
423                                       __func__, __LINE__, msglog);
424                                return false;
425                        }
426
427                        dbi_result_free(result_update);
428                }
429                dbi_result_free(result);
430        }
431        lon += sprintf(tbPar + lon, "(0,0)");
432        // Eliminar particiones almacenadas que ya no existen
433        result_update = dbi_conn_queryf(dbi->conn,
434                "DELETE FROM ordenadores_particiones WHERE idordenador=%d AND (numdisk, numpar) NOT IN (%s)",
435                        ido, tbPar);
436        if (!result_update) {
437                dbi_conn_error(dbi->conn, &msglog);
438                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
439                       __func__, __LINE__, msglog);
440                return false;
441        }
442        dbi_result_free(result_update);
443
444        return true;
445}
446// ________________________________________________________________________________________________________
447// Función: checkDato
448//
449//      Descripción:
450//               Esta función comprueba si existe un dato en una tabla y si no es así lo incluye. devuelve en
451//              cualquier caso el identificador del registro existenet o del insertado
452//      Parámetros:
453//              - db: Objeto base de datos (ya operativo)
454//              - tbl: Objeto tabla
455//              - dato: Dato
456//              - tabla: Nombre de la tabla
457//              - nomdato: Nombre del dato en la tabla
458//              - nomidentificador: Nombre del identificador en la tabla
459//      Devuelve:
460//              El identificador del registro existente o el del insertado
461//
462//      Especificaciones:
463//              En caso de producirse algún error se devuelve el valor 0
464// ________________________________________________________________________________________________________
465
466int checkDato(struct og_dbi *dbi, char *dato, const char *tabla,
467                     const char *nomdato, const char *nomidentificador)
468{
469        const char *msglog;
470        int identificador;
471        dbi_result result;
472
473        if (strlen(dato) == 0)
474                return (0); // EL dato no tiene valor
475        result = dbi_conn_queryf(dbi->conn,
476                        "SELECT %s FROM %s WHERE %s ='%s'", nomidentificador,
477                        tabla, nomdato, dato);
478
479        // Ejecuta consulta
480        if (!result) {
481                dbi_conn_error(dbi->conn, &msglog);
482                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
483                       __func__, __LINE__, msglog);
484                return (0);
485        }
486        if (!dbi_result_next_row(result)) { //  Software NO existente
487                dbi_result_free(result);
488
489                result = dbi_conn_queryf(dbi->conn,
490                                "INSERT INTO %s (%s) VALUES('%s')", tabla, nomdato, dato);
491                if (!result) {
492                        dbi_conn_error(dbi->conn, &msglog);
493                        og_info((char *)msglog);
494                        return (0);
495                }
496                // Recupera el identificador del software
497                identificador = dbi_conn_sequence_last(dbi->conn, NULL);
498        } else {
499                identificador = dbi_result_get_uint(result, nomidentificador);
500        }
501        dbi_result_free(result);
502
503        return (identificador);
504}
505
506struct og_task {
507        uint32_t        procedure_id;
508        uint32_t        type_scope;
509        uint32_t        scope;
510        const char      *filtered_scope;
511        const char      *params;
512};
513
514static TRAMA *og_msg_alloc(char *data, unsigned int len);
515static void og_msg_free(TRAMA *ptrTrama);
516
517static bool og_send_cmd(char *ips_array[], int ips_array_len,
518                        const char *state, TRAMA *ptrTrama)
519{
520        int i, idx;
521
522        for (i = 0; i < ips_array_len; i++) {
523                if (clienteDisponible(ips_array[i], &idx)) { // Si el cliente puede recibir comandos
524                        int sock = tbsockets[idx].cli ? tbsockets[idx].cli->io.fd : -1;
525
526                        strcpy(tbsockets[idx].estado, state); // Actualiza el estado del cliente
527                        if (sock >= 0 && !mandaTrama(&sock, ptrTrama)) {
528                                syslog(LOG_ERR, "failed to send response to %s:%s\n",
529                                       ips_array[i], strerror(errno));
530                        }
531                }
532        }
533        return true;
534}
535
536// ________________________________________________________________________________________________________
537// Función: Levanta
538//
539//      Descripción:
540//              Enciende ordenadores a través de la red cuyas macs se pasan como parámetro
541//      Parámetros:
542//              - iph: Cadena de direcciones ip separadas por ";"
543//              - mac: Cadena de direcciones mac separadas por ";"
544//              - mar: Método de arranque (1=Broadcast, 2=Unicast)
545//      Devuelve:
546//              true: Si el proceso es correcto
547//              false: En caso de ocurrir algún error
548// ________________________________________________________________________________________________________
549
550bool Levanta(char *ptrIP[], char *ptrMacs[], int lon, char *mar)
551{
552        unsigned int on = 1;
553        struct sockaddr_in local;
554        int i, res;
555        int s;
556
557        /* Creación de socket para envío de magig packet */
558        s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
559        if (s < 0) {
560                syslog(LOG_ERR, "cannot create socket for magic packet\n");
561                return false;
562        }
563        res = setsockopt(s, SOL_SOCKET, SO_BROADCAST, (unsigned int *) &on,
564                         sizeof(on));
565        if (res < 0) {
566                syslog(LOG_ERR, "cannot set broadcast socket\n");
567                return false;
568        }
569        memset(&local, 0, sizeof(local));
570        local.sin_family = AF_INET;
571        local.sin_port = htons(PUERTO_WAKEUP);
572        local.sin_addr.s_addr = htonl(INADDR_ANY);
573
574        for (i = 0; i < lon; i++) {
575                if (!WakeUp(s, ptrIP[i], ptrMacs[i], mar)) {
576                        syslog(LOG_ERR, "problem sending magic packet\n");
577                        close(s);
578                        return false;
579                }
580        }
581        close(s);
582        return true;
583}
584
585#define OG_WOL_SEQUENCE         6
586#define OG_WOL_MACADDR_LEN      6
587#define OG_WOL_REPEAT           16
588
589struct wol_msg {
590        char secuencia_FF[OG_WOL_SEQUENCE];
591        char macbin[OG_WOL_REPEAT][OG_WOL_MACADDR_LEN];
592};
593
594static bool wake_up_broadcast(int sd, struct sockaddr_in *client,
595                              const struct wol_msg *msg)
596{
597        struct sockaddr_in *broadcast_addr;
598        struct ifaddrs *ifaddr, *ifa;
599        int ret;
600
601        if (getifaddrs(&ifaddr) < 0) {
602                syslog(LOG_ERR, "cannot get list of addresses\n");
603                return false;
604        }
605
606        client->sin_addr.s_addr = htonl(INADDR_BROADCAST);
607
608        for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
609                if (ifa->ifa_addr == NULL ||
610                    ifa->ifa_addr->sa_family != AF_INET ||
611                    strcmp(ifa->ifa_name, interface) != 0)
612                        continue;
613
614                broadcast_addr =
615                        (struct sockaddr_in *)ifa->ifa_ifu.ifu_broadaddr;
616                client->sin_addr.s_addr = broadcast_addr->sin_addr.s_addr;
617                break;
618        }
619        freeifaddrs(ifaddr);
620
621        ret = sendto(sd, msg, sizeof(*msg), 0,
622                     (struct sockaddr *)client, sizeof(*client));
623        if (ret < 0) {
624                syslog(LOG_ERR, "failed to send broadcast wol\n");
625                return false;
626        }
627
628        return true;
629}
630
631static bool wake_up_unicast(int sd, struct sockaddr_in *client,
632                            const struct wol_msg *msg,
633                            const struct in_addr *addr)
634{
635        int ret;
636
637        client->sin_addr.s_addr = addr->s_addr;
638
639        ret = sendto(sd, msg, sizeof(*msg), 0,
640                     (struct sockaddr *)client, sizeof(*client));
641        if (ret < 0) {
642                syslog(LOG_ERR, "failed to send unicast wol\n");
643                return false;
644        }
645
646        return true;
647}
648
649enum wol_delivery_type {
650        OG_WOL_BROADCAST = 1,
651        OG_WOL_UNICAST = 2
652};
653
654//_____________________________________________________________________________________________________________
655// Función: WakeUp
656//
657//       Descripción:
658//              Enciende el ordenador cuya MAC se pasa como parámetro
659//      Parámetros:
660//              - s : Socket para enviar trama magic packet
661//              - iph : Cadena con la dirección ip
662//              - mac : Cadena con la dirección mac en formato XXXXXXXXXXXX
663//              - mar: Método de arranque (1=Broadcast, 2=Unicast)
664//      Devuelve:
665//              true: Si el proceso es correcto
666//              false: En caso de ocurrir algún error
667//_____________________________________________________________________________________________________________
668//
669bool WakeUp(int s, char* iph, char *mac, char *mar)
670{
671        unsigned int macaddr[OG_WOL_MACADDR_LEN];
672        char HDaddress_bin[OG_WOL_MACADDR_LEN];
673        struct sockaddr_in WakeUpCliente;
674        struct wol_msg Trama_WakeUp;
675        struct in_addr addr;
676        bool ret;
677        int i;
678
679        for (i = 0; i < 6; i++) // Primera secuencia de la trama Wake Up (0xFFFFFFFFFFFF)
680                Trama_WakeUp.secuencia_FF[i] = 0xFF;
681
682        sscanf(mac, "%02x%02x%02x%02x%02x%02x",
683               &macaddr[0], &macaddr[1], &macaddr[2],
684               &macaddr[3], &macaddr[4], &macaddr[5]);
685
686        for (i = 0; i < 6; i++)
687                HDaddress_bin[i] = (uint8_t)macaddr[i];
688
689        for (i = 0; i < 16; i++) // Segunda secuencia de la trama Wake Up , repetir 16 veces su la MAC
690                memcpy(&Trama_WakeUp.macbin[i][0], &HDaddress_bin, 6);
691
692        /* Creación de socket del cliente que recibe la trama magic packet */
693        WakeUpCliente.sin_family = AF_INET;
694        WakeUpCliente.sin_port = htons((short) PUERTO_WAKEUP);
695
696        switch (atoi(mar)) {
697        case OG_WOL_BROADCAST:
698                ret = wake_up_broadcast(s, &WakeUpCliente, &Trama_WakeUp);
699                break;
700        case OG_WOL_UNICAST:
701                if (inet_aton(iph, &addr) < 0) {
702                        syslog(LOG_ERR, "bad IP address for unicast wol\n");
703                        ret = false;
704                        break;
705                }
706                ret = wake_up_unicast(s, &WakeUpCliente, &Trama_WakeUp, &addr);
707                break;
708        default:
709                syslog(LOG_ERR, "unknown wol type\n");
710                ret = false;
711                break;
712        }
713        return ret;
714}
715
716// ________________________________________________________________________________________________________
717// Función: actualizaCreacionImagen
718//
719//      Descripción:
720//              Esta función actualiza la base de datos con el resultado de la creación de una imagen
721//      Parámetros:
722//              - db: Objeto base de datos (ya operativo)
723//              - tbl: Objeto tabla
724//              - idi: Identificador de la imagen
725//              - dsk: Disco de donde se creó
726//              - par: Partición de donde se creó
727//              - cpt: Código de partición
728//              - ipr: Ip del repositorio
729//              - ido: Identificador del ordenador modelo
730//      Devuelve:
731//              true: Si el proceso es correcto
732//              false: En caso de ocurrir algún error
733// ________________________________________________________________________________________________________
734bool actualizaCreacionImagen(struct og_dbi *dbi, char *idi, char *dsk,
735                             char *par, char *cpt, char *ipr, char *ido)
736{
737        const char *msglog;
738        dbi_result result;
739        int idr,ifs;
740
741        /* Toma identificador del repositorio correspondiente al ordenador modelo */
742        result = dbi_conn_queryf(dbi->conn,
743                        "SELECT repositorios.idrepositorio"
744                        "  FROM repositorios"
745                        "  LEFT JOIN ordenadores USING (idrepositorio)"
746                        " WHERE repositorios.ip='%s' AND ordenadores.idordenador=%s", ipr, ido);
747
748        if (!result) {
749                dbi_conn_error(dbi->conn, &msglog);
750                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
751                       __func__, __LINE__, msglog);
752                return false;
753        }
754        if (!dbi_result_next_row(result)) {
755                syslog(LOG_ERR,
756                       "repository does not exist in database (%s:%d)\n",
757                       __func__, __LINE__);
758                dbi_result_free(result);
759                return false;
760        }
761        idr = dbi_result_get_uint(result, "idrepositorio");
762        dbi_result_free(result);
763
764        /* Toma identificador del perfilsoftware */
765        result = dbi_conn_queryf(dbi->conn,
766                        "SELECT idperfilsoft"
767                        "  FROM ordenadores_particiones"
768                        " WHERE idordenador=%s AND numdisk=%s AND numpar=%s", ido, dsk, par);
769
770        if (!result) {
771                dbi_conn_error(dbi->conn, &msglog);
772                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
773                       __func__, __LINE__, msglog);
774                return false;
775        }
776        if (!dbi_result_next_row(result)) {
777                syslog(LOG_ERR,
778                       "software profile does not exist in database (%s:%d)\n",
779                       __func__, __LINE__);
780                dbi_result_free(result);
781                return false;
782        }
783        ifs = dbi_result_get_uint(result, "idperfilsoft");
784        dbi_result_free(result);
785
786        /* Actualizar los datos de la imagen */
787        result = dbi_conn_queryf(dbi->conn,
788                "UPDATE imagenes"
789                "   SET idordenador=%s, numdisk=%s, numpar=%s, codpar=%s,"
790                "       idperfilsoft=%d, idrepositorio=%d,"
791                "       fechacreacion=NOW(), revision=revision+1"
792                " WHERE idimagen=%s", ido, dsk, par, cpt, ifs, idr, idi);
793
794        if (!result) {
795                dbi_conn_error(dbi->conn, &msglog);
796                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
797                       __func__, __LINE__, msglog);
798                return false;
799        }
800        dbi_result_free(result);
801
802        /* Actualizar los datos en el cliente */
803        result = dbi_conn_queryf(dbi->conn,
804                "UPDATE ordenadores_particiones"
805                "   SET idimagen=%s, revision=(SELECT revision FROM imagenes WHERE idimagen=%s),"
806                "       fechadespliegue=NOW()"
807                " WHERE idordenador=%s AND numdisk=%s AND numpar=%s",
808                idi, idi, ido, dsk, par);
809        if (!result) {
810                dbi_conn_error(dbi->conn, &msglog);
811                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
812                       __func__, __LINE__, msglog);
813                return false;
814        }
815        dbi_result_free(result);
816
817        return true;
818}
819
820// ________________________________________________________________________________________________________
821// Función: actualizaRestauracionImagen
822//
823//      Descripción:
824//              Esta función actualiza la base de datos con el resultado de la restauración de una imagen
825//      Parámetros:
826//              - db: Objeto base de datos (ya operativo)
827//              - tbl: Objeto tabla
828//              - idi: Identificador de la imagen
829//              - dsk: Disco de donde se restauró
830//              - par: Partición de donde se restauró
831//              - ido: Identificador del cliente donde se restauró
832//              - ifs: Identificador del perfil software contenido      en la imagen
833//      Devuelve:
834//              true: Si el proceso es correcto
835//              false: En caso de ocurrir algún error
836// ________________________________________________________________________________________________________
837bool actualizaRestauracionImagen(struct og_dbi *dbi, char *idi,
838                                 char *dsk, char *par, char *ido, char *ifs)
839{
840        const char *msglog;
841        dbi_result result;
842
843        /* Actualizar los datos de la imagen */
844        result = dbi_conn_queryf(dbi->conn,
845                        "UPDATE ordenadores_particiones"
846                        "   SET idimagen=%s, idperfilsoft=%s, fechadespliegue=NOW(),"
847                        "       revision=(SELECT revision FROM imagenes WHERE idimagen=%s),"
848                        "       idnombreso=IFNULL((SELECT idnombreso FROM perfilessoft WHERE idperfilsoft=%s),0)"
849                        " WHERE idordenador=%s AND numdisk=%s AND numpar=%s", idi, ifs, idi, ifs, ido, dsk, par);
850
851        if (!result) {
852                dbi_conn_error(dbi->conn, &msglog);
853                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
854                       __func__, __LINE__, msglog);
855                return false;
856        }
857        dbi_result_free(result);
858
859        return true;
860}
861// ________________________________________________________________________________________________________
862// Función: actualizaHardware
863//
864//              Descripción:
865//                      Actualiza la base de datos con la configuracion hardware del cliente
866//              Parámetros:
867//                      - db: Objeto base de datos (ya operativo)
868//                      - tbl: Objeto tabla
869//                      - hrd: cadena con el inventario hardware
870//                      - ido: Identificador del ordenador
871//                      - npc: Nombre del ordenador
872//                      - idc: Identificador del centro o Unidad organizativa
873// ________________________________________________________________________________________________________
874//
875bool actualizaHardware(struct og_dbi *dbi, char *hrd, char *ido, char *npc,
876                       char *idc)
877{
878        const char *msglog;
879        int idtipohardware, idperfilhard;
880        int lon, i, j, aux;
881        bool retval;
882        char *whard;
883        int tbidhardware[MAXHARDWARE];
884        char *tbHardware[MAXHARDWARE],*dualHardware[2], strInt[LONINT], *idhardwares;
885        dbi_result result;
886
887        /* Toma Centro (Unidad Organizativa) */
888        result = dbi_conn_queryf(dbi->conn,
889                                 "SELECT idperfilhard FROM ordenadores WHERE idordenador=%s",
890                                 ido);
891        if (!result) {
892                dbi_conn_error(dbi->conn, &msglog);
893                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
894                       __func__, __LINE__, msglog);
895                return false;
896        }
897        if (!dbi_result_next_row(result)) {
898                syslog(LOG_ERR, "client does not exist in database (%s:%d)\n",
899                       __func__, __LINE__);
900                dbi_result_free(result);
901                return false;
902        }
903        idperfilhard = dbi_result_get_uint(result, "idperfilhard");
904        dbi_result_free(result);
905
906        whard=escaparCadena(hrd); // Codificar comillas simples
907        if(!whard)
908                return false;
909        /* Recorre componentes hardware*/
910        lon = splitCadena(tbHardware, whard, '\n');
911        if (lon > MAXHARDWARE)
912                lon = MAXHARDWARE; // Limita el número de componentes hardware
913        /*
914         for (i=0;i<lon;i++){
915         sprintf(msglog,"Linea de inventario: %s",tbHardware[i]);
916         RegistraLog(msglog,false);
917         }
918         */
919        for (i = 0; i < lon; i++) {
920                splitCadena(dualHardware, rTrim(tbHardware[i]), '=');
921                //sprintf(msglog,"nemonico: %s",dualHardware[0]);
922                //RegistraLog(msglog,false);
923                //sprintf(msglog,"valor: %s",dualHardware[1]);
924                //RegistraLog(msglog,false);
925                result = dbi_conn_queryf(dbi->conn,
926                                         "SELECT idtipohardware,descripcion FROM tipohardwares WHERE nemonico='%s'",
927                                         dualHardware[0]);
928                if (!result) {
929                        dbi_conn_error(dbi->conn, &msglog);
930                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
931                               __func__, __LINE__, msglog);
932                        return false;
933                }
934                if (!dbi_result_next_row(result)) { //  Tipo de Hardware NO existente
935                        dbi_result_free(result);
936                        return false;
937                } else { //  Tipo de Hardware Existe
938                        idtipohardware = dbi_result_get_uint(result, "idtipohardware");
939                        dbi_result_free(result);
940
941                        result = dbi_conn_queryf(dbi->conn,
942                                                 "SELECT idhardware FROM hardwares WHERE idtipohardware=%d AND descripcion='%s'",
943                                                 idtipohardware, dualHardware[1]);
944
945                        if (!result) {
946                                dbi_conn_error(dbi->conn, &msglog);
947                                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
948                                       __func__, __LINE__, msglog);
949                                return false;
950                        }
951
952                        if (!dbi_result_next_row(result)) { //  Hardware NO existente
953                                dbi_result_free(result);
954                                result = dbi_conn_queryf(dbi->conn,
955                                                        "INSERT hardwares (idtipohardware,descripcion,idcentro,grupoid) "
956                                                        " VALUES(%d,'%s',%s,0)", idtipohardware,
957                                                dualHardware[1], idc);
958                                if (!result) {
959                                        dbi_conn_error(dbi->conn, &msglog);
960                                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
961                                               __func__, __LINE__, msglog);
962                                        return false;
963                                }
964
965                                // Recupera el identificador del hardware
966                                tbidhardware[i] = dbi_conn_sequence_last(dbi->conn, NULL);
967                        } else {
968                                tbidhardware[i] = dbi_result_get_uint(result, "idhardware");
969                        }
970                        dbi_result_free(result);
971                }
972        }
973        // Ordena tabla de identificadores para cosultar si existe un pefil con esas especificaciones
974
975        for (i = 0; i < lon - 1; i++) {
976                for (j = i + 1; j < lon; j++) {
977                        if (tbidhardware[i] > tbidhardware[j]) {
978                                aux = tbidhardware[i];
979                                tbidhardware[i] = tbidhardware[j];
980                                tbidhardware[j] = aux;
981                        }
982                }
983        }
984        /* Crea cadena de identificadores de componentes hardware separados por coma */
985        sprintf(strInt, "%d", tbidhardware[lon - 1]); // Pasa a cadena el último identificador que es de mayor longitud
986        aux = strlen(strInt); // Calcula longitud de cadena para reservar espacio a todos los perfiles
987        idhardwares = reservaMemoria(sizeof(aux) * lon + lon);
988        if (idhardwares == NULL) {
989                syslog(LOG_ERR, "%s:%d OOM\n", __FILE__, __LINE__);
990                return false;
991        }
992        aux = sprintf(idhardwares, "%d", tbidhardware[0]);
993        for (i = 1; i < lon; i++)
994                aux += sprintf(idhardwares + aux, ",%d", tbidhardware[i]);
995
996        if (!cuestionPerfilHardware(dbi, idc, ido, idperfilhard, idhardwares,
997                        npc, tbidhardware, lon)) {
998                syslog(LOG_ERR, "Problem updating client hardware\n");
999                retval=false;
1000        }
1001        else {
1002                retval=true;
1003        }
1004        liberaMemoria(whard);
1005        liberaMemoria(idhardwares);
1006        return (retval);
1007}
1008// ________________________________________________________________________________________________________
1009// Función: cuestionPerfilHardware
1010//
1011//              Descripción:
1012//                      Comprueba existencia de perfil hardware y actualización de éste para el ordenador
1013//              Parámetros:
1014//                      - db: Objeto base de datos (ya operativo)
1015//                      - tbl: Objeto tabla
1016//                      - idc: Identificador de la Unidad organizativa donde se encuentra el cliente
1017//                      - ido: Identificador del ordenador
1018//                      - tbidhardware: Identificador del tipo de hardware
1019//                      - con: Número de componentes detectados para configurar un el perfil hardware
1020//                      - npc: Nombre del cliente
1021// ________________________________________________________________________________________________________
1022bool cuestionPerfilHardware(struct og_dbi *dbi, char *idc, char *ido,
1023                int idperfilhardware, char *idhardwares, char *npc, int *tbidhardware,
1024                int lon)
1025{
1026        const char *msglog;
1027        dbi_result result;
1028        int i;
1029        int nwidperfilhard;
1030
1031        // Busca perfil hard del ordenador que contenga todos los componentes hardware encontrados
1032        result = dbi_conn_queryf(dbi->conn,
1033                "SELECT idperfilhard FROM"
1034                " (SELECT perfileshard_hardwares.idperfilhard as idperfilhard,"
1035                "       group_concat(cast(perfileshard_hardwares.idhardware AS char( 11) )"
1036                "       ORDER BY perfileshard_hardwares.idhardware SEPARATOR ',' ) AS idhardwares"
1037                " FROM  perfileshard_hardwares"
1038                " GROUP BY perfileshard_hardwares.idperfilhard) AS temp"
1039                " WHERE idhardwares LIKE '%s'", idhardwares);
1040
1041        if (!result) {
1042                dbi_conn_error(dbi->conn, &msglog);
1043                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1044                       __func__, __LINE__, msglog);
1045                return false;
1046        }
1047        if (!dbi_result_next_row(result)) {
1048                // No existe un perfil hardware con esos componentes de componentes hardware, lo crea
1049                dbi_result_free(result);
1050                result = dbi_conn_queryf(dbi->conn,
1051                                "INSERT perfileshard  (descripcion,idcentro,grupoid)"
1052                                " VALUES('Perfil hardware (%s) ',%s,0)", npc, idc);
1053                if (!result) {
1054                        dbi_conn_error(dbi->conn, &msglog);
1055                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1056                               __func__, __LINE__, msglog);
1057                        return false;
1058                }
1059                dbi_result_free(result);
1060
1061                // Recupera el identificador del nuevo perfil hardware
1062                nwidperfilhard = dbi_conn_sequence_last(dbi->conn, NULL);
1063
1064                // Crea la relación entre perfiles y componenetes hardware
1065                for (i = 0; i < lon; i++) {
1066                        result = dbi_conn_queryf(dbi->conn,
1067                                        "INSERT perfileshard_hardwares  (idperfilhard,idhardware)"
1068                                                " VALUES(%d,%d)", nwidperfilhard, tbidhardware[i]);
1069                        if (!result) {
1070                                dbi_conn_error(dbi->conn, &msglog);
1071                                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1072                                       __func__, __LINE__, msglog);
1073                                return false;
1074                        }
1075                        dbi_result_free(result);
1076                }
1077        } else { // Existe un perfil con todos esos componentes
1078                nwidperfilhard = dbi_result_get_uint(result, "idperfilhard");
1079                dbi_result_free(result);
1080        }
1081        if (idperfilhardware != nwidperfilhard) { // No coinciden los perfiles
1082                // Actualiza el identificador del perfil hardware del ordenador
1083                result = dbi_conn_queryf(dbi->conn,
1084                        "UPDATE ordenadores SET idperfilhard=%d"
1085                        " WHERE idordenador=%s", nwidperfilhard, ido);
1086                if (!result) {
1087                        dbi_conn_error(dbi->conn, &msglog);
1088                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1089                               __func__, __LINE__, msglog);
1090                        return false;
1091                }
1092                dbi_result_free(result);
1093        }
1094        /* Eliminar Relación de hardwares con Perfiles hardware que quedan húerfanos */
1095        result = dbi_conn_queryf(dbi->conn,
1096                "DELETE FROM perfileshard_hardwares WHERE idperfilhard IN "
1097                " (SELECT idperfilhard FROM perfileshard WHERE idperfilhard NOT IN"
1098                " (SELECT DISTINCT idperfilhard from ordenadores))");
1099        if (!result) {
1100                dbi_conn_error(dbi->conn, &msglog);
1101                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1102                       __func__, __LINE__, msglog);
1103                return false;
1104        }
1105        dbi_result_free(result);
1106
1107        /* Eliminar Perfiles hardware que quedan húerfanos */
1108        result = dbi_conn_queryf(dbi->conn,
1109                        "DELETE FROM perfileshard WHERE idperfilhard NOT IN"
1110                        " (SELECT DISTINCT idperfilhard FROM ordenadores)");
1111        if (!result) {
1112                dbi_conn_error(dbi->conn, &msglog);
1113                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1114                       __func__, __LINE__, msglog);
1115                return false;
1116        }
1117        dbi_result_free(result);
1118
1119        /* Eliminar Relación de hardwares con Perfiles hardware que quedan húerfanos */
1120        result = dbi_conn_queryf(dbi->conn,
1121                        "DELETE FROM perfileshard_hardwares WHERE idperfilhard NOT IN"
1122                        " (SELECT idperfilhard FROM perfileshard)");
1123        if (!result) {
1124                dbi_conn_error(dbi->conn, &msglog);
1125                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1126                       __func__, __LINE__, msglog);
1127                return false;
1128        }
1129        dbi_result_free(result);
1130
1131        return true;
1132}
1133// ________________________________________________________________________________________________________
1134// Función: actualizaSoftware
1135//
1136//      Descripción:
1137//              Actualiza la base de datos con la configuración software del cliente
1138//      Parámetros:
1139//              - db: Objeto base de datos (ya operativo)
1140//              - tbl: Objeto tabla
1141//              - sft: cadena con el inventario software
1142//              - par: Número de la partición
1143//              - ido: Identificador del ordenador del cliente en la tabla
1144//              - npc: Nombre del ordenador
1145//              - idc: Identificador del centro o Unidad organizativa
1146//      Devuelve:
1147//              true: Si el proceso es correcto
1148//              false: En caso de ocurrir algún error
1149//
1150//      Versión 1.1.0: Se incluye el sistema operativo. Autora: Irina Gómez - ETSII Universidad Sevilla
1151// ________________________________________________________________________________________________________
1152bool actualizaSoftware(struct og_dbi *dbi, char *sft, char *par,char *ido,
1153                       char *npc, char *idc)
1154{
1155        int i, j, lon, aux, idperfilsoft, idnombreso;
1156        bool retval;
1157        char *wsft;
1158        int tbidsoftware[MAXSOFTWARE];
1159        char *tbSoftware[MAXSOFTWARE], strInt[LONINT], *idsoftwares;
1160        const char *msglog;
1161        dbi_result result;
1162
1163        /* Toma Centro (Unidad Organizativa) y perfil software */
1164        result = dbi_conn_queryf(dbi->conn,
1165                "SELECT idperfilsoft,numpar"
1166                " FROM ordenadores_particiones"
1167                " WHERE idordenador=%s", ido);
1168        if (!result) {
1169                dbi_conn_error(dbi->conn, &msglog);
1170                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1171                       __func__, __LINE__, msglog);
1172                return false;
1173        }
1174        idperfilsoft = 0; // Por defecto se supone que el ordenador no tiene aún detectado el perfil software
1175        while (dbi_result_next_row(result)) {
1176                aux = dbi_result_get_uint(result, "numpar");
1177                if (aux == atoi(par)) { // Se encuentra la partición
1178                        idperfilsoft = dbi_result_get_uint(result, "idperfilsoft");
1179                        break;
1180                }
1181        }
1182        dbi_result_free(result);
1183        wsft=escaparCadena(sft); // Codificar comillas simples
1184        if(!wsft)
1185                return false;
1186
1187        /* Recorre componentes software*/
1188        lon = splitCadena(tbSoftware, wsft, '\n');
1189
1190        if (lon == 0)
1191                return true; // No hay lineas que procesar
1192        if (lon > MAXSOFTWARE)
1193                lon = MAXSOFTWARE; // Limita el número de componentes software
1194
1195        idnombreso = 0;
1196        for (i = 0; i < lon; i++) {
1197                // Primera línea es el sistema operativo: se obtiene identificador
1198                if (i == 0) {
1199                        idnombreso = checkDato(dbi, rTrim(tbSoftware[i]), "nombresos", "nombreso", "idnombreso");
1200                        continue;
1201                }
1202
1203                result = dbi_conn_queryf(dbi->conn,
1204                                "SELECT idsoftware FROM softwares WHERE descripcion ='%s'",
1205                                rTrim(tbSoftware[i]));
1206                if (!result) {
1207                        dbi_conn_error(dbi->conn, &msglog);
1208                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1209                               __func__, __LINE__, msglog);
1210                        return false;
1211                }
1212
1213                if (!dbi_result_next_row(result)) {
1214                        dbi_result_free(result);
1215                        result = dbi_conn_queryf(dbi->conn,
1216                                                "INSERT INTO softwares (idtiposoftware,descripcion,idcentro,grupoid)"
1217                                                " VALUES(2,'%s',%s,0)", tbSoftware[i], idc);
1218                        if (!result) { // Error al insertar
1219                                dbi_conn_error(dbi->conn, &msglog);
1220                                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1221                                       __func__, __LINE__, msglog);
1222                                return false;
1223                        }
1224
1225                        // Recupera el identificador del software
1226                        tbidsoftware[i] = dbi_conn_sequence_last(dbi->conn, NULL);
1227                } else {
1228                        tbidsoftware[i] = dbi_result_get_uint(result, "idsoftware");
1229                }
1230                dbi_result_free(result);
1231        }
1232
1233        // Ordena tabla de identificadores para cosultar si existe un pefil con esas especificaciones
1234
1235        for (i = 0; i < lon - 1; i++) {
1236                for (j = i + 1; j < lon; j++) {
1237                        if (tbidsoftware[i] > tbidsoftware[j]) {
1238                                aux = tbidsoftware[i];
1239                                tbidsoftware[i] = tbidsoftware[j];
1240                                tbidsoftware[j] = aux;
1241                        }
1242                }
1243        }
1244        /* Crea cadena de identificadores de componentes software separados por coma */
1245        sprintf(strInt, "%d", tbidsoftware[lon - 1]); // Pasa a cadena el último identificador que es de mayor longitud
1246        aux = strlen(strInt); // Calcula longitud de cadena para reservar espacio a todos los perfiles
1247        idsoftwares = reservaMemoria((sizeof(aux)+1) * lon + lon);
1248        if (idsoftwares == NULL) {
1249                syslog(LOG_ERR, "%s:%d OOM\n", __FILE__, __LINE__);
1250                return false;
1251        }
1252        aux = sprintf(idsoftwares, "%d", tbidsoftware[0]);
1253        for (i = 1; i < lon; i++)
1254                aux += sprintf(idsoftwares + aux, ",%d", tbidsoftware[i]);
1255
1256        // Comprueba existencia de perfil software y actualización de éste para el ordenador
1257        if (!cuestionPerfilSoftware(dbi, idc, ido, idperfilsoft, idnombreso, idsoftwares,
1258                        npc, par, tbidsoftware, lon)) {
1259                syslog(LOG_ERR, "cannot update software\n");
1260                og_info((char *)msglog);
1261                retval=false;
1262        }
1263        else {
1264                retval=true;
1265        }
1266        liberaMemoria(wsft);
1267        liberaMemoria(idsoftwares);
1268        return (retval);
1269}
1270// ________________________________________________________________________________________________________
1271// Función: CuestionPerfilSoftware
1272//
1273//      Parámetros:
1274//              - db: Objeto base de datos (ya operativo)
1275//              - tbl: Objeto tabla
1276//              - idcentro: Identificador del centro en la tabla
1277//              - ido: Identificador del ordenador del cliente en la tabla
1278//              - idnombreso: Identificador del sistema operativo
1279//              - idsoftwares: Cadena con los identificadores de componentes software separados por comas
1280//              - npc: Nombre del ordenador del cliente
1281//              - particion: Número de la partición
1282//              - tbidsoftware: Array con los identificadores de componentes software
1283//              - lon: Número de componentes
1284//      Devuelve:
1285//              true: Si el proceso es correcto
1286//              false: En caso de ocurrir algún error
1287//
1288//      Versión 1.1.0: Se incluye el sistema operativo. Autora: Irina Gómez - ETSII Universidad Sevilla
1289//_________________________________________________________________________________________________________
1290bool cuestionPerfilSoftware(struct og_dbi *dbi, char *idc, char *ido,
1291                            int idperfilsoftware, int idnombreso,
1292                            char *idsoftwares, char *npc, char *par,
1293                            int *tbidsoftware, int lon)
1294{
1295        int i, nwidperfilsoft;
1296        const char *msglog;
1297        dbi_result result;
1298
1299        // Busca perfil soft del ordenador que contenga todos los componentes software encontrados
1300        result = dbi_conn_queryf(dbi->conn,
1301                "SELECT idperfilsoft FROM"
1302                " (SELECT perfilessoft_softwares.idperfilsoft as idperfilsoft,"
1303                "       group_concat(cast(perfilessoft_softwares.idsoftware AS char( 11) )"
1304                "       ORDER BY perfilessoft_softwares.idsoftware SEPARATOR ',' ) AS idsoftwares"
1305                " FROM  perfilessoft_softwares"
1306                " GROUP BY perfilessoft_softwares.idperfilsoft) AS temp"
1307                " WHERE idsoftwares LIKE '%s'", idsoftwares);
1308
1309        if (!result) {
1310                dbi_conn_error(dbi->conn, &msglog);
1311                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1312                       __func__, __LINE__, msglog);
1313                return false;
1314        }
1315        if (!dbi_result_next_row(result)) { // No existe un perfil software con esos componentes de componentes software, lo crea
1316                dbi_result_free(result);
1317                result = dbi_conn_queryf(dbi->conn,
1318                                "INSERT perfilessoft  (descripcion, idcentro, grupoid, idnombreso)"
1319                                " VALUES('Perfil Software (%s, Part:%s) ',%s,0,%i)", npc, par, idc,idnombreso);
1320                if (!result) {
1321                        dbi_conn_error(dbi->conn, &msglog);
1322                        og_info((char *)msglog);
1323                        return false;
1324                }
1325
1326                dbi_result_free(result);
1327                // Recupera el identificador del nuevo perfil software
1328                nwidperfilsoft = dbi_conn_sequence_last(dbi->conn, NULL);
1329
1330                // Crea la relación entre perfiles y componenetes software
1331                for (i = 0; i < lon; i++) {
1332                        result = dbi_conn_queryf(dbi->conn,
1333                                                "INSERT perfilessoft_softwares (idperfilsoft,idsoftware)"
1334                                                " VALUES(%d,%d)", nwidperfilsoft, tbidsoftware[i]);
1335                        if (!result) {
1336                                dbi_conn_error(dbi->conn, &msglog);
1337                                og_info((char *)msglog);
1338                                return false;
1339                        }
1340                        dbi_result_free(result);
1341                }
1342        } else { // Existe un perfil con todos esos componentes
1343                nwidperfilsoft = dbi_result_get_uint(result, "idperfilsoft");
1344                dbi_result_free(result);
1345        }
1346
1347        if (idperfilsoftware != nwidperfilsoft) { // No coinciden los perfiles
1348                // Actualiza el identificador del perfil software del ordenador
1349                result = dbi_conn_queryf(dbi->conn,
1350                                "UPDATE ordenadores_particiones SET idperfilsoft=%d,idimagen=0"
1351                                " WHERE idordenador=%s AND numpar=%s", nwidperfilsoft, ido, par);
1352                if (!result) { // Error al insertar
1353                        dbi_conn_error(dbi->conn, &msglog);
1354                        og_info((char *)msglog);
1355                        return false;
1356                }
1357                dbi_result_free(result);
1358        }
1359
1360        /* DEPURACIÓN DE PERFILES SOFTWARE */
1361
1362         /* Eliminar Relación de softwares con Perfiles software que quedan húerfanos */
1363        result = dbi_conn_queryf(dbi->conn,
1364                "DELETE FROM perfilessoft_softwares WHERE idperfilsoft IN "\
1365                " (SELECT idperfilsoft FROM perfilessoft WHERE idperfilsoft NOT IN"\
1366                " (SELECT DISTINCT idperfilsoft from ordenadores_particiones) AND idperfilsoft NOT IN"\
1367                " (SELECT DISTINCT idperfilsoft from imagenes))");
1368        if (!result) {
1369                dbi_conn_error(dbi->conn, &msglog);
1370                og_info((char *)msglog);
1371                return false;
1372        }
1373        dbi_result_free(result),
1374        /* Eliminar Perfiles software que quedan húerfanos */
1375        result = dbi_conn_queryf(dbi->conn,
1376                "DELETE FROM perfilessoft WHERE idperfilsoft NOT IN"
1377                " (SELECT DISTINCT idperfilsoft from ordenadores_particiones)"\
1378                " AND  idperfilsoft NOT IN"\
1379                " (SELECT DISTINCT idperfilsoft from imagenes)");
1380        if (!result) {
1381                dbi_conn_error(dbi->conn, &msglog);
1382                og_info((char *)msglog);
1383                return false;
1384        }
1385        dbi_result_free(result),
1386
1387        /* Eliminar Relación de softwares con Perfiles software que quedan húerfanos */
1388        result = dbi_conn_queryf(dbi->conn,
1389                        "DELETE FROM perfilessoft_softwares WHERE idperfilsoft NOT IN"
1390                        " (SELECT idperfilsoft from perfilessoft)");
1391        if (!result) {
1392                dbi_conn_error(dbi->conn, &msglog);
1393                og_info((char *)msglog);
1394                return false;
1395        }
1396        dbi_result_free(result);
1397
1398        return true;
1399}
1400
1401static void og_client_release(struct ev_loop *loop, struct og_client *cli)
1402{
1403        if (cli->keepalive_idx >= 0) {
1404                syslog(LOG_DEBUG, "closing keepalive connection for %s:%hu in slot %d\n",
1405                       inet_ntoa(cli->addr.sin_addr),
1406                       ntohs(cli->addr.sin_port), cli->keepalive_idx);
1407                tbsockets[cli->keepalive_idx].cli = NULL;
1408        }
1409
1410        list_del(&cli->list);
1411        ev_io_stop(loop, &cli->io);
1412        close(cli->io.fd);
1413        free(cli);
1414}
1415
1416static void og_client_keepalive(struct ev_loop *loop, struct og_client *cli)
1417{
1418        struct og_client *old_cli;
1419
1420        old_cli = tbsockets[cli->keepalive_idx].cli;
1421        if (old_cli && old_cli != cli) {
1422                syslog(LOG_DEBUG, "closing old keepalive connection for %s:%hu\n",
1423                       inet_ntoa(old_cli->addr.sin_addr),
1424                       ntohs(old_cli->addr.sin_port));
1425
1426                og_client_release(loop, old_cli);
1427        }
1428        tbsockets[cli->keepalive_idx].cli = cli;
1429}
1430
1431static void og_client_reset_state(struct og_client *cli)
1432{
1433        cli->state = OG_CLIENT_RECEIVING_HEADER;
1434        cli->buf_len = 0;
1435}
1436
1437static TRAMA *og_msg_alloc(char *data, unsigned int len)
1438{
1439        TRAMA *ptrTrama;
1440
1441        ptrTrama = (TRAMA *)reservaMemoria(sizeof(TRAMA));
1442        if (!ptrTrama) {
1443                syslog(LOG_ERR, "OOM\n");
1444                return NULL;
1445        }
1446
1447        initParametros(ptrTrama, len);
1448        memcpy(ptrTrama, "@JMMLCAMDJ_MCDJ", LONGITUD_CABECERATRAMA);
1449        memcpy(ptrTrama->parametros, data, len);
1450        ptrTrama->lonprm = len;
1451
1452        return ptrTrama;
1453}
1454
1455static void og_msg_free(TRAMA *ptrTrama)
1456{
1457        liberaMemoria(ptrTrama->parametros);
1458        liberaMemoria(ptrTrama);
1459}
1460
1461#define OG_CLIENTS_MAX  4096
1462#define OG_PARTITION_MAX 4
1463
1464struct og_partition {
1465        const char      *disk;
1466        const char      *number;
1467        const char      *code;
1468        const char      *size;
1469        const char      *filesystem;
1470        const char      *format;
1471        const char      *os;
1472        const char      *used_size;
1473};
1474
1475struct og_sync_params {
1476        const char      *sync;
1477        const char      *diff;
1478        const char      *remove;
1479        const char      *compress;
1480        const char      *cleanup;
1481        const char      *cache;
1482        const char      *cleanup_cache;
1483        const char      *remove_dst;
1484        const char      *diff_id;
1485        const char      *diff_name;
1486        const char      *path;
1487        const char      *method;
1488};
1489
1490struct og_msg_params {
1491        const char      *ips_array[OG_CLIENTS_MAX];
1492        const char      *mac_array[OG_CLIENTS_MAX];
1493        unsigned int    ips_array_len;
1494        const char      *wol_type;
1495        char            run_cmd[4096];
1496        const char      *disk;
1497        const char      *partition;
1498        const char      *repository;
1499        const char      *name;
1500        const char      *id;
1501        const char      *code;
1502        const char      *type;
1503        const char      *profile;
1504        const char      *cache;
1505        const char      *cache_size;
1506        bool            echo;
1507        struct og_partition     partition_setup[OG_PARTITION_MAX];
1508        struct og_sync_params sync_setup;
1509        struct og_schedule_time time;
1510        const char      *task_id;
1511        uint64_t        flags;
1512};
1513
1514#define OG_COMPUTER_NAME_MAXLEN 100
1515
1516struct og_computer {
1517        unsigned int    id;
1518        unsigned int    center;
1519        unsigned int    room;
1520        char            name[OG_COMPUTER_NAME_MAXLEN + 1];
1521};
1522
1523#define OG_REST_PARAM_ADDR                      (1UL << 0)
1524#define OG_REST_PARAM_MAC                       (1UL << 1)
1525#define OG_REST_PARAM_WOL_TYPE                  (1UL << 2)
1526#define OG_REST_PARAM_RUN_CMD                   (1UL << 3)
1527#define OG_REST_PARAM_DISK                      (1UL << 4)
1528#define OG_REST_PARAM_PARTITION                 (1UL << 5)
1529#define OG_REST_PARAM_REPO                      (1UL << 6)
1530#define OG_REST_PARAM_NAME                      (1UL << 7)
1531#define OG_REST_PARAM_ID                        (1UL << 8)
1532#define OG_REST_PARAM_CODE                      (1UL << 9)
1533#define OG_REST_PARAM_TYPE                      (1UL << 10)
1534#define OG_REST_PARAM_PROFILE                   (1UL << 11)
1535#define OG_REST_PARAM_CACHE                     (1UL << 12)
1536#define OG_REST_PARAM_CACHE_SIZE                (1UL << 13)
1537#define OG_REST_PARAM_PART_0                    (1UL << 14)
1538#define OG_REST_PARAM_PART_1                    (1UL << 15)
1539#define OG_REST_PARAM_PART_2                    (1UL << 16)
1540#define OG_REST_PARAM_PART_3                    (1UL << 17)
1541#define OG_REST_PARAM_SYNC_SYNC                 (1UL << 18)
1542#define OG_REST_PARAM_SYNC_DIFF                 (1UL << 19)
1543#define OG_REST_PARAM_SYNC_REMOVE               (1UL << 20)
1544#define OG_REST_PARAM_SYNC_COMPRESS             (1UL << 21)
1545#define OG_REST_PARAM_SYNC_CLEANUP              (1UL << 22)
1546#define OG_REST_PARAM_SYNC_CACHE                (1UL << 23)
1547#define OG_REST_PARAM_SYNC_CLEANUP_CACHE        (1UL << 24)
1548#define OG_REST_PARAM_SYNC_REMOVE_DST           (1UL << 25)
1549#define OG_REST_PARAM_SYNC_DIFF_ID              (1UL << 26)
1550#define OG_REST_PARAM_SYNC_DIFF_NAME            (1UL << 27)
1551#define OG_REST_PARAM_SYNC_PATH                 (1UL << 28)
1552#define OG_REST_PARAM_SYNC_METHOD               (1UL << 29)
1553#define OG_REST_PARAM_ECHO                      (1UL << 30)
1554#define OG_REST_PARAM_TASK                      (1UL << 31)
1555#define OG_REST_PARAM_TIME_YEARS                (1UL << 32)
1556#define OG_REST_PARAM_TIME_MONTHS               (1UL << 33)
1557#define OG_REST_PARAM_TIME_WEEKS                (1UL << 34)
1558#define OG_REST_PARAM_TIME_WEEK_DAYS            (1UL << 35)
1559#define OG_REST_PARAM_TIME_DAYS                 (1UL << 36)
1560#define OG_REST_PARAM_TIME_HOURS                (1UL << 37)
1561#define OG_REST_PARAM_TIME_AM_PM                (1UL << 38)
1562#define OG_REST_PARAM_TIME_MINUTES              (1UL << 39)
1563
1564enum og_rest_method {
1565        OG_METHOD_GET   = 0,
1566        OG_METHOD_POST,
1567        OG_METHOD_NO_HTTP
1568};
1569
1570static struct og_client *og_client_find(const char *ip)
1571{
1572        struct og_client *client;
1573        struct in_addr addr;
1574        int res;
1575
1576        res = inet_aton(ip, &addr);
1577        if (!res) {
1578                syslog(LOG_ERR, "Invalid IP string: %s\n", ip);
1579                return NULL;
1580        }
1581
1582        list_for_each_entry(client, &client_list, list) {
1583                if (client->addr.sin_addr.s_addr == addr.s_addr && client->agent) {
1584                        return client;
1585                }
1586        }
1587
1588        return NULL;
1589}
1590
1591static bool og_msg_params_validate(const struct og_msg_params *params,
1592                                   const uint64_t flags)
1593{
1594        return (params->flags & flags) == flags;
1595}
1596
1597static int og_json_parse_clients(json_t *element, struct og_msg_params *params)
1598{
1599        unsigned int i;
1600        json_t *k;
1601
1602        if (json_typeof(element) != JSON_ARRAY)
1603                return -1;
1604
1605        for (i = 0; i < json_array_size(element); i++) {
1606                k = json_array_get(element, i);
1607                if (json_typeof(k) != JSON_STRING)
1608                        return -1;
1609
1610                params->ips_array[params->ips_array_len++] =
1611                        json_string_value(k);
1612
1613                params->flags |= OG_REST_PARAM_ADDR;
1614        }
1615
1616        return 0;
1617}
1618
1619static int og_json_parse_string(json_t *element, const char **str)
1620{
1621        if (json_typeof(element) != JSON_STRING)
1622                return -1;
1623
1624        *str = json_string_value(element);
1625        return 0;
1626}
1627
1628static int og_json_parse_uint(json_t *element, uint32_t *integer)
1629{
1630        if (json_typeof(element) != JSON_INTEGER)
1631                return -1;
1632
1633        *integer = json_integer_value(element);
1634        return 0;
1635}
1636
1637static int og_json_parse_bool(json_t *element, bool *value)
1638{
1639        if (json_typeof(element) == JSON_TRUE)
1640                *value = true;
1641        else if (json_typeof(element) == JSON_FALSE)
1642                *value = false;
1643        else
1644                return -1;
1645
1646        return 0;
1647}
1648
1649static int og_json_parse_sync_params(json_t *element,
1650                                     struct og_msg_params *params)
1651{
1652        const char *key;
1653        json_t *value;
1654        int err = 0;
1655
1656        json_object_foreach(element, key, value) {
1657                if (!strcmp(key, "sync")) {
1658                        err = og_json_parse_string(value, &params->sync_setup.sync);
1659                        params->flags |= OG_REST_PARAM_SYNC_SYNC;
1660                } else if (!strcmp(key, "diff")) {
1661                        err = og_json_parse_string(value, &params->sync_setup.diff);
1662                        params->flags |= OG_REST_PARAM_SYNC_DIFF;
1663                } else if (!strcmp(key, "remove")) {
1664                        err = og_json_parse_string(value, &params->sync_setup.remove);
1665                        params->flags |= OG_REST_PARAM_SYNC_REMOVE;
1666                } else if (!strcmp(key, "compress")) {
1667                        err = og_json_parse_string(value, &params->sync_setup.compress);
1668                        params->flags |= OG_REST_PARAM_SYNC_COMPRESS;
1669                } else if (!strcmp(key, "cleanup")) {
1670                        err = og_json_parse_string(value, &params->sync_setup.cleanup);
1671                        params->flags |= OG_REST_PARAM_SYNC_CLEANUP;
1672                } else if (!strcmp(key, "cache")) {
1673                        err = og_json_parse_string(value, &params->sync_setup.cache);
1674                        params->flags |= OG_REST_PARAM_SYNC_CACHE;
1675                } else if (!strcmp(key, "cleanup_cache")) {
1676                        err = og_json_parse_string(value, &params->sync_setup.cleanup_cache);
1677                        params->flags |= OG_REST_PARAM_SYNC_CLEANUP_CACHE;
1678                } else if (!strcmp(key, "remove_dst")) {
1679                        err = og_json_parse_string(value, &params->sync_setup.remove_dst);
1680                        params->flags |= OG_REST_PARAM_SYNC_REMOVE_DST;
1681                } else if (!strcmp(key, "diff_id")) {
1682                        err = og_json_parse_string(value, &params->sync_setup.diff_id);
1683                        params->flags |= OG_REST_PARAM_SYNC_DIFF_ID;
1684                } else if (!strcmp(key, "diff_name")) {
1685                        err = og_json_parse_string(value, &params->sync_setup.diff_name);
1686                        params->flags |= OG_REST_PARAM_SYNC_DIFF_NAME;
1687                } else if (!strcmp(key, "path")) {
1688                        err = og_json_parse_string(value, &params->sync_setup.path);
1689                        params->flags |= OG_REST_PARAM_SYNC_PATH;
1690                } else if (!strcmp(key, "method")) {
1691                        err = og_json_parse_string(value, &params->sync_setup.method);
1692                        params->flags |= OG_REST_PARAM_SYNC_METHOD;
1693                }
1694
1695                if (err != 0)
1696                        return err;
1697        }
1698        return err;
1699}
1700
1701#define OG_PARAM_PART_NUMBER                    (1UL << 0)
1702#define OG_PARAM_PART_CODE                      (1UL << 1)
1703#define OG_PARAM_PART_FILESYSTEM                (1UL << 2)
1704#define OG_PARAM_PART_SIZE                      (1UL << 3)
1705#define OG_PARAM_PART_FORMAT                    (1UL << 4)
1706#define OG_PARAM_PART_DISK                      (1UL << 5)
1707#define OG_PARAM_PART_OS                        (1UL << 6)
1708#define OG_PARAM_PART_USED_SIZE                 (1UL << 7)
1709
1710static int og_json_parse_partition(json_t *element,
1711                                   struct og_partition *part,
1712                                   uint64_t required_flags)
1713{
1714        uint64_t flags = 0UL;
1715        const char *key;
1716        json_t *value;
1717        int err = 0;
1718
1719        json_object_foreach(element, key, value) {
1720                if (!strcmp(key, "partition")) {
1721                        err = og_json_parse_string(value, &part->number);
1722                        flags |= OG_PARAM_PART_NUMBER;
1723                } else if (!strcmp(key, "code")) {
1724                        err = og_json_parse_string(value, &part->code);
1725                        flags |= OG_PARAM_PART_CODE;
1726                } else if (!strcmp(key, "filesystem")) {
1727                        err = og_json_parse_string(value, &part->filesystem);
1728                        flags |= OG_PARAM_PART_FILESYSTEM;
1729                } else if (!strcmp(key, "size")) {
1730                        err = og_json_parse_string(value, &part->size);
1731                        flags |= OG_PARAM_PART_SIZE;
1732                } else if (!strcmp(key, "format")) {
1733                        err = og_json_parse_string(value, &part->format);
1734                        flags |= OG_PARAM_PART_FORMAT;
1735                } else if (!strcmp(key, "disk")) {
1736                        err = og_json_parse_string(value, &part->disk);
1737                        flags |= OG_PARAM_PART_DISK;
1738                } else if (!strcmp(key, "os")) {
1739                        err = og_json_parse_string(value, &part->os);
1740                        flags |= OG_PARAM_PART_OS;
1741                } else if (!strcmp(key, "used_size")) {
1742                        err = og_json_parse_string(value, &part->used_size);
1743                        flags |= OG_PARAM_PART_USED_SIZE;
1744                }
1745
1746                if (err < 0)
1747                        return err;
1748        }
1749
1750        if (flags != required_flags)
1751                return -1;
1752
1753        return err;
1754}
1755
1756static int og_json_parse_partition_setup(json_t *element,
1757                                         struct og_msg_params *params)
1758{
1759        unsigned int i;
1760        json_t *k;
1761
1762        if (json_typeof(element) != JSON_ARRAY)
1763                return -1;
1764
1765        for (i = 0; i < json_array_size(element) && i < OG_PARTITION_MAX; ++i) {
1766                k = json_array_get(element, i);
1767
1768                if (json_typeof(k) != JSON_OBJECT)
1769                        return -1;
1770
1771                if (og_json_parse_partition(k, &params->partition_setup[i],
1772                                            OG_PARAM_PART_NUMBER |
1773                                            OG_PARAM_PART_CODE |
1774                                            OG_PARAM_PART_FILESYSTEM |
1775                                            OG_PARAM_PART_SIZE |
1776                                            OG_PARAM_PART_FORMAT) < 0)
1777                        return -1;
1778
1779                params->flags |= (OG_REST_PARAM_PART_0 << i);
1780        }
1781        return 0;
1782}
1783
1784static int og_json_parse_time_params(json_t *element,
1785                                     struct og_msg_params *params)
1786{
1787        const char *key;
1788        json_t *value;
1789        int err = 0;
1790
1791        json_object_foreach(element, key, value) {
1792                if (!strcmp(key, "years")) {
1793                        err = og_json_parse_uint(value, &params->time.years);
1794                        params->flags |= OG_REST_PARAM_TIME_YEARS;
1795                } else if (!strcmp(key, "months")) {
1796                        err = og_json_parse_uint(value, &params->time.months);
1797                        params->flags |= OG_REST_PARAM_TIME_MONTHS;
1798                } else if (!strcmp(key, "weeks")) {
1799                        err = og_json_parse_uint(value, &params->time.weeks);
1800                        params->flags |= OG_REST_PARAM_TIME_WEEKS;
1801                } else if (!strcmp(key, "week_days")) {
1802                        err = og_json_parse_uint(value, &params->time.week_days);
1803                        params->flags |= OG_REST_PARAM_TIME_WEEK_DAYS;
1804                } else if (!strcmp(key, "days")) {
1805                        err = og_json_parse_uint(value, &params->time.days);
1806                        params->flags |= OG_REST_PARAM_TIME_DAYS;
1807                } else if (!strcmp(key, "hours")) {
1808                        err = og_json_parse_uint(value, &params->time.hours);
1809                        params->flags |= OG_REST_PARAM_TIME_HOURS;
1810                } else if (!strcmp(key, "am_pm")) {
1811                        err = og_json_parse_uint(value, &params->time.am_pm);
1812                        params->flags |= OG_REST_PARAM_TIME_AM_PM;
1813                } else if (!strcmp(key, "minutes")) {
1814                        err = og_json_parse_uint(value, &params->time.minutes);
1815                        params->flags |= OG_REST_PARAM_TIME_MINUTES;
1816                }
1817                if (err != 0)
1818                        return err;
1819        }
1820
1821        return err;
1822}
1823
1824static const char *og_cmd_to_uri[OG_CMD_MAX] = {
1825        [OG_CMD_WOL]            = "wol",
1826        [OG_CMD_PROBE]          = "probe",
1827        [OG_CMD_SHELL_RUN]      = "shell/run",
1828        [OG_CMD_SESSION]        = "session",
1829        [OG_CMD_POWEROFF]       = "poweroff",
1830        [OG_CMD_REFRESH]        = "refresh",
1831        [OG_CMD_REBOOT]         = "reboot",
1832        [OG_CMD_STOP]           = "stop",
1833        [OG_CMD_HARDWARE]       = "hardware",
1834        [OG_CMD_SOFTWARE]       = "software",
1835        [OG_CMD_IMAGE_CREATE]   = "image/create",
1836        [OG_CMD_IMAGE_RESTORE]  = "image/restore",
1837        [OG_CMD_SETUP]          = "setup",
1838        [OG_CMD_RUN_SCHEDULE]   = "run/schedule",
1839};
1840
1841static bool og_client_is_busy(const struct og_client *cli,
1842                              enum og_cmd_type type)
1843{
1844        switch (type) {
1845        case OG_CMD_REBOOT:
1846        case OG_CMD_POWEROFF:
1847        case OG_CMD_STOP:
1848                break;
1849        default:
1850                if (cli->last_cmd != OG_CMD_UNSPEC)
1851                        return true;
1852                break;
1853        }
1854
1855        return false;
1856}
1857
1858static int og_send_request(enum og_rest_method method, enum og_cmd_type type,
1859                           const struct og_msg_params *params,
1860                           const json_t *data)
1861{
1862        const char *content_type = "Content-Type: application/json";
1863        char content [OG_MSG_REQUEST_MAXLEN - 700] = {};
1864        char buf[OG_MSG_REQUEST_MAXLEN] = {};
1865        unsigned int content_length;
1866        char method_str[5] = {};
1867        struct og_client *cli;
1868        const char *uri;
1869        unsigned int i;
1870        int client_sd;
1871
1872        if (method == OG_METHOD_GET)
1873                snprintf(method_str, 5, "GET");
1874        else if (method == OG_METHOD_POST)
1875                snprintf(method_str, 5, "POST");
1876        else
1877                return -1;
1878
1879        if (!data)
1880                content_length = 0;
1881        else
1882                content_length = json_dumpb(data, content,
1883                                            OG_MSG_REQUEST_MAXLEN - 700,
1884                                            JSON_COMPACT);
1885
1886        uri = og_cmd_to_uri[type];
1887        snprintf(buf, OG_MSG_REQUEST_MAXLEN,
1888                 "%s /%s HTTP/1.1\r\nContent-Length: %d\r\n%s\r\n\r\n%s",
1889                 method_str, uri, content_length, content_type, content);
1890
1891        for (i = 0; i < params->ips_array_len; i++) {
1892                cli = og_client_find(params->ips_array[i]);
1893                if (!cli)
1894                        continue;
1895
1896                if (og_client_is_busy(cli, type))
1897                        continue;
1898
1899                client_sd = cli->io.fd;
1900                if (client_sd < 0) {
1901                        syslog(LOG_INFO, "Client %s not conected\n",
1902                               params->ips_array[i]);
1903                        continue;
1904                }
1905
1906                if (send(client_sd, buf, strlen(buf), 0) < 0)
1907                        continue;
1908
1909                cli->last_cmd = type;
1910        }
1911
1912        return 0;
1913}
1914
1915static int og_cmd_post_clients(json_t *element, struct og_msg_params *params)
1916{
1917        const char *key;
1918        json_t *value;
1919        int err = 0;
1920
1921        if (json_typeof(element) != JSON_OBJECT)
1922                return -1;
1923
1924        json_object_foreach(element, key, value) {
1925                if (!strcmp(key, "clients"))
1926                        err = og_json_parse_clients(value, params);
1927
1928                if (err < 0)
1929                        break;
1930        }
1931
1932        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
1933                return -1;
1934
1935        return og_send_request(OG_METHOD_POST, OG_CMD_PROBE, params, NULL);
1936}
1937
1938struct og_buffer {
1939        char    *data;
1940        int     len;
1941};
1942
1943static int og_json_dump_clients(const char *buffer, size_t size, void *data)
1944{
1945        struct og_buffer *og_buffer = (struct og_buffer *)data;
1946
1947        memcpy(og_buffer->data + og_buffer->len, buffer, size);
1948        og_buffer->len += size;
1949
1950        return 0;
1951}
1952
1953static int og_cmd_get_clients(json_t *element, struct og_msg_params *params,
1954                              char *buffer_reply)
1955{
1956        json_t *root, *array, *addr, *state, *object;
1957        struct og_client *client;
1958        struct og_buffer og_buffer = {
1959                .data   = buffer_reply,
1960        };
1961
1962        array = json_array();
1963        if (!array)
1964                return -1;
1965
1966        list_for_each_entry(client, &client_list, list) {
1967                if (!client->agent)
1968                        continue;
1969
1970                object = json_object();
1971                if (!object) {
1972                        json_decref(array);
1973                        return -1;
1974                }
1975                addr = json_string(inet_ntoa(client->addr.sin_addr));
1976                if (!addr) {
1977                        json_decref(object);
1978                        json_decref(array);
1979                        return -1;
1980                }
1981                json_object_set_new(object, "addr", addr);
1982                state = json_string(og_client_status(client));
1983                if (!state) {
1984                        json_decref(object);
1985                        json_decref(array);
1986                        return -1;
1987                }
1988                json_object_set_new(object, "state", state);
1989                json_array_append_new(array, object);
1990        }
1991        root = json_pack("{s:o}", "clients", array);
1992        if (!root) {
1993                json_decref(array);
1994                return -1;
1995        }
1996
1997        json_dump_callback(root, og_json_dump_clients, &og_buffer, 0);
1998        json_decref(root);
1999
2000        return 0;
2001}
2002
2003static int og_json_parse_target(json_t *element, struct og_msg_params *params)
2004{
2005        const char *key;
2006        json_t *value;
2007
2008        if (json_typeof(element) != JSON_OBJECT) {
2009                return -1;
2010        }
2011
2012        json_object_foreach(element, key, value) {
2013                if (!strcmp(key, "addr")) {
2014                        if (json_typeof(value) != JSON_STRING)
2015                                return -1;
2016
2017                        params->ips_array[params->ips_array_len] =
2018                                json_string_value(value);
2019
2020                        params->flags |= OG_REST_PARAM_ADDR;
2021                } else if (!strcmp(key, "mac")) {
2022                        if (json_typeof(value) != JSON_STRING)
2023                                return -1;
2024
2025                        params->mac_array[params->ips_array_len] =
2026                                json_string_value(value);
2027
2028                        params->flags |= OG_REST_PARAM_MAC;
2029                }
2030        }
2031
2032        return 0;
2033}
2034
2035static int og_json_parse_targets(json_t *element, struct og_msg_params *params)
2036{
2037        unsigned int i;
2038        json_t *k;
2039        int err;
2040
2041        if (json_typeof(element) != JSON_ARRAY)
2042                return -1;
2043
2044        for (i = 0; i < json_array_size(element); i++) {
2045                k = json_array_get(element, i);
2046
2047                if (json_typeof(k) != JSON_OBJECT)
2048                        return -1;
2049
2050                err = og_json_parse_target(k, params);
2051                if (err < 0)
2052                        return err;
2053
2054                params->ips_array_len++;
2055        }
2056        return 0;
2057}
2058
2059static int og_json_parse_type(json_t *element, struct og_msg_params *params)
2060{
2061        const char *type;
2062
2063        if (json_typeof(element) != JSON_STRING)
2064                return -1;
2065
2066        params->wol_type = json_string_value(element);
2067
2068        type = json_string_value(element);
2069        if (!strcmp(type, "unicast"))
2070                params->wol_type = "2";
2071        else if (!strcmp(type, "broadcast"))
2072                params->wol_type = "1";
2073
2074        params->flags |= OG_REST_PARAM_WOL_TYPE;
2075
2076        return 0;
2077}
2078
2079static int og_cmd_wol(json_t *element, struct og_msg_params *params)
2080{
2081        const char *key;
2082        json_t *value;
2083        int err = 0;
2084
2085        if (json_typeof(element) != JSON_OBJECT)
2086                return -1;
2087
2088        json_object_foreach(element, key, value) {
2089                if (!strcmp(key, "clients")) {
2090                        err = og_json_parse_targets(value, params);
2091                } else if (!strcmp(key, "type")) {
2092                        err = og_json_parse_type(value, params);
2093                }
2094
2095                if (err < 0)
2096                        break;
2097        }
2098
2099        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
2100                                            OG_REST_PARAM_MAC |
2101                                            OG_REST_PARAM_WOL_TYPE))
2102                return -1;
2103
2104        if (!Levanta((char **)params->ips_array, (char **)params->mac_array,
2105                     params->ips_array_len, (char *)params->wol_type))
2106                return -1;
2107
2108        return 0;
2109}
2110
2111static int og_json_parse_run(json_t *element, struct og_msg_params *params)
2112{
2113        if (json_typeof(element) != JSON_STRING)
2114                return -1;
2115
2116        snprintf(params->run_cmd, sizeof(params->run_cmd), "%s",
2117                 json_string_value(element));
2118
2119        params->flags |= OG_REST_PARAM_RUN_CMD;
2120
2121        return 0;
2122}
2123
2124static int og_cmd_run_post(json_t *element, struct og_msg_params *params)
2125{
2126        json_t *value, *clients;
2127        const char *key;
2128        unsigned int i;
2129        int err = 0;
2130
2131        if (json_typeof(element) != JSON_OBJECT)
2132                return -1;
2133
2134        json_object_foreach(element, key, value) {
2135                if (!strcmp(key, "clients"))
2136                        err = og_json_parse_clients(value, params);
2137                else if (!strcmp(key, "run"))
2138                        err = og_json_parse_run(value, params);
2139                else if (!strcmp(key, "echo")) {
2140                        err = og_json_parse_bool(value, &params->echo);
2141                        params->flags |= OG_REST_PARAM_ECHO;
2142                }
2143
2144                if (err < 0)
2145                        break;
2146        }
2147
2148        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
2149                                            OG_REST_PARAM_RUN_CMD |
2150                                            OG_REST_PARAM_ECHO))
2151                return -1;
2152
2153        clients = json_copy(element);
2154        json_object_del(clients, "clients");
2155
2156        err = og_send_request(OG_METHOD_POST, OG_CMD_SHELL_RUN, params, clients);
2157        if (err < 0)
2158                return err;
2159
2160        for (i = 0; i < params->ips_array_len; i++) {
2161                char filename[4096];
2162                FILE *f;
2163
2164                sprintf(filename, "/tmp/_Seconsola_%s", params->ips_array[i]);
2165                f = fopen(filename, "wt");
2166                fclose(f);
2167        }
2168
2169        return 0;
2170}
2171
2172static int og_cmd_run_get(json_t *element, struct og_msg_params *params,
2173                          char *buffer_reply)
2174{
2175        struct og_buffer og_buffer = {
2176                .data   = buffer_reply,
2177        };
2178        json_t *root, *value, *array;
2179        const char *key;
2180        unsigned int i;
2181        int err = 0;
2182
2183        if (json_typeof(element) != JSON_OBJECT)
2184                return -1;
2185
2186        json_object_foreach(element, key, value) {
2187                if (!strcmp(key, "clients"))
2188                        err = og_json_parse_clients(value, params);
2189
2190                if (err < 0)
2191                        return err;
2192        }
2193
2194        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
2195                return -1;
2196
2197        array = json_array();
2198        if (!array)
2199                return -1;
2200
2201        for (i = 0; i < params->ips_array_len; i++) {
2202                json_t *object, *output, *addr;
2203                char data[4096] = {};
2204                char filename[4096];
2205                int fd, numbytes;
2206
2207                sprintf(filename, "/tmp/_Seconsola_%s", params->ips_array[i]);
2208
2209                fd = open(filename, O_RDONLY);
2210                if (!fd)
2211                        return -1;
2212
2213                numbytes = read(fd, data, sizeof(data));
2214                if (numbytes < 0) {
2215                        close(fd);
2216                        return -1;
2217                }
2218                data[sizeof(data) - 1] = '\0';
2219                close(fd);
2220
2221                object = json_object();
2222                if (!object) {
2223                        json_decref(array);
2224                        return -1;
2225                }
2226                addr = json_string(params->ips_array[i]);
2227                if (!addr) {
2228                        json_decref(object);
2229                        json_decref(array);
2230                        return -1;
2231                }
2232                json_object_set_new(object, "addr", addr);
2233
2234                output = json_string(data);
2235                if (!output) {
2236                        json_decref(object);
2237                        json_decref(array);
2238                        return -1;
2239                }
2240                json_object_set_new(object, "output", output);
2241
2242                json_array_append_new(array, object);
2243        }
2244
2245        root = json_pack("{s:o}", "clients", array);
2246        if (!root)
2247                return -1;
2248
2249        json_dump_callback(root, og_json_dump_clients, &og_buffer, 0);
2250        json_decref(root);
2251
2252        return 0;
2253}
2254
2255static int og_cmd_session(json_t *element, struct og_msg_params *params)
2256{
2257        json_t *clients, *value;
2258        const char *key;
2259        int err = 0;
2260
2261        if (json_typeof(element) != JSON_OBJECT)
2262                return -1;
2263
2264        json_object_foreach(element, key, value) {
2265                if (!strcmp(key, "clients")) {
2266                        err = og_json_parse_clients(value, params);
2267                } else if (!strcmp(key, "disk")) {
2268                        err = og_json_parse_string(value, &params->disk);
2269                        params->flags |= OG_REST_PARAM_DISK;
2270                } else if (!strcmp(key, "partition")) {
2271                        err = og_json_parse_string(value, &params->partition);
2272                        params->flags |= OG_REST_PARAM_PARTITION;
2273                }
2274
2275                if (err < 0)
2276                        return err;
2277        }
2278
2279        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
2280                                            OG_REST_PARAM_DISK |
2281                                            OG_REST_PARAM_PARTITION))
2282                return -1;
2283
2284        clients = json_copy(element);
2285        json_object_del(clients, "clients");
2286
2287        return og_send_request(OG_METHOD_POST, OG_CMD_SESSION, params, clients);
2288}
2289
2290static int og_cmd_poweroff(json_t *element, struct og_msg_params *params)
2291{
2292        const char *key;
2293        json_t *value;
2294        int err = 0;
2295
2296        if (json_typeof(element) != JSON_OBJECT)
2297                return -1;
2298
2299        json_object_foreach(element, key, value) {
2300                if (!strcmp(key, "clients"))
2301                        err = og_json_parse_clients(value, params);
2302
2303                if (err < 0)
2304                        break;
2305        }
2306
2307        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
2308                return -1;
2309
2310        return og_send_request(OG_METHOD_POST, OG_CMD_POWEROFF, params, NULL);
2311}
2312
2313static int og_cmd_refresh(json_t *element, struct og_msg_params *params)
2314{
2315        const char *key;
2316        json_t *value;
2317        int err = 0;
2318
2319        if (json_typeof(element) != JSON_OBJECT)
2320                return -1;
2321
2322        json_object_foreach(element, key, value) {
2323                if (!strcmp(key, "clients"))
2324                        err = og_json_parse_clients(value, params);
2325
2326                if (err < 0)
2327                        break;
2328        }
2329
2330        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
2331                return -1;
2332
2333        return og_send_request(OG_METHOD_GET, OG_CMD_REFRESH, params, NULL);
2334}
2335
2336static int og_cmd_reboot(json_t *element, struct og_msg_params *params)
2337{
2338        const char *key;
2339        json_t *value;
2340        int err = 0;
2341
2342        if (json_typeof(element) != JSON_OBJECT)
2343                return -1;
2344
2345        json_object_foreach(element, key, value) {
2346                if (!strcmp(key, "clients"))
2347                        err = og_json_parse_clients(value, params);
2348
2349                if (err < 0)
2350                        break;
2351        }
2352
2353        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
2354                return -1;
2355
2356        return og_send_request(OG_METHOD_POST, OG_CMD_REBOOT, params, NULL);
2357}
2358
2359static int og_cmd_stop(json_t *element, struct og_msg_params *params)
2360{
2361        const char *key;
2362        json_t *value;
2363        int err = 0;
2364
2365        if (json_typeof(element) != JSON_OBJECT)
2366                return -1;
2367
2368        json_object_foreach(element, key, value) {
2369                if (!strcmp(key, "clients"))
2370                        err = og_json_parse_clients(value, params);
2371
2372                if (err < 0)
2373                        break;
2374        }
2375
2376        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
2377                return -1;
2378
2379        return og_send_request(OG_METHOD_POST, OG_CMD_STOP, params, NULL);
2380}
2381
2382static int og_cmd_hardware(json_t *element, struct og_msg_params *params)
2383{
2384        const char *key;
2385        json_t *value;
2386        int err = 0;
2387
2388        if (json_typeof(element) != JSON_OBJECT)
2389                return -1;
2390
2391        json_object_foreach(element, key, value) {
2392                if (!strcmp(key, "clients"))
2393                        err = og_json_parse_clients(value, params);
2394
2395                if (err < 0)
2396                        break;
2397        }
2398
2399        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
2400                return -1;
2401
2402        return og_send_request(OG_METHOD_GET, OG_CMD_HARDWARE, params, NULL);
2403}
2404
2405static int og_cmd_software(json_t *element, struct og_msg_params *params)
2406{
2407        json_t *clients, *value;
2408        const char *key;
2409        int err = 0;
2410
2411        if (json_typeof(element) != JSON_OBJECT)
2412                return -1;
2413
2414        json_object_foreach(element, key, value) {
2415                if (!strcmp(key, "clients"))
2416                        err = og_json_parse_clients(value, params);
2417                else if (!strcmp(key, "disk")) {
2418                        err = og_json_parse_string(value, &params->disk);
2419                        params->flags |= OG_REST_PARAM_DISK;
2420                }
2421                else if (!strcmp(key, "partition")) {
2422                        err = og_json_parse_string(value, &params->partition);
2423                        params->flags |= OG_REST_PARAM_PARTITION;
2424                }
2425
2426                if (err < 0)
2427                        break;
2428        }
2429
2430        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
2431                                            OG_REST_PARAM_DISK |
2432                                            OG_REST_PARAM_PARTITION))
2433                return -1;
2434
2435        clients = json_copy(element);
2436        json_object_del(clients, "clients");
2437
2438        return og_send_request(OG_METHOD_POST, OG_CMD_SOFTWARE, params, clients);
2439}
2440
2441static int og_cmd_create_image(json_t *element, struct og_msg_params *params)
2442{
2443        json_t *value, *clients;
2444        const char *key;
2445        int err = 0;
2446
2447        if (json_typeof(element) != JSON_OBJECT)
2448                return -1;
2449
2450        json_object_foreach(element, key, value) {
2451                if (!strcmp(key, "disk")) {
2452                        err = og_json_parse_string(value, &params->disk);
2453                        params->flags |= OG_REST_PARAM_DISK;
2454                } else if (!strcmp(key, "partition")) {
2455                        err = og_json_parse_string(value, &params->partition);
2456                        params->flags |= OG_REST_PARAM_PARTITION;
2457                } else if (!strcmp(key, "name")) {
2458                        err = og_json_parse_string(value, &params->name);
2459                        params->flags |= OG_REST_PARAM_NAME;
2460                } else if (!strcmp(key, "repository")) {
2461                        err = og_json_parse_string(value, &params->repository);
2462                        params->flags |= OG_REST_PARAM_REPO;
2463                } else if (!strcmp(key, "clients")) {
2464                        err = og_json_parse_clients(value, params);
2465                } else if (!strcmp(key, "id")) {
2466                        err = og_json_parse_string(value, &params->id);
2467                        params->flags |= OG_REST_PARAM_ID;
2468                } else if (!strcmp(key, "code")) {
2469                        err = og_json_parse_string(value, &params->code);
2470                        params->flags |= OG_REST_PARAM_CODE;
2471                }
2472
2473                if (err < 0)
2474                        break;
2475        }
2476
2477        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
2478                                            OG_REST_PARAM_DISK |
2479                                            OG_REST_PARAM_PARTITION |
2480                                            OG_REST_PARAM_CODE |
2481                                            OG_REST_PARAM_ID |
2482                                            OG_REST_PARAM_NAME |
2483                                            OG_REST_PARAM_REPO))
2484                return -1;
2485
2486        clients = json_copy(element);
2487        json_object_del(clients, "clients");
2488
2489        return og_send_request(OG_METHOD_POST, OG_CMD_IMAGE_CREATE, params,
2490                               clients);
2491}
2492
2493static int og_cmd_restore_image(json_t *element, struct og_msg_params *params)
2494{
2495        json_t *clients, *value;
2496        const char *key;
2497        int err = 0;
2498
2499        if (json_typeof(element) != JSON_OBJECT)
2500                return -1;
2501
2502        json_object_foreach(element, key, value) {
2503                if (!strcmp(key, "disk")) {
2504                        err = og_json_parse_string(value, &params->disk);
2505                        params->flags |= OG_REST_PARAM_DISK;
2506                } else if (!strcmp(key, "partition")) {
2507                        err = og_json_parse_string(value, &params->partition);
2508                        params->flags |= OG_REST_PARAM_PARTITION;
2509                } else if (!strcmp(key, "name")) {
2510                        err = og_json_parse_string(value, &params->name);
2511                        params->flags |= OG_REST_PARAM_NAME;
2512                } else if (!strcmp(key, "repository")) {
2513                        err = og_json_parse_string(value, &params->repository);
2514                        params->flags |= OG_REST_PARAM_REPO;
2515                } else if (!strcmp(key, "clients")) {
2516                        err = og_json_parse_clients(value, params);
2517                } else if (!strcmp(key, "type")) {
2518                        err = og_json_parse_string(value, &params->type);
2519                        params->flags |= OG_REST_PARAM_TYPE;
2520                } else if (!strcmp(key, "profile")) {
2521                        err = og_json_parse_string(value, &params->profile);
2522                        params->flags |= OG_REST_PARAM_PROFILE;
2523                } else if (!strcmp(key, "id")) {
2524                        err = og_json_parse_string(value, &params->id);
2525                        params->flags |= OG_REST_PARAM_ID;
2526                }
2527
2528                if (err < 0)
2529                        break;
2530        }
2531
2532        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
2533                                            OG_REST_PARAM_DISK |
2534                                            OG_REST_PARAM_PARTITION |
2535                                            OG_REST_PARAM_NAME |
2536                                            OG_REST_PARAM_REPO |
2537                                            OG_REST_PARAM_TYPE |
2538                                            OG_REST_PARAM_PROFILE |
2539                                            OG_REST_PARAM_ID))
2540                return -1;
2541
2542        clients = json_copy(element);
2543        json_object_del(clients, "clients");
2544
2545        return og_send_request(OG_METHOD_POST, OG_CMD_IMAGE_RESTORE, params,
2546                               clients);
2547}
2548
2549static int og_cmd_setup(json_t *element, struct og_msg_params *params)
2550{
2551        json_t *value, *clients;
2552        const char *key;
2553        int err = 0;
2554
2555        if (json_typeof(element) != JSON_OBJECT)
2556                return -1;
2557
2558        json_object_foreach(element, key, value) {
2559                if (!strcmp(key, "clients")) {
2560                        err = og_json_parse_clients(value, params);
2561                } else if (!strcmp(key, "disk")) {
2562                        err = og_json_parse_string(value, &params->disk);
2563                        params->flags |= OG_REST_PARAM_DISK;
2564                } else if (!strcmp(key, "cache")) {
2565                        err = og_json_parse_string(value, &params->cache);
2566                        params->flags |= OG_REST_PARAM_CACHE;
2567                } else if (!strcmp(key, "cache_size")) {
2568                        err = og_json_parse_string(value, &params->cache_size);
2569                        params->flags |= OG_REST_PARAM_CACHE_SIZE;
2570                } else if (!strcmp(key, "partition_setup")) {
2571                        err = og_json_parse_partition_setup(value, params);
2572                }
2573
2574                if (err < 0)
2575                        break;
2576        }
2577
2578        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
2579                                            OG_REST_PARAM_DISK |
2580                                            OG_REST_PARAM_CACHE |
2581                                            OG_REST_PARAM_CACHE_SIZE |
2582                                            OG_REST_PARAM_PART_0 |
2583                                            OG_REST_PARAM_PART_1 |
2584                                            OG_REST_PARAM_PART_2 |
2585                                            OG_REST_PARAM_PART_3))
2586                return -1;
2587
2588        clients = json_copy(element);
2589        json_object_del(clients, "clients");
2590
2591        return og_send_request(OG_METHOD_POST, OG_CMD_SETUP, params, clients);
2592}
2593
2594static int og_cmd_run_schedule(json_t *element, struct og_msg_params *params)
2595{
2596        const char *key;
2597        json_t *value;
2598        int err = 0;
2599
2600        json_object_foreach(element, key, value) {
2601                if (!strcmp(key, "clients"))
2602                        err = og_json_parse_clients(value, params);
2603
2604                if (err < 0)
2605                        break;
2606        }
2607
2608        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
2609                return -1;
2610
2611        return og_send_request(OG_METHOD_GET, OG_CMD_RUN_SCHEDULE, params,
2612                               NULL);
2613}
2614
2615static int og_cmd_create_basic_image(json_t *element, struct og_msg_params *params)
2616{
2617        char buf[4096] = {};
2618        int err = 0, len;
2619        const char *key;
2620        json_t *value;
2621        TRAMA *msg;
2622
2623        if (json_typeof(element) != JSON_OBJECT)
2624                return -1;
2625
2626        json_object_foreach(element, key, value) {
2627                if (!strcmp(key, "clients")) {
2628                        err = og_json_parse_clients(value, params);
2629                } else if (!strcmp(key, "disk")) {
2630                        err = og_json_parse_string(value, &params->disk);
2631                        params->flags |= OG_REST_PARAM_DISK;
2632                } else if (!strcmp(key, "partition")) {
2633                        err = og_json_parse_string(value, &params->partition);
2634                        params->flags |= OG_REST_PARAM_PARTITION;
2635                } else if (!strcmp(key, "code")) {
2636                        err = og_json_parse_string(value, &params->code);
2637                        params->flags |= OG_REST_PARAM_CODE;
2638                } else if (!strcmp(key, "id")) {
2639                        err = og_json_parse_string(value, &params->id);
2640                        params->flags |= OG_REST_PARAM_ID;
2641                } else if (!strcmp(key, "name")) {
2642                        err = og_json_parse_string(value, &params->name);
2643                        params->flags |= OG_REST_PARAM_NAME;
2644                } else if (!strcmp(key, "repository")) {
2645                        err = og_json_parse_string(value, &params->repository);
2646                        params->flags |= OG_REST_PARAM_REPO;
2647                } else if (!strcmp(key, "sync_params")) {
2648                        err = og_json_parse_sync_params(value, params);
2649                }
2650
2651                if (err < 0)
2652                        break;
2653        }
2654
2655        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
2656                                            OG_REST_PARAM_DISK |
2657                                            OG_REST_PARAM_PARTITION |
2658                                            OG_REST_PARAM_CODE |
2659                                            OG_REST_PARAM_ID |
2660                                            OG_REST_PARAM_NAME |
2661                                            OG_REST_PARAM_REPO |
2662                                            OG_REST_PARAM_SYNC_SYNC |
2663                                            OG_REST_PARAM_SYNC_DIFF |
2664                                            OG_REST_PARAM_SYNC_REMOVE |
2665                                            OG_REST_PARAM_SYNC_COMPRESS |
2666                                            OG_REST_PARAM_SYNC_CLEANUP |
2667                                            OG_REST_PARAM_SYNC_CACHE |
2668                                            OG_REST_PARAM_SYNC_CLEANUP_CACHE |
2669                                            OG_REST_PARAM_SYNC_REMOVE_DST))
2670                return -1;
2671
2672        len = snprintf(buf, sizeof(buf),
2673                       "nfn=CrearImagenBasica\rdsk=%s\rpar=%s\rcpt=%s\ridi=%s\r"
2674                       "nci=%s\ripr=%s\rrti=\rmsy=%s\rwhl=%s\reli=%s\rcmp=%s\rbpi=%s\r"
2675                       "cpc=%s\rbpc=%s\rnba=%s\r",
2676                       params->disk, params->partition, params->code, params->id,
2677                       params->name, params->repository, params->sync_setup.sync,
2678                       params->sync_setup.diff, params->sync_setup.remove,
2679                       params->sync_setup.compress, params->sync_setup.cleanup,
2680                       params->sync_setup.cache, params->sync_setup.cleanup_cache,
2681                       params->sync_setup.remove_dst);
2682
2683        msg = og_msg_alloc(buf, len);
2684        if (!msg)
2685                return -1;
2686
2687        og_send_cmd((char **)params->ips_array, params->ips_array_len,
2688                    CLIENTE_OCUPADO, msg);
2689
2690        og_msg_free(msg);
2691
2692        return 0;
2693}
2694
2695static int og_cmd_create_incremental_image(json_t *element, struct og_msg_params *params)
2696{
2697        char buf[4096] = {};
2698        int err = 0, len;
2699        const char *key;
2700        json_t *value;
2701        TRAMA *msg;
2702
2703        if (json_typeof(element) != JSON_OBJECT)
2704                return -1;
2705
2706        json_object_foreach(element, key, value) {
2707                if (!strcmp(key, "clients"))
2708                        err = og_json_parse_clients(value, params);
2709                else if (!strcmp(key, "disk")) {
2710                        err = og_json_parse_string(value, &params->disk);
2711                        params->flags |= OG_REST_PARAM_DISK;
2712                } else if (!strcmp(key, "partition")) {
2713                        err = og_json_parse_string(value, &params->partition);
2714                        params->flags |= OG_REST_PARAM_PARTITION;
2715                } else if (!strcmp(key, "id")) {
2716                        err = og_json_parse_string(value, &params->id);
2717                        params->flags |= OG_REST_PARAM_ID;
2718                } else if (!strcmp(key, "name")) {
2719                        err = og_json_parse_string(value, &params->name);
2720                        params->flags |= OG_REST_PARAM_NAME;
2721                } else if (!strcmp(key, "repository")) {
2722                        err = og_json_parse_string(value, &params->repository);
2723                        params->flags |= OG_REST_PARAM_REPO;
2724                } else if (!strcmp(key, "sync_params")) {
2725                        err = og_json_parse_sync_params(value, params);
2726                }
2727
2728                if (err < 0)
2729                        break;
2730        }
2731
2732        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
2733                                            OG_REST_PARAM_DISK |
2734                                            OG_REST_PARAM_PARTITION |
2735                                            OG_REST_PARAM_ID |
2736                                            OG_REST_PARAM_NAME |
2737                                            OG_REST_PARAM_REPO |
2738                                            OG_REST_PARAM_SYNC_SYNC |
2739                                            OG_REST_PARAM_SYNC_PATH |
2740                                            OG_REST_PARAM_SYNC_DIFF |
2741                                            OG_REST_PARAM_SYNC_DIFF_ID |
2742                                            OG_REST_PARAM_SYNC_DIFF_NAME |
2743                                            OG_REST_PARAM_SYNC_REMOVE |
2744                                            OG_REST_PARAM_SYNC_COMPRESS |
2745                                            OG_REST_PARAM_SYNC_CLEANUP |
2746                                            OG_REST_PARAM_SYNC_CACHE |
2747                                            OG_REST_PARAM_SYNC_CLEANUP_CACHE |
2748                                            OG_REST_PARAM_SYNC_REMOVE_DST))
2749                return -1;
2750
2751        len = snprintf(buf, sizeof(buf),
2752                       "nfn=CrearSoftIncremental\rdsk=%s\rpar=%s\ridi=%s\rnci=%s\r"
2753                       "rti=%s\ripr=%s\ridf=%s\rncf=%s\rmsy=%s\rwhl=%s\reli=%s\rcmp=%s\r"
2754                       "bpi=%s\rcpc=%s\rbpc=%s\rnba=%s\r",
2755                       params->disk, params->partition, params->id, params->name,
2756                       params->sync_setup.path, params->repository, params->sync_setup.diff_id,
2757                       params->sync_setup.diff_name, params->sync_setup.sync,
2758                       params->sync_setup.diff, params->sync_setup.remove_dst,
2759                       params->sync_setup.compress, params->sync_setup.cleanup,
2760                       params->sync_setup.cache, params->sync_setup.cleanup_cache,
2761                       params->sync_setup.remove_dst);
2762
2763        msg = og_msg_alloc(buf, len);
2764        if (!msg)
2765                return -1;
2766
2767        og_send_cmd((char **)params->ips_array, params->ips_array_len,
2768                    CLIENTE_OCUPADO, msg);
2769
2770        og_msg_free(msg);
2771
2772        return 0;
2773}
2774
2775static int og_cmd_restore_basic_image(json_t *element, struct og_msg_params *params)
2776{
2777        char buf[4096] = {};
2778        int err = 0, len;
2779        const char *key;
2780        json_t *value;
2781        TRAMA *msg;
2782
2783        if (json_typeof(element) != JSON_OBJECT)
2784                return -1;
2785
2786        json_object_foreach(element, key, value) {
2787                if (!strcmp(key, "clients")) {
2788                        err = og_json_parse_clients(value, params);
2789                } else if (!strcmp(key, "disk")) {
2790                        err = og_json_parse_string(value, &params->disk);
2791                        params->flags |= OG_REST_PARAM_DISK;
2792                } else if (!strcmp(key, "partition")) {
2793                        err = og_json_parse_string(value, &params->partition);
2794                        params->flags |= OG_REST_PARAM_PARTITION;
2795                } else if (!strcmp(key, "id")) {
2796                        err = og_json_parse_string(value, &params->id);
2797                        params->flags |= OG_REST_PARAM_ID;
2798                } else if (!strcmp(key, "name")) {
2799                        err = og_json_parse_string(value, &params->name);
2800                        params->flags |= OG_REST_PARAM_NAME;
2801                } else if (!strcmp(key, "repository")) {
2802                        err = og_json_parse_string(value, &params->repository);
2803                        params->flags |= OG_REST_PARAM_REPO;
2804                } else if (!strcmp(key, "profile")) {
2805                        err = og_json_parse_string(value, &params->profile);
2806                        params->flags |= OG_REST_PARAM_PROFILE;
2807                } else if (!strcmp(key, "type")) {
2808                        err = og_json_parse_string(value, &params->type);
2809                        params->flags |= OG_REST_PARAM_TYPE;
2810                } else if (!strcmp(key, "sync_params")) {
2811                        err = og_json_parse_sync_params(value, params);
2812                }
2813
2814                if (err < 0)
2815                        break;
2816        }
2817
2818        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
2819                                            OG_REST_PARAM_DISK |
2820                                            OG_REST_PARAM_PARTITION |
2821                                            OG_REST_PARAM_ID |
2822                                            OG_REST_PARAM_NAME |
2823                                            OG_REST_PARAM_REPO |
2824                                            OG_REST_PARAM_PROFILE |
2825                                            OG_REST_PARAM_TYPE |
2826                                            OG_REST_PARAM_SYNC_PATH |
2827                                            OG_REST_PARAM_SYNC_METHOD |
2828                                            OG_REST_PARAM_SYNC_SYNC |
2829                                            OG_REST_PARAM_SYNC_DIFF |
2830                                            OG_REST_PARAM_SYNC_REMOVE |
2831                                            OG_REST_PARAM_SYNC_COMPRESS |
2832                                            OG_REST_PARAM_SYNC_CLEANUP |
2833                                            OG_REST_PARAM_SYNC_CACHE |
2834                                            OG_REST_PARAM_SYNC_CLEANUP_CACHE |
2835                                            OG_REST_PARAM_SYNC_REMOVE_DST))
2836                return -1;
2837
2838        len = snprintf(buf, sizeof(buf),
2839                       "nfn=RestaurarImagenBasica\rdsk=%s\rpar=%s\ridi=%s\rnci=%s\r"
2840                           "ipr=%s\rifs=%s\rrti=%s\rmet=%s\rmsy=%s\rtpt=%s\rwhl=%s\r"
2841                           "eli=%s\rcmp=%s\rbpi=%s\rcpc=%s\rbpc=%s\rnba=%s\r",
2842                       params->disk, params->partition, params->id, params->name,
2843                           params->repository, params->profile, params->sync_setup.path,
2844                           params->sync_setup.method, params->sync_setup.sync, params->type,
2845                           params->sync_setup.diff, params->sync_setup.remove,
2846                       params->sync_setup.compress, params->sync_setup.cleanup,
2847                       params->sync_setup.cache, params->sync_setup.cleanup_cache,
2848                       params->sync_setup.remove_dst);
2849
2850        msg = og_msg_alloc(buf, len);
2851        if (!msg)
2852                return -1;
2853
2854        og_send_cmd((char **)params->ips_array, params->ips_array_len,
2855                    CLIENTE_OCUPADO, msg);
2856
2857        og_msg_free(msg);
2858
2859        return 0;
2860}
2861
2862static int og_cmd_restore_incremental_image(json_t *element, struct og_msg_params *params)
2863{
2864        char buf[4096] = {};
2865        int err = 0, len;
2866        const char *key;
2867        json_t *value;
2868        TRAMA *msg;
2869
2870        if (json_typeof(element) != JSON_OBJECT)
2871                return -1;
2872
2873        json_object_foreach(element, key, value) {
2874                if (!strcmp(key, "clients")) {
2875                        err = og_json_parse_clients(value, params);
2876                } else if (!strcmp(key, "disk")) {
2877                        err = og_json_parse_string(value, &params->disk);
2878                        params->flags |= OG_REST_PARAM_DISK;
2879                } else if (!strcmp(key, "partition")) {
2880                        err = og_json_parse_string(value, &params->partition);
2881                        params->flags |= OG_REST_PARAM_PARTITION;
2882                } else if (!strcmp(key, "id")) {
2883                        err = og_json_parse_string(value, &params->id);
2884                        params->flags |= OG_REST_PARAM_ID;
2885                } else if (!strcmp(key, "name")) {
2886                        err = og_json_parse_string(value, &params->name);
2887                        params->flags |= OG_REST_PARAM_NAME;
2888                } else if (!strcmp(key, "repository")) {
2889                        err = og_json_parse_string(value, &params->repository);
2890                        params->flags |= OG_REST_PARAM_REPO;
2891                } else if (!strcmp(key, "profile")) {
2892                        err = og_json_parse_string(value, &params->profile);
2893                        params->flags |= OG_REST_PARAM_PROFILE;
2894                } else if (!strcmp(key, "type")) {
2895                        err = og_json_parse_string(value, &params->type);
2896                        params->flags |= OG_REST_PARAM_TYPE;
2897                } else if (!strcmp(key, "sync_params")) {
2898                        err = og_json_parse_sync_params(value, params);
2899                }
2900
2901                if (err < 0)
2902                        break;
2903        }
2904
2905        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
2906                                            OG_REST_PARAM_DISK |
2907                                            OG_REST_PARAM_PARTITION |
2908                                            OG_REST_PARAM_ID |
2909                                            OG_REST_PARAM_NAME |
2910                                            OG_REST_PARAM_REPO |
2911                                            OG_REST_PARAM_PROFILE |
2912                                            OG_REST_PARAM_TYPE |
2913                                            OG_REST_PARAM_SYNC_DIFF_ID |
2914                                            OG_REST_PARAM_SYNC_DIFF_NAME |
2915                                            OG_REST_PARAM_SYNC_PATH |
2916                                            OG_REST_PARAM_SYNC_METHOD |
2917                                            OG_REST_PARAM_SYNC_SYNC |
2918                                            OG_REST_PARAM_SYNC_DIFF |
2919                                            OG_REST_PARAM_SYNC_REMOVE |
2920                                            OG_REST_PARAM_SYNC_COMPRESS |
2921                                            OG_REST_PARAM_SYNC_CLEANUP |
2922                                            OG_REST_PARAM_SYNC_CACHE |
2923                                            OG_REST_PARAM_SYNC_CLEANUP_CACHE |
2924                                            OG_REST_PARAM_SYNC_REMOVE_DST))
2925                return -1;
2926
2927        len = snprintf(buf, sizeof(buf),
2928                       "nfn=RestaurarSoftIncremental\rdsk=%s\rpar=%s\ridi=%s\rnci=%s\r"
2929                           "ipr=%s\rifs=%s\ridf=%s\rncf=%s\rrti=%s\rmet=%s\rmsy=%s\r"
2930                           "tpt=%s\rwhl=%s\reli=%s\rcmp=%s\rbpi=%s\rcpc=%s\rbpc=%s\r"
2931                           "nba=%s\r",
2932                       params->disk, params->partition, params->id, params->name,
2933                           params->repository, params->profile, params->sync_setup.diff_id,
2934                           params->sync_setup.diff_name, params->sync_setup.path,
2935                           params->sync_setup.method, params->sync_setup.sync, params->type,
2936                           params->sync_setup.diff, params->sync_setup.remove,
2937                       params->sync_setup.compress, params->sync_setup.cleanup,
2938                       params->sync_setup.cache, params->sync_setup.cleanup_cache,
2939                       params->sync_setup.remove_dst);
2940
2941        msg = og_msg_alloc(buf, len);
2942        if (!msg)
2943                return -1;
2944
2945        og_send_cmd((char **)params->ips_array, params->ips_array_len,
2946                    CLIENTE_OCUPADO, msg);
2947
2948        og_msg_free(msg);
2949
2950        return 0;
2951}
2952
2953struct og_cmd {
2954        struct list_head        list;
2955        uint32_t                client_id;
2956        const char              *ip;
2957        const char              *mac;
2958        enum og_cmd_type        type;
2959        enum og_rest_method     method;
2960        struct og_msg_params    params;
2961        json_t                  *json;
2962};
2963
2964static LIST_HEAD(cmd_list);
2965
2966static const struct og_cmd *og_cmd_find(const char *client_ip)
2967{
2968        struct og_cmd *cmd, *next;
2969
2970        list_for_each_entry_safe(cmd, next, &cmd_list, list) {
2971                if (strcmp(cmd->ip, client_ip))
2972                        continue;
2973
2974                list_del(&cmd->list);
2975                return cmd;
2976        }
2977
2978        return NULL;
2979}
2980
2981static void og_cmd_free(const struct og_cmd *cmd)
2982{
2983        struct og_msg_params *params = (struct og_msg_params *)&cmd->params;
2984        int i;
2985
2986        for (i = 0; i < params->ips_array_len; i++) {
2987                free((void *)params->ips_array[i]);
2988                free((void *)params->mac_array[i]);
2989        }
2990        free((void *)params->wol_type);
2991
2992        if (cmd->json)
2993                json_decref(cmd->json);
2994
2995        free((void *)cmd->ip);
2996        free((void *)cmd->mac);
2997        free((void *)cmd);
2998}
2999
3000static void og_cmd_init(struct og_cmd *cmd, enum og_rest_method method,
3001                        enum og_cmd_type type, json_t *root)
3002{
3003        cmd->type = type;
3004        cmd->method = method;
3005        cmd->params.ips_array[0] = strdup(cmd->ip);
3006        cmd->params.ips_array_len = 1;
3007        cmd->json = root;
3008}
3009
3010static int og_cmd_legacy_wol(const char *input, struct og_cmd *cmd)
3011{
3012        char wol_type[2] = {};
3013
3014        if (sscanf(input, "mar=%s", wol_type) != 1) {
3015                syslog(LOG_ERR, "malformed database legacy input\n");
3016                return -1;
3017        }
3018
3019        og_cmd_init(cmd, OG_METHOD_NO_HTTP, OG_CMD_WOL, NULL);
3020        cmd->params.mac_array[0] = strdup(cmd->mac);
3021        cmd->params.wol_type = strdup(wol_type);
3022
3023        return 0;
3024}
3025
3026static int og_cmd_legacy_shell_run(const char *input, struct og_cmd *cmd)
3027{
3028        json_t *root, *script, *echo;
3029
3030        script = json_string(input + 4);
3031        echo = json_boolean(false);
3032
3033        root = json_object();
3034        if (!root)
3035                return -1;
3036        json_object_set_new(root, "run", script);
3037        json_object_set_new(root, "echo", echo);
3038
3039        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_SHELL_RUN, root);
3040
3041        return 0;
3042}
3043
3044#define OG_DB_SMALLINT_MAXLEN   6
3045
3046static int og_cmd_legacy_session(const char *input, struct og_cmd *cmd)
3047{
3048        char part_str[OG_DB_SMALLINT_MAXLEN + 1];
3049        char disk_str[OG_DB_SMALLINT_MAXLEN + 1];
3050        json_t *root, *disk, *partition;
3051
3052        if (sscanf(input, "dsk=%s\rpar=%s\r", disk_str, part_str) != 2)
3053                return -1;
3054        partition = json_string(part_str);
3055        disk = json_string(disk_str);
3056
3057        root = json_object();
3058        if (!root)
3059                return -1;
3060        json_object_set_new(root, "partition", partition);
3061        json_object_set_new(root, "disk", disk);
3062
3063        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_SESSION, root);
3064
3065        return 0;
3066}
3067
3068static int og_cmd_legacy_poweroff(const char *input, struct og_cmd *cmd)
3069{
3070        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_POWEROFF, NULL);
3071
3072        return 0;
3073}
3074
3075static int og_cmd_legacy_refresh(const char *input, struct og_cmd *cmd)
3076{
3077        og_cmd_init(cmd, OG_METHOD_GET, OG_CMD_REFRESH, NULL);
3078
3079        return 0;
3080}
3081
3082static int og_cmd_legacy_reboot(const char *input, struct og_cmd *cmd)
3083{
3084        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_REBOOT, NULL);
3085
3086        return 0;
3087}
3088
3089static int og_cmd_legacy_stop(const char *input, struct og_cmd *cmd)
3090{
3091        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_STOP, NULL);
3092
3093        return 0;
3094}
3095
3096static int og_cmd_legacy_hardware(const char *input, struct og_cmd *cmd)
3097{
3098        og_cmd_init(cmd, OG_METHOD_GET, OG_CMD_HARDWARE, NULL);
3099
3100        return 0;
3101}
3102
3103static int og_cmd_legacy_software(const char *input, struct og_cmd *cmd)
3104{
3105        og_cmd_init(cmd, OG_METHOD_GET, OG_CMD_SOFTWARE, NULL);
3106
3107        return 0;
3108}
3109
3110#define OG_DB_IMAGE_NAME_MAXLEN 50
3111#define OG_DB_FILESYSTEM_MAXLEN 16
3112#define OG_DB_INT8_MAXLEN       8
3113#define OG_DB_INT_MAXLEN        11
3114#define OG_DB_IP_MAXLEN         15
3115
3116struct og_image_legacy {
3117        char software_id[OG_DB_INT_MAXLEN + 1];
3118        char image_id[OG_DB_INT_MAXLEN + 1];
3119        char name[OG_DB_IMAGE_NAME_MAXLEN + 1];
3120        char repo[OG_DB_IP_MAXLEN + 1];
3121        char part[OG_DB_SMALLINT_MAXLEN + 1];
3122        char disk[OG_DB_SMALLINT_MAXLEN + 1];
3123        char code[OG_DB_INT8_MAXLEN + 1];
3124};
3125
3126struct og_legacy_partition {
3127        char partition[OG_DB_SMALLINT_MAXLEN + 1];
3128        char code[OG_DB_INT8_MAXLEN + 1];
3129        char size[OG_DB_INT_MAXLEN + 1];
3130        char filesystem[OG_DB_FILESYSTEM_MAXLEN + 1];
3131        char format[2]; /* Format is a boolean 0 or 1 => length is 2 */
3132};
3133
3134static int og_cmd_legacy_image_create(const char *input, struct og_cmd *cmd)
3135{
3136        json_t *root, *disk, *partition, *code, *image_id, *name, *repo;
3137        struct og_image_legacy img = {};
3138
3139        if (sscanf(input, "dsk=%s\rpar=%s\rcpt=%s\ridi=%s\rnci=%s\ripr=%s\r",
3140                   img.disk, img.part, img.code, img.image_id, img.name,
3141                   img.repo) != 6)
3142                return -1;
3143        image_id = json_string(img.image_id);
3144        partition = json_string(img.part);
3145        code = json_string(img.code);
3146        name = json_string(img.name);
3147        repo = json_string(img.repo);
3148        disk = json_string(img.disk);
3149
3150        root = json_object();
3151        if (!root)
3152                return -1;
3153        json_object_set_new(root, "partition", partition);
3154        json_object_set_new(root, "repository", repo);
3155        json_object_set_new(root, "id", image_id);
3156        json_object_set_new(root, "code", code);
3157        json_object_set_new(root, "name", name);
3158        json_object_set_new(root, "disk", disk);
3159
3160        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_IMAGE_CREATE, root);
3161
3162        return 0;
3163}
3164
3165#define OG_DB_RESTORE_TYPE_MAXLEN       64
3166
3167static int og_cmd_legacy_image_restore(const char *input, struct og_cmd *cmd)
3168{
3169        json_t *root, *disk, *partition, *image_id, *name, *repo;
3170        char restore_type_str[OG_DB_RESTORE_TYPE_MAXLEN + 1] = {};
3171        char software_id_str[OG_DB_INT_MAXLEN + 1] = {};
3172        json_t *software_id, *restore_type;
3173        struct og_image_legacy img = {};
3174
3175        if (sscanf(input,
3176                   "dsk=%s\rpar=%s\ridi=%s\rnci=%s\ripr=%s\rifs=%s\rptc=%s\r",
3177                   img.disk, img.part, img.image_id, img.name, img.repo,
3178                   software_id_str, restore_type_str) != 7)
3179                return -1;
3180
3181        restore_type = json_string(restore_type_str);
3182        software_id = json_string(software_id_str);
3183        image_id = json_string(img.image_id);
3184        partition = json_string(img.part);
3185        name = json_string(img.name);
3186        repo = json_string(img.repo);
3187        disk = json_string(img.disk);
3188
3189        root = json_object();
3190        if (!root)
3191                return -1;
3192        json_object_set_new(root, "profile", software_id);
3193        json_object_set_new(root, "partition", partition);
3194        json_object_set_new(root, "type", restore_type);
3195        json_object_set_new(root, "repository", repo);
3196        json_object_set_new(root, "id", image_id);
3197        json_object_set_new(root, "name", name);
3198        json_object_set_new(root, "disk", disk);
3199
3200        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_IMAGE_RESTORE, root);
3201
3202        return 0;
3203}
3204
3205static int og_cmd_legacy_setup(const char *input, struct og_cmd *cmd)
3206{
3207        json_t *root, *disk, *cache, *cache_size, *partition_setup, *object;
3208        struct og_legacy_partition part_cfg[OG_PARTITION_MAX] = {};
3209        char cache_size_str [OG_DB_INT_MAXLEN + 1];
3210        char disk_str [OG_DB_SMALLINT_MAXLEN + 1];
3211        json_t *part, *code, *fs, *size, *format;
3212        unsigned int partition_len = 0;
3213        const char *in_ptr;
3214        char cache_str[2];
3215
3216        if (sscanf(input, "dsk=%s\rcfg=dis=%*[^*]*che=%[^*]*tch=%[^!]!",
3217                   disk_str, cache_str, cache_size_str) != 3)
3218                return -1;
3219
3220        in_ptr = strstr(input, "!") + 1;
3221        while (strlen(in_ptr) > 0) {
3222                if(sscanf(in_ptr,
3223                          "par=%[^*]*cpt=%[^*]*sfi=%[^*]*tam=%[^*]*ope=%[^%%]%%",
3224                          part_cfg[partition_len].partition,
3225                          part_cfg[partition_len].code,
3226                          part_cfg[partition_len].filesystem,
3227                          part_cfg[partition_len].size,
3228                          part_cfg[partition_len].format) != 5)
3229                        return -1;
3230                in_ptr = strstr(in_ptr, "%") + 1;
3231                partition_len++;
3232        }
3233
3234        root = json_object();
3235        if (!root)
3236                return -1;
3237
3238        cache_size = json_string(cache_size_str);
3239        cache = json_string(cache_str);
3240        partition_setup = json_array();
3241        disk = json_string(disk_str);
3242
3243        for (unsigned int i = 0; i < partition_len; ++i) {
3244                object = json_object();
3245                if (!object) {
3246                        json_decref(root);
3247                        return -1;
3248                }
3249
3250                part = json_string(part_cfg[i].partition);
3251                fs = json_string(part_cfg[i].filesystem);
3252                format = json_string(part_cfg[i].format);
3253                code = json_string(part_cfg[i].code);
3254                size = json_string(part_cfg[i].size);
3255
3256                json_object_set_new(object, "partition", part);
3257                json_object_set_new(object, "filesystem", fs);
3258                json_object_set_new(object, "format", format);
3259                json_object_set_new(object, "code", code);
3260                json_object_set_new(object, "size", size);
3261
3262                json_array_append_new(partition_setup, object);
3263        }
3264
3265        json_object_set_new(root, "partition_setup", partition_setup);
3266        json_object_set_new(root, "cache_size", cache_size);
3267        json_object_set_new(root, "cache", cache);
3268        json_object_set_new(root, "disk", disk);
3269
3270        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_SETUP, root);
3271
3272        return 0;
3273}
3274
3275static int og_cmd_legacy_run_schedule(const char *input, struct og_cmd *cmd)
3276{
3277        og_cmd_init(cmd, OG_METHOD_GET, OG_CMD_RUN_SCHEDULE, NULL);
3278
3279        return 0;
3280}
3281
3282static int og_cmd_legacy(const char *input, struct og_cmd *cmd)
3283{
3284        char legacy_cmd[32] = {};
3285        int err = -1;
3286
3287        if (sscanf(input, "nfn=%31s\r", legacy_cmd) != 1) {
3288                syslog(LOG_ERR, "malformed database legacy input\n");
3289                return -1;
3290        }
3291        input = strchr(input, '\r') + 1;
3292
3293        if (!strcmp(legacy_cmd, "Arrancar")) {
3294                err = og_cmd_legacy_wol(input, cmd);
3295        } else if (!strcmp(legacy_cmd, "EjecutarScript")) {
3296                err = og_cmd_legacy_shell_run(input, cmd);
3297        } else if (!strcmp(legacy_cmd, "IniciarSesion")) {
3298                err = og_cmd_legacy_session(input, cmd);
3299        } else if (!strcmp(legacy_cmd, "Apagar")) {
3300                err = og_cmd_legacy_poweroff(input, cmd);
3301        } else if (!strcmp(legacy_cmd, "Actualizar")) {
3302                err = og_cmd_legacy_refresh(input, cmd);
3303        } else if (!strcmp(legacy_cmd, "Reiniciar")) {
3304                err = og_cmd_legacy_reboot(input, cmd);
3305        } else if (!strcmp(legacy_cmd, "Purgar")) {
3306                err = og_cmd_legacy_stop(input, cmd);
3307        } else if (!strcmp(legacy_cmd, "InventarioHardware")) {
3308                err = og_cmd_legacy_hardware(input, cmd);
3309        } else if (!strcmp(legacy_cmd, "InventarioSoftware")) {
3310                err = og_cmd_legacy_software(input, cmd);
3311        } else if (!strcmp(legacy_cmd, "CrearImagen")) {
3312                err = og_cmd_legacy_image_create(input, cmd);
3313        } else if (!strcmp(legacy_cmd, "RestaurarImagen")) {
3314                err = og_cmd_legacy_image_restore(input, cmd);
3315        } else if (!strcmp(legacy_cmd, "Configurar")) {
3316                err = og_cmd_legacy_setup(input, cmd);
3317        } else if (!strcmp(legacy_cmd, "EjecutaComandosPendientes") ||
3318                   !strcmp(legacy_cmd, "Actualizar")) {
3319                err = og_cmd_legacy_run_schedule(input, cmd);
3320        }
3321
3322        return err;
3323}
3324
3325static int og_queue_task_command(struct og_dbi *dbi, const struct og_task *task,
3326                                 char *query)
3327{
3328        struct og_cmd *cmd;
3329        const char *msglog;
3330        dbi_result result;
3331
3332        result = dbi_conn_queryf(dbi->conn, query);
3333        if (!result) {
3334                dbi_conn_error(dbi->conn, &msglog);
3335                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3336                       __func__, __LINE__, msglog);
3337                return -1;
3338        }
3339
3340        while (dbi_result_next_row(result)) {
3341                cmd = (struct og_cmd *)calloc(1, sizeof(struct og_cmd));
3342                if (!cmd) {
3343                        dbi_result_free(result);
3344                        return -1;
3345                }
3346
3347                cmd->client_id  = dbi_result_get_uint(result, "idordenador");
3348                cmd->ip         = strdup(dbi_result_get_string(result, "ip"));
3349                cmd->mac        = strdup(dbi_result_get_string(result, "mac"));
3350                og_cmd_legacy(task->params, cmd);
3351
3352                list_add_tail(&cmd->list, &cmd_list);
3353
3354        }
3355
3356        dbi_result_free(result);
3357
3358        return 0;
3359}
3360
3361static int og_queue_task_group_clients(struct og_dbi *dbi, struct og_task *task,
3362                                       char *query)
3363{
3364
3365        const char *msglog;
3366        dbi_result result;
3367
3368        result = dbi_conn_queryf(dbi->conn, query);
3369        if (!result) {
3370                dbi_conn_error(dbi->conn, &msglog);
3371                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3372                       __func__, __LINE__, msglog);
3373                return -1;
3374        }
3375
3376        while (dbi_result_next_row(result)) {
3377                uint32_t group_id = dbi_result_get_uint(result, "idgrupo");
3378
3379                sprintf(query, "SELECT idgrupo FROM gruposordenadores "
3380                                "WHERE grupoid=%d", group_id);
3381                if (og_queue_task_group_clients(dbi, task, query)) {
3382                        dbi_result_free(result);
3383                        return -1;
3384                }
3385
3386                sprintf(query,"SELECT ip, mac, idordenador FROM ordenadores "
3387                              "WHERE grupoid=%d", group_id);
3388                if (og_queue_task_command(dbi, task, query)) {
3389                        dbi_result_free(result);
3390                        return -1;
3391                }
3392
3393        }
3394
3395        dbi_result_free(result);
3396
3397        return 0;
3398}
3399
3400static int og_queue_task_classrooms(struct og_dbi *dbi, struct og_task *task,
3401                                    char *query)
3402{
3403
3404        const char *msglog;
3405        dbi_result result;
3406
3407        result = dbi_conn_queryf(dbi->conn, query);
3408        if (!result) {
3409                dbi_conn_error(dbi->conn, &msglog);
3410                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3411                       __func__, __LINE__, msglog);
3412                return -1;
3413        }
3414
3415        while (dbi_result_next_row(result)) {
3416                uint32_t classroom_id = dbi_result_get_uint(result, "idaula");
3417
3418                sprintf(query, "SELECT idgrupo FROM gruposordenadores "
3419                                "WHERE idaula=%d AND grupoid=0", classroom_id);
3420                if (og_queue_task_group_clients(dbi, task, query)) {
3421                        dbi_result_free(result);
3422                        return -1;
3423                }
3424
3425                sprintf(query,"SELECT ip, mac, idordenador FROM ordenadores "
3426                                "WHERE idaula=%d AND grupoid=0", classroom_id);
3427                if (og_queue_task_command(dbi, task, query)) {
3428                        dbi_result_free(result);
3429                        return -1;
3430                }
3431
3432        }
3433
3434        dbi_result_free(result);
3435
3436        return 0;
3437}
3438
3439static int og_queue_task_group_classrooms(struct og_dbi *dbi,
3440                                          struct og_task *task, char *query)
3441{
3442
3443        const char *msglog;
3444        dbi_result result;
3445
3446        result = dbi_conn_queryf(dbi->conn, query);
3447        if (!result) {
3448                dbi_conn_error(dbi->conn, &msglog);
3449                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3450                       __func__, __LINE__, msglog);
3451                return -1;
3452        }
3453
3454        while (dbi_result_next_row(result)) {
3455                uint32_t group_id = dbi_result_get_uint(result, "idgrupo");
3456
3457                sprintf(query, "SELECT idgrupo FROM grupos "
3458                                "WHERE grupoid=%d AND tipo=%d", group_id, AMBITO_GRUPOSAULAS);
3459                if (og_queue_task_group_classrooms(dbi, task, query)) {
3460                        dbi_result_free(result);
3461                        return -1;
3462                }
3463
3464                sprintf(query,"SELECT idaula FROM aulas WHERE grupoid=%d", group_id);
3465                if (og_queue_task_classrooms(dbi, task, query)) {
3466                        dbi_result_free(result);
3467                        return -1;
3468                }
3469
3470        }
3471
3472        dbi_result_free(result);
3473
3474        return 0;
3475}
3476
3477static int og_queue_task_center(struct og_dbi *dbi, struct og_task *task,
3478                                char *query)
3479{
3480
3481        sprintf(query,"SELECT idgrupo FROM grupos WHERE idcentro=%i AND grupoid=0 AND tipo=%d",
3482                task->scope, AMBITO_GRUPOSAULAS);
3483        if (og_queue_task_group_classrooms(dbi, task, query))
3484                return -1;
3485
3486        sprintf(query,"SELECT idaula FROM aulas WHERE idcentro=%i AND grupoid=0",
3487                task->scope);
3488        if (og_queue_task_classrooms(dbi, task, query))
3489                return -1;
3490
3491        return 0;
3492}
3493
3494static int og_queue_task_clients(struct og_dbi *dbi, struct og_task *task)
3495{
3496        char query[4096];
3497
3498        switch (task->type_scope) {
3499                case AMBITO_CENTROS:
3500                        return og_queue_task_center(dbi, task, query);
3501                case AMBITO_GRUPOSAULAS:
3502                        sprintf(query, "SELECT idgrupo FROM grupos "
3503                                       "WHERE idgrupo=%i AND tipo=%d",
3504                                       task->scope, AMBITO_GRUPOSAULAS);
3505                        return og_queue_task_group_classrooms(dbi, task, query);
3506                case AMBITO_AULAS:
3507                        sprintf(query, "SELECT idaula FROM aulas "
3508                                       "WHERE idaula = %d", task->scope);
3509                        return og_queue_task_classrooms(dbi, task, query);
3510                case AMBITO_GRUPOSORDENADORES:
3511                        sprintf(query, "SELECT idgrupo FROM gruposordenadores "
3512                                       "WHERE idgrupo = %d", task->scope);
3513                        return og_queue_task_group_clients(dbi, task, query);
3514                case AMBITO_ORDENADORES:
3515                        sprintf(query, "SELECT ip, mac, idordenador "
3516                                       "FROM ordenadores "
3517                                       "WHERE idordenador = %d", task->scope);
3518                        return og_queue_task_command(dbi, task, query);
3519        }
3520        return 0;
3521}
3522
3523static int og_dbi_queue_procedure(struct og_dbi *dbi, struct og_task *task)
3524{
3525        uint32_t procedure_id;
3526        const char *msglog;
3527        dbi_result result;
3528
3529        result = dbi_conn_queryf(dbi->conn,
3530                        "SELECT parametros, procedimientoid "
3531                        "FROM procedimientos_acciones "
3532                        "WHERE idprocedimiento=%d ORDER BY orden", task->procedure_id);
3533        if (!result) {
3534                dbi_conn_error(dbi->conn, &msglog);
3535                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3536                       __func__, __LINE__, msglog);
3537                return -1;
3538        }
3539
3540        while (dbi_result_next_row(result)) {
3541                procedure_id = dbi_result_get_uint(result, "procedimientoid");
3542                if (procedure_id > 0) {
3543                        task->procedure_id = procedure_id;
3544                        if (og_dbi_queue_procedure(dbi, task))
3545                                return -1;
3546                        continue;
3547                }
3548
3549                task->params    = strdup(dbi_result_get_string(result, "parametros"));
3550                if (og_queue_task_clients(dbi, task))
3551                        return -1;
3552        }
3553
3554        dbi_result_free(result);
3555
3556        return 0;
3557}
3558
3559static int og_dbi_queue_task(struct og_dbi *dbi, uint32_t task_id)
3560{
3561        struct og_task task = {};
3562        uint32_t task_id_next;
3563        struct og_cmd *cmd;
3564        const char *msglog;
3565        dbi_result result;
3566
3567        result = dbi_conn_queryf(dbi->conn,
3568                        "SELECT tareas_acciones.orden, "
3569                                "tareas_acciones.idprocedimiento, "
3570                                "tareas_acciones.tareaid, "
3571                                "tareas.ambito, "
3572                                "tareas.idambito, "
3573                                "tareas.restrambito "
3574                        " FROM tareas"
3575                                " INNER JOIN tareas_acciones ON tareas_acciones.idtarea=tareas.idtarea"
3576                        " WHERE tareas_acciones.idtarea=%u ORDER BY tareas_acciones.orden ASC", task_id);
3577        if (!result) {
3578                dbi_conn_error(dbi->conn, &msglog);
3579                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3580                       __func__, __LINE__, msglog);
3581                return -1;
3582        }
3583
3584        while (dbi_result_next_row(result)) {
3585                task_id_next = dbi_result_get_uint(result, "procedimientoid");
3586
3587                if (task_id_next > 0) {
3588                        if (og_dbi_queue_task(dbi, task_id_next))
3589                                return -1;
3590
3591                        continue;
3592                }
3593                task.procedure_id = dbi_result_get_uint(result, "idprocedimiento");
3594                task.type_scope = dbi_result_get_uint(result, "ambito");
3595                task.scope = dbi_result_get_uint(result, "idambito");
3596                task.filtered_scope = dbi_result_get_string(result, "restrambito");
3597
3598                og_dbi_queue_procedure(dbi, &task);
3599        }
3600
3601        dbi_result_free(result);
3602
3603        list_for_each_entry(cmd, &cmd_list, list) {
3604                if (cmd->type != OG_CMD_WOL)
3605                        continue;
3606
3607                if (!Levanta((char **)cmd->params.ips_array,
3608                             (char **)cmd->params.mac_array,
3609                             cmd->params.ips_array_len,
3610                             (char *)cmd->params.wol_type))
3611                        return -1;
3612        }
3613
3614        return 0;
3615}
3616
3617void og_dbi_schedule_task(unsigned int task_id)
3618{
3619        struct og_msg_params params = {};
3620        bool duplicated = false;
3621        struct og_cmd *cmd;
3622        struct og_dbi *dbi;
3623        unsigned int i;
3624
3625        dbi = og_dbi_open(&dbi_config);
3626        if (!dbi) {
3627                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
3628                       __func__, __LINE__);
3629                return;
3630        }
3631        og_dbi_queue_task(dbi, task_id);
3632        og_dbi_close(dbi);
3633
3634        list_for_each_entry(cmd, &cmd_list, list) {
3635                for (i = 0; i < params.ips_array_len; i++) {
3636                        if (!strncmp(cmd->ip, params.ips_array[i],
3637                                     OG_DB_IP_MAXLEN)) {
3638                                duplicated = true;
3639                                break;
3640                        }
3641                }
3642
3643                if (!duplicated)
3644                        params.ips_array[params.ips_array_len++] = cmd->ip;
3645                else
3646                        duplicated = false;
3647        }
3648
3649        og_send_request(OG_METHOD_GET, OG_CMD_RUN_SCHEDULE, &params, NULL);
3650}
3651
3652static int og_cmd_task_post(json_t *element, struct og_msg_params *params)
3653{
3654        struct og_cmd *cmd;
3655        struct og_dbi *dbi;
3656        const char *key;
3657        json_t *value;
3658        int err;
3659
3660        if (json_typeof(element) != JSON_OBJECT)
3661                return -1;
3662
3663        json_object_foreach(element, key, value) {
3664                if (!strcmp(key, "task")) {
3665                        err = og_json_parse_string(value, &params->task_id);
3666                        params->flags |= OG_REST_PARAM_TASK;
3667                }
3668
3669                if (err < 0)
3670                        break;
3671        }
3672
3673        if (!og_msg_params_validate(params, OG_REST_PARAM_TASK))
3674                return -1;
3675
3676        dbi = og_dbi_open(&dbi_config);
3677        if (!dbi) {
3678                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
3679                           __func__, __LINE__);
3680                return -1;
3681        }
3682
3683        og_dbi_queue_task(dbi, atoi(params->task_id));
3684        og_dbi_close(dbi);
3685
3686        list_for_each_entry(cmd, &cmd_list, list)
3687                params->ips_array[params->ips_array_len++] = cmd->ip;
3688
3689        return og_send_request(OG_METHOD_GET, OG_CMD_RUN_SCHEDULE, params,
3690                               NULL);
3691}
3692
3693static int og_dbi_schedule_get(void)
3694{
3695        uint32_t schedule_id, task_id;
3696        struct og_schedule_time time;
3697        struct og_dbi *dbi;
3698        const char *msglog;
3699        dbi_result result;
3700
3701        dbi = og_dbi_open(&dbi_config);
3702        if (!dbi) {
3703                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
3704                       __func__, __LINE__);
3705                return -1;
3706        }
3707
3708        result = dbi_conn_queryf(dbi->conn,
3709                                 "SELECT idprogramacion, tipoaccion, identificador, "
3710                                 "sesion, annos, meses, diario, dias, semanas, horas, "
3711                                 "ampm, minutos FROM programaciones "
3712                                 "WHERE suspendida = 0");
3713        if (!result) {
3714                dbi_conn_error(dbi->conn, &msglog);
3715                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3716                       __func__, __LINE__, msglog);
3717                return -1;
3718        }
3719
3720        while (dbi_result_next_row(result)) {
3721                memset(&time, 0, sizeof(time));
3722                schedule_id = dbi_result_get_uint(result, "idprogramacion");
3723                task_id = dbi_result_get_uint(result, "identificador");
3724                time.years = dbi_result_get_uint(result, "annos");
3725                time.months = dbi_result_get_uint(result, "meses");
3726                time.weeks = dbi_result_get_uint(result, "semanas");
3727                time.week_days = dbi_result_get_uint(result, "dias");
3728                time.days = dbi_result_get_uint(result, "diario");
3729                time.hours = dbi_result_get_uint(result, "horas");
3730                time.am_pm = dbi_result_get_uint(result, "ampm");
3731                time.minutes = dbi_result_get_uint(result, "minutos");
3732
3733                og_schedule_create(schedule_id, task_id, &time);
3734        }
3735
3736        dbi_result_free(result);
3737
3738        return 0;
3739}
3740
3741static int og_dbi_schedule_create(struct og_dbi *dbi,
3742                                  struct og_msg_params *params,
3743                                  uint32_t *schedule_id)
3744{
3745        const char *msglog;
3746        dbi_result result;
3747        uint8_t suspended = 0;
3748        uint8_t type = 3;
3749
3750        result = dbi_conn_queryf(dbi->conn,
3751                                 "INSERT INTO programaciones (tipoaccion,"
3752                                 " identificador, nombrebloque, annos, meses,"
3753                                 " semanas, dias, diario, horas, ampm, minutos,"
3754                                 " suspendida) VALUES (%d, %s, '%s', %d, %d,"
3755                                 " %d, %d, %d, %d, %d, %d, %d)", type,
3756                                 params->task_id, params->name,
3757                                 params->time.years, params->time.months,
3758                                 params->time.weeks, params->time.week_days,
3759                                 params->time.days, params->time.hours,
3760                                 params->time.am_pm, params->time.minutes,
3761                                 suspended);
3762        if (!result) {
3763                dbi_conn_error(dbi->conn, &msglog);
3764                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3765                       __func__, __LINE__, msglog);
3766                return -1;
3767        }
3768        dbi_result_free(result);
3769
3770        *schedule_id = dbi_conn_sequence_last(dbi->conn, NULL);
3771
3772        return 0;
3773}
3774
3775static int og_dbi_schedule_update(struct og_dbi *dbi,
3776                                  struct og_msg_params *params)
3777{
3778        const char *msglog;
3779        dbi_result result;
3780        uint8_t type = 3;
3781
3782        result = dbi_conn_queryf(dbi->conn,
3783                                 "UPDATE programaciones SET tipoaccion=%d, "
3784                                 "identificador='%s', nombrebloque='%s', "
3785                                 "annos=%d, meses=%d, "
3786                                 "diario=%d, horas=%d, ampm=%d, minutos=%d "
3787                                 "WHERE idprogramacion='%s'",
3788                                 type, params->task_id, params->name,
3789                                 params->time.years, params->time.months,
3790                                 params->time.days, params->time.hours,
3791                                 params->time.am_pm, params->time.minutes,
3792                                 params->id);
3793
3794        if (!result) {
3795                dbi_conn_error(dbi->conn, &msglog);
3796                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3797                       __func__, __LINE__, msglog);
3798                return -1;
3799        }
3800        dbi_result_free(result);
3801
3802        return 0;
3803}
3804
3805static int og_dbi_schedule_delete(struct og_dbi *dbi, uint32_t id)
3806{
3807        const char *msglog;
3808        dbi_result result;
3809
3810        result = dbi_conn_queryf(dbi->conn,
3811                                 "DELETE FROM programaciones WHERE idprogramacion=%d",
3812                                 id);
3813        if (!result) {
3814                dbi_conn_error(dbi->conn, &msglog);
3815                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3816                       __func__, __LINE__, msglog);
3817                return -1;
3818        }
3819        dbi_result_free(result);
3820
3821        return 0;
3822}
3823
3824struct og_db_schedule {
3825        uint32_t                id;
3826        uint32_t                task_id;
3827        const char              *name;
3828        struct og_schedule_time time;
3829        uint32_t                week_days;
3830        uint32_t                weeks;
3831        uint32_t                suspended;
3832        uint32_t                session;
3833};
3834
3835static int og_dbi_schedule_get_json(struct og_dbi *dbi, json_t *root,
3836                                    const char *task_id, const char *schedule_id)
3837{
3838        struct og_db_schedule schedule;
3839        json_t *obj, *array;
3840        const char *msglog;
3841        dbi_result result;
3842        int err = 0;
3843
3844        if (task_id) {
3845                result = dbi_conn_queryf(dbi->conn,
3846                                         "SELECT idprogramacion,"
3847                                         "       identificador, nombrebloque,"
3848                                         "       annos, meses, diario, dias,"
3849                                         "       semanas, horas, ampm,"
3850                                         "       minutos,suspendida, sesion "
3851                                         "FROM programaciones "
3852                                         "WHERE identificador=%d",
3853                                         atoi(task_id));
3854        } else if (schedule_id) {
3855                result = dbi_conn_queryf(dbi->conn,
3856                                         "SELECT idprogramacion,"
3857                                         "       identificador, nombrebloque,"
3858                                         "       annos, meses, diario, dias,"
3859                                         "       semanas, horas, ampm,"
3860                                         "       minutos,suspendida, sesion "
3861                                         "FROM programaciones "
3862                                         "WHERE idprogramacion=%d",
3863                                         atoi(schedule_id));
3864        } else {
3865                result = dbi_conn_queryf(dbi->conn,
3866                                         "SELECT idprogramacion,"
3867                                         "       identificador, nombrebloque,"
3868                                         "       annos, meses, diario, dias,"
3869                                         "       semanas, horas, ampm,"
3870                                         "       minutos,suspendida, sesion "
3871                                         "FROM programaciones");
3872        }
3873
3874        if (!result) {
3875                dbi_conn_error(dbi->conn, &msglog);
3876                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3877                       __func__, __LINE__, msglog);
3878                return -1;
3879        }
3880
3881        array = json_array();
3882        if (!array)
3883                return -1;
3884
3885        while (dbi_result_next_row(result)) {
3886                schedule.id = dbi_result_get_uint(result, "idprogramacion");
3887                schedule.task_id = dbi_result_get_uint(result, "identificador");
3888                schedule.name = dbi_result_get_string(result, "nombrebloque");
3889                schedule.time.years = dbi_result_get_uint(result, "annos");
3890                schedule.time.months = dbi_result_get_uint(result, "meses");
3891                schedule.time.days = dbi_result_get_uint(result, "diario");
3892                schedule.time.hours = dbi_result_get_uint(result, "horas");
3893                schedule.time.am_pm = dbi_result_get_uint(result, "ampm");
3894                schedule.time.minutes = dbi_result_get_uint(result, "minutos");
3895                schedule.week_days = dbi_result_get_uint(result, "dias");
3896                schedule.weeks = dbi_result_get_uint(result, "semanas");
3897                schedule.suspended = dbi_result_get_uint(result, "suspendida");
3898                schedule.session = dbi_result_get_uint(result, "sesion");
3899
3900                obj = json_object();
3901                if (!obj) {
3902                        err = -1;
3903                        break;
3904                }
3905                json_object_set_new(obj, "id", json_integer(schedule.id));
3906                json_object_set_new(obj, "task", json_integer(schedule.task_id));
3907                json_object_set_new(obj, "name", json_string(schedule.name));
3908                json_object_set_new(obj, "years", json_integer(schedule.time.years));
3909                json_object_set_new(obj, "months", json_integer(schedule.time.months));
3910                json_object_set_new(obj, "days", json_integer(schedule.time.days));
3911                json_object_set_new(obj, "hours", json_integer(schedule.time.hours));
3912                json_object_set_new(obj, "am_pm", json_integer(schedule.time.am_pm));
3913                json_object_set_new(obj, "minutes", json_integer(schedule.time.minutes));
3914                json_object_set_new(obj, "week_days", json_integer(schedule.week_days));
3915                json_object_set_new(obj, "weeks", json_integer(schedule.weeks));
3916                json_object_set_new(obj, "suspended", json_integer(schedule.suspended));
3917                json_object_set_new(obj, "session", json_integer(schedule.session));
3918
3919                json_array_append_new(array, obj);
3920        }
3921
3922        json_object_set_new(root, "schedule", array);
3923
3924        dbi_result_free(result);
3925
3926        return err;
3927}
3928
3929static struct ev_loop *og_loop;
3930
3931static int og_cmd_schedule_create(json_t *element, struct og_msg_params *params)
3932{
3933        uint32_t schedule_id;
3934        struct og_dbi *dbi;
3935        const char *key;
3936        json_t *value;
3937        int err;
3938
3939        if (json_typeof(element) != JSON_OBJECT)
3940                return -1;
3941
3942        json_object_foreach(element, key, value) {
3943                if (!strcmp(key, "task")) {
3944                        err = og_json_parse_string(value, &params->task_id);
3945                        params->flags |= OG_REST_PARAM_TASK;
3946                } else if (!strcmp(key, "name")) {
3947                        err = og_json_parse_string(value, &params->name);
3948                        params->flags |= OG_REST_PARAM_NAME;
3949                } else if (!strcmp(key, "when"))
3950                        err = og_json_parse_time_params(value, params);
3951
3952                if (err < 0)
3953                        break;
3954        }
3955
3956        if (!og_msg_params_validate(params, OG_REST_PARAM_TASK |
3957                                            OG_REST_PARAM_NAME |
3958                                            OG_REST_PARAM_TIME_YEARS |
3959                                            OG_REST_PARAM_TIME_MONTHS |
3960                                            OG_REST_PARAM_TIME_WEEKS |
3961                                            OG_REST_PARAM_TIME_WEEK_DAYS |
3962                                            OG_REST_PARAM_TIME_DAYS |
3963                                            OG_REST_PARAM_TIME_HOURS |
3964                                            OG_REST_PARAM_TIME_MINUTES |
3965                                            OG_REST_PARAM_TIME_AM_PM))
3966                return -1;
3967
3968        dbi = og_dbi_open(&dbi_config);
3969        if (!dbi) {
3970                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
3971                           __func__, __LINE__);
3972                return -1;
3973        }
3974
3975        err = og_dbi_schedule_create(dbi, params, &schedule_id);
3976        og_dbi_close(dbi);
3977
3978        if (err < 0)
3979                return -1;
3980
3981        og_schedule_create(schedule_id, atoi(params->task_id), &params->time);
3982        og_schedule_refresh(og_loop);
3983
3984        return err;
3985}
3986
3987static int og_cmd_schedule_update(json_t *element, struct og_msg_params *params)
3988{
3989        struct og_dbi *dbi;
3990        const char *key;
3991        json_t *value;
3992        int err;
3993
3994        if (json_typeof(element) != JSON_OBJECT)
3995                return -1;
3996
3997        json_object_foreach(element, key, value) {
3998                if (!strcmp(key, "id")) {
3999                        err = og_json_parse_string(value, &params->id);
4000                        params->flags |= OG_REST_PARAM_ID;
4001                } else if (!strcmp(key, "task")) {
4002                        err = og_json_parse_string(value, &params->task_id);
4003                        params->flags |= OG_REST_PARAM_TASK;
4004                } else if (!strcmp(key, "name")) {
4005                        err = og_json_parse_string(value, &params->name);
4006                        params->flags |= OG_REST_PARAM_NAME;
4007                } else if (!strcmp(key, "when"))
4008                        err = og_json_parse_time_params(value, params);
4009
4010                if (err < 0)
4011                        break;
4012        }
4013
4014        if (!og_msg_params_validate(params, OG_REST_PARAM_ID |
4015                                            OG_REST_PARAM_TASK |
4016                                            OG_REST_PARAM_NAME |
4017                                            OG_REST_PARAM_TIME_YEARS |
4018                                            OG_REST_PARAM_TIME_MONTHS |
4019                                            OG_REST_PARAM_TIME_DAYS |
4020                                            OG_REST_PARAM_TIME_HOURS |
4021                                            OG_REST_PARAM_TIME_MINUTES |
4022                                            OG_REST_PARAM_TIME_AM_PM))
4023                return -1;
4024
4025        dbi = og_dbi_open(&dbi_config);
4026        if (!dbi) {
4027                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
4028                           __func__, __LINE__);
4029                return -1;
4030        }
4031
4032        err = og_dbi_schedule_update(dbi, params);
4033        og_dbi_close(dbi);
4034
4035        if (err < 0)
4036                return err;
4037
4038        og_schedule_update(og_loop, atoi(params->id), atoi(params->task_id),
4039                           &params->time);
4040        og_schedule_refresh(og_loop);
4041
4042        return err;
4043}
4044
4045static int og_cmd_schedule_delete(json_t *element, struct og_msg_params *params)
4046{
4047        struct og_dbi *dbi;
4048        const char *key;
4049        json_t *value;
4050        int err;
4051
4052        if (json_typeof(element) != JSON_OBJECT)
4053                return -1;
4054
4055        json_object_foreach(element, key, value) {
4056                if (!strcmp(key, "id")) {
4057                        err = og_json_parse_string(value, &params->id);
4058                        params->flags |= OG_REST_PARAM_ID;
4059                } else {
4060                        return -1;
4061                }
4062
4063                if (err < 0)
4064                        break;
4065        }
4066
4067        if (!og_msg_params_validate(params, OG_REST_PARAM_ID))
4068                return -1;
4069
4070        dbi = og_dbi_open(&dbi_config);
4071        if (!dbi) {
4072                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
4073                           __func__, __LINE__);
4074                return -1;
4075        }
4076
4077        err = og_dbi_schedule_delete(dbi, atoi(params->id));
4078        og_dbi_close(dbi);
4079
4080        og_schedule_delete(og_loop, atoi(params->id));
4081
4082        return err;
4083}
4084
4085static int og_cmd_schedule_get(json_t *element, struct og_msg_params *params,
4086                               char *buffer_reply)
4087{
4088        struct og_buffer og_buffer = {
4089                .data   = buffer_reply,
4090        };
4091        json_t *schedule_root;
4092        struct og_dbi *dbi;
4093        const char *key;
4094        json_t *value;
4095        int err;
4096
4097        if (element) {
4098                if (json_typeof(element) != JSON_OBJECT)
4099                        return -1;
4100
4101                json_object_foreach(element, key, value) {
4102                        if (!strcmp(key, "task")) {
4103                                err = og_json_parse_string(value,
4104                                                           &params->task_id);
4105                        } else if (!strcmp(key, "id")) {
4106                                err = og_json_parse_string(value, &params->id);
4107                        } else {
4108                                return -1;
4109                        }
4110
4111                        if (err < 0)
4112                                break;
4113                }
4114        }
4115
4116        dbi = og_dbi_open(&dbi_config);
4117        if (!dbi) {
4118                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
4119                           __func__, __LINE__);
4120                return -1;
4121        }
4122
4123        schedule_root = json_object();
4124        if (!schedule_root) {
4125                og_dbi_close(dbi);
4126                return -1;
4127        }
4128
4129        err = og_dbi_schedule_get_json(dbi, schedule_root,
4130                                       params->task_id, params->id);
4131        og_dbi_close(dbi);
4132
4133        if (err >= 0)
4134                json_dump_callback(schedule_root, og_json_dump_clients, &og_buffer, 0);
4135
4136        json_decref(schedule_root);
4137
4138        return err;
4139}
4140
4141static int og_client_method_not_found(struct og_client *cli)
4142{
4143        /* To meet RFC 7231, this function MUST generate an Allow header field
4144         * containing the correct methods. For example: "Allow: POST\r\n"
4145         */
4146        char buf[] = "HTTP/1.1 405 Method Not Allowed\r\n"
4147                     "Content-Length: 0\r\n\r\n";
4148
4149        send(og_client_socket(cli), buf, strlen(buf), 0);
4150
4151        return -1;
4152}
4153
4154static int og_client_bad_request(struct og_client *cli)
4155{
4156        char buf[] = "HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\n\r\n";
4157
4158        send(og_client_socket(cli), buf, strlen(buf), 0);
4159
4160        return -1;
4161}
4162
4163static int og_client_not_found(struct og_client *cli)
4164{
4165        char buf[] = "HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n";
4166
4167        send(og_client_socket(cli), buf, strlen(buf), 0);
4168
4169        return -1;
4170}
4171
4172static int og_client_not_authorized(struct og_client *cli)
4173{
4174        char buf[] = "HTTP/1.1 401 Unauthorized\r\n"
4175                     "WWW-Authenticate: Basic\r\n"
4176                     "Content-Length: 0\r\n\r\n";
4177
4178        send(og_client_socket(cli), buf, strlen(buf), 0);
4179
4180        return -1;
4181}
4182
4183static int og_server_internal_error(struct og_client *cli)
4184{
4185        char buf[] = "HTTP/1.1 500 Internal Server Error\r\n"
4186                     "Content-Length: 0\r\n\r\n";
4187
4188        send(og_client_socket(cli), buf, strlen(buf), 0);
4189
4190        return -1;
4191}
4192
4193static int og_client_payload_too_large(struct og_client *cli)
4194{
4195        char buf[] = "HTTP/1.1 413 Payload Too Large\r\n"
4196                     "Content-Length: 0\r\n\r\n";
4197
4198        send(og_client_socket(cli), buf, strlen(buf), 0);
4199
4200        return -1;
4201}
4202
4203#define OG_MSG_RESPONSE_MAXLEN  65536
4204
4205static int og_client_ok(struct og_client *cli, char *buf_reply)
4206{
4207        char buf[OG_MSG_RESPONSE_MAXLEN] = {};
4208        int err = 0, len;
4209
4210        len = snprintf(buf, sizeof(buf),
4211                       "HTTP/1.1 200 OK\r\nContent-Length: %ld\r\n\r\n%s",
4212                       strlen(buf_reply), buf_reply);
4213        if (len >= (int)sizeof(buf))
4214                err = og_server_internal_error(cli);
4215
4216        send(og_client_socket(cli), buf, strlen(buf), 0);
4217
4218        return err;
4219}
4220
4221static int og_client_state_process_payload_rest(struct og_client *cli)
4222{
4223        char buf_reply[OG_MSG_RESPONSE_MAXLEN] = {};
4224        struct og_msg_params params = {};
4225        enum og_rest_method method;
4226        const char *cmd, *body;
4227        json_error_t json_err;
4228        json_t *root = NULL;
4229        int err = 0;
4230
4231        syslog(LOG_DEBUG, "%s:%hu %.32s ...\n",
4232               inet_ntoa(cli->addr.sin_addr),
4233               ntohs(cli->addr.sin_port), cli->buf);
4234
4235        if (!strncmp(cli->buf, "GET", strlen("GET"))) {
4236                method = OG_METHOD_GET;
4237                cmd = cli->buf + strlen("GET") + 2;
4238        } else if (!strncmp(cli->buf, "POST", strlen("POST"))) {
4239                method = OG_METHOD_POST;
4240                cmd = cli->buf + strlen("POST") + 2;
4241        } else
4242                return og_client_method_not_found(cli);
4243
4244        body = strstr(cli->buf, "\r\n\r\n") + 4;
4245
4246        if (strcmp(cli->auth_token, auth_token)) {
4247                syslog(LOG_ERR, "wrong Authentication key\n");
4248                return og_client_not_authorized(cli);
4249        }
4250
4251        if (cli->content_length) {
4252                root = json_loads(body, 0, &json_err);
4253                if (!root) {
4254                        syslog(LOG_ERR, "malformed json line %d: %s\n",
4255                               json_err.line, json_err.text);
4256                        return og_client_not_found(cli);
4257                }
4258        }
4259
4260        if (!strncmp(cmd, "clients", strlen("clients"))) {
4261                if (method != OG_METHOD_POST &&
4262                    method != OG_METHOD_GET)
4263                        return og_client_method_not_found(cli);
4264
4265                if (method == OG_METHOD_POST && !root) {
4266                        syslog(LOG_ERR, "command clients with no payload\n");
4267                        return og_client_bad_request(cli);
4268                }
4269                switch (method) {
4270                case OG_METHOD_POST:
4271                        err = og_cmd_post_clients(root, &params);
4272                        break;
4273                case OG_METHOD_GET:
4274                        err = og_cmd_get_clients(root, &params, buf_reply);
4275                        break;
4276                default:
4277                        return og_client_bad_request(cli);
4278                }
4279        } else if (!strncmp(cmd, "wol", strlen("wol"))) {
4280                if (method != OG_METHOD_POST)
4281                        return og_client_method_not_found(cli);
4282
4283                if (!root) {
4284                        syslog(LOG_ERR, "command wol with no payload\n");
4285                        return og_client_bad_request(cli);
4286                }
4287                err = og_cmd_wol(root, &params);
4288        } else if (!strncmp(cmd, "shell/run", strlen("shell/run"))) {
4289                if (method != OG_METHOD_POST)
4290                        return og_client_method_not_found(cli);
4291
4292                if (!root) {
4293                        syslog(LOG_ERR, "command run with no payload\n");
4294                        return og_client_bad_request(cli);
4295                }
4296                err = og_cmd_run_post(root, &params);
4297        } else if (!strncmp(cmd, "shell/output", strlen("shell/output"))) {
4298                if (method != OG_METHOD_POST)
4299                        return og_client_method_not_found(cli);
4300
4301                if (!root) {
4302                        syslog(LOG_ERR, "command output with no payload\n");
4303                        return og_client_bad_request(cli);
4304                }
4305
4306                err = og_cmd_run_get(root, &params, buf_reply);
4307        } else if (!strncmp(cmd, "session", strlen("session"))) {
4308                if (method != OG_METHOD_POST)
4309                        return og_client_method_not_found(cli);
4310
4311                if (!root) {
4312                        syslog(LOG_ERR, "command session with no payload\n");
4313                        return og_client_bad_request(cli);
4314                }
4315                err = og_cmd_session(root, &params);
4316        } else if (!strncmp(cmd, "poweroff", strlen("poweroff"))) {
4317                if (method != OG_METHOD_POST)
4318                        return og_client_method_not_found(cli);
4319
4320                if (!root) {
4321                        syslog(LOG_ERR, "command poweroff with no payload\n");
4322                        return og_client_bad_request(cli);
4323                }
4324                err = og_cmd_poweroff(root, &params);
4325        } else if (!strncmp(cmd, "reboot", strlen("reboot"))) {
4326                if (method != OG_METHOD_POST)
4327                        return og_client_method_not_found(cli);
4328
4329                if (!root) {
4330                        syslog(LOG_ERR, "command reboot with no payload\n");
4331                        return og_client_bad_request(cli);
4332                }
4333                err = og_cmd_reboot(root, &params);
4334        } else if (!strncmp(cmd, "stop", strlen("stop"))) {
4335                if (method != OG_METHOD_POST)
4336                        return og_client_method_not_found(cli);
4337
4338                if (!root) {
4339                        syslog(LOG_ERR, "command stop with no payload\n");
4340                        return og_client_bad_request(cli);
4341                }
4342                err = og_cmd_stop(root, &params);
4343        } else if (!strncmp(cmd, "refresh", strlen("refresh"))) {
4344                if (method != OG_METHOD_POST)
4345                        return og_client_method_not_found(cli);
4346
4347                if (!root) {
4348                        syslog(LOG_ERR, "command refresh with no payload\n");
4349                        return og_client_bad_request(cli);
4350                }
4351                err = og_cmd_refresh(root, &params);
4352        } else if (!strncmp(cmd, "hardware", strlen("hardware"))) {
4353                if (method != OG_METHOD_POST)
4354                        return og_client_method_not_found(cli);
4355
4356                if (!root) {
4357                        syslog(LOG_ERR, "command hardware with no payload\n");
4358                        return og_client_bad_request(cli);
4359                }
4360                err = og_cmd_hardware(root, &params);
4361        } else if (!strncmp(cmd, "software", strlen("software"))) {
4362                if (method != OG_METHOD_POST)
4363                        return og_client_method_not_found(cli);
4364
4365                if (!root) {
4366                        syslog(LOG_ERR, "command software with no payload\n");
4367                        return og_client_bad_request(cli);
4368                }
4369                err = og_cmd_software(root, &params);
4370        } else if (!strncmp(cmd, "image/create/basic",
4371                            strlen("image/create/basic"))) {
4372                if (method != OG_METHOD_POST)
4373                        return og_client_method_not_found(cli);
4374
4375                if (!root) {
4376                        syslog(LOG_ERR, "command create with no payload\n");
4377                        return og_client_bad_request(cli);
4378                }
4379                err = og_cmd_create_basic_image(root, &params);
4380        } else if (!strncmp(cmd, "image/create/incremental",
4381                            strlen("image/create/incremental"))) {
4382                if (method != OG_METHOD_POST)
4383                        return og_client_method_not_found(cli);
4384
4385                if (!root) {
4386                        syslog(LOG_ERR, "command create with no payload\n");
4387                        return og_client_bad_request(cli);
4388                }
4389                err = og_cmd_create_incremental_image(root, &params);
4390        } else if (!strncmp(cmd, "image/create", strlen("image/create"))) {
4391                if (method != OG_METHOD_POST)
4392                        return og_client_method_not_found(cli);
4393
4394                if (!root) {
4395                        syslog(LOG_ERR, "command create with no payload\n");
4396                        return og_client_bad_request(cli);
4397                }
4398                err = og_cmd_create_image(root, &params);
4399        } else if (!strncmp(cmd, "image/restore/basic",
4400                                strlen("image/restore/basic"))) {
4401                if (method != OG_METHOD_POST)
4402                        return og_client_method_not_found(cli);
4403
4404                if (!root) {
4405                        syslog(LOG_ERR, "command create with no payload\n");
4406                        return og_client_bad_request(cli);
4407                }
4408                err = og_cmd_restore_basic_image(root, &params);
4409        } else if (!strncmp(cmd, "image/restore/incremental",
4410                                strlen("image/restore/incremental"))) {
4411                if (method != OG_METHOD_POST)
4412                        return og_client_method_not_found(cli);
4413
4414                if (!root) {
4415                        syslog(LOG_ERR, "command create with no payload\n");
4416                        return og_client_bad_request(cli);
4417                }
4418                err = og_cmd_restore_incremental_image(root, &params);
4419        } else if (!strncmp(cmd, "image/restore", strlen("image/restore"))) {
4420                if (method != OG_METHOD_POST)
4421                        return og_client_method_not_found(cli);
4422
4423                if (!root) {
4424                        syslog(LOG_ERR, "command create with no payload\n");
4425                        return og_client_bad_request(cli);
4426                }
4427                err = og_cmd_restore_image(root, &params);
4428        } else if (!strncmp(cmd, "setup", strlen("setup"))) {
4429                if (method != OG_METHOD_POST)
4430                        return og_client_method_not_found(cli);
4431
4432                if (!root) {
4433                        syslog(LOG_ERR, "command create with no payload\n");
4434                        return og_client_bad_request(cli);
4435                }
4436                err = og_cmd_setup(root, &params);
4437        } else if (!strncmp(cmd, "run/schedule", strlen("run/schedule"))) {
4438                if (method != OG_METHOD_POST)
4439                        return og_client_method_not_found(cli);
4440
4441                if (!root) {
4442                        syslog(LOG_ERR, "command create with no payload\n");
4443                        return og_client_bad_request(cli);
4444                }
4445
4446                err = og_cmd_run_schedule(root, &params);
4447        } else if (!strncmp(cmd, "task/run", strlen("task/run"))) {
4448                if (method != OG_METHOD_POST)
4449                        return og_client_method_not_found(cli);
4450
4451                if (!root) {
4452                        syslog(LOG_ERR, "command task with no payload\n");
4453                        return og_client_bad_request(cli);
4454                }
4455                err = og_cmd_task_post(root, &params);
4456        } else if (!strncmp(cmd, "schedule/create",
4457                            strlen("schedule/create"))) {
4458                if (method != OG_METHOD_POST)
4459                        return og_client_method_not_found(cli);
4460
4461                if (!root) {
4462                        syslog(LOG_ERR, "command task with no payload\n");
4463                        return og_client_bad_request(cli);
4464                }
4465                err = og_cmd_schedule_create(root, &params);
4466        } else if (!strncmp(cmd, "schedule/delete",
4467                            strlen("schedule/delete"))) {
4468                if (method != OG_METHOD_POST)
4469                        return og_client_method_not_found(cli);
4470
4471                if (!root) {
4472                        syslog(LOG_ERR, "command task with no payload\n");
4473                        return og_client_bad_request(cli);
4474                }
4475                err = og_cmd_schedule_delete(root, &params);
4476        } else if (!strncmp(cmd, "schedule/update",
4477                            strlen("schedule/update"))) {
4478                if (method != OG_METHOD_POST)
4479                        return og_client_method_not_found(cli);
4480
4481                if (!root) {
4482                        syslog(LOG_ERR, "command task with no payload\n");
4483                        return og_client_bad_request(cli);
4484                }
4485                err = og_cmd_schedule_update(root, &params);
4486        } else if (!strncmp(cmd, "schedule/get",
4487                            strlen("schedule/get"))) {
4488                if (method != OG_METHOD_POST)
4489                        return og_client_method_not_found(cli);
4490
4491                err = og_cmd_schedule_get(root, &params, buf_reply);
4492        } else {
4493                syslog(LOG_ERR, "unknown command: %.32s ...\n", cmd);
4494                err = og_client_not_found(cli);
4495        }
4496
4497        if (root)
4498                json_decref(root);
4499
4500        if (err < 0)
4501                return og_client_bad_request(cli);
4502
4503        err = og_client_ok(cli, buf_reply);
4504        if (err < 0) {
4505                syslog(LOG_ERR, "HTTP response to %s:%hu is too large\n",
4506                       inet_ntoa(cli->addr.sin_addr),
4507                       ntohs(cli->addr.sin_port));
4508        }
4509
4510        return err;
4511}
4512
4513static int og_client_state_recv_hdr_rest(struct og_client *cli)
4514{
4515        char *ptr;
4516
4517        ptr = strstr(cli->buf, "\r\n\r\n");
4518        if (!ptr)
4519                return 0;
4520
4521        cli->msg_len = ptr - cli->buf + 4;
4522
4523        ptr = strstr(cli->buf, "Content-Length: ");
4524        if (ptr) {
4525                sscanf(ptr, "Content-Length: %i[^\r\n]", &cli->content_length);
4526                if (cli->content_length < 0)
4527                        return -1;
4528                cli->msg_len += cli->content_length;
4529        }
4530
4531        ptr = strstr(cli->buf, "Authorization: ");
4532        if (ptr)
4533                sscanf(ptr, "Authorization: %63[^\r\n]", cli->auth_token);
4534
4535        return 1;
4536}
4537
4538static int og_client_recv(struct og_client *cli, int events)
4539{
4540        struct ev_io *io = &cli->io;
4541        int ret;
4542
4543        if (events & EV_ERROR) {
4544                syslog(LOG_ERR, "unexpected error event from client %s:%hu\n",
4545                               inet_ntoa(cli->addr.sin_addr),
4546                               ntohs(cli->addr.sin_port));
4547                return 0;
4548        }
4549
4550        ret = recv(io->fd, cli->buf + cli->buf_len,
4551                   sizeof(cli->buf) - cli->buf_len, 0);
4552        if (ret <= 0) {
4553                if (ret < 0) {
4554                        syslog(LOG_ERR, "error reading from client %s:%hu (%s)\n",
4555                               inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port),
4556                               strerror(errno));
4557                } else {
4558                        syslog(LOG_DEBUG, "closed connection by %s:%hu\n",
4559                               inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
4560                }
4561                return ret;
4562        }
4563
4564        return ret;
4565}
4566
4567static void og_client_read_cb(struct ev_loop *loop, struct ev_io *io, int events)
4568{
4569        struct og_client *cli;
4570        int ret;
4571
4572        cli = container_of(io, struct og_client, io);
4573
4574        ret = og_client_recv(cli, events);
4575        if (ret <= 0)
4576                goto close;
4577
4578        if (cli->keepalive_idx >= 0)
4579                return;
4580
4581        ev_timer_again(loop, &cli->timer);
4582
4583        cli->buf_len += ret;
4584        if (cli->buf_len >= sizeof(cli->buf)) {
4585                syslog(LOG_ERR, "client request from %s:%hu is too long\n",
4586                       inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
4587                og_client_payload_too_large(cli);
4588                goto close;
4589        }
4590
4591        switch (cli->state) {
4592        case OG_CLIENT_RECEIVING_HEADER:
4593                ret = og_client_state_recv_hdr_rest(cli);
4594                if (ret < 0)
4595                        goto close;
4596                if (!ret)
4597                        return;
4598
4599                cli->state = OG_CLIENT_RECEIVING_PAYLOAD;
4600                /* Fall through. */
4601        case OG_CLIENT_RECEIVING_PAYLOAD:
4602                /* Still not enough data to process request. */
4603                if (cli->buf_len < cli->msg_len)
4604                        return;
4605
4606                cli->state = OG_CLIENT_PROCESSING_REQUEST;
4607                /* fall through. */
4608        case OG_CLIENT_PROCESSING_REQUEST:
4609                ret = og_client_state_process_payload_rest(cli);
4610                if (ret < 0) {
4611                        syslog(LOG_ERR, "Failed to process HTTP request from %s:%hu\n",
4612                               inet_ntoa(cli->addr.sin_addr),
4613                               ntohs(cli->addr.sin_port));
4614                }
4615                if (ret < 0)
4616                        goto close;
4617
4618                if (cli->keepalive_idx < 0) {
4619                        syslog(LOG_DEBUG, "server closing connection to %s:%hu\n",
4620                               inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
4621                        goto close;
4622                } else {
4623                        syslog(LOG_DEBUG, "leaving client %s:%hu in keepalive mode\n",
4624                               inet_ntoa(cli->addr.sin_addr),
4625                               ntohs(cli->addr.sin_port));
4626                        og_client_keepalive(loop, cli);
4627                        og_client_reset_state(cli);
4628                }
4629                break;
4630        default:
4631                syslog(LOG_ERR, "unknown state, critical internal error\n");
4632                goto close;
4633        }
4634        return;
4635close:
4636        ev_timer_stop(loop, &cli->timer);
4637        og_client_release(loop, cli);
4638}
4639
4640enum og_agent_state {
4641        OG_AGENT_RECEIVING_HEADER       = 0,
4642        OG_AGENT_RECEIVING_PAYLOAD,
4643        OG_AGENT_PROCESSING_RESPONSE,
4644};
4645
4646static int og_agent_state_recv_hdr_rest(struct og_client *cli)
4647{
4648        char *ptr;
4649
4650        ptr = strstr(cli->buf, "\r\n\r\n");
4651        if (!ptr)
4652                return 0;
4653
4654        cli->msg_len = ptr - cli->buf + 4;
4655
4656        ptr = strstr(cli->buf, "Content-Length: ");
4657        if (ptr) {
4658                sscanf(ptr, "Content-Length: %i[^\r\n]", &cli->content_length);
4659                if (cli->content_length < 0)
4660                        return -1;
4661                cli->msg_len += cli->content_length;
4662        }
4663
4664        return 1;
4665}
4666
4667static void og_agent_reset_state(struct og_client *cli)
4668{
4669        cli->state = OG_AGENT_RECEIVING_HEADER;
4670        cli->buf_len = 0;
4671        cli->content_length = 0;
4672        memset(cli->buf, 0, sizeof(cli->buf));
4673}
4674
4675static int og_dbi_get_computer_info(struct og_computer *computer,
4676                                    struct in_addr addr)
4677{
4678        const char *msglog;
4679        struct og_dbi *dbi;
4680        dbi_result result;
4681
4682        dbi = og_dbi_open(&dbi_config);
4683        if (!dbi) {
4684                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
4685                       __func__, __LINE__);
4686                return -1;
4687        }
4688        result = dbi_conn_queryf(dbi->conn,
4689                                 "SELECT ordenadores.idordenador,"
4690                                 "       ordenadores.nombreordenador,"
4691                                 "       ordenadores.idaula,"
4692                                 "       centros.idcentro FROM ordenadores "
4693                                 "INNER JOIN aulas ON aulas.idaula=ordenadores.idaula "
4694                                 "INNER JOIN centros ON centros.idcentro=aulas.idcentro "
4695                                 "WHERE ordenadores.ip='%s'", inet_ntoa(addr));
4696        if (!result) {
4697                dbi_conn_error(dbi->conn, &msglog);
4698                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
4699                       __func__, __LINE__, msglog);
4700                return -1;
4701        }
4702        if (!dbi_result_next_row(result)) {
4703                syslog(LOG_ERR, "client does not exist in database (%s:%d)\n",
4704                       __func__, __LINE__);
4705                dbi_result_free(result);
4706                return -1;
4707        }
4708
4709        computer->id = dbi_result_get_uint(result, "idordenador");
4710        computer->center = dbi_result_get_uint(result, "idcentro");
4711        computer->room = dbi_result_get_uint(result, "idaula");
4712        strncpy(computer->name,
4713                dbi_result_get_string(result, "nombreordenador"),
4714                OG_COMPUTER_NAME_MAXLEN);
4715
4716        dbi_result_free(result);
4717        og_dbi_close(dbi);
4718
4719        return 0;
4720}
4721
4722static int og_resp_probe(struct og_client *cli, json_t *data)
4723{
4724        const char *status = NULL;
4725        const char *key;
4726        json_t *value;
4727        int err = 0;
4728
4729        if (json_typeof(data) != JSON_OBJECT)
4730                return -1;
4731
4732        json_object_foreach(data, key, value) {
4733                if (!strcmp(key, "status")) {
4734                        err = og_json_parse_string(value, &status);
4735                        if (err < 0)
4736                                return err;
4737                } else {
4738                        return -1;
4739                }
4740        }
4741
4742        if (!strcmp(status, "BSY"))
4743                cli->status = OG_CLIENT_STATUS_BUSY;
4744        else if (!strcmp(status, "OPG"))
4745                cli->status = OG_CLIENT_STATUS_OGLIVE;
4746
4747        return status ? 0 : -1;
4748}
4749
4750static int og_resp_shell_run(struct og_client *cli, json_t *data)
4751{
4752        const char *output = NULL;
4753        char filename[4096];
4754        const char *key;
4755        json_t *value;
4756        int err = -1;
4757        FILE *file;
4758
4759        if (json_typeof(data) != JSON_OBJECT)
4760                return -1;
4761
4762        json_object_foreach(data, key, value) {
4763                if (!strcmp(key, "out")) {
4764                        err = og_json_parse_string(value, &output);
4765                        if (err < 0)
4766                                return err;
4767                } else {
4768                        return -1;
4769                }
4770        }
4771
4772        if (!output) {
4773                syslog(LOG_ERR, "%s:%d: malformed json response\n",
4774                       __FILE__, __LINE__);
4775                return -1;
4776        }
4777
4778        sprintf(filename, "/tmp/_Seconsola_%s", inet_ntoa(cli->addr.sin_addr));
4779        file = fopen(filename, "wt");
4780        if (!file) {
4781                syslog(LOG_ERR, "cannot open file %s: %s\n",
4782                       filename, strerror(errno));
4783                return -1;
4784        }
4785
4786        fprintf(file, "%s", output);
4787        fclose(file);
4788
4789        return 0;
4790}
4791
4792struct og_computer_legacy  {
4793        char center[OG_DB_INT_MAXLEN + 1];
4794        char id[OG_DB_INT_MAXLEN + 1];
4795        char hardware[8192];
4796};
4797
4798static int og_resp_hardware(json_t *data, struct og_client *cli)
4799{
4800        struct og_computer_legacy legacy = {};
4801        const char *hardware = NULL;
4802        struct og_computer computer;
4803        struct og_dbi *dbi;
4804        const char *key;
4805        json_t *value;
4806        int err = 0;
4807        bool res;
4808
4809        if (json_typeof(data) != JSON_OBJECT)
4810                return -1;
4811
4812        json_object_foreach(data, key, value) {
4813                if (!strcmp(key, "hardware")) {
4814                        err = og_json_parse_string(value, &hardware);
4815                        if (err < 0)
4816                                return -1;
4817                } else {
4818                        return -1;
4819                }
4820        }
4821
4822        if (!hardware) {
4823                syslog(LOG_ERR, "malformed response json\n");
4824                return -1;
4825        }
4826
4827        err = og_dbi_get_computer_info(&computer, cli->addr.sin_addr);
4828        if (err < 0)
4829                return -1;
4830
4831        snprintf(legacy.center, sizeof(legacy.center), "%d", computer.center);
4832        snprintf(legacy.id, sizeof(legacy.id), "%d", computer.id);
4833        snprintf(legacy.hardware, sizeof(legacy.hardware), "%s", hardware);
4834
4835        dbi = og_dbi_open(&dbi_config);
4836        if (!dbi) {
4837                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
4838                       __func__, __LINE__);
4839                return -1;
4840        }
4841
4842        res = actualizaHardware(dbi, legacy.hardware, legacy.id, computer.name,
4843                                legacy.center);
4844        og_dbi_close(dbi);
4845
4846        if (!res) {
4847                syslog(LOG_ERR, "Problem updating client configuration\n");
4848                return -1;
4849        }
4850
4851        return 0;
4852}
4853
4854struct og_software_legacy {
4855        char software[8192];
4856        char center[OG_DB_INT_MAXLEN + 1];
4857        char part[OG_DB_SMALLINT_MAXLEN + 1];
4858        char id[OG_DB_INT_MAXLEN + 1];
4859};
4860
4861static int og_resp_software(json_t *data, struct og_client *cli)
4862{
4863        struct og_software_legacy legacy = {};
4864        const char *partition = NULL;
4865        const char *software = NULL;
4866        struct og_computer computer;
4867        struct og_dbi *dbi;
4868        const char *key;
4869        json_t *value;
4870        int err = 0;
4871        bool res;
4872
4873        if (json_typeof(data) != JSON_OBJECT)
4874                return -1;
4875
4876        json_object_foreach(data, key, value) {
4877                if (!strcmp(key, "software"))
4878                        err = og_json_parse_string(value, &software);
4879                else if (!strcmp(key, "partition"))
4880                        err = og_json_parse_string(value, &partition);
4881                else
4882                        return -1;
4883
4884                if (err < 0)
4885                        return -1;
4886        }
4887
4888        if (!software || !partition) {
4889                syslog(LOG_ERR, "malformed response json\n");
4890                return -1;
4891        }
4892
4893        err = og_dbi_get_computer_info(&computer, cli->addr.sin_addr);
4894        if (err < 0)
4895                return -1;
4896
4897        snprintf(legacy.software, sizeof(legacy.software), "%s", software);
4898        snprintf(legacy.part, sizeof(legacy.part), "%s", partition);
4899        snprintf(legacy.id, sizeof(legacy.id), "%d", computer.id);
4900        snprintf(legacy.center, sizeof(legacy.center), "%d", computer.center);
4901
4902        dbi = og_dbi_open(&dbi_config);
4903        if (!dbi) {
4904                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
4905                       __func__, __LINE__);
4906                return -1;
4907        }
4908
4909        res = actualizaSoftware(dbi, legacy.software, legacy.part, legacy.id,
4910                                computer.name, legacy.center);
4911        og_dbi_close(dbi);
4912
4913        if (!res) {
4914                syslog(LOG_ERR, "Problem updating client configuration\n");
4915                return -1;
4916        }
4917
4918        return 0;
4919}
4920
4921#define OG_PARAMS_RESP_REFRESH  (OG_PARAM_PART_DISK |           \
4922                                 OG_PARAM_PART_NUMBER |         \
4923                                 OG_PARAM_PART_CODE |           \
4924                                 OG_PARAM_PART_FILESYSTEM |     \
4925                                 OG_PARAM_PART_OS |             \
4926                                 OG_PARAM_PART_SIZE |           \
4927                                 OG_PARAM_PART_USED_SIZE)
4928
4929static int og_json_parse_partition_array(json_t *value,
4930                                         struct og_partition *partitions)
4931{
4932        json_t *element;
4933        int i, err;
4934
4935        if (json_typeof(value) != JSON_ARRAY)
4936                return -1;
4937
4938        for (i = 0; i < json_array_size(value) && i < OG_PARTITION_MAX; i++) {
4939                element = json_array_get(value, i);
4940
4941                err = og_json_parse_partition(element, &partitions[i],
4942                                              OG_PARAMS_RESP_REFRESH);
4943                if (err < 0)
4944                        return err;
4945        }
4946
4947        return 0;
4948}
4949
4950static int og_resp_refresh(json_t *data, struct og_client *cli)
4951{
4952        struct og_partition partitions[OG_PARTITION_MAX] = {};
4953        const char *serial_number = NULL;
4954        struct og_partition disk_setup;
4955        struct og_computer computer;
4956        char cfg[1024] = {};
4957        struct og_dbi *dbi;
4958        const char *key;
4959        unsigned int i;
4960        json_t *value;
4961        int err = 0;
4962        bool res;
4963
4964        if (json_typeof(data) != JSON_OBJECT)
4965                return -1;
4966
4967        json_object_foreach(data, key, value) {
4968                if (!strcmp(key, "disk_setup")) {
4969                        err = og_json_parse_partition(value,
4970                                                      &disk_setup,
4971                                                      OG_PARAMS_RESP_REFRESH);
4972                } else if (!strcmp(key, "partition_setup")) {
4973                        err = og_json_parse_partition_array(value, partitions);
4974                } else if (!strcmp(key, "serial_number")) {
4975                        err = og_json_parse_string(value, &serial_number);
4976                } else {
4977                        return -1;
4978                }
4979
4980                if (err < 0)
4981                        return err;
4982        }
4983
4984        err = og_dbi_get_computer_info(&computer, cli->addr.sin_addr);
4985        if (err < 0)
4986                return -1;
4987
4988        if (strlen(serial_number) > 0)
4989                snprintf(cfg, sizeof(cfg), "ser=%s\n", serial_number);
4990
4991        if (!disk_setup.disk || !disk_setup.number || !disk_setup.code ||
4992            !disk_setup.filesystem || !disk_setup.os || !disk_setup.size ||
4993            !disk_setup.used_size)
4994                return -1;
4995
4996        snprintf(cfg + strlen(cfg), sizeof(cfg) - strlen(cfg),
4997                 "disk=%s\tpar=%s\tcpt=%s\tfsi=%s\tsoi=%s\ttam=%s\tuso=%s\n",
4998                 disk_setup.disk, disk_setup.number, disk_setup.code,
4999                 disk_setup.filesystem, disk_setup.os, disk_setup.size,
5000                 disk_setup.used_size);
5001
5002        for (i = 0; i < OG_PARTITION_MAX; i++) {
5003                if (!partitions[i].disk || !partitions[i].number ||
5004                    !partitions[i].code || !partitions[i].filesystem ||
5005                    !partitions[i].os || !partitions[i].size ||
5006                    !partitions[i].used_size)
5007                        continue;
5008
5009                snprintf(cfg + strlen(cfg), sizeof(cfg) - strlen(cfg),
5010                         "disk=%s\tpar=%s\tcpt=%s\tfsi=%s\tsoi=%s\ttam=%s\tuso=%s\n",
5011                         partitions[i].disk, partitions[i].number,
5012                         partitions[i].code, partitions[i].filesystem,
5013                         partitions[i].os, partitions[i].size,
5014                         partitions[i].used_size);
5015        }
5016
5017        dbi = og_dbi_open(&dbi_config);
5018        if (!dbi) {
5019                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
5020                                  __func__, __LINE__);
5021                return -1;
5022        }
5023        res = actualizaConfiguracion(dbi, cfg, computer.id);
5024        og_dbi_close(dbi);
5025
5026        if (!res) {
5027                syslog(LOG_ERR, "Problem updating client configuration\n");
5028                return -1;
5029        }
5030
5031        return 0;
5032}
5033
5034static int og_resp_image_create(json_t *data, struct og_client *cli)
5035{
5036        struct og_software_legacy soft_legacy;
5037        struct og_image_legacy img_legacy;
5038        const char *partition = NULL;
5039        const char *software = NULL;
5040        const char *image_id = NULL;
5041        struct og_computer computer;
5042        const char *disk = NULL;
5043        const char *code = NULL;
5044        const char *name = NULL;
5045        const char *repo = NULL;
5046        struct og_dbi *dbi;
5047        const char *key;
5048        json_t *value;
5049        int err = 0;
5050        bool res;
5051
5052        if (json_typeof(data) != JSON_OBJECT)
5053                return -1;
5054
5055        json_object_foreach(data, key, value) {
5056                if (!strcmp(key, "software"))
5057                        err = og_json_parse_string(value, &software);
5058                else if (!strcmp(key, "partition"))
5059                        err = og_json_parse_string(value, &partition);
5060                else if (!strcmp(key, "disk"))
5061                        err = og_json_parse_string(value, &disk);
5062                else if (!strcmp(key, "code"))
5063                        err = og_json_parse_string(value, &code);
5064                else if (!strcmp(key, "id"))
5065                        err = og_json_parse_string(value, &image_id);
5066                else if (!strcmp(key, "name"))
5067                        err = og_json_parse_string(value, &name);
5068                else if (!strcmp(key, "repository"))
5069                        err = og_json_parse_string(value, &repo);
5070                else
5071                        return -1;
5072
5073                if (err < 0)
5074                        return err;
5075        }
5076
5077        if (!software || !partition || !disk || !code || !image_id || !name ||
5078            !repo) {
5079                syslog(LOG_ERR, "malformed response json\n");
5080                return -1;
5081        }
5082
5083        err = og_dbi_get_computer_info(&computer, cli->addr.sin_addr);
5084        if (err < 0)
5085                return -1;
5086
5087        snprintf(soft_legacy.center, sizeof(soft_legacy.center), "%d",
5088                 computer.center);
5089        snprintf(soft_legacy.software, sizeof(soft_legacy.software), "%s",
5090                 software);
5091        snprintf(img_legacy.image_id, sizeof(img_legacy.image_id), "%s",
5092                 image_id);
5093        snprintf(soft_legacy.id, sizeof(soft_legacy.id), "%d", computer.id);
5094        snprintf(img_legacy.part, sizeof(img_legacy.part), "%s", partition);
5095        snprintf(img_legacy.disk, sizeof(img_legacy.disk), "%s", disk);
5096        snprintf(img_legacy.code, sizeof(img_legacy.code), "%s", code);
5097        snprintf(img_legacy.name, sizeof(img_legacy.name), "%s", name);
5098        snprintf(img_legacy.repo, sizeof(img_legacy.repo), "%s", repo);
5099
5100        dbi = og_dbi_open(&dbi_config);
5101        if (!dbi) {
5102                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
5103                       __func__, __LINE__);
5104                return -1;
5105        }
5106
5107        res = actualizaSoftware(dbi,
5108                                soft_legacy.software,
5109                                img_legacy.part,
5110                                soft_legacy.id,
5111                                computer.name,
5112                                soft_legacy.center);
5113        if (!res) {
5114                og_dbi_close(dbi);
5115                syslog(LOG_ERR, "Problem updating client configuration\n");
5116                return -1;
5117        }
5118
5119        res = actualizaCreacionImagen(dbi,
5120                                      img_legacy.image_id,
5121                                      img_legacy.disk,
5122                                      img_legacy.part,
5123                                      img_legacy.code,
5124                                      img_legacy.repo,
5125                                      soft_legacy.id);
5126        og_dbi_close(dbi);
5127
5128        if (!res) {
5129                syslog(LOG_ERR, "Problem updating client configuration\n");
5130                return -1;
5131        }
5132
5133        return 0;
5134}
5135
5136static int og_resp_image_restore(json_t *data, struct og_client *cli)
5137{
5138        struct og_software_legacy soft_legacy;
5139        struct og_image_legacy img_legacy;
5140        const char *partition = NULL;
5141        const char *image_id = NULL;
5142        struct og_computer computer;
5143        const char *disk = NULL;
5144        dbi_result query_result;
5145        struct og_dbi *dbi;
5146        const char *key;
5147        json_t *value;
5148        int err = 0;
5149        bool res;
5150
5151        if (json_typeof(data) != JSON_OBJECT)
5152                return -1;
5153
5154        json_object_foreach(data, key, value) {
5155                if (!strcmp(key, "partition"))
5156                        err = og_json_parse_string(value, &partition);
5157                else if (!strcmp(key, "disk"))
5158                        err = og_json_parse_string(value, &disk);
5159                else if (!strcmp(key, "image_id"))
5160                        err = og_json_parse_string(value, &image_id);
5161                else
5162                        return -1;
5163
5164                if (err < 0)
5165                        return err;
5166        }
5167
5168        if (!partition || !disk || !image_id) {
5169                syslog(LOG_ERR, "malformed response json\n");
5170                return -1;
5171        }
5172
5173        err = og_dbi_get_computer_info(&computer, cli->addr.sin_addr);
5174        if (err < 0)
5175                return -1;
5176
5177        snprintf(img_legacy.image_id, sizeof(img_legacy.image_id), "%s",
5178                 image_id);
5179        snprintf(img_legacy.part, sizeof(img_legacy.part), "%s", partition);
5180        snprintf(img_legacy.disk, sizeof(img_legacy.disk), "%s", disk);
5181        snprintf(soft_legacy.id, sizeof(soft_legacy.id), "%d", computer.id);
5182
5183        dbi = og_dbi_open(&dbi_config);
5184        if (!dbi) {
5185                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
5186                       __func__, __LINE__);
5187                return -1;
5188        }
5189
5190        query_result = dbi_conn_queryf(dbi->conn,
5191                                       "SELECT idperfilsoft FROM imagenes "
5192                                       " WHERE idimagen='%s'",
5193                                       image_id);
5194        if (!query_result) {
5195                og_dbi_close(dbi);
5196                syslog(LOG_ERR, "failed to query database\n");
5197                return -1;
5198        }
5199        if (!dbi_result_next_row(query_result)) {
5200                dbi_result_free(query_result);
5201                og_dbi_close(dbi);
5202                syslog(LOG_ERR, "software profile does not exist in database\n");
5203                return -1;
5204        }
5205        snprintf(img_legacy.software_id, sizeof(img_legacy.software_id),
5206                 "%d", dbi_result_get_uint(query_result, "idperfilsoft"));
5207        dbi_result_free(query_result);
5208
5209        res = actualizaRestauracionImagen(dbi,
5210                                          img_legacy.image_id,
5211                                          img_legacy.disk,
5212                                          img_legacy.part,
5213                                          soft_legacy.id,
5214                                          img_legacy.software_id);
5215        og_dbi_close(dbi);
5216
5217        if (!res) {
5218                syslog(LOG_ERR, "Problem updating client configuration\n");
5219                return -1;
5220        }
5221
5222        return 0;
5223}
5224
5225static int og_agent_state_process_response(struct og_client *cli)
5226{
5227        json_error_t json_err;
5228        json_t *root;
5229        int err = -1;
5230        char *body;
5231
5232        if (strncmp(cli->buf, "HTTP/1.0 200 OK", strlen("HTTP/1.0 200 OK")))
5233                return -1;
5234
5235        if (!cli->content_length) {
5236                cli->last_cmd = OG_CMD_UNSPEC;
5237                return 0;
5238        }
5239
5240        body = strstr(cli->buf, "\r\n\r\n") + 4;
5241
5242        root = json_loads(body, 0, &json_err);
5243        if (!root) {
5244                syslog(LOG_ERR, "%s:%d: malformed json line %d: %s\n",
5245                       __FILE__, __LINE__, json_err.line, json_err.text);
5246                return -1;
5247        }
5248
5249        switch (cli->last_cmd) {
5250        case OG_CMD_PROBE:
5251                err = og_resp_probe(cli, root);
5252                break;
5253        case OG_CMD_SHELL_RUN:
5254                err = og_resp_shell_run(cli, root);
5255                break;
5256        case OG_CMD_HARDWARE:
5257                err = og_resp_hardware(root, cli);
5258                break;
5259        case OG_CMD_SOFTWARE:
5260                err = og_resp_software(root, cli);
5261                break;
5262        case OG_CMD_REFRESH:
5263                err = og_resp_refresh(root, cli);
5264                break;
5265        case OG_CMD_SETUP:
5266                err = og_resp_refresh(root, cli);
5267                break;
5268        case OG_CMD_IMAGE_CREATE:
5269                err = og_resp_image_create(root, cli);
5270                break;
5271        case OG_CMD_IMAGE_RESTORE:
5272                err = og_resp_image_restore(root, cli);
5273                break;
5274        default:
5275                err = -1;
5276                break;
5277        }
5278
5279        cli->last_cmd = OG_CMD_UNSPEC;
5280
5281        return err;
5282}
5283
5284static void og_agent_deliver_pending_cmd(struct og_client *cli)
5285{
5286        const struct og_cmd *cmd;
5287
5288        cmd = og_cmd_find(inet_ntoa(cli->addr.sin_addr));
5289        if (!cmd)
5290                return;
5291
5292        og_send_request(cmd->method, cmd->type, &cmd->params, cmd->json);
5293
5294        og_cmd_free(cmd);
5295}
5296
5297static void og_agent_read_cb(struct ev_loop *loop, struct ev_io *io, int events)
5298{
5299        struct og_client *cli;
5300        int ret;
5301
5302        cli = container_of(io, struct og_client, io);
5303
5304        ret = og_client_recv(cli, events);
5305        if (ret <= 0)
5306                goto close;
5307
5308        ev_timer_again(loop, &cli->timer);
5309
5310        cli->buf_len += ret;
5311        if (cli->buf_len >= sizeof(cli->buf)) {
5312                syslog(LOG_ERR, "client request from %s:%hu is too long\n",
5313                       inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
5314                goto close;
5315        }
5316
5317        switch (cli->state) {
5318        case OG_AGENT_RECEIVING_HEADER:
5319                ret = og_agent_state_recv_hdr_rest(cli);
5320                if (ret < 0)
5321                        goto close;
5322                if (!ret)
5323                        return;
5324
5325                cli->state = OG_AGENT_RECEIVING_PAYLOAD;
5326                /* Fall through. */
5327        case OG_AGENT_RECEIVING_PAYLOAD:
5328                /* Still not enough data to process request. */
5329                if (cli->buf_len < cli->msg_len)
5330                        return;
5331
5332                cli->state = OG_AGENT_PROCESSING_RESPONSE;
5333                /* fall through. */
5334        case OG_AGENT_PROCESSING_RESPONSE:
5335                ret = og_agent_state_process_response(cli);
5336                if (ret < 0) {
5337                        syslog(LOG_ERR, "Failed to process HTTP request from %s:%hu\n",
5338                               inet_ntoa(cli->addr.sin_addr),
5339                               ntohs(cli->addr.sin_port));
5340                        goto close;
5341                }
5342                og_agent_deliver_pending_cmd(cli);
5343
5344                syslog(LOG_DEBUG, "leaving client %s:%hu in keepalive mode\n",
5345                       inet_ntoa(cli->addr.sin_addr),
5346                       ntohs(cli->addr.sin_port));
5347                og_agent_reset_state(cli);
5348                break;
5349        default:
5350                syslog(LOG_ERR, "unknown state, critical internal error\n");
5351                goto close;
5352        }
5353        return;
5354close:
5355        ev_timer_stop(loop, &cli->timer);
5356        og_client_release(loop, cli);
5357}
5358
5359static void og_client_timer_cb(struct ev_loop *loop, ev_timer *timer, int events)
5360{
5361        struct og_client *cli;
5362
5363        cli = container_of(timer, struct og_client, timer);
5364        if (cli->keepalive_idx >= 0) {
5365                ev_timer_again(loop, &cli->timer);
5366                return;
5367        }
5368        syslog(LOG_ERR, "timeout request for client %s:%hu\n",
5369               inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
5370
5371        og_client_release(loop, cli);
5372}
5373
5374static void og_agent_send_refresh(struct og_client *cli)
5375{
5376        struct og_msg_params params;
5377        int err;
5378
5379        params.ips_array[0] = inet_ntoa(cli->addr.sin_addr);
5380        params.ips_array_len = 1;
5381
5382        err = og_send_request(OG_METHOD_GET, OG_CMD_REFRESH, &params, NULL);
5383        if (err < 0) {
5384                syslog(LOG_ERR, "Can't send refresh to: %s\n",
5385                       params.ips_array[0]);
5386        } else {
5387                syslog(LOG_INFO, "Sent refresh to: %s\n",
5388                       params.ips_array[0]);
5389        }
5390}
5391
5392static int socket_rest, socket_agent_rest;
5393
5394static void og_server_accept_cb(struct ev_loop *loop, struct ev_io *io,
5395                                int events)
5396{
5397        struct sockaddr_in client_addr;
5398        socklen_t addrlen = sizeof(client_addr);
5399        struct og_client *cli;
5400        int client_sd;
5401
5402        if (events & EV_ERROR)
5403                return;
5404
5405        client_sd = accept(io->fd, (struct sockaddr *)&client_addr, &addrlen);
5406        if (client_sd < 0) {
5407                syslog(LOG_ERR, "cannot accept client connection\n");
5408                return;
5409        }
5410
5411        cli = (struct og_client *)calloc(1, sizeof(struct og_client));
5412        if (!cli) {
5413                close(client_sd);
5414                return;
5415        }
5416        memcpy(&cli->addr, &client_addr, sizeof(client_addr));
5417        if (io->fd == socket_agent_rest)
5418                cli->keepalive_idx = 0;
5419        else
5420                cli->keepalive_idx = -1;
5421
5422        if (io->fd == socket_rest)
5423                cli->rest = true;
5424        else if (io->fd == socket_agent_rest)
5425                cli->agent = true;
5426
5427        syslog(LOG_DEBUG, "connection from client %s:%hu\n",
5428               inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
5429
5430        if (io->fd == socket_agent_rest)
5431                ev_io_init(&cli->io, og_agent_read_cb, client_sd, EV_READ);
5432        else
5433                ev_io_init(&cli->io, og_client_read_cb, client_sd, EV_READ);
5434
5435        ev_io_start(loop, &cli->io);
5436        if (io->fd == socket_agent_rest) {
5437                ev_timer_init(&cli->timer, og_client_timer_cb,
5438                              OG_AGENT_CLIENT_TIMEOUT, 0.);
5439        } else {
5440                ev_timer_init(&cli->timer, og_client_timer_cb,
5441                              OG_CLIENT_TIMEOUT, 0.);
5442        }
5443        ev_timer_start(loop, &cli->timer);
5444        list_add(&cli->list, &client_list);
5445
5446        if (io->fd == socket_agent_rest) {
5447                og_agent_send_refresh(cli);
5448        }
5449}
5450
5451static int og_socket_server_init(const char *port)
5452{
5453        struct sockaddr_in local;
5454        int sd, on = 1;
5455
5456        sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
5457        if (sd < 0) {
5458                syslog(LOG_ERR, "cannot create main socket\n");
5459                return -1;
5460        }
5461        setsockopt(sd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(int));
5462
5463        local.sin_addr.s_addr = htonl(INADDR_ANY);
5464        local.sin_family = AF_INET;
5465        local.sin_port = htons(atoi(port));
5466
5467        if (bind(sd, (struct sockaddr *) &local, sizeof(local)) < 0) {
5468                close(sd);
5469                syslog(LOG_ERR, "cannot bind socket\n");
5470                return -1;
5471        }
5472
5473        listen(sd, 250);
5474
5475        return sd;
5476}
5477
5478int main(int argc, char *argv[])
5479{
5480        struct ev_io ev_io_server_rest, ev_io_agent_rest;
5481        int i;
5482
5483        og_loop = ev_default_loop(0);
5484
5485        if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
5486                exit(EXIT_FAILURE);
5487
5488        openlog("ogAdmServer", LOG_PID, LOG_DAEMON);
5489
5490        /*--------------------------------------------------------------------------------------------------------
5491         Validación de parámetros de ejecución y lectura del fichero de configuración del servicio
5492         ---------------------------------------------------------------------------------------------------------*/
5493        if (!validacionParametros(argc, argv, 1)) // Valida parámetros de ejecución
5494                exit(EXIT_FAILURE);
5495
5496        if (!tomaConfiguracion(szPathFileCfg)) { // Toma parametros de configuracion
5497                exit(EXIT_FAILURE);
5498        }
5499
5500        /*--------------------------------------------------------------------------------------------------------
5501         // Inicializa array de información de los clientes
5502         ---------------------------------------------------------------------------------------------------------*/
5503        for (i = 0; i < MAXIMOS_CLIENTES; i++) {
5504                tbsockets[i].ip[0] = '\0';
5505                tbsockets[i].cli = NULL;
5506        }
5507        /*--------------------------------------------------------------------------------------------------------
5508         Creación y configuración del socket del servicio
5509         ---------------------------------------------------------------------------------------------------------*/
5510
5511        socket_rest = og_socket_server_init("8888");
5512        if (socket_rest < 0)
5513                exit(EXIT_FAILURE);
5514
5515        ev_io_init(&ev_io_server_rest, og_server_accept_cb, socket_rest, EV_READ);
5516        ev_io_start(og_loop, &ev_io_server_rest);
5517
5518        socket_agent_rest = og_socket_server_init("8889");
5519        if (socket_agent_rest < 0)
5520                exit(EXIT_FAILURE);
5521
5522        ev_io_init(&ev_io_agent_rest, og_server_accept_cb, socket_agent_rest, EV_READ);
5523        ev_io_start(og_loop, &ev_io_agent_rest);
5524
5525        if (og_dbi_schedule_get() < 0)
5526                exit(EXIT_FAILURE);
5527
5528        og_schedule_next(og_loop);
5529
5530        infoLog(1); // Inicio de sesión
5531
5532        /* old log file has been deprecated. */
5533        og_log(97, false);
5534
5535        syslog(LOG_INFO, "Waiting for connections\n");
5536
5537        while (1)
5538                ev_loop(og_loop, 0);
5539
5540        exit(EXIT_SUCCESS);
5541}
Note: See TracBrowser for help on using the repository browser.