source: ogServer-Git/src/rest.c @ 1f13855

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

#1043 add WOL_SENT state

WOL_SENT tells that WakeOnLan? was sent to computer, after 60 seconds,
if computer does not boot, this state is released.

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