source: ogServer-Git/src/rest.c @ 2958d23

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

#942 Use client's IP as filter in GET /hardware

This patch uses client's IP instead of scope ID as a filter for the
request.

Request:
GET /hardware
{

"client": 192.168.56.11?

}

Response:
200 OK
{

"hardware": [

{

"description": "BIOS",
"type": "Tipo de proceso de arranque"

},
{

"description": "QEMU Standard PC (i440FX + PIIX, 1996) v.pc-i440fx-5.1",
"type": "Marca y modelo del equipo"

},
{

"description": "Intel Corp. Intel Core Processor (Haswell, no TSX, IBRS) 2GHz v.pc-i440fx-5.1",
"type": "Microprocesadores"

},
{

"description": "QEMU 2049MiB (DIMM 0)",
"type": "Memorias"

},
{

"description": "Red Hat, Inc. Virtio network device v.00",
"type": "Tarjetas de Red"

}

]

}

  • Property mode set to 100644
File size: 100.4 KB
Line 
1/*
2 * Copyright (C) 2020 Soleta Networks <info@soleta.eu>
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Affero General Public License as published by the
6 * Free Software Foundation, version 3.
7 */
8
9#include "ogAdmServer.h"
10#include "dbi.h"
11#include "utils.h"
12#include "list.h"
13#include "rest.h"
14#include "cfg.h"
15#include "schedule.h"
16#include <ev.h>
17#include <syslog.h>
18#include <sys/ioctl.h>
19#include <ifaddrs.h>
20#include <sys/types.h>
21#include <sys/stat.h>
22#include <fcntl.h>
23#include <jansson.h>
24#include <dirent.h>
25#include <time.h>
26#include <stdlib.h>
27#include <unistd.h>
28#include <sys/wait.h>
29#include <sys/statvfs.h>
30
31struct ev_loop *og_loop;
32
33#define OG_REST_PARAM_ADDR                      (1UL << 0)
34#define OG_REST_PARAM_MAC                       (1UL << 1)
35#define OG_REST_PARAM_WOL_TYPE                  (1UL << 2)
36#define OG_REST_PARAM_RUN_CMD                   (1UL << 3)
37#define OG_REST_PARAM_DISK                      (1UL << 4)
38#define OG_REST_PARAM_PARTITION                 (1UL << 5)
39#define OG_REST_PARAM_REPO                      (1UL << 6)
40#define OG_REST_PARAM_NAME                      (1UL << 7)
41#define OG_REST_PARAM_ID                        (1UL << 8)
42#define OG_REST_PARAM_CODE                      (1UL << 9)
43#define OG_REST_PARAM_TYPE                      (1UL << 10)
44#define OG_REST_PARAM_PROFILE                   (1UL << 11)
45#define OG_REST_PARAM_CACHE                     (1UL << 12)
46#define OG_REST_PARAM_CACHE_SIZE                (1UL << 13)
47#define OG_REST_PARAM_PART_0                    (1UL << 14)
48#define OG_REST_PARAM_PART_1                    (1UL << 15)
49#define OG_REST_PARAM_PART_2                    (1UL << 16)
50#define OG_REST_PARAM_PART_3                    (1UL << 17)
51#define OG_REST_PARAM_SYNC_SYNC                 (1UL << 18)
52#define OG_REST_PARAM_SYNC_DIFF                 (1UL << 19)
53#define OG_REST_PARAM_SYNC_REMOVE               (1UL << 20)
54#define OG_REST_PARAM_SYNC_COMPRESS             (1UL << 21)
55#define OG_REST_PARAM_SYNC_CLEANUP              (1UL << 22)
56#define OG_REST_PARAM_SYNC_CACHE                (1UL << 23)
57#define OG_REST_PARAM_SYNC_CLEANUP_CACHE        (1UL << 24)
58#define OG_REST_PARAM_SYNC_REMOVE_DST           (1UL << 25)
59#define OG_REST_PARAM_SYNC_DIFF_ID              (1UL << 26)
60#define OG_REST_PARAM_SYNC_DIFF_NAME            (1UL << 27)
61#define OG_REST_PARAM_SYNC_PATH                 (1UL << 28)
62#define OG_REST_PARAM_SYNC_METHOD               (1UL << 29)
63#define OG_REST_PARAM_ECHO                      (1UL << 30)
64#define OG_REST_PARAM_TASK                      (1UL << 31)
65#define OG_REST_PARAM_TIME_YEARS                (1UL << 32)
66#define OG_REST_PARAM_TIME_MONTHS               (1UL << 33)
67#define OG_REST_PARAM_TIME_WEEKS                (1UL << 34)
68#define OG_REST_PARAM_TIME_WEEK_DAYS            (1UL << 35)
69#define OG_REST_PARAM_TIME_DAYS                 (1UL << 36)
70#define OG_REST_PARAM_TIME_HOURS                (1UL << 37)
71#define OG_REST_PARAM_TIME_AM_PM                (1UL << 38)
72#define OG_REST_PARAM_TIME_MINUTES              (1UL << 39)
73#define OG_REST_PARAM_NETMASK                   (1UL << 40)
74#define OG_REST_PARAM_SCOPE                     (1UL << 41)
75#define OG_REST_PARAM_MODE                      (1UL << 42)
76
77static LIST_HEAD(client_list);
78
79void og_client_add(struct og_client *cli)
80{
81        list_add(&cli->list, &client_list);
82}
83
84static struct og_client *og_client_find(const char *ip)
85{
86        struct og_client *client;
87        struct in_addr addr;
88        int res;
89
90        res = inet_aton(ip, &addr);
91        if (!res) {
92                syslog(LOG_ERR, "Invalid IP string: %s\n", ip);
93                return NULL;
94        }
95
96        list_for_each_entry(client, &client_list, list) {
97                if (client->addr.sin_addr.s_addr == addr.s_addr && client->agent) {
98                        return client;
99                }
100        }
101
102        return NULL;
103}
104
105static const char *og_client_status(const struct og_client *cli)
106{
107        switch (cli->last_cmd) {
108        case OG_CMD_UNSPEC:
109        case OG_CMD_PROBE:
110                break;
111        default:
112                return "BSY";
113        }
114
115        switch (cli->status) {
116        case OG_CLIENT_STATUS_BUSY:
117                return "BSY";
118        case OG_CLIENT_STATUS_OGLIVE:
119                return "OPG";
120        case OG_CLIENT_STATUS_VIRTUAL:
121                return "VDI";
122        default:
123                return "OFF";
124        }
125}
126
127static bool og_msg_params_validate(const struct og_msg_params *params,
128                                   const uint64_t flags)
129{
130        return (params->flags & flags) == flags;
131}
132
133static bool og_flags_validate(const uint64_t flags,
134                              const uint64_t required_flags)
135{
136        return (flags & required_flags) == required_flags;
137}
138
139static int og_json_parse_clients(json_t *element, struct og_msg_params *params)
140{
141        unsigned int i;
142        json_t *k;
143
144        if (json_typeof(element) != JSON_ARRAY)
145                return -1;
146
147        for (i = 0; i < json_array_size(element); i++) {
148                k = json_array_get(element, i);
149                if (json_typeof(k) != JSON_STRING)
150                        return -1;
151
152                params->ips_array[params->ips_array_len++] =
153                        json_string_value(k);
154
155                params->flags |= OG_REST_PARAM_ADDR;
156        }
157
158        return 0;
159}
160
161static int og_json_parse_partition_setup(json_t *element,
162                                         struct og_msg_params *params)
163{
164        unsigned int i;
165        json_t *k;
166
167        if (json_typeof(element) != JSON_ARRAY)
168                return -1;
169
170        for (i = 0; i < json_array_size(element) && i < OG_PARTITION_MAX; ++i) {
171                k = json_array_get(element, i);
172
173                if (json_typeof(k) != JSON_OBJECT)
174                        return -1;
175
176                if (og_json_parse_partition(k, &params->partition_setup[i],
177                                            OG_PARAM_PART_NUMBER |
178                                            OG_PARAM_PART_CODE |
179                                            OG_PARAM_PART_FILESYSTEM |
180                                            OG_PARAM_PART_SIZE |
181                                            OG_PARAM_PART_FORMAT) < 0)
182                        return -1;
183
184                params->flags |= (OG_REST_PARAM_PART_0 << i);
185        }
186        return 0;
187}
188
189static int og_json_parse_time_params(json_t *element,
190                                     struct og_msg_params *params)
191{
192        const char *key;
193        json_t *value;
194        int err = 0;
195
196        json_object_foreach(element, key, value) {
197                if (!strcmp(key, "years")) {
198                        err = og_json_parse_uint(value, &params->time.years);
199                        params->flags |= OG_REST_PARAM_TIME_YEARS;
200                } else if (!strcmp(key, "months")) {
201                        err = og_json_parse_uint(value, &params->time.months);
202                        params->flags |= OG_REST_PARAM_TIME_MONTHS;
203                } else if (!strcmp(key, "weeks")) {
204                        err = og_json_parse_uint(value, &params->time.weeks);
205                        params->flags |= OG_REST_PARAM_TIME_WEEKS;
206                } else if (!strcmp(key, "week_days")) {
207                        err = og_json_parse_uint(value, &params->time.week_days);
208                        params->flags |= OG_REST_PARAM_TIME_WEEK_DAYS;
209                } else if (!strcmp(key, "days")) {
210                        err = og_json_parse_uint(value, &params->time.days);
211                        params->flags |= OG_REST_PARAM_TIME_DAYS;
212                } else if (!strcmp(key, "hours")) {
213                        err = og_json_parse_uint(value, &params->time.hours);
214                        params->flags |= OG_REST_PARAM_TIME_HOURS;
215                } else if (!strcmp(key, "am_pm")) {
216                        err = og_json_parse_uint(value, &params->time.am_pm);
217                        params->flags |= OG_REST_PARAM_TIME_AM_PM;
218                } else if (!strcmp(key, "minutes")) {
219                        err = og_json_parse_uint(value, &params->time.minutes);
220                        params->flags |= OG_REST_PARAM_TIME_MINUTES;
221                }
222                if (err != 0)
223                        return err;
224        }
225
226        return err;
227}
228
229static const char *og_cmd_to_uri[OG_CMD_MAX] = {
230        [OG_CMD_WOL]            = "wol",
231        [OG_CMD_PROBE]          = "probe",
232        [OG_CMD_SHELL_RUN]      = "shell/run",
233        [OG_CMD_SESSION]        = "session",
234        [OG_CMD_POWEROFF]       = "poweroff",
235        [OG_CMD_REFRESH]        = "refresh",
236        [OG_CMD_REBOOT]         = "reboot",
237        [OG_CMD_STOP]           = "stop",
238        [OG_CMD_HARDWARE]       = "hardware",
239        [OG_CMD_SOFTWARE]       = "software",
240        [OG_CMD_IMAGE_CREATE]   = "image/create",
241        [OG_CMD_IMAGE_RESTORE]  = "image/restore",
242        [OG_CMD_SETUP]          = "setup",
243        [OG_CMD_RUN_SCHEDULE]   = "run/schedule",
244        [OG_CMD_IMAGES]         = "images",
245};
246
247static bool og_client_is_busy(const struct og_client *cli,
248                              enum og_cmd_type type)
249{
250        switch (type) {
251        case OG_CMD_REBOOT:
252        case OG_CMD_POWEROFF:
253        case OG_CMD_STOP:
254                break;
255        default:
256                if (cli->last_cmd != OG_CMD_UNSPEC)
257                        return true;
258                break;
259        }
260
261        return false;
262}
263
264int og_send_request(enum og_rest_method method, enum og_cmd_type type,
265                    const struct og_msg_params *params,
266                    const json_t *data)
267{
268        const char *content_type = "Content-Type: application/json";
269        char content [OG_MSG_REQUEST_MAXLEN - 700] = {};
270        char buf[OG_MSG_REQUEST_MAXLEN] = {};
271        unsigned int content_length;
272        char method_str[5] = {};
273        struct og_client *cli;
274        const char *uri;
275        unsigned int i;
276        int client_sd;
277
278        if (method == OG_METHOD_GET)
279                snprintf(method_str, 5, "GET");
280        else if (method == OG_METHOD_POST)
281                snprintf(method_str, 5, "POST");
282        else
283                return -1;
284
285        if (!data)
286                content_length = 0;
287        else
288                content_length = json_dumpb(data, content,
289                                            OG_MSG_REQUEST_MAXLEN - 700,
290                                            JSON_COMPACT);
291
292        uri = og_cmd_to_uri[type];
293        snprintf(buf, OG_MSG_REQUEST_MAXLEN,
294                 "%s /%s HTTP/1.1\r\nContent-Length: %d\r\n%s\r\n\r\n%s",
295                 method_str, uri, content_length, content_type, content);
296
297        for (i = 0; i < params->ips_array_len; i++) {
298                cli = og_client_find(params->ips_array[i]);
299                if (!cli)
300                        continue;
301
302                if (og_client_is_busy(cli, type))
303                        continue;
304
305                client_sd = cli->io.fd;
306                if (client_sd < 0) {
307                        syslog(LOG_INFO, "Client %s not conected\n",
308                               params->ips_array[i]);
309                        continue;
310                }
311
312                if (send(client_sd, buf, strlen(buf), 0) < 0)
313                        continue;
314
315                cli->last_cmd = type;
316        }
317
318        return 0;
319}
320
321static int og_cmd_post_clients(json_t *element, struct og_msg_params *params)
322{
323        const char *key;
324        json_t *value;
325        int err = 0;
326
327        if (json_typeof(element) != JSON_OBJECT)
328                return -1;
329
330        json_object_foreach(element, key, value) {
331                if (!strcmp(key, "clients"))
332                        err = og_json_parse_clients(value, params);
333
334                if (err < 0)
335                        break;
336        }
337
338        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
339                return -1;
340
341        return og_send_request(OG_METHOD_POST, OG_CMD_PROBE, params, NULL);
342}
343
344struct og_buffer {
345        char    *data;
346        int     len;
347};
348
349static int og_json_dump_clients(const char *buffer, size_t size, void *data)
350{
351        struct og_buffer *og_buffer = (struct og_buffer *)data;
352
353        memcpy(og_buffer->data + og_buffer->len, buffer, size);
354        og_buffer->len += size;
355
356        return 0;
357}
358
359static int og_cmd_get_clients(json_t *element, struct og_msg_params *params,
360                              char *buffer_reply)
361{
362        json_t *root, *array, *addr, *state, *object;
363        struct og_client *client;
364        struct og_buffer og_buffer = {
365                .data   = buffer_reply,
366        };
367
368        array = json_array();
369        if (!array)
370                return -1;
371
372        list_for_each_entry(client, &client_list, list) {
373                if (!client->agent)
374                        continue;
375
376                object = json_object();
377                if (!object) {
378                        json_decref(array);
379                        return -1;
380                }
381                addr = json_string(inet_ntoa(client->addr.sin_addr));
382                if (!addr) {
383                        json_decref(object);
384                        json_decref(array);
385                        return -1;
386                }
387                json_object_set_new(object, "addr", addr);
388                state = json_string(og_client_status(client));
389                if (!state) {
390                        json_decref(object);
391                        json_decref(array);
392                        return -1;
393                }
394                json_object_set_new(object, "state", state);
395                json_array_append_new(array, object);
396        }
397        root = json_pack("{s:o}", "clients", array);
398        if (!root) {
399                json_decref(array);
400                return -1;
401        }
402
403        json_dump_callback(root, og_json_dump_clients, &og_buffer, 0);
404        json_decref(root);
405
406        return 0;
407}
408
409static int og_json_parse_target(json_t *element, struct og_msg_params *params)
410{
411        const char *key;
412        json_t *value;
413
414        if (json_typeof(element) != JSON_OBJECT) {
415                return -1;
416        }
417
418        json_object_foreach(element, key, value) {
419                if (!strcmp(key, "addr")) {
420                        if (json_typeof(value) != JSON_STRING)
421                                return -1;
422
423                        params->ips_array[params->ips_array_len] =
424                                json_string_value(value);
425
426                        params->flags |= OG_REST_PARAM_ADDR;
427                } else if (!strcmp(key, "mac")) {
428                        if (json_typeof(value) != JSON_STRING)
429                                return -1;
430
431                        params->mac_array[params->ips_array_len] =
432                                json_string_value(value);
433
434                        params->flags |= OG_REST_PARAM_MAC;
435                } else if (!strcmp(key, "netmask")) {
436                        if (json_typeof(value) != JSON_STRING)
437                                return -1;
438
439                        params->netmask_array[params->ips_array_len] =
440                                json_string_value(value);
441
442                        params->flags |= OG_REST_PARAM_NETMASK;
443                }
444        }
445
446        return 0;
447}
448
449static int og_json_parse_targets(json_t *element, struct og_msg_params *params)
450{
451        unsigned int i;
452        json_t *k;
453        int err;
454
455        if (json_typeof(element) != JSON_ARRAY)
456                return -1;
457
458        for (i = 0; i < json_array_size(element); i++) {
459                k = json_array_get(element, i);
460
461                if (json_typeof(k) != JSON_OBJECT)
462                        return -1;
463
464                err = og_json_parse_target(k, params);
465                if (err < 0)
466                        return err;
467
468                params->ips_array_len++;
469        }
470        return 0;
471}
472
473static int og_json_parse_type(json_t *element, struct og_msg_params *params)
474{
475        const char *type;
476
477        if (json_typeof(element) != JSON_STRING)
478                return -1;
479
480        params->wol_type = json_string_value(element);
481
482        type = json_string_value(element);
483        if (!strcmp(type, "unicast"))
484                params->wol_type = "2";
485        else if (!strcmp(type, "broadcast"))
486                params->wol_type = "1";
487
488        params->flags |= OG_REST_PARAM_WOL_TYPE;
489
490        return 0;
491}
492
493static int og_cmd_wol(json_t *element, struct og_msg_params *params)
494{
495        const char *key;
496        json_t *value;
497        int err = 0;
498
499        if (json_typeof(element) != JSON_OBJECT)
500                return -1;
501
502        json_object_foreach(element, key, value) {
503                if (!strcmp(key, "clients")) {
504                        err = og_json_parse_targets(value, params);
505                } else if (!strcmp(key, "type")) {
506                        err = og_json_parse_type(value, params);
507                }
508
509                if (err < 0)
510                        break;
511        }
512
513        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
514                                            OG_REST_PARAM_MAC |
515                                            OG_REST_PARAM_NETMASK |
516                                            OG_REST_PARAM_WOL_TYPE))
517                return -1;
518
519        if (!Levanta((char **)params->ips_array, (char **)params->mac_array,
520                     (char **)params->netmask_array, params->ips_array_len,
521                     (char *)params->wol_type))
522                return -1;
523
524        return 0;
525}
526
527static int og_json_parse_run(json_t *element, struct og_msg_params *params)
528{
529        if (json_typeof(element) != JSON_STRING)
530                return -1;
531
532        snprintf(params->run_cmd, sizeof(params->run_cmd), "%s",
533                 json_string_value(element));
534
535        params->flags |= OG_REST_PARAM_RUN_CMD;
536
537        return 0;
538}
539
540static int og_cmd_run_post(json_t *element, struct og_msg_params *params)
541{
542        json_t *value, *clients;
543        const char *key;
544        unsigned int i;
545        int err = 0;
546
547        if (json_typeof(element) != JSON_OBJECT)
548                return -1;
549
550        json_object_foreach(element, key, value) {
551                if (!strcmp(key, "clients"))
552                        err = og_json_parse_clients(value, params);
553                else if (!strcmp(key, "run"))
554                        err = og_json_parse_run(value, params);
555                else if (!strcmp(key, "echo")) {
556                        err = og_json_parse_bool(value, &params->echo);
557                        params->flags |= OG_REST_PARAM_ECHO;
558                }
559
560                if (err < 0)
561                        break;
562        }
563
564        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
565                                            OG_REST_PARAM_RUN_CMD |
566                                            OG_REST_PARAM_ECHO))
567                return -1;
568
569        clients = json_copy(element);
570        json_object_del(clients, "clients");
571
572        err = og_send_request(OG_METHOD_POST, OG_CMD_SHELL_RUN, params, clients);
573        if (err < 0)
574                return err;
575
576        for (i = 0; i < params->ips_array_len; i++) {
577                char filename[4096];
578                FILE *f;
579
580                sprintf(filename, "/tmp/_Seconsola_%s", params->ips_array[i]);
581                f = fopen(filename, "wt");
582                fclose(f);
583        }
584
585        return 0;
586}
587
588static int og_cmd_run_get(json_t *element, struct og_msg_params *params,
589                          char *buffer_reply)
590{
591        struct og_buffer og_buffer = {
592                .data   = buffer_reply,
593        };
594        json_t *root, *value, *array;
595        const char *key;
596        unsigned int i;
597        int err = 0;
598
599        if (json_typeof(element) != JSON_OBJECT)
600                return -1;
601
602        json_object_foreach(element, key, value) {
603                if (!strcmp(key, "clients"))
604                        err = og_json_parse_clients(value, params);
605
606                if (err < 0)
607                        return err;
608        }
609
610        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
611                return -1;
612
613        array = json_array();
614        if (!array)
615                return -1;
616
617        for (i = 0; i < params->ips_array_len; i++) {
618                json_t *object, *output, *addr;
619                char data[4096] = {};
620                char filename[4096];
621                int fd, numbytes;
622
623                sprintf(filename, "/tmp/_Seconsola_%s", params->ips_array[i]);
624
625                fd = open(filename, O_RDONLY);
626                if (!fd)
627                        return -1;
628
629                numbytes = read(fd, data, sizeof(data));
630                if (numbytes < 0) {
631                        close(fd);
632                        return -1;
633                }
634                data[sizeof(data) - 1] = '\0';
635                close(fd);
636
637                object = json_object();
638                if (!object) {
639                        json_decref(array);
640                        return -1;
641                }
642                addr = json_string(params->ips_array[i]);
643                if (!addr) {
644                        json_decref(object);
645                        json_decref(array);
646                        return -1;
647                }
648                json_object_set_new(object, "addr", addr);
649
650                output = json_string(data);
651                if (!output) {
652                        json_decref(object);
653                        json_decref(array);
654                        return -1;
655                }
656                json_object_set_new(object, "output", output);
657
658                json_array_append_new(array, object);
659        }
660
661        root = json_pack("{s:o}", "clients", array);
662        if (!root)
663                return -1;
664
665        json_dump_callback(root, og_json_dump_clients, &og_buffer, 0);
666        json_decref(root);
667
668        return 0;
669}
670
671static int og_cmd_session(json_t *element, struct og_msg_params *params)
672{
673        json_t *clients, *value;
674        const char *key;
675        int err = 0;
676
677        if (json_typeof(element) != JSON_OBJECT)
678                return -1;
679
680        json_object_foreach(element, key, value) {
681                if (!strcmp(key, "clients")) {
682                        err = og_json_parse_clients(value, params);
683                } else if (!strcmp(key, "disk")) {
684                        err = og_json_parse_string(value, &params->disk);
685                        params->flags |= OG_REST_PARAM_DISK;
686                } else if (!strcmp(key, "partition")) {
687                        err = og_json_parse_string(value, &params->partition);
688                        params->flags |= OG_REST_PARAM_PARTITION;
689                }
690
691                if (err < 0)
692                        return err;
693        }
694
695        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
696                                            OG_REST_PARAM_DISK |
697                                            OG_REST_PARAM_PARTITION))
698                return -1;
699
700        clients = json_copy(element);
701        json_object_del(clients, "clients");
702
703        return og_send_request(OG_METHOD_POST, OG_CMD_SESSION, params, clients);
704}
705
706static int og_cmd_poweroff(json_t *element, struct og_msg_params *params)
707{
708        const char *key;
709        json_t *value;
710        int err = 0;
711
712        if (json_typeof(element) != JSON_OBJECT)
713                return -1;
714
715        json_object_foreach(element, key, value) {
716                if (!strcmp(key, "clients"))
717                        err = og_json_parse_clients(value, params);
718
719                if (err < 0)
720                        break;
721        }
722
723        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
724                return -1;
725
726        return og_send_request(OG_METHOD_POST, OG_CMD_POWEROFF, params, NULL);
727}
728
729static int og_cmd_refresh(json_t *element, struct og_msg_params *params)
730{
731        const char *key;
732        json_t *value;
733        int err = 0;
734
735        if (json_typeof(element) != JSON_OBJECT)
736                return -1;
737
738        json_object_foreach(element, key, value) {
739                if (!strcmp(key, "clients"))
740                        err = og_json_parse_clients(value, params);
741
742                if (err < 0)
743                        break;
744        }
745
746        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
747                return -1;
748
749        return og_send_request(OG_METHOD_GET, OG_CMD_REFRESH, params, NULL);
750}
751
752static int og_cmd_reboot(json_t *element, struct og_msg_params *params)
753{
754        const char *key;
755        json_t *value;
756        int err = 0;
757
758        if (json_typeof(element) != JSON_OBJECT)
759                return -1;
760
761        json_object_foreach(element, key, value) {
762                if (!strcmp(key, "clients"))
763                        err = og_json_parse_clients(value, params);
764
765                if (err < 0)
766                        break;
767        }
768
769        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
770                return -1;
771
772        return og_send_request(OG_METHOD_POST, OG_CMD_REBOOT, params, NULL);
773}
774
775#define OG_TFTP_TMPL_PATH "/opt/opengnsys/tftpboot/menu.lst/templates"
776
777static int og_cmd_get_modes(json_t *element, struct og_msg_params *params,
778                            char *buffer_reply)
779{
780        struct og_buffer og_buffer = {
781                .data = buffer_reply
782        };
783        json_t *root, *modes;
784        struct dirent *dent;
785        DIR *d = NULL;
786
787        root = json_object();
788        if (!root)
789                return -1;
790
791        modes = json_array();
792        if (!modes) {
793                json_decref(root);
794                return -1;
795        }
796
797        d = opendir(OG_TFTP_TMPL_PATH);
798        if (!d) {
799                json_decref(modes);
800                json_decref(root);
801                syslog(LOG_ERR, "Cannot open directory %s\n",
802                       OG_TFTP_TMPL_PATH);
803                return -1;
804        }
805
806        dent = readdir(d);
807        while (dent) {
808                if (dent->d_type != DT_REG) {
809                        dent = readdir(d);
810                        continue;
811                }
812                json_array_append_new(modes, json_string(dent->d_name));
813                dent = readdir(d);
814        }
815
816        json_object_set_new(root, "modes", modes);
817        json_dump_callback(root, og_json_dump_clients, &og_buffer, 0);
818        json_decref(root);
819        closedir(d);
820
821        return 0;
822}
823
824static int og_change_db_mode(struct og_dbi *dbi, const char *mac,
825                             const char * mode)
826{
827        const char *msglog;
828        dbi_result result;
829
830        result = dbi_conn_queryf(dbi->conn,
831                                 "UPDATE ordenadores SET arranque='%s' "
832                                 "WHERE mac='%s'",
833                                 mode, mac);
834
835        if (!result) {
836                dbi_conn_error(dbi->conn, &msglog);
837                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
838                       __func__, __LINE__, msglog);
839                return -1;
840        }
841
842        dbi_result_free(result);
843        return 0;
844}
845
846static int og_set_client_mode(struct og_dbi *dbi, const char *mac,
847                              const char *mode, const char *template_name)
848{
849        char filename[PATH_MAX + 1] = "/tmp/mode_params_XXXXXX";
850        char cmd_params[16384] = {};
851        char params[4096] = "\0";
852        const char *msglog;
853        dbi_result result;
854        unsigned int i;
855        int numbytes;
856        int status;
857        int fd;
858
859        result = dbi_conn_queryf(dbi->conn,
860                "SELECT ' LANG=%s', ' ip=', CONCAT_WS(':', ordenadores.ip, (SELECT (@serverip:=ipserveradm) FROM entornos LIMIT 1), aulas.router, aulas.netmask, ordenadores.nombreordenador, ordenadores.netiface, 'none'), ' group=', REPLACE(TRIM(aulas.nombreaula), ' ', '_'), ' ogrepo=', (@repoip:=IFNULL(repositorios.ip, '')), ' oglive=', @serverip, ' oglog=', @serverip, ' ogshare=', @serverip, ' oglivedir=', ordenadores.oglivedir, ' ogprof=', IF(ordenadores.idordenador=aulas.idordprofesor, 'true', 'false'), IF(perfileshard.descripcion<>'', CONCAT(' hardprofile=', REPLACE(TRIM(perfileshard.descripcion), ' ', '_')), ''), IF(aulas.ntp<>'', CONCAT(' ogntp=', aulas.ntp), ''), IF(aulas.dns<>'', CONCAT(' ogdns=', aulas.dns), ''), IF(aulas.proxy<>'', CONCAT(' ogproxy=', aulas.proxy), ''), IF(entidades.ogunit=1 AND NOT centros.directorio='', CONCAT(' ogunit=', centros.directorio), ''), CASE WHEN menus.resolucion IS NULL THEN '' WHEN menus.resolucion <= '999' THEN CONCAT(' vga=', menus.resolucion) WHEN menus.resolucion LIKE '%:%' THEN CONCAT(' video=', menus.resolucion) ELSE menus.resolucion END FROM ordenadores JOIN aulas USING(idaula) JOIN centros USING(idcentro) JOIN entidades USING(identidad) LEFT JOIN repositorios USING(idrepositorio) LEFT JOIN perfileshard USING(idperfilhard) LEFT JOIN menus USING(idmenu) WHERE ordenadores.mac='%s'", getenv("LANG"), mac);
861
862        if (dbi_result_get_numrows(result) != 1) {
863                dbi_conn_error(dbi->conn, &msglog);
864                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
865                       __FILE__, __LINE__, msglog);
866                dbi_result_free(result);
867                return -1;
868        }
869        dbi_result_next_row(result);
870
871        for (i = 1; i <= dbi_result_get_numfields(result); ++i)
872                strcat(params, dbi_result_get_string_idx(result, i));
873
874        dbi_result_free(result);
875
876        snprintf(cmd_params, sizeof(cmd_params),
877                 "MODE_FILE='%s'\nMAC='%s'\nDATA='%s'\n"
878                 "MODE='PERM'\nTEMPLATE_NAME='%s'",
879                 mode, mac, params, template_name);
880
881        fd = mkstemp(filename);
882        if (fd < 0) {
883                syslog(LOG_ERR, "cannot generate temp file (%s:%d)\n",
884                       __func__, __LINE__);
885                return -1;
886        }
887
888        numbytes = write(fd, cmd_params, strlen(cmd_params) + 1);
889        close(fd);
890
891        if (numbytes < 0) {
892                syslog(LOG_ERR, "cannot write file\n");
893                unlink(filename);
894                return -1;
895        }
896
897        if (fork() == 0) {
898                execlp("/bin/bash", "/bin/bash",
899                       "/opt/opengnsys/bin/setclientmode", filename, NULL);
900                syslog(LOG_ERR, "failed script execution (%s:%d)\n",
901                       __func__, __LINE__);
902                exit(EXIT_FAILURE);
903        } else {
904                wait(&status);
905        }
906        unlink(filename);
907
908        if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
909                syslog(LOG_ERR, "failed script execution (%s:%d)\n",
910                       __func__, __LINE__);
911                return -1;
912        }
913
914        if (og_change_db_mode(dbi, mac, mode) < 0) {
915                syslog(LOG_ERR, "failed to change db mode (%s:%d)\n",
916                       __func__, __LINE__);
917                return -1;
918        }
919
920        return 0;
921}
922
923static int og_cmd_post_modes(json_t *element, struct og_msg_params *params)
924{
925        char ips_str[(OG_DB_IP_MAXLEN + 1) * OG_CLIENTS_MAX + 1] = {};
926        char template_file[PATH_MAX + 1] = {};
927        char template_name[PATH_MAX + 1] = {};
928        char first_line[PATH_MAX + 1] = {};
929        const char *mode_str, *mac;
930        int ips_str_len = 0;
931        struct og_dbi *dbi;
932        uint64_t flags = 0;
933        dbi_result result;
934        const char *key;
935        json_t *value;
936        int err = 0;
937        FILE *f;
938        int i;
939
940        json_object_foreach(element, key, value) {
941                if (!strcmp(key, "clients")) {
942                        err = og_json_parse_clients(value, params);
943                } else if (!strcmp(key, "mode")) {
944                        err = og_json_parse_string(value, &mode_str);
945                        flags |= OG_REST_PARAM_MODE;
946                } else {
947                        err = -1;
948                }
949
950                if (err < 0)
951                        break;
952        }
953
954        if (!og_flags_validate(flags, OG_REST_PARAM_MODE) ||
955            !og_msg_params_validate(params, OG_REST_PARAM_ADDR))
956                return -1;
957
958        snprintf(template_file, sizeof(template_file), "%s/%s",
959                 OG_TFTP_TMPL_PATH, mode_str);
960        f = fopen(template_file, "r");
961        if (!f) {
962                syslog(LOG_ERR, "cannot open file (%s:%d)\n",
963                       __func__, __LINE__);
964                return -1;
965        }
966
967        if (!fgets(first_line, sizeof(first_line), f)) {
968                fclose(f);
969                syslog(LOG_ERR, "cannot read file (%s:%d)\n",
970                       __func__, __LINE__);
971                return -1;
972        }
973
974        fclose(f);
975
976        if (sscanf(first_line, "##NO-TOCAR-ESTA-LINEA %s", template_name) != 1) {
977                syslog(LOG_ERR, "malformed template: %s", first_line);
978                return -1;
979        }
980
981        for (i = 0; i < params->ips_array_len; ++i) {
982                ips_str_len += snprintf(ips_str + ips_str_len,
983                                        sizeof(ips_str) - ips_str_len,
984                                        "'%s',", params->ips_array[i]);
985        }
986        ips_str[ips_str_len - 1] = '\0';
987
988        dbi = og_dbi_open(&ogconfig.db);
989        if (!dbi) {
990                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
991                       __func__, __LINE__);
992                return -1;
993        }
994
995        result = dbi_conn_queryf(dbi->conn,
996                                 "SELECT mac FROM ordenadores "
997                                 "WHERE ip IN (%s)", ips_str);
998
999        while (dbi_result_next_row(result)) {
1000                mac = dbi_result_get_string(result, "mac");
1001                err = og_set_client_mode(dbi, mac, mode_str, template_name);
1002                if (err != 0) {
1003                        dbi_result_free(result);
1004                        og_dbi_close(dbi);
1005                        return -1;
1006                }
1007        }
1008
1009        dbi_result_free(result);
1010        og_dbi_close(dbi);
1011
1012        return 0;
1013}
1014
1015static int og_cmd_get_client_setup(json_t *element,
1016                                   struct og_msg_params *params,
1017                                   char *buffer_reply)
1018{
1019        json_t *value, *root, *partitions_array, *partition_json;
1020        const char *key, *msglog;
1021        unsigned int len_part;
1022        struct og_dbi *dbi;
1023        dbi_result result;
1024        int err = 0;
1025
1026        struct og_buffer og_buffer = {
1027                .data = buffer_reply
1028        };
1029
1030        struct {
1031                int disk;
1032                int number;
1033                int code;
1034                int size;
1035                int filesystem;
1036                int format;
1037                int os;
1038                int used_size;
1039                int image;
1040                int software;
1041        } partition;
1042
1043        json_object_foreach(element, key, value) {
1044                if (!strcmp(key, "client")) {
1045                        err = og_json_parse_clients(value, params);
1046                }
1047
1048                if (err < 0)
1049                        break;
1050        }
1051
1052        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
1053                return -1;
1054
1055        if (params->ips_array_len != 1)
1056                return -1;
1057
1058        root = json_object();
1059        if (!root)
1060                return -1;
1061
1062        partitions_array = json_array();
1063        if (!partitions_array) {
1064                json_decref(root);
1065                return -1;
1066        }
1067        json_object_set_new(root, "partitions", partitions_array);
1068
1069        dbi = og_dbi_open(&ogconfig.db);
1070        if (!dbi) {
1071                json_decref(root);
1072                syslog(LOG_ERR, "cannot open conection database (%s:%d)\n",
1073                       __func__, __LINE__);
1074                return -1;
1075        }
1076
1077        result = dbi_conn_queryf(dbi->conn,
1078                                 "SELECT numdisk, numpar, codpar, tamano, "
1079                                 "       uso, idsistemafichero, idnombreso, "
1080                                 "       idimagen, idperfilsoft "
1081                                 "FROM ordenadores_particiones "
1082                                 "INNER JOIN ordenadores "
1083                                 "ON ordenadores.idordenador = ordenadores_particiones.idordenador "
1084                                 "WHERE ordenadores.ip='%s'",
1085                                 params->ips_array[0]);
1086        if (!result) {
1087                json_decref(root);
1088                dbi_conn_error(dbi->conn, &msglog);
1089                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1090                       __func__, __LINE__, msglog);
1091                og_dbi_close(dbi);
1092                return -1;
1093        }
1094
1095        len_part = 0;
1096        /* partition 0 represents the full disk, hence OG_PARTITION_MAX + 1. */
1097        while (dbi_result_next_row(result) && len_part < OG_PARTITION_MAX + 1) {
1098                partition.disk = dbi_result_get_int(result, "numdisk");
1099                partition.number = dbi_result_get_int(result, "numpar");
1100                partition.code = dbi_result_get_int(result, "codpar");
1101                partition.size = dbi_result_get_int(result, "tamano");
1102                partition.used_size = dbi_result_get_int(result, "uso");
1103                partition.filesystem = dbi_result_get_int(result, "idsistemafichero");
1104                partition.os = dbi_result_get_int(result, "idnombreso");
1105                partition.image = dbi_result_get_int(result, "idimagen");
1106                partition.software = dbi_result_get_int(result, "idperfilsoft");
1107
1108                partition_json = json_object();
1109                if (!partition_json) {
1110                        json_decref(root);
1111                        dbi_result_free(result);
1112                        og_dbi_close(dbi);
1113                        return -1;
1114                }
1115
1116                json_object_set_new(partition_json, "disk",
1117                                    json_integer(partition.disk));
1118                json_object_set_new(partition_json, "partition",
1119                                    json_integer(partition.number));
1120                json_object_set_new(partition_json, "code",
1121                                    json_integer(partition.code));
1122                json_object_set_new(partition_json, "size",
1123                                    json_integer(partition.size));
1124                json_object_set_new(partition_json, "used_size",
1125                                    json_integer(partition.used_size));
1126                json_object_set_new(partition_json, "filesystem",
1127                                    json_integer(partition.filesystem));
1128                json_object_set_new(partition_json, "os",
1129                                    json_integer(partition.os));
1130                json_object_set_new(partition_json, "image",
1131                                    json_integer(partition.image));
1132                json_object_set_new(partition_json, "software",
1133                                    json_integer(partition.software));
1134                json_array_append_new(partitions_array, partition_json);
1135
1136                ++len_part;
1137        }
1138
1139        dbi_result_free(result);
1140        og_dbi_close(dbi);
1141
1142        json_dump_callback(root, og_json_dump_clients, &og_buffer, 0);
1143        json_decref(root);
1144        return 0;
1145}
1146
1147static int og_cmd_get_client_info(json_t *element,
1148                                  struct og_msg_params *params,
1149                                  char *buffer_reply)
1150{
1151        struct og_computer computer = {};
1152        json_t *value, *root;
1153        struct in_addr addr;
1154        struct og_dbi *dbi;
1155        const char *key;
1156        int err = 0;
1157
1158        struct og_buffer og_buffer = {
1159                .data = buffer_reply
1160        };
1161
1162        json_object_foreach(element, key, value) {
1163                if (!strcmp(key, "client")) {
1164                        err = og_json_parse_clients(value, params);
1165                }
1166
1167                if (err < 0)
1168                        break;
1169        }
1170
1171        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
1172                return -1;
1173
1174        if (params->ips_array_len != 1)
1175                return -1;
1176
1177        if (inet_aton(params->ips_array[0], &addr) == 0)
1178                return -1;
1179
1180        dbi = og_dbi_open(&ogconfig.db);
1181        if (!dbi) {
1182                syslog(LOG_ERR, "cannot open conection database (%s:%d)\n",
1183                       __func__, __LINE__);
1184                return -1;
1185        }
1186
1187        if (og_dbi_get_computer_info(dbi, &computer, addr)) {
1188                og_dbi_close(dbi);
1189                return -1;
1190        }
1191
1192        og_dbi_close(dbi);
1193
1194        root = json_object();
1195        if (!root)
1196                return -1;
1197
1198        json_object_set_new(root, "serial_number",
1199                            json_string(computer.serial_number));
1200        json_object_set_new(root, "hardware_id",
1201                            json_integer(computer.hardware_id));
1202        json_object_set_new(root, "netdriver", json_string(computer.netdriver));
1203        json_object_set_new(root, "maintenance", json_boolean(computer.name));
1204        json_object_set_new(root, "netiface", json_string(computer.netiface));
1205        json_object_set_new(root, "repo_id", json_integer(computer.repo_id));
1206        json_object_set_new(root, "livedir", json_string(computer.livedir));
1207        json_object_set_new(root, "netmask", json_string(computer.netmask));
1208        json_object_set_new(root, "center", json_integer(computer.center));
1209        json_object_set_new(root, "remote", json_boolean(computer.remote));
1210        json_object_set_new(root, "room", json_integer(computer.room));
1211        json_object_set_new(root, "name", json_string(computer.name));
1212        json_object_set_new(root, "boot", json_string(computer.boot));
1213        json_object_set_new(root, "mac", json_string(computer.mac));
1214        json_object_set_new(root, "id", json_integer(computer.id));
1215        json_object_set_new(root, "ip", json_string(computer.ip));
1216
1217        json_dump_callback(root, og_json_dump_clients, &og_buffer, 0);
1218        json_decref(root);
1219        return 0;
1220}
1221
1222static int og_cmd_post_client_add(json_t *element,
1223                                  struct og_msg_params *params,
1224                                  char *buffer_reply)
1225{
1226        struct og_computer computer = {};
1227        const char *key, *msglog;
1228        struct og_dbi *dbi;
1229        dbi_result result;
1230        json_t *value;
1231        int err = 0;
1232
1233        json_object_foreach(element, key, value) {
1234                if (!strcmp(key, "serial_number")) {
1235                        err = og_json_parse_string_copy(value,
1236                                                        computer.serial_number,
1237                                                        sizeof(computer.serial_number));
1238                } else if (!strcmp(key, "hardware_id")) {
1239                        err = og_json_parse_uint(value, &computer.hardware_id);
1240                } else if (!strcmp(key, "netdriver")) {
1241                        err = og_json_parse_string_copy(value,
1242                                                        computer.netdriver,
1243                                                        sizeof(computer.netdriver));
1244                } else if (!strcmp(key, "maintenance")) {
1245                        err = og_json_parse_bool(value, &computer.maintenance);
1246                } else if (!strcmp(key, "netiface")) {
1247                        err = og_json_parse_string_copy(value,
1248                                                        computer.netiface,
1249                                                        sizeof(computer.netiface));
1250                } else if (!strcmp(key, "repo_id")) {
1251                        err = og_json_parse_uint(value, &computer.repo_id);
1252                } else if (!strcmp(key, "livedir")) {
1253                        err = og_json_parse_string_copy(value,
1254                                                        computer.livedir,
1255                                                        sizeof(computer.livedir));
1256                } else if (!strcmp(key, "netmask")) {
1257                        err = og_json_parse_string_copy(value,
1258                                                        computer.netmask,
1259                                                        sizeof(computer.netmask));
1260                } else if (!strcmp(key, "remote")) {
1261                        err = og_json_parse_bool(value, &computer.remote);
1262                } else if (!strcmp(key, "room")) {
1263                        err = og_json_parse_uint(value, &computer.room);
1264                } else if (!strcmp(key, "name")) {
1265                        err = og_json_parse_string_copy(value,
1266                                                        computer.name,
1267                                                        sizeof(computer.name));
1268                } else if (!strcmp(key, "boot")) {
1269                        err = og_json_parse_string_copy(value,
1270                                                        computer.boot,
1271                                                        sizeof(computer.boot));
1272                } else if (!strcmp(key, "mac")) {
1273                        err = og_json_parse_string_copy(value,
1274                                                        computer.mac,
1275                                                        sizeof(computer.mac));
1276                } else if (!strcmp(key, "ip")) {
1277                        err = og_json_parse_string_copy(value,
1278                                                        computer.ip,
1279                                                        sizeof(computer.ip));
1280                }
1281
1282                if (err < 0)
1283                        break;
1284        }
1285
1286        dbi = og_dbi_open(&ogconfig.db);
1287        if (!dbi) {
1288                syslog(LOG_ERR, "cannot open conection database (%s:%d)\n",
1289                       __func__, __LINE__);
1290                return -1;
1291        }
1292
1293        result = dbi_conn_queryf(dbi->conn,
1294                                 "SELECT ip FROM ordenadores WHERE ip='%s'",
1295                                 computer.ip);
1296
1297        if (!result) {
1298                dbi_conn_error(dbi->conn, &msglog);
1299                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1300                       __func__, __LINE__, msglog);
1301                og_dbi_close(dbi);
1302                return -1;
1303        }
1304
1305        if (dbi_result_get_numrows(result) > 0) {
1306                syslog(LOG_ERR, "client with the same IP already exists: %s\n",
1307                       computer.ip);
1308                dbi_result_free(result);
1309                og_dbi_close(dbi);
1310                return -1;
1311        }
1312        dbi_result_free(result);
1313
1314        result = dbi_conn_queryf(dbi->conn,
1315                                 "INSERT INTO ordenadores("
1316                                 "  nombreordenador,"
1317                                 "  numserie,"
1318                                 "  ip,"
1319                                 "  mac,"
1320                                 "  idaula,"
1321                                 "  idperfilhard,"
1322                                 "  idrepositorio,"
1323                                 "  mascara,"
1324                                 "  arranque,"
1325                                 "  netiface,"
1326                                 "  netdriver,"
1327                                 "  oglivedir,"
1328                                 "  inremotepc,"
1329                                 "  maintenance"
1330                                 ") VALUES ('%s', '%s', '%s', '%s', %u, %u,"
1331                                 "           %u, '%s', '%s', '%s', '%s',"
1332                                 "          '%s', %u, %u)",
1333                                 computer.name, computer.serial_number,
1334                                 computer.ip, computer.mac, computer.room,
1335                                 computer.hardware_id, computer.repo_id,
1336                                 computer.netmask, computer.boot,
1337                                 computer.netiface, computer.netdriver,
1338                                 computer.livedir, computer.remote,
1339                                 computer.maintenance);
1340
1341        if (!result) {
1342                dbi_conn_error(dbi->conn, &msglog);
1343                syslog(LOG_ERR, "failed to add client to database (%s:%d) %s\n",
1344                       __func__, __LINE__, msglog);
1345                og_dbi_close(dbi);
1346                return -1;
1347        }
1348
1349        dbi_result_free(result);
1350        og_dbi_close(dbi);
1351        return 0;
1352}
1353
1354static int og_cmd_post_client_delete(json_t *element,
1355                                     struct og_msg_params *params)
1356{
1357        const char *key, *msglog;
1358        struct og_dbi *dbi;
1359        dbi_result result;
1360        unsigned int i;
1361        json_t *value;
1362        int err = 0;
1363
1364        json_object_foreach(element, key, value) {
1365                if (!strcmp(key, "clients"))
1366                        err = og_json_parse_clients(value, params);
1367                else
1368                        err = -1;
1369
1370                if (err < 0)
1371                        break;
1372        }
1373
1374        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
1375                return -1;
1376
1377        dbi = og_dbi_open(&ogconfig.db);
1378        if (!dbi) {
1379                syslog(LOG_ERR, "cannot open conection database (%s:%d)\n",
1380                       __func__, __LINE__);
1381                return -1;
1382        }
1383
1384        for (i = 0; i < params->ips_array_len; i++) {
1385                result = dbi_conn_queryf(dbi->conn,
1386                                         "DELETE FROM ordenadores WHERE ip='%s'",
1387                                         params->ips_array[i]);
1388
1389                if (!result) {
1390                        dbi_conn_error(dbi->conn, &msglog);
1391                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1392                               __func__, __LINE__, msglog);
1393                        og_dbi_close(dbi);
1394                        return -1;
1395                }
1396
1397                dbi_result_free(result);
1398        }
1399
1400        og_dbi_close(dbi);
1401        return 0;
1402}
1403
1404static int og_cmd_stop(json_t *element, struct og_msg_params *params)
1405{
1406        const char *key;
1407        json_t *value;
1408        int err = 0;
1409
1410        if (json_typeof(element) != JSON_OBJECT)
1411                return -1;
1412
1413        json_object_foreach(element, key, value) {
1414                if (!strcmp(key, "clients"))
1415                        err = og_json_parse_clients(value, params);
1416
1417                if (err < 0)
1418                        break;
1419        }
1420
1421        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
1422                return -1;
1423
1424        return og_send_request(OG_METHOD_POST, OG_CMD_STOP, params, NULL);
1425}
1426
1427static int og_cmd_hardware(json_t *element, struct og_msg_params *params)
1428{
1429        const char *key;
1430        json_t *value;
1431        int err = 0;
1432
1433        if (json_typeof(element) != JSON_OBJECT)
1434                return -1;
1435
1436        json_object_foreach(element, key, value) {
1437                if (!strcmp(key, "clients"))
1438                        err = og_json_parse_clients(value, params);
1439
1440                if (err < 0)
1441                        break;
1442        }
1443
1444        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
1445                return -1;
1446
1447        return og_send_request(OG_METHOD_GET, OG_CMD_HARDWARE, params, NULL);
1448}
1449
1450static int og_cmd_get_hardware(json_t *element, struct og_msg_params *params,
1451                               char *buffer_reply)
1452{
1453        const char *key, *msglog, *hw_item, *hw_type;
1454        json_t *value, *root, *array, *item;
1455        struct og_dbi *dbi;
1456        dbi_result result;
1457        int err = 0;
1458
1459        struct og_buffer og_buffer = {
1460                .data = buffer_reply
1461        };
1462
1463        json_object_foreach(element, key, value) {
1464                if (!strcmp(key, "client"))
1465                        err = og_json_parse_clients(value, params);
1466                else
1467                        err = -1;
1468
1469                if (err < 0)
1470                        return err;
1471        }
1472
1473        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
1474                return -1;
1475
1476        dbi = og_dbi_open(&ogconfig.db);
1477        if (!dbi) {
1478                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
1479                       __func__, __LINE__);
1480                return -1;
1481        }
1482
1483        result = dbi_conn_queryf(dbi->conn,
1484                                 "SELECT hardwares.descripcion AS item, "
1485                                 "       tipohardwares.descripcion AS type "
1486                                 "FROM hardwares "
1487                                 "INNER JOIN perfileshard_hardwares "
1488                                 "    ON hardwares.idhardware = perfileshard_hardwares.idhardware "
1489                                 "INNER JOIN ordenadores "
1490                                 "    ON perfileshard_hardwares.idperfilhard = ordenadores.idperfilhard "
1491                                 "INNER JOIN tipohardwares "
1492                                 "    ON hardwares.idtipohardware = tipohardwares.idtipohardware "
1493                                 "WHERE ordenadores.ip = '%s'",
1494                                 params->ips_array[0]);
1495        if (!result) {
1496                dbi_conn_error(dbi->conn, &msglog);
1497                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1498                       __func__, __LINE__, msglog);
1499                og_dbi_close(dbi);
1500                return -1;
1501        }
1502
1503        array = json_array();
1504        if (!array) {
1505                dbi_result_free(result);
1506                og_dbi_close(dbi);
1507                return -1;
1508        }
1509
1510        while (dbi_result_next_row(result)) {
1511                item = json_object();
1512                if (!item) {
1513                        dbi_result_free(result);
1514                        og_dbi_close(dbi);
1515                        json_decref(array);
1516                        return -1;
1517                }
1518
1519                hw_item = dbi_result_get_string(result, "item");
1520                hw_type = dbi_result_get_string(result, "type");
1521
1522                json_object_set_new(item, "type", json_string(hw_type));
1523                json_object_set_new(item, "description", json_string(hw_item));
1524                json_array_append_new(array, item);
1525        }
1526
1527        dbi_result_free(result);
1528        og_dbi_close(dbi);
1529
1530        root = json_object();
1531        if (!root){
1532                json_decref(array);
1533                return -1;
1534        }
1535
1536        json_object_set_new(root, "hardware", array);
1537
1538        json_dump_callback(root, og_json_dump_clients, &og_buffer, 0);
1539        json_decref(root);
1540        return 0;
1541}
1542
1543static int og_cmd_software(json_t *element, struct og_msg_params *params)
1544{
1545        json_t *clients, *value;
1546        const char *key;
1547        int err = 0;
1548
1549        if (json_typeof(element) != JSON_OBJECT)
1550                return -1;
1551
1552        json_object_foreach(element, key, value) {
1553                if (!strcmp(key, "clients"))
1554                        err = og_json_parse_clients(value, params);
1555                else if (!strcmp(key, "disk")) {
1556                        err = og_json_parse_string(value, &params->disk);
1557                        params->flags |= OG_REST_PARAM_DISK;
1558                }
1559                else if (!strcmp(key, "partition")) {
1560                        err = og_json_parse_string(value, &params->partition);
1561                        params->flags |= OG_REST_PARAM_PARTITION;
1562                }
1563
1564                if (err < 0)
1565                        break;
1566        }
1567
1568        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
1569                                            OG_REST_PARAM_DISK |
1570                                            OG_REST_PARAM_PARTITION))
1571                return -1;
1572
1573        clients = json_copy(element);
1574        json_object_del(clients, "clients");
1575
1576        return og_send_request(OG_METHOD_POST, OG_CMD_SOFTWARE, params, clients);
1577}
1578
1579static int og_cmd_get_software(json_t *element, struct og_msg_params *params,
1580                               char *buffer_reply)
1581{
1582        json_t *value, *software, *root;
1583        const char *key, *msglog, *name;
1584        uint64_t disk, partition;
1585        uint64_t flags = 0;
1586        struct og_dbi *dbi;
1587        dbi_result result;
1588        int err = 0;
1589
1590        struct og_buffer og_buffer = {
1591                .data = buffer_reply
1592        };
1593
1594        if (json_typeof(element) != JSON_OBJECT)
1595                return -1;
1596
1597        json_object_foreach(element, key, value) {
1598                if (!strcmp(key, "client")) {
1599                        err = og_json_parse_clients(value, params);
1600                } else if (!strcmp(key, "disk")) {
1601                        err = og_json_parse_uint64(value, &disk);
1602                        flags |= OG_REST_PARAM_DISK;
1603                } else if (!strcmp(key, "partition")) {
1604                        err = og_json_parse_uint64(value, &partition);
1605                        flags |= OG_REST_PARAM_PARTITION;
1606                }
1607
1608                if (err < 0)
1609                        break;
1610        }
1611
1612        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR) ||
1613            !og_flags_validate(flags, OG_REST_PARAM_DISK |
1614                                      OG_REST_PARAM_PARTITION))
1615                return -1;
1616
1617        dbi = og_dbi_open(&ogconfig.db);
1618        if (!dbi) {
1619                syslog(LOG_ERR, "cannot open conection database (%s:%d)\n",
1620                       __func__, __LINE__);
1621                return -1;
1622        }
1623
1624        result = dbi_conn_queryf(dbi->conn,
1625                                 "SELECT s.descripcion "
1626                                 "FROM softwares s "
1627                                 "INNER JOIN perfilessoft_softwares pss "
1628                                 "ON s.idsoftware = pss.idsoftware "
1629                                 "INNER JOIN ordenadores_particiones op "
1630                                 "ON pss.idperfilsoft = op.idperfilsoft "
1631                                 "INNER JOIN ordenadores o "
1632                                 "ON o.idordenador = op.idordenador "
1633                                 "WHERE o.ip='%s' AND "
1634                                 "      op.numdisk=%lu AND "
1635                                 "      op.numpar=%lu",
1636                                 params->ips_array[0], disk, partition);
1637        if (!result) {
1638                dbi_conn_error(dbi->conn, &msglog);
1639                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1640                       __func__, __LINE__, msglog);
1641                return -1;
1642        }
1643        software = json_array();
1644        if (!software) {
1645                dbi_result_free(result);
1646                og_dbi_close(dbi);
1647                return -1;
1648        }
1649
1650        while (dbi_result_next_row(result)) {
1651                name = dbi_result_get_string(result, "descripcion");
1652                json_array_append_new(software, json_string(name));
1653        }
1654
1655        dbi_result_free(result);
1656        og_dbi_close(dbi);
1657
1658        root = json_object();
1659        if (!root) {
1660                json_decref(software);
1661                return -1;
1662        }
1663        json_object_set_new(root, "software", software);
1664
1665        json_dump_callback(root, og_json_dump_clients, &og_buffer, 0);
1666        json_decref(root);
1667        return 0;
1668}
1669
1670#define OG_IMAGE_TYPE_MAXLEN    4
1671
1672static int og_get_image_stats(const char *name,
1673                              struct stat *image_stats)
1674{
1675        const char *dir = ogconfig.repo.dir;
1676        char filename[PATH_MAX + 1];
1677
1678        snprintf(filename, sizeof(filename), "%s/%s.img", dir, name);
1679        if (stat(filename, image_stats) < 0) {
1680                syslog(LOG_ERR, "%s image does not exists", name);
1681                return -1;
1682        }
1683        return 0;
1684}
1685
1686static json_t *og_json_disk_alloc()
1687{
1688        const char *dir = ogconfig.repo.dir;
1689        struct statvfs buffer;
1690        json_t *disk_json;
1691        int ret;
1692
1693        ret = statvfs(dir, &buffer);
1694        if (ret)
1695                return NULL;
1696
1697        disk_json = json_object();
1698        if (!disk_json)
1699                return NULL;
1700
1701        json_object_set_new(disk_json, "total",
1702                            json_integer(buffer.f_blocks * buffer.f_frsize));
1703        json_object_set_new(disk_json, "free",
1704                            json_integer(buffer.f_bfree * buffer.f_frsize));
1705
1706        return disk_json;
1707}
1708
1709#define OG_PERMS_IRWX (S_IRWXU | S_IRWXG | S_IRWXO)
1710#define OG_PERMS_MAXLEN 4
1711
1712static json_t *og_json_image_alloc(struct og_image *image)
1713{
1714        char perms_string[OG_PERMS_MAXLEN];
1715        json_t *image_json;
1716        char *modified;
1717        uint16_t perms;
1718
1719        image_json = json_object();
1720        if (!image_json)
1721                return NULL;
1722
1723        perms = image->image_stats.st_mode & OG_PERMS_IRWX;
1724        snprintf(perms_string, sizeof(perms_string), "%o", perms);
1725
1726        modified = ctime(&image->image_stats.st_mtime);
1727        modified[strlen(modified) - 1] = '\0';
1728
1729        json_object_set_new(image_json, "name",
1730                            json_string(image->name));
1731        json_object_set_new(image_json, "datasize",
1732                            json_integer(image->datasize));
1733        json_object_set_new(image_json, "size",
1734                            json_integer(image->image_stats.st_size));
1735        json_object_set_new(image_json, "modified",
1736                            json_string(modified));
1737        json_object_set_new(image_json, "permissions",
1738                            json_string(perms_string));
1739        json_object_set_new(image_json, "software_id",
1740                            json_integer(image->software_id));
1741        json_object_set_new(image_json, "type",
1742                            json_integer(image->type));
1743        json_object_set_new(image_json, "id",
1744                            json_integer(image->id));
1745
1746        return image_json;
1747}
1748
1749static int og_cmd_images(char *buffer_reply)
1750{
1751        json_t *root, *images, *image_json, *disk_json;
1752        struct og_buffer og_buffer = {
1753                .data = buffer_reply
1754        };
1755        struct og_image image;
1756        struct og_dbi *dbi;
1757        dbi_result result;
1758
1759        root = json_object();
1760        if (!root)
1761                return -1;
1762
1763        images = json_array();
1764        if (!images) {
1765                json_decref(root);
1766                return -1;
1767        }
1768
1769        json_object_set_new(root, "images", images);
1770
1771        dbi = og_dbi_open(&ogconfig.db);
1772        if (!dbi) {
1773                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
1774                       __func__, __LINE__);
1775                json_decref(root);
1776                return -1;
1777        }
1778
1779        result = dbi_conn_queryf(dbi->conn,
1780                                 "SELECT i.nombreca, o.nombreordenador, "
1781                                 "       i.clonator, i.compressor, "
1782                                 "       i.filesystem, i.datasize, "
1783                                 "       i.idperfilsoft, i.tipo, "
1784                                 "       i.idimagen "
1785                                 "FROM imagenes i "
1786                                 "LEFT JOIN ordenadores o "
1787                                 "ON i.idordenador = o.idordenador");
1788
1789        while (dbi_result_next_row(result)) {
1790                image = (struct og_image){0};
1791                image.datasize = dbi_result_get_ulonglong(result, "datasize");
1792                image.software_id = dbi_result_get_ulonglong(result, "idperfilsoft");
1793                image.type = dbi_result_get_ulonglong(result, "tipo");
1794                image.id = dbi_result_get_ulonglong(result, "idimagen");
1795                snprintf(image.name, sizeof(image.name), "%s",
1796                         dbi_result_get_string(result, "nombreca"));
1797
1798                if (og_get_image_stats(image.name, &image.image_stats)) {
1799                        continue;
1800                }
1801
1802                image_json = og_json_image_alloc(&image);
1803                if (!image_json) {
1804                        dbi_result_free(result);
1805                        og_dbi_close(dbi);
1806                        json_decref(root);
1807                        return -1;
1808                }
1809
1810                json_array_append(images, image_json);
1811        }
1812
1813        dbi_result_free(result);
1814        og_dbi_close(dbi);
1815
1816        disk_json = og_json_disk_alloc();
1817        if (!disk_json) {
1818                syslog(LOG_ERR, "cannot allocate disk json");
1819                json_decref(root);
1820                return -1;
1821        }
1822
1823        json_object_set_new(root, "disk", disk_json);
1824
1825        json_dump_callback(root, og_json_dump_clients, &og_buffer, 0);
1826        json_decref(root);
1827
1828        return 0;
1829}
1830
1831static int og_cmd_create_image(json_t *element, struct og_msg_params *params)
1832{
1833        char new_image_id[OG_DB_INT_MAXLEN + 1];
1834        struct og_image image = {};
1835        json_t *value, *clients;
1836        struct og_dbi *dbi;
1837        const char *key;
1838        int err = 0;
1839
1840        if (json_typeof(element) != JSON_OBJECT)
1841                return -1;
1842
1843        json_object_foreach(element, key, value) {
1844                if (!strcmp(key, "disk")) {
1845                        err = og_json_parse_string(value, &params->disk);
1846                        params->flags |= OG_REST_PARAM_DISK;
1847                } else if (!strcmp(key, "partition")) {
1848                        err = og_json_parse_string(value, &params->partition);
1849                        params->flags |= OG_REST_PARAM_PARTITION;
1850                } else if (!strcmp(key, "name")) {
1851                        err = og_json_parse_string(value, &params->name);
1852                        params->flags |= OG_REST_PARAM_NAME;
1853                } else if (!strcmp(key, "repository")) {
1854                        err = og_json_parse_string(value, &params->repository);
1855                        params->flags |= OG_REST_PARAM_REPO;
1856                } else if (!strcmp(key, "clients")) {
1857                        err = og_json_parse_clients(value, params);
1858                } else if (!strcmp(key, "id")) {
1859                        err = og_json_parse_string(value, &params->id);
1860                        params->flags |= OG_REST_PARAM_ID;
1861                } else if (!strcmp(key, "code")) {
1862                        err = og_json_parse_string(value, &params->code);
1863                        params->flags |= OG_REST_PARAM_CODE;
1864                } else if (!strcmp(key, "description")) {
1865                        err = og_json_parse_string_copy(value,
1866                                                        image.description,
1867                                                        sizeof(image.description));
1868                } else if (!strcmp(key, "group_id")) {
1869                        err = og_json_parse_uint64(value, &image.group_id);
1870                } else if (!strcmp(key, "center_id")) {
1871                        err = og_json_parse_uint64(value, &image.center_id);
1872                }
1873
1874
1875                if (err < 0)
1876                        break;
1877        }
1878
1879        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
1880                                            OG_REST_PARAM_DISK |
1881                                            OG_REST_PARAM_PARTITION |
1882                                            OG_REST_PARAM_CODE |
1883                                            OG_REST_PARAM_ID |
1884                                            OG_REST_PARAM_NAME |
1885                                            OG_REST_PARAM_REPO))
1886                return -1;
1887
1888        /* If there is a description, this means the image is not in the DB. */
1889        if (image.description[0]) {
1890                snprintf(image.name, sizeof(image.name), "%s", params->name);
1891
1892                dbi = og_dbi_open(&ogconfig.db);
1893                if (!dbi) {
1894                        syslog(LOG_ERR,
1895                               "cannot open connection database (%s:%d)\n",
1896                               __func__, __LINE__);
1897                        return -1;
1898                }
1899
1900                err = og_dbi_add_image(dbi, &image);
1901
1902                og_dbi_close(dbi);
1903                if (err < 0)
1904                        return err;
1905
1906                snprintf(new_image_id, sizeof(new_image_id), "%u", err);
1907                params->id = new_image_id;
1908        }
1909
1910        clients = json_copy(element);
1911        json_object_del(clients, "clients");
1912
1913        return og_send_request(OG_METHOD_POST, OG_CMD_IMAGE_CREATE, params,
1914                               clients);
1915}
1916
1917static int og_cmd_restore_image(json_t *element, struct og_msg_params *params)
1918{
1919        json_t *clients, *value;
1920        const char *key;
1921        int err = 0;
1922
1923        if (json_typeof(element) != JSON_OBJECT)
1924                return -1;
1925
1926        json_object_foreach(element, key, value) {
1927                if (!strcmp(key, "disk")) {
1928                        err = og_json_parse_string(value, &params->disk);
1929                        params->flags |= OG_REST_PARAM_DISK;
1930                } else if (!strcmp(key, "partition")) {
1931                        err = og_json_parse_string(value, &params->partition);
1932                        params->flags |= OG_REST_PARAM_PARTITION;
1933                } else if (!strcmp(key, "name")) {
1934                        err = og_json_parse_string(value, &params->name);
1935                        params->flags |= OG_REST_PARAM_NAME;
1936                } else if (!strcmp(key, "repository")) {
1937                        err = og_json_parse_string(value, &params->repository);
1938                        params->flags |= OG_REST_PARAM_REPO;
1939                } else if (!strcmp(key, "clients")) {
1940                        err = og_json_parse_clients(value, params);
1941                } else if (!strcmp(key, "type")) {
1942                        err = og_json_parse_string(value, &params->type);
1943                        params->flags |= OG_REST_PARAM_TYPE;
1944                } else if (!strcmp(key, "profile")) {
1945                        err = og_json_parse_string(value, &params->profile);
1946                        params->flags |= OG_REST_PARAM_PROFILE;
1947                } else if (!strcmp(key, "id")) {
1948                        err = og_json_parse_string(value, &params->id);
1949                        params->flags |= OG_REST_PARAM_ID;
1950                }
1951
1952                if (err < 0)
1953                        break;
1954        }
1955
1956        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
1957                                            OG_REST_PARAM_DISK |
1958                                            OG_REST_PARAM_PARTITION |
1959                                            OG_REST_PARAM_NAME |
1960                                            OG_REST_PARAM_REPO |
1961                                            OG_REST_PARAM_TYPE |
1962                                            OG_REST_PARAM_PROFILE |
1963                                            OG_REST_PARAM_ID))
1964                return -1;
1965
1966        clients = json_copy(element);
1967        json_object_del(clients, "clients");
1968
1969        return og_send_request(OG_METHOD_POST, OG_CMD_IMAGE_RESTORE, params,
1970                               clients);
1971}
1972
1973static int og_cmd_setup(json_t *element, struct og_msg_params *params)
1974{
1975        json_t *value, *clients;
1976        const char *key;
1977        int err = 0;
1978
1979        if (json_typeof(element) != JSON_OBJECT)
1980                return -1;
1981
1982        json_object_foreach(element, key, value) {
1983                if (!strcmp(key, "clients")) {
1984                        err = og_json_parse_clients(value, params);
1985                } else if (!strcmp(key, "disk")) {
1986                        err = og_json_parse_string(value, &params->disk);
1987                        params->flags |= OG_REST_PARAM_DISK;
1988                } else if (!strcmp(key, "cache")) {
1989                        err = og_json_parse_string(value, &params->cache);
1990                        params->flags |= OG_REST_PARAM_CACHE;
1991                } else if (!strcmp(key, "cache_size")) {
1992                        err = og_json_parse_string(value, &params->cache_size);
1993                        params->flags |= OG_REST_PARAM_CACHE_SIZE;
1994                } else if (!strcmp(key, "partition_setup")) {
1995                        err = og_json_parse_partition_setup(value, params);
1996                }
1997
1998                if (err < 0)
1999                        break;
2000        }
2001
2002        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
2003                                            OG_REST_PARAM_DISK |
2004                                            OG_REST_PARAM_CACHE |
2005                                            OG_REST_PARAM_CACHE_SIZE |
2006                                            OG_REST_PARAM_PART_0 |
2007                                            OG_REST_PARAM_PART_1 |
2008                                            OG_REST_PARAM_PART_2 |
2009                                            OG_REST_PARAM_PART_3))
2010                return -1;
2011
2012        clients = json_copy(element);
2013        json_object_del(clients, "clients");
2014
2015        return og_send_request(OG_METHOD_POST, OG_CMD_SETUP, params, clients);
2016}
2017
2018static int og_cmd_run_schedule(json_t *element, struct og_msg_params *params)
2019{
2020        const char *key;
2021        json_t *value;
2022        int err = 0;
2023
2024        json_object_foreach(element, key, value) {
2025                if (!strcmp(key, "clients"))
2026                        err = og_json_parse_clients(value, params);
2027
2028                if (err < 0)
2029                        break;
2030        }
2031
2032        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
2033                return -1;
2034
2035        return og_send_request(OG_METHOD_GET, OG_CMD_RUN_SCHEDULE, params,
2036                               NULL);
2037}
2038
2039static LIST_HEAD(cmd_list);
2040
2041const struct og_cmd *og_cmd_find(const char *client_ip)
2042{
2043        struct og_cmd *cmd, *next;
2044
2045        list_for_each_entry_safe(cmd, next, &cmd_list, list) {
2046                if (strcmp(cmd->ip, client_ip))
2047                        continue;
2048
2049                list_del(&cmd->list);
2050                return cmd;
2051        }
2052
2053        return NULL;
2054}
2055
2056void og_cmd_free(const struct og_cmd *cmd)
2057{
2058        struct og_msg_params *params = (struct og_msg_params *)&cmd->params;
2059        int i;
2060
2061        for (i = 0; i < params->ips_array_len; i++) {
2062                free((void *)params->ips_array[i]);
2063                free((void *)params->mac_array[i]);
2064        }
2065        free((void *)params->wol_type);
2066
2067        if (cmd->json)
2068                json_decref(cmd->json);
2069
2070        free((void *)cmd->ip);
2071        free((void *)cmd->mac);
2072        free((void *)cmd);
2073}
2074
2075static void og_cmd_init(struct og_cmd *cmd, enum og_rest_method method,
2076                        enum og_cmd_type type, json_t *root)
2077{
2078        cmd->type = type;
2079        cmd->method = method;
2080        cmd->params.ips_array[0] = strdup(cmd->ip);
2081        cmd->params.ips_array_len = 1;
2082        cmd->json = root;
2083}
2084
2085static int og_cmd_legacy_wol(const char *input, struct og_cmd *cmd)
2086{
2087        char wol_type[2] = {};
2088
2089        if (sscanf(input, "mar=%s", wol_type) != 1) {
2090                syslog(LOG_ERR, "malformed database legacy input\n");
2091                return -1;
2092        }
2093
2094        og_cmd_init(cmd, OG_METHOD_NO_HTTP, OG_CMD_WOL, NULL);
2095        cmd->params.mac_array[0] = strdup(cmd->mac);
2096        cmd->params.wol_type = strdup(wol_type);
2097
2098        return 0;
2099}
2100
2101static int og_cmd_legacy_shell_run(const char *input, struct og_cmd *cmd)
2102{
2103        json_t *root, *script, *echo;
2104
2105        script = json_string(input + 4);
2106        echo = json_boolean(false);
2107
2108        root = json_object();
2109        if (!root)
2110                return -1;
2111        json_object_set_new(root, "run", script);
2112        json_object_set_new(root, "echo", echo);
2113
2114        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_SHELL_RUN, root);
2115
2116        return 0;
2117}
2118
2119static int og_cmd_legacy_session(const char *input, struct og_cmd *cmd)
2120{
2121        char part_str[OG_DB_SMALLINT_MAXLEN + 1];
2122        char disk_str[OG_DB_SMALLINT_MAXLEN + 1];
2123        json_t *root, *disk, *partition;
2124
2125        if (sscanf(input, "dsk=%s\rpar=%s\r", disk_str, part_str) != 2)
2126                return -1;
2127        partition = json_string(part_str);
2128        disk = json_string(disk_str);
2129
2130        root = json_object();
2131        if (!root)
2132                return -1;
2133        json_object_set_new(root, "partition", partition);
2134        json_object_set_new(root, "disk", disk);
2135
2136        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_SESSION, root);
2137
2138        return 0;
2139}
2140
2141static int og_cmd_legacy_poweroff(const char *input, struct og_cmd *cmd)
2142{
2143        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_POWEROFF, NULL);
2144
2145        return 0;
2146}
2147
2148static int og_cmd_legacy_refresh(const char *input, struct og_cmd *cmd)
2149{
2150        og_cmd_init(cmd, OG_METHOD_GET, OG_CMD_REFRESH, NULL);
2151
2152        return 0;
2153}
2154
2155static int og_cmd_legacy_reboot(const char *input, struct og_cmd *cmd)
2156{
2157        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_REBOOT, NULL);
2158
2159        return 0;
2160}
2161
2162static int og_cmd_legacy_stop(const char *input, struct og_cmd *cmd)
2163{
2164        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_STOP, NULL);
2165
2166        return 0;
2167}
2168
2169static int og_cmd_legacy_hardware(const char *input, struct og_cmd *cmd)
2170{
2171        og_cmd_init(cmd, OG_METHOD_GET, OG_CMD_HARDWARE, NULL);
2172
2173        return 0;
2174}
2175
2176static int og_cmd_legacy_software(const char *input, struct og_cmd *cmd)
2177{
2178        og_cmd_init(cmd, OG_METHOD_GET, OG_CMD_SOFTWARE, NULL);
2179
2180        return 0;
2181}
2182
2183static int og_cmd_legacy_image_create(const char *input, struct og_cmd *cmd)
2184{
2185        json_t *root, *disk, *partition, *code, *image_id, *name, *repo;
2186        struct og_image_legacy img = {};
2187
2188        if (sscanf(input, "dsk=%s\rpar=%s\rcpt=%s\ridi=%s\rnci=%s\ripr=%s\r",
2189                   img.disk, img.part, img.code, img.image_id, img.name,
2190                   img.repo) != 6)
2191                return -1;
2192        image_id = json_string(img.image_id);
2193        partition = json_string(img.part);
2194        code = json_string(img.code);
2195        name = json_string(img.name);
2196        repo = json_string(img.repo);
2197        disk = json_string(img.disk);
2198
2199        root = json_object();
2200        if (!root)
2201                return -1;
2202        json_object_set_new(root, "partition", partition);
2203        json_object_set_new(root, "repository", repo);
2204        json_object_set_new(root, "id", image_id);
2205        json_object_set_new(root, "code", code);
2206        json_object_set_new(root, "name", name);
2207        json_object_set_new(root, "disk", disk);
2208
2209        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_IMAGE_CREATE, root);
2210
2211        return 0;
2212}
2213
2214#define OG_DB_RESTORE_TYPE_MAXLEN       64
2215
2216static int og_cmd_legacy_image_restore(const char *input, struct og_cmd *cmd)
2217{
2218        json_t *root, *disk, *partition, *image_id, *name, *repo;
2219        char restore_type_str[OG_DB_RESTORE_TYPE_MAXLEN + 1] = {};
2220        char software_id_str[OG_DB_INT_MAXLEN + 1] = {};
2221        json_t *software_id, *restore_type;
2222        struct og_image_legacy img = {};
2223
2224        if (sscanf(input,
2225                   "dsk=%s\rpar=%s\ridi=%s\rnci=%s\ripr=%s\rifs=%s\rptc=%s\r",
2226                   img.disk, img.part, img.image_id, img.name, img.repo,
2227                   software_id_str, restore_type_str) != 7)
2228                return -1;
2229
2230        restore_type = json_string(restore_type_str);
2231        software_id = json_string(software_id_str);
2232        image_id = json_string(img.image_id);
2233        partition = json_string(img.part);
2234        name = json_string(img.name);
2235        repo = json_string(img.repo);
2236        disk = json_string(img.disk);
2237
2238        root = json_object();
2239        if (!root)
2240                return -1;
2241        json_object_set_new(root, "profile", software_id);
2242        json_object_set_new(root, "partition", partition);
2243        json_object_set_new(root, "type", restore_type);
2244        json_object_set_new(root, "repository", repo);
2245        json_object_set_new(root, "id", image_id);
2246        json_object_set_new(root, "name", name);
2247        json_object_set_new(root, "disk", disk);
2248
2249        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_IMAGE_RESTORE, root);
2250
2251        return 0;
2252}
2253
2254static int og_cmd_legacy_setup(const char *input, struct og_cmd *cmd)
2255{
2256        json_t *root, *disk, *cache, *cache_size, *partition_setup, *object;
2257        struct og_legacy_partition part_cfg[OG_PARTITION_MAX] = {};
2258        char cache_size_str [OG_DB_INT_MAXLEN + 1];
2259        char disk_str [OG_DB_SMALLINT_MAXLEN + 1];
2260        json_t *part, *code, *fs, *size, *format;
2261        unsigned int partition_len = 0;
2262        const char *in_ptr;
2263        char cache_str[2];
2264
2265        if (sscanf(input, "dsk=%s\rcfg=dis=%*[^*]*che=%[^*]*tch=%[^!]!",
2266                   disk_str, cache_str, cache_size_str) != 3)
2267                return -1;
2268
2269        in_ptr = strstr(input, "!") + 1;
2270        while (strlen(in_ptr) > 0) {
2271                if(sscanf(in_ptr,
2272                          "par=%[^*]*cpt=%[^*]*sfi=%[^*]*tam=%[^*]*ope=%[^%%]%%",
2273                          part_cfg[partition_len].partition,
2274                          part_cfg[partition_len].code,
2275                          part_cfg[partition_len].filesystem,
2276                          part_cfg[partition_len].size,
2277                          part_cfg[partition_len].format) != 5)
2278                        return -1;
2279                in_ptr = strstr(in_ptr, "%") + 1;
2280                partition_len++;
2281        }
2282
2283        root = json_object();
2284        if (!root)
2285                return -1;
2286
2287        cache_size = json_string(cache_size_str);
2288        cache = json_string(cache_str);
2289        partition_setup = json_array();
2290        disk = json_string(disk_str);
2291
2292        for (unsigned int i = 0; i < partition_len; ++i) {
2293                object = json_object();
2294                if (!object) {
2295                        json_decref(root);
2296                        return -1;
2297                }
2298
2299                part = json_string(part_cfg[i].partition);
2300                fs = json_string(part_cfg[i].filesystem);
2301                format = json_string(part_cfg[i].format);
2302                code = json_string(part_cfg[i].code);
2303                size = json_string(part_cfg[i].size);
2304
2305                json_object_set_new(object, "partition", part);
2306                json_object_set_new(object, "filesystem", fs);
2307                json_object_set_new(object, "format", format);
2308                json_object_set_new(object, "code", code);
2309                json_object_set_new(object, "size", size);
2310
2311                json_array_append_new(partition_setup, object);
2312        }
2313
2314        json_object_set_new(root, "partition_setup", partition_setup);
2315        json_object_set_new(root, "cache_size", cache_size);
2316        json_object_set_new(root, "cache", cache);
2317        json_object_set_new(root, "disk", disk);
2318
2319        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_SETUP, root);
2320
2321        return 0;
2322}
2323
2324static int og_cmd_legacy_run_schedule(const char *input, struct og_cmd *cmd)
2325{
2326        og_cmd_init(cmd, OG_METHOD_GET, OG_CMD_RUN_SCHEDULE, NULL);
2327
2328        return 0;
2329}
2330
2331static int og_cmd_legacy(const char *input, struct og_cmd *cmd)
2332{
2333        char legacy_cmd[32] = {};
2334        int err = -1;
2335
2336        if (sscanf(input, "nfn=%31s\r", legacy_cmd) != 1) {
2337                syslog(LOG_ERR, "malformed database legacy input\n");
2338                return -1;
2339        }
2340        input = strchr(input, '\r') + 1;
2341
2342        if (!strcmp(legacy_cmd, "Arrancar")) {
2343                err = og_cmd_legacy_wol(input, cmd);
2344        } else if (!strcmp(legacy_cmd, "EjecutarScript")) {
2345                err = og_cmd_legacy_shell_run(input, cmd);
2346        } else if (!strcmp(legacy_cmd, "IniciarSesion")) {
2347                err = og_cmd_legacy_session(input, cmd);
2348        } else if (!strcmp(legacy_cmd, "Apagar")) {
2349                err = og_cmd_legacy_poweroff(input, cmd);
2350        } else if (!strcmp(legacy_cmd, "Actualizar")) {
2351                err = og_cmd_legacy_refresh(input, cmd);
2352        } else if (!strcmp(legacy_cmd, "Reiniciar")) {
2353                err = og_cmd_legacy_reboot(input, cmd);
2354        } else if (!strcmp(legacy_cmd, "Purgar")) {
2355                err = og_cmd_legacy_stop(input, cmd);
2356        } else if (!strcmp(legacy_cmd, "InventarioHardware")) {
2357                err = og_cmd_legacy_hardware(input, cmd);
2358        } else if (!strcmp(legacy_cmd, "InventarioSoftware")) {
2359                err = og_cmd_legacy_software(input, cmd);
2360        } else if (!strcmp(legacy_cmd, "CrearImagen")) {
2361                err = og_cmd_legacy_image_create(input, cmd);
2362        } else if (!strcmp(legacy_cmd, "RestaurarImagen")) {
2363                err = og_cmd_legacy_image_restore(input, cmd);
2364        } else if (!strcmp(legacy_cmd, "Configurar")) {
2365                err = og_cmd_legacy_setup(input, cmd);
2366        } else if (!strcmp(legacy_cmd, "EjecutaComandosPendientes") ||
2367                   !strcmp(legacy_cmd, "Actualizar")) {
2368                err = og_cmd_legacy_run_schedule(input, cmd);
2369        }
2370
2371        return err;
2372}
2373
2374static int og_dbi_add_action(const struct og_dbi *dbi, const struct og_task *task,
2375                             struct og_cmd *cmd)
2376{
2377        char start_date_string[24];
2378        struct tm *start_date;
2379        const char *msglog;
2380        dbi_result result;
2381        time_t now;
2382
2383        time(&now);
2384        start_date = localtime(&now);
2385
2386        sprintf(start_date_string, "%hu/%hhu/%hhu %hhu:%hhu:%hhu",
2387                start_date->tm_year + 1900, start_date->tm_mon + 1,
2388                start_date->tm_mday, start_date->tm_hour, start_date->tm_min,
2389                start_date->tm_sec);
2390        result = dbi_conn_queryf(dbi->conn,
2391                                "INSERT INTO acciones (idordenador, "
2392                                "tipoaccion, idtipoaccion, descriaccion, ip, "
2393                                "sesion, idcomando, parametros, fechahorareg, "
2394                                "estado, resultado, ambito, idambito, "
2395                                "restrambito, idprocedimiento, idcentro, "
2396                                "idprogramacion) "
2397                                "VALUES (%d, %d, %d, '%s', '%s', %d, %d, '%s', "
2398                                "'%s', %d, %d, %d, %d, '%s', %d, %d, %d)",
2399                                cmd->client_id, EJECUCION_TAREA, task->task_id,
2400                                "", cmd->ip, 0, task->command_id,
2401                                task->params, start_date_string,
2402                                ACCION_INICIADA, ACCION_SINRESULTADO,
2403                                task->type_scope, task->scope, "",
2404                                task->procedure_id, task->center_id,
2405                                task->schedule_id);
2406        if (!result) {
2407                dbi_conn_error(dbi->conn, &msglog);
2408                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2409                       __func__, __LINE__, msglog);
2410                return -1;
2411        }
2412        cmd->id = dbi_conn_sequence_last(dbi->conn, NULL);
2413        dbi_result_free(result);
2414
2415        return 0;
2416}
2417
2418static int og_queue_task_command(struct og_dbi *dbi, const struct og_task *task,
2419                                 char *query)
2420{
2421        struct og_cmd *cmd;
2422        const char *msglog;
2423        dbi_result result;
2424
2425        result = dbi_conn_queryf(dbi->conn, query);
2426        if (!result) {
2427                dbi_conn_error(dbi->conn, &msglog);
2428                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2429                       __func__, __LINE__, msglog);
2430                return -1;
2431        }
2432
2433        while (dbi_result_next_row(result)) {
2434                cmd = (struct og_cmd *)calloc(1, sizeof(struct og_cmd));
2435                if (!cmd) {
2436                        dbi_result_free(result);
2437                        return -1;
2438                }
2439
2440                cmd->client_id  = dbi_result_get_uint(result, "idordenador");
2441                cmd->ip         = strdup(dbi_result_get_string(result, "ip"));
2442                cmd->mac        = strdup(dbi_result_get_string(result, "mac"));
2443
2444                og_cmd_legacy(task->params, cmd);
2445
2446                if (task->procedure_id) {
2447                        if (og_dbi_add_action(dbi, task, cmd)) {
2448                                dbi_result_free(result);
2449                                return -1;
2450                        }
2451                } else {
2452                        cmd->id = task->task_id;
2453                }
2454
2455                list_add_tail(&cmd->list, &cmd_list);
2456        }
2457
2458        dbi_result_free(result);
2459
2460        return 0;
2461}
2462
2463static int og_queue_task_group_clients(struct og_dbi *dbi, struct og_task *task,
2464                                       char *query)
2465{
2466
2467        const char *msglog;
2468        dbi_result result;
2469
2470        result = dbi_conn_queryf(dbi->conn, query);
2471        if (!result) {
2472                dbi_conn_error(dbi->conn, &msglog);
2473                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2474                       __func__, __LINE__, msglog);
2475                return -1;
2476        }
2477
2478        while (dbi_result_next_row(result)) {
2479                uint32_t group_id = dbi_result_get_uint(result, "idgrupo");
2480
2481                sprintf(query, "SELECT idgrupo FROM gruposordenadores "
2482                                "WHERE grupoid=%d", group_id);
2483                if (og_queue_task_group_clients(dbi, task, query)) {
2484                        dbi_result_free(result);
2485                        return -1;
2486                }
2487
2488                sprintf(query,"SELECT ip, mac, idordenador FROM ordenadores "
2489                              "WHERE grupoid=%d", group_id);
2490                if (og_queue_task_command(dbi, task, query)) {
2491                        dbi_result_free(result);
2492                        return -1;
2493                }
2494
2495        }
2496
2497        dbi_result_free(result);
2498
2499        return 0;
2500}
2501
2502static int og_queue_task_group_classrooms(struct og_dbi *dbi,
2503                                          struct og_task *task, char *query)
2504{
2505
2506        const char *msglog;
2507        dbi_result result;
2508
2509        result = dbi_conn_queryf(dbi->conn, query);
2510        if (!result) {
2511                dbi_conn_error(dbi->conn, &msglog);
2512                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2513                       __func__, __LINE__, msglog);
2514                return -1;
2515        }
2516
2517        while (dbi_result_next_row(result)) {
2518                uint32_t group_id = dbi_result_get_uint(result, "idgrupo");
2519
2520                sprintf(query, "SELECT idgrupo FROM grupos "
2521                                "WHERE grupoid=%d AND tipo=%d", group_id, AMBITO_GRUPOSAULAS);
2522                if (og_queue_task_group_classrooms(dbi, task, query)) {
2523                        dbi_result_free(result);
2524                        return -1;
2525                }
2526
2527                sprintf(query,
2528                        "SELECT ip,mac,idordenador "
2529                        "FROM ordenadores INNER JOIN aulas "
2530                        "WHERE ordenadores.idaula=aulas.idaula "
2531                        "AND aulas.grupoid=%d",
2532                        group_id);
2533                if (og_queue_task_command(dbi, task, query)) {
2534                        dbi_result_free(result);
2535                        return -1;
2536                }
2537
2538        }
2539
2540        dbi_result_free(result);
2541
2542        return 0;
2543}
2544
2545static int og_queue_task_clients(struct og_dbi *dbi, struct og_task *task)
2546{
2547        char query[4096];
2548
2549        switch (task->type_scope) {
2550                case AMBITO_CENTROS:
2551                        sprintf(query,
2552                                "SELECT ip,mac,idordenador "
2553                                "FROM ordenadores INNER JOIN aulas "
2554                                "WHERE ordenadores.idaula=aulas.idaula "
2555                                "AND idcentro=%d",
2556                                task->scope);
2557                        return og_queue_task_command(dbi, task, query);
2558                case AMBITO_GRUPOSAULAS:
2559                        sprintf(query,
2560                                "SELECT idgrupo FROM grupos "
2561                                "WHERE idgrupo=%i AND tipo=%d",
2562                                task->scope, AMBITO_GRUPOSAULAS);
2563                        return og_queue_task_group_classrooms(dbi, task, query);
2564                case AMBITO_AULAS:
2565                        sprintf(query,
2566                                "SELECT ip,mac,idordenador FROM ordenadores "
2567                                "WHERE idaula=%d",
2568                                task->scope);
2569                        return og_queue_task_command(dbi, task, query);
2570                case AMBITO_GRUPOSORDENADORES:
2571                        sprintf(query,
2572                                "SELECT idgrupo FROM gruposordenadores "
2573                                "WHERE idgrupo = %d",
2574                                task->scope);
2575                        return og_queue_task_group_clients(dbi, task, query);
2576                case AMBITO_ORDENADORES:
2577                        sprintf(query,
2578                                "SELECT ip, mac, idordenador FROM ordenadores "
2579                                "WHERE idordenador = %d",
2580                                task->scope);
2581                        return og_queue_task_command(dbi, task, query);
2582        }
2583        return 0;
2584}
2585
2586int og_dbi_queue_procedure(struct og_dbi *dbi, struct og_task *task)
2587{
2588        uint32_t procedure_id;
2589        const char *msglog;
2590        dbi_result result;
2591
2592        result = dbi_conn_queryf(dbi->conn,
2593                        "SELECT parametros, procedimientoid, idcomando "
2594                        "FROM procedimientos_acciones "
2595                        "WHERE idprocedimiento=%d ORDER BY orden", task->procedure_id);
2596        if (!result) {
2597                dbi_conn_error(dbi->conn, &msglog);
2598                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2599                       __func__, __LINE__, msglog);
2600                return -1;
2601        }
2602
2603        while (dbi_result_next_row(result)) {
2604                procedure_id = dbi_result_get_uint(result, "procedimientoid");
2605                if (procedure_id > 0) {
2606                        task->procedure_id = procedure_id;
2607                        if (og_dbi_queue_procedure(dbi, task))
2608                                return -1;
2609                        continue;
2610                }
2611
2612                task->params    = strdup(dbi_result_get_string(result, "parametros"));
2613                task->command_id = dbi_result_get_uint(result, "idcomando");
2614                if (og_queue_task_clients(dbi, task))
2615                        return -1;
2616        }
2617
2618        dbi_result_free(result);
2619
2620        return 0;
2621}
2622
2623static int og_dbi_queue_task(struct og_dbi *dbi, uint32_t task_id,
2624                             uint32_t schedule_id)
2625{
2626        struct og_task task = {};
2627        uint32_t task_id_next;
2628        const char *msglog;
2629        dbi_result result;
2630
2631        task.schedule_id = schedule_id;
2632
2633        result = dbi_conn_queryf(dbi->conn,
2634                        "SELECT tareas_acciones.orden, "
2635                                "tareas_acciones.idprocedimiento, "
2636                                "tareas_acciones.tareaid, "
2637                                "tareas.idtarea, "
2638                                "tareas.idcentro, "
2639                                "tareas.ambito, "
2640                                "tareas.idambito, "
2641                                "tareas.restrambito "
2642                        " FROM tareas"
2643                                " INNER JOIN tareas_acciones ON tareas_acciones.idtarea=tareas.idtarea"
2644                        " WHERE tareas_acciones.idtarea=%u ORDER BY tareas_acciones.orden ASC", task_id);
2645        if (!result) {
2646                dbi_conn_error(dbi->conn, &msglog);
2647                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2648                       __func__, __LINE__, msglog);
2649                return -1;
2650        }
2651
2652        while (dbi_result_next_row(result)) {
2653                task_id_next = dbi_result_get_uint(result, "tareaid");
2654
2655                if (task_id_next > 0) {
2656                        if (og_dbi_queue_task(dbi, task_id_next, schedule_id))
2657                                return -1;
2658
2659                        continue;
2660                }
2661                task.task_id = dbi_result_get_uint(result, "idtarea");
2662                task.center_id = dbi_result_get_uint(result, "idcentro");
2663                task.procedure_id = dbi_result_get_uint(result, "idprocedimiento");
2664                task.type_scope = dbi_result_get_uint(result, "ambito");
2665                task.scope = dbi_result_get_uint(result, "idambito");
2666                task.filtered_scope = dbi_result_get_string(result, "restrambito");
2667
2668                og_dbi_queue_procedure(dbi, &task);
2669        }
2670
2671        dbi_result_free(result);
2672
2673        return 0;
2674}
2675
2676static int og_dbi_queue_command(struct og_dbi *dbi, uint32_t task_id,
2677                                uint32_t schedule_id)
2678{
2679        struct og_task task = {};
2680        const char *msglog;
2681        dbi_result result;
2682        char query[4096];
2683
2684        result = dbi_conn_queryf(dbi->conn,
2685                        "SELECT idaccion, idcentro, idordenador, parametros "
2686                        "FROM acciones "
2687                        "WHERE sesion = %u", task_id);
2688        if (!result) {
2689                dbi_conn_error(dbi->conn, &msglog);
2690                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2691                       __func__, __LINE__, msglog);
2692                return -1;
2693        }
2694
2695        while (dbi_result_next_row(result)) {
2696                task.task_id = dbi_result_get_uint(result, "idaccion");
2697                task.center_id = dbi_result_get_uint(result, "idcentro");
2698                task.scope = dbi_result_get_uint(result, "idordenador");
2699                task.params = strdup(dbi_result_get_string(result, "parametros"));
2700
2701                sprintf(query,
2702                        "SELECT ip, mac, idordenador FROM ordenadores "
2703                        "WHERE idordenador = %d",
2704                        task.scope);
2705                if (og_queue_task_command(dbi, &task, query)) {
2706                        dbi_result_free(result);
2707                        return -1;
2708                }
2709        }
2710
2711        dbi_result_free(result);
2712
2713        return 0;
2714}
2715
2716int og_dbi_update_action(uint32_t id, bool success)
2717{
2718        char end_date_string[24];
2719        struct tm *end_date;
2720        const char *msglog;
2721        struct og_dbi *dbi;
2722        uint8_t status = 2;
2723        dbi_result result;
2724        time_t now;
2725
2726        if (!id)
2727                return 0;
2728
2729        dbi = og_dbi_open(&ogconfig.db);
2730        if (!dbi) {
2731                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
2732                       __func__, __LINE__);
2733                return -1;
2734        }
2735
2736        time(&now);
2737        end_date = localtime(&now);
2738
2739        sprintf(end_date_string, "%hu/%hhu/%hhu %hhu:%hhu:%hhu",
2740                end_date->tm_year + 1900, end_date->tm_mon + 1,
2741                end_date->tm_mday, end_date->tm_hour, end_date->tm_min,
2742                end_date->tm_sec);
2743        result = dbi_conn_queryf(dbi->conn,
2744                                 "UPDATE acciones SET fechahorafin='%s', "
2745                                 "estado=%d, resultado=%d WHERE idaccion=%d",
2746                                 end_date_string, ACCION_FINALIZADA,
2747                                 status - success, id);
2748
2749        if (!result) {
2750                dbi_conn_error(dbi->conn, &msglog);
2751                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2752                       __func__, __LINE__, msglog);
2753                og_dbi_close(dbi);
2754                return -1;
2755        }
2756        dbi_result_free(result);
2757        og_dbi_close(dbi);
2758
2759        return 0;
2760}
2761
2762void og_schedule_run(unsigned int task_id, unsigned int schedule_id,
2763                     enum og_schedule_type type)
2764{
2765        struct og_msg_params params = {};
2766        bool duplicated = false;
2767        struct og_cmd *cmd, *next;
2768        struct og_dbi *dbi;
2769        unsigned int i;
2770
2771        dbi = og_dbi_open(&ogconfig.db);
2772        if (!dbi) {
2773                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
2774                       __func__, __LINE__);
2775                return;
2776        }
2777
2778        switch (type) {
2779        case OG_SCHEDULE_TASK:
2780                og_dbi_queue_task(dbi, task_id, schedule_id);
2781                break;
2782        case OG_SCHEDULE_PROCEDURE:
2783        case OG_SCHEDULE_COMMAND:
2784                og_dbi_queue_command(dbi, task_id, schedule_id);
2785                break;
2786        }
2787        og_dbi_close(dbi);
2788
2789        list_for_each_entry(cmd, &cmd_list, list) {
2790                for (i = 0; i < params.ips_array_len; i++) {
2791                        if (!strncmp(cmd->ip, params.ips_array[i],
2792                                     OG_DB_IP_MAXLEN)) {
2793                                duplicated = true;
2794                                break;
2795                        }
2796                }
2797
2798                if (!duplicated)
2799                        params.ips_array[params.ips_array_len++] = cmd->ip;
2800                else
2801                        duplicated = false;
2802        }
2803
2804        list_for_each_entry_safe(cmd, next, &cmd_list, list) {
2805                if (cmd->type != OG_CMD_WOL)
2806                        continue;
2807
2808                if (Levanta((char **)cmd->params.ips_array,
2809                            (char **)cmd->params.mac_array,
2810                            (char **)cmd->params.netmask_array,
2811                            cmd->params.ips_array_len,
2812                            (char *)cmd->params.wol_type))
2813                        og_dbi_update_action(cmd->id, true);
2814
2815                list_del(&cmd->list);
2816                og_cmd_free(cmd);
2817        }
2818
2819        og_send_request(OG_METHOD_GET, OG_CMD_RUN_SCHEDULE, &params, NULL);
2820}
2821
2822static int og_cmd_task_post(json_t *element, struct og_msg_params *params)
2823{
2824        struct og_cmd *cmd;
2825        struct og_dbi *dbi;
2826        const char *key;
2827        json_t *value;
2828        int err;
2829
2830        if (json_typeof(element) != JSON_OBJECT)
2831                return -1;
2832
2833        json_object_foreach(element, key, value) {
2834                if (!strcmp(key, "task")) {
2835                        err = og_json_parse_string(value, &params->task_id);
2836                        params->flags |= OG_REST_PARAM_TASK;
2837                }
2838
2839                if (err < 0)
2840                        break;
2841        }
2842
2843        if (!og_msg_params_validate(params, OG_REST_PARAM_TASK))
2844                return -1;
2845
2846        dbi = og_dbi_open(&ogconfig.db);
2847        if (!dbi) {
2848                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
2849                           __func__, __LINE__);
2850                return -1;
2851        }
2852
2853        og_schedule_run(atoi(params->task_id), 0, OG_SCHEDULE_TASK);
2854        og_dbi_close(dbi);
2855
2856        list_for_each_entry(cmd, &cmd_list, list)
2857                params->ips_array[params->ips_array_len++] = cmd->ip;
2858
2859        return og_send_request(OG_METHOD_GET, OG_CMD_RUN_SCHEDULE, params,
2860                               NULL);
2861}
2862
2863static int og_dbi_scope_get_computer(struct og_dbi *dbi, json_t *array,
2864                                     uint32_t room_id)
2865{
2866        const char *computer_name, *computer_ip;
2867        uint32_t computer_id;
2868        const char *msglog;
2869        dbi_result result;
2870        json_t *computer;
2871
2872        result = dbi_conn_queryf(dbi->conn,
2873                                 "SELECT idordenador, nombreordenador, ip "
2874                                 "FROM ordenadores WHERE idaula=%d",
2875                                 room_id);
2876        if (!result) {
2877                dbi_conn_error(dbi->conn, &msglog);
2878                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2879                       __func__, __LINE__, msglog);
2880                return -1;
2881        }
2882
2883        while (dbi_result_next_row(result)) {
2884                computer_id = dbi_result_get_uint(result, "idordenador");
2885                computer_name = dbi_result_get_string(result, "nombreordenador");
2886                computer_ip = dbi_result_get_string(result, "ip");
2887
2888                computer = json_object();
2889                if (!computer) {
2890                        dbi_result_free(result);
2891                        return -1;
2892                }
2893
2894                json_object_set_new(computer, "name", json_string(computer_name));
2895                json_object_set_new(computer, "type", json_string("computer"));
2896                json_object_set_new(computer, "id", json_integer(computer_id));
2897                json_object_set_new(computer, "scope", json_array());
2898                json_object_set_new(computer, "ip", json_string(computer_ip));
2899                json_array_append(array, computer);
2900                json_decref(computer);
2901        }
2902        dbi_result_free(result);
2903
2904        return 0;
2905}
2906
2907static int og_dbi_scope_get_room(struct og_dbi *dbi, json_t *array,
2908                                 uint32_t center_id)
2909{
2910        char room_name[OG_DB_ROOM_NAME_MAXLEN + 1] = {};
2911        json_t *room, *room_array;
2912        const char *msglog;
2913        dbi_result result;
2914        uint32_t room_id;
2915
2916        result = dbi_conn_queryf(dbi->conn,
2917                                 "SELECT idaula, nombreaula FROM aulas WHERE "
2918                                 "idcentro=%d",
2919                                 center_id);
2920        if (!result) {
2921                dbi_conn_error(dbi->conn, &msglog);
2922                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2923                       __func__, __LINE__, msglog);
2924                return -1;
2925        }
2926
2927        while (dbi_result_next_row(result)) {
2928                room_id = dbi_result_get_uint(result, "idaula");
2929                strncpy(room_name,
2930                        dbi_result_get_string(result, "nombreaula"),
2931                        OG_DB_CENTER_NAME_MAXLEN);
2932
2933                room = json_object();
2934                if (!room) {
2935                        dbi_result_free(result);
2936                        return -1;
2937                }
2938
2939                json_object_set_new(room, "name", json_string(room_name));
2940                json_object_set_new(room, "type", json_string("room"));
2941                json_object_set_new(room, "id", json_integer(room_id));
2942                json_object_set_new(room, "scope", json_array());
2943                json_array_append(array, room);
2944                json_decref(room);
2945
2946                room_array = json_object_get(room, "scope");
2947                if (!room_array) {
2948                        dbi_result_free(result);
2949                        return -1;
2950                }
2951
2952                if (og_dbi_scope_get_computer(dbi, room_array, room_id)) {
2953                        dbi_result_free(result);
2954                        return -1;
2955                }
2956        }
2957        dbi_result_free(result);
2958
2959        return 0;
2960}
2961
2962static int og_dbi_scope_get(struct og_dbi *dbi, json_t *array)
2963{
2964        char center_name[OG_DB_CENTER_NAME_MAXLEN + 1] = {};
2965        json_t *center, *array_room;
2966        const char *msglog;
2967        uint32_t center_id;
2968        dbi_result result;
2969
2970        result = dbi_conn_queryf(dbi->conn,
2971                                 "SELECT nombrecentro, idcentro FROM centros");
2972        if (!result) {
2973                dbi_conn_error(dbi->conn, &msglog);
2974                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2975                       __func__, __LINE__, msglog);
2976                return -1;
2977        }
2978
2979        while (dbi_result_next_row(result)) {
2980                center_id = dbi_result_get_uint(result, "idcentro");
2981                strncpy(center_name,
2982                        dbi_result_get_string(result, "nombrecentro"),
2983                        OG_DB_CENTER_NAME_MAXLEN);
2984
2985                center = json_object();
2986                if (!center) {
2987                        dbi_result_free(result);
2988                        return -1;
2989                }
2990
2991                array_room = json_array();
2992                if (!array_room) {
2993                        dbi_result_free(result);
2994                        json_decref(center);
2995                        return -1;
2996                }
2997
2998                json_object_set_new(center, "name", json_string(center_name));
2999                json_object_set_new(center, "type", json_string("center"));
3000                json_object_set_new(center, "id", json_integer(center_id));
3001                json_object_set_new(center, "scope", array_room);
3002                json_array_append(array, center);
3003                json_decref(center);
3004
3005                if (og_dbi_scope_get_room(dbi, array_room, center_id)) {
3006                        dbi_result_free(result);
3007                        return -1;
3008                }
3009        }
3010
3011        dbi_result_free(result);
3012
3013        return 0;
3014}
3015
3016static int og_cmd_scope_get(json_t *element, struct og_msg_params *params,
3017                            char *buffer_reply)
3018{
3019        struct og_buffer og_buffer = {
3020                .data = buffer_reply
3021        };
3022        json_t *root, *array;
3023        struct og_dbi *dbi;
3024
3025        root = json_object();
3026        if (!root)
3027                return -1;
3028
3029        array = json_array();
3030        if (!array) {
3031                json_decref(root);
3032                return -1;
3033        }
3034        json_object_set_new(root, "scope", array);
3035
3036        dbi = og_dbi_open(&ogconfig.db);
3037        if (!dbi) {
3038                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
3039                       __func__, __LINE__);
3040                json_decref(root);
3041                return -1;
3042        }
3043
3044        if (og_dbi_scope_get(dbi, array)) {
3045                og_dbi_close(dbi);
3046                json_decref(root);
3047                return -1;
3048        }
3049
3050        og_dbi_close(dbi);
3051
3052        json_dump_callback(root, og_json_dump_clients, &og_buffer, 0);
3053        json_decref(root);
3054
3055        return 0;
3056}
3057
3058int og_dbi_schedule_get(void)
3059{
3060        uint32_t schedule_id, task_id;
3061        struct og_schedule_time time;
3062        struct og_dbi *dbi;
3063        const char *msglog;
3064        dbi_result result;
3065
3066        dbi = og_dbi_open(&ogconfig.db);
3067        if (!dbi) {
3068                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
3069                       __func__, __LINE__);
3070                return -1;
3071        }
3072
3073        result = dbi_conn_queryf(dbi->conn,
3074                                 "SELECT idprogramacion, tipoaccion, identificador, "
3075                                 "sesion, annos, meses, diario, dias, semanas, horas, "
3076                                 "ampm, minutos FROM programaciones "
3077                                 "WHERE suspendida = 0");
3078        if (!result) {
3079                dbi_conn_error(dbi->conn, &msglog);
3080                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3081                       __func__, __LINE__, msglog);
3082                og_dbi_close(dbi);
3083                return -1;
3084        }
3085
3086        while (dbi_result_next_row(result)) {
3087                memset(&time, 0, sizeof(time));
3088                schedule_id = dbi_result_get_uint(result, "idprogramacion");
3089                task_id = dbi_result_get_uint(result, "identificador");
3090                time.years = dbi_result_get_uint(result, "annos");
3091                time.months = dbi_result_get_uint(result, "meses");
3092                time.weeks = dbi_result_get_uint(result, "semanas");
3093                time.week_days = dbi_result_get_uint(result, "dias");
3094                time.days = dbi_result_get_uint(result, "diario");
3095                time.hours = dbi_result_get_uint(result, "horas");
3096                time.am_pm = dbi_result_get_uint(result, "ampm");
3097                time.minutes = dbi_result_get_uint(result, "minutos");
3098                time.on_start = true;
3099
3100                og_schedule_create(schedule_id, task_id, OG_SCHEDULE_TASK,
3101                                   &time);
3102        }
3103
3104        dbi_result_free(result);
3105        og_dbi_close(dbi);
3106
3107        return 0;
3108}
3109
3110static int og_dbi_schedule_create(struct og_dbi *dbi,
3111                                  struct og_msg_params *params,
3112                                  uint32_t *schedule_id,
3113                                  enum og_schedule_type schedule_type)
3114{
3115        uint8_t suspended = 0;
3116        uint32_t session = 0;
3117        const char *msglog;
3118        dbi_result result;
3119        uint8_t type;
3120
3121        switch (schedule_type) {
3122        case OG_SCHEDULE_TASK:
3123                type = 3;
3124                break;
3125        case OG_SCHEDULE_PROCEDURE:
3126                type = 2;
3127                break;
3128        case OG_SCHEDULE_COMMAND:
3129                session = atoi(params->task_id);
3130                type = 1;
3131                break;
3132        }
3133
3134        result = dbi_conn_queryf(dbi->conn,
3135                                 "INSERT INTO programaciones (tipoaccion,"
3136                                 " identificador, nombrebloque, annos, meses,"
3137                                 " semanas, dias, diario, horas, ampm, minutos,"
3138                                 " suspendida, sesion) VALUES (%d, %s, '%s',"
3139                                 " %d, %d, %d, %d, %d, %d, %d, %d, %d, %d)",
3140                                 type, params->task_id, params->name,
3141                                 params->time.years, params->time.months,
3142                                 params->time.weeks, params->time.week_days,
3143                                 params->time.days, params->time.hours,
3144                                 params->time.am_pm, params->time.minutes,
3145                                 suspended, session);
3146        if (!result) {
3147                dbi_conn_error(dbi->conn, &msglog);
3148                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3149                       __func__, __LINE__, msglog);
3150                return -1;
3151        }
3152        dbi_result_free(result);
3153
3154        *schedule_id = dbi_conn_sequence_last(dbi->conn, NULL);
3155
3156        return 0;
3157}
3158
3159static int og_dbi_schedule_update(struct og_dbi *dbi,
3160                                  struct og_msg_params *params)
3161{
3162        const char *msglog;
3163        dbi_result result;
3164        uint8_t type = 3;
3165
3166        result = dbi_conn_queryf(dbi->conn,
3167                                 "UPDATE programaciones SET tipoaccion=%d, "
3168                                 "identificador='%s', nombrebloque='%s', "
3169                                 "annos=%d, meses=%d, "
3170                                 "diario=%d, horas=%d, ampm=%d, minutos=%d "
3171                                 "WHERE idprogramacion='%s'",
3172                                 type, params->task_id, params->name,
3173                                 params->time.years, params->time.months,
3174                                 params->time.days, params->time.hours,
3175                                 params->time.am_pm, params->time.minutes,
3176                                 params->id);
3177
3178        if (!result) {
3179                dbi_conn_error(dbi->conn, &msglog);
3180                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3181                       __func__, __LINE__, msglog);
3182                return -1;
3183        }
3184        dbi_result_free(result);
3185
3186        return 0;
3187}
3188
3189static int og_dbi_schedule_delete(struct og_dbi *dbi, uint32_t id)
3190{
3191        const char *msglog;
3192        dbi_result result;
3193
3194        result = dbi_conn_queryf(dbi->conn,
3195                                 "DELETE FROM programaciones WHERE idprogramacion=%d",
3196                                 id);
3197        if (!result) {
3198                dbi_conn_error(dbi->conn, &msglog);
3199                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3200                       __func__, __LINE__, msglog);
3201                return -1;
3202        }
3203        dbi_result_free(result);
3204
3205        return 0;
3206}
3207
3208struct og_db_schedule {
3209        uint32_t                id;
3210        uint32_t                task_id;
3211        const char              *name;
3212        struct og_schedule_time time;
3213        uint32_t                week_days;
3214        uint32_t                weeks;
3215        uint32_t                suspended;
3216        uint32_t                session;
3217};
3218
3219static int og_dbi_schedule_get_json(struct og_dbi *dbi, json_t *root,
3220                                    const char *task_id, const char *schedule_id)
3221{
3222        struct og_db_schedule schedule;
3223        json_t *obj, *array;
3224        const char *msglog;
3225        dbi_result result;
3226        int err = 0;
3227
3228        if (task_id) {
3229                result = dbi_conn_queryf(dbi->conn,
3230                                         "SELECT idprogramacion,"
3231                                         "       identificador, nombrebloque,"
3232                                         "       annos, meses, diario, dias,"
3233                                         "       semanas, horas, ampm,"
3234                                         "       minutos,suspendida, sesion "
3235                                         "FROM programaciones "
3236                                         "WHERE identificador=%d",
3237                                         atoi(task_id));
3238        } else if (schedule_id) {
3239                result = dbi_conn_queryf(dbi->conn,
3240                                         "SELECT idprogramacion,"
3241                                         "       identificador, nombrebloque,"
3242                                         "       annos, meses, diario, dias,"
3243                                         "       semanas, horas, ampm,"
3244                                         "       minutos,suspendida, sesion "
3245                                         "FROM programaciones "
3246                                         "WHERE idprogramacion=%d",
3247                                         atoi(schedule_id));
3248        } else {
3249                result = dbi_conn_queryf(dbi->conn,
3250                                         "SELECT idprogramacion,"
3251                                         "       identificador, nombrebloque,"
3252                                         "       annos, meses, diario, dias,"
3253                                         "       semanas, horas, ampm,"
3254                                         "       minutos,suspendida, sesion "
3255                                         "FROM programaciones");
3256        }
3257
3258        if (!result) {
3259                dbi_conn_error(dbi->conn, &msglog);
3260                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3261                       __func__, __LINE__, msglog);
3262                return -1;
3263        }
3264
3265        array = json_array();
3266        if (!array)
3267                return -1;
3268
3269        while (dbi_result_next_row(result)) {
3270                schedule.id = dbi_result_get_uint(result, "idprogramacion");
3271                schedule.task_id = dbi_result_get_uint(result, "identificador");
3272                schedule.name = dbi_result_get_string(result, "nombrebloque");
3273                schedule.time.years = dbi_result_get_uint(result, "annos");
3274                schedule.time.months = dbi_result_get_uint(result, "meses");
3275                schedule.time.days = dbi_result_get_uint(result, "diario");
3276                schedule.time.hours = dbi_result_get_uint(result, "horas");
3277                schedule.time.am_pm = dbi_result_get_uint(result, "ampm");
3278                schedule.time.minutes = dbi_result_get_uint(result, "minutos");
3279                schedule.week_days = dbi_result_get_uint(result, "dias");
3280                schedule.weeks = dbi_result_get_uint(result, "semanas");
3281                schedule.suspended = dbi_result_get_uint(result, "suspendida");
3282                schedule.session = dbi_result_get_uint(result, "sesion");
3283
3284                obj = json_object();
3285                if (!obj) {
3286                        err = -1;
3287                        break;
3288                }
3289                json_object_set_new(obj, "id", json_integer(schedule.id));
3290                json_object_set_new(obj, "task", json_integer(schedule.task_id));
3291                json_object_set_new(obj, "name", json_string(schedule.name));
3292                json_object_set_new(obj, "years", json_integer(schedule.time.years));
3293                json_object_set_new(obj, "months", json_integer(schedule.time.months));
3294                json_object_set_new(obj, "days", json_integer(schedule.time.days));
3295                json_object_set_new(obj, "hours", json_integer(schedule.time.hours));
3296                json_object_set_new(obj, "am_pm", json_integer(schedule.time.am_pm));
3297                json_object_set_new(obj, "minutes", json_integer(schedule.time.minutes));
3298                json_object_set_new(obj, "week_days", json_integer(schedule.week_days));
3299                json_object_set_new(obj, "weeks", json_integer(schedule.weeks));
3300                json_object_set_new(obj, "suspended", json_integer(schedule.suspended));
3301                json_object_set_new(obj, "session", json_integer(schedule.session));
3302
3303                json_array_append_new(array, obj);
3304        }
3305
3306        json_object_set_new(root, "schedule", array);
3307
3308        dbi_result_free(result);
3309
3310        return err;
3311}
3312
3313static int og_task_schedule_create(struct og_msg_params *params)
3314{
3315        enum og_schedule_type type;
3316        uint32_t schedule_id;
3317        struct og_dbi *dbi;
3318        int err;
3319
3320        if (!strcmp(params->type, "task"))
3321                type = OG_SCHEDULE_TASK;
3322        else if (!strcmp(params->type, "procedure"))
3323                type = OG_SCHEDULE_PROCEDURE;
3324        else if (!strcmp(params->type, "command"))
3325                type = OG_SCHEDULE_COMMAND;
3326        else
3327                return -1;
3328
3329        dbi = og_dbi_open(&ogconfig.db);
3330        if (!dbi) {
3331                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
3332                       __func__, __LINE__);
3333                return -1;
3334        }
3335
3336        err = og_dbi_schedule_create(dbi, params, &schedule_id, type);
3337        if (err < 0) {
3338                og_dbi_close(dbi);
3339                return -1;
3340        }
3341        og_schedule_create(schedule_id, atoi(params->task_id), type,
3342                           &params->time);
3343        og_schedule_refresh(og_loop);
3344        og_dbi_close(dbi);
3345
3346        return 0;
3347}
3348
3349static int og_cmd_schedule_create(json_t *element, struct og_msg_params *params)
3350{
3351        const char *key;
3352        json_t *value;
3353        int err;
3354
3355        if (json_typeof(element) != JSON_OBJECT)
3356                return -1;
3357
3358        json_object_foreach(element, key, value) {
3359                if (!strcmp(key, "task")) {
3360                        err = og_json_parse_string(value, &params->task_id);
3361                        params->flags |= OG_REST_PARAM_TASK;
3362                } else if (!strcmp(key, "name")) {
3363                        err = og_json_parse_string(value, &params->name);
3364                        params->flags |= OG_REST_PARAM_NAME;
3365                } else if (!strcmp(key, "when")) {
3366                        err = og_json_parse_time_params(value, params);
3367                } else if (!strcmp(key, "type")) {
3368                        err = og_json_parse_string(value, &params->type);
3369                        params->flags |= OG_REST_PARAM_TYPE;
3370                }
3371
3372                if (err < 0)
3373                        break;
3374        }
3375
3376        if (!og_msg_params_validate(params, OG_REST_PARAM_TASK |
3377                                            OG_REST_PARAM_NAME |
3378                                            OG_REST_PARAM_TIME_YEARS |
3379                                            OG_REST_PARAM_TIME_MONTHS |
3380                                            OG_REST_PARAM_TIME_WEEKS |
3381                                            OG_REST_PARAM_TIME_WEEK_DAYS |
3382                                            OG_REST_PARAM_TIME_DAYS |
3383                                            OG_REST_PARAM_TIME_HOURS |
3384                                            OG_REST_PARAM_TIME_MINUTES |
3385                                            OG_REST_PARAM_TIME_AM_PM |
3386                                            OG_REST_PARAM_TYPE))
3387                return -1;
3388
3389        return og_task_schedule_create(params);
3390}
3391
3392static int og_cmd_schedule_update(json_t *element, struct og_msg_params *params)
3393{
3394        struct og_dbi *dbi;
3395        const char *key;
3396        json_t *value;
3397        int err;
3398
3399        if (json_typeof(element) != JSON_OBJECT)
3400                return -1;
3401
3402        json_object_foreach(element, key, value) {
3403                if (!strcmp(key, "id")) {
3404                        err = og_json_parse_string(value, &params->id);
3405                        params->flags |= OG_REST_PARAM_ID;
3406                } else if (!strcmp(key, "task")) {
3407                        err = og_json_parse_string(value, &params->task_id);
3408                        params->flags |= OG_REST_PARAM_TASK;
3409                } else if (!strcmp(key, "name")) {
3410                        err = og_json_parse_string(value, &params->name);
3411                        params->flags |= OG_REST_PARAM_NAME;
3412                } else if (!strcmp(key, "when"))
3413                        err = og_json_parse_time_params(value, params);
3414
3415                if (err < 0)
3416                        break;
3417        }
3418
3419        if (!og_msg_params_validate(params, OG_REST_PARAM_ID |
3420                                            OG_REST_PARAM_TASK |
3421                                            OG_REST_PARAM_NAME |
3422                                            OG_REST_PARAM_TIME_YEARS |
3423                                            OG_REST_PARAM_TIME_MONTHS |
3424                                            OG_REST_PARAM_TIME_DAYS |
3425                                            OG_REST_PARAM_TIME_HOURS |
3426                                            OG_REST_PARAM_TIME_MINUTES |
3427                                            OG_REST_PARAM_TIME_AM_PM))
3428                return -1;
3429
3430        dbi = og_dbi_open(&ogconfig.db);
3431        if (!dbi) {
3432                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
3433                           __func__, __LINE__);
3434                return -1;
3435        }
3436
3437        err = og_dbi_schedule_update(dbi, params);
3438        og_dbi_close(dbi);
3439
3440        if (err < 0)
3441                return err;
3442
3443        og_schedule_update(og_loop, atoi(params->id), atoi(params->task_id),
3444                           &params->time);
3445        og_schedule_refresh(og_loop);
3446
3447        return err;
3448}
3449
3450static int og_cmd_schedule_delete(json_t *element, struct og_msg_params *params)
3451{
3452        struct og_dbi *dbi;
3453        const char *key;
3454        json_t *value;
3455        int err;
3456
3457        if (json_typeof(element) != JSON_OBJECT)
3458                return -1;
3459
3460        json_object_foreach(element, key, value) {
3461                if (!strcmp(key, "id")) {
3462                        err = og_json_parse_string(value, &params->id);
3463                        params->flags |= OG_REST_PARAM_ID;
3464                } else {
3465                        return -1;
3466                }
3467
3468                if (err < 0)
3469                        break;
3470        }
3471
3472        if (!og_msg_params_validate(params, OG_REST_PARAM_ID))
3473                return -1;
3474
3475        dbi = og_dbi_open(&ogconfig.db);
3476        if (!dbi) {
3477                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
3478                           __func__, __LINE__);
3479                return -1;
3480        }
3481
3482        err = og_dbi_schedule_delete(dbi, atoi(params->id));
3483        og_dbi_close(dbi);
3484
3485        og_schedule_delete(og_loop, atoi(params->id));
3486
3487        return err;
3488}
3489
3490static int og_cmd_schedule_get(json_t *element, struct og_msg_params *params,
3491                               char *buffer_reply)
3492{
3493        struct og_buffer og_buffer = {
3494                .data   = buffer_reply,
3495        };
3496        json_t *schedule_root;
3497        struct og_dbi *dbi;
3498        const char *key;
3499        json_t *value;
3500        int err;
3501
3502        if (element) {
3503                if (json_typeof(element) != JSON_OBJECT)
3504                        return -1;
3505
3506                json_object_foreach(element, key, value) {
3507                        if (!strcmp(key, "task")) {
3508                                err = og_json_parse_string(value,
3509                                                           &params->task_id);
3510                        } else if (!strcmp(key, "id")) {
3511                                err = og_json_parse_string(value, &params->id);
3512                        } else {
3513                                return -1;
3514                        }
3515
3516                        if (err < 0)
3517                                break;
3518                }
3519        }
3520
3521        dbi = og_dbi_open(&ogconfig.db);
3522        if (!dbi) {
3523                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
3524                           __func__, __LINE__);
3525                return -1;
3526        }
3527
3528        schedule_root = json_object();
3529        if (!schedule_root) {
3530                og_dbi_close(dbi);
3531                return -1;
3532        }
3533
3534        err = og_dbi_schedule_get_json(dbi, schedule_root,
3535                                       params->task_id, params->id);
3536        og_dbi_close(dbi);
3537
3538        if (err >= 0)
3539                json_dump_callback(schedule_root, og_json_dump_clients, &og_buffer, 0);
3540
3541        json_decref(schedule_root);
3542
3543        return err;
3544}
3545
3546static int og_client_method_not_found(struct og_client *cli)
3547{
3548        /* To meet RFC 7231, this function MUST generate an Allow header field
3549         * containing the correct methods. For example: "Allow: POST\r\n"
3550         */
3551        char buf[] = "HTTP/1.1 405 Method Not Allowed\r\n"
3552                     "Content-Length: 0\r\n\r\n";
3553
3554        send(og_client_socket(cli), buf, strlen(buf), 0);
3555
3556        return -1;
3557}
3558
3559static int og_client_bad_request(struct og_client *cli)
3560{
3561        char buf[] = "HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\n\r\n";
3562
3563        send(og_client_socket(cli), buf, strlen(buf), 0);
3564
3565        return -1;
3566}
3567
3568static int og_client_not_found(struct og_client *cli)
3569{
3570        char buf[] = "HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n";
3571
3572        send(og_client_socket(cli), buf, strlen(buf), 0);
3573
3574        return -1;
3575}
3576
3577static int og_client_not_authorized(struct og_client *cli)
3578{
3579        char buf[] = "HTTP/1.1 401 Unauthorized\r\n"
3580                     "WWW-Authenticate: Basic\r\n"
3581                     "Content-Length: 0\r\n\r\n";
3582
3583        send(og_client_socket(cli), buf, strlen(buf), 0);
3584
3585        return -1;
3586}
3587
3588static int og_server_internal_error(struct og_client *cli)
3589{
3590        char buf[] = "HTTP/1.1 500 Internal Server Error\r\n"
3591                     "Content-Length: 0\r\n\r\n";
3592
3593        send(og_client_socket(cli), buf, strlen(buf), 0);
3594
3595        return -1;
3596}
3597
3598#define OG_MSG_RESPONSE_MAXLEN  65536
3599
3600static int og_client_ok(struct og_client *cli, char *buf_reply)
3601{
3602        char buf[OG_MSG_RESPONSE_MAXLEN] = {};
3603        int err = 0, len;
3604
3605        len = snprintf(buf, sizeof(buf),
3606                       "HTTP/1.1 200 OK\r\nContent-Length: %ld\r\n\r\n%s",
3607                       strlen(buf_reply), buf_reply);
3608        if (len >= (int)sizeof(buf))
3609                err = og_server_internal_error(cli);
3610
3611        send(og_client_socket(cli), buf, strlen(buf), 0);
3612
3613        return err;
3614}
3615
3616int og_client_state_process_payload_rest(struct og_client *cli)
3617{
3618        char buf_reply[OG_MSG_RESPONSE_MAXLEN] = {};
3619        struct og_msg_params params = {};
3620        enum og_rest_method method;
3621        const char *cmd, *body;
3622        json_error_t json_err;
3623        json_t *root = NULL;
3624        int err = 0;
3625
3626        syslog(LOG_DEBUG, "%s:%hu %.32s ...\n",
3627               inet_ntoa(cli->addr.sin_addr),
3628               ntohs(cli->addr.sin_port), cli->buf);
3629
3630        if (!strncmp(cli->buf, "GET", strlen("GET"))) {
3631                method = OG_METHOD_GET;
3632                cmd = cli->buf + strlen("GET") + 2;
3633        } else if (!strncmp(cli->buf, "POST", strlen("POST"))) {
3634                method = OG_METHOD_POST;
3635                cmd = cli->buf + strlen("POST") + 2;
3636        } else
3637                return og_client_method_not_found(cli);
3638
3639        body = strstr(cli->buf, "\r\n\r\n") + 4;
3640
3641        if (strcmp(cli->auth_token, ogconfig.rest.api_token)) {
3642                syslog(LOG_ERR, "wrong Authentication key\n");
3643                return og_client_not_authorized(cli);
3644        }
3645
3646        if (cli->content_length) {
3647                root = json_loads(body, 0, &json_err);
3648                if (!root) {
3649                        syslog(LOG_ERR, "malformed json line %d: %s\n",
3650                               json_err.line, json_err.text);
3651                        return og_client_not_found(cli);
3652                }
3653        }
3654
3655        if (!strncmp(cmd, "clients", strlen("clients"))) {
3656                if (method != OG_METHOD_POST &&
3657                    method != OG_METHOD_GET)
3658                        return og_client_method_not_found(cli);
3659
3660                if (method == OG_METHOD_POST && !root) {
3661                        syslog(LOG_ERR, "command clients with no payload\n");
3662                        return og_client_bad_request(cli);
3663                }
3664                switch (method) {
3665                case OG_METHOD_POST:
3666                        err = og_cmd_post_clients(root, &params);
3667                        break;
3668                case OG_METHOD_GET:
3669                        err = og_cmd_get_clients(root, &params, buf_reply);
3670                        break;
3671                default:
3672                        return og_client_bad_request(cli);
3673                }
3674        } else if (!strncmp(cmd, "client/setup",
3675                            strlen("client/setup"))) {
3676                if (method != OG_METHOD_GET)
3677                        return og_client_method_not_found(cli);
3678
3679                if (!root) {
3680                        syslog(LOG_ERR,
3681                               "command client partitions with no payload\n");
3682                        return og_client_bad_request(cli);
3683                }
3684
3685                err = og_cmd_get_client_setup(root, &params, buf_reply);
3686        } else if (!strncmp(cmd, "client/info",
3687                            strlen("client/info"))) {
3688                if (method != OG_METHOD_GET)
3689                        return og_client_method_not_found(cli);
3690
3691                if (!root) {
3692                        syslog(LOG_ERR,
3693                               "command client info with no payload\n");
3694                        return og_client_bad_request(cli);
3695                }
3696
3697                err = og_cmd_get_client_info(root, &params, buf_reply);
3698        } else if (!strncmp(cmd, "client/add", strlen("client/add"))) {
3699                if (method != OG_METHOD_POST)
3700                        return og_client_method_not_found(cli);
3701
3702                if (!root) {
3703                        syslog(LOG_ERR,
3704                               "command client info with no payload\n");
3705                        return og_client_bad_request(cli);
3706                }
3707
3708                err = og_cmd_post_client_add(root, &params, buf_reply);
3709        } else if (!strncmp(cmd, "client/delete", strlen("client/delete"))) {
3710                if (method != OG_METHOD_POST)
3711                        return og_client_method_not_found(cli);
3712
3713                if (!root) {
3714                        syslog(LOG_ERR,
3715                               "command client delete with no payload\n");
3716                        return og_client_bad_request(cli);
3717                }
3718
3719                err = og_cmd_post_client_delete(root, &params);
3720        } else if (!strncmp(cmd, "wol", strlen("wol"))) {
3721                if (method != OG_METHOD_POST)
3722                        return og_client_method_not_found(cli);
3723
3724                if (!root) {
3725                        syslog(LOG_ERR, "command wol with no payload\n");
3726                        return og_client_bad_request(cli);
3727                }
3728                err = og_cmd_wol(root, &params);
3729        } else if (!strncmp(cmd, "shell/run", strlen("shell/run"))) {
3730                if (method != OG_METHOD_POST)
3731                        return og_client_method_not_found(cli);
3732
3733                if (!root) {
3734                        syslog(LOG_ERR, "command run with no payload\n");
3735                        return og_client_bad_request(cli);
3736                }
3737                err = og_cmd_run_post(root, &params);
3738        } else if (!strncmp(cmd, "shell/output", strlen("shell/output"))) {
3739                if (method != OG_METHOD_POST)
3740                        return og_client_method_not_found(cli);
3741
3742                if (!root) {
3743                        syslog(LOG_ERR, "command output with no payload\n");
3744                        return og_client_bad_request(cli);
3745                }
3746
3747                err = og_cmd_run_get(root, &params, buf_reply);
3748        } else if (!strncmp(cmd, "session", strlen("session"))) {
3749                if (method != OG_METHOD_POST)
3750                        return og_client_method_not_found(cli);
3751
3752                if (!root) {
3753                        syslog(LOG_ERR, "command session with no payload\n");
3754                        return og_client_bad_request(cli);
3755                }
3756                err = og_cmd_session(root, &params);
3757        } else if (!strncmp(cmd, "scopes", strlen("scopes"))) {
3758                if (method != OG_METHOD_GET)
3759                        return og_client_method_not_found(cli);
3760
3761                err = og_cmd_scope_get(root, &params, buf_reply);
3762        } else if (!strncmp(cmd, "poweroff", strlen("poweroff"))) {
3763                if (method != OG_METHOD_POST)
3764                        return og_client_method_not_found(cli);
3765
3766                if (!root) {
3767                        syslog(LOG_ERR, "command poweroff with no payload\n");
3768                        return og_client_bad_request(cli);
3769                }
3770                err = og_cmd_poweroff(root, &params);
3771        } else if (!strncmp(cmd, "reboot", strlen("reboot"))) {
3772                if (method != OG_METHOD_POST)
3773                        return og_client_method_not_found(cli);
3774
3775                if (!root) {
3776                        syslog(LOG_ERR, "command reboot with no payload\n");
3777                        return og_client_bad_request(cli);
3778                }
3779                err = og_cmd_reboot(root, &params);
3780        } else if (!strncmp(cmd, "mode", strlen("mode"))) {
3781                if (method != OG_METHOD_GET && method != OG_METHOD_POST)
3782                        return og_client_method_not_found(cli);
3783
3784                if (method == OG_METHOD_POST && !root) {
3785                        syslog(LOG_ERR, "command mode with no payload\n");
3786                        return og_client_bad_request(cli);
3787                }
3788
3789                if (method == OG_METHOD_GET)
3790                        err = og_cmd_get_modes(root, &params, buf_reply);
3791                else if (method == OG_METHOD_POST)
3792                        err = og_cmd_post_modes(root, &params);
3793        } else if (!strncmp(cmd, "stop", strlen("stop"))) {
3794                if (method != OG_METHOD_POST)
3795                        return og_client_method_not_found(cli);
3796
3797                if (!root) {
3798                        syslog(LOG_ERR, "command stop with no payload\n");
3799                        return og_client_bad_request(cli);
3800                }
3801                err = og_cmd_stop(root, &params);
3802        } else if (!strncmp(cmd, "refresh", strlen("refresh"))) {
3803                if (method != OG_METHOD_POST)
3804                        return og_client_method_not_found(cli);
3805
3806                if (!root) {
3807                        syslog(LOG_ERR, "command refresh with no payload\n");
3808                        return og_client_bad_request(cli);
3809                }
3810                err = og_cmd_refresh(root, &params);
3811        } else if (!strncmp(cmd, "hardware", strlen("hardware"))) {
3812                if (method != OG_METHOD_GET && method != OG_METHOD_POST)
3813                        return og_client_method_not_found(cli);
3814
3815                if (!root) {
3816                        syslog(LOG_ERR, "command hardware with no payload\n");
3817                        return og_client_bad_request(cli);
3818                }
3819
3820                if (method == OG_METHOD_GET)
3821                        err = og_cmd_get_hardware(root, &params, buf_reply);
3822                else if (method == OG_METHOD_POST)
3823                        err = og_cmd_hardware(root, &params);
3824        } else if (!strncmp(cmd, "software", strlen("software"))) {
3825                if (method != OG_METHOD_POST && method != OG_METHOD_GET)
3826                        return og_client_method_not_found(cli);
3827
3828                if (!root) {
3829                        syslog(LOG_ERR, "command software with no payload\n");
3830                        return og_client_bad_request(cli);
3831                }
3832
3833                if (method == OG_METHOD_POST)
3834                        err = og_cmd_software(root, &params);
3835                else
3836                        err = og_cmd_get_software(root, &params, buf_reply);
3837        } else if (!strncmp(cmd, "images", strlen("images"))) {
3838                if (method != OG_METHOD_GET)
3839                        return og_client_method_not_found(cli);
3840
3841                if (!root)
3842                        err = og_cmd_images(buf_reply);
3843                else
3844                        return og_client_method_not_found(cli);
3845        } else if (!strncmp(cmd, "image/create", strlen("image/create"))) {
3846                if (method != OG_METHOD_POST)
3847                        return og_client_method_not_found(cli);
3848
3849                if (!root) {
3850                        syslog(LOG_ERR, "command create with no payload\n");
3851                        return og_client_bad_request(cli);
3852                }
3853                err = og_cmd_create_image(root, &params);
3854        } else if (!strncmp(cmd, "image/restore", strlen("image/restore"))) {
3855                if (method != OG_METHOD_POST)
3856                        return og_client_method_not_found(cli);
3857
3858                if (!root) {
3859                        syslog(LOG_ERR, "command create with no payload\n");
3860                        return og_client_bad_request(cli);
3861                }
3862                err = og_cmd_restore_image(root, &params);
3863        } else if (!strncmp(cmd, "setup", strlen("setup"))) {
3864                if (method != OG_METHOD_POST)
3865                        return og_client_method_not_found(cli);
3866
3867                if (!root) {
3868                        syslog(LOG_ERR, "command create with no payload\n");
3869                        return og_client_bad_request(cli);
3870                }
3871                err = og_cmd_setup(root, &params);
3872        } else if (!strncmp(cmd, "run/schedule", strlen("run/schedule"))) {
3873                if (method != OG_METHOD_POST)
3874                        return og_client_method_not_found(cli);
3875
3876                if (!root) {
3877                        syslog(LOG_ERR, "command create with no payload\n");
3878                        return og_client_bad_request(cli);
3879                }
3880
3881                err = og_cmd_run_schedule(root, &params);
3882        } else if (!strncmp(cmd, "task/run", strlen("task/run"))) {
3883                if (method != OG_METHOD_POST)
3884                        return og_client_method_not_found(cli);
3885
3886                if (!root) {
3887                        syslog(LOG_ERR, "command task with no payload\n");
3888                        return og_client_bad_request(cli);
3889                }
3890                err = og_cmd_task_post(root, &params);
3891        } else if (!strncmp(cmd, "schedule/create",
3892                            strlen("schedule/create"))) {
3893                if (method != OG_METHOD_POST)
3894                        return og_client_method_not_found(cli);
3895
3896                if (!root) {
3897                        syslog(LOG_ERR, "command task with no payload\n");
3898                        return og_client_bad_request(cli);
3899                }
3900                err = og_cmd_schedule_create(root, &params);
3901        } else if (!strncmp(cmd, "schedule/delete",
3902                            strlen("schedule/delete"))) {
3903                if (method != OG_METHOD_POST)
3904                        return og_client_method_not_found(cli);
3905
3906                if (!root) {
3907                        syslog(LOG_ERR, "command task with no payload\n");
3908                        return og_client_bad_request(cli);
3909                }
3910                err = og_cmd_schedule_delete(root, &params);
3911        } else if (!strncmp(cmd, "schedule/update",
3912                            strlen("schedule/update"))) {
3913                if (method != OG_METHOD_POST)
3914                        return og_client_method_not_found(cli);
3915
3916                if (!root) {
3917                        syslog(LOG_ERR, "command task with no payload\n");
3918                        return og_client_bad_request(cli);
3919                }
3920                err = og_cmd_schedule_update(root, &params);
3921        } else if (!strncmp(cmd, "schedule/get",
3922                            strlen("schedule/get"))) {
3923                if (method != OG_METHOD_POST)
3924                        return og_client_method_not_found(cli);
3925
3926                err = og_cmd_schedule_get(root, &params, buf_reply);
3927        } else {
3928                syslog(LOG_ERR, "unknown command: %.32s ...\n", cmd);
3929                err = og_client_not_found(cli);
3930        }
3931
3932        if (root)
3933                json_decref(root);
3934
3935        if (err < 0)
3936                return og_client_bad_request(cli);
3937
3938        err = og_client_ok(cli, buf_reply);
3939        if (err < 0) {
3940                syslog(LOG_ERR, "HTTP response to %s:%hu is too large\n",
3941                       inet_ntoa(cli->addr.sin_addr),
3942                       ntohs(cli->addr.sin_port));
3943        }
3944
3945        return err;
3946}
Note: See TracBrowser for help on using the repository browser.