kinetic-c  v0.12.0
Seagate Kinetic Protocol Client Library for C
kinetic_acl.c
Go to the documentation of this file.
1 /*
2 * kinetic-c
3 * Copyright (C) 2015 Seagate Technology.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 *
19 */
20 #include <string.h>
21 #include <stdio.h>
22 #include <fcntl.h>
23 #include <errno.h>
24 
25 #include "kinetic_logger.h"
26 #include "kinetic_acl.h"
27 #include "json.h"
28 
29 typedef struct {
31  const char *string;
32 } permission_pair;
33 
34 static permission_pair permission_table[] = {
44 };
45 
46 #define PERM_TABLE_ROWS (sizeof(permission_table)/sizeof(permission_table)[0])
47 
48 static KineticACLLoadResult read_next_ACL(const char *buf, size_t buf_size,
49  size_t offset, size_t *new_offset, struct json_tokener *tokener,
50  Com__Seagate__Kinetic__Proto__Command__Security__ACL **instance);
51 static KineticACLLoadResult unpack_scopes(Com__Seagate__Kinetic__Proto__Command__Security__ACL *acl,
52  int scope_count, json_object *scopes);
53 static KineticACLLoadResult acl_of_string(const char *buf, size_t buf_size, struct ACL **instance);
54 
56 {
57  for (size_t i = 0; i < PERM_TABLE_ROWS; i++) {
58  permission_pair *pp = &permission_table[i];
59  if (pp->permission == perm) { return pp->string; }
60  }
61  return "INVALID";
62 }
63 
65 {
66  for (size_t i = 0; i < PERM_TABLE_ROWS; i++) {
67  permission_pair *pp = &permission_table[i];
68  if (0 == strcmp(str, pp->string)) { return pp->permission; }
69  }
71 }
72 
74 KineticACL_LoadFromFile(const char *path, struct ACL **instance)
75 {
76  if (path == NULL || instance == NULL) {
77  return ACL_ERROR_NULL;
78  }
79 
80  int fd = open(path, O_RDONLY);
81  if (fd == -1) {
82 #ifndef TEST
83  LOGF0("Failed ot open file '%s': %s", path, strerror(errno));
84 #endif
85  errno = 0;
86  return ACL_ERROR_BAD_JSON;
87  }
89 
90  const int BUF_START_SIZE = 256;
91  char *buf = calloc(1, BUF_START_SIZE);
92  if (buf == NULL) {
93  res = ACL_ERROR_MEMORY;
94  goto cleanup;
95  }
96  size_t buf_sz = BUF_START_SIZE;
97  size_t buf_used = 0;
98 
99  ssize_t read_sz = 0;
100  for (;;) {
101  read_sz = read(fd, &buf[buf_used], buf_sz - buf_used);
102  if (read_sz == -1) {
103  res = ACL_ERROR_JSON_FILE;
104  goto cleanup;
105  } else if (read_sz == 0) {
106  break;
107  } else {
108  buf_used += read_sz;
109  if (buf_sz == buf_used) {
110  size_t nsz = 2 * buf_sz;
111  char *nbuf = realloc(buf, nsz);
112  if (nbuf) {
113  buf_sz = nsz;
114  buf = nbuf;
115  }
116  }
117  }
118  }
119 
120 #ifndef TEST
121  LOGF2(" -- read %zd bytes, parsing...", buf_used);
122 #endif
123  res = acl_of_string(buf, buf_used, instance);
124 cleanup:
125  if (buf) { free(buf); }
126  close(fd);
127  return res;
128 }
129 
130 static KineticACLLoadResult acl_of_string(const char *buf, size_t buf_size, struct ACL **instance)
131 {
133  struct ACL *acl_group = NULL;
134  Com__Seagate__Kinetic__Proto__Command__Security__ACL **acl_array = NULL;
135  struct json_tokener* tokener = NULL;
136 
137  acl_group = calloc(1, sizeof(*acl_group));
138  if (acl_group == NULL) { goto cleanup; }
139 
140  acl_group->ACLs = calloc(1, sizeof(Com__Seagate__Kinetic__Proto__Command__Security__ACL *));
141  if (acl_group->ACLs == NULL) { goto cleanup; }
142  acl_group->ACL_ceil = 1;
143  acl_group->ACL_count = 0;
144 
145  tokener = json_tokener_new();
146  if (tokener == NULL) { goto cleanup; }
147 
148  size_t offset = 0;
149 
150  while (buf_size - offset > 0) {
151  size_t offset_out = 0;
152  Com__Seagate__Kinetic__Proto__Command__Security__ACL *new_acl = NULL;
153 #ifndef TEST
154  LOGF2(" -- reading next ACL at offset %zd, rem %zd", offset, buf_size - offset);
155 #endif
156  res = read_next_ACL(buf, buf_size, offset,
157  &offset_out, tokener, &new_acl);
158  offset += offset_out;
159 #ifndef TEST
160  LOGF2(" -- result %d, offset_out %zd", res, offset);
161 #endif
162  if (res == ACL_OK) {
163  if (acl_group->ACL_count == acl_group->ACL_ceil) { /* grow */
164  size_t nsz = 2 * acl_group->ACL_ceil * sizeof(acl_group->ACLs[0]);
165  Com__Seagate__Kinetic__Proto__Command__Security__ACL **nACLs = realloc(acl_group->ACLs, nsz);
166  if (nACLs == NULL) {
167  goto cleanup;
168  } else {
169  acl_group->ACL_ceil *= 2;
170  acl_group->ACLs = nACLs;
171  }
172  }
173  acl_group->ACLs[acl_group->ACL_count] = new_acl;
174  acl_group->ACL_count++;
175  } else {
176  break;
177  }
178  }
179 
180 cleanup:
181  if (tokener) { json_tokener_free(tokener); }
182 
183  if (res == ACL_END_OF_STREAM || res == ACL_OK) {
184  if (acl_group && acl_group->ACL_count == 0) {
185  LOG2("Failed to read any JSON objects");
186  return ACL_ERROR_BAD_JSON;
187  } else { /* read at least one ACL */
188  *instance = acl_group;
189  return ACL_OK;
190  }
191  } else {
192  if (acl_group) { free(acl_group); }
193  if (acl_array) { free(acl_array); }
194  return res;
195  }
196 }
197 
198 static KineticACLLoadResult read_next_ACL(const char *buf, size_t buf_size,
199  size_t offset, size_t *new_offset,
200  struct json_tokener *tokener, Com__Seagate__Kinetic__Proto__Command__Security__ACL **instance)
201 {
202  struct json_object *obj = json_tokener_parse_ex(tokener,
203  &buf[offset], buf_size - offset);
204  if (obj == NULL) {
205  if (json_tokener_get_error(tokener) == json_tokener_error_parse_eof) {
206  return ACL_END_OF_STREAM;
207  } else {
208  LOGF2("JSON error %d", json_tokener_get_error(tokener));
209  return ACL_ERROR_BAD_JSON;
210  }
211  }
212 
213  *new_offset = tokener->char_offset;
214 
216  Com__Seagate__Kinetic__Proto__Command__Security__ACL *acl = NULL;
217  uint8_t *data = NULL;
218 
219  int scope_count = 0;
220  struct json_object *val = NULL;
221  if (json_object_object_get_ex(obj, "scope", &val)) {
222  scope_count = json_object_array_length(val);
223  } else {
225  goto cleanup;
226  }
227 
228  size_t alloc_sz = sizeof(*acl);
229  acl = calloc(1, alloc_sz);
230  if (acl == NULL) { goto cleanup; }
231 
233 
234  /* Copy fields */
235  if (json_object_object_get_ex(obj, "identity", &val)) {
236  acl->has_identity = true;
237  acl->identity = json_object_get_int64(val);
238  } else {
239  acl->has_identity = false;
240  }
241 
242  if (json_object_object_get_ex(obj, "key", &val)) {
243  const char *key = json_object_get_string(val);
244  size_t len = strlen(key);
245 
246  acl->has_hmacalgorithm = true;
248 
249  acl->key.len = len;
250  data = calloc(1, len + 1);
251  if (data == NULL) { goto cleanup; }
252  memcpy(data, key, len);
253  data[len] = '\0';
254  acl->key.data = data;
255  data = NULL;
256  acl->has_key = true;
257  }
258 
259  if (json_object_object_get_ex(obj, "HMACAlgorithm", &val)) {
260  const char *hmac = json_object_get_string(val);
261  if (0 != strcmp(hmac, "HmacSHA1")) {
263  goto cleanup;
264  } else {
265  // acl->key->type is already set to HMAC_SHA1.
266  }
267  }
268 
269  struct json_object *scopes = NULL;
270  if (json_object_object_get_ex(obj, "scope", &scopes)) {
271  res = unpack_scopes(acl, scope_count, scopes);
272  if (res != ACL_OK) { goto cleanup; }
273  }
274 
275  /* Decrement JSON object refcount, freeing it. */
276  json_object_put(obj);
277  *instance = acl;
278  return ACL_OK;
279 cleanup:
280  if (obj) { json_object_put(obj); }
281  if (acl) { free(acl); }
282  if (data) { free(data); }
283  return res;
284 }
285 
286 static KineticACLLoadResult unpack_scopes(Com__Seagate__Kinetic__Proto__Command__Security__ACL *acl,
287  int scope_count, json_object *scopes)
288 {
290  Com__Seagate__Kinetic__Proto__Command__Security__ACL__Scope **scope_array = NULL;
292  Com__Seagate__Kinetic__Proto__Command__Security__ACL__Scope *scope = NULL;
293  uint8_t *data = NULL;
294 
295  scope_array = calloc(scope_count, sizeof(*scope_array));
296  if (scope_array == NULL) { goto cleanup; }
297 
298  acl->scope = scope_array;
299 
300  for (int si = 0; si < scope_count; si++) {
301  struct json_object *cur_scope = json_object_array_get_idx(scopes, si);
302  if (cur_scope) {
303  scope = calloc(1, sizeof(*scope));
304  if (scope == NULL) { goto cleanup; }
306 
307  struct json_object *val = NULL;
308  if (json_object_object_get_ex(cur_scope, "offset", &val)) {
309  scope->offset = json_object_get_int64(val);
310  scope->has_offset = true;
311  } else {
312  scope->has_offset = false;
313  }
314 
315  if (json_object_object_get_ex(cur_scope, "value", &val)) {
316  const char *str = json_object_get_string(val);
317  if (str) {
318  size_t len = strlen(str);
319  data = malloc(len + 1);
320  if (data == NULL) {
321  return ACL_ERROR_MEMORY;
322  } else {
323  memcpy(data, str, len);
324  data[len] = '\0';
325  scope->value.data = data;
326  scope->value.len = len;
327  data = NULL;
328  scope->has_value = true;
329  }
330  }
331  } else {
332  scope->has_value = false;
333  }
334 
335  scope->n_permission = 0;
336  if (json_object_object_get_ex(cur_scope, "permission", &val)) {
337  perm_array = calloc(ACL_MAX_PERMISSIONS, sizeof(*perm_array));
338  if (perm_array == NULL) { goto cleanup; }
339  scope->permission = perm_array;
340  perm_array = NULL;
341 
342  enum json_type perm_type = json_object_get_type(val);
343  if (perm_type == json_type_string) {
344  scope->permission[0] = permission_of_str(json_object_get_string(val));
347  } else {
348  scope->n_permission++;
349  }
350  } else if (perm_type == json_type_array) {
351  int count = json_object_array_length(val);
352  for (int i = 0; i < count; i++) {
353  struct json_object *jperm = json_object_array_get_idx(val, i);
355  p = permission_of_str(json_object_get_string(jperm));
358  } else {
359  scope->permission[scope->n_permission] = p;
360  scope->n_permission++;
361  }
362  }
363  } else {
365  }
366  }
367  if (json_object_object_get_ex(cur_scope, "TlsRequired", &val)) {
368  scope->tlsrequired = json_object_get_boolean(val);
369  scope->has_tlsrequired = true;
370  }
371 
372  acl->scope[acl->n_scope] = scope;
373  acl->n_scope++;
374  scope = NULL;
375  }
376  }
377  acl->n_scope = scope_count;
378  return ACL_OK;
379 
380 cleanup:
381  if (scope_array) { free(scope_array); }
382  if (scope) { free(scope); }
383  if (perm_array) { free(perm_array); }
384  if (data) { free(data); }
385  return res;
386 }
387 
388 void KineticACL_Print(FILE *f, struct ACL *ACLs)
389 {
390  if (ACLs == NULL) {
391  fprintf(f, "NULL\n");
392  return;
393  }
394 
395  fprintf(f, "ACLs [%zd]:\n", ACLs->ACL_count);
396 
397  for (size_t ai = 0; ai < ACLs->ACL_count; ai++) {
398  Com__Seagate__Kinetic__Proto__Command__Security__ACL *acl = ACLs->ACLs[ai];
399  if (acl == NULL) { continue; }
400  if (ai > 0) { fprintf(f, "\n"); }
401 
402  if (acl->has_identity) {
403  fprintf(f, " identity: %lld\n", (long long)acl->identity);
404  }
405 
406  if (acl->has_key) {
407  fprintf(f, " key[%s,%zd]: \"%s\"\n",
408  "HmacSHA1", acl->key.len, acl->key.data);
409  }
410 
411  fprintf(f, " scopes: (%zd)\n", acl->n_scope);
412 
413  for (size_t si = 0; si < acl->n_scope; si++) {
414  Com__Seagate__Kinetic__Proto__Command__Security__ACL__Scope *scope = acl->scope[si];
415  if (si > 0) { fprintf(f, "\n"); }
416  fprintf(f, " scope %zd:\n", si);
417  if (scope->has_offset) {
418  fprintf(f, " offset: %lld\n", (long long)scope->offset);
419  }
420  if (scope->has_value) {
421  fprintf(f, " value[%zd]: \"%s\"\n",
422  scope->value.len, scope->value.data);
423  }
424  for (size_t pi = 0; pi < scope->n_permission; pi++) {
425  fprintf(f, " permission: %s\n",
426  str_of_permission(scope->permission[pi]));
427  }
428 
429  if (scope->has_tlsrequired) {
430  fprintf(f, " tlsrequired: %d\n", scope->tlsrequired);
431  }
432  }
433  }
434 }
435 
436 void KineticACL_Free(struct ACL *ACLs) {
437  if (ACLs) {
438  for (size_t ai = 0; ai < ACLs->ACL_count; ai++) {
439  Com__Seagate__Kinetic__Proto__Command__Security__ACL *acl = ACLs->ACLs[ai];
440  if (acl) {
441  for (size_t si = 0; si < acl->n_scope; si++) {
442  Com__Seagate__Kinetic__Proto__Command__Security__ACL__Scope *scope = acl->scope[si];
443  if (scope->has_value && scope->value.data) {
444  free(scope->value.data);
445  }
446 
447  if (scope->n_permission > 0) {
448  free(scope->permission);
449  }
450  free(scope);
451  }
452  free(acl->scope);
453 
454  if (acl->has_key && acl->key.data) {
455  free(acl->key.data);
456  }
457  free(acl);
458  }
459  }
460  free(ACLs->ACLs);
461  free(ACLs);
462  }
463 }
Com__Seagate__Kinetic__Proto__Command__Security__ACL__Permission
Definition: kinetic.pb-c.h:190
void KineticACL_Free(struct ACL *ACLs)
Definition: kinetic_acl.c:436
void com__seagate__kinetic__proto__command__security__acl__scope__init(Com__Seagate__Kinetic__Proto__Command__Security__ACL__Scope *message)
Definition: kinetic.pb-c.c:217
static KineticACLLoadResult unpack_scopes(Com__Seagate__Kinetic__Proto__Command__Security__ACL *acl, int scope_count, json_object *scopes)
Definition: kinetic_acl.c:286
static Com__Seagate__Kinetic__Proto__Command__Security__ACL__Permission permission_of_str(const char *str)
Definition: kinetic_acl.c:64
Missing required field.
static KineticACLLoadResult acl_of_string(const char *buf, size_t buf_size, struct ACL **instance)
Definition: kinetic_acl.c:130
End of stream.
KineticACLLoadResult
void com__seagate__kinetic__proto__command__security__acl__init(Com__Seagate__Kinetic__Proto__Command__Security__ACL *message)
Definition: kinetic.pb-c.c:223
#define LOG2(message)
Com__Seagate__Kinetic__Proto__Command__Security__ACL ** ACLs
ACL struct array.
#define LOGF0(message,...)
KineticACLLoadResult KineticACL_LoadFromFile(const char *path, struct ACL **instance)
Definition: kinetic_acl.c:74
static permission_pair permission_table[]
Definition: kinetic_acl.c:34
Unable to open JSON file.
Invalid JSON in file.
void KineticACL_Print(FILE *f, struct ACL *ACLs)
Definition: kinetic_acl.c:388
#define ACL_MAX_PERMISSIONS
#define PERM_TABLE_ROWS
Definition: kinetic_acl.c:46
size_t ACL_ceil
Ceiling of ACLs array: resize if count == ceil.
size_t ACL_count
How many ACL * structs are in ACLs[].
NULL pointer error.
Memory allocation failure.
static KineticACLLoadResult read_next_ACL(const char *buf, size_t buf_size, size_t offset, size_t *new_offset, struct json_tokener *tokener, Com__Seagate__Kinetic__Proto__Command__Security__ACL **instance)
Definition: kinetic_acl.c:198
#define LOGF2(message,...)
static const char * str_of_permission(Com__Seagate__Kinetic__Proto__Command__Security__ACL__Permission perm)
Definition: kinetic_acl.c:55