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

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

#942 Create DB image when calling POST /image/create

In case the DB entry for an image does not exist when POST /image/create
is called, this patch takes care of calling it.

This adds few optional json parameters to the POST /image/create API. If
optional parameters are included then this patch creates the DB entry,
otherwise it just creates the actual image and updates the existing
entry.

Request:
POST /image/create
{

"clients":192.168.56.11?,
"disk":"1",
"partition":"1",
"name":"archlinux",
"repository":"192.168.56.10",
"id":"24",
"code":"131",
"description":"This is a test",
"group_id":0,
"center_id":1

}
Response:
200 OK

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