source: ogServer-Git/sources/ogAdmServer.c @ 130b6ff

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

#942 Add weeks and week days to the schedule API

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