source: ogServer-Git/sources/ogAdmServer.c @ 3acd4b4

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

#942 add WoL on commands, procedures and tasks

These cases are different from a basic WoL command because they all use
the queue. The queue standard behaviour waits for the client to be ON
to send orders, but in WoL commands the client is going to be OFF. The
behaviour of WoL must be different.

This commit implements WoL for queued commands, procedures and tasks.
The queue now sends Wol commands without waiting to the client to be ON.

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