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

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

#1004 Add GET /client/setup HTTP REST method

This method provides the partitions setup for a specific client. The
request must contain exactly 1 client's IP.

Request:
GET /client/setup
{'client': 192.168.56.12?}

Response:
200 OK
{

"partitions": [

{

"disk": 1,
"partition": 0,
"code": 0,
"size": 20971520,
"used_size": 0,
"filesystem": 0,
"os": 0,
"image": 0,
"software": 0

}

]

}

  • Property mode set to 100644
File size: 85.3 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        while (dbi_result_next_row(result) && len_part < OG_PARTITION_MAX) {
1095                partition.disk = dbi_result_get_int(result, "numdisk");
1096                partition.number = dbi_result_get_int(result, "numpar");
1097                partition.code = dbi_result_get_int(result, "codpar");
1098                partition.size = dbi_result_get_int(result, "tamano");
1099                partition.used_size = dbi_result_get_int(result, "uso");
1100                partition.filesystem = dbi_result_get_int(result, "idsistemafichero");
1101                partition.os = dbi_result_get_int(result, "idnombreso");
1102                partition.image = dbi_result_get_int(result, "idimagen");
1103                partition.software = dbi_result_get_int(result, "idperfilsoft");
1104
1105                partition_json = json_object();
1106                if (!partition_json) {
1107                        json_decref(root);
1108                        dbi_result_free(result);
1109                        og_dbi_close(dbi);
1110                        return -1;
1111                }
1112
1113                json_object_set_new(partition_json, "disk",
1114                                    json_integer(partition.disk));
1115                json_object_set_new(partition_json, "partition",
1116                                    json_integer(partition.number));
1117                json_object_set_new(partition_json, "code",
1118                                    json_integer(partition.code));
1119                json_object_set_new(partition_json, "size",
1120                                    json_integer(partition.size));
1121                json_object_set_new(partition_json, "used_size",
1122                                    json_integer(partition.used_size));
1123                json_object_set_new(partition_json, "filesystem",
1124                                    json_integer(partition.filesystem));
1125                json_object_set_new(partition_json, "os",
1126                                    json_integer(partition.os));
1127                json_object_set_new(partition_json, "image",
1128                                    json_integer(partition.image));
1129                json_object_set_new(partition_json, "software",
1130                                    json_integer(partition.software));
1131                json_array_append_new(partitions_array, partition_json);
1132
1133                ++len_part;
1134        }
1135
1136        dbi_result_free(result);
1137        og_dbi_close(dbi);
1138
1139        json_dump_callback(root, og_json_dump_clients, &og_buffer, 0);
1140        json_decref(root);
1141        return 0;
1142}
1143
1144static int og_cmd_stop(json_t *element, struct og_msg_params *params)
1145{
1146        const char *key;
1147        json_t *value;
1148        int err = 0;
1149
1150        if (json_typeof(element) != JSON_OBJECT)
1151                return -1;
1152
1153        json_object_foreach(element, key, value) {
1154                if (!strcmp(key, "clients"))
1155                        err = og_json_parse_clients(value, params);
1156
1157                if (err < 0)
1158                        break;
1159        }
1160
1161        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
1162                return -1;
1163
1164        return og_send_request(OG_METHOD_POST, OG_CMD_STOP, params, NULL);
1165}
1166
1167static int og_cmd_hardware(json_t *element, struct og_msg_params *params)
1168{
1169        const char *key;
1170        json_t *value;
1171        int err = 0;
1172
1173        if (json_typeof(element) != JSON_OBJECT)
1174                return -1;
1175
1176        json_object_foreach(element, key, value) {
1177                if (!strcmp(key, "clients"))
1178                        err = og_json_parse_clients(value, params);
1179
1180                if (err < 0)
1181                        break;
1182        }
1183
1184        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
1185                return -1;
1186
1187        return og_send_request(OG_METHOD_GET, OG_CMD_HARDWARE, params, NULL);
1188}
1189
1190static int og_cmd_get_hardware(json_t *element, struct og_msg_params *params,
1191                               char *buffer_reply)
1192{
1193        const char *key, *msglog, *hw_item, *hw_type;
1194        json_t *value, *root, *array, *item;
1195        struct og_scope scope = {};
1196        uint64_t flags = 0;
1197        struct og_dbi *dbi;
1198        dbi_result result;
1199        int err = 0;
1200
1201        struct og_buffer og_buffer = {
1202                .data = buffer_reply
1203        };
1204
1205        json_object_foreach(element, key, value) {
1206                if (!strcmp(key, "scope")) {
1207                        err = og_json_parse_scope(value, &scope,
1208                                                  OG_PARAM_SCOPE_ID |
1209                                                  OG_PARAM_SCOPE_TYPE);
1210                        flags |= OG_REST_PARAM_SCOPE;
1211                } else {
1212                        err = -1;
1213                }
1214
1215                if (err < 0)
1216                        return err;
1217        }
1218
1219        if (!og_flags_validate(flags, OG_REST_PARAM_SCOPE))
1220                return -1;
1221
1222        if (strcmp(scope.type, "computer")) {
1223                syslog(LOG_ERR, "incorrect scope type\n");
1224                return -1;
1225        }
1226
1227        dbi = og_dbi_open(&dbi_config);
1228        if (!dbi) {
1229                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
1230                       __func__, __LINE__);
1231                return -1;
1232        }
1233
1234        result = dbi_conn_queryf(dbi->conn,
1235                                 "SELECT hardwares.descripcion AS item, "
1236                                 "       tipohardwares.descripcion AS type "
1237                                 "FROM hardwares "
1238                                 "INNER JOIN perfileshard_hardwares "
1239                                 "    ON hardwares.idhardware = perfileshard_hardwares.idhardware "
1240                                 "INNER JOIN ordenadores "
1241                                 "    ON perfileshard_hardwares.idperfilhard = ordenadores.idperfilhard "
1242                                 "INNER JOIN tipohardwares "
1243                                 "    ON hardwares.idtipohardware = tipohardwares.idtipohardware "
1244                                 "WHERE ordenadores.idordenador = %u",
1245                                 scope.id);
1246        if (!result) {
1247                dbi_conn_error(dbi->conn, &msglog);
1248                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1249                       __func__, __LINE__, msglog);
1250                og_dbi_close(dbi);
1251                return -1;
1252        }
1253
1254        array = json_array();
1255        if (!array) {
1256                dbi_result_free(result);
1257                og_dbi_close(dbi);
1258                return -1;
1259        }
1260
1261        while (dbi_result_next_row(result)) {
1262                item = json_object();
1263                if (!item) {
1264                        dbi_result_free(result);
1265                        og_dbi_close(dbi);
1266                        json_decref(array);
1267                        return -1;
1268                }
1269
1270                hw_item = dbi_result_get_string(result, "item");
1271                hw_type = dbi_result_get_string(result, "type");
1272
1273                json_object_set_new(item, "type", json_string(hw_type));
1274                json_object_set_new(item, "description", json_string(hw_item));
1275                json_array_append_new(array, item);
1276        }
1277
1278        dbi_result_free(result);
1279        og_dbi_close(dbi);
1280
1281        root = json_object();
1282        if (!root){
1283                json_decref(array);
1284                return -1;
1285        }
1286
1287        json_object_set_new(root, "hardware", array);
1288
1289        json_dump_callback(root, og_json_dump_clients, &og_buffer, 0);
1290        json_decref(root);
1291        return 0;
1292}
1293
1294static int og_cmd_software(json_t *element, struct og_msg_params *params)
1295{
1296        json_t *clients, *value;
1297        const char *key;
1298        int err = 0;
1299
1300        if (json_typeof(element) != JSON_OBJECT)
1301                return -1;
1302
1303        json_object_foreach(element, key, value) {
1304                if (!strcmp(key, "clients"))
1305                        err = og_json_parse_clients(value, params);
1306                else if (!strcmp(key, "disk")) {
1307                        err = og_json_parse_string(value, &params->disk);
1308                        params->flags |= OG_REST_PARAM_DISK;
1309                }
1310                else if (!strcmp(key, "partition")) {
1311                        err = og_json_parse_string(value, &params->partition);
1312                        params->flags |= OG_REST_PARAM_PARTITION;
1313                }
1314
1315                if (err < 0)
1316                        break;
1317        }
1318
1319        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
1320                                            OG_REST_PARAM_DISK |
1321                                            OG_REST_PARAM_PARTITION))
1322                return -1;
1323
1324        clients = json_copy(element);
1325        json_object_del(clients, "clients");
1326
1327        return og_send_request(OG_METHOD_POST, OG_CMD_SOFTWARE, params, clients);
1328}
1329
1330static int og_cmd_create_image(json_t *element, struct og_msg_params *params)
1331{
1332        json_t *value, *clients;
1333        const char *key;
1334        int err = 0;
1335
1336        if (json_typeof(element) != JSON_OBJECT)
1337                return -1;
1338
1339        json_object_foreach(element, key, value) {
1340                if (!strcmp(key, "disk")) {
1341                        err = og_json_parse_string(value, &params->disk);
1342                        params->flags |= OG_REST_PARAM_DISK;
1343                } else if (!strcmp(key, "partition")) {
1344                        err = og_json_parse_string(value, &params->partition);
1345                        params->flags |= OG_REST_PARAM_PARTITION;
1346                } else if (!strcmp(key, "name")) {
1347                        err = og_json_parse_string(value, &params->name);
1348                        params->flags |= OG_REST_PARAM_NAME;
1349                } else if (!strcmp(key, "repository")) {
1350                        err = og_json_parse_string(value, &params->repository);
1351                        params->flags |= OG_REST_PARAM_REPO;
1352                } else if (!strcmp(key, "clients")) {
1353                        err = og_json_parse_clients(value, params);
1354                } else if (!strcmp(key, "id")) {
1355                        err = og_json_parse_string(value, &params->id);
1356                        params->flags |= OG_REST_PARAM_ID;
1357                } else if (!strcmp(key, "code")) {
1358                        err = og_json_parse_string(value, &params->code);
1359                        params->flags |= OG_REST_PARAM_CODE;
1360                }
1361
1362                if (err < 0)
1363                        break;
1364        }
1365
1366        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
1367                                            OG_REST_PARAM_DISK |
1368                                            OG_REST_PARAM_PARTITION |
1369                                            OG_REST_PARAM_CODE |
1370                                            OG_REST_PARAM_ID |
1371                                            OG_REST_PARAM_NAME |
1372                                            OG_REST_PARAM_REPO))
1373                return -1;
1374
1375        clients = json_copy(element);
1376        json_object_del(clients, "clients");
1377
1378        return og_send_request(OG_METHOD_POST, OG_CMD_IMAGE_CREATE, params,
1379                               clients);
1380}
1381
1382static int og_cmd_restore_image(json_t *element, struct og_msg_params *params)
1383{
1384        json_t *clients, *value;
1385        const char *key;
1386        int err = 0;
1387
1388        if (json_typeof(element) != JSON_OBJECT)
1389                return -1;
1390
1391        json_object_foreach(element, key, value) {
1392                if (!strcmp(key, "disk")) {
1393                        err = og_json_parse_string(value, &params->disk);
1394                        params->flags |= OG_REST_PARAM_DISK;
1395                } else if (!strcmp(key, "partition")) {
1396                        err = og_json_parse_string(value, &params->partition);
1397                        params->flags |= OG_REST_PARAM_PARTITION;
1398                } else if (!strcmp(key, "name")) {
1399                        err = og_json_parse_string(value, &params->name);
1400                        params->flags |= OG_REST_PARAM_NAME;
1401                } else if (!strcmp(key, "repository")) {
1402                        err = og_json_parse_string(value, &params->repository);
1403                        params->flags |= OG_REST_PARAM_REPO;
1404                } else if (!strcmp(key, "clients")) {
1405                        err = og_json_parse_clients(value, params);
1406                } else if (!strcmp(key, "type")) {
1407                        err = og_json_parse_string(value, &params->type);
1408                        params->flags |= OG_REST_PARAM_TYPE;
1409                } else if (!strcmp(key, "profile")) {
1410                        err = og_json_parse_string(value, &params->profile);
1411                        params->flags |= OG_REST_PARAM_PROFILE;
1412                } else if (!strcmp(key, "id")) {
1413                        err = og_json_parse_string(value, &params->id);
1414                        params->flags |= OG_REST_PARAM_ID;
1415                }
1416
1417                if (err < 0)
1418                        break;
1419        }
1420
1421        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
1422                                            OG_REST_PARAM_DISK |
1423                                            OG_REST_PARAM_PARTITION |
1424                                            OG_REST_PARAM_NAME |
1425                                            OG_REST_PARAM_REPO |
1426                                            OG_REST_PARAM_TYPE |
1427                                            OG_REST_PARAM_PROFILE |
1428                                            OG_REST_PARAM_ID))
1429                return -1;
1430
1431        clients = json_copy(element);
1432        json_object_del(clients, "clients");
1433
1434        return og_send_request(OG_METHOD_POST, OG_CMD_IMAGE_RESTORE, params,
1435                               clients);
1436}
1437
1438static int og_cmd_setup(json_t *element, struct og_msg_params *params)
1439{
1440        json_t *value, *clients;
1441        const char *key;
1442        int err = 0;
1443
1444        if (json_typeof(element) != JSON_OBJECT)
1445                return -1;
1446
1447        json_object_foreach(element, key, value) {
1448                if (!strcmp(key, "clients")) {
1449                        err = og_json_parse_clients(value, params);
1450                } else if (!strcmp(key, "disk")) {
1451                        err = og_json_parse_string(value, &params->disk);
1452                        params->flags |= OG_REST_PARAM_DISK;
1453                } else if (!strcmp(key, "cache")) {
1454                        err = og_json_parse_string(value, &params->cache);
1455                        params->flags |= OG_REST_PARAM_CACHE;
1456                } else if (!strcmp(key, "cache_size")) {
1457                        err = og_json_parse_string(value, &params->cache_size);
1458                        params->flags |= OG_REST_PARAM_CACHE_SIZE;
1459                } else if (!strcmp(key, "partition_setup")) {
1460                        err = og_json_parse_partition_setup(value, params);
1461                }
1462
1463                if (err < 0)
1464                        break;
1465        }
1466
1467        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
1468                                            OG_REST_PARAM_DISK |
1469                                            OG_REST_PARAM_CACHE |
1470                                            OG_REST_PARAM_CACHE_SIZE |
1471                                            OG_REST_PARAM_PART_0 |
1472                                            OG_REST_PARAM_PART_1 |
1473                                            OG_REST_PARAM_PART_2 |
1474                                            OG_REST_PARAM_PART_3))
1475                return -1;
1476
1477        clients = json_copy(element);
1478        json_object_del(clients, "clients");
1479
1480        return og_send_request(OG_METHOD_POST, OG_CMD_SETUP, params, clients);
1481}
1482
1483static int og_cmd_run_schedule(json_t *element, struct og_msg_params *params)
1484{
1485        const char *key;
1486        json_t *value;
1487        int err = 0;
1488
1489        json_object_foreach(element, key, value) {
1490                if (!strcmp(key, "clients"))
1491                        err = og_json_parse_clients(value, params);
1492
1493                if (err < 0)
1494                        break;
1495        }
1496
1497        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
1498                return -1;
1499
1500        return og_send_request(OG_METHOD_GET, OG_CMD_RUN_SCHEDULE, params,
1501                               NULL);
1502}
1503
1504static LIST_HEAD(cmd_list);
1505
1506const struct og_cmd *og_cmd_find(const char *client_ip)
1507{
1508        struct og_cmd *cmd, *next;
1509
1510        list_for_each_entry_safe(cmd, next, &cmd_list, list) {
1511                if (strcmp(cmd->ip, client_ip))
1512                        continue;
1513
1514                list_del(&cmd->list);
1515                return cmd;
1516        }
1517
1518        return NULL;
1519}
1520
1521void og_cmd_free(const struct og_cmd *cmd)
1522{
1523        struct og_msg_params *params = (struct og_msg_params *)&cmd->params;
1524        int i;
1525
1526        for (i = 0; i < params->ips_array_len; i++) {
1527                free((void *)params->ips_array[i]);
1528                free((void *)params->mac_array[i]);
1529        }
1530        free((void *)params->wol_type);
1531
1532        if (cmd->json)
1533                json_decref(cmd->json);
1534
1535        free((void *)cmd->ip);
1536        free((void *)cmd->mac);
1537        free((void *)cmd);
1538}
1539
1540static void og_cmd_init(struct og_cmd *cmd, enum og_rest_method method,
1541                        enum og_cmd_type type, json_t *root)
1542{
1543        cmd->type = type;
1544        cmd->method = method;
1545        cmd->params.ips_array[0] = strdup(cmd->ip);
1546        cmd->params.ips_array_len = 1;
1547        cmd->json = root;
1548}
1549
1550static int og_cmd_legacy_wol(const char *input, struct og_cmd *cmd)
1551{
1552        char wol_type[2] = {};
1553
1554        if (sscanf(input, "mar=%s", wol_type) != 1) {
1555                syslog(LOG_ERR, "malformed database legacy input\n");
1556                return -1;
1557        }
1558
1559        og_cmd_init(cmd, OG_METHOD_NO_HTTP, OG_CMD_WOL, NULL);
1560        cmd->params.mac_array[0] = strdup(cmd->mac);
1561        cmd->params.wol_type = strdup(wol_type);
1562
1563        return 0;
1564}
1565
1566static int og_cmd_legacy_shell_run(const char *input, struct og_cmd *cmd)
1567{
1568        json_t *root, *script, *echo;
1569
1570        script = json_string(input + 4);
1571        echo = json_boolean(false);
1572
1573        root = json_object();
1574        if (!root)
1575                return -1;
1576        json_object_set_new(root, "run", script);
1577        json_object_set_new(root, "echo", echo);
1578
1579        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_SHELL_RUN, root);
1580
1581        return 0;
1582}
1583
1584static int og_cmd_legacy_session(const char *input, struct og_cmd *cmd)
1585{
1586        char part_str[OG_DB_SMALLINT_MAXLEN + 1];
1587        char disk_str[OG_DB_SMALLINT_MAXLEN + 1];
1588        json_t *root, *disk, *partition;
1589
1590        if (sscanf(input, "dsk=%s\rpar=%s\r", disk_str, part_str) != 2)
1591                return -1;
1592        partition = json_string(part_str);
1593        disk = json_string(disk_str);
1594
1595        root = json_object();
1596        if (!root)
1597                return -1;
1598        json_object_set_new(root, "partition", partition);
1599        json_object_set_new(root, "disk", disk);
1600
1601        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_SESSION, root);
1602
1603        return 0;
1604}
1605
1606static int og_cmd_legacy_poweroff(const char *input, struct og_cmd *cmd)
1607{
1608        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_POWEROFF, NULL);
1609
1610        return 0;
1611}
1612
1613static int og_cmd_legacy_refresh(const char *input, struct og_cmd *cmd)
1614{
1615        og_cmd_init(cmd, OG_METHOD_GET, OG_CMD_REFRESH, NULL);
1616
1617        return 0;
1618}
1619
1620static int og_cmd_legacy_reboot(const char *input, struct og_cmd *cmd)
1621{
1622        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_REBOOT, NULL);
1623
1624        return 0;
1625}
1626
1627static int og_cmd_legacy_stop(const char *input, struct og_cmd *cmd)
1628{
1629        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_STOP, NULL);
1630
1631        return 0;
1632}
1633
1634static int og_cmd_legacy_hardware(const char *input, struct og_cmd *cmd)
1635{
1636        og_cmd_init(cmd, OG_METHOD_GET, OG_CMD_HARDWARE, NULL);
1637
1638        return 0;
1639}
1640
1641static int og_cmd_legacy_software(const char *input, struct og_cmd *cmd)
1642{
1643        og_cmd_init(cmd, OG_METHOD_GET, OG_CMD_SOFTWARE, NULL);
1644
1645        return 0;
1646}
1647
1648static int og_cmd_legacy_image_create(const char *input, struct og_cmd *cmd)
1649{
1650        json_t *root, *disk, *partition, *code, *image_id, *name, *repo;
1651        struct og_image_legacy img = {};
1652
1653        if (sscanf(input, "dsk=%s\rpar=%s\rcpt=%s\ridi=%s\rnci=%s\ripr=%s\r",
1654                   img.disk, img.part, img.code, img.image_id, img.name,
1655                   img.repo) != 6)
1656                return -1;
1657        image_id = json_string(img.image_id);
1658        partition = json_string(img.part);
1659        code = json_string(img.code);
1660        name = json_string(img.name);
1661        repo = json_string(img.repo);
1662        disk = json_string(img.disk);
1663
1664        root = json_object();
1665        if (!root)
1666                return -1;
1667        json_object_set_new(root, "partition", partition);
1668        json_object_set_new(root, "repository", repo);
1669        json_object_set_new(root, "id", image_id);
1670        json_object_set_new(root, "code", code);
1671        json_object_set_new(root, "name", name);
1672        json_object_set_new(root, "disk", disk);
1673
1674        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_IMAGE_CREATE, root);
1675
1676        return 0;
1677}
1678
1679#define OG_DB_RESTORE_TYPE_MAXLEN       64
1680
1681static int og_cmd_legacy_image_restore(const char *input, struct og_cmd *cmd)
1682{
1683        json_t *root, *disk, *partition, *image_id, *name, *repo;
1684        char restore_type_str[OG_DB_RESTORE_TYPE_MAXLEN + 1] = {};
1685        char software_id_str[OG_DB_INT_MAXLEN + 1] = {};
1686        json_t *software_id, *restore_type;
1687        struct og_image_legacy img = {};
1688
1689        if (sscanf(input,
1690                   "dsk=%s\rpar=%s\ridi=%s\rnci=%s\ripr=%s\rifs=%s\rptc=%s\r",
1691                   img.disk, img.part, img.image_id, img.name, img.repo,
1692                   software_id_str, restore_type_str) != 7)
1693                return -1;
1694
1695        restore_type = json_string(restore_type_str);
1696        software_id = json_string(software_id_str);
1697        image_id = json_string(img.image_id);
1698        partition = json_string(img.part);
1699        name = json_string(img.name);
1700        repo = json_string(img.repo);
1701        disk = json_string(img.disk);
1702
1703        root = json_object();
1704        if (!root)
1705                return -1;
1706        json_object_set_new(root, "profile", software_id);
1707        json_object_set_new(root, "partition", partition);
1708        json_object_set_new(root, "type", restore_type);
1709        json_object_set_new(root, "repository", repo);
1710        json_object_set_new(root, "id", image_id);
1711        json_object_set_new(root, "name", name);
1712        json_object_set_new(root, "disk", disk);
1713
1714        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_IMAGE_RESTORE, root);
1715
1716        return 0;
1717}
1718
1719static int og_cmd_legacy_setup(const char *input, struct og_cmd *cmd)
1720{
1721        json_t *root, *disk, *cache, *cache_size, *partition_setup, *object;
1722        struct og_legacy_partition part_cfg[OG_PARTITION_MAX] = {};
1723        char cache_size_str [OG_DB_INT_MAXLEN + 1];
1724        char disk_str [OG_DB_SMALLINT_MAXLEN + 1];
1725        json_t *part, *code, *fs, *size, *format;
1726        unsigned int partition_len = 0;
1727        const char *in_ptr;
1728        char cache_str[2];
1729
1730        if (sscanf(input, "dsk=%s\rcfg=dis=%*[^*]*che=%[^*]*tch=%[^!]!",
1731                   disk_str, cache_str, cache_size_str) != 3)
1732                return -1;
1733
1734        in_ptr = strstr(input, "!") + 1;
1735        while (strlen(in_ptr) > 0) {
1736                if(sscanf(in_ptr,
1737                          "par=%[^*]*cpt=%[^*]*sfi=%[^*]*tam=%[^*]*ope=%[^%%]%%",
1738                          part_cfg[partition_len].partition,
1739                          part_cfg[partition_len].code,
1740                          part_cfg[partition_len].filesystem,
1741                          part_cfg[partition_len].size,
1742                          part_cfg[partition_len].format) != 5)
1743                        return -1;
1744                in_ptr = strstr(in_ptr, "%") + 1;
1745                partition_len++;
1746        }
1747
1748        root = json_object();
1749        if (!root)
1750                return -1;
1751
1752        cache_size = json_string(cache_size_str);
1753        cache = json_string(cache_str);
1754        partition_setup = json_array();
1755        disk = json_string(disk_str);
1756
1757        for (unsigned int i = 0; i < partition_len; ++i) {
1758                object = json_object();
1759                if (!object) {
1760                        json_decref(root);
1761                        return -1;
1762                }
1763
1764                part = json_string(part_cfg[i].partition);
1765                fs = json_string(part_cfg[i].filesystem);
1766                format = json_string(part_cfg[i].format);
1767                code = json_string(part_cfg[i].code);
1768                size = json_string(part_cfg[i].size);
1769
1770                json_object_set_new(object, "partition", part);
1771                json_object_set_new(object, "filesystem", fs);
1772                json_object_set_new(object, "format", format);
1773                json_object_set_new(object, "code", code);
1774                json_object_set_new(object, "size", size);
1775
1776                json_array_append_new(partition_setup, object);
1777        }
1778
1779        json_object_set_new(root, "partition_setup", partition_setup);
1780        json_object_set_new(root, "cache_size", cache_size);
1781        json_object_set_new(root, "cache", cache);
1782        json_object_set_new(root, "disk", disk);
1783
1784        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_SETUP, root);
1785
1786        return 0;
1787}
1788
1789static int og_cmd_legacy_run_schedule(const char *input, struct og_cmd *cmd)
1790{
1791        og_cmd_init(cmd, OG_METHOD_GET, OG_CMD_RUN_SCHEDULE, NULL);
1792
1793        return 0;
1794}
1795
1796static int og_cmd_legacy(const char *input, struct og_cmd *cmd)
1797{
1798        char legacy_cmd[32] = {};
1799        int err = -1;
1800
1801        if (sscanf(input, "nfn=%31s\r", legacy_cmd) != 1) {
1802                syslog(LOG_ERR, "malformed database legacy input\n");
1803                return -1;
1804        }
1805        input = strchr(input, '\r') + 1;
1806
1807        if (!strcmp(legacy_cmd, "Arrancar")) {
1808                err = og_cmd_legacy_wol(input, cmd);
1809        } else if (!strcmp(legacy_cmd, "EjecutarScript")) {
1810                err = og_cmd_legacy_shell_run(input, cmd);
1811        } else if (!strcmp(legacy_cmd, "IniciarSesion")) {
1812                err = og_cmd_legacy_session(input, cmd);
1813        } else if (!strcmp(legacy_cmd, "Apagar")) {
1814                err = og_cmd_legacy_poweroff(input, cmd);
1815        } else if (!strcmp(legacy_cmd, "Actualizar")) {
1816                err = og_cmd_legacy_refresh(input, cmd);
1817        } else if (!strcmp(legacy_cmd, "Reiniciar")) {
1818                err = og_cmd_legacy_reboot(input, cmd);
1819        } else if (!strcmp(legacy_cmd, "Purgar")) {
1820                err = og_cmd_legacy_stop(input, cmd);
1821        } else if (!strcmp(legacy_cmd, "InventarioHardware")) {
1822                err = og_cmd_legacy_hardware(input, cmd);
1823        } else if (!strcmp(legacy_cmd, "InventarioSoftware")) {
1824                err = og_cmd_legacy_software(input, cmd);
1825        } else if (!strcmp(legacy_cmd, "CrearImagen")) {
1826                err = og_cmd_legacy_image_create(input, cmd);
1827        } else if (!strcmp(legacy_cmd, "RestaurarImagen")) {
1828                err = og_cmd_legacy_image_restore(input, cmd);
1829        } else if (!strcmp(legacy_cmd, "Configurar")) {
1830                err = og_cmd_legacy_setup(input, cmd);
1831        } else if (!strcmp(legacy_cmd, "EjecutaComandosPendientes") ||
1832                   !strcmp(legacy_cmd, "Actualizar")) {
1833                err = og_cmd_legacy_run_schedule(input, cmd);
1834        }
1835
1836        return err;
1837}
1838
1839static int og_dbi_add_action(const struct og_dbi *dbi, const struct og_task *task,
1840                             struct og_cmd *cmd)
1841{
1842        char start_date_string[24];
1843        struct tm *start_date;
1844        const char *msglog;
1845        dbi_result result;
1846        time_t now;
1847
1848        time(&now);
1849        start_date = localtime(&now);
1850
1851        sprintf(start_date_string, "%hu/%hhu/%hhu %hhu:%hhu:%hhu",
1852                start_date->tm_year + 1900, start_date->tm_mon + 1,
1853                start_date->tm_mday, start_date->tm_hour, start_date->tm_min,
1854                start_date->tm_sec);
1855        result = dbi_conn_queryf(dbi->conn,
1856                                "INSERT INTO acciones (idordenador, "
1857                                "tipoaccion, idtipoaccion, descriaccion, ip, "
1858                                "sesion, idcomando, parametros, fechahorareg, "
1859                                "estado, resultado, ambito, idambito, "
1860                                "restrambito, idprocedimiento, idcentro, "
1861                                "idprogramacion) "
1862                                "VALUES (%d, %d, %d, '%s', '%s', %d, %d, '%s', "
1863                                "'%s', %d, %d, %d, %d, '%s', %d, %d, %d)",
1864                                cmd->client_id, EJECUCION_TAREA, task->task_id,
1865                                "", cmd->ip, 0, task->command_id,
1866                                task->params, start_date_string,
1867                                ACCION_INICIADA, ACCION_SINRESULTADO,
1868                                task->type_scope, task->scope, "",
1869                                task->procedure_id, task->center_id,
1870                                task->schedule_id);
1871        if (!result) {
1872                dbi_conn_error(dbi->conn, &msglog);
1873                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1874                       __func__, __LINE__, msglog);
1875                return -1;
1876        }
1877        cmd->id = dbi_conn_sequence_last(dbi->conn, NULL);
1878        dbi_result_free(result);
1879
1880        return 0;
1881}
1882
1883static int og_queue_task_command(struct og_dbi *dbi, const struct og_task *task,
1884                                 char *query)
1885{
1886        struct og_cmd *cmd;
1887        const char *msglog;
1888        dbi_result result;
1889
1890        result = dbi_conn_queryf(dbi->conn, query);
1891        if (!result) {
1892                dbi_conn_error(dbi->conn, &msglog);
1893                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1894                       __func__, __LINE__, msglog);
1895                return -1;
1896        }
1897
1898        while (dbi_result_next_row(result)) {
1899                cmd = (struct og_cmd *)calloc(1, sizeof(struct og_cmd));
1900                if (!cmd) {
1901                        dbi_result_free(result);
1902                        return -1;
1903                }
1904
1905                cmd->client_id  = dbi_result_get_uint(result, "idordenador");
1906                cmd->ip         = strdup(dbi_result_get_string(result, "ip"));
1907                cmd->mac        = strdup(dbi_result_get_string(result, "mac"));
1908
1909                og_cmd_legacy(task->params, cmd);
1910
1911                if (task->procedure_id) {
1912                        if (og_dbi_add_action(dbi, task, cmd)) {
1913                                dbi_result_free(result);
1914                                return -1;
1915                        }
1916                } else {
1917                        cmd->id = task->task_id;
1918                }
1919
1920                list_add_tail(&cmd->list, &cmd_list);
1921        }
1922
1923        dbi_result_free(result);
1924
1925        return 0;
1926}
1927
1928static int og_queue_task_group_clients(struct og_dbi *dbi, struct og_task *task,
1929                                       char *query)
1930{
1931
1932        const char *msglog;
1933        dbi_result result;
1934
1935        result = dbi_conn_queryf(dbi->conn, query);
1936        if (!result) {
1937                dbi_conn_error(dbi->conn, &msglog);
1938                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1939                       __func__, __LINE__, msglog);
1940                return -1;
1941        }
1942
1943        while (dbi_result_next_row(result)) {
1944                uint32_t group_id = dbi_result_get_uint(result, "idgrupo");
1945
1946                sprintf(query, "SELECT idgrupo FROM gruposordenadores "
1947                                "WHERE grupoid=%d", group_id);
1948                if (og_queue_task_group_clients(dbi, task, query)) {
1949                        dbi_result_free(result);
1950                        return -1;
1951                }
1952
1953                sprintf(query,"SELECT ip, mac, idordenador FROM ordenadores "
1954                              "WHERE grupoid=%d", group_id);
1955                if (og_queue_task_command(dbi, task, query)) {
1956                        dbi_result_free(result);
1957                        return -1;
1958                }
1959
1960        }
1961
1962        dbi_result_free(result);
1963
1964        return 0;
1965}
1966
1967static int og_queue_task_group_classrooms(struct og_dbi *dbi,
1968                                          struct og_task *task, char *query)
1969{
1970
1971        const char *msglog;
1972        dbi_result result;
1973
1974        result = dbi_conn_queryf(dbi->conn, query);
1975        if (!result) {
1976                dbi_conn_error(dbi->conn, &msglog);
1977                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1978                       __func__, __LINE__, msglog);
1979                return -1;
1980        }
1981
1982        while (dbi_result_next_row(result)) {
1983                uint32_t group_id = dbi_result_get_uint(result, "idgrupo");
1984
1985                sprintf(query, "SELECT idgrupo FROM grupos "
1986                                "WHERE grupoid=%d AND tipo=%d", group_id, AMBITO_GRUPOSAULAS);
1987                if (og_queue_task_group_classrooms(dbi, task, query)) {
1988                        dbi_result_free(result);
1989                        return -1;
1990                }
1991
1992                sprintf(query,
1993                        "SELECT ip,mac,idordenador "
1994                        "FROM ordenadores INNER JOIN aulas "
1995                        "WHERE ordenadores.idaula=aulas.idaula "
1996                        "AND aulas.grupoid=%d",
1997                        group_id);
1998                if (og_queue_task_command(dbi, task, query)) {
1999                        dbi_result_free(result);
2000                        return -1;
2001                }
2002
2003        }
2004
2005        dbi_result_free(result);
2006
2007        return 0;
2008}
2009
2010static int og_queue_task_clients(struct og_dbi *dbi, struct og_task *task)
2011{
2012        char query[4096];
2013
2014        switch (task->type_scope) {
2015                case AMBITO_CENTROS:
2016                        sprintf(query,
2017                                "SELECT ip,mac,idordenador "
2018                                "FROM ordenadores INNER JOIN aulas "
2019                                "WHERE ordenadores.idaula=aulas.idaula "
2020                                "AND idcentro=%d",
2021                                task->scope);
2022                        return og_queue_task_command(dbi, task, query);
2023                case AMBITO_GRUPOSAULAS:
2024                        sprintf(query,
2025                                "SELECT idgrupo FROM grupos "
2026                                "WHERE idgrupo=%i AND tipo=%d",
2027                                task->scope, AMBITO_GRUPOSAULAS);
2028                        return og_queue_task_group_classrooms(dbi, task, query);
2029                case AMBITO_AULAS:
2030                        sprintf(query,
2031                                "SELECT ip,mac,idordenador FROM ordenadores "
2032                                "WHERE idaula=%d",
2033                                task->scope);
2034                        return og_queue_task_command(dbi, task, query);
2035                case AMBITO_GRUPOSORDENADORES:
2036                        sprintf(query,
2037                                "SELECT idgrupo FROM gruposordenadores "
2038                                "WHERE idgrupo = %d",
2039                                task->scope);
2040                        return og_queue_task_group_clients(dbi, task, query);
2041                case AMBITO_ORDENADORES:
2042                        sprintf(query,
2043                                "SELECT ip, mac, idordenador FROM ordenadores "
2044                                "WHERE idordenador = %d",
2045                                task->scope);
2046                        return og_queue_task_command(dbi, task, query);
2047        }
2048        return 0;
2049}
2050
2051int og_dbi_queue_procedure(struct og_dbi *dbi, struct og_task *task)
2052{
2053        uint32_t procedure_id;
2054        const char *msglog;
2055        dbi_result result;
2056
2057        result = dbi_conn_queryf(dbi->conn,
2058                        "SELECT parametros, procedimientoid, idcomando "
2059                        "FROM procedimientos_acciones "
2060                        "WHERE idprocedimiento=%d ORDER BY orden", task->procedure_id);
2061        if (!result) {
2062                dbi_conn_error(dbi->conn, &msglog);
2063                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2064                       __func__, __LINE__, msglog);
2065                return -1;
2066        }
2067
2068        while (dbi_result_next_row(result)) {
2069                procedure_id = dbi_result_get_uint(result, "procedimientoid");
2070                if (procedure_id > 0) {
2071                        task->procedure_id = procedure_id;
2072                        if (og_dbi_queue_procedure(dbi, task))
2073                                return -1;
2074                        continue;
2075                }
2076
2077                task->params    = strdup(dbi_result_get_string(result, "parametros"));
2078                task->command_id = dbi_result_get_uint(result, "idcomando");
2079                if (og_queue_task_clients(dbi, task))
2080                        return -1;
2081        }
2082
2083        dbi_result_free(result);
2084
2085        return 0;
2086}
2087
2088static int og_dbi_queue_task(struct og_dbi *dbi, uint32_t task_id,
2089                             uint32_t schedule_id)
2090{
2091        struct og_task task = {};
2092        uint32_t task_id_next;
2093        const char *msglog;
2094        dbi_result result;
2095
2096        task.schedule_id = schedule_id;
2097
2098        result = dbi_conn_queryf(dbi->conn,
2099                        "SELECT tareas_acciones.orden, "
2100                                "tareas_acciones.idprocedimiento, "
2101                                "tareas_acciones.tareaid, "
2102                                "tareas.idtarea, "
2103                                "tareas.idcentro, "
2104                                "tareas.ambito, "
2105                                "tareas.idambito, "
2106                                "tareas.restrambito "
2107                        " FROM tareas"
2108                                " INNER JOIN tareas_acciones ON tareas_acciones.idtarea=tareas.idtarea"
2109                        " WHERE tareas_acciones.idtarea=%u ORDER BY tareas_acciones.orden ASC", task_id);
2110        if (!result) {
2111                dbi_conn_error(dbi->conn, &msglog);
2112                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2113                       __func__, __LINE__, msglog);
2114                return -1;
2115        }
2116
2117        while (dbi_result_next_row(result)) {
2118                task_id_next = dbi_result_get_uint(result, "tareaid");
2119
2120                if (task_id_next > 0) {
2121                        if (og_dbi_queue_task(dbi, task_id_next, schedule_id))
2122                                return -1;
2123
2124                        continue;
2125                }
2126                task.task_id = dbi_result_get_uint(result, "idtarea");
2127                task.center_id = dbi_result_get_uint(result, "idcentro");
2128                task.procedure_id = dbi_result_get_uint(result, "idprocedimiento");
2129                task.type_scope = dbi_result_get_uint(result, "ambito");
2130                task.scope = dbi_result_get_uint(result, "idambito");
2131                task.filtered_scope = dbi_result_get_string(result, "restrambito");
2132
2133                og_dbi_queue_procedure(dbi, &task);
2134        }
2135
2136        dbi_result_free(result);
2137
2138        return 0;
2139}
2140
2141static int og_dbi_queue_command(struct og_dbi *dbi, uint32_t task_id,
2142                                uint32_t schedule_id)
2143{
2144        struct og_task task = {};
2145        const char *msglog;
2146        dbi_result result;
2147        char query[4096];
2148
2149        result = dbi_conn_queryf(dbi->conn,
2150                        "SELECT idaccion, idcentro, idordenador, parametros "
2151                        "FROM acciones "
2152                        "WHERE sesion = %u", task_id);
2153        if (!result) {
2154                dbi_conn_error(dbi->conn, &msglog);
2155                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2156                       __func__, __LINE__, msglog);
2157                return -1;
2158        }
2159
2160        while (dbi_result_next_row(result)) {
2161                task.task_id = dbi_result_get_uint(result, "idaccion");
2162                task.center_id = dbi_result_get_uint(result, "idcentro");
2163                task.scope = dbi_result_get_uint(result, "idordenador");
2164                task.params = strdup(dbi_result_get_string(result, "parametros"));
2165
2166                sprintf(query,
2167                        "SELECT ip, mac, idordenador FROM ordenadores "
2168                        "WHERE idordenador = %d",
2169                        task.scope);
2170                if (og_queue_task_command(dbi, &task, query)) {
2171                        dbi_result_free(result);
2172                        return -1;
2173                }
2174        }
2175
2176        dbi_result_free(result);
2177
2178        return 0;
2179}
2180
2181int og_dbi_update_action(uint32_t id, bool success)
2182{
2183        char end_date_string[24];
2184        struct tm *end_date;
2185        const char *msglog;
2186        struct og_dbi *dbi;
2187        uint8_t status = 2;
2188        dbi_result result;
2189        time_t now;
2190
2191        if (!id)
2192                return 0;
2193
2194        dbi = og_dbi_open(&dbi_config);
2195        if (!dbi) {
2196                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
2197                       __func__, __LINE__);
2198                return -1;
2199        }
2200
2201        time(&now);
2202        end_date = localtime(&now);
2203
2204        sprintf(end_date_string, "%hu/%hhu/%hhu %hhu:%hhu:%hhu",
2205                end_date->tm_year + 1900, end_date->tm_mon + 1,
2206                end_date->tm_mday, end_date->tm_hour, end_date->tm_min,
2207                end_date->tm_sec);
2208        result = dbi_conn_queryf(dbi->conn,
2209                                 "UPDATE acciones SET fechahorafin='%s', "
2210                                 "estado=%d, resultado=%d WHERE idaccion=%d",
2211                                 end_date_string, ACCION_FINALIZADA,
2212                                 status - success, id);
2213
2214        if (!result) {
2215                dbi_conn_error(dbi->conn, &msglog);
2216                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2217                       __func__, __LINE__, msglog);
2218                og_dbi_close(dbi);
2219                return -1;
2220        }
2221        dbi_result_free(result);
2222        og_dbi_close(dbi);
2223
2224        return 0;
2225}
2226
2227void og_schedule_run(unsigned int task_id, unsigned int schedule_id,
2228                     enum og_schedule_type type)
2229{
2230        struct og_msg_params params = {};
2231        bool duplicated = false;
2232        struct og_cmd *cmd, *next;
2233        struct og_dbi *dbi;
2234        unsigned int i;
2235
2236        dbi = og_dbi_open(&dbi_config);
2237        if (!dbi) {
2238                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
2239                       __func__, __LINE__);
2240                return;
2241        }
2242
2243        switch (type) {
2244        case OG_SCHEDULE_TASK:
2245                og_dbi_queue_task(dbi, task_id, schedule_id);
2246                break;
2247        case OG_SCHEDULE_PROCEDURE:
2248        case OG_SCHEDULE_COMMAND:
2249                og_dbi_queue_command(dbi, task_id, schedule_id);
2250                break;
2251        }
2252        og_dbi_close(dbi);
2253
2254        list_for_each_entry(cmd, &cmd_list, list) {
2255                for (i = 0; i < params.ips_array_len; i++) {
2256                        if (!strncmp(cmd->ip, params.ips_array[i],
2257                                     OG_DB_IP_MAXLEN)) {
2258                                duplicated = true;
2259                                break;
2260                        }
2261                }
2262
2263                if (!duplicated)
2264                        params.ips_array[params.ips_array_len++] = cmd->ip;
2265                else
2266                        duplicated = false;
2267        }
2268
2269        list_for_each_entry_safe(cmd, next, &cmd_list, list) {
2270                if (cmd->type != OG_CMD_WOL)
2271                        continue;
2272
2273                if (Levanta((char **)cmd->params.ips_array,
2274                            (char **)cmd->params.mac_array,
2275                            (char **)cmd->params.netmask_array,
2276                            cmd->params.ips_array_len,
2277                            (char *)cmd->params.wol_type))
2278                        og_dbi_update_action(cmd->id, true);
2279
2280                list_del(&cmd->list);
2281                og_cmd_free(cmd);
2282        }
2283
2284        og_send_request(OG_METHOD_GET, OG_CMD_RUN_SCHEDULE, &params, NULL);
2285}
2286
2287static int og_cmd_task_post(json_t *element, struct og_msg_params *params)
2288{
2289        struct og_cmd *cmd;
2290        struct og_dbi *dbi;
2291        const char *key;
2292        json_t *value;
2293        int err;
2294
2295        if (json_typeof(element) != JSON_OBJECT)
2296                return -1;
2297
2298        json_object_foreach(element, key, value) {
2299                if (!strcmp(key, "task")) {
2300                        err = og_json_parse_string(value, &params->task_id);
2301                        params->flags |= OG_REST_PARAM_TASK;
2302                }
2303
2304                if (err < 0)
2305                        break;
2306        }
2307
2308        if (!og_msg_params_validate(params, OG_REST_PARAM_TASK))
2309                return -1;
2310
2311        dbi = og_dbi_open(&dbi_config);
2312        if (!dbi) {
2313                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
2314                           __func__, __LINE__);
2315                return -1;
2316        }
2317
2318        og_schedule_run(atoi(params->task_id), 0, OG_SCHEDULE_TASK);
2319        og_dbi_close(dbi);
2320
2321        list_for_each_entry(cmd, &cmd_list, list)
2322                params->ips_array[params->ips_array_len++] = cmd->ip;
2323
2324        return og_send_request(OG_METHOD_GET, OG_CMD_RUN_SCHEDULE, params,
2325                               NULL);
2326}
2327
2328static int og_dbi_scope_get_computer(struct og_dbi *dbi, json_t *array,
2329                                     uint32_t room_id)
2330{
2331        const char *computer_name, *computer_ip;
2332        uint32_t computer_id;
2333        const char *msglog;
2334        dbi_result result;
2335        json_t *computer;
2336
2337        result = dbi_conn_queryf(dbi->conn,
2338                                 "SELECT idordenador, nombreordenador, ip "
2339                                 "FROM ordenadores WHERE idaula=%d",
2340                                 room_id);
2341        if (!result) {
2342                dbi_conn_error(dbi->conn, &msglog);
2343                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2344                       __func__, __LINE__, msglog);
2345                return -1;
2346        }
2347
2348        while (dbi_result_next_row(result)) {
2349                computer_id = dbi_result_get_uint(result, "idordenador");
2350                computer_name = dbi_result_get_string(result, "nombreordenador");
2351                computer_ip = dbi_result_get_string(result, "ip");
2352
2353                computer = json_object();
2354                if (!computer) {
2355                        dbi_result_free(result);
2356                        return -1;
2357                }
2358
2359                json_object_set_new(computer, "name", json_string(computer_name));
2360                json_object_set_new(computer, "type", json_string("computer"));
2361                json_object_set_new(computer, "id", json_integer(computer_id));
2362                json_object_set_new(computer, "scope", json_array());
2363                json_object_set_new(computer, "ip", json_string(computer_ip));
2364                json_array_append(array, computer);
2365                json_decref(computer);
2366        }
2367        dbi_result_free(result);
2368
2369        return 0;
2370}
2371
2372static int og_dbi_scope_get_room(struct og_dbi *dbi, json_t *array,
2373                                 uint32_t center_id)
2374{
2375        char room_name[OG_DB_ROOM_NAME_MAXLEN + 1] = {};
2376        json_t *room, *room_array;
2377        const char *msglog;
2378        dbi_result result;
2379        uint32_t room_id;
2380
2381        result = dbi_conn_queryf(dbi->conn,
2382                                 "SELECT idaula, nombreaula FROM aulas WHERE "
2383                                 "idcentro=%d",
2384                                 center_id);
2385        if (!result) {
2386                dbi_conn_error(dbi->conn, &msglog);
2387                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2388                       __func__, __LINE__, msglog);
2389                return -1;
2390        }
2391
2392        while (dbi_result_next_row(result)) {
2393                room_id = dbi_result_get_uint(result, "idaula");
2394                strncpy(room_name,
2395                        dbi_result_get_string(result, "nombreaula"),
2396                        OG_DB_CENTER_NAME_MAXLEN);
2397
2398                room = json_object();
2399                if (!room) {
2400                        dbi_result_free(result);
2401                        return -1;
2402                }
2403
2404                json_object_set_new(room, "name", json_string(room_name));
2405                json_object_set_new(room, "type", json_string("room"));
2406                json_object_set_new(room, "id", json_integer(room_id));
2407                json_object_set_new(room, "scope", json_array());
2408                json_array_append(array, room);
2409                json_decref(room);
2410
2411                room_array = json_object_get(room, "scope");
2412                if (!room_array) {
2413                        dbi_result_free(result);
2414                        return -1;
2415                }
2416
2417                if (og_dbi_scope_get_computer(dbi, room_array, room_id)) {
2418                        dbi_result_free(result);
2419                        return -1;
2420                }
2421        }
2422        dbi_result_free(result);
2423
2424        return 0;
2425}
2426
2427static int og_dbi_scope_get(struct og_dbi *dbi, json_t *array)
2428{
2429        char center_name[OG_DB_CENTER_NAME_MAXLEN + 1] = {};
2430        json_t *center, *array_room;
2431        const char *msglog;
2432        uint32_t center_id;
2433        dbi_result result;
2434
2435        result = dbi_conn_queryf(dbi->conn,
2436                                 "SELECT nombrecentro, idcentro FROM centros");
2437        if (!result) {
2438                dbi_conn_error(dbi->conn, &msglog);
2439                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2440                       __func__, __LINE__, msglog);
2441                return -1;
2442        }
2443
2444        while (dbi_result_next_row(result)) {
2445                center_id = dbi_result_get_uint(result, "idcentro");
2446                strncpy(center_name,
2447                        dbi_result_get_string(result, "nombrecentro"),
2448                        OG_DB_CENTER_NAME_MAXLEN);
2449
2450                center = json_object();
2451                if (!center) {
2452                        dbi_result_free(result);
2453                        return -1;
2454                }
2455
2456                array_room = json_array();
2457                if (!array_room) {
2458                        dbi_result_free(result);
2459                        json_decref(center);
2460                        return -1;
2461                }
2462
2463                json_object_set_new(center, "name", json_string(center_name));
2464                json_object_set_new(center, "type", json_string("center"));
2465                json_object_set_new(center, "id", json_integer(center_id));
2466                json_object_set_new(center, "scope", array_room);
2467                json_array_append(array, center);
2468                json_decref(center);
2469
2470                if (og_dbi_scope_get_room(dbi, array_room, center_id)) {
2471                        dbi_result_free(result);
2472                        return -1;
2473                }
2474        }
2475
2476        dbi_result_free(result);
2477
2478        return 0;
2479}
2480
2481static int og_cmd_scope_get(json_t *element, struct og_msg_params *params,
2482                            char *buffer_reply)
2483{
2484        struct og_buffer og_buffer = {
2485                .data = buffer_reply
2486        };
2487        json_t *root, *array;
2488        struct og_dbi *dbi;
2489
2490        root = json_object();
2491        if (!root)
2492                return -1;
2493
2494        array = json_array();
2495        if (!array) {
2496                json_decref(root);
2497                return -1;
2498        }
2499        json_object_set_new(root, "scope", array);
2500
2501        dbi = og_dbi_open(&dbi_config);
2502        if (!dbi) {
2503                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
2504                       __func__, __LINE__);
2505                json_decref(root);
2506                return -1;
2507        }
2508
2509        if (og_dbi_scope_get(dbi, array)) {
2510                og_dbi_close(dbi);
2511                json_decref(root);
2512                return -1;
2513        }
2514
2515        og_dbi_close(dbi);
2516
2517        json_dump_callback(root, og_json_dump_clients, &og_buffer, 0);
2518        json_decref(root);
2519
2520        return 0;
2521}
2522
2523int og_dbi_schedule_get(void)
2524{
2525        uint32_t schedule_id, task_id;
2526        struct og_schedule_time time;
2527        struct og_dbi *dbi;
2528        const char *msglog;
2529        dbi_result result;
2530
2531        dbi = og_dbi_open(&dbi_config);
2532        if (!dbi) {
2533                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
2534                       __func__, __LINE__);
2535                return -1;
2536        }
2537
2538        result = dbi_conn_queryf(dbi->conn,
2539                                 "SELECT idprogramacion, tipoaccion, identificador, "
2540                                 "sesion, annos, meses, diario, dias, semanas, horas, "
2541                                 "ampm, minutos FROM programaciones "
2542                                 "WHERE suspendida = 0");
2543        if (!result) {
2544                dbi_conn_error(dbi->conn, &msglog);
2545                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2546                       __func__, __LINE__, msglog);
2547                og_dbi_close(dbi);
2548                return -1;
2549        }
2550
2551        while (dbi_result_next_row(result)) {
2552                memset(&time, 0, sizeof(time));
2553                schedule_id = dbi_result_get_uint(result, "idprogramacion");
2554                task_id = dbi_result_get_uint(result, "identificador");
2555                time.years = dbi_result_get_uint(result, "annos");
2556                time.months = dbi_result_get_uint(result, "meses");
2557                time.weeks = dbi_result_get_uint(result, "semanas");
2558                time.week_days = dbi_result_get_uint(result, "dias");
2559                time.days = dbi_result_get_uint(result, "diario");
2560                time.hours = dbi_result_get_uint(result, "horas");
2561                time.am_pm = dbi_result_get_uint(result, "ampm");
2562                time.minutes = dbi_result_get_uint(result, "minutos");
2563                time.on_start = true;
2564
2565                og_schedule_create(schedule_id, task_id, OG_SCHEDULE_TASK,
2566                                   &time);
2567        }
2568
2569        dbi_result_free(result);
2570        og_dbi_close(dbi);
2571
2572        return 0;
2573}
2574
2575static int og_dbi_schedule_create(struct og_dbi *dbi,
2576                                  struct og_msg_params *params,
2577                                  uint32_t *schedule_id,
2578                                  enum og_schedule_type schedule_type)
2579{
2580        uint8_t suspended = 0;
2581        uint32_t session = 0;
2582        const char *msglog;
2583        dbi_result result;
2584        uint8_t type;
2585
2586        switch (schedule_type) {
2587        case OG_SCHEDULE_TASK:
2588                type = 3;
2589                break;
2590        case OG_SCHEDULE_PROCEDURE:
2591                type = 2;
2592                break;
2593        case OG_SCHEDULE_COMMAND:
2594                session = atoi(params->task_id);
2595                type = 1;
2596                break;
2597        }
2598
2599        result = dbi_conn_queryf(dbi->conn,
2600                                 "INSERT INTO programaciones (tipoaccion,"
2601                                 " identificador, nombrebloque, annos, meses,"
2602                                 " semanas, dias, diario, horas, ampm, minutos,"
2603                                 " suspendida, sesion) VALUES (%d, %s, '%s',"
2604                                 " %d, %d, %d, %d, %d, %d, %d, %d, %d, %d)",
2605                                 type, params->task_id, params->name,
2606                                 params->time.years, params->time.months,
2607                                 params->time.weeks, params->time.week_days,
2608                                 params->time.days, params->time.hours,
2609                                 params->time.am_pm, params->time.minutes,
2610                                 suspended, session);
2611        if (!result) {
2612                dbi_conn_error(dbi->conn, &msglog);
2613                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2614                       __func__, __LINE__, msglog);
2615                return -1;
2616        }
2617        dbi_result_free(result);
2618
2619        *schedule_id = dbi_conn_sequence_last(dbi->conn, NULL);
2620
2621        return 0;
2622}
2623
2624static int og_dbi_schedule_update(struct og_dbi *dbi,
2625                                  struct og_msg_params *params)
2626{
2627        const char *msglog;
2628        dbi_result result;
2629        uint8_t type = 3;
2630
2631        result = dbi_conn_queryf(dbi->conn,
2632                                 "UPDATE programaciones SET tipoaccion=%d, "
2633                                 "identificador='%s', nombrebloque='%s', "
2634                                 "annos=%d, meses=%d, "
2635                                 "diario=%d, horas=%d, ampm=%d, minutos=%d "
2636                                 "WHERE idprogramacion='%s'",
2637                                 type, params->task_id, params->name,
2638                                 params->time.years, params->time.months,
2639                                 params->time.days, params->time.hours,
2640                                 params->time.am_pm, params->time.minutes,
2641                                 params->id);
2642
2643        if (!result) {
2644                dbi_conn_error(dbi->conn, &msglog);
2645                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2646                       __func__, __LINE__, msglog);
2647                return -1;
2648        }
2649        dbi_result_free(result);
2650
2651        return 0;
2652}
2653
2654static int og_dbi_schedule_delete(struct og_dbi *dbi, uint32_t id)
2655{
2656        const char *msglog;
2657        dbi_result result;
2658
2659        result = dbi_conn_queryf(dbi->conn,
2660                                 "DELETE FROM programaciones WHERE idprogramacion=%d",
2661                                 id);
2662        if (!result) {
2663                dbi_conn_error(dbi->conn, &msglog);
2664                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2665                       __func__, __LINE__, msglog);
2666                return -1;
2667        }
2668        dbi_result_free(result);
2669
2670        return 0;
2671}
2672
2673struct og_db_schedule {
2674        uint32_t                id;
2675        uint32_t                task_id;
2676        const char              *name;
2677        struct og_schedule_time time;
2678        uint32_t                week_days;
2679        uint32_t                weeks;
2680        uint32_t                suspended;
2681        uint32_t                session;
2682};
2683
2684static int og_dbi_schedule_get_json(struct og_dbi *dbi, json_t *root,
2685                                    const char *task_id, const char *schedule_id)
2686{
2687        struct og_db_schedule schedule;
2688        json_t *obj, *array;
2689        const char *msglog;
2690        dbi_result result;
2691        int err = 0;
2692
2693        if (task_id) {
2694                result = dbi_conn_queryf(dbi->conn,
2695                                         "SELECT idprogramacion,"
2696                                         "       identificador, nombrebloque,"
2697                                         "       annos, meses, diario, dias,"
2698                                         "       semanas, horas, ampm,"
2699                                         "       minutos,suspendida, sesion "
2700                                         "FROM programaciones "
2701                                         "WHERE identificador=%d",
2702                                         atoi(task_id));
2703        } else if (schedule_id) {
2704                result = dbi_conn_queryf(dbi->conn,
2705                                         "SELECT idprogramacion,"
2706                                         "       identificador, nombrebloque,"
2707                                         "       annos, meses, diario, dias,"
2708                                         "       semanas, horas, ampm,"
2709                                         "       minutos,suspendida, sesion "
2710                                         "FROM programaciones "
2711                                         "WHERE idprogramacion=%d",
2712                                         atoi(schedule_id));
2713        } else {
2714                result = dbi_conn_queryf(dbi->conn,
2715                                         "SELECT idprogramacion,"
2716                                         "       identificador, nombrebloque,"
2717                                         "       annos, meses, diario, dias,"
2718                                         "       semanas, horas, ampm,"
2719                                         "       minutos,suspendida, sesion "
2720                                         "FROM programaciones");
2721        }
2722
2723        if (!result) {
2724                dbi_conn_error(dbi->conn, &msglog);
2725                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
2726                       __func__, __LINE__, msglog);
2727                return -1;
2728        }
2729
2730        array = json_array();
2731        if (!array)
2732                return -1;
2733
2734        while (dbi_result_next_row(result)) {
2735                schedule.id = dbi_result_get_uint(result, "idprogramacion");
2736                schedule.task_id = dbi_result_get_uint(result, "identificador");
2737                schedule.name = dbi_result_get_string(result, "nombrebloque");
2738                schedule.time.years = dbi_result_get_uint(result, "annos");
2739                schedule.time.months = dbi_result_get_uint(result, "meses");
2740                schedule.time.days = dbi_result_get_uint(result, "diario");
2741                schedule.time.hours = dbi_result_get_uint(result, "horas");
2742                schedule.time.am_pm = dbi_result_get_uint(result, "ampm");
2743                schedule.time.minutes = dbi_result_get_uint(result, "minutos");
2744                schedule.week_days = dbi_result_get_uint(result, "dias");
2745                schedule.weeks = dbi_result_get_uint(result, "semanas");
2746                schedule.suspended = dbi_result_get_uint(result, "suspendida");
2747                schedule.session = dbi_result_get_uint(result, "sesion");
2748
2749                obj = json_object();
2750                if (!obj) {
2751                        err = -1;
2752                        break;
2753                }
2754                json_object_set_new(obj, "id", json_integer(schedule.id));
2755                json_object_set_new(obj, "task", json_integer(schedule.task_id));
2756                json_object_set_new(obj, "name", json_string(schedule.name));
2757                json_object_set_new(obj, "years", json_integer(schedule.time.years));
2758                json_object_set_new(obj, "months", json_integer(schedule.time.months));
2759                json_object_set_new(obj, "days", json_integer(schedule.time.days));
2760                json_object_set_new(obj, "hours", json_integer(schedule.time.hours));
2761                json_object_set_new(obj, "am_pm", json_integer(schedule.time.am_pm));
2762                json_object_set_new(obj, "minutes", json_integer(schedule.time.minutes));
2763                json_object_set_new(obj, "week_days", json_integer(schedule.week_days));
2764                json_object_set_new(obj, "weeks", json_integer(schedule.weeks));
2765                json_object_set_new(obj, "suspended", json_integer(schedule.suspended));
2766                json_object_set_new(obj, "session", json_integer(schedule.session));
2767
2768                json_array_append_new(array, obj);
2769        }
2770
2771        json_object_set_new(root, "schedule", array);
2772
2773        dbi_result_free(result);
2774
2775        return err;
2776}
2777
2778static int og_task_schedule_create(struct og_msg_params *params)
2779{
2780        enum og_schedule_type type;
2781        uint32_t schedule_id;
2782        struct og_dbi *dbi;
2783        int err;
2784
2785        if (!strcmp(params->type, "task"))
2786                type = OG_SCHEDULE_TASK;
2787        else if (!strcmp(params->type, "procedure"))
2788                type = OG_SCHEDULE_PROCEDURE;
2789        else if (!strcmp(params->type, "command"))
2790                type = OG_SCHEDULE_COMMAND;
2791        else
2792                return -1;
2793
2794        dbi = og_dbi_open(&dbi_config);
2795        if (!dbi) {
2796                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
2797                       __func__, __LINE__);
2798                return -1;
2799        }
2800
2801        err = og_dbi_schedule_create(dbi, params, &schedule_id, type);
2802        if (err < 0) {
2803                og_dbi_close(dbi);
2804                return -1;
2805        }
2806        og_schedule_create(schedule_id, atoi(params->task_id), type,
2807                           &params->time);
2808        og_schedule_refresh(og_loop);
2809        og_dbi_close(dbi);
2810
2811        return 0;
2812}
2813
2814static int og_cmd_schedule_create(json_t *element, struct og_msg_params *params)
2815{
2816        const char *key;
2817        json_t *value;
2818        int err;
2819
2820        if (json_typeof(element) != JSON_OBJECT)
2821                return -1;
2822
2823        json_object_foreach(element, key, value) {
2824                if (!strcmp(key, "task")) {
2825                        err = og_json_parse_string(value, &params->task_id);
2826                        params->flags |= OG_REST_PARAM_TASK;
2827                } else if (!strcmp(key, "name")) {
2828                        err = og_json_parse_string(value, &params->name);
2829                        params->flags |= OG_REST_PARAM_NAME;
2830                } else if (!strcmp(key, "when")) {
2831                        err = og_json_parse_time_params(value, params);
2832                } else if (!strcmp(key, "type")) {
2833                        err = og_json_parse_string(value, &params->type);
2834                        params->flags |= OG_REST_PARAM_TYPE;
2835                }
2836
2837                if (err < 0)
2838                        break;
2839        }
2840
2841        if (!og_msg_params_validate(params, OG_REST_PARAM_TASK |
2842                                            OG_REST_PARAM_NAME |
2843                                            OG_REST_PARAM_TIME_YEARS |
2844                                            OG_REST_PARAM_TIME_MONTHS |
2845                                            OG_REST_PARAM_TIME_WEEKS |
2846                                            OG_REST_PARAM_TIME_WEEK_DAYS |
2847                                            OG_REST_PARAM_TIME_DAYS |
2848                                            OG_REST_PARAM_TIME_HOURS |
2849                                            OG_REST_PARAM_TIME_MINUTES |
2850                                            OG_REST_PARAM_TIME_AM_PM |
2851                                            OG_REST_PARAM_TYPE))
2852                return -1;
2853
2854        return og_task_schedule_create(params);
2855}
2856
2857static int og_cmd_schedule_update(json_t *element, struct og_msg_params *params)
2858{
2859        struct og_dbi *dbi;
2860        const char *key;
2861        json_t *value;
2862        int err;
2863
2864        if (json_typeof(element) != JSON_OBJECT)
2865                return -1;
2866
2867        json_object_foreach(element, key, value) {
2868                if (!strcmp(key, "id")) {
2869                        err = og_json_parse_string(value, &params->id);
2870                        params->flags |= OG_REST_PARAM_ID;
2871                } else if (!strcmp(key, "task")) {
2872                        err = og_json_parse_string(value, &params->task_id);
2873                        params->flags |= OG_REST_PARAM_TASK;
2874                } else if (!strcmp(key, "name")) {
2875                        err = og_json_parse_string(value, &params->name);
2876                        params->flags |= OG_REST_PARAM_NAME;
2877                } else if (!strcmp(key, "when"))
2878                        err = og_json_parse_time_params(value, params);
2879
2880                if (err < 0)
2881                        break;
2882        }
2883
2884        if (!og_msg_params_validate(params, OG_REST_PARAM_ID |
2885                                            OG_REST_PARAM_TASK |
2886                                            OG_REST_PARAM_NAME |
2887                                            OG_REST_PARAM_TIME_YEARS |
2888                                            OG_REST_PARAM_TIME_MONTHS |
2889                                            OG_REST_PARAM_TIME_DAYS |
2890                                            OG_REST_PARAM_TIME_HOURS |
2891                                            OG_REST_PARAM_TIME_MINUTES |
2892                                            OG_REST_PARAM_TIME_AM_PM))
2893                return -1;
2894
2895        dbi = og_dbi_open(&dbi_config);
2896        if (!dbi) {
2897                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
2898                           __func__, __LINE__);
2899                return -1;
2900        }
2901
2902        err = og_dbi_schedule_update(dbi, params);
2903        og_dbi_close(dbi);
2904
2905        if (err < 0)
2906                return err;
2907
2908        og_schedule_update(og_loop, atoi(params->id), atoi(params->task_id),
2909                           &params->time);
2910        og_schedule_refresh(og_loop);
2911
2912        return err;
2913}
2914
2915static int og_cmd_schedule_delete(json_t *element, struct og_msg_params *params)
2916{
2917        struct og_dbi *dbi;
2918        const char *key;
2919        json_t *value;
2920        int err;
2921
2922        if (json_typeof(element) != JSON_OBJECT)
2923                return -1;
2924
2925        json_object_foreach(element, key, value) {
2926                if (!strcmp(key, "id")) {
2927                        err = og_json_parse_string(value, &params->id);
2928                        params->flags |= OG_REST_PARAM_ID;
2929                } else {
2930                        return -1;
2931                }
2932
2933                if (err < 0)
2934                        break;
2935        }
2936
2937        if (!og_msg_params_validate(params, OG_REST_PARAM_ID))
2938                return -1;
2939
2940        dbi = og_dbi_open(&dbi_config);
2941        if (!dbi) {
2942                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
2943                           __func__, __LINE__);
2944                return -1;
2945        }
2946
2947        err = og_dbi_schedule_delete(dbi, atoi(params->id));
2948        og_dbi_close(dbi);
2949
2950        og_schedule_delete(og_loop, atoi(params->id));
2951
2952        return err;
2953}
2954
2955static int og_cmd_schedule_get(json_t *element, struct og_msg_params *params,
2956                               char *buffer_reply)
2957{
2958        struct og_buffer og_buffer = {
2959                .data   = buffer_reply,
2960        };
2961        json_t *schedule_root;
2962        struct og_dbi *dbi;
2963        const char *key;
2964        json_t *value;
2965        int err;
2966
2967        if (element) {
2968                if (json_typeof(element) != JSON_OBJECT)
2969                        return -1;
2970
2971                json_object_foreach(element, key, value) {
2972                        if (!strcmp(key, "task")) {
2973                                err = og_json_parse_string(value,
2974                                                           &params->task_id);
2975                        } else if (!strcmp(key, "id")) {
2976                                err = og_json_parse_string(value, &params->id);
2977                        } else {
2978                                return -1;
2979                        }
2980
2981                        if (err < 0)
2982                                break;
2983                }
2984        }
2985
2986        dbi = og_dbi_open(&dbi_config);
2987        if (!dbi) {
2988                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
2989                           __func__, __LINE__);
2990                return -1;
2991        }
2992
2993        schedule_root = json_object();
2994        if (!schedule_root) {
2995                og_dbi_close(dbi);
2996                return -1;
2997        }
2998
2999        err = og_dbi_schedule_get_json(dbi, schedule_root,
3000                                       params->task_id, params->id);
3001        og_dbi_close(dbi);
3002
3003        if (err >= 0)
3004                json_dump_callback(schedule_root, og_json_dump_clients, &og_buffer, 0);
3005
3006        json_decref(schedule_root);
3007
3008        return err;
3009}
3010
3011static int og_client_method_not_found(struct og_client *cli)
3012{
3013        /* To meet RFC 7231, this function MUST generate an Allow header field
3014         * containing the correct methods. For example: "Allow: POST\r\n"
3015         */
3016        char buf[] = "HTTP/1.1 405 Method Not Allowed\r\n"
3017                     "Content-Length: 0\r\n\r\n";
3018
3019        send(og_client_socket(cli), buf, strlen(buf), 0);
3020
3021        return -1;
3022}
3023
3024static int og_client_bad_request(struct og_client *cli)
3025{
3026        char buf[] = "HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\n\r\n";
3027
3028        send(og_client_socket(cli), buf, strlen(buf), 0);
3029
3030        return -1;
3031}
3032
3033static int og_client_not_found(struct og_client *cli)
3034{
3035        char buf[] = "HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n";
3036
3037        send(og_client_socket(cli), buf, strlen(buf), 0);
3038
3039        return -1;
3040}
3041
3042static int og_client_not_authorized(struct og_client *cli)
3043{
3044        char buf[] = "HTTP/1.1 401 Unauthorized\r\n"
3045                     "WWW-Authenticate: Basic\r\n"
3046                     "Content-Length: 0\r\n\r\n";
3047
3048        send(og_client_socket(cli), buf, strlen(buf), 0);
3049
3050        return -1;
3051}
3052
3053static int og_server_internal_error(struct og_client *cli)
3054{
3055        char buf[] = "HTTP/1.1 500 Internal Server Error\r\n"
3056                     "Content-Length: 0\r\n\r\n";
3057
3058        send(og_client_socket(cli), buf, strlen(buf), 0);
3059
3060        return -1;
3061}
3062
3063#define OG_MSG_RESPONSE_MAXLEN  65536
3064
3065static int og_client_ok(struct og_client *cli, char *buf_reply)
3066{
3067        char buf[OG_MSG_RESPONSE_MAXLEN] = {};
3068        int err = 0, len;
3069
3070        len = snprintf(buf, sizeof(buf),
3071                       "HTTP/1.1 200 OK\r\nContent-Length: %ld\r\n\r\n%s",
3072                       strlen(buf_reply), buf_reply);
3073        if (len >= (int)sizeof(buf))
3074                err = og_server_internal_error(cli);
3075
3076        send(og_client_socket(cli), buf, strlen(buf), 0);
3077
3078        return err;
3079}
3080
3081int og_client_state_process_payload_rest(struct og_client *cli)
3082{
3083        char buf_reply[OG_MSG_RESPONSE_MAXLEN] = {};
3084        struct og_msg_params params = {};
3085        enum og_rest_method method;
3086        const char *cmd, *body;
3087        json_error_t json_err;
3088        json_t *root = NULL;
3089        int err = 0;
3090
3091        syslog(LOG_DEBUG, "%s:%hu %.32s ...\n",
3092               inet_ntoa(cli->addr.sin_addr),
3093               ntohs(cli->addr.sin_port), cli->buf);
3094
3095        if (!strncmp(cli->buf, "GET", strlen("GET"))) {
3096                method = OG_METHOD_GET;
3097                cmd = cli->buf + strlen("GET") + 2;
3098        } else if (!strncmp(cli->buf, "POST", strlen("POST"))) {
3099                method = OG_METHOD_POST;
3100                cmd = cli->buf + strlen("POST") + 2;
3101        } else
3102                return og_client_method_not_found(cli);
3103
3104        body = strstr(cli->buf, "\r\n\r\n") + 4;
3105
3106        if (strcmp(cli->auth_token, auth_token)) {
3107                syslog(LOG_ERR, "wrong Authentication key\n");
3108                return og_client_not_authorized(cli);
3109        }
3110
3111        if (cli->content_length) {
3112                root = json_loads(body, 0, &json_err);
3113                if (!root) {
3114                        syslog(LOG_ERR, "malformed json line %d: %s\n",
3115                               json_err.line, json_err.text);
3116                        return og_client_not_found(cli);
3117                }
3118        }
3119
3120        if (!strncmp(cmd, "clients", strlen("clients"))) {
3121                if (method != OG_METHOD_POST &&
3122                    method != OG_METHOD_GET)
3123                        return og_client_method_not_found(cli);
3124
3125                if (method == OG_METHOD_POST && !root) {
3126                        syslog(LOG_ERR, "command clients with no payload\n");
3127                        return og_client_bad_request(cli);
3128                }
3129                switch (method) {
3130                case OG_METHOD_POST:
3131                        err = og_cmd_post_clients(root, &params);
3132                        break;
3133                case OG_METHOD_GET:
3134                        err = og_cmd_get_clients(root, &params, buf_reply);
3135                        break;
3136                default:
3137                        return og_client_bad_request(cli);
3138                }
3139        } else if (!strncmp(cmd, "client/setup",
3140                            strlen("client/setup"))) {
3141                if (method != OG_METHOD_GET)
3142                        return og_client_method_not_found(cli);
3143
3144                if (!root) {
3145                        syslog(LOG_ERR,
3146                               "command client partitions with no payload\n");
3147                        return og_client_bad_request(cli);
3148                }
3149
3150                err = og_cmd_get_client_setup(root, &params, buf_reply);
3151        } else if (!strncmp(cmd, "wol", strlen("wol"))) {
3152                if (method != OG_METHOD_POST)
3153                        return og_client_method_not_found(cli);
3154
3155                if (!root) {
3156                        syslog(LOG_ERR, "command wol with no payload\n");
3157                        return og_client_bad_request(cli);
3158                }
3159                err = og_cmd_wol(root, &params);
3160        } else if (!strncmp(cmd, "shell/run", strlen("shell/run"))) {
3161                if (method != OG_METHOD_POST)
3162                        return og_client_method_not_found(cli);
3163
3164                if (!root) {
3165                        syslog(LOG_ERR, "command run with no payload\n");
3166                        return og_client_bad_request(cli);
3167                }
3168                err = og_cmd_run_post(root, &params);
3169        } else if (!strncmp(cmd, "shell/output", strlen("shell/output"))) {
3170                if (method != OG_METHOD_POST)
3171                        return og_client_method_not_found(cli);
3172
3173                if (!root) {
3174                        syslog(LOG_ERR, "command output with no payload\n");
3175                        return og_client_bad_request(cli);
3176                }
3177
3178                err = og_cmd_run_get(root, &params, buf_reply);
3179        } else if (!strncmp(cmd, "session", strlen("session"))) {
3180                if (method != OG_METHOD_POST)
3181                        return og_client_method_not_found(cli);
3182
3183                if (!root) {
3184                        syslog(LOG_ERR, "command session with no payload\n");
3185                        return og_client_bad_request(cli);
3186                }
3187                err = og_cmd_session(root, &params);
3188        } else if (!strncmp(cmd, "scopes", strlen("scopes"))) {
3189                if (method != OG_METHOD_GET)
3190                        return og_client_method_not_found(cli);
3191
3192                err = og_cmd_scope_get(root, &params, buf_reply);
3193        } else if (!strncmp(cmd, "poweroff", strlen("poweroff"))) {
3194                if (method != OG_METHOD_POST)
3195                        return og_client_method_not_found(cli);
3196
3197                if (!root) {
3198                        syslog(LOG_ERR, "command poweroff with no payload\n");
3199                        return og_client_bad_request(cli);
3200                }
3201                err = og_cmd_poweroff(root, &params);
3202        } else if (!strncmp(cmd, "reboot", strlen("reboot"))) {
3203                if (method != OG_METHOD_POST)
3204                        return og_client_method_not_found(cli);
3205
3206                if (!root) {
3207                        syslog(LOG_ERR, "command reboot with no payload\n");
3208                        return og_client_bad_request(cli);
3209                }
3210                err = og_cmd_reboot(root, &params);
3211        } else if (!strncmp(cmd, "mode", strlen("mode"))) {
3212                if (method != OG_METHOD_GET && method != OG_METHOD_POST)
3213                        return og_client_method_not_found(cli);
3214
3215                if (method == OG_METHOD_POST && !root) {
3216                        syslog(LOG_ERR, "command mode with no payload\n");
3217                        return og_client_bad_request(cli);
3218                }
3219
3220                if (method == OG_METHOD_GET)
3221                        err = og_cmd_get_modes(root, &params, buf_reply);
3222                else if (method == OG_METHOD_POST)
3223                        err = og_cmd_post_modes(root, &params);
3224        } else if (!strncmp(cmd, "stop", strlen("stop"))) {
3225                if (method != OG_METHOD_POST)
3226                        return og_client_method_not_found(cli);
3227
3228                if (!root) {
3229                        syslog(LOG_ERR, "command stop with no payload\n");
3230                        return og_client_bad_request(cli);
3231                }
3232                err = og_cmd_stop(root, &params);
3233        } else if (!strncmp(cmd, "refresh", strlen("refresh"))) {
3234                if (method != OG_METHOD_POST)
3235                        return og_client_method_not_found(cli);
3236
3237                if (!root) {
3238                        syslog(LOG_ERR, "command refresh with no payload\n");
3239                        return og_client_bad_request(cli);
3240                }
3241                err = og_cmd_refresh(root, &params);
3242        } else if (!strncmp(cmd, "hardware", strlen("hardware"))) {
3243                if (method != OG_METHOD_GET && method != OG_METHOD_POST)
3244                        return og_client_method_not_found(cli);
3245
3246                if (!root) {
3247                        syslog(LOG_ERR, "command hardware with no payload\n");
3248                        return og_client_bad_request(cli);
3249                }
3250
3251                if (method == OG_METHOD_GET)
3252                        err = og_cmd_get_hardware(root, &params, buf_reply);
3253                else if (method == OG_METHOD_POST)
3254                        err = og_cmd_hardware(root, &params);
3255        } else if (!strncmp(cmd, "software", strlen("software"))) {
3256                if (method != OG_METHOD_POST)
3257                        return og_client_method_not_found(cli);
3258
3259                if (!root) {
3260                        syslog(LOG_ERR, "command software with no payload\n");
3261                        return og_client_bad_request(cli);
3262                }
3263                err = og_cmd_software(root, &params);
3264        } else if (!strncmp(cmd, "image/create", strlen("image/create"))) {
3265                if (method != OG_METHOD_POST)
3266                        return og_client_method_not_found(cli);
3267
3268                if (!root) {
3269                        syslog(LOG_ERR, "command create with no payload\n");
3270                        return og_client_bad_request(cli);
3271                }
3272                err = og_cmd_create_image(root, &params);
3273        } else if (!strncmp(cmd, "image/restore", strlen("image/restore"))) {
3274                if (method != OG_METHOD_POST)
3275                        return og_client_method_not_found(cli);
3276
3277                if (!root) {
3278                        syslog(LOG_ERR, "command create with no payload\n");
3279                        return og_client_bad_request(cli);
3280                }
3281                err = og_cmd_restore_image(root, &params);
3282        } else if (!strncmp(cmd, "setup", strlen("setup"))) {
3283                if (method != OG_METHOD_POST)
3284                        return og_client_method_not_found(cli);
3285
3286                if (!root) {
3287                        syslog(LOG_ERR, "command create with no payload\n");
3288                        return og_client_bad_request(cli);
3289                }
3290                err = og_cmd_setup(root, &params);
3291        } else if (!strncmp(cmd, "run/schedule", strlen("run/schedule"))) {
3292                if (method != OG_METHOD_POST)
3293                        return og_client_method_not_found(cli);
3294
3295                if (!root) {
3296                        syslog(LOG_ERR, "command create with no payload\n");
3297                        return og_client_bad_request(cli);
3298                }
3299
3300                err = og_cmd_run_schedule(root, &params);
3301        } else if (!strncmp(cmd, "task/run", strlen("task/run"))) {
3302                if (method != OG_METHOD_POST)
3303                        return og_client_method_not_found(cli);
3304
3305                if (!root) {
3306                        syslog(LOG_ERR, "command task with no payload\n");
3307                        return og_client_bad_request(cli);
3308                }
3309                err = og_cmd_task_post(root, &params);
3310        } else if (!strncmp(cmd, "schedule/create",
3311                            strlen("schedule/create"))) {
3312                if (method != OG_METHOD_POST)
3313                        return og_client_method_not_found(cli);
3314
3315                if (!root) {
3316                        syslog(LOG_ERR, "command task with no payload\n");
3317                        return og_client_bad_request(cli);
3318                }
3319                err = og_cmd_schedule_create(root, &params);
3320        } else if (!strncmp(cmd, "schedule/delete",
3321                            strlen("schedule/delete"))) {
3322                if (method != OG_METHOD_POST)
3323                        return og_client_method_not_found(cli);
3324
3325                if (!root) {
3326                        syslog(LOG_ERR, "command task with no payload\n");
3327                        return og_client_bad_request(cli);
3328                }
3329                err = og_cmd_schedule_delete(root, &params);
3330        } else if (!strncmp(cmd, "schedule/update",
3331                            strlen("schedule/update"))) {
3332                if (method != OG_METHOD_POST)
3333                        return og_client_method_not_found(cli);
3334
3335                if (!root) {
3336                        syslog(LOG_ERR, "command task with no payload\n");
3337                        return og_client_bad_request(cli);
3338                }
3339                err = og_cmd_schedule_update(root, &params);
3340        } else if (!strncmp(cmd, "schedule/get",
3341                            strlen("schedule/get"))) {
3342                if (method != OG_METHOD_POST)
3343                        return og_client_method_not_found(cli);
3344
3345                err = og_cmd_schedule_get(root, &params, buf_reply);
3346        } else {
3347                syslog(LOG_ERR, "unknown command: %.32s ...\n", cmd);
3348                err = og_client_not_found(cli);
3349        }
3350
3351        if (root)
3352                json_decref(root);
3353
3354        if (err < 0)
3355                return og_client_bad_request(cli);
3356
3357        err = og_client_ok(cli, buf_reply);
3358        if (err < 0) {
3359                syslog(LOG_ERR, "HTTP response to %s:%hu is too large\n",
3360                       inet_ntoa(cli->addr.sin_addr),
3361                       ntohs(cli->addr.sin_port));
3362        }
3363
3364        return err;
3365}
Note: See TracBrowser for help on using the repository browser.