2 * This file is part of buxton.
4 * Copyright (C) 2013 Intel Corporation
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.
25 #define BUXTON_ROOT_CHECK_ENV "BUXTON_ROOT_CHECK"
27 bool buxton_direct_open(BuxtonControl *control)
32 memzero(&(control->config), sizeof(BuxtonConfig));
33 buxton_init_layers(&(control->config));
35 control->client.direct = true;
36 control->client.pid = getpid();
41 int32_t buxton_direct_get_value(BuxtonControl *control, _BuxtonKey *key,
42 BuxtonData *data, BuxtonString *data_label,
43 BuxtonString *client_label)
45 /* Handle direct manipulation */
48 BuxtonString layer = (BuxtonString){ NULL, 0 };
53 BuxtonLayerType layer_origin = -1;
58 if (key->layer.value) {
59 ret = (int32_t)buxton_direct_get_value_for_layer(control, key, data,
65 config = &control->config;
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,
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);
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;
90 layer_origin = LAYER_USER;
92 priority = l->priority;
93 layer.value = l->name.value;
94 layer.length = l->name.length;
99 key->layer.value = layer.value;
100 key->layer.length = layer.length;
101 ret = (int32_t)buxton_direct_get_value_for_layer(control,
106 key->layer.value = NULL;
107 key->layer.length = 0;
114 int buxton_direct_get_value_for_layer(BuxtonControl *control,
117 BuxtonString *data_label,
118 BuxtonString *client_label)
120 /* Handle direct manipulation */
121 BuxtonBackend *backend = NULL;
122 BuxtonLayer *layer = NULL;
123 BuxtonConfig *config;
126 BuxtonString group_label;
133 buxton_debug("get_value '%s:%s' for layer '%s' start\n",
134 key->group.value, key->name.value, key->layer.value);
136 memzero(&g, sizeof(BuxtonData));
137 memzero(&group, sizeof(_BuxtonKey));
138 memzero(&group_label, sizeof(BuxtonString));
140 if (!key->layer.value) {
145 config = &control->config;
146 if ((layer = hashmap_get(config->layers, key->layer.value)) == NULL) {
150 backend = backend_for_layer(config, layer);
153 layer->uid = control->client.uid;
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)) {
160 ret = buxton_direct_get_value_for_layer(control, &group, &g, &group_label, NULL);
162 buxton_debug("Group %s for name %s missing for get value\n", key->group.value, key->name.value);
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)) {
175 ret = backend->get_value(layer, key, data, data_label);
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);
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);
198 bool buxton_direct_set_value(BuxtonControl *control,
203 BuxtonBackend *backend;
205 BuxtonConfig *config;
206 BuxtonString default_label = buxton_string_pack("_");
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;
220 buxton_debug("set_value start\n");
222 group = malloc0(sizeof(_BuxtonKey));
226 g = malloc0(sizeof(BuxtonData));
230 group_label = malloc0(sizeof(BuxtonString));
235 d = malloc0(sizeof(BuxtonData));
239 data_label = malloc0(sizeof(BuxtonString));
244 /* Groups must be created first, so bail if this key's group doesn't exist */
245 if (!buxton_copy_key_group(key, group)) {
249 ret = buxton_direct_get_value_for_layer(control, group, g, group_label, NULL);
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);
256 /* Access checks are not needed for direct clients, where label is NULL */
258 if (!buxton_check_smack_access(label, group_label, ACCESS_WRITE)) {
262 ret = buxton_direct_get_value_for_layer(control, key, d, data_label, NULL);
263 if (ret == -ENOENT || ret == EINVAL) {
267 if (!buxton_check_smack_access(label, data_label, ACCESS_WRITE)) {
275 ret = buxton_direct_get_value_for_layer(control, key, d, data_label, NULL);
276 if (ret == -ENOENT || ret == EINVAL) {
285 config = &control->config;
286 if ((layer = hashmap_get(config->layers, key->layer.value)) == NULL) {
290 if (layer->readonly) {
291 buxton_debug("Read-only layer!\n");
295 backend = backend_for_layer(config, layer);
298 layer->uid = control->client.uid;
299 ret = backend->set_value(layer, key, data, l);
301 buxton_debug("set value failed: %s\n", strerror(ret));
307 buxton_debug("set_value end\n");
311 bool buxton_direct_set_label(BuxtonControl *control,
315 BuxtonBackend *backend;
317 BuxtonConfig *config;
325 config = &control->config;
327 if ((layer = hashmap_get(config->layers, key->layer.value)) == NULL) {
331 if (layer->readonly) {
332 buxton_debug("Read-only layer!\n");
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"));
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);
346 buxton_debug("Cannot set labels in a user layer\n");
350 backend = backend_for_layer(config, layer);
353 layer->uid = control->client.uid;
354 ret = backend->set_value(layer, key, NULL, label);
356 buxton_debug("set label failed: %s\n", strerror(ret));
365 bool buxton_direct_create_group(BuxtonControl *control,
369 BuxtonBackend *backend;
371 BuxtonConfig *config;
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;
383 data = malloc0(sizeof(BuxtonData));
387 group = malloc0(sizeof(BuxtonData));
391 dlabel = malloc0(sizeof(BuxtonString));
395 glabel = malloc0(sizeof(BuxtonString));
400 config = &control->config;
402 if ((layer = hashmap_get(config->layers, key->layer.value)) == NULL) {
406 if (layer->readonly) {
407 buxton_debug("Read-only layer!\n");
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"));
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);
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);
427 backend = backend_for_layer(config, layer);
430 /* Since groups don't have a value, we create a dummy value */
432 s = buxton_string_pack("BUXTON_GROUP_VALUE");
433 if (!buxton_string_copy(&s, &data->store.d_string)) {
438 if (!buxton_string_copy(label, dlabel)) {
442 /* _ (floor) is our current default label */
443 l = buxton_string_pack("_");
444 if (!buxton_string_copy(&l, dlabel)) {
449 layer->uid = control->client.uid;
450 ret = backend->set_value(layer, key, data, dlabel);
452 buxton_debug("create group failed: %s\n", strerror(ret));
461 bool buxton_direct_remove_group(BuxtonControl *control,
463 BuxtonString *client_label)
465 BuxtonBackend *backend;
467 BuxtonConfig *config;
468 _cleanup_buxton_data_ BuxtonData *group = NULL;
469 _cleanup_buxton_string_ BuxtonString *glabel = NULL;
476 group = malloc0(sizeof(BuxtonData));
480 glabel = malloc0(sizeof(BuxtonString));
485 config = &control->config;
487 if ((layer = hashmap_get(config->layers, key->layer.value)) == NULL) {
491 if (layer->readonly) {
492 buxton_debug("Read-ony layer!\n");
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"));
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);
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);
512 if (layer->type == LAYER_USER) {
513 if (client_label && !buxton_check_smack_access(client_label, glabel, ACCESS_WRITE)) {
518 backend = backend_for_layer(config, layer);
521 layer->uid = control->client.uid;
523 ret = backend->unset_value(layer, key, NULL, NULL);
525 buxton_debug("remove group failed: %s\n", strerror(ret));
534 bool buxton_direct_list_keys(BuxtonControl *control,
535 BuxtonString *layer_name,
541 /* Handle direct manipulation */
542 BuxtonBackend *backend = NULL;
544 BuxtonConfig *config;
546 config = &control->config;
547 if ((layer = hashmap_get(config->layers, layer_name->value)) == NULL) {
550 backend = backend_for_layer(config, layer);
553 layer->uid = control->client.uid;
554 return backend->list_keys(layer, list);
557 bool buxton_direct_unset_value(BuxtonControl *control,
561 BuxtonBackend *backend;
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;
575 group = malloc0(sizeof(_BuxtonKey));
579 g = malloc0(sizeof(BuxtonData));
583 group_label = malloc0(sizeof(BuxtonString));
588 d = malloc0(sizeof(BuxtonData));
592 data_label = malloc0(sizeof(BuxtonString));
597 if (!buxton_copy_key_group(key, group)) {
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);
606 /* Access checks are not needed for direct clients, where label is NULL */
608 if (!buxton_check_smack_access(label, group_label, ACCESS_WRITE)) {
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)) {
616 buxton_debug("Key %s not found, so unset fails\n", key->name.value);
621 config = &control->config;
622 if ((layer = hashmap_get(config->layers, key->layer.value)) == NULL) {
626 if (layer->readonly) {
627 buxton_debug("Read-only layer!\n");
630 backend = backend_for_layer(config, layer);
633 layer->uid = control->client.uid;
634 ret = backend->unset_value(layer, key, NULL, NULL);
636 buxton_debug("Unset value failed: %s\n", strerror(ret));
645 bool buxton_direct_init_db(BuxtonControl *control, BuxtonString *layer_name)
647 BuxtonBackend *backend;
648 BuxtonConfig *config;
656 config = &control->config;
657 layer = hashmap_get(config->layers, layer_name->value);
662 if (layer->type == LAYER_USER) {
667 backend = backend_for_layer(config, layer);
670 db = backend->create_db(layer);
679 void buxton_direct_close(BuxtonControl *control)
682 BuxtonBackend *backend;
686 control->client.direct = false;
688 HASHMAP_FOREACH(backend, control->config.backends, iterator) {
689 destroy_backend(backend);
691 hashmap_free(control->config.backends);
692 hashmap_free(control->config.databases);
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);
700 hashmap_free(control->config.layers);
702 control->client.direct = false;
703 control->config.backends = NULL;
704 control->config.databases = NULL;
705 control->config.layers = NULL;
709 * Editor modelines - http://www.wireshark.org/tools/modelines.html
714 * indent-tabs-mode: t
717 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
718 * :indentSize=8:tabSize=8:noTabs=false: