source: ogServer-Git/src/rest.c @ d7e2022

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

Fix size of og_cmd_get_client_setup() return array

The return array needs to store 1 extra element for the disk setup.

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