source: ogServer-Git/sources/ogAdmServer.c @ af30cc7

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

#980 Add client REST API basic infrastructure in ogAdmServer

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