1/**
2 * \file
3 * \brief Simple capability storage
4 *
5 * Moved from chips in the coordination service in order
6 * to get rid of chips. We don't store caps with our
7 * get/set API because there is currently no good solution
8 * to store caps in the SKB:
9 * 1. It's easy for clients to change cap info in SKB and
10 *    the server does cap_delete() on the corrupted data
11 *    in case a capability is retrieved
12 * 2. In case we store it as records we may need to depend
13 *    on the implementation of caprefs.
14 */
15
16/*
17 * Copyright (c) 2009, 2010, ETH Zurich.
18 * All rights reserved.
19 *
20 * This file is distributed under the terms in the attached LICENSE file.
21 * If you do not find this file, copies can be found by writing to:
22 * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
23 */
24
25#include <stdio.h>
26#include <string.h>
27
28#include <barrelfish/barrelfish.h>
29#include <if/octopus_defs.h>
30
31#include <octopus_server/init.h>
32#include <octopus_server/service.h>
33#include <octopus_server/debug.h>
34
35#include <hashtable/hashtable.h>
36
37#include "queue.h"
38
39static struct hashtable *capdb = NULL;
40
41static void get_cap_reply(struct octopus_binding *b,
42        struct oct_reply_state* ns)
43{
44    errval_t err;
45    err = b->tx_vtbl.get_cap_response(b, MKCONT(free, ns), ns->cap, ns->error);
46
47    if (err_is_fail(err)) {
48        if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
49            oct_rpc_enqueue_reply(b, ns);
50            return;
51        }
52        USER_PANIC_ERR(err, "SKB: sending %s failed!", __FUNCTION__);
53    }
54}
55
56void get_cap_handler(struct octopus_binding *b, const char *key)
57{
58    errval_t err, reterr = SYS_ERR_OK;
59    struct capref cap;
60
61    capdb->d.get_capability(&capdb->d, (CONST_CAST)key, &cap);
62
63    if(capcmp(cap, NULL_CAP)) {
64        reterr = OCT_ERR_CAP_NAME_UNKNOWN;
65    }
66
67    struct oct_reply_state* ns = NULL;
68    err = new_oct_reply_state(&ns, get_cap_reply);
69    assert(err_is_ok(err));
70    ns->cap = cap;
71    ns->error = reterr;
72    ns->reply(b, ns);
73}
74
75static void put_cap_reply(struct octopus_binding *b,
76        struct oct_reply_state* ns)
77{
78    errval_t err;
79    err = b->tx_vtbl.put_cap_response(b, MKCONT(free, ns), ns->error);
80
81    if (err_is_fail(err)) {
82        if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
83            oct_rpc_enqueue_reply(b, ns);
84            return;
85        }
86        USER_PANIC_ERR(err, "SKB: sending %s failed!", __FUNCTION__);
87    }
88}
89
90void put_cap_handler(struct octopus_binding *b, const char *key,
91                            struct capref cap)
92{
93    errval_t err, reterr = SYS_ERR_OK;
94    struct capref dbcap;
95
96    capdb->d.get_capability(&capdb->d, (CONST_CAST)key, &dbcap);
97    if(!capcmp(dbcap, NULL_CAP)) {
98        reterr = OCT_ERR_CAP_OVERWRITE;
99        err = cap_delete(cap);
100        assert(err_is_ok(err));
101    } else {
102        /* we need to make our own copy of the key */
103        key = strdup(key);
104        int r = capdb->d.put_capability(&capdb->d, (CONST_CAST)key, cap);
105        assert(r == 0);
106    }
107
108    struct oct_reply_state* ns = NULL;
109    err = new_oct_reply_state(&ns, put_cap_reply);
110    assert(err_is_ok(err));
111    ns->error = reterr;
112    ns->reply(b, ns);
113}
114
115static void free_ns(void* arg) {
116    struct oct_reply_state* ns = (struct oct_reply_state*) arg;
117    free(ns->retkey);
118    free(ns);
119}
120
121static void sput_cap_reply(struct octopus_binding *b,
122        struct oct_reply_state* ns)
123{
124    errval_t err;
125    err = b->tx_vtbl.sput_cap_response(b, MKCONT(free_ns, ns), ns->retkey, ns->error);
126    if (err_is_fail(err)) {
127        if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
128            oct_rpc_enqueue_reply(b, ns);
129            return;
130        }
131        USER_PANIC_ERR(err, "SKB: sending %s failed!", __FUNCTION__);
132    }
133}
134
135void sput_cap_handler(struct octopus_binding *b, const char *key,
136                      struct capref cap)
137{
138    errval_t err, reterr = SYS_ERR_OK;
139    struct oct_reply_state* ns = NULL;
140    struct capref dbcap;
141    // Identfier to make sure all caps have a unique key
142    static uint32_t CAP_IDENT = 0;
143
144    char* uniquekey = NULL;
145    int r = asprintf(&uniquekey, "%s%d", key, CAP_IDENT++);
146    if (uniquekey == NULL || r == -1) {
147        reterr = LIB_ERR_MALLOC_FAIL;
148        goto out;
149    }
150
151    capdb->d.get_capability(&capdb->d, (CONST_CAST)key, &dbcap);
152    if(!capcmp(dbcap, NULL_CAP)) {
153        // This case is not intended to happen
154        // but can if a malicious client takes a key
155        reterr = OCT_ERR_CAP_OVERWRITE;
156    } else {
157        // we need to make our own copy of the key
158        char* dupkey = strdup(uniquekey);
159        r = capdb->d.put_capability(&capdb->d, (CONST_CAST)dupkey, cap);
160        assert(r == 0);
161    }
162
163out:
164    err = new_oct_reply_state(&ns, sput_cap_reply);
165    assert(err_is_ok(err));
166    ns->retkey = uniquekey;
167    ns->error = reterr;
168    ns->reply(b, ns);
169}
170
171static void remove_cap_reply(struct octopus_binding *b,
172        struct oct_reply_state* ns)
173{
174    errval_t err;
175    err = b->tx_vtbl.remove_cap_response(b, MKCONT(free, ns), ns->error);
176
177    if (err_is_fail(err)) {
178        if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
179            oct_rpc_enqueue_reply(b, ns);
180            return;
181        }
182        USER_PANIC_ERR(err, "SKB: sending %s failed!", __FUNCTION__);
183    }
184}
185
186void remove_cap_handler(struct octopus_binding *b, const char *key)
187{
188    errval_t err, reterr = SYS_ERR_OK;
189
190    struct capref cap;
191    capdb->d.get_capability(&capdb->d, (CONST_CAST)key, &cap);
192    if(capcmp(cap, NULL_CAP)) {
193        reterr = OCT_ERR_CAP_NAME_UNKNOWN;
194    }
195    else {
196        cap_delete(cap);
197        capdb->d.remove(&capdb->d, key, strlen(key));
198    }
199
200    struct oct_reply_state* ns = NULL;
201    err = new_oct_reply_state(&ns, remove_cap_reply);
202    assert(err_is_ok(err));
203    ns->error = reterr;
204    ns->reply(b, ns);
205}
206
207errval_t init_capstorage(void)
208{
209    capdb = create_hashtable();
210    assert(capdb != NULL);
211
212    return SYS_ERR_OK;
213}
214