source: ogServer-Git/sources/ogAdmServer.c @ 54c7ca3

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

#980 Complete API REST for ogClient

  • 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_DAYS                 (1UL << 34)
1558#define OG_REST_PARAM_TIME_HOURS                (1UL << 35)
1559#define OG_REST_PARAM_TIME_AM_PM                (1UL << 36)
1560#define OG_REST_PARAM_TIME_MINUTES              (1UL << 37)
1561
1562enum og_rest_method {
1563        OG_METHOD_GET   = 0,
1564        OG_METHOD_POST,
1565        OG_METHOD_NO_HTTP
1566};
1567
1568static struct og_client *og_client_find(const char *ip)
1569{
1570        struct og_client *client;
1571        struct in_addr addr;
1572        int res;
1573
1574        res = inet_aton(ip, &addr);
1575        if (!res) {
1576                syslog(LOG_ERR, "Invalid IP string: %s\n", ip);
1577                return NULL;
1578        }
1579
1580        list_for_each_entry(client, &client_list, list) {
1581                if (client->addr.sin_addr.s_addr == addr.s_addr && client->agent) {
1582                        return client;
1583                }
1584        }
1585
1586        return NULL;
1587}
1588
1589static bool og_msg_params_validate(const struct og_msg_params *params,
1590                                   const uint64_t flags)
1591{
1592        return (params->flags & flags) == flags;
1593}
1594
1595static int og_json_parse_clients(json_t *element, struct og_msg_params *params)
1596{
1597        unsigned int i;
1598        json_t *k;
1599
1600        if (json_typeof(element) != JSON_ARRAY)
1601                return -1;
1602
1603        for (i = 0; i < json_array_size(element); i++) {
1604                k = json_array_get(element, i);
1605                if (json_typeof(k) != JSON_STRING)
1606                        return -1;
1607
1608                params->ips_array[params->ips_array_len++] =
1609                        json_string_value(k);
1610
1611                params->flags |= OG_REST_PARAM_ADDR;
1612        }
1613
1614        return 0;
1615}
1616
1617static int og_json_parse_string(json_t *element, const char **str)
1618{
1619        if (json_typeof(element) != JSON_STRING)
1620                return -1;
1621
1622        *str = json_string_value(element);
1623        return 0;
1624}
1625
1626static int og_json_parse_uint(json_t *element, uint32_t *integer)
1627{
1628        if (json_typeof(element) != JSON_INTEGER)
1629                return -1;
1630
1631        *integer = json_integer_value(element);
1632        return 0;
1633}
1634
1635static int og_json_parse_bool(json_t *element, bool *value)
1636{
1637        if (json_typeof(element) == JSON_TRUE)
1638                *value = true;
1639        else if (json_typeof(element) == JSON_FALSE)
1640                *value = false;
1641        else
1642                return -1;
1643
1644        return 0;
1645}
1646
1647static int og_json_parse_sync_params(json_t *element,
1648                                     struct og_msg_params *params)
1649{
1650        const char *key;
1651        json_t *value;
1652        int err = 0;
1653
1654        json_object_foreach(element, key, value) {
1655                if (!strcmp(key, "sync")) {
1656                        err = og_json_parse_string(value, &params->sync_setup.sync);
1657                        params->flags |= OG_REST_PARAM_SYNC_SYNC;
1658                } else if (!strcmp(key, "diff")) {
1659                        err = og_json_parse_string(value, &params->sync_setup.diff);
1660                        params->flags |= OG_REST_PARAM_SYNC_DIFF;
1661                } else if (!strcmp(key, "remove")) {
1662                        err = og_json_parse_string(value, &params->sync_setup.remove);
1663                        params->flags |= OG_REST_PARAM_SYNC_REMOVE;
1664                } else if (!strcmp(key, "compress")) {
1665                        err = og_json_parse_string(value, &params->sync_setup.compress);
1666                        params->flags |= OG_REST_PARAM_SYNC_COMPRESS;
1667                } else if (!strcmp(key, "cleanup")) {
1668                        err = og_json_parse_string(value, &params->sync_setup.cleanup);
1669                        params->flags |= OG_REST_PARAM_SYNC_CLEANUP;
1670                } else if (!strcmp(key, "cache")) {
1671                        err = og_json_parse_string(value, &params->sync_setup.cache);
1672                        params->flags |= OG_REST_PARAM_SYNC_CACHE;
1673                } else if (!strcmp(key, "cleanup_cache")) {
1674                        err = og_json_parse_string(value, &params->sync_setup.cleanup_cache);
1675                        params->flags |= OG_REST_PARAM_SYNC_CLEANUP_CACHE;
1676                } else if (!strcmp(key, "remove_dst")) {
1677                        err = og_json_parse_string(value, &params->sync_setup.remove_dst);
1678                        params->flags |= OG_REST_PARAM_SYNC_REMOVE_DST;
1679                } else if (!strcmp(key, "diff_id")) {
1680                        err = og_json_parse_string(value, &params->sync_setup.diff_id);
1681                        params->flags |= OG_REST_PARAM_SYNC_DIFF_ID;
1682                } else if (!strcmp(key, "diff_name")) {
1683                        err = og_json_parse_string(value, &params->sync_setup.diff_name);
1684                        params->flags |= OG_REST_PARAM_SYNC_DIFF_NAME;
1685                } else if (!strcmp(key, "path")) {
1686                        err = og_json_parse_string(value, &params->sync_setup.path);
1687                        params->flags |= OG_REST_PARAM_SYNC_PATH;
1688                } else if (!strcmp(key, "method")) {
1689                        err = og_json_parse_string(value, &params->sync_setup.method);
1690                        params->flags |= OG_REST_PARAM_SYNC_METHOD;
1691                }
1692
1693                if (err != 0)
1694                        return err;
1695        }
1696        return err;
1697}
1698
1699#define OG_PARAM_PART_NUMBER                    (1UL << 0)
1700#define OG_PARAM_PART_CODE                      (1UL << 1)
1701#define OG_PARAM_PART_FILESYSTEM                (1UL << 2)
1702#define OG_PARAM_PART_SIZE                      (1UL << 3)
1703#define OG_PARAM_PART_FORMAT                    (1UL << 4)
1704#define OG_PARAM_PART_DISK                      (1UL << 5)
1705#define OG_PARAM_PART_OS                        (1UL << 6)
1706#define OG_PARAM_PART_USED_SIZE                 (1UL << 7)
1707
1708static int og_json_parse_partition(json_t *element,
1709                                   struct og_partition *part,
1710                                   uint64_t required_flags)
1711{
1712        uint64_t flags = 0UL;
1713        const char *key;
1714        json_t *value;
1715        int err = 0;
1716
1717        json_object_foreach(element, key, value) {
1718                if (!strcmp(key, "partition")) {
1719                        err = og_json_parse_string(value, &part->number);
1720                        flags |= OG_PARAM_PART_NUMBER;
1721                } else if (!strcmp(key, "code")) {
1722                        err = og_json_parse_string(value, &part->code);
1723                        flags |= OG_PARAM_PART_CODE;
1724                } else if (!strcmp(key, "filesystem")) {
1725                        err = og_json_parse_string(value, &part->filesystem);
1726                        flags |= OG_PARAM_PART_FILESYSTEM;
1727                } else if (!strcmp(key, "size")) {
1728                        err = og_json_parse_string(value, &part->size);
1729                        flags |= OG_PARAM_PART_SIZE;
1730                } else if (!strcmp(key, "format")) {
1731                        err = og_json_parse_string(value, &part->format);
1732                        flags |= OG_PARAM_PART_FORMAT;
1733                } else if (!strcmp(key, "disk")) {
1734                        err = og_json_parse_string(value, &part->disk);
1735                        flags |= OG_PARAM_PART_DISK;
1736                } else if (!strcmp(key, "os")) {
1737                        err = og_json_parse_string(value, &part->os);
1738                        flags |= OG_PARAM_PART_OS;
1739                } else if (!strcmp(key, "used_size")) {
1740                        err = og_json_parse_string(value, &part->used_size);
1741                        flags |= OG_PARAM_PART_USED_SIZE;
1742                }
1743
1744                if (err < 0)
1745                        return err;
1746        }
1747
1748        if (flags != required_flags)
1749                return -1;
1750
1751        return err;
1752}
1753
1754static int og_json_parse_partition_setup(json_t *element,
1755                                         struct og_msg_params *params)
1756{
1757        unsigned int i;
1758        json_t *k;
1759
1760        if (json_typeof(element) != JSON_ARRAY)
1761                return -1;
1762
1763        for (i = 0; i < json_array_size(element) && i < OG_PARTITION_MAX; ++i) {
1764                k = json_array_get(element, i);
1765
1766                if (json_typeof(k) != JSON_OBJECT)
1767                        return -1;
1768
1769                if (og_json_parse_partition(k, &params->partition_setup[i],
1770                                            OG_PARAM_PART_NUMBER |
1771                                            OG_PARAM_PART_CODE |
1772                                            OG_PARAM_PART_FILESYSTEM |
1773                                            OG_PARAM_PART_SIZE |
1774                                            OG_PARAM_PART_FORMAT) < 0)
1775                        return -1;
1776
1777                params->flags |= (OG_REST_PARAM_PART_0 << i);
1778        }
1779        return 0;
1780}
1781
1782static int og_json_parse_time_params(json_t *element,
1783                                     struct og_msg_params *params)
1784{
1785        const char *key;
1786        json_t *value;
1787        int err = 0;
1788
1789        json_object_foreach(element, key, value) {
1790                if (!strcmp(key, "years")) {
1791                        err = og_json_parse_uint(value, &params->time.years);
1792                        params->flags |= OG_REST_PARAM_TIME_YEARS;
1793                } else if (!strcmp(key, "months")) {
1794                        err = og_json_parse_uint(value, &params->time.months);
1795                        params->flags |= OG_REST_PARAM_TIME_MONTHS;
1796                } else if (!strcmp(key, "days")) {
1797                        err = og_json_parse_uint(value, &params->time.days);
1798                        params->flags |= OG_REST_PARAM_TIME_DAYS;
1799                } else if (!strcmp(key, "hours")) {
1800                        err = og_json_parse_uint(value, &params->time.hours);
1801                        params->flags |= OG_REST_PARAM_TIME_HOURS;
1802                } else if (!strcmp(key, "am_pm")) {
1803                        err = og_json_parse_uint(value, &params->time.am_pm);
1804                        params->flags |= OG_REST_PARAM_TIME_AM_PM;
1805                } else if (!strcmp(key, "minutes")) {
1806                        err = og_json_parse_uint(value, &params->time.minutes);
1807                        params->flags |= OG_REST_PARAM_TIME_MINUTES;
1808                }
1809                if (err != 0)
1810                        return err;
1811        }
1812
1813        return err;
1814}
1815
1816static const char *og_cmd_to_uri[OG_CMD_MAX] = {
1817        [OG_CMD_WOL]            = "wol",
1818        [OG_CMD_PROBE]          = "probe",
1819        [OG_CMD_SHELL_RUN]      = "shell/run",
1820        [OG_CMD_SESSION]        = "session",
1821        [OG_CMD_POWEROFF]       = "poweroff",
1822        [OG_CMD_REFRESH]        = "refresh",
1823        [OG_CMD_REBOOT]         = "reboot",
1824        [OG_CMD_STOP]           = "stop",
1825        [OG_CMD_HARDWARE]       = "hardware",
1826        [OG_CMD_SOFTWARE]       = "software",
1827        [OG_CMD_IMAGE_CREATE]   = "image/create",
1828        [OG_CMD_IMAGE_RESTORE]  = "image/restore",
1829        [OG_CMD_SETUP]          = "setup",
1830        [OG_CMD_RUN_SCHEDULE]   = "run/schedule",
1831};
1832
1833static bool og_client_is_busy(const struct og_client *cli,
1834                              enum og_cmd_type type)
1835{
1836        switch (type) {
1837        case OG_CMD_REBOOT:
1838        case OG_CMD_POWEROFF:
1839        case OG_CMD_STOP:
1840                break;
1841        default:
1842                if (cli->last_cmd != OG_CMD_UNSPEC)
1843                        return true;
1844                break;
1845        }
1846
1847        return false;
1848}
1849
1850static int og_send_request(enum og_rest_method method, enum og_cmd_type type,
1851                           const struct og_msg_params *params,
1852                           const json_t *data)
1853{
1854        const char *content_type = "Content-Type: application/json";
1855        char content [OG_MSG_REQUEST_MAXLEN - 700] = {};
1856        char buf[OG_MSG_REQUEST_MAXLEN] = {};
1857        unsigned int content_length;
1858        char method_str[5] = {};
1859        struct og_client *cli;
1860        const char *uri;
1861        unsigned int i;
1862        int client_sd;
1863
1864        if (method == OG_METHOD_GET)
1865                snprintf(method_str, 5, "GET");
1866        else if (method == OG_METHOD_POST)
1867                snprintf(method_str, 5, "POST");
1868        else
1869                return -1;
1870
1871        if (!data)
1872                content_length = 0;
1873        else
1874                content_length = json_dumpb(data, content,
1875                                            OG_MSG_REQUEST_MAXLEN - 700,
1876                                            JSON_COMPACT);
1877
1878        uri = og_cmd_to_uri[type];
1879        snprintf(buf, OG_MSG_REQUEST_MAXLEN,
1880                 "%s /%s HTTP/1.1\r\nContent-Length: %d\r\n%s\r\n\r\n%s",
1881                 method_str, uri, content_length, content_type, content);
1882
1883        for (i = 0; i < params->ips_array_len; i++) {
1884                cli = og_client_find(params->ips_array[i]);
1885                if (!cli)
1886                        continue;
1887
1888                if (og_client_is_busy(cli, type))
1889                        continue;
1890
1891                client_sd = cli->io.fd;
1892                if (client_sd < 0) {
1893                        syslog(LOG_INFO, "Client %s not conected\n",
1894                               params->ips_array[i]);
1895                        continue;
1896                }
1897
1898                if (send(client_sd, buf, strlen(buf), 0) < 0)
1899                        continue;
1900
1901                cli->last_cmd = type;
1902        }
1903
1904        return 0;
1905}
1906
1907static int og_cmd_post_clients(json_t *element, struct og_msg_params *params)
1908{
1909        const char *key;
1910        json_t *value;
1911        int err = 0;
1912
1913        if (json_typeof(element) != JSON_OBJECT)
1914                return -1;
1915
1916        json_object_foreach(element, key, value) {
1917                if (!strcmp(key, "clients"))
1918                        err = og_json_parse_clients(value, params);
1919
1920                if (err < 0)
1921                        break;
1922        }
1923
1924        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
1925                return -1;
1926
1927        return og_send_request(OG_METHOD_POST, OG_CMD_PROBE, params, NULL);
1928}
1929
1930struct og_buffer {
1931        char    *data;
1932        int     len;
1933};
1934
1935static int og_json_dump_clients(const char *buffer, size_t size, void *data)
1936{
1937        struct og_buffer *og_buffer = (struct og_buffer *)data;
1938
1939        memcpy(og_buffer->data + og_buffer->len, buffer, size);
1940        og_buffer->len += size;
1941
1942        return 0;
1943}
1944
1945static int og_cmd_get_clients(json_t *element, struct og_msg_params *params,
1946                              char *buffer_reply)
1947{
1948        json_t *root, *array, *addr, *state, *object;
1949        struct og_client *client;
1950        struct og_buffer og_buffer = {
1951                .data   = buffer_reply,
1952        };
1953
1954        array = json_array();
1955        if (!array)
1956                return -1;
1957
1958        list_for_each_entry(client, &client_list, list) {
1959                if (!client->agent)
1960                        continue;
1961
1962                object = json_object();
1963                if (!object) {
1964                        json_decref(array);
1965                        return -1;
1966                }
1967                addr = json_string(inet_ntoa(client->addr.sin_addr));
1968                if (!addr) {
1969                        json_decref(object);
1970                        json_decref(array);
1971                        return -1;
1972                }
1973                json_object_set_new(object, "addr", addr);
1974                state = json_string(og_client_status(client));
1975                if (!state) {
1976                        json_decref(object);
1977                        json_decref(array);
1978                        return -1;
1979                }
1980                json_object_set_new(object, "state", state);
1981                json_array_append_new(array, object);
1982        }
1983        root = json_pack("{s:o}", "clients", array);
1984        if (!root) {
1985                json_decref(array);
1986                return -1;
1987        }
1988
1989        json_dump_callback(root, og_json_dump_clients, &og_buffer, 0);
1990        json_decref(root);
1991
1992        return 0;
1993}
1994
1995static int og_json_parse_target(json_t *element, struct og_msg_params *params)
1996{
1997        const char *key;
1998        json_t *value;
1999
2000        if (json_typeof(element) != JSON_OBJECT) {
2001                return -1;
2002        }
2003
2004        json_object_foreach(element, key, value) {
2005                if (!strcmp(key, "addr")) {
2006                        if (json_typeof(value) != JSON_STRING)
2007                                return -1;
2008
2009                        params->ips_array[params->ips_array_len] =
2010                                json_string_value(value);
2011
2012                        params->flags |= OG_REST_PARAM_ADDR;
2013                } else if (!strcmp(key, "mac")) {
2014                        if (json_typeof(value) != JSON_STRING)
2015                                return -1;
2016
2017                        params->mac_array[params->ips_array_len] =
2018                                json_string_value(value);
2019
2020                        params->flags |= OG_REST_PARAM_MAC;
2021                }
2022        }
2023
2024        return 0;
2025}
2026
2027static int og_json_parse_targets(json_t *element, struct og_msg_params *params)
2028{
2029        unsigned int i;
2030        json_t *k;
2031        int err;
2032
2033        if (json_typeof(element) != JSON_ARRAY)
2034                return -1;
2035
2036        for (i = 0; i < json_array_size(element); i++) {
2037                k = json_array_get(element, i);
2038
2039                if (json_typeof(k) != JSON_OBJECT)
2040                        return -1;
2041
2042                err = og_json_parse_target(k, params);
2043                if (err < 0)
2044                        return err;
2045
2046                params->ips_array_len++;
2047        }
2048        return 0;
2049}
2050
2051static int og_json_parse_type(json_t *element, struct og_msg_params *params)
2052{
2053        const char *type;
2054
2055        if (json_typeof(element) != JSON_STRING)
2056                return -1;
2057
2058        params->wol_type = json_string_value(element);
2059
2060        type = json_string_value(element);
2061        if (!strcmp(type, "unicast"))
2062                params->wol_type = "2";
2063        else if (!strcmp(type, "broadcast"))
2064                params->wol_type = "1";
2065
2066        params->flags |= OG_REST_PARAM_WOL_TYPE;
2067
2068        return 0;
2069}
2070
2071static int og_cmd_wol(json_t *element, struct og_msg_params *params)
2072{
2073        const char *key;
2074        json_t *value;
2075        int err = 0;
2076
2077        if (json_typeof(element) != JSON_OBJECT)
2078                return -1;
2079
2080        json_object_foreach(element, key, value) {
2081                if (!strcmp(key, "clients")) {
2082                        err = og_json_parse_targets(value, params);
2083                } else if (!strcmp(key, "type")) {
2084                        err = og_json_parse_type(value, params);
2085                }
2086
2087                if (err < 0)
2088                        break;
2089        }
2090
2091        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
2092                                            OG_REST_PARAM_MAC |
2093                                            OG_REST_PARAM_WOL_TYPE))
2094                return -1;
2095
2096        if (!Levanta((char **)params->ips_array, (char **)params->mac_array,
2097                     params->ips_array_len, (char *)params->wol_type))
2098                return -1;
2099
2100        return 0;
2101}
2102
2103static int og_json_parse_run(json_t *element, struct og_msg_params *params)
2104{
2105        if (json_typeof(element) != JSON_STRING)
2106                return -1;
2107
2108        snprintf(params->run_cmd, sizeof(params->run_cmd), "%s",
2109                 json_string_value(element));
2110
2111        params->flags |= OG_REST_PARAM_RUN_CMD;
2112
2113        return 0;
2114}
2115
2116static int og_cmd_run_post(json_t *element, struct og_msg_params *params)
2117{
2118        json_t *value, *clients;
2119        const char *key;
2120        unsigned int i;
2121        int err = 0;
2122
2123        if (json_typeof(element) != JSON_OBJECT)
2124                return -1;
2125
2126        json_object_foreach(element, key, value) {
2127                if (!strcmp(key, "clients"))
2128                        err = og_json_parse_clients(value, params);
2129                else if (!strcmp(key, "run"))
2130                        err = og_json_parse_run(value, params);
2131                else if (!strcmp(key, "echo")) {
2132                        err = og_json_parse_bool(value, &params->echo);
2133                        params->flags |= OG_REST_PARAM_ECHO;
2134                }
2135
2136                if (err < 0)
2137                        break;
2138        }
2139
2140        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
2141                                            OG_REST_PARAM_RUN_CMD |
2142                                            OG_REST_PARAM_ECHO))
2143                return -1;
2144
2145        clients = json_copy(element);
2146        json_object_del(clients, "clients");
2147
2148        err = og_send_request(OG_METHOD_POST, OG_CMD_SHELL_RUN, params, clients);
2149        if (err < 0)
2150                return err;
2151
2152        for (i = 0; i < params->ips_array_len; i++) {
2153                char filename[4096];
2154                FILE *f;
2155
2156                sprintf(filename, "/tmp/_Seconsola_%s", params->ips_array[i]);
2157                f = fopen(filename, "wt");
2158                fclose(f);
2159        }
2160
2161        return 0;
2162}
2163
2164static int og_cmd_run_get(json_t *element, struct og_msg_params *params,
2165                          char *buffer_reply)
2166{
2167        struct og_buffer og_buffer = {
2168                .data   = buffer_reply,
2169        };
2170        json_t *root, *value, *array;
2171        const char *key;
2172        unsigned int i;
2173        int err = 0;
2174
2175        if (json_typeof(element) != JSON_OBJECT)
2176                return -1;
2177
2178        json_object_foreach(element, key, value) {
2179                if (!strcmp(key, "clients"))
2180                        err = og_json_parse_clients(value, params);
2181
2182                if (err < 0)
2183                        return err;
2184        }
2185
2186        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
2187                return -1;
2188
2189        array = json_array();
2190        if (!array)
2191                return -1;
2192
2193        for (i = 0; i < params->ips_array_len; i++) {
2194                json_t *object, *output, *addr;
2195                char data[4096] = {};
2196                char filename[4096];
2197                int fd, numbytes;
2198
2199                sprintf(filename, "/tmp/_Seconsola_%s", params->ips_array[i]);
2200
2201                fd = open(filename, O_RDONLY);
2202                if (!fd)
2203                        return -1;
2204
2205                numbytes = read(fd, data, sizeof(data));
2206                if (numbytes < 0) {
2207                        close(fd);
2208                        return -1;
2209                }
2210                data[sizeof(data) - 1] = '\0';
2211                close(fd);
2212
2213                object = json_object();
2214                if (!object) {
2215                        json_decref(array);
2216                        return -1;
2217                }
2218                addr = json_string(params->ips_array[i]);
2219                if (!addr) {
2220                        json_decref(object);
2221                        json_decref(array);
2222                        return -1;
2223                }
2224                json_object_set_new(object, "addr", addr);
2225
2226                output = json_string(data);
2227                if (!output) {
2228                        json_decref(object);
2229                        json_decref(array);
2230                        return -1;
2231                }
2232                json_object_set_new(object, "output", output);
2233
2234                json_array_append_new(array, object);
2235        }
2236
2237        root = json_pack("{s:o}", "clients", array);
2238        if (!root)
2239                return -1;
2240
2241        json_dump_callback(root, og_json_dump_clients, &og_buffer, 0);
2242        json_decref(root);
2243
2244        return 0;
2245}
2246
2247static int og_cmd_session(json_t *element, struct og_msg_params *params)
2248{
2249        json_t *clients, *value;
2250        const char *key;
2251        int err = 0;
2252
2253        if (json_typeof(element) != JSON_OBJECT)
2254                return -1;
2255
2256        json_object_foreach(element, key, value) {
2257                if (!strcmp(key, "clients")) {
2258                        err = og_json_parse_clients(value, params);
2259                } else if (!strcmp(key, "disk")) {
2260                        err = og_json_parse_string(value, &params->disk);
2261                        params->flags |= OG_REST_PARAM_DISK;
2262                } else if (!strcmp(key, "partition")) {
2263                        err = og_json_parse_string(value, &params->partition);
2264                        params->flags |= OG_REST_PARAM_PARTITION;
2265                }
2266
2267                if (err < 0)
2268                        return err;
2269        }
2270
2271        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
2272                                            OG_REST_PARAM_DISK |
2273                                            OG_REST_PARAM_PARTITION))
2274                return -1;
2275
2276        clients = json_copy(element);
2277        json_object_del(clients, "clients");
2278
2279        return og_send_request(OG_METHOD_POST, OG_CMD_SESSION, params, clients);
2280}
2281
2282static int og_cmd_poweroff(json_t *element, struct og_msg_params *params)
2283{
2284        const char *key;
2285        json_t *value;
2286        int err = 0;
2287
2288        if (json_typeof(element) != JSON_OBJECT)
2289                return -1;
2290
2291        json_object_foreach(element, key, value) {
2292                if (!strcmp(key, "clients"))
2293                        err = og_json_parse_clients(value, params);
2294
2295                if (err < 0)
2296                        break;
2297        }
2298
2299        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
2300                return -1;
2301
2302        return og_send_request(OG_METHOD_POST, OG_CMD_POWEROFF, params, NULL);
2303}
2304
2305static int og_cmd_refresh(json_t *element, struct og_msg_params *params)
2306{
2307        const char *key;
2308        json_t *value;
2309        int err = 0;
2310
2311        if (json_typeof(element) != JSON_OBJECT)
2312                return -1;
2313
2314        json_object_foreach(element, key, value) {
2315                if (!strcmp(key, "clients"))
2316                        err = og_json_parse_clients(value, params);
2317
2318                if (err < 0)
2319                        break;
2320        }
2321
2322        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
2323                return -1;
2324
2325        return og_send_request(OG_METHOD_GET, OG_CMD_REFRESH, params, NULL);
2326}
2327
2328static int og_cmd_reboot(json_t *element, struct og_msg_params *params)
2329{
2330        const char *key;
2331        json_t *value;
2332        int err = 0;
2333
2334        if (json_typeof(element) != JSON_OBJECT)
2335                return -1;
2336
2337        json_object_foreach(element, key, value) {
2338                if (!strcmp(key, "clients"))
2339                        err = og_json_parse_clients(value, params);
2340
2341                if (err < 0)
2342                        break;
2343        }
2344
2345        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
2346                return -1;
2347
2348        return og_send_request(OG_METHOD_POST, OG_CMD_REBOOT, params, NULL);
2349}
2350
2351static int og_cmd_stop(json_t *element, struct og_msg_params *params)
2352{
2353        const char *key;
2354        json_t *value;
2355        int err = 0;
2356
2357        if (json_typeof(element) != JSON_OBJECT)
2358                return -1;
2359
2360        json_object_foreach(element, key, value) {
2361                if (!strcmp(key, "clients"))
2362                        err = og_json_parse_clients(value, params);
2363
2364                if (err < 0)
2365                        break;
2366        }
2367
2368        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
2369                return -1;
2370
2371        return og_send_request(OG_METHOD_POST, OG_CMD_STOP, params, NULL);
2372}
2373
2374static int og_cmd_hardware(json_t *element, struct og_msg_params *params)
2375{
2376        const char *key;
2377        json_t *value;
2378        int err = 0;
2379
2380        if (json_typeof(element) != JSON_OBJECT)
2381                return -1;
2382
2383        json_object_foreach(element, key, value) {
2384                if (!strcmp(key, "clients"))
2385                        err = og_json_parse_clients(value, params);
2386
2387                if (err < 0)
2388                        break;
2389        }
2390
2391        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
2392                return -1;
2393
2394        return og_send_request(OG_METHOD_GET, OG_CMD_HARDWARE, params, NULL);
2395}
2396
2397static int og_cmd_software(json_t *element, struct og_msg_params *params)
2398{
2399        json_t *clients, *value;
2400        const char *key;
2401        int err = 0;
2402
2403        if (json_typeof(element) != JSON_OBJECT)
2404                return -1;
2405
2406        json_object_foreach(element, key, value) {
2407                if (!strcmp(key, "clients"))
2408                        err = og_json_parse_clients(value, params);
2409                else if (!strcmp(key, "disk")) {
2410                        err = og_json_parse_string(value, &params->disk);
2411                        params->flags |= OG_REST_PARAM_DISK;
2412                }
2413                else if (!strcmp(key, "partition")) {
2414                        err = og_json_parse_string(value, &params->partition);
2415                        params->flags |= OG_REST_PARAM_PARTITION;
2416                }
2417
2418                if (err < 0)
2419                        break;
2420        }
2421
2422        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
2423                                            OG_REST_PARAM_DISK |
2424                                            OG_REST_PARAM_PARTITION))
2425                return -1;
2426
2427        clients = json_copy(element);
2428        json_object_del(clients, "clients");
2429
2430        return og_send_request(OG_METHOD_POST, OG_CMD_SOFTWARE, params, clients);
2431}
2432
2433static int og_cmd_create_image(json_t *element, struct og_msg_params *params)
2434{
2435        json_t *value, *clients;
2436        const char *key;
2437        int err = 0;
2438
2439        if (json_typeof(element) != JSON_OBJECT)
2440                return -1;
2441
2442        json_object_foreach(element, key, value) {
2443                if (!strcmp(key, "disk")) {
2444                        err = og_json_parse_string(value, &params->disk);
2445                        params->flags |= OG_REST_PARAM_DISK;
2446                } else if (!strcmp(key, "partition")) {
2447                        err = og_json_parse_string(value, &params->partition);
2448                        params->flags |= OG_REST_PARAM_PARTITION;
2449                } else if (!strcmp(key, "name")) {
2450                        err = og_json_parse_string(value, &params->name);
2451                        params->flags |= OG_REST_PARAM_NAME;
2452                } else if (!strcmp(key, "repository")) {
2453                        err = og_json_parse_string(value, &params->repository);
2454                        params->flags |= OG_REST_PARAM_REPO;
2455                } else if (!strcmp(key, "clients")) {
2456                        err = og_json_parse_clients(value, params);
2457                } else if (!strcmp(key, "id")) {
2458                        err = og_json_parse_string(value, &params->id);
2459                        params->flags |= OG_REST_PARAM_ID;
2460                } else if (!strcmp(key, "code")) {
2461                        err = og_json_parse_string(value, &params->code);
2462                        params->flags |= OG_REST_PARAM_CODE;
2463                }
2464
2465                if (err < 0)
2466                        break;
2467        }
2468
2469        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
2470                                            OG_REST_PARAM_DISK |
2471                                            OG_REST_PARAM_PARTITION |
2472                                            OG_REST_PARAM_CODE |
2473                                            OG_REST_PARAM_ID |
2474                                            OG_REST_PARAM_NAME |
2475                                            OG_REST_PARAM_REPO))
2476                return -1;
2477
2478        clients = json_copy(element);
2479        json_object_del(clients, "clients");
2480
2481        return og_send_request(OG_METHOD_POST, OG_CMD_IMAGE_CREATE, params,
2482                               clients);
2483}
2484
2485static int og_cmd_restore_image(json_t *element, struct og_msg_params *params)
2486{
2487        json_t *clients, *value;
2488        const char *key;
2489        int err = 0;
2490
2491        if (json_typeof(element) != JSON_OBJECT)
2492                return -1;
2493
2494        json_object_foreach(element, key, value) {
2495                if (!strcmp(key, "disk")) {
2496                        err = og_json_parse_string(value, &params->disk);
2497                        params->flags |= OG_REST_PARAM_DISK;
2498                } else if (!strcmp(key, "partition")) {
2499                        err = og_json_parse_string(value, &params->partition);
2500                        params->flags |= OG_REST_PARAM_PARTITION;
2501                } else if (!strcmp(key, "name")) {
2502                        err = og_json_parse_string(value, &params->name);
2503                        params->flags |= OG_REST_PARAM_NAME;
2504                } else if (!strcmp(key, "repository")) {
2505                        err = og_json_parse_string(value, &params->repository);
2506                        params->flags |= OG_REST_PARAM_REPO;
2507                } else if (!strcmp(key, "clients")) {
2508                        err = og_json_parse_clients(value, params);
2509                } else if (!strcmp(key, "type")) {
2510                        err = og_json_parse_string(value, &params->type);
2511                        params->flags |= OG_REST_PARAM_TYPE;
2512                } else if (!strcmp(key, "profile")) {
2513                        err = og_json_parse_string(value, &params->profile);
2514                        params->flags |= OG_REST_PARAM_PROFILE;
2515                } else if (!strcmp(key, "id")) {
2516                        err = og_json_parse_string(value, &params->id);
2517                        params->flags |= OG_REST_PARAM_ID;
2518                }
2519
2520                if (err < 0)
2521                        break;
2522        }
2523
2524        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
2525                                            OG_REST_PARAM_DISK |
2526                                            OG_REST_PARAM_PARTITION |
2527                                            OG_REST_PARAM_NAME |
2528                                            OG_REST_PARAM_REPO |
2529                                            OG_REST_PARAM_TYPE |
2530                                            OG_REST_PARAM_PROFILE |
2531                                            OG_REST_PARAM_ID))
2532                return -1;
2533
2534        clients = json_copy(element);
2535        json_object_del(clients, "clients");
2536
2537        return og_send_request(OG_METHOD_POST, OG_CMD_IMAGE_RESTORE, params,
2538                               clients);
2539}
2540
2541static int og_cmd_setup(json_t *element, struct og_msg_params *params)
2542{
2543        json_t *value, *clients;
2544        const char *key;
2545        int err = 0;
2546
2547        if (json_typeof(element) != JSON_OBJECT)
2548                return -1;
2549
2550        json_object_foreach(element, key, value) {
2551                if (!strcmp(key, "clients")) {
2552                        err = og_json_parse_clients(value, params);
2553                } else if (!strcmp(key, "disk")) {
2554                        err = og_json_parse_string(value, &params->disk);
2555                        params->flags |= OG_REST_PARAM_DISK;
2556                } else if (!strcmp(key, "cache")) {
2557                        err = og_json_parse_string(value, &params->cache);
2558                        params->flags |= OG_REST_PARAM_CACHE;
2559                } else if (!strcmp(key, "cache_size")) {
2560                        err = og_json_parse_string(value, &params->cache_size);
2561                        params->flags |= OG_REST_PARAM_CACHE_SIZE;
2562                } else if (!strcmp(key, "partition_setup")) {
2563                        err = og_json_parse_partition_setup(value, params);
2564                }
2565
2566                if (err < 0)
2567                        break;
2568        }
2569
2570        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
2571                                            OG_REST_PARAM_DISK |
2572                                            OG_REST_PARAM_CACHE |
2573                                            OG_REST_PARAM_CACHE_SIZE |
2574                                            OG_REST_PARAM_PART_0 |
2575                                            OG_REST_PARAM_PART_1 |
2576                                            OG_REST_PARAM_PART_2 |
2577                                            OG_REST_PARAM_PART_3))
2578                return -1;
2579
2580        clients = json_copy(element);
2581        json_object_del(clients, "clients");
2582
2583        return og_send_request(OG_METHOD_POST, OG_CMD_SETUP, params, clients);
2584}
2585
2586static int og_cmd_run_schedule(json_t *element, struct og_msg_params *params)
2587{
2588        const char *key;
2589        json_t *value;
2590        int err = 0;
2591
2592        json_object_foreach(element, key, value) {
2593                if (!strcmp(key, "clients"))
2594                        err = og_json_parse_clients(value, params);
2595
2596                if (err < 0)
2597                        break;
2598        }
2599
2600        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
2601                return -1;
2602
2603        return og_send_request(OG_METHOD_GET, OG_CMD_RUN_SCHEDULE, params,
2604                               NULL);
2605}
2606
2607static int og_cmd_create_basic_image(json_t *element, struct og_msg_params *params)
2608{
2609        char buf[4096] = {};
2610        int err = 0, len;
2611        const char *key;
2612        json_t *value;
2613        TRAMA *msg;
2614
2615        if (json_typeof(element) != JSON_OBJECT)
2616                return -1;
2617
2618        json_object_foreach(element, key, value) {
2619                if (!strcmp(key, "clients")) {
2620                        err = og_json_parse_clients(value, params);
2621                } else if (!strcmp(key, "disk")) {
2622                        err = og_json_parse_string(value, &params->disk);
2623                        params->flags |= OG_REST_PARAM_DISK;
2624                } else if (!strcmp(key, "partition")) {
2625                        err = og_json_parse_string(value, &params->partition);
2626                        params->flags |= OG_REST_PARAM_PARTITION;
2627                } else if (!strcmp(key, "code")) {
2628                        err = og_json_parse_string(value, &params->code);
2629                        params->flags |= OG_REST_PARAM_CODE;
2630                } else if (!strcmp(key, "id")) {
2631                        err = og_json_parse_string(value, &params->id);
2632                        params->flags |= OG_REST_PARAM_ID;
2633                } else if (!strcmp(key, "name")) {
2634                        err = og_json_parse_string(value, &params->name);
2635                        params->flags |= OG_REST_PARAM_NAME;
2636                } else if (!strcmp(key, "repository")) {
2637                        err = og_json_parse_string(value, &params->repository);
2638                        params->flags |= OG_REST_PARAM_REPO;
2639                } else if (!strcmp(key, "sync_params")) {
2640                        err = og_json_parse_sync_params(value, params);
2641                }
2642
2643                if (err < 0)
2644                        break;
2645        }
2646
2647        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
2648                                            OG_REST_PARAM_DISK |
2649                                            OG_REST_PARAM_PARTITION |
2650                                            OG_REST_PARAM_CODE |
2651                                            OG_REST_PARAM_ID |
2652                                            OG_REST_PARAM_NAME |
2653                                            OG_REST_PARAM_REPO |
2654                                            OG_REST_PARAM_SYNC_SYNC |
2655                                            OG_REST_PARAM_SYNC_DIFF |
2656                                            OG_REST_PARAM_SYNC_REMOVE |
2657                                            OG_REST_PARAM_SYNC_COMPRESS |
2658                                            OG_REST_PARAM_SYNC_CLEANUP |
2659                                            OG_REST_PARAM_SYNC_CACHE |
2660                                            OG_REST_PARAM_SYNC_CLEANUP_CACHE |
2661                                            OG_REST_PARAM_SYNC_REMOVE_DST))
2662                return -1;
2663
2664        len = snprintf(buf, sizeof(buf),
2665                       "nfn=CrearImagenBasica\rdsk=%s\rpar=%s\rcpt=%s\ridi=%s\r"
2666                       "nci=%s\ripr=%s\rrti=\rmsy=%s\rwhl=%s\reli=%s\rcmp=%s\rbpi=%s\r"
2667                       "cpc=%s\rbpc=%s\rnba=%s\r",
2668                       params->disk, params->partition, params->code, params->id,
2669                       params->name, params->repository, params->sync_setup.sync,
2670                       params->sync_setup.diff, params->sync_setup.remove,
2671                       params->sync_setup.compress, params->sync_setup.cleanup,
2672                       params->sync_setup.cache, params->sync_setup.cleanup_cache,
2673                       params->sync_setup.remove_dst);
2674
2675        msg = og_msg_alloc(buf, len);
2676        if (!msg)
2677                return -1;
2678
2679        og_send_cmd((char **)params->ips_array, params->ips_array_len,
2680                    CLIENTE_OCUPADO, msg);
2681
2682        og_msg_free(msg);
2683
2684        return 0;
2685}
2686
2687static int og_cmd_create_incremental_image(json_t *element, struct og_msg_params *params)
2688{
2689        char buf[4096] = {};
2690        int err = 0, len;
2691        const char *key;
2692        json_t *value;
2693        TRAMA *msg;
2694
2695        if (json_typeof(element) != JSON_OBJECT)
2696                return -1;
2697
2698        json_object_foreach(element, key, value) {
2699                if (!strcmp(key, "clients"))
2700                        err = og_json_parse_clients(value, params);
2701                else if (!strcmp(key, "disk")) {
2702                        err = og_json_parse_string(value, &params->disk);
2703                        params->flags |= OG_REST_PARAM_DISK;
2704                } else if (!strcmp(key, "partition")) {
2705                        err = og_json_parse_string(value, &params->partition);
2706                        params->flags |= OG_REST_PARAM_PARTITION;
2707                } else if (!strcmp(key, "id")) {
2708                        err = og_json_parse_string(value, &params->id);
2709                        params->flags |= OG_REST_PARAM_ID;
2710                } else if (!strcmp(key, "name")) {
2711                        err = og_json_parse_string(value, &params->name);
2712                        params->flags |= OG_REST_PARAM_NAME;
2713                } else if (!strcmp(key, "repository")) {
2714                        err = og_json_parse_string(value, &params->repository);
2715                        params->flags |= OG_REST_PARAM_REPO;
2716                } else if (!strcmp(key, "sync_params")) {
2717                        err = og_json_parse_sync_params(value, params);
2718                }
2719
2720                if (err < 0)
2721                        break;
2722        }
2723
2724        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
2725                                            OG_REST_PARAM_DISK |
2726                                            OG_REST_PARAM_PARTITION |
2727                                            OG_REST_PARAM_ID |
2728                                            OG_REST_PARAM_NAME |
2729                                            OG_REST_PARAM_REPO |
2730                                            OG_REST_PARAM_SYNC_SYNC |
2731                                            OG_REST_PARAM_SYNC_PATH |
2732                                            OG_REST_PARAM_SYNC_DIFF |
2733                                            OG_REST_PARAM_SYNC_DIFF_ID |
2734                                            OG_REST_PARAM_SYNC_DIFF_NAME |
2735                                            OG_REST_PARAM_SYNC_REMOVE |
2736                                            OG_REST_PARAM_SYNC_COMPRESS |
2737                                            OG_REST_PARAM_SYNC_CLEANUP |
2738                                            OG_REST_PARAM_SYNC_CACHE |
2739                                            OG_REST_PARAM_SYNC_CLEANUP_CACHE |
2740                                            OG_REST_PARAM_SYNC_REMOVE_DST))
2741                return -1;
2742
2743        len = snprintf(buf, sizeof(buf),
2744                       "nfn=CrearSoftIncremental\rdsk=%s\rpar=%s\ridi=%s\rnci=%s\r"
2745                       "rti=%s\ripr=%s\ridf=%s\rncf=%s\rmsy=%s\rwhl=%s\reli=%s\rcmp=%s\r"
2746                       "bpi=%s\rcpc=%s\rbpc=%s\rnba=%s\r",
2747                       params->disk, params->partition, params->id, params->name,
2748                       params->sync_setup.path, params->repository, params->sync_setup.diff_id,
2749                       params->sync_setup.diff_name, params->sync_setup.sync,
2750                       params->sync_setup.diff, params->sync_setup.remove_dst,
2751                       params->sync_setup.compress, params->sync_setup.cleanup,
2752                       params->sync_setup.cache, params->sync_setup.cleanup_cache,
2753                       params->sync_setup.remove_dst);
2754
2755        msg = og_msg_alloc(buf, len);
2756        if (!msg)
2757                return -1;
2758
2759        og_send_cmd((char **)params->ips_array, params->ips_array_len,
2760                    CLIENTE_OCUPADO, msg);
2761
2762        og_msg_free(msg);
2763
2764        return 0;
2765}
2766
2767static int og_cmd_restore_basic_image(json_t *element, struct og_msg_params *params)
2768{
2769        char buf[4096] = {};
2770        int err = 0, len;
2771        const char *key;
2772        json_t *value;
2773        TRAMA *msg;
2774
2775        if (json_typeof(element) != JSON_OBJECT)
2776                return -1;
2777
2778        json_object_foreach(element, key, value) {
2779                if (!strcmp(key, "clients")) {
2780                        err = og_json_parse_clients(value, params);
2781                } else if (!strcmp(key, "disk")) {
2782                        err = og_json_parse_string(value, &params->disk);
2783                        params->flags |= OG_REST_PARAM_DISK;
2784                } else if (!strcmp(key, "partition")) {
2785                        err = og_json_parse_string(value, &params->partition);
2786                        params->flags |= OG_REST_PARAM_PARTITION;
2787                } else if (!strcmp(key, "id")) {
2788                        err = og_json_parse_string(value, &params->id);
2789                        params->flags |= OG_REST_PARAM_ID;
2790                } else if (!strcmp(key, "name")) {
2791                        err = og_json_parse_string(value, &params->name);
2792                        params->flags |= OG_REST_PARAM_NAME;
2793                } else if (!strcmp(key, "repository")) {
2794                        err = og_json_parse_string(value, &params->repository);
2795                        params->flags |= OG_REST_PARAM_REPO;
2796                } else if (!strcmp(key, "profile")) {
2797                        err = og_json_parse_string(value, &params->profile);
2798                        params->flags |= OG_REST_PARAM_PROFILE;
2799                } else if (!strcmp(key, "type")) {
2800                        err = og_json_parse_string(value, &params->type);
2801                        params->flags |= OG_REST_PARAM_TYPE;
2802                } else if (!strcmp(key, "sync_params")) {
2803                        err = og_json_parse_sync_params(value, params);
2804                }
2805
2806                if (err < 0)
2807                        break;
2808        }
2809
2810        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
2811                                            OG_REST_PARAM_DISK |
2812                                            OG_REST_PARAM_PARTITION |
2813                                            OG_REST_PARAM_ID |
2814                                            OG_REST_PARAM_NAME |
2815                                            OG_REST_PARAM_REPO |
2816                                            OG_REST_PARAM_PROFILE |
2817                                            OG_REST_PARAM_TYPE |
2818                                            OG_REST_PARAM_SYNC_PATH |
2819                                            OG_REST_PARAM_SYNC_METHOD |
2820                                            OG_REST_PARAM_SYNC_SYNC |
2821                                            OG_REST_PARAM_SYNC_DIFF |
2822                                            OG_REST_PARAM_SYNC_REMOVE |
2823                                            OG_REST_PARAM_SYNC_COMPRESS |
2824                                            OG_REST_PARAM_SYNC_CLEANUP |
2825                                            OG_REST_PARAM_SYNC_CACHE |
2826                                            OG_REST_PARAM_SYNC_CLEANUP_CACHE |
2827                                            OG_REST_PARAM_SYNC_REMOVE_DST))
2828                return -1;
2829
2830        len = snprintf(buf, sizeof(buf),
2831                       "nfn=RestaurarImagenBasica\rdsk=%s\rpar=%s\ridi=%s\rnci=%s\r"
2832                           "ipr=%s\rifs=%s\rrti=%s\rmet=%s\rmsy=%s\rtpt=%s\rwhl=%s\r"
2833                           "eli=%s\rcmp=%s\rbpi=%s\rcpc=%s\rbpc=%s\rnba=%s\r",
2834                       params->disk, params->partition, params->id, params->name,
2835                           params->repository, params->profile, params->sync_setup.path,
2836                           params->sync_setup.method, params->sync_setup.sync, params->type,
2837                           params->sync_setup.diff, params->sync_setup.remove,
2838                       params->sync_setup.compress, params->sync_setup.cleanup,
2839                       params->sync_setup.cache, params->sync_setup.cleanup_cache,
2840                       params->sync_setup.remove_dst);
2841
2842        msg = og_msg_alloc(buf, len);
2843        if (!msg)
2844                return -1;
2845
2846        og_send_cmd((char **)params->ips_array, params->ips_array_len,
2847                    CLIENTE_OCUPADO, msg);
2848
2849        og_msg_free(msg);
2850
2851        return 0;
2852}
2853
2854static int og_cmd_restore_incremental_image(json_t *element, struct og_msg_params *params)
2855{
2856        char buf[4096] = {};
2857        int err = 0, len;
2858        const char *key;
2859        json_t *value;
2860        TRAMA *msg;
2861
2862        if (json_typeof(element) != JSON_OBJECT)
2863                return -1;
2864
2865        json_object_foreach(element, key, value) {
2866                if (!strcmp(key, "clients")) {
2867                        err = og_json_parse_clients(value, params);
2868                } else if (!strcmp(key, "disk")) {
2869                        err = og_json_parse_string(value, &params->disk);
2870                        params->flags |= OG_REST_PARAM_DISK;
2871                } else if (!strcmp(key, "partition")) {
2872                        err = og_json_parse_string(value, &params->partition);
2873                        params->flags |= OG_REST_PARAM_PARTITION;
2874                } else if (!strcmp(key, "id")) {
2875                        err = og_json_parse_string(value, &params->id);
2876                        params->flags |= OG_REST_PARAM_ID;
2877                } else if (!strcmp(key, "name")) {
2878                        err = og_json_parse_string(value, &params->name);
2879                        params->flags |= OG_REST_PARAM_NAME;
2880                } else if (!strcmp(key, "repository")) {
2881                        err = og_json_parse_string(value, &params->repository);
2882                        params->flags |= OG_REST_PARAM_REPO;
2883                } else if (!strcmp(key, "profile")) {
2884                        err = og_json_parse_string(value, &params->profile);
2885                        params->flags |= OG_REST_PARAM_PROFILE;
2886                } else if (!strcmp(key, "type")) {
2887                        err = og_json_parse_string(value, &params->type);
2888                        params->flags |= OG_REST_PARAM_TYPE;
2889                } else if (!strcmp(key, "sync_params")) {
2890                        err = og_json_parse_sync_params(value, params);
2891                }
2892
2893                if (err < 0)
2894                        break;
2895        }
2896
2897        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
2898                                            OG_REST_PARAM_DISK |
2899                                            OG_REST_PARAM_PARTITION |
2900                                            OG_REST_PARAM_ID |
2901                                            OG_REST_PARAM_NAME |
2902                                            OG_REST_PARAM_REPO |
2903                                            OG_REST_PARAM_PROFILE |
2904                                            OG_REST_PARAM_TYPE |
2905                                            OG_REST_PARAM_SYNC_DIFF_ID |
2906                                            OG_REST_PARAM_SYNC_DIFF_NAME |
2907                                            OG_REST_PARAM_SYNC_PATH |
2908                                            OG_REST_PARAM_SYNC_METHOD |
2909                                            OG_REST_PARAM_SYNC_SYNC |
2910                                            OG_REST_PARAM_SYNC_DIFF |
2911                                            OG_REST_PARAM_SYNC_REMOVE |
2912                                            OG_REST_PARAM_SYNC_COMPRESS |
2913                                            OG_REST_PARAM_SYNC_CLEANUP |
2914                                            OG_REST_PARAM_SYNC_CACHE |
2915                                            OG_REST_PARAM_SYNC_CLEANUP_CACHE |
2916                                            OG_REST_PARAM_SYNC_REMOVE_DST))
2917                return -1;
2918
2919        len = snprintf(buf, sizeof(buf),
2920                       "nfn=RestaurarSoftIncremental\rdsk=%s\rpar=%s\ridi=%s\rnci=%s\r"
2921                           "ipr=%s\rifs=%s\ridf=%s\rncf=%s\rrti=%s\rmet=%s\rmsy=%s\r"
2922                           "tpt=%s\rwhl=%s\reli=%s\rcmp=%s\rbpi=%s\rcpc=%s\rbpc=%s\r"
2923                           "nba=%s\r",
2924                       params->disk, params->partition, params->id, params->name,
2925                           params->repository, params->profile, params->sync_setup.diff_id,
2926                           params->sync_setup.diff_name, params->sync_setup.path,
2927                           params->sync_setup.method, params->sync_setup.sync, params->type,
2928                           params->sync_setup.diff, params->sync_setup.remove,
2929                       params->sync_setup.compress, params->sync_setup.cleanup,
2930                       params->sync_setup.cache, params->sync_setup.cleanup_cache,
2931                       params->sync_setup.remove_dst);
2932
2933        msg = og_msg_alloc(buf, len);
2934        if (!msg)
2935                return -1;
2936
2937        og_send_cmd((char **)params->ips_array, params->ips_array_len,
2938                    CLIENTE_OCUPADO, msg);
2939
2940        og_msg_free(msg);
2941
2942        return 0;
2943}
2944
2945struct og_cmd {
2946        struct list_head        list;
2947        uint32_t                client_id;
2948        const char              *ip;
2949        const char              *mac;
2950        enum og_cmd_type        type;
2951        enum og_rest_method     method;
2952        struct og_msg_params    params;
2953        json_t                  *json;
2954};
2955
2956static LIST_HEAD(cmd_list);
2957
2958static const struct og_cmd *og_cmd_find(const char *client_ip)
2959{
2960        struct og_cmd *cmd, *next;
2961
2962        list_for_each_entry_safe(cmd, next, &cmd_list, list) {
2963                if (strcmp(cmd->ip, client_ip))
2964                        continue;
2965
2966                list_del(&cmd->list);
2967                return cmd;
2968        }
2969
2970        return NULL;
2971}
2972
2973static void og_cmd_free(const struct og_cmd *cmd)
2974{
2975        struct og_msg_params *params = (struct og_msg_params *)&cmd->params;
2976        int i;
2977
2978        for (i = 0; i < params->ips_array_len; i++) {
2979                free((void *)params->ips_array[i]);
2980                free((void *)params->mac_array[i]);
2981        }
2982        free((void *)params->wol_type);
2983
2984        if (cmd->json)
2985                json_decref(cmd->json);
2986
2987        free((void *)cmd->ip);
2988        free((void *)cmd->mac);
2989        free((void *)cmd);
2990}
2991
2992static void og_cmd_init(struct og_cmd *cmd, enum og_rest_method method,
2993                        enum og_cmd_type type, json_t *root)
2994{
2995        cmd->type = type;
2996        cmd->method = method;
2997        cmd->params.ips_array[0] = strdup(cmd->ip);
2998        cmd->params.ips_array_len = 1;
2999        cmd->json = root;
3000}
3001
3002static int og_cmd_legacy_wol(const char *input, struct og_cmd *cmd)
3003{
3004        char wol_type[2] = {};
3005
3006        if (sscanf(input, "mar=%s", wol_type) != 1) {
3007                syslog(LOG_ERR, "malformed database legacy input\n");
3008                return -1;
3009        }
3010
3011        og_cmd_init(cmd, OG_METHOD_NO_HTTP, OG_CMD_WOL, NULL);
3012        cmd->params.mac_array[0] = strdup(cmd->mac);
3013        cmd->params.wol_type = strdup(wol_type);
3014
3015        return 0;
3016}
3017
3018static int og_cmd_legacy_shell_run(const char *input, struct og_cmd *cmd)
3019{
3020        json_t *root, *script, *echo;
3021
3022        script = json_string(input + 4);
3023        echo = json_boolean(false);
3024
3025        root = json_object();
3026        if (!root)
3027                return -1;
3028        json_object_set_new(root, "run", script);
3029        json_object_set_new(root, "echo", echo);
3030
3031        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_SHELL_RUN, root);
3032
3033        return 0;
3034}
3035
3036#define OG_DB_SMALLINT_MAXLEN   6
3037
3038static int og_cmd_legacy_session(const char *input, struct og_cmd *cmd)
3039{
3040        char part_str[OG_DB_SMALLINT_MAXLEN + 1];
3041        char disk_str[OG_DB_SMALLINT_MAXLEN + 1];
3042        json_t *root, *disk, *partition;
3043
3044        if (sscanf(input, "dsk=%s\rpar=%s\r", disk_str, part_str) != 2)
3045                return -1;
3046        partition = json_string(part_str);
3047        disk = json_string(disk_str);
3048
3049        root = json_object();
3050        if (!root)
3051                return -1;
3052        json_object_set_new(root, "partition", partition);
3053        json_object_set_new(root, "disk", disk);
3054
3055        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_SESSION, root);
3056
3057        return 0;
3058}
3059
3060static int og_cmd_legacy_poweroff(const char *input, struct og_cmd *cmd)
3061{
3062        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_POWEROFF, NULL);
3063
3064        return 0;
3065}
3066
3067static int og_cmd_legacy_refresh(const char *input, struct og_cmd *cmd)
3068{
3069        og_cmd_init(cmd, OG_METHOD_GET, OG_CMD_REFRESH, NULL);
3070
3071        return 0;
3072}
3073
3074static int og_cmd_legacy_reboot(const char *input, struct og_cmd *cmd)
3075{
3076        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_REBOOT, NULL);
3077
3078        return 0;
3079}
3080
3081static int og_cmd_legacy_stop(const char *input, struct og_cmd *cmd)
3082{
3083        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_STOP, NULL);
3084
3085        return 0;
3086}
3087
3088static int og_cmd_legacy_hardware(const char *input, struct og_cmd *cmd)
3089{
3090        og_cmd_init(cmd, OG_METHOD_GET, OG_CMD_HARDWARE, NULL);
3091
3092        return 0;
3093}
3094
3095static int og_cmd_legacy_software(const char *input, struct og_cmd *cmd)
3096{
3097        og_cmd_init(cmd, OG_METHOD_GET, OG_CMD_SOFTWARE, NULL);
3098
3099        return 0;
3100}
3101
3102#define OG_DB_IMAGE_NAME_MAXLEN 50
3103#define OG_DB_FILESYSTEM_MAXLEN 16
3104#define OG_DB_INT8_MAXLEN       8
3105#define OG_DB_INT_MAXLEN        11
3106#define OG_DB_IP_MAXLEN         15
3107
3108struct og_image_legacy {
3109        char software_id[OG_DB_INT_MAXLEN + 1];
3110        char image_id[OG_DB_INT_MAXLEN + 1];
3111        char name[OG_DB_IMAGE_NAME_MAXLEN + 1];
3112        char repo[OG_DB_IP_MAXLEN + 1];
3113        char part[OG_DB_SMALLINT_MAXLEN + 1];
3114        char disk[OG_DB_SMALLINT_MAXLEN + 1];
3115        char code[OG_DB_INT8_MAXLEN + 1];
3116};
3117
3118struct og_legacy_partition {
3119        char partition[OG_DB_SMALLINT_MAXLEN + 1];
3120        char code[OG_DB_INT8_MAXLEN + 1];
3121        char size[OG_DB_INT_MAXLEN + 1];
3122        char filesystem[OG_DB_FILESYSTEM_MAXLEN + 1];
3123        char format[2]; /* Format is a boolean 0 or 1 => length is 2 */
3124};
3125
3126static int og_cmd_legacy_image_create(const char *input, struct og_cmd *cmd)
3127{
3128        json_t *root, *disk, *partition, *code, *image_id, *name, *repo;
3129        struct og_image_legacy img = {};
3130
3131        if (sscanf(input, "dsk=%s\rpar=%s\rcpt=%s\ridi=%s\rnci=%s\ripr=%s\r",
3132                   img.disk, img.part, img.code, img.image_id, img.name,
3133                   img.repo) != 6)
3134                return -1;
3135        image_id = json_string(img.image_id);
3136        partition = json_string(img.part);
3137        code = json_string(img.code);
3138        name = json_string(img.name);
3139        repo = json_string(img.repo);
3140        disk = json_string(img.disk);
3141
3142        root = json_object();
3143        if (!root)
3144                return -1;
3145        json_object_set_new(root, "partition", partition);
3146        json_object_set_new(root, "repository", repo);
3147        json_object_set_new(root, "id", image_id);
3148        json_object_set_new(root, "code", code);
3149        json_object_set_new(root, "name", name);
3150        json_object_set_new(root, "disk", disk);
3151
3152        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_IMAGE_CREATE, root);
3153
3154        return 0;
3155}
3156
3157#define OG_DB_RESTORE_TYPE_MAXLEN       64
3158
3159static int og_cmd_legacy_image_restore(const char *input, struct og_cmd *cmd)
3160{
3161        json_t *root, *disk, *partition, *image_id, *name, *repo;
3162        char restore_type_str[OG_DB_RESTORE_TYPE_MAXLEN + 1] = {};
3163        char software_id_str[OG_DB_INT_MAXLEN + 1] = {};
3164        json_t *software_id, *restore_type;
3165        struct og_image_legacy img = {};
3166
3167        if (sscanf(input,
3168                   "dsk=%s\rpar=%s\ridi=%s\rnci=%s\ripr=%s\rifs=%s\rptc=%s\r",
3169                   img.disk, img.part, img.image_id, img.name, img.repo,
3170                   software_id_str, restore_type_str) != 7)
3171                return -1;
3172
3173        restore_type = json_string(restore_type_str);
3174        software_id = json_string(software_id_str);
3175        image_id = json_string(img.image_id);
3176        partition = json_string(img.part);
3177        name = json_string(img.name);
3178        repo = json_string(img.repo);
3179        disk = json_string(img.disk);
3180
3181        root = json_object();
3182        if (!root)
3183                return -1;
3184        json_object_set_new(root, "profile", software_id);
3185        json_object_set_new(root, "partition", partition);
3186        json_object_set_new(root, "type", restore_type);
3187        json_object_set_new(root, "repository", repo);
3188        json_object_set_new(root, "id", image_id);
3189        json_object_set_new(root, "name", name);
3190        json_object_set_new(root, "disk", disk);
3191
3192        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_IMAGE_RESTORE, root);
3193
3194        return 0;
3195}
3196
3197static int og_cmd_legacy_setup(const char *input, struct og_cmd *cmd)
3198{
3199        json_t *root, *disk, *cache, *cache_size, *partition_setup, *object;
3200        struct og_legacy_partition part_cfg[OG_PARTITION_MAX] = {};
3201        char cache_size_str [OG_DB_INT_MAXLEN + 1];
3202        char disk_str [OG_DB_SMALLINT_MAXLEN + 1];
3203        json_t *part, *code, *fs, *size, *format;
3204        unsigned int partition_len = 0;
3205        const char *in_ptr;
3206        char cache_str[2];
3207
3208        if (sscanf(input, "dsk=%s\rcfg=dis=%*[^*]*che=%[^*]*tch=%[^!]!",
3209                   disk_str, cache_str, cache_size_str) != 3)
3210                return -1;
3211
3212        in_ptr = strstr(input, "!") + 1;
3213        while (strlen(in_ptr) > 0) {
3214                if(sscanf(in_ptr,
3215                          "par=%[^*]*cpt=%[^*]*sfi=%[^*]*tam=%[^*]*ope=%[^%%]%%",
3216                          part_cfg[partition_len].partition,
3217                          part_cfg[partition_len].code,
3218                          part_cfg[partition_len].filesystem,
3219                          part_cfg[partition_len].size,
3220                          part_cfg[partition_len].format) != 5)
3221                        return -1;
3222                in_ptr = strstr(in_ptr, "%") + 1;
3223                partition_len++;
3224        }
3225
3226        root = json_object();
3227        if (!root)
3228                return -1;
3229
3230        cache_size = json_string(cache_size_str);
3231        cache = json_string(cache_str);
3232        partition_setup = json_array();
3233        disk = json_string(disk_str);
3234
3235        for (unsigned int i = 0; i < partition_len; ++i) {
3236                object = json_object();
3237                if (!object) {
3238                        json_decref(root);
3239                        return -1;
3240                }
3241
3242                part = json_string(part_cfg[i].partition);
3243                fs = json_string(part_cfg[i].filesystem);
3244                format = json_string(part_cfg[i].format);
3245                code = json_string(part_cfg[i].code);
3246                size = json_string(part_cfg[i].size);
3247
3248                json_object_set_new(object, "partition", part);
3249                json_object_set_new(object, "filesystem", fs);
3250                json_object_set_new(object, "format", format);
3251                json_object_set_new(object, "code", code);
3252                json_object_set_new(object, "size", size);
3253
3254                json_array_append_new(partition_setup, object);
3255        }
3256
3257        json_object_set_new(root, "partition_setup", partition_setup);
3258        json_object_set_new(root, "cache_size", cache_size);
3259        json_object_set_new(root, "cache", cache);
3260        json_object_set_new(root, "disk", disk);
3261
3262        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_SETUP, root);
3263
3264        return 0;
3265}
3266
3267static int og_cmd_legacy_run_schedule(const char *input, struct og_cmd *cmd)
3268{
3269        og_cmd_init(cmd, OG_METHOD_GET, OG_CMD_RUN_SCHEDULE, NULL);
3270
3271        return 0;
3272}
3273
3274static int og_cmd_legacy(const char *input, struct og_cmd *cmd)
3275{
3276        char legacy_cmd[32] = {};
3277        int err = -1;
3278
3279        if (sscanf(input, "nfn=%31s\r", legacy_cmd) != 1) {
3280                syslog(LOG_ERR, "malformed database legacy input\n");
3281                return -1;
3282        }
3283        input = strchr(input, '\r') + 1;
3284
3285        if (!strcmp(legacy_cmd, "Arrancar")) {
3286                err = og_cmd_legacy_wol(input, cmd);
3287        } else if (!strcmp(legacy_cmd, "EjecutarScript")) {
3288                err = og_cmd_legacy_shell_run(input, cmd);
3289        } else if (!strcmp(legacy_cmd, "IniciarSesion")) {
3290                err = og_cmd_legacy_session(input, cmd);
3291        } else if (!strcmp(legacy_cmd, "Apagar")) {
3292                err = og_cmd_legacy_poweroff(input, cmd);
3293        } else if (!strcmp(legacy_cmd, "Actualizar")) {
3294                err = og_cmd_legacy_refresh(input, cmd);
3295        } else if (!strcmp(legacy_cmd, "Reiniciar")) {
3296                err = og_cmd_legacy_reboot(input, cmd);
3297        } else if (!strcmp(legacy_cmd, "Purgar")) {
3298                err = og_cmd_legacy_stop(input, cmd);
3299        } else if (!strcmp(legacy_cmd, "InventarioHardware")) {
3300                err = og_cmd_legacy_hardware(input, cmd);
3301        } else if (!strcmp(legacy_cmd, "InventarioSoftware")) {
3302                err = og_cmd_legacy_software(input, cmd);
3303        } else if (!strcmp(legacy_cmd, "CrearImagen")) {
3304                err = og_cmd_legacy_image_create(input, cmd);
3305        } else if (!strcmp(legacy_cmd, "RestaurarImagen")) {
3306                err = og_cmd_legacy_image_restore(input, cmd);
3307        } else if (!strcmp(legacy_cmd, "Configurar")) {
3308                err = og_cmd_legacy_setup(input, cmd);
3309        } else if (!strcmp(legacy_cmd, "EjecutaComandosPendientes") ||
3310                   !strcmp(legacy_cmd, "Actualizar")) {
3311                err = og_cmd_legacy_run_schedule(input, cmd);
3312        }
3313
3314        return err;
3315}
3316
3317static int og_queue_task_command(struct og_dbi *dbi, const struct og_task *task,
3318                                 char *query)
3319{
3320        struct og_cmd *cmd;
3321        const char *msglog;
3322        dbi_result result;
3323
3324        result = dbi_conn_queryf(dbi->conn, query);
3325        if (!result) {
3326                dbi_conn_error(dbi->conn, &msglog);
3327                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3328                       __func__, __LINE__, msglog);
3329                return -1;
3330        }
3331
3332        while (dbi_result_next_row(result)) {
3333                cmd = (struct og_cmd *)calloc(1, sizeof(struct og_cmd));
3334                if (!cmd) {
3335                        dbi_result_free(result);
3336                        return -1;
3337                }
3338
3339                cmd->client_id  = dbi_result_get_uint(result, "idordenador");
3340                cmd->ip         = strdup(dbi_result_get_string(result, "ip"));
3341                cmd->mac        = strdup(dbi_result_get_string(result, "mac"));
3342                og_cmd_legacy(task->params, cmd);
3343
3344                list_add_tail(&cmd->list, &cmd_list);
3345
3346        }
3347
3348        dbi_result_free(result);
3349
3350        return 0;
3351}
3352
3353static int og_queue_task_group_clients(struct og_dbi *dbi, struct og_task *task,
3354                                       char *query)
3355{
3356
3357        const char *msglog;
3358        dbi_result result;
3359
3360        result = dbi_conn_queryf(dbi->conn, query);
3361        if (!result) {
3362                dbi_conn_error(dbi->conn, &msglog);
3363                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3364                       __func__, __LINE__, msglog);
3365                return -1;
3366        }
3367
3368        while (dbi_result_next_row(result)) {
3369                uint32_t group_id = dbi_result_get_uint(result, "idgrupo");
3370
3371                sprintf(query, "SELECT idgrupo FROM gruposordenadores "
3372                                "WHERE grupoid=%d", group_id);
3373                if (og_queue_task_group_clients(dbi, task, query)) {
3374                        dbi_result_free(result);
3375                        return -1;
3376                }
3377
3378                sprintf(query,"SELECT ip, mac, idordenador FROM ordenadores "
3379                              "WHERE grupoid=%d", group_id);
3380                if (og_queue_task_command(dbi, task, query)) {
3381                        dbi_result_free(result);
3382                        return -1;
3383                }
3384
3385        }
3386
3387        dbi_result_free(result);
3388
3389        return 0;
3390}
3391
3392static int og_queue_task_classrooms(struct og_dbi *dbi, struct og_task *task,
3393                                    char *query)
3394{
3395
3396        const char *msglog;
3397        dbi_result result;
3398
3399        result = dbi_conn_queryf(dbi->conn, query);
3400        if (!result) {
3401                dbi_conn_error(dbi->conn, &msglog);
3402                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3403                       __func__, __LINE__, msglog);
3404                return -1;
3405        }
3406
3407        while (dbi_result_next_row(result)) {
3408                uint32_t classroom_id = dbi_result_get_uint(result, "idaula");
3409
3410                sprintf(query, "SELECT idgrupo FROM gruposordenadores "
3411                                "WHERE idaula=%d AND grupoid=0", classroom_id);
3412                if (og_queue_task_group_clients(dbi, task, query)) {
3413                        dbi_result_free(result);
3414                        return -1;
3415                }
3416
3417                sprintf(query,"SELECT ip, mac, idordenador FROM ordenadores "
3418                                "WHERE idaula=%d AND grupoid=0", classroom_id);
3419                if (og_queue_task_command(dbi, task, query)) {
3420                        dbi_result_free(result);
3421                        return -1;
3422                }
3423
3424        }
3425
3426        dbi_result_free(result);
3427
3428        return 0;
3429}
3430
3431static int og_queue_task_group_classrooms(struct og_dbi *dbi,
3432                                          struct og_task *task, char *query)
3433{
3434
3435        const char *msglog;
3436        dbi_result result;
3437
3438        result = dbi_conn_queryf(dbi->conn, query);
3439        if (!result) {
3440                dbi_conn_error(dbi->conn, &msglog);
3441                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3442                       __func__, __LINE__, msglog);
3443                return -1;
3444        }
3445
3446        while (dbi_result_next_row(result)) {
3447                uint32_t group_id = dbi_result_get_uint(result, "idgrupo");
3448
3449                sprintf(query, "SELECT idgrupo FROM grupos "
3450                                "WHERE grupoid=%d AND tipo=%d", group_id, AMBITO_GRUPOSAULAS);
3451                if (og_queue_task_group_classrooms(dbi, task, query)) {
3452                        dbi_result_free(result);
3453                        return -1;
3454                }
3455
3456                sprintf(query,"SELECT idaula FROM aulas WHERE grupoid=%d", group_id);
3457                if (og_queue_task_classrooms(dbi, task, query)) {
3458                        dbi_result_free(result);
3459                        return -1;
3460                }
3461
3462        }
3463
3464        dbi_result_free(result);
3465
3466        return 0;
3467}
3468
3469static int og_queue_task_center(struct og_dbi *dbi, struct og_task *task,
3470                                char *query)
3471{
3472
3473        sprintf(query,"SELECT idgrupo FROM grupos WHERE idcentro=%i AND grupoid=0 AND tipo=%d",
3474                task->scope, AMBITO_GRUPOSAULAS);
3475        if (og_queue_task_group_classrooms(dbi, task, query))
3476                return -1;
3477
3478        sprintf(query,"SELECT idaula FROM aulas WHERE idcentro=%i AND grupoid=0",
3479                task->scope);
3480        if (og_queue_task_classrooms(dbi, task, query))
3481                return -1;
3482
3483        return 0;
3484}
3485
3486static int og_queue_task_clients(struct og_dbi *dbi, struct og_task *task)
3487{
3488        char query[4096];
3489
3490        switch (task->type_scope) {
3491                case AMBITO_CENTROS:
3492                        return og_queue_task_center(dbi, task, query);
3493                case AMBITO_GRUPOSAULAS:
3494                        sprintf(query, "SELECT idgrupo FROM grupos "
3495                                       "WHERE idgrupo=%i AND tipo=%d",
3496                                       task->scope, AMBITO_GRUPOSAULAS);
3497                        return og_queue_task_group_classrooms(dbi, task, query);
3498                case AMBITO_AULAS:
3499                        sprintf(query, "SELECT idaula FROM aulas "
3500                                       "WHERE idaula = %d", task->scope);
3501                        return og_queue_task_classrooms(dbi, task, query);
3502                case AMBITO_GRUPOSORDENADORES:
3503                        sprintf(query, "SELECT idgrupo FROM gruposordenadores "
3504                                       "WHERE idgrupo = %d", task->scope);
3505                        return og_queue_task_group_clients(dbi, task, query);
3506                case AMBITO_ORDENADORES:
3507                        sprintf(query, "SELECT ip, mac, idordenador "
3508                                       "FROM ordenadores "
3509                                       "WHERE idordenador = %d", task->scope);
3510                        return og_queue_task_command(dbi, task, query);
3511        }
3512        return 0;
3513}
3514
3515static int og_dbi_queue_procedure(struct og_dbi *dbi, struct og_task *task)
3516{
3517        uint32_t procedure_id;
3518        const char *msglog;
3519        dbi_result result;
3520
3521        result = dbi_conn_queryf(dbi->conn,
3522                        "SELECT parametros, procedimientoid "
3523                        "FROM procedimientos_acciones "
3524                        "WHERE idprocedimiento=%d ORDER BY orden", task->procedure_id);
3525        if (!result) {
3526                dbi_conn_error(dbi->conn, &msglog);
3527                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3528                       __func__, __LINE__, msglog);
3529                return -1;
3530        }
3531
3532        while (dbi_result_next_row(result)) {
3533                procedure_id = dbi_result_get_uint(result, "procedimientoid");
3534                if (procedure_id > 0) {
3535                        task->procedure_id = procedure_id;
3536                        if (og_dbi_queue_procedure(dbi, task))
3537                                return -1;
3538                        continue;
3539                }
3540
3541                task->params    = strdup(dbi_result_get_string(result, "parametros"));
3542                if (og_queue_task_clients(dbi, task))
3543                        return -1;
3544        }
3545
3546        dbi_result_free(result);
3547
3548        return 0;
3549}
3550
3551static int og_dbi_queue_task(struct og_dbi *dbi, uint32_t task_id)
3552{
3553        struct og_task task = {};
3554        uint32_t task_id_next;
3555        struct og_cmd *cmd;
3556        const char *msglog;
3557        dbi_result result;
3558
3559        result = dbi_conn_queryf(dbi->conn,
3560                        "SELECT tareas_acciones.orden, "
3561                                "tareas_acciones.idprocedimiento, "
3562                                "tareas_acciones.tareaid, "
3563                                "tareas.ambito, "
3564                                "tareas.idambito, "
3565                                "tareas.restrambito "
3566                        " FROM tareas"
3567                                " INNER JOIN tareas_acciones ON tareas_acciones.idtarea=tareas.idtarea"
3568                        " WHERE tareas_acciones.idtarea=%u ORDER BY tareas_acciones.orden ASC", task_id);
3569        if (!result) {
3570                dbi_conn_error(dbi->conn, &msglog);
3571                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3572                       __func__, __LINE__, msglog);
3573                return -1;
3574        }
3575
3576        while (dbi_result_next_row(result)) {
3577                task_id_next = dbi_result_get_uint(result, "procedimientoid");
3578
3579                if (task_id_next > 0) {
3580                        if (og_dbi_queue_task(dbi, task_id_next))
3581                                return -1;
3582
3583                        continue;
3584                }
3585                task.procedure_id = dbi_result_get_uint(result, "idprocedimiento");
3586                task.type_scope = dbi_result_get_uint(result, "ambito");
3587                task.scope = dbi_result_get_uint(result, "idambito");
3588                task.filtered_scope = dbi_result_get_string(result, "restrambito");
3589
3590                og_dbi_queue_procedure(dbi, &task);
3591        }
3592
3593        dbi_result_free(result);
3594
3595        list_for_each_entry(cmd, &cmd_list, list) {
3596                if (cmd->type != OG_CMD_WOL)
3597                        continue;
3598
3599                if (!Levanta((char **)cmd->params.ips_array,
3600                             (char **)cmd->params.mac_array,
3601                             cmd->params.ips_array_len,
3602                             (char *)cmd->params.wol_type))
3603                        return -1;
3604        }
3605
3606        return 0;
3607}
3608
3609void og_dbi_schedule_task(unsigned int task_id)
3610{
3611        struct og_msg_params params = {};
3612        bool duplicated = false;
3613        struct og_cmd *cmd;
3614        struct og_dbi *dbi;
3615        unsigned int i;
3616
3617        dbi = og_dbi_open(&dbi_config);
3618        if (!dbi) {
3619                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
3620                       __func__, __LINE__);
3621                return;
3622        }
3623        og_dbi_queue_task(dbi, task_id);
3624        og_dbi_close(dbi);
3625
3626        list_for_each_entry(cmd, &cmd_list, list) {
3627                for (i = 0; i < params.ips_array_len; i++) {
3628                        if (!strncmp(cmd->ip, params.ips_array[i],
3629                                     OG_DB_IP_MAXLEN)) {
3630                                duplicated = true;
3631                                break;
3632                        }
3633                }
3634
3635                if (!duplicated)
3636                        params.ips_array[params.ips_array_len++] = cmd->ip;
3637                else
3638                        duplicated = false;
3639        }
3640
3641        og_send_request(OG_METHOD_GET, OG_CMD_RUN_SCHEDULE, &params, NULL);
3642}
3643
3644static int og_cmd_task_post(json_t *element, struct og_msg_params *params)
3645{
3646        struct og_cmd *cmd;
3647        struct og_dbi *dbi;
3648        const char *key;
3649        json_t *value;
3650        int err;
3651
3652        if (json_typeof(element) != JSON_OBJECT)
3653                return -1;
3654
3655        json_object_foreach(element, key, value) {
3656                if (!strcmp(key, "task")) {
3657                        err = og_json_parse_string(value, &params->task_id);
3658                        params->flags |= OG_REST_PARAM_TASK;
3659                }
3660
3661                if (err < 0)
3662                        break;
3663        }
3664
3665        if (!og_msg_params_validate(params, OG_REST_PARAM_TASK))
3666                return -1;
3667
3668        dbi = og_dbi_open(&dbi_config);
3669        if (!dbi) {
3670                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
3671                           __func__, __LINE__);
3672                return -1;
3673        }
3674
3675        og_dbi_queue_task(dbi, atoi(params->task_id));
3676        og_dbi_close(dbi);
3677
3678        list_for_each_entry(cmd, &cmd_list, list)
3679                params->ips_array[params->ips_array_len++] = cmd->ip;
3680
3681        return og_send_request(OG_METHOD_GET, OG_CMD_RUN_SCHEDULE, params,
3682                               NULL);
3683}
3684
3685static int og_dbi_schedule_get(void)
3686{
3687        uint32_t schedule_id, task_id;
3688        struct og_schedule_time time;
3689        struct og_dbi *dbi;
3690        const char *msglog;
3691        dbi_result result;
3692
3693        dbi = og_dbi_open(&dbi_config);
3694        if (!dbi) {
3695                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
3696                       __func__, __LINE__);
3697                return -1;
3698        }
3699
3700        result = dbi_conn_queryf(dbi->conn,
3701                                 "SELECT idprogramacion, tipoaccion, identificador, "
3702                                 "sesion, annos, meses, diario, dias, semanas, horas, "
3703                                 "ampm, minutos FROM programaciones "
3704                                 "WHERE suspendida = 0");
3705        if (!result) {
3706                dbi_conn_error(dbi->conn, &msglog);
3707                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3708                       __func__, __LINE__, msglog);
3709                return -1;
3710        }
3711
3712        while (dbi_result_next_row(result)) {
3713                memset(&time, 0, sizeof(time));
3714                schedule_id = dbi_result_get_uint(result, "idprogramacion");
3715                task_id = dbi_result_get_uint(result, "identificador");
3716                time.years = dbi_result_get_uint(result, "annos");
3717                time.months = dbi_result_get_uint(result, "meses");
3718                time.weeks = dbi_result_get_uint(result, "semanas");
3719                time.week_days = dbi_result_get_uint(result, "dias");
3720                time.days = dbi_result_get_uint(result, "diario");
3721                time.hours = dbi_result_get_uint(result, "horas");
3722                time.am_pm = dbi_result_get_uint(result, "ampm");
3723                time.minutes = dbi_result_get_uint(result, "minutos");
3724
3725                og_schedule_create(schedule_id, task_id, &time);
3726        }
3727
3728        dbi_result_free(result);
3729
3730        return 0;
3731}
3732
3733static int og_dbi_schedule_create(struct og_dbi *dbi,
3734                                  struct og_msg_params *params,
3735                                  uint32_t *schedule_id)
3736{
3737        const char *msglog;
3738        dbi_result result;
3739        uint8_t suspended = 0;
3740        uint8_t type = 3;
3741
3742        result = dbi_conn_queryf(dbi->conn,
3743                                 "INSERT INTO programaciones (tipoaccion,"
3744                                 " identificador, nombrebloque, annos, meses,"
3745                                 " diario, horas, ampm, minutos, suspendida) VALUES (%d,"
3746                                 " %s, '%s', %d, %d, %d, %d, %d, %d, %d)", type,
3747                                 params->task_id, params->name, params->time.years,
3748                                 params->time.months, params->time.days,
3749                                 params->time.hours, params->time.am_pm,
3750                                 params->time.minutes, suspended);
3751        if (!result) {
3752                dbi_conn_error(dbi->conn, &msglog);
3753                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3754                       __func__, __LINE__, msglog);
3755                return -1;
3756        }
3757        dbi_result_free(result);
3758
3759        *schedule_id = dbi_conn_sequence_last(dbi->conn, NULL);
3760
3761        return 0;
3762}
3763
3764static int og_dbi_schedule_update(struct og_dbi *dbi,
3765                                  struct og_msg_params *params)
3766{
3767        const char *msglog;
3768        dbi_result result;
3769        uint8_t type = 3;
3770
3771        result = dbi_conn_queryf(dbi->conn,
3772                                 "UPDATE programaciones SET tipoaccion=%d, "
3773                                 "identificador='%s', nombrebloque='%s', "
3774                                 "annos=%d, meses=%d, "
3775                                 "diario=%d, horas=%d, ampm=%d, minutos=%d "
3776                                 "WHERE idprogramacion='%s'",
3777                                 type, params->task_id, params->name,
3778                                 params->time.years, params->time.months,
3779                                 params->time.days, params->time.hours,
3780                                 params->time.am_pm, params->time.minutes,
3781                                 params->id);
3782
3783        if (!result) {
3784                dbi_conn_error(dbi->conn, &msglog);
3785                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3786                       __func__, __LINE__, msglog);
3787                return -1;
3788        }
3789        dbi_result_free(result);
3790
3791        return 0;
3792}
3793
3794static int og_dbi_schedule_delete(struct og_dbi *dbi, uint32_t id)
3795{
3796        const char *msglog;
3797        dbi_result result;
3798
3799        result = dbi_conn_queryf(dbi->conn,
3800                                 "DELETE FROM programaciones WHERE idprogramacion=%d",
3801                                 id);
3802        if (!result) {
3803                dbi_conn_error(dbi->conn, &msglog);
3804                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3805                       __func__, __LINE__, msglog);
3806                return -1;
3807        }
3808        dbi_result_free(result);
3809
3810        return 0;
3811}
3812
3813struct og_db_schedule {
3814        uint32_t                id;
3815        uint32_t                task_id;
3816        const char              *name;
3817        struct og_schedule_time time;
3818        uint32_t                week_days;
3819        uint32_t                weeks;
3820        uint32_t                suspended;
3821        uint32_t                session;
3822};
3823
3824static int og_dbi_schedule_get_json(struct og_dbi *dbi, json_t *root,
3825                                    const char *task_id, const char *schedule_id)
3826{
3827        struct og_db_schedule schedule;
3828        json_t *obj, *array;
3829        const char *msglog;
3830        dbi_result result;
3831        int err = 0;
3832
3833        if (task_id) {
3834                result = dbi_conn_queryf(dbi->conn,
3835                                         "SELECT idprogramacion,"
3836                                         "       identificador, nombrebloque,"
3837                                         "       annos, meses, diario, dias,"
3838                                         "       semanas, horas, ampm,"
3839                                         "       minutos,suspendida, sesion "
3840                                         "FROM programaciones "
3841                                         "WHERE identificador=%d",
3842                                         atoi(task_id));
3843        } else if (schedule_id) {
3844                result = dbi_conn_queryf(dbi->conn,
3845                                         "SELECT idprogramacion,"
3846                                         "       identificador, nombrebloque,"
3847                                         "       annos, meses, diario, dias,"
3848                                         "       semanas, horas, ampm,"
3849                                         "       minutos,suspendida, sesion "
3850                                         "FROM programaciones "
3851                                         "WHERE idprogramacion=%d",
3852                                         atoi(schedule_id));
3853        } else {
3854                result = dbi_conn_queryf(dbi->conn,
3855                                         "SELECT idprogramacion,"
3856                                         "       identificador, nombrebloque,"
3857                                         "       annos, meses, diario, dias,"
3858                                         "       semanas, horas, ampm,"
3859                                         "       minutos,suspendida, sesion "
3860                                         "FROM programaciones");
3861        }
3862
3863        if (!result) {
3864                dbi_conn_error(dbi->conn, &msglog);
3865                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3866                       __func__, __LINE__, msglog);
3867                return -1;
3868        }
3869
3870        array = json_array();
3871        if (!array)
3872                return -1;
3873
3874        while (dbi_result_next_row(result)) {
3875                schedule.id = dbi_result_get_uint(result, "idprogramacion");
3876                schedule.task_id = dbi_result_get_uint(result, "identificador");
3877                schedule.name = dbi_result_get_string(result, "nombrebloque");
3878                schedule.time.years = dbi_result_get_uint(result, "annos");
3879                schedule.time.months = dbi_result_get_uint(result, "meses");
3880                schedule.time.days = dbi_result_get_uint(result, "diario");
3881                schedule.time.hours = dbi_result_get_uint(result, "horas");
3882                schedule.time.am_pm = dbi_result_get_uint(result, "ampm");
3883                schedule.time.minutes = dbi_result_get_uint(result, "minutos");
3884                schedule.week_days = dbi_result_get_uint(result, "dias");
3885                schedule.weeks = dbi_result_get_uint(result, "semanas");
3886                schedule.suspended = dbi_result_get_uint(result, "suspendida");
3887                schedule.session = dbi_result_get_uint(result, "sesion");
3888
3889                obj = json_object();
3890                if (!obj) {
3891                        err = -1;
3892                        break;
3893                }
3894                json_object_set_new(obj, "id", json_integer(schedule.id));
3895                json_object_set_new(obj, "task", json_integer(schedule.task_id));
3896                json_object_set_new(obj, "name", json_string(schedule.name));
3897                json_object_set_new(obj, "years", json_integer(schedule.time.years));
3898                json_object_set_new(obj, "months", json_integer(schedule.time.months));
3899                json_object_set_new(obj, "days", json_integer(schedule.time.days));
3900                json_object_set_new(obj, "hours", json_integer(schedule.time.hours));
3901                json_object_set_new(obj, "am_pm", json_integer(schedule.time.am_pm));
3902                json_object_set_new(obj, "minutes", json_integer(schedule.time.minutes));
3903                json_object_set_new(obj, "week_days", json_integer(schedule.week_days));
3904                json_object_set_new(obj, "weeks", json_integer(schedule.weeks));
3905                json_object_set_new(obj, "suspended", json_integer(schedule.suspended));
3906                json_object_set_new(obj, "session", json_integer(schedule.session));
3907
3908                json_array_append_new(array, obj);
3909        }
3910
3911        json_object_set_new(root, "schedule", array);
3912
3913        dbi_result_free(result);
3914
3915        return err;
3916}
3917
3918static struct ev_loop *og_loop;
3919
3920static int og_cmd_schedule_create(json_t *element, struct og_msg_params *params)
3921{
3922        uint32_t schedule_id;
3923        struct og_dbi *dbi;
3924        const char *key;
3925        json_t *value;
3926        int err;
3927
3928        if (json_typeof(element) != JSON_OBJECT)
3929                return -1;
3930
3931        json_object_foreach(element, key, value) {
3932                if (!strcmp(key, "task")) {
3933                        err = og_json_parse_string(value, &params->task_id);
3934                        params->flags |= OG_REST_PARAM_TASK;
3935                } else if (!strcmp(key, "name")) {
3936                        err = og_json_parse_string(value, &params->name);
3937                        params->flags |= OG_REST_PARAM_NAME;
3938                } else if (!strcmp(key, "when"))
3939                        err = og_json_parse_time_params(value, params);
3940
3941                if (err < 0)
3942                        break;
3943        }
3944
3945        if (!og_msg_params_validate(params, OG_REST_PARAM_TASK |
3946                                            OG_REST_PARAM_NAME |
3947                                            OG_REST_PARAM_TIME_YEARS |
3948                                            OG_REST_PARAM_TIME_MONTHS |
3949                                            OG_REST_PARAM_TIME_DAYS |
3950                                            OG_REST_PARAM_TIME_HOURS |
3951                                            OG_REST_PARAM_TIME_MINUTES |
3952                                            OG_REST_PARAM_TIME_AM_PM))
3953                return -1;
3954
3955        dbi = og_dbi_open(&dbi_config);
3956        if (!dbi) {
3957                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
3958                           __func__, __LINE__);
3959                return -1;
3960        }
3961
3962        err = og_dbi_schedule_create(dbi, params, &schedule_id);
3963        og_dbi_close(dbi);
3964
3965        if (err < 0)
3966                return -1;
3967
3968        og_schedule_create(schedule_id, atoi(params->task_id), &params->time);
3969        og_schedule_refresh(og_loop);
3970
3971        return err;
3972}
3973
3974static int og_cmd_schedule_update(json_t *element, struct og_msg_params *params)
3975{
3976        struct og_dbi *dbi;
3977        const char *key;
3978        json_t *value;
3979        int err;
3980
3981        if (json_typeof(element) != JSON_OBJECT)
3982                return -1;
3983
3984        json_object_foreach(element, key, value) {
3985                if (!strcmp(key, "id")) {
3986                        err = og_json_parse_string(value, &params->id);
3987                        params->flags |= OG_REST_PARAM_ID;
3988                } else if (!strcmp(key, "task")) {
3989                        err = og_json_parse_string(value, &params->task_id);
3990                        params->flags |= OG_REST_PARAM_TASK;
3991                } else if (!strcmp(key, "name")) {
3992                        err = og_json_parse_string(value, &params->name);
3993                        params->flags |= OG_REST_PARAM_NAME;
3994                } else if (!strcmp(key, "when"))
3995                        err = og_json_parse_time_params(value, params);
3996
3997                if (err < 0)
3998                        break;
3999        }
4000
4001        if (!og_msg_params_validate(params, OG_REST_PARAM_ID |
4002                                            OG_REST_PARAM_TASK |
4003                                            OG_REST_PARAM_NAME |
4004                                            OG_REST_PARAM_TIME_YEARS |
4005                                            OG_REST_PARAM_TIME_MONTHS |
4006                                            OG_REST_PARAM_TIME_DAYS |
4007                                            OG_REST_PARAM_TIME_HOURS |
4008                                            OG_REST_PARAM_TIME_MINUTES |
4009                                            OG_REST_PARAM_TIME_AM_PM))
4010                return -1;
4011
4012        dbi = og_dbi_open(&dbi_config);
4013        if (!dbi) {
4014                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
4015                           __func__, __LINE__);
4016                return -1;
4017        }
4018
4019        err = og_dbi_schedule_update(dbi, params);
4020        og_dbi_close(dbi);
4021
4022        if (err < 0)
4023                return err;
4024
4025        og_schedule_update(og_loop, atoi(params->id), atoi(params->task_id),
4026                           &params->time);
4027        og_schedule_refresh(og_loop);
4028
4029        return err;
4030}
4031
4032static int og_cmd_schedule_delete(json_t *element, struct og_msg_params *params)
4033{
4034        struct og_dbi *dbi;
4035        const char *key;
4036        json_t *value;
4037        int err;
4038
4039        if (json_typeof(element) != JSON_OBJECT)
4040                return -1;
4041
4042        json_object_foreach(element, key, value) {
4043                if (!strcmp(key, "id")) {
4044                        err = og_json_parse_string(value, &params->id);
4045                        params->flags |= OG_REST_PARAM_ID;
4046                } else {
4047                        return -1;
4048                }
4049
4050                if (err < 0)
4051                        break;
4052        }
4053
4054        if (!og_msg_params_validate(params, OG_REST_PARAM_ID))
4055                return -1;
4056
4057        dbi = og_dbi_open(&dbi_config);
4058        if (!dbi) {
4059                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
4060                           __func__, __LINE__);
4061                return -1;
4062        }
4063
4064        err = og_dbi_schedule_delete(dbi, atoi(params->id));
4065        og_dbi_close(dbi);
4066
4067        og_schedule_delete(og_loop, atoi(params->id));
4068
4069        return err;
4070}
4071
4072static int og_cmd_schedule_get(json_t *element, struct og_msg_params *params,
4073                               char *buffer_reply)
4074{
4075        struct og_buffer og_buffer = {
4076                .data   = buffer_reply,
4077        };
4078        json_t *schedule_root;
4079        struct og_dbi *dbi;
4080        const char *key;
4081        json_t *value;
4082        int err;
4083
4084        if (element) {
4085                if (json_typeof(element) != JSON_OBJECT)
4086                        return -1;
4087
4088                json_object_foreach(element, key, value) {
4089                        if (!strcmp(key, "task")) {
4090                                err = og_json_parse_string(value,
4091                                                           &params->task_id);
4092                        } else if (!strcmp(key, "id")) {
4093                                err = og_json_parse_string(value, &params->id);
4094                        } else {
4095                                return -1;
4096                        }
4097
4098                        if (err < 0)
4099                                break;
4100                }
4101        }
4102
4103        dbi = og_dbi_open(&dbi_config);
4104        if (!dbi) {
4105                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
4106                           __func__, __LINE__);
4107                return -1;
4108        }
4109
4110        schedule_root = json_object();
4111        if (!schedule_root) {
4112                og_dbi_close(dbi);
4113                return -1;
4114        }
4115
4116        err = og_dbi_schedule_get_json(dbi, schedule_root,
4117                                       params->task_id, params->id);
4118        og_dbi_close(dbi);
4119
4120        if (err >= 0)
4121                json_dump_callback(schedule_root, og_json_dump_clients, &og_buffer, 0);
4122
4123        json_decref(schedule_root);
4124
4125        return err;
4126}
4127
4128static int og_client_method_not_found(struct og_client *cli)
4129{
4130        /* To meet RFC 7231, this function MUST generate an Allow header field
4131         * containing the correct methods. For example: "Allow: POST\r\n"
4132         */
4133        char buf[] = "HTTP/1.1 405 Method Not Allowed\r\n"
4134                     "Content-Length: 0\r\n\r\n";
4135
4136        send(og_client_socket(cli), buf, strlen(buf), 0);
4137
4138        return -1;
4139}
4140
4141static int og_client_bad_request(struct og_client *cli)
4142{
4143        char buf[] = "HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\n\r\n";
4144
4145        send(og_client_socket(cli), buf, strlen(buf), 0);
4146
4147        return -1;
4148}
4149
4150static int og_client_not_found(struct og_client *cli)
4151{
4152        char buf[] = "HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n";
4153
4154        send(og_client_socket(cli), buf, strlen(buf), 0);
4155
4156        return -1;
4157}
4158
4159static int og_client_not_authorized(struct og_client *cli)
4160{
4161        char buf[] = "HTTP/1.1 401 Unauthorized\r\n"
4162                     "WWW-Authenticate: Basic\r\n"
4163                     "Content-Length: 0\r\n\r\n";
4164
4165        send(og_client_socket(cli), buf, strlen(buf), 0);
4166
4167        return -1;
4168}
4169
4170static int og_server_internal_error(struct og_client *cli)
4171{
4172        char buf[] = "HTTP/1.1 500 Internal Server Error\r\n"
4173                     "Content-Length: 0\r\n\r\n";
4174
4175        send(og_client_socket(cli), buf, strlen(buf), 0);
4176
4177        return -1;
4178}
4179
4180static int og_client_payload_too_large(struct og_client *cli)
4181{
4182        char buf[] = "HTTP/1.1 413 Payload Too Large\r\n"
4183                     "Content-Length: 0\r\n\r\n";
4184
4185        send(og_client_socket(cli), buf, strlen(buf), 0);
4186
4187        return -1;
4188}
4189
4190#define OG_MSG_RESPONSE_MAXLEN  65536
4191
4192static int og_client_ok(struct og_client *cli, char *buf_reply)
4193{
4194        char buf[OG_MSG_RESPONSE_MAXLEN] = {};
4195        int err = 0, len;
4196
4197        len = snprintf(buf, sizeof(buf),
4198                       "HTTP/1.1 200 OK\r\nContent-Length: %ld\r\n\r\n%s",
4199                       strlen(buf_reply), buf_reply);
4200        if (len >= (int)sizeof(buf))
4201                err = og_server_internal_error(cli);
4202
4203        send(og_client_socket(cli), buf, strlen(buf), 0);
4204
4205        return err;
4206}
4207
4208static int og_client_state_process_payload_rest(struct og_client *cli)
4209{
4210        char buf_reply[OG_MSG_RESPONSE_MAXLEN] = {};
4211        struct og_msg_params params = {};
4212        enum og_rest_method method;
4213        const char *cmd, *body;
4214        json_error_t json_err;
4215        json_t *root = NULL;
4216        int err = 0;
4217
4218        syslog(LOG_DEBUG, "%s:%hu %.32s ...\n",
4219               inet_ntoa(cli->addr.sin_addr),
4220               ntohs(cli->addr.sin_port), cli->buf);
4221
4222        if (!strncmp(cli->buf, "GET", strlen("GET"))) {
4223                method = OG_METHOD_GET;
4224                cmd = cli->buf + strlen("GET") + 2;
4225        } else if (!strncmp(cli->buf, "POST", strlen("POST"))) {
4226                method = OG_METHOD_POST;
4227                cmd = cli->buf + strlen("POST") + 2;
4228        } else
4229                return og_client_method_not_found(cli);
4230
4231        body = strstr(cli->buf, "\r\n\r\n") + 4;
4232
4233        if (strcmp(cli->auth_token, auth_token)) {
4234                syslog(LOG_ERR, "wrong Authentication key\n");
4235                return og_client_not_authorized(cli);
4236        }
4237
4238        if (cli->content_length) {
4239                root = json_loads(body, 0, &json_err);
4240                if (!root) {
4241                        syslog(LOG_ERR, "malformed json line %d: %s\n",
4242                               json_err.line, json_err.text);
4243                        return og_client_not_found(cli);
4244                }
4245        }
4246
4247        if (!strncmp(cmd, "clients", strlen("clients"))) {
4248                if (method != OG_METHOD_POST &&
4249                    method != OG_METHOD_GET)
4250                        return og_client_method_not_found(cli);
4251
4252                if (method == OG_METHOD_POST && !root) {
4253                        syslog(LOG_ERR, "command clients with no payload\n");
4254                        return og_client_bad_request(cli);
4255                }
4256                switch (method) {
4257                case OG_METHOD_POST:
4258                        err = og_cmd_post_clients(root, &params);
4259                        break;
4260                case OG_METHOD_GET:
4261                        err = og_cmd_get_clients(root, &params, buf_reply);
4262                        break;
4263                default:
4264                        return og_client_bad_request(cli);
4265                }
4266        } else if (!strncmp(cmd, "wol", strlen("wol"))) {
4267                if (method != OG_METHOD_POST)
4268                        return og_client_method_not_found(cli);
4269
4270                if (!root) {
4271                        syslog(LOG_ERR, "command wol with no payload\n");
4272                        return og_client_bad_request(cli);
4273                }
4274                err = og_cmd_wol(root, &params);
4275        } else if (!strncmp(cmd, "shell/run", strlen("shell/run"))) {
4276                if (method != OG_METHOD_POST)
4277                        return og_client_method_not_found(cli);
4278
4279                if (!root) {
4280                        syslog(LOG_ERR, "command run with no payload\n");
4281                        return og_client_bad_request(cli);
4282                }
4283                err = og_cmd_run_post(root, &params);
4284        } else if (!strncmp(cmd, "shell/output", strlen("shell/output"))) {
4285                if (method != OG_METHOD_POST)
4286                        return og_client_method_not_found(cli);
4287
4288                if (!root) {
4289                        syslog(LOG_ERR, "command output with no payload\n");
4290                        return og_client_bad_request(cli);
4291                }
4292
4293                err = og_cmd_run_get(root, &params, buf_reply);
4294        } else if (!strncmp(cmd, "session", strlen("session"))) {
4295                if (method != OG_METHOD_POST)
4296                        return og_client_method_not_found(cli);
4297
4298                if (!root) {
4299                        syslog(LOG_ERR, "command session with no payload\n");
4300                        return og_client_bad_request(cli);
4301                }
4302                err = og_cmd_session(root, &params);
4303        } else if (!strncmp(cmd, "poweroff", strlen("poweroff"))) {
4304                if (method != OG_METHOD_POST)
4305                        return og_client_method_not_found(cli);
4306
4307                if (!root) {
4308                        syslog(LOG_ERR, "command poweroff with no payload\n");
4309                        return og_client_bad_request(cli);
4310                }
4311                err = og_cmd_poweroff(root, &params);
4312        } else if (!strncmp(cmd, "reboot", strlen("reboot"))) {
4313                if (method != OG_METHOD_POST)
4314                        return og_client_method_not_found(cli);
4315
4316                if (!root) {
4317                        syslog(LOG_ERR, "command reboot with no payload\n");
4318                        return og_client_bad_request(cli);
4319                }
4320                err = og_cmd_reboot(root, &params);
4321        } else if (!strncmp(cmd, "stop", strlen("stop"))) {
4322                if (method != OG_METHOD_POST)
4323                        return og_client_method_not_found(cli);
4324
4325                if (!root) {
4326                        syslog(LOG_ERR, "command stop with no payload\n");
4327                        return og_client_bad_request(cli);
4328                }
4329                err = og_cmd_stop(root, &params);
4330        } else if (!strncmp(cmd, "refresh", strlen("refresh"))) {
4331                if (method != OG_METHOD_POST)
4332                        return og_client_method_not_found(cli);
4333
4334                if (!root) {
4335                        syslog(LOG_ERR, "command refresh with no payload\n");
4336                        return og_client_bad_request(cli);
4337                }
4338                err = og_cmd_refresh(root, &params);
4339        } else if (!strncmp(cmd, "hardware", strlen("hardware"))) {
4340                if (method != OG_METHOD_POST)
4341                        return og_client_method_not_found(cli);
4342
4343                if (!root) {
4344                        syslog(LOG_ERR, "command hardware with no payload\n");
4345                        return og_client_bad_request(cli);
4346                }
4347                err = og_cmd_hardware(root, &params);
4348        } else if (!strncmp(cmd, "software", strlen("software"))) {
4349                if (method != OG_METHOD_POST)
4350                        return og_client_method_not_found(cli);
4351
4352                if (!root) {
4353                        syslog(LOG_ERR, "command software with no payload\n");
4354                        return og_client_bad_request(cli);
4355                }
4356                err = og_cmd_software(root, &params);
4357        } else if (!strncmp(cmd, "image/create/basic",
4358                            strlen("image/create/basic"))) {
4359                if (method != OG_METHOD_POST)
4360                        return og_client_method_not_found(cli);
4361
4362                if (!root) {
4363                        syslog(LOG_ERR, "command create with no payload\n");
4364                        return og_client_bad_request(cli);
4365                }
4366                err = og_cmd_create_basic_image(root, &params);
4367        } else if (!strncmp(cmd, "image/create/incremental",
4368                            strlen("image/create/incremental"))) {
4369                if (method != OG_METHOD_POST)
4370                        return og_client_method_not_found(cli);
4371
4372                if (!root) {
4373                        syslog(LOG_ERR, "command create with no payload\n");
4374                        return og_client_bad_request(cli);
4375                }
4376                err = og_cmd_create_incremental_image(root, &params);
4377        } else if (!strncmp(cmd, "image/create", strlen("image/create"))) {
4378                if (method != OG_METHOD_POST)
4379                        return og_client_method_not_found(cli);
4380
4381                if (!root) {
4382                        syslog(LOG_ERR, "command create with no payload\n");
4383                        return og_client_bad_request(cli);
4384                }
4385                err = og_cmd_create_image(root, &params);
4386        } else if (!strncmp(cmd, "image/restore/basic",
4387                                strlen("image/restore/basic"))) {
4388                if (method != OG_METHOD_POST)
4389                        return og_client_method_not_found(cli);
4390
4391                if (!root) {
4392                        syslog(LOG_ERR, "command create with no payload\n");
4393                        return og_client_bad_request(cli);
4394                }
4395                err = og_cmd_restore_basic_image(root, &params);
4396        } else if (!strncmp(cmd, "image/restore/incremental",
4397                                strlen("image/restore/incremental"))) {
4398                if (method != OG_METHOD_POST)
4399                        return og_client_method_not_found(cli);
4400
4401                if (!root) {
4402                        syslog(LOG_ERR, "command create with no payload\n");
4403                        return og_client_bad_request(cli);
4404                }
4405                err = og_cmd_restore_incremental_image(root, &params);
4406        } else if (!strncmp(cmd, "image/restore", strlen("image/restore"))) {
4407                if (method != OG_METHOD_POST)
4408                        return og_client_method_not_found(cli);
4409
4410                if (!root) {
4411                        syslog(LOG_ERR, "command create with no payload\n");
4412                        return og_client_bad_request(cli);
4413                }
4414                err = og_cmd_restore_image(root, &params);
4415        } else if (!strncmp(cmd, "setup", strlen("setup"))) {
4416                if (method != OG_METHOD_POST)
4417                        return og_client_method_not_found(cli);
4418
4419                if (!root) {
4420                        syslog(LOG_ERR, "command create with no payload\n");
4421                        return og_client_bad_request(cli);
4422                }
4423                err = og_cmd_setup(root, &params);
4424        } else if (!strncmp(cmd, "run/schedule", strlen("run/schedule"))) {
4425                if (method != OG_METHOD_POST)
4426                        return og_client_method_not_found(cli);
4427
4428                if (!root) {
4429                        syslog(LOG_ERR, "command create with no payload\n");
4430                        return og_client_bad_request(cli);
4431                }
4432
4433                err = og_cmd_run_schedule(root, &params);
4434        } else if (!strncmp(cmd, "task/run", strlen("task/run"))) {
4435                if (method != OG_METHOD_POST)
4436                        return og_client_method_not_found(cli);
4437
4438                if (!root) {
4439                        syslog(LOG_ERR, "command task with no payload\n");
4440                        return og_client_bad_request(cli);
4441                }
4442                err = og_cmd_task_post(root, &params);
4443        } else if (!strncmp(cmd, "schedule/create",
4444                            strlen("schedule/create"))) {
4445                if (method != OG_METHOD_POST)
4446                        return og_client_method_not_found(cli);
4447
4448                if (!root) {
4449                        syslog(LOG_ERR, "command task with no payload\n");
4450                        return og_client_bad_request(cli);
4451                }
4452                err = og_cmd_schedule_create(root, &params);
4453        } else if (!strncmp(cmd, "schedule/delete",
4454                            strlen("schedule/delete"))) {
4455                if (method != OG_METHOD_POST)
4456                        return og_client_method_not_found(cli);
4457
4458                if (!root) {
4459                        syslog(LOG_ERR, "command task with no payload\n");
4460                        return og_client_bad_request(cli);
4461                }
4462                err = og_cmd_schedule_delete(root, &params);
4463        } else if (!strncmp(cmd, "schedule/update",
4464                            strlen("schedule/update"))) {
4465                if (method != OG_METHOD_POST)
4466                        return og_client_method_not_found(cli);
4467
4468                if (!root) {
4469                        syslog(LOG_ERR, "command task with no payload\n");
4470                        return og_client_bad_request(cli);
4471                }
4472                err = og_cmd_schedule_update(root, &params);
4473        } else if (!strncmp(cmd, "schedule/get",
4474                            strlen("schedule/get"))) {
4475                if (method != OG_METHOD_POST)
4476                        return og_client_method_not_found(cli);
4477
4478                err = og_cmd_schedule_get(root, &params, buf_reply);
4479        } else {
4480                syslog(LOG_ERR, "unknown command: %.32s ...\n", cmd);
4481                err = og_client_not_found(cli);
4482        }
4483
4484        if (root)
4485                json_decref(root);
4486
4487        if (err < 0)
4488                return og_client_bad_request(cli);
4489
4490        err = og_client_ok(cli, buf_reply);
4491        if (err < 0) {
4492                syslog(LOG_ERR, "HTTP response to %s:%hu is too large\n",
4493                       inet_ntoa(cli->addr.sin_addr),
4494                       ntohs(cli->addr.sin_port));
4495        }
4496
4497        return err;
4498}
4499
4500static int og_client_state_recv_hdr_rest(struct og_client *cli)
4501{
4502        char *ptr;
4503
4504        ptr = strstr(cli->buf, "\r\n\r\n");
4505        if (!ptr)
4506                return 0;
4507
4508        cli->msg_len = ptr - cli->buf + 4;
4509
4510        ptr = strstr(cli->buf, "Content-Length: ");
4511        if (ptr) {
4512                sscanf(ptr, "Content-Length: %i[^\r\n]", &cli->content_length);
4513                if (cli->content_length < 0)
4514                        return -1;
4515                cli->msg_len += cli->content_length;
4516        }
4517
4518        ptr = strstr(cli->buf, "Authorization: ");
4519        if (ptr)
4520                sscanf(ptr, "Authorization: %63[^\r\n]", cli->auth_token);
4521
4522        return 1;
4523}
4524
4525static int og_client_recv(struct og_client *cli, int events)
4526{
4527        struct ev_io *io = &cli->io;
4528        int ret;
4529
4530        if (events & EV_ERROR) {
4531                syslog(LOG_ERR, "unexpected error event from client %s:%hu\n",
4532                               inet_ntoa(cli->addr.sin_addr),
4533                               ntohs(cli->addr.sin_port));
4534                return 0;
4535        }
4536
4537        ret = recv(io->fd, cli->buf + cli->buf_len,
4538                   sizeof(cli->buf) - cli->buf_len, 0);
4539        if (ret <= 0) {
4540                if (ret < 0) {
4541                        syslog(LOG_ERR, "error reading from client %s:%hu (%s)\n",
4542                               inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port),
4543                               strerror(errno));
4544                } else {
4545                        syslog(LOG_DEBUG, "closed connection by %s:%hu\n",
4546                               inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
4547                }
4548                return ret;
4549        }
4550
4551        return ret;
4552}
4553
4554static void og_client_read_cb(struct ev_loop *loop, struct ev_io *io, int events)
4555{
4556        struct og_client *cli;
4557        int ret;
4558
4559        cli = container_of(io, struct og_client, io);
4560
4561        ret = og_client_recv(cli, events);
4562        if (ret <= 0)
4563                goto close;
4564
4565        if (cli->keepalive_idx >= 0)
4566                return;
4567
4568        ev_timer_again(loop, &cli->timer);
4569
4570        cli->buf_len += ret;
4571        if (cli->buf_len >= sizeof(cli->buf)) {
4572                syslog(LOG_ERR, "client request from %s:%hu is too long\n",
4573                       inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
4574                og_client_payload_too_large(cli);
4575                goto close;
4576        }
4577
4578        switch (cli->state) {
4579        case OG_CLIENT_RECEIVING_HEADER:
4580                ret = og_client_state_recv_hdr_rest(cli);
4581                if (ret < 0)
4582                        goto close;
4583                if (!ret)
4584                        return;
4585
4586                cli->state = OG_CLIENT_RECEIVING_PAYLOAD;
4587                /* Fall through. */
4588        case OG_CLIENT_RECEIVING_PAYLOAD:
4589                /* Still not enough data to process request. */
4590                if (cli->buf_len < cli->msg_len)
4591                        return;
4592
4593                cli->state = OG_CLIENT_PROCESSING_REQUEST;
4594                /* fall through. */
4595        case OG_CLIENT_PROCESSING_REQUEST:
4596                ret = og_client_state_process_payload_rest(cli);
4597                if (ret < 0) {
4598                        syslog(LOG_ERR, "Failed to process HTTP request from %s:%hu\n",
4599                               inet_ntoa(cli->addr.sin_addr),
4600                               ntohs(cli->addr.sin_port));
4601                }
4602                if (ret < 0)
4603                        goto close;
4604
4605                if (cli->keepalive_idx < 0) {
4606                        syslog(LOG_DEBUG, "server closing connection to %s:%hu\n",
4607                               inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
4608                        goto close;
4609                } else {
4610                        syslog(LOG_DEBUG, "leaving client %s:%hu in keepalive mode\n",
4611                               inet_ntoa(cli->addr.sin_addr),
4612                               ntohs(cli->addr.sin_port));
4613                        og_client_keepalive(loop, cli);
4614                        og_client_reset_state(cli);
4615                }
4616                break;
4617        default:
4618                syslog(LOG_ERR, "unknown state, critical internal error\n");
4619                goto close;
4620        }
4621        return;
4622close:
4623        ev_timer_stop(loop, &cli->timer);
4624        og_client_release(loop, cli);
4625}
4626
4627enum og_agent_state {
4628        OG_AGENT_RECEIVING_HEADER       = 0,
4629        OG_AGENT_RECEIVING_PAYLOAD,
4630        OG_AGENT_PROCESSING_RESPONSE,
4631};
4632
4633static int og_agent_state_recv_hdr_rest(struct og_client *cli)
4634{
4635        char *ptr;
4636
4637        ptr = strstr(cli->buf, "\r\n\r\n");
4638        if (!ptr)
4639                return 0;
4640
4641        cli->msg_len = ptr - cli->buf + 4;
4642
4643        ptr = strstr(cli->buf, "Content-Length: ");
4644        if (ptr) {
4645                sscanf(ptr, "Content-Length: %i[^\r\n]", &cli->content_length);
4646                if (cli->content_length < 0)
4647                        return -1;
4648                cli->msg_len += cli->content_length;
4649        }
4650
4651        return 1;
4652}
4653
4654static void og_agent_reset_state(struct og_client *cli)
4655{
4656        cli->state = OG_AGENT_RECEIVING_HEADER;
4657        cli->buf_len = 0;
4658        cli->content_length = 0;
4659        memset(cli->buf, 0, sizeof(cli->buf));
4660}
4661
4662static int og_dbi_get_computer_info(struct og_computer *computer,
4663                                    struct in_addr addr)
4664{
4665        const char *msglog;
4666        struct og_dbi *dbi;
4667        dbi_result result;
4668
4669        dbi = og_dbi_open(&dbi_config);
4670        if (!dbi) {
4671                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
4672                       __func__, __LINE__);
4673                return -1;
4674        }
4675        result = dbi_conn_queryf(dbi->conn,
4676                                 "SELECT ordenadores.idordenador,"
4677                                 "       ordenadores.nombreordenador,"
4678                                 "       ordenadores.idaula,"
4679                                 "       centros.idcentro FROM ordenadores "
4680                                 "INNER JOIN aulas ON aulas.idaula=ordenadores.idaula "
4681                                 "INNER JOIN centros ON centros.idcentro=aulas.idcentro "
4682                                 "WHERE ordenadores.ip='%s'", inet_ntoa(addr));
4683        if (!result) {
4684                dbi_conn_error(dbi->conn, &msglog);
4685                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
4686                       __func__, __LINE__, msglog);
4687                return -1;
4688        }
4689        if (!dbi_result_next_row(result)) {
4690                syslog(LOG_ERR, "client does not exist in database (%s:%d)\n",
4691                       __func__, __LINE__);
4692                dbi_result_free(result);
4693                return -1;
4694        }
4695
4696        computer->id = dbi_result_get_uint(result, "idordenador");
4697        computer->center = dbi_result_get_uint(result, "idcentro");
4698        computer->room = dbi_result_get_uint(result, "idaula");
4699        strncpy(computer->name,
4700                dbi_result_get_string(result, "nombreordenador"),
4701                OG_COMPUTER_NAME_MAXLEN);
4702
4703        dbi_result_free(result);
4704        og_dbi_close(dbi);
4705
4706        return 0;
4707}
4708
4709static int og_resp_probe(struct og_client *cli, json_t *data)
4710{
4711        const char *status = NULL;
4712        const char *key;
4713        json_t *value;
4714        int err = 0;
4715
4716        if (json_typeof(data) != JSON_OBJECT)
4717                return -1;
4718
4719        json_object_foreach(data, key, value) {
4720                if (!strcmp(key, "status")) {
4721                        err = og_json_parse_string(value, &status);
4722                        if (err < 0)
4723                                return err;
4724                } else {
4725                        return -1;
4726                }
4727        }
4728
4729        if (!strcmp(status, "BSY"))
4730                cli->status = OG_CLIENT_STATUS_BUSY;
4731        else if (!strcmp(status, "OPG"))
4732                cli->status = OG_CLIENT_STATUS_OGLIVE;
4733
4734        return status ? 0 : -1;
4735}
4736
4737static int og_resp_shell_run(struct og_client *cli, json_t *data)
4738{
4739        const char *output = NULL;
4740        char filename[4096];
4741        const char *key;
4742        json_t *value;
4743        int err = -1;
4744        FILE *file;
4745
4746        if (json_typeof(data) != JSON_OBJECT)
4747                return -1;
4748
4749        json_object_foreach(data, key, value) {
4750                if (!strcmp(key, "out")) {
4751                        err = og_json_parse_string(value, &output);
4752                        if (err < 0)
4753                                return err;
4754                } else {
4755                        return -1;
4756                }
4757        }
4758
4759        if (!output) {
4760                syslog(LOG_ERR, "%s:%d: malformed json response\n",
4761                       __FILE__, __LINE__);
4762                return -1;
4763        }
4764
4765        sprintf(filename, "/tmp/_Seconsola_%s", inet_ntoa(cli->addr.sin_addr));
4766        file = fopen(filename, "wt");
4767        if (!file) {
4768                syslog(LOG_ERR, "cannot open file %s: %s\n",
4769                       filename, strerror(errno));
4770                return -1;
4771        }
4772
4773        fprintf(file, "%s", output);
4774        fclose(file);
4775
4776        return 0;
4777}
4778
4779struct og_computer_legacy  {
4780        char center[OG_DB_INT_MAXLEN + 1];
4781        char id[OG_DB_INT_MAXLEN + 1];
4782        char hardware[8192];
4783};
4784
4785static int og_resp_hardware(json_t *data, struct og_client *cli)
4786{
4787        struct og_computer_legacy legacy = {};
4788        const char *hardware = NULL;
4789        struct og_computer computer;
4790        struct og_dbi *dbi;
4791        const char *key;
4792        json_t *value;
4793        int err = 0;
4794        bool res;
4795
4796        if (json_typeof(data) != JSON_OBJECT)
4797                return -1;
4798
4799        json_object_foreach(data, key, value) {
4800                if (!strcmp(key, "hardware")) {
4801                        err = og_json_parse_string(value, &hardware);
4802                        if (err < 0)
4803                                return -1;
4804                } else {
4805                        return -1;
4806                }
4807        }
4808
4809        if (!hardware) {
4810                syslog(LOG_ERR, "malformed response json\n");
4811                return -1;
4812        }
4813
4814        err = og_dbi_get_computer_info(&computer, cli->addr.sin_addr);
4815        if (err < 0)
4816                return -1;
4817
4818        snprintf(legacy.center, sizeof(legacy.center), "%d", computer.center);
4819        snprintf(legacy.id, sizeof(legacy.id), "%d", computer.id);
4820        snprintf(legacy.hardware, sizeof(legacy.hardware), "%s", hardware);
4821
4822        dbi = og_dbi_open(&dbi_config);
4823        if (!dbi) {
4824                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
4825                       __func__, __LINE__);
4826                return -1;
4827        }
4828
4829        res = actualizaHardware(dbi, legacy.hardware, legacy.id, computer.name,
4830                                legacy.center);
4831        og_dbi_close(dbi);
4832
4833        if (!res) {
4834                syslog(LOG_ERR, "Problem updating client configuration\n");
4835                return -1;
4836        }
4837
4838        return 0;
4839}
4840
4841struct og_software_legacy {
4842        char software[8192];
4843        char center[OG_DB_INT_MAXLEN + 1];
4844        char part[OG_DB_SMALLINT_MAXLEN + 1];
4845        char id[OG_DB_INT_MAXLEN + 1];
4846};
4847
4848static int og_resp_software(json_t *data, struct og_client *cli)
4849{
4850        struct og_software_legacy legacy = {};
4851        const char *partition = NULL;
4852        const char *software = NULL;
4853        struct og_computer computer;
4854        struct og_dbi *dbi;
4855        const char *key;
4856        json_t *value;
4857        int err = 0;
4858        bool res;
4859
4860        if (json_typeof(data) != JSON_OBJECT)
4861                return -1;
4862
4863        json_object_foreach(data, key, value) {
4864                if (!strcmp(key, "software"))
4865                        err = og_json_parse_string(value, &software);
4866                else if (!strcmp(key, "partition"))
4867                        err = og_json_parse_string(value, &partition);
4868                else
4869                        return -1;
4870
4871                if (err < 0)
4872                        return -1;
4873        }
4874
4875        if (!software || !partition) {
4876                syslog(LOG_ERR, "malformed response json\n");
4877                return -1;
4878        }
4879
4880        err = og_dbi_get_computer_info(&computer, cli->addr.sin_addr);
4881        if (err < 0)
4882                return -1;
4883
4884        snprintf(legacy.software, sizeof(legacy.software), "%s", software);
4885        snprintf(legacy.part, sizeof(legacy.part), "%s", partition);
4886        snprintf(legacy.id, sizeof(legacy.id), "%d", computer.id);
4887        snprintf(legacy.center, sizeof(legacy.center), "%d", computer.center);
4888
4889        dbi = og_dbi_open(&dbi_config);
4890        if (!dbi) {
4891                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
4892                       __func__, __LINE__);
4893                return -1;
4894        }
4895
4896        res = actualizaSoftware(dbi, legacy.software, legacy.part, legacy.id,
4897                                computer.name, legacy.center);
4898        og_dbi_close(dbi);
4899
4900        if (!res) {
4901                syslog(LOG_ERR, "Problem updating client configuration\n");
4902                return -1;
4903        }
4904
4905        return 0;
4906}
4907
4908#define OG_PARAMS_RESP_REFRESH  (OG_PARAM_PART_DISK |           \
4909                                 OG_PARAM_PART_NUMBER |         \
4910                                 OG_PARAM_PART_CODE |           \
4911                                 OG_PARAM_PART_FILESYSTEM |     \
4912                                 OG_PARAM_PART_OS |             \
4913                                 OG_PARAM_PART_SIZE |           \
4914                                 OG_PARAM_PART_USED_SIZE)
4915
4916static int og_json_parse_partition_array(json_t *value,
4917                                         struct og_partition *partitions)
4918{
4919        json_t *element;
4920        int i, err;
4921
4922        if (json_typeof(value) != JSON_ARRAY)
4923                return -1;
4924
4925        for (i = 0; i < json_array_size(value) && i < OG_PARTITION_MAX; i++) {
4926                element = json_array_get(value, i);
4927
4928                err = og_json_parse_partition(element, &partitions[i],
4929                                              OG_PARAMS_RESP_REFRESH);
4930                if (err < 0)
4931                        return err;
4932        }
4933
4934        return 0;
4935}
4936
4937static int og_resp_refresh(json_t *data, struct og_client *cli)
4938{
4939        struct og_partition partitions[OG_PARTITION_MAX] = {};
4940        const char *serial_number = NULL;
4941        struct og_partition disk_setup;
4942        struct og_computer computer;
4943        char cfg[1024] = {};
4944        struct og_dbi *dbi;
4945        const char *key;
4946        unsigned int i;
4947        json_t *value;
4948        int err = 0;
4949        bool res;
4950
4951        if (json_typeof(data) != JSON_OBJECT)
4952                return -1;
4953
4954        json_object_foreach(data, key, value) {
4955                if (!strcmp(key, "disk_setup")) {
4956                        err = og_json_parse_partition(value,
4957                                                      &disk_setup,
4958                                                      OG_PARAMS_RESP_REFRESH);
4959                } else if (!strcmp(key, "partition_setup")) {
4960                        err = og_json_parse_partition_array(value, partitions);
4961                } else if (!strcmp(key, "serial_number")) {
4962                        err = og_json_parse_string(value, &serial_number);
4963                } else {
4964                        return -1;
4965                }
4966
4967                if (err < 0)
4968                        return err;
4969        }
4970
4971        err = og_dbi_get_computer_info(&computer, cli->addr.sin_addr);
4972        if (err < 0)
4973                return -1;
4974
4975        if (strlen(serial_number) > 0)
4976                snprintf(cfg, sizeof(cfg), "ser=%s\n", serial_number);
4977
4978        if (!disk_setup.disk || !disk_setup.number || !disk_setup.code ||
4979            !disk_setup.filesystem || !disk_setup.os || !disk_setup.size ||
4980            !disk_setup.used_size)
4981                return -1;
4982
4983        snprintf(cfg + strlen(cfg), sizeof(cfg) - strlen(cfg),
4984                 "disk=%s\tpar=%s\tcpt=%s\tfsi=%s\tsoi=%s\ttam=%s\tuso=%s\n",
4985                 disk_setup.disk, disk_setup.number, disk_setup.code,
4986                 disk_setup.filesystem, disk_setup.os, disk_setup.size,
4987                 disk_setup.used_size);
4988
4989        for (i = 0; i < OG_PARTITION_MAX; i++) {
4990                if (!partitions[i].disk || !partitions[i].number ||
4991                    !partitions[i].code || !partitions[i].filesystem ||
4992                    !partitions[i].os || !partitions[i].size ||
4993                    !partitions[i].used_size)
4994                        continue;
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                         partitions[i].disk, partitions[i].number,
4999                         partitions[i].code, partitions[i].filesystem,
5000                         partitions[i].os, partitions[i].size,
5001                         partitions[i].used_size);
5002        }
5003
5004        dbi = og_dbi_open(&dbi_config);
5005        if (!dbi) {
5006                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
5007                                  __func__, __LINE__);
5008                return -1;
5009        }
5010        res = actualizaConfiguracion(dbi, cfg, computer.id);
5011        og_dbi_close(dbi);
5012
5013        if (!res) {
5014                syslog(LOG_ERR, "Problem updating client configuration\n");
5015                return -1;
5016        }
5017
5018        return 0;
5019}
5020
5021static int og_resp_image_create(json_t *data, struct og_client *cli)
5022{
5023        struct og_software_legacy soft_legacy;
5024        struct og_image_legacy img_legacy;
5025        const char *partition = NULL;
5026        const char *software = NULL;
5027        const char *image_id = NULL;
5028        struct og_computer computer;
5029        const char *disk = NULL;
5030        const char *code = NULL;
5031        const char *name = NULL;
5032        const char *repo = NULL;
5033        struct og_dbi *dbi;
5034        const char *key;
5035        json_t *value;
5036        int err = 0;
5037        bool res;
5038
5039        if (json_typeof(data) != JSON_OBJECT)
5040                return -1;
5041
5042        json_object_foreach(data, key, value) {
5043                if (!strcmp(key, "software"))
5044                        err = og_json_parse_string(value, &software);
5045                else if (!strcmp(key, "partition"))
5046                        err = og_json_parse_string(value, &partition);
5047                else if (!strcmp(key, "disk"))
5048                        err = og_json_parse_string(value, &disk);
5049                else if (!strcmp(key, "code"))
5050                        err = og_json_parse_string(value, &code);
5051                else if (!strcmp(key, "id"))
5052                        err = og_json_parse_string(value, &image_id);
5053                else if (!strcmp(key, "name"))
5054                        err = og_json_parse_string(value, &name);
5055                else if (!strcmp(key, "repository"))
5056                        err = og_json_parse_string(value, &repo);
5057                else
5058                        return -1;
5059
5060                if (err < 0)
5061                        return err;
5062        }
5063
5064        if (!software || !partition || !disk || !code || !image_id || !name ||
5065            !repo) {
5066                syslog(LOG_ERR, "malformed response json\n");
5067                return -1;
5068        }
5069
5070        err = og_dbi_get_computer_info(&computer, cli->addr.sin_addr);
5071        if (err < 0)
5072                return -1;
5073
5074        snprintf(soft_legacy.center, sizeof(soft_legacy.center), "%d",
5075                 computer.center);
5076        snprintf(soft_legacy.software, sizeof(soft_legacy.software), "%s",
5077                 software);
5078        snprintf(img_legacy.image_id, sizeof(img_legacy.image_id), "%s",
5079                 image_id);
5080        snprintf(soft_legacy.id, sizeof(soft_legacy.id), "%d", computer.id);
5081        snprintf(img_legacy.part, sizeof(img_legacy.part), "%s", partition);
5082        snprintf(img_legacy.disk, sizeof(img_legacy.disk), "%s", disk);
5083        snprintf(img_legacy.code, sizeof(img_legacy.code), "%s", code);
5084        snprintf(img_legacy.name, sizeof(img_legacy.name), "%s", name);
5085        snprintf(img_legacy.repo, sizeof(img_legacy.repo), "%s", repo);
5086
5087        dbi = og_dbi_open(&dbi_config);
5088        if (!dbi) {
5089                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
5090                       __func__, __LINE__);
5091                return -1;
5092        }
5093
5094        res = actualizaSoftware(dbi,
5095                                soft_legacy.software,
5096                                img_legacy.part,
5097                                soft_legacy.id,
5098                                computer.name,
5099                                soft_legacy.center);
5100        if (!res) {
5101                og_dbi_close(dbi);
5102                syslog(LOG_ERR, "Problem updating client configuration\n");
5103                return -1;
5104        }
5105
5106        res = actualizaCreacionImagen(dbi,
5107                                      img_legacy.image_id,
5108                                      img_legacy.disk,
5109                                      img_legacy.part,
5110                                      img_legacy.code,
5111                                      img_legacy.repo,
5112                                      soft_legacy.id);
5113        og_dbi_close(dbi);
5114
5115        if (!res) {
5116                syslog(LOG_ERR, "Problem updating client configuration\n");
5117                return -1;
5118        }
5119
5120        return 0;
5121}
5122
5123static int og_resp_image_restore(json_t *data, struct og_client *cli)
5124{
5125        struct og_software_legacy soft_legacy;
5126        struct og_image_legacy img_legacy;
5127        const char *partition = NULL;
5128        const char *image_id = NULL;
5129        struct og_computer computer;
5130        const char *disk = NULL;
5131        dbi_result query_result;
5132        struct og_dbi *dbi;
5133        const char *key;
5134        json_t *value;
5135        int err = 0;
5136        bool res;
5137
5138        if (json_typeof(data) != JSON_OBJECT)
5139                return -1;
5140
5141        json_object_foreach(data, key, value) {
5142                if (!strcmp(key, "partition"))
5143                        err = og_json_parse_string(value, &partition);
5144                else if (!strcmp(key, "disk"))
5145                        err = og_json_parse_string(value, &disk);
5146                else if (!strcmp(key, "image_id"))
5147                        err = og_json_parse_string(value, &image_id);
5148                else
5149                        return -1;
5150
5151                if (err < 0)
5152                        return err;
5153        }
5154
5155        if (!partition || !disk || !image_id) {
5156                syslog(LOG_ERR, "malformed response json\n");
5157                return -1;
5158        }
5159
5160        err = og_dbi_get_computer_info(&computer, cli->addr.sin_addr);
5161        if (err < 0)
5162                return -1;
5163
5164        snprintf(img_legacy.image_id, sizeof(img_legacy.image_id), "%s",
5165                 image_id);
5166        snprintf(img_legacy.part, sizeof(img_legacy.part), "%s", partition);
5167        snprintf(img_legacy.disk, sizeof(img_legacy.disk), "%s", disk);
5168        snprintf(soft_legacy.id, sizeof(soft_legacy.id), "%d", computer.id);
5169
5170        dbi = og_dbi_open(&dbi_config);
5171        if (!dbi) {
5172                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
5173                       __func__, __LINE__);
5174                return -1;
5175        }
5176
5177        query_result = dbi_conn_queryf(dbi->conn,
5178                                       "SELECT idperfilsoft FROM imagenes "
5179                                       " WHERE idimagen='%s'",
5180                                       image_id);
5181        if (!query_result) {
5182                og_dbi_close(dbi);
5183                syslog(LOG_ERR, "failed to query database\n");
5184                return -1;
5185        }
5186        if (!dbi_result_next_row(query_result)) {
5187                dbi_result_free(query_result);
5188                og_dbi_close(dbi);
5189                syslog(LOG_ERR, "software profile does not exist in database\n");
5190                return -1;
5191        }
5192        snprintf(img_legacy.software_id, sizeof(img_legacy.software_id),
5193                 "%d", dbi_result_get_uint(query_result, "idperfilsoft"));
5194        dbi_result_free(query_result);
5195
5196        res = actualizaRestauracionImagen(dbi,
5197                                          img_legacy.image_id,
5198                                          img_legacy.disk,
5199                                          img_legacy.part,
5200                                          soft_legacy.id,
5201                                          img_legacy.software_id);
5202        og_dbi_close(dbi);
5203
5204        if (!res) {
5205                syslog(LOG_ERR, "Problem updating client configuration\n");
5206                return -1;
5207        }
5208
5209        return 0;
5210}
5211
5212static int og_agent_state_process_response(struct og_client *cli)
5213{
5214        json_error_t json_err;
5215        json_t *root;
5216        int err = -1;
5217        char *body;
5218
5219        if (strncmp(cli->buf, "HTTP/1.0 200 OK", strlen("HTTP/1.0 200 OK")))
5220                return -1;
5221
5222        if (!cli->content_length) {
5223                cli->last_cmd = OG_CMD_UNSPEC;
5224                return 0;
5225        }
5226
5227        body = strstr(cli->buf, "\r\n\r\n") + 4;
5228
5229        root = json_loads(body, 0, &json_err);
5230        if (!root) {
5231                syslog(LOG_ERR, "%s:%d: malformed json line %d: %s\n",
5232                       __FILE__, __LINE__, json_err.line, json_err.text);
5233                return -1;
5234        }
5235
5236        switch (cli->last_cmd) {
5237        case OG_CMD_PROBE:
5238                err = og_resp_probe(cli, root);
5239                break;
5240        case OG_CMD_SHELL_RUN:
5241                err = og_resp_shell_run(cli, root);
5242                break;
5243        case OG_CMD_HARDWARE:
5244                err = og_resp_hardware(root, cli);
5245                break;
5246        case OG_CMD_SOFTWARE:
5247                err = og_resp_software(root, cli);
5248                break;
5249        case OG_CMD_REFRESH:
5250                err = og_resp_refresh(root, cli);
5251                break;
5252        case OG_CMD_SETUP:
5253                err = og_resp_refresh(root, cli);
5254                break;
5255        case OG_CMD_IMAGE_CREATE:
5256                err = og_resp_image_create(root, cli);
5257                break;
5258        case OG_CMD_IMAGE_RESTORE:
5259                err = og_resp_image_restore(root, cli);
5260                break;
5261        default:
5262                err = -1;
5263                break;
5264        }
5265
5266        cli->last_cmd = OG_CMD_UNSPEC;
5267
5268        return err;
5269}
5270
5271static void og_agent_deliver_pending_cmd(struct og_client *cli)
5272{
5273        const struct og_cmd *cmd;
5274
5275        cmd = og_cmd_find(inet_ntoa(cli->addr.sin_addr));
5276        if (!cmd)
5277                return;
5278
5279        og_send_request(cmd->method, cmd->type, &cmd->params, cmd->json);
5280
5281        og_cmd_free(cmd);
5282}
5283
5284static void og_agent_read_cb(struct ev_loop *loop, struct ev_io *io, int events)
5285{
5286        struct og_client *cli;
5287        int ret;
5288
5289        cli = container_of(io, struct og_client, io);
5290
5291        ret = og_client_recv(cli, events);
5292        if (ret <= 0)
5293                goto close;
5294
5295        ev_timer_again(loop, &cli->timer);
5296
5297        cli->buf_len += ret;
5298        if (cli->buf_len >= sizeof(cli->buf)) {
5299                syslog(LOG_ERR, "client request from %s:%hu is too long\n",
5300                       inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
5301                goto close;
5302        }
5303
5304        switch (cli->state) {
5305        case OG_AGENT_RECEIVING_HEADER:
5306                ret = og_agent_state_recv_hdr_rest(cli);
5307                if (ret < 0)
5308                        goto close;
5309                if (!ret)
5310                        return;
5311
5312                cli->state = OG_AGENT_RECEIVING_PAYLOAD;
5313                /* Fall through. */
5314        case OG_AGENT_RECEIVING_PAYLOAD:
5315                /* Still not enough data to process request. */
5316                if (cli->buf_len < cli->msg_len)
5317                        return;
5318
5319                cli->state = OG_AGENT_PROCESSING_RESPONSE;
5320                /* fall through. */
5321        case OG_AGENT_PROCESSING_RESPONSE:
5322                ret = og_agent_state_process_response(cli);
5323                if (ret < 0) {
5324                        syslog(LOG_ERR, "Failed to process HTTP request from %s:%hu\n",
5325                               inet_ntoa(cli->addr.sin_addr),
5326                               ntohs(cli->addr.sin_port));
5327                        goto close;
5328                }
5329                og_agent_deliver_pending_cmd(cli);
5330
5331                syslog(LOG_DEBUG, "leaving client %s:%hu in keepalive mode\n",
5332                       inet_ntoa(cli->addr.sin_addr),
5333                       ntohs(cli->addr.sin_port));
5334                og_agent_reset_state(cli);
5335                break;
5336        default:
5337                syslog(LOG_ERR, "unknown state, critical internal error\n");
5338                goto close;
5339        }
5340        return;
5341close:
5342        ev_timer_stop(loop, &cli->timer);
5343        og_client_release(loop, cli);
5344}
5345
5346static void og_client_timer_cb(struct ev_loop *loop, ev_timer *timer, int events)
5347{
5348        struct og_client *cli;
5349
5350        cli = container_of(timer, struct og_client, timer);
5351        if (cli->keepalive_idx >= 0) {
5352                ev_timer_again(loop, &cli->timer);
5353                return;
5354        }
5355        syslog(LOG_ERR, "timeout request for client %s:%hu\n",
5356               inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
5357
5358        og_client_release(loop, cli);
5359}
5360
5361static void og_agent_send_probe(struct og_client *cli)
5362{
5363        json_t *id, *name, *center, *room, *object;
5364        struct og_msg_params params;
5365        struct og_computer computer;
5366        int err;
5367
5368        err = og_dbi_get_computer_info(&computer, cli->addr.sin_addr);
5369        if (err < 0)
5370                return;
5371
5372        params.ips_array[0] = inet_ntoa(cli->addr.sin_addr);
5373        params.ips_array_len = 1;
5374
5375        id = json_integer(computer.id);
5376        center = json_integer(computer.center);
5377        room = json_integer(computer.room);
5378        name = json_string(computer.name);
5379
5380        object = json_object();
5381        if (!object)
5382                return;
5383        json_object_set_new(object, "id", id);
5384        json_object_set_new(object, "name", name);
5385        json_object_set_new(object, "center", center);
5386        json_object_set_new(object, "room", room);
5387
5388        err = og_send_request(OG_METHOD_POST, OG_CMD_PROBE, &params, object);
5389        if (err < 0) {
5390                syslog(LOG_ERR, "Can't send probe to: %s\n",
5391                       params.ips_array[0]);
5392        } else {
5393                syslog(LOG_INFO, "Sent probe to: %s\n",
5394                       params.ips_array[0]);
5395        }
5396}
5397
5398static int socket_rest, socket_agent_rest;
5399
5400static void og_server_accept_cb(struct ev_loop *loop, struct ev_io *io,
5401                                int events)
5402{
5403        struct sockaddr_in client_addr;
5404        socklen_t addrlen = sizeof(client_addr);
5405        struct og_client *cli;
5406        int client_sd;
5407
5408        if (events & EV_ERROR)
5409                return;
5410
5411        client_sd = accept(io->fd, (struct sockaddr *)&client_addr, &addrlen);
5412        if (client_sd < 0) {
5413                syslog(LOG_ERR, "cannot accept client connection\n");
5414                return;
5415        }
5416
5417        cli = (struct og_client *)calloc(1, sizeof(struct og_client));
5418        if (!cli) {
5419                close(client_sd);
5420                return;
5421        }
5422        memcpy(&cli->addr, &client_addr, sizeof(client_addr));
5423        if (io->fd == socket_agent_rest)
5424                cli->keepalive_idx = 0;
5425        else
5426                cli->keepalive_idx = -1;
5427
5428        if (io->fd == socket_rest)
5429                cli->rest = true;
5430        else if (io->fd == socket_agent_rest)
5431                cli->agent = true;
5432
5433        syslog(LOG_DEBUG, "connection from client %s:%hu\n",
5434               inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
5435
5436        if (io->fd == socket_agent_rest)
5437                ev_io_init(&cli->io, og_agent_read_cb, client_sd, EV_READ);
5438        else
5439                ev_io_init(&cli->io, og_client_read_cb, client_sd, EV_READ);
5440
5441        ev_io_start(loop, &cli->io);
5442        if (io->fd == socket_agent_rest) {
5443                ev_timer_init(&cli->timer, og_client_timer_cb,
5444                              OG_AGENT_CLIENT_TIMEOUT, 0.);
5445        } else {
5446                ev_timer_init(&cli->timer, og_client_timer_cb,
5447                              OG_CLIENT_TIMEOUT, 0.);
5448        }
5449        ev_timer_start(loop, &cli->timer);
5450        list_add(&cli->list, &client_list);
5451
5452        if (io->fd == socket_agent_rest)
5453                og_agent_send_probe(cli);
5454}
5455
5456static int og_socket_server_init(const char *port)
5457{
5458        struct sockaddr_in local;
5459        int sd, on = 1;
5460
5461        sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
5462        if (sd < 0) {
5463                syslog(LOG_ERR, "cannot create main socket\n");
5464                return -1;
5465        }
5466        setsockopt(sd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(int));
5467
5468        local.sin_addr.s_addr = htonl(INADDR_ANY);
5469        local.sin_family = AF_INET;
5470        local.sin_port = htons(atoi(port));
5471
5472        if (bind(sd, (struct sockaddr *) &local, sizeof(local)) < 0) {
5473                close(sd);
5474                syslog(LOG_ERR, "cannot bind socket\n");
5475                return -1;
5476        }
5477
5478        listen(sd, 250);
5479
5480        return sd;
5481}
5482
5483int main(int argc, char *argv[])
5484{
5485        struct ev_io ev_io_server_rest, ev_io_agent_rest;
5486        int i;
5487
5488        og_loop = ev_default_loop(0);
5489
5490        if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
5491                exit(EXIT_FAILURE);
5492
5493        openlog("ogAdmServer", LOG_PID, LOG_DAEMON);
5494
5495        /*--------------------------------------------------------------------------------------------------------
5496         Validación de parámetros de ejecución y lectura del fichero de configuración del servicio
5497         ---------------------------------------------------------------------------------------------------------*/
5498        if (!validacionParametros(argc, argv, 1)) // Valida parámetros de ejecución
5499                exit(EXIT_FAILURE);
5500
5501        if (!tomaConfiguracion(szPathFileCfg)) { // Toma parametros de configuracion
5502                exit(EXIT_FAILURE);
5503        }
5504
5505        /*--------------------------------------------------------------------------------------------------------
5506         // Inicializa array de información de los clientes
5507         ---------------------------------------------------------------------------------------------------------*/
5508        for (i = 0; i < MAXIMOS_CLIENTES; i++) {
5509                tbsockets[i].ip[0] = '\0';
5510                tbsockets[i].cli = NULL;
5511        }
5512        /*--------------------------------------------------------------------------------------------------------
5513         Creación y configuración del socket del servicio
5514         ---------------------------------------------------------------------------------------------------------*/
5515
5516        socket_rest = og_socket_server_init("8888");
5517        if (socket_rest < 0)
5518                exit(EXIT_FAILURE);
5519
5520        ev_io_init(&ev_io_server_rest, og_server_accept_cb, socket_rest, EV_READ);
5521        ev_io_start(og_loop, &ev_io_server_rest);
5522
5523        socket_agent_rest = og_socket_server_init("8889");
5524        if (socket_agent_rest < 0)
5525                exit(EXIT_FAILURE);
5526
5527        ev_io_init(&ev_io_agent_rest, og_server_accept_cb, socket_agent_rest, EV_READ);
5528        ev_io_start(og_loop, &ev_io_agent_rest);
5529
5530        if (og_dbi_schedule_get() < 0)
5531                exit(EXIT_FAILURE);
5532
5533        og_schedule_next(og_loop);
5534
5535        infoLog(1); // Inicio de sesión
5536
5537        /* old log file has been deprecated. */
5538        og_log(97, false);
5539
5540        syslog(LOG_INFO, "Waiting for connections\n");
5541
5542        while (1)
5543                ev_loop(og_loop, 0);
5544
5545        exit(EXIT_SUCCESS);
5546}
Note: See TracBrowser for help on using the repository browser.