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