-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathckvs_client.c
360 lines (304 loc) · 10.3 KB
/
ckvs_client.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
#include "ckvs_client.h"
#include "ckvs.h"
#include "ckvs_crypto.h"
#include "ckvs_io.h"
#include "ckvs_rpc.h"
#include "ckvs_utils.h"
#include "error.h"
#include "util.h"
#include <curl/curl.h>
#include <json-c/json.h>
#include <openssl/evp.h>
#include <stdlib.h>
// Define how much characters there is for the get request other than the key
// and auth_key
#define LEN_GET_URL 19
int ckvs_client_stats(const char *url, int optargc, _unused char *optargv[]) {
M_REQUIRE_NON_NULL(url);
// Only one argument is allowed
if (optargc > 0) {
return ERR_TOO_MANY_ARGUMENTS;
}
struct ckvs_connection conn;
// Init the conn with the url
int err = ckvs_rpc_init(&conn, url);
if (err != 0) {
return err;
}
// Fill the buffer of conn with the answer of the get request
err = ckvs_rpc(&conn, "/stats");
if (err != 0) {
ckvs_rpc_close(&conn);
return err;
}
struct json_object *result = json_tokener_parse(conn.resp_buf);
if (result == NULL) {
pps_printf("%s\n", conn.resp_buf);
ckvs_rpc_close(&conn);
return ERR_IO;
}
ckvs_rpc_close(&conn);
struct json_object *header_string = NULL, *version = NULL, *table_size = NULL,
*threshold_entries = NULL, *num_entries = NULL,
*keys = NULL;
// We make our variables pointing toward the good field from our result json
// object
json_object_object_get_ex(result, "header_string", &header_string);
json_object_object_get_ex(result, "version", &version);
json_object_object_get_ex(result, "table_size", &table_size);
json_object_object_get_ex(result, "threshold_entries", &threshold_entries);
json_object_object_get_ex(result, "num_entries", &num_entries);
json_object_object_get_ex(result, "keys", &keys);
if (header_string == NULL || version == NULL || table_size == NULL ||
threshold_entries == NULL || num_entries == NULL || keys == NULL) {
json_object_put(result);
return ERR_IO;
}
// We create a header using the transformed values we got from the function
// json_object_get_ex
struct ckvs_header header;
strncpy(header.header_string, json_object_get_string(header_string),
CKVS_HEADERSTRINGLEN);
header.version = (uint32_t)json_object_get_int(version);
header.table_size = (uint32_t)json_object_get_int(table_size);
header.threshold_entries = (uint32_t)json_object_get_int(threshold_entries);
header.num_entries = (uint32_t)json_object_get_int(num_entries);
// We print the header using the function print_header
print_header(&header);
// Next we iterate on the table of keys, convert them and print them
size_t keys_len = json_object_array_length(keys);
for (size_t i = 0; i < keys_len; i++) {
struct json_object *key = json_object_array_get_idx(keys, i);
if (key == NULL) {
json_object_put(result);
return ERR_IO;
}
pps_printf("Key : ");
pps_printf(STR_LENGTH_FMT(CKVS_MAXKEYLEN), json_object_get_string(key));
pps_printf("\n");
}
// We just have to close the json object and free the memory
json_object_put(result);
return ERR_NONE;
}
static int ckvs_client_getset(const char *url, const char *key, const char *pwd,
const char *set_value) {
M_REQUIRE_NON_NULL(url);
M_REQUIRE_NON_NULL(key);
M_REQUIRE_NON_NULL(pwd);
struct ckvs_connection conn;
// Init the connections to the url
int err = ckvs_rpc_init(&conn, url);
if (err != 0) {
return err;
}
CURL *curl = curl_easy_init();
if (curl == NULL) {
ckvs_rpc_close(&conn);
return ERR_IO;
}
// Format the string of the key to be compliant to the url format
char *key_escaped = curl_easy_escape(curl, key, 0);
if (key_escaped == NULL) {
curl_easy_cleanup(curl);
ckvs_rpc_close(&conn);
return ERR_OUT_OF_MEMORY;
}
// We free up the CURL
curl_easy_cleanup(curl);
// We store the auth_key generated by ckvs_client_encrypt_pwd inside memrecord
ckvs_memrecord_t memrecord;
ckvs_client_encrypt_pwd(&memrecord, key, pwd);
// 2 characters per byte of the key + 1 for the '\0' character
char auth_hex[2 * SHA256_DIGEST_LENGTH + 1];
// We convert the auth_key into a hexadecimal string
SHA256_to_string(&(memrecord.auth_key), auth_hex);
// Get request
if (set_value == NULL) {
// We generate the string for the GET request
char *buffer_request = calloc(
LEN_GET_URL + strlen(key_escaped) + strlen(auth_hex) + 1, sizeof(char));
if (buffer_request == NULL) {
curl_free(key_escaped);
ckvs_rpc_close(&conn);
return ERR_OUT_OF_MEMORY;
}
sprintf(buffer_request, "/get?key=%s&auth_key=%s", key_escaped, auth_hex);
curl_free(key_escaped);
// Send the GET request to the url
err = ckvs_rpc(&conn, buffer_request);
if (err != 0) {
free(buffer_request);
ckvs_rpc_close(&conn);
return err;
}
struct json_object *result = json_tokener_parse(conn.resp_buf);
if (result == NULL) {
pps_printf("%s\n", conn.resp_buf);
free(buffer_request);
ckvs_rpc_close(&conn);
return ERR_IO;
}
free(buffer_request);
buffer_request = NULL;
ckvs_rpc_close(&conn);
struct json_object *c2, *data = NULL;
// We parse the json object we got from the response of the GET request
json_object_object_get_ex(result, "c2", &c2);
json_object_object_get_ex(result, "data", &data);
// We get the pointer to the c2 and the data fields
const char *c2_hex = json_object_get_string(c2);
const char *data_hex = json_object_get_string(data);
if (data_hex == NULL || c2_hex == NULL) {
json_object_put(result);
return ERR_IO;
}
// We transformed the hexadecimal string of c2 into a byte array
struct ckvs_sha c2_sha;
err = SHA256_from_string(c2_hex, &c2_sha);
if (err == -1) {
json_object_put(result);
return err;
}
// We use it to compute the master key
err = ckvs_client_compute_masterkey(&memrecord, &c2_sha);
if (err != 0) {
json_object_put(result);
return err;
}
// We transformed the hexadecimal string of data into a byte array
size_t data_len = ((strlen(data_hex) + 1) / 2);
uint8_t *data_buf_crypt = calloc(data_len + 1, sizeof(uint8_t));
if (data_buf_crypt == NULL) {
json_object_put(result);
return ERR_OUT_OF_MEMORY;
}
int buf_len_crypt = hex_decode(data_hex, data_buf_crypt);
if (buf_len_crypt == -1) {
free(data_buf_crypt);
json_object_put(result);
return buf_len_crypt;
}
// We decrypt the data using the master key
size_t buf_len_plain = 0;
unsigned char *data_buf_plain =
calloc(data_len + EVP_MAX_BLOCK_LENGTH + 1, sizeof(unsigned char));
if (data_buf_plain == NULL) {
free(data_buf_crypt);
json_object_put(result);
return ERR_OUT_OF_MEMORY;
}
err = ckvs_client_crypt_value(&memrecord, 0, data_buf_crypt,
(size_t)buf_len_crypt, data_buf_plain,
&buf_len_plain);
if (err != ERR_NONE) {
free(data_buf_crypt);
free(data_buf_plain);
json_object_put(result);
return err;
}
data_buf_plain[buf_len_plain] = '\0';
// We print the data
pps_printf("%s", data_buf_plain);
// We just have to close the json object and free the memory
json_object_put(result);
free(data_buf_crypt);
free(data_buf_plain);
}
// Set request
else {
struct ckvs_sha c2_sha;
unsigned char *outbuf = NULL;
size_t outbuflen = 0;
// encrypt the value and generate new c2
err =
ckvs_encrypt_value(&c2_sha, &memrecord, set_value, &outbuf, &outbuflen);
if (err != ERR_NONE) {
ckvs_rpc_close(&conn);
curl_free(key_escaped);
return err;
}
// hex_encode the encrypted text
char *outbuf_hex = calloc(outbuflen * 2 + 1, 1);
if (outbuf_hex == NULL) {
free(outbuf);
curl_free(key_escaped);
ckvs_rpc_close(&conn);
return ERR_OUT_OF_MEMORY;
}
hex_encode(outbuf, outbuflen, outbuf_hex);
free(outbuf);
outbuf = NULL;
// hex_encode the c2
char *c2_hex_encoded = calloc(SHA256_DIGEST_LENGTH * 2 + 1, 1);
if (c2_hex_encoded == NULL) {
free(outbuf);
free(outbuf_hex);
curl_free(key_escaped);
ckvs_rpc_close(&conn);
return ERR_OUT_OF_MEMORY;
}
hex_encode((const uint8_t *)&c2_sha, SHA256_DIGEST_LENGTH, c2_hex_encoded);
// prepare the url
const char prefix[] = "/set?name=data.json&offset=0";
char *buffer_url_request =
calloc(LEN_GET_URL + strlen(prefix) + strlen(key_escaped) +
strlen(auth_hex) + 1,
1);
if (buffer_url_request == NULL) {
curl_free(key_escaped);
free(outbuf_hex);
free(c2_hex_encoded);
ckvs_rpc_close(&conn);
return ERR_OUT_OF_MEMORY;
}
sprintf(buffer_url_request, "%s&key=%s&auth_key=%s", prefix, key_escaped,
auth_hex);
curl_free(key_escaped);
key_escaped = NULL;
// put c2 and data in a json object
struct json_object *json_obj = json_object_new_object();
json_object_object_add(json_obj, "c2",
json_object_new_string(c2_hex_encoded));
json_object_object_add(json_obj, "data",
json_object_new_string(outbuf_hex));
const char *json_str = json_object_to_json_string(json_obj);
// send the request
err = ckvs_post(&conn, buffer_url_request, json_str);
free(buffer_url_request);
free(outbuf);
json_object_put(json_obj);
ckvs_rpc_close(&conn);
free(outbuf_hex);
free(c2_hex_encoded);
}
return err;
}
int ckvs_client_get(const char *url, int optargc, char *optargv[]) {
M_REQUIRE_NON_NULL(url);
if (optargc > 2) {
return ERR_TOO_MANY_ARGUMENTS;
} else if (optargc < 2) {
return ERR_NOT_ENOUGH_ARGUMENTS;
}
return ckvs_client_getset(url, optargv[0], optargv[1], NULL);
}
int ckvs_client_set(const char *url, int optargc, char *optargv[]) {
M_REQUIRE_NON_NULL(url);
if (optargc > 3) {
return ERR_TOO_MANY_ARGUMENTS;
} else if (optargc < 3) {
return ERR_NOT_ENOUGH_ARGUMENTS;
}
char *buf = NULL;
size_t buf_size = 0;
// read value to write
int err = read_value_file_content(optargv[2], &buf, &buf_size);
if (err != ERR_NONE) {
return err;
}
// set value
err = ckvs_client_getset(url, optargv[0], optargv[1], buf);
free(buf);
return err;
}