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

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

ogServer is AGPLv3+

Update license header in files.

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