source: admin/Sources/Services/ogAdmServer/sources/ogAdmServer.c @ 7242996

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

#942 Add /run/task to API REST

This patch adds a new command to the REST API to run tasks.

A task (tarea) is composed of procedures (procedimientos), each procedure is
composed of commands (acciones) that are represented through legacy sockHidra
parameters in the database.

This results in iterating over the task (tareas_acciones) table in the
database to fetch the list of procedures (procedimientos).

Then, this iterates over the list commands that compose a procedures
represented through procedimientos_acciones table.

Finally, this builds and sends the sockHidra legacy message for the client.

This patch includes an implementation of the Linux linked list.

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