source: ogServer-Git/src/rest.c @ 4ae9903

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

#980 Select POST /mode clients by ip instead of scope name

This patch selects clients whose modes need to be changed in the current
request. This patch makes POST /mode consistent with the rest of the
REST API where clients are selected and filtered by ip.

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