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

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

#1010 Fix /software missing body in queued mode

ogServer do not send /software parameters to ogClient in queued mode.

Add parameters as JSON body.

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