source: ogServer-Git/src/rest.c @ 3b1f2c2

Last change on this file since 3b1f2c2 was 29e7641, checked in by OpenGnSys Support Team <soporte-og@…>, 3 years ago

#915 Add /room/add POST method

Adds POST method to add rooms (labs), required payload parameters are
name, netmask and center; any additional attributes are optional.

Required JSON:

{ "center": 0,

"name": "classroom10",
"netmask": "255.255.255.0" }

Full JSON:

{ "center": 0,

"name": "classroom11",
"netmask": "255.255.255.0",
"group": 0,
"location": "First floor",
"gateway": "192.168.56.1",
"ntp": "hora.cica.es",
"dns": "1.1.1.1",
"remote": True }

This commit also adds unit tests for /room/add POST method.

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