source: ogServer-Git/sources/ogAdmServer.cpp @ d3239f7

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

#941 Consolidate RESPUESTA_Configurar and RESPUESTA_EjecutarScript

These function are almost identical, remove duplicated code.

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