tizen 2.3.1 release
[external/buxton.git] / src / shared / direct.c
1 /*
2  * This file is part of buxton.
3  *
4  * Copyright (C) 2013 Intel Corporation
5  *
6  * buxton is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as
8  * published by the Free Software Foundation; either version 2.1
9  * of the License, or (at your option) any later version.
10  */
11
12 #ifdef HAVE_CONFIG_H
13         #include "config.h"
14 #endif
15
16 #include <errno.h>
17 #include <string.h>
18 #include <stdlib.h>
19
20 #include "direct.h"
21 #include "log.h"
22 #include "smack.h"
23 #include "util.h"
24
25 #define BUXTON_ROOT_CHECK_ENV "BUXTON_ROOT_CHECK"
26
27 bool buxton_direct_open(BuxtonControl *control)
28 {
29
30         assert(control);
31
32         memzero(&(control->config), sizeof(BuxtonConfig));
33         buxton_init_layers(&(control->config));
34
35         control->client.direct = true;
36         control->client.pid = getpid();
37
38         return true;
39 }
40
41 int32_t buxton_direct_get_value(BuxtonControl *control, _BuxtonKey *key,
42                              BuxtonData *data, BuxtonString *data_label,
43                              BuxtonString *client_label)
44 {
45         /* Handle direct manipulation */
46         BuxtonLayer *l;
47         BuxtonConfig *config;
48         BuxtonString layer = (BuxtonString){ NULL, 0 };
49         Iterator i;
50         BuxtonData d;
51         int priority = 0;
52         int32_t ret;
53         BuxtonLayerType layer_origin = -1;
54
55         assert(control);
56         assert(key);
57
58         if (key->layer.value) {
59                 ret = (int32_t)buxton_direct_get_value_for_layer(control, key, data,
60                                                       data_label,
61                                                       client_label);
62                 return ret;
63         }
64
65         config = &control->config;
66
67         HASHMAP_FOREACH(l, config->layers, i) {
68                 key->layer.value = l->name.value;
69                 key->layer.length = l->name.length;
70                 ret = (int32_t)buxton_direct_get_value_for_layer(control,
71                                                       key,
72                                                       &d,
73                                                       data_label,
74                                                       client_label);
75                 if (!ret) {
76                         free(data_label->value);
77                         data_label->value = NULL;
78                         data_label->length = 0;
79                         if (d.type == STRING) {
80                                 free(d.store.d_string.value);
81                         }
82
83                         if ((l->type == LAYER_SYSTEM && (layer_origin != LAYER_SYSTEM ||
84                                                          priority <= l->priority)) ||
85                             (l->type == LAYER_USER && layer_origin != LAYER_SYSTEM &&
86                              priority <= l->priority)) {
87                                 if (l->type == LAYER_SYSTEM) {
88                                         layer_origin = LAYER_SYSTEM;
89                                 } else {
90                                         layer_origin = LAYER_USER;
91                                 }
92                                 priority = l->priority;
93                                 layer.value = l->name.value;
94                                 layer.length = l->name.length;
95                         }
96                 }
97         }
98         if (layer.value) {
99                 key->layer.value = layer.value;
100                 key->layer.length = layer.length;
101                 ret = (int32_t)buxton_direct_get_value_for_layer(control,
102                                                       key,
103                                                       data,
104                                                       data_label,
105                                                       client_label);
106                 key->layer.value = NULL;
107                 key->layer.length = 0;
108
109                 return ret;
110         }
111         return ENOENT;
112 }
113
114 int buxton_direct_get_value_for_layer(BuxtonControl *control,
115                                        _BuxtonKey *key,
116                                        BuxtonData *data,
117                                        BuxtonString *data_label,
118                                        BuxtonString *client_label)
119 {
120         /* Handle direct manipulation */
121         BuxtonBackend *backend = NULL;
122         BuxtonLayer *layer = NULL;
123         BuxtonConfig *config;
124         BuxtonData g;
125         _BuxtonKey group;
126         BuxtonString group_label;
127         int ret;
128
129         assert(control);
130         assert(key);
131         assert(data_label);
132
133         buxton_debug("get_value '%s:%s' for layer '%s' start\n",
134                      key->group.value, key->name.value, key->layer.value);
135
136         memzero(&g, sizeof(BuxtonData));
137         memzero(&group, sizeof(_BuxtonKey));
138         memzero(&group_label, sizeof(BuxtonString));
139
140         if (!key->layer.value) {
141                 ret = EINVAL;
142                 goto fail;
143         }
144
145         config = &control->config;
146         if ((layer = hashmap_get(config->layers, key->layer.value)) == NULL) {
147                 ret = EINVAL;
148                 goto fail;
149         }
150         backend = backend_for_layer(config, layer);
151         assert(backend);
152
153         layer->uid = control->client.uid;
154
155         /* Groups must be created first, so bail if this key's group doesn't exist */
156         if (key->name.value) {
157                 if (!buxton_copy_key_group(key, &group)) {
158                         abort();
159                 }
160                 ret = buxton_direct_get_value_for_layer(control, &group, &g, &group_label, NULL);
161                 if (ret) {
162                         buxton_debug("Group %s for name %s missing for get value\n", key->group.value, key->name.value);
163                         goto fail;
164                 }
165         }
166
167         /* The group checks are only needed for key lookups, or we recurse endlessly */
168         if (key->name.value && client_label) {
169                 if (!buxton_check_smack_access(client_label, &group_label, ACCESS_READ)) {
170                         ret = EPERM;
171                         goto fail;
172                 }
173         }
174
175         ret = backend->get_value(layer, key, data, data_label);
176         if (!ret) {
177                 /* Access checks are not needed for direct clients, where client_label is NULL */
178                 if (data_label->value && client_label && client_label->value &&
179                     !buxton_check_smack_access(client_label, data_label, ACCESS_READ)) {
180                         /* Client lacks permission to read the value */
181                         free(data_label->value);
182                         ret = EPERM;
183                         goto fail;
184                 }
185         }
186
187 fail:
188         free(g.store.d_string.value);
189         free(group.group.value);
190         free(group.name.value);
191         free(group.layer.value);
192         free(group_label.value);
193         buxton_debug("get_value '%s:%s' for layer '%s' end\n",
194                      key->group.value, key->name.value, key->layer.value);
195         return ret;
196 }
197
198 bool buxton_direct_set_value(BuxtonControl *control,
199                              _BuxtonKey *key,
200                              BuxtonData *data,
201                              BuxtonString *label)
202 {
203         BuxtonBackend *backend;
204         BuxtonLayer *layer;
205         BuxtonConfig *config;
206         BuxtonString default_label = buxton_string_pack("_");
207         BuxtonString *l;
208         _cleanup_buxton_data_ BuxtonData *d = NULL;
209         _cleanup_buxton_data_ BuxtonData *g = NULL;
210         _cleanup_buxton_key_ _BuxtonKey *group = NULL;
211         _cleanup_buxton_string_ BuxtonString *data_label = NULL;
212         _cleanup_buxton_string_ BuxtonString *group_label = NULL;
213         bool r = false;
214         int ret;
215
216         assert(control);
217         assert(key);
218         assert(data);
219
220         buxton_debug("set_value start\n");
221
222         group = malloc0(sizeof(_BuxtonKey));
223         if (!group) {
224                 abort();
225         }
226         g = malloc0(sizeof(BuxtonData));
227         if (!g) {
228                 abort();
229         }
230         group_label = malloc0(sizeof(BuxtonString));
231         if (!group_label) {
232                 abort();
233         }
234
235         d = malloc0(sizeof(BuxtonData));
236         if (!d) {
237                 abort();
238         }
239         data_label = malloc0(sizeof(BuxtonString));
240         if (!data_label) {
241                 abort();
242         }
243
244         /* Groups must be created first, so bail if this key's group doesn't exist */
245         if (!buxton_copy_key_group(key, group)) {
246                 abort();
247         }
248
249         ret = buxton_direct_get_value_for_layer(control, group, g, group_label, NULL);
250         if (ret) {
251                 buxton_debug("Error(%d): %s\n", ret, strerror(ret));
252                 buxton_debug("Group %s for name %s missing for set value\n", key->group.value, key->name.value);
253                 goto fail;
254         }
255
256         /* Access checks are not needed for direct clients, where label is NULL */
257         if (label) {
258                 if (!buxton_check_smack_access(label, group_label, ACCESS_WRITE)) {
259                         goto fail;
260                 }
261
262                 ret = buxton_direct_get_value_for_layer(control, key, d, data_label, NULL);
263                 if (ret == -ENOENT || ret == EINVAL) {
264                         goto fail;
265                 }
266                 if (!ret) {
267                         if (!buxton_check_smack_access(label, data_label, ACCESS_WRITE)) {
268                                 goto fail;
269                         }
270                         l = data_label;
271                 } else {
272                         l = label;
273                 }
274         } else {
275                 ret = buxton_direct_get_value_for_layer(control, key, d, data_label, NULL);
276                 if (ret == -ENOENT || ret == EINVAL) {
277                         goto fail;
278                 } else if (!ret) {
279                         l = data_label;
280                 } else {
281                         l = &default_label;
282                 }
283         }
284
285         config = &control->config;
286         if ((layer = hashmap_get(config->layers, key->layer.value)) == NULL) {
287                 goto fail;
288         }
289
290         if (layer->readonly) {
291                 buxton_debug("Read-only layer!\n");
292                 goto fail;
293         }
294
295         backend = backend_for_layer(config, layer);
296         assert(backend);
297
298         layer->uid = control->client.uid;
299         ret = backend->set_value(layer, key, data, l);
300         if (ret) {
301                 buxton_debug("set value failed: %s\n", strerror(ret));
302         } else {
303                 r = true;
304         }
305
306 fail:
307         buxton_debug("set_value end\n");
308         return r;
309 }
310
311 bool buxton_direct_set_label(BuxtonControl *control,
312                              _BuxtonKey *key,
313                              BuxtonString *label)
314 {
315         BuxtonBackend *backend;
316         BuxtonLayer *layer;
317         BuxtonConfig *config;
318         bool r = false;
319         int ret;
320
321         assert(control);
322         assert(key);
323         assert(label);
324
325         config = &control->config;
326
327         if ((layer = hashmap_get(config->layers, key->layer.value)) == NULL) {
328                 goto fail;
329         }
330
331         if (layer->readonly) {
332                 buxton_debug("Read-only layer!\n");
333                 goto fail;
334         }
335
336         if (layer->type == LAYER_SYSTEM) {
337                 char *root_check = getenv(BUXTON_ROOT_CHECK_ENV);
338                 bool skip_check = (root_check && streq(root_check, "0"));
339
340                 /* FIXME: should check client's capability set instead of UID */
341                 if (control->client.uid != 0 && !skip_check) {
342                         buxton_debug("Not permitted to create group '%s'\n", key->group.value);
343                         goto fail;
344                 }
345         } else {
346                 buxton_debug("Cannot set labels in a user layer\n");
347                 goto fail;
348         }
349
350         backend = backend_for_layer(config, layer);
351         assert(backend);
352
353         layer->uid = control->client.uid;
354         ret = backend->set_value(layer, key, NULL, label);
355         if (ret) {
356                 buxton_debug("set label failed: %s\n", strerror(ret));
357         } else {
358                 r = true;
359         }
360
361 fail:
362         return r;
363 }
364
365 bool buxton_direct_create_group(BuxtonControl *control,
366                                 _BuxtonKey *key,
367                                 BuxtonString *label)
368 {
369         BuxtonBackend *backend;
370         BuxtonLayer *layer;
371         BuxtonConfig *config;
372         BuxtonString s, l;
373         _cleanup_buxton_data_ BuxtonData *data = NULL;
374         _cleanup_buxton_data_ BuxtonData *group = NULL;
375         _cleanup_buxton_string_ BuxtonString *dlabel = NULL;
376         _cleanup_buxton_string_ BuxtonString *glabel = NULL;
377         bool r = false;
378         int ret;
379
380         assert(control);
381         assert(key);
382
383         data = malloc0(sizeof(BuxtonData));
384         if (!data) {
385                 abort();
386         }
387         group = malloc0(sizeof(BuxtonData));
388         if (!group) {
389                 abort();
390         }
391         dlabel = malloc0(sizeof(BuxtonString));
392         if (!dlabel) {
393                 abort();
394         }
395         glabel = malloc0(sizeof(BuxtonString));
396         if (!glabel) {
397                 abort();
398         }
399
400         config = &control->config;
401
402         if ((layer = hashmap_get(config->layers, key->layer.value)) == NULL) {
403                 goto fail;
404         }
405
406         if (layer->readonly) {
407                 buxton_debug("Read-only layer!\n");
408                 goto fail;
409         }
410
411         if (layer->type == LAYER_SYSTEM) {
412                 char *root_check = getenv(BUXTON_ROOT_CHECK_ENV);
413                 bool skip_check = (root_check && streq(root_check, "0"));
414
415                 /* FIXME: should check client's capability set instead of UID */
416                 if (control->client.uid != 0 && !skip_check) {
417                         buxton_debug("Not permitted to create group '%s'\n", key->group.value);
418                         goto fail;
419                 }
420         }
421
422         if (buxton_direct_get_value_for_layer(control, key, group, glabel, NULL) != ENOENT) {
423                 buxton_debug("Group '%s' already exists\n", key->group.value);
424                 goto fail;
425         }
426
427         backend = backend_for_layer(config, layer);
428         assert(backend);
429
430         /* Since groups don't have a value, we create a dummy value */
431         data->type = STRING;
432         s = buxton_string_pack("BUXTON_GROUP_VALUE");
433         if (!buxton_string_copy(&s, &data->store.d_string)) {
434                 abort();
435         }
436
437         if (label) {
438                 if (!buxton_string_copy(label, dlabel)) {
439                         abort();
440                 }
441         } else {
442                 /* _ (floor) is our current default label */
443                 l = buxton_string_pack("_");
444                 if (!buxton_string_copy(&l, dlabel)) {
445                         abort();
446                 }
447         }
448
449         layer->uid = control->client.uid;
450         ret = backend->set_value(layer, key, data, dlabel);
451         if (ret) {
452                 buxton_debug("create group failed: %s\n", strerror(ret));
453         } else {
454                 r = true;
455         }
456
457 fail:
458         return r;
459 }
460
461 bool buxton_direct_remove_group(BuxtonControl *control,
462                                 _BuxtonKey *key,
463                                 BuxtonString *client_label)
464 {
465         BuxtonBackend *backend;
466         BuxtonLayer *layer;
467         BuxtonConfig *config;
468         _cleanup_buxton_data_ BuxtonData *group = NULL;
469         _cleanup_buxton_string_ BuxtonString *glabel = NULL;
470         bool r = false;
471         int ret;
472
473         assert(control);
474         assert(key);
475
476         group = malloc0(sizeof(BuxtonData));
477         if (!group) {
478                 abort();
479         }
480         glabel = malloc0(sizeof(BuxtonString));
481         if (!glabel) {
482                 abort();
483         }
484
485         config = &control->config;
486
487         if ((layer = hashmap_get(config->layers, key->layer.value)) == NULL) {
488                 goto fail;
489         }
490
491         if (layer->readonly) {
492                 buxton_debug("Read-ony layer!\n");
493                 goto fail;
494         }
495
496         if (layer->type == LAYER_SYSTEM) {
497                 char *root_check = getenv(BUXTON_ROOT_CHECK_ENV);
498                 bool skip_check = (root_check && streq(root_check, "0"));
499
500                 /* FIXME: should check client's capability set instead of UID */
501                 if (control->client.uid != 0 && !skip_check) {
502                         buxton_debug("Not permitted to remove group '%s'\n", key->group.value);
503                         goto fail;
504                 }
505         }
506
507         if (buxton_direct_get_value_for_layer(control, key, group, glabel, NULL)) {
508                 buxton_debug("Group '%s' doesn't exist\n", key->group.value);
509                 goto fail;
510         }
511
512         if (layer->type == LAYER_USER) {
513                 if (client_label && !buxton_check_smack_access(client_label, glabel, ACCESS_WRITE)) {
514                         goto fail;
515                 }
516         }
517
518         backend = backend_for_layer(config, layer);
519         assert(backend);
520
521         layer->uid = control->client.uid;
522
523         ret = backend->unset_value(layer, key, NULL, NULL);
524         if (ret) {
525                 buxton_debug("remove group failed: %s\n", strerror(ret));
526         } else {
527                 r = true;
528         }
529
530 fail:
531         return r;
532 }
533
534 bool buxton_direct_list_keys(BuxtonControl *control,
535                              BuxtonString *layer_name,
536                              BuxtonArray **list)
537 {
538         assert(control);
539         assert(layer_name);
540
541         /* Handle direct manipulation */
542         BuxtonBackend *backend = NULL;
543         BuxtonLayer *layer;
544         BuxtonConfig *config;
545
546         config = &control->config;
547         if ((layer = hashmap_get(config->layers, layer_name->value)) == NULL) {
548                 return false;
549         }
550         backend = backend_for_layer(config, layer);
551         assert(backend);
552
553         layer->uid = control->client.uid;
554         return backend->list_keys(layer, list);
555 }
556
557 bool buxton_direct_unset_value(BuxtonControl *control,
558                                _BuxtonKey *key,
559                                BuxtonString *label)
560 {
561         BuxtonBackend *backend;
562         BuxtonLayer *layer;
563         BuxtonConfig *config;
564         _cleanup_buxton_string_ BuxtonString *data_label = NULL;
565         _cleanup_buxton_string_ BuxtonString *group_label = NULL;
566         _cleanup_buxton_data_ BuxtonData *d = NULL;
567         _cleanup_buxton_data_ BuxtonData *g = NULL;
568         _cleanup_buxton_key_ _BuxtonKey *group = NULL;
569         int ret;
570         bool r = false;
571
572         assert(control);
573         assert(key);
574
575         group = malloc0(sizeof(_BuxtonKey));
576         if (!group) {
577                 abort();
578         }
579         g = malloc0(sizeof(BuxtonData));
580         if (!g) {
581                 abort();
582         }
583         group_label = malloc0(sizeof(BuxtonString));
584         if (!group_label) {
585                 abort();
586         }
587
588         d = malloc0(sizeof(BuxtonData));
589         if (!d) {
590                 abort();
591         }
592         data_label = malloc0(sizeof(BuxtonString));
593         if (!data_label) {
594                 abort();
595         }
596
597         if (!buxton_copy_key_group(key, group)) {
598                 abort();
599         }
600
601         if (buxton_direct_get_value_for_layer(control, group, g, group_label, NULL)) {
602                 buxton_debug("Group %s for name %s missing for unset value\n", key->group.value, key->name.value);
603                 goto fail;
604         }
605
606         /* Access checks are not needed for direct clients, where label is NULL */
607         if (label) {
608                 if (!buxton_check_smack_access(label, group_label, ACCESS_WRITE)) {
609                         goto fail;
610                 }
611                 if (!buxton_direct_get_value_for_layer(control, key, d, data_label, NULL)) {
612                         if (!buxton_check_smack_access(label, data_label, ACCESS_WRITE)) {
613                                 goto fail;
614                         }
615                 } else {
616                         buxton_debug("Key %s not found, so unset fails\n", key->name.value);
617                         goto fail;
618                 }
619         }
620
621         config = &control->config;
622         if ((layer = hashmap_get(config->layers, key->layer.value)) == NULL) {
623                 return false;
624         }
625
626         if (layer->readonly) {
627                 buxton_debug("Read-only layer!\n");
628                 return false;
629         }
630         backend = backend_for_layer(config, layer);
631         assert(backend);
632
633         layer->uid = control->client.uid;
634         ret = backend->unset_value(layer, key, NULL, NULL);
635         if (ret) {
636                 buxton_debug("Unset value failed: %s\n", strerror(ret));
637         } else {
638                 r = true;
639         }
640
641 fail:
642         return r;
643 }
644
645 bool buxton_direct_init_db(BuxtonControl *control, BuxtonString *layer_name)
646 {
647         BuxtonBackend *backend;
648         BuxtonConfig *config;
649         BuxtonLayer *layer;
650         bool ret = false;
651         void *db;
652
653         assert(control);
654         assert(layer_name);
655
656         config = &control->config;
657         layer = hashmap_get(config->layers, layer_name->value);
658         if (!layer) {
659                 goto end;
660         }
661
662         if (layer->type == LAYER_USER) {
663                 ret = true;
664                 goto end;
665         }
666
667         backend = backend_for_layer(config, layer);
668         assert(backend);
669
670         db = backend->create_db(layer);
671         if (db) {
672                 ret = true;
673         }
674
675 end:
676         return ret;
677 }
678
679 void buxton_direct_close(BuxtonControl *control)
680 {
681         Iterator iterator;
682         BuxtonBackend *backend;
683         BuxtonLayer *layer;
684         BuxtonString *key;
685
686         control->client.direct = false;
687
688         HASHMAP_FOREACH(backend, control->config.backends, iterator) {
689                 destroy_backend(backend);
690         }
691         hashmap_free(control->config.backends);
692         hashmap_free(control->config.databases);
693
694         HASHMAP_FOREACH_KEY(layer, key, control->config.layers, iterator) {
695                 hashmap_remove(control->config.layers, key);
696                 free(layer->name.value);
697                 free(layer->description);
698                 free(layer);
699         }
700         hashmap_free(control->config.layers);
701
702         control->client.direct = false;
703         control->config.backends = NULL;
704         control->config.databases = NULL;
705         control->config.layers = NULL;
706 }
707
708 /*
709  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
710  *
711  * Local variables:
712  * c-basic-offset: 8
713  * tab-width: 8
714  * indent-tabs-mode: t
715  * End:
716  *
717  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
718  * :indentSize=8:tabSize=8:noTabs=false:
719  */