diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2015-01-19 11:26:48 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2015-01-19 11:35:21 +0200 |
commit | 4d1258de786a83888d123f4e8f791f1ad6ecf605 (patch) | |
tree | e172edcda699af4b7db72f42e30f4399866b339b /lib | |
parent | 0766417065bfec9747bf0f41f9b68c27e378f817 (diff) | |
download | eclat-4d1258de786a83888d123f4e8f791f1ad6ecf605.tar.gz eclat-4d1258de786a83888d123f4e8f791f1ad6ecf605.tar.bz2 |
Initial support for IAM
* NEWS: Update.
* doc/eclat.1man: Update.
* lib/.gitignore: Update.
* lib/Makefile.am (libeclat_a_SOURCES): Add new files.
* lib/json.h: New file.
* lib/jsongrm.y: New file.
* lib/jsonlex.l: New file.
* lib/yytrans: New file.
* lib/libeclat.h (ec2_query) <token>: New member
(eclat_query_create): Change signature.
* lib/qcreat.c (eclat_query_create): Take security token as 5th
argument.
* lib/reqsign.c (querysign2): Add security token.
* src/cmdline.opt: Update copyright years
* src/ec2map.c (ec2_map_get): Pass security token to
eclat_query_create.
* src/eclat.c (security_token): New variable.
(eclat_do_command): Pass security token to
eclat_query_create.
(main): Get authentication credentials from the instance
store, if not found in the access file.
* src/eclat.h (security_token): New extern.
(eclat_get_instance_creds): New proto.
* src/util.c (eclat_get_instance_zone): Use json parser.
(eclat_get_instance_creds): New function.
* tests/Makefile.am (noinst_PROGRAMS): add tjson
* tests/tjson.c: New file.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/.gitignore | 4 | ||||
-rw-r--r-- | lib/Makefile.am | 10 | ||||
-rw-r--r-- | lib/json.h | 66 | ||||
-rw-r--r-- | lib/jsongrm.y | 316 | ||||
-rw-r--r-- | lib/jsonlex.l | 183 | ||||
-rw-r--r-- | lib/libeclat.h | 3 | ||||
-rw-r--r-- | lib/qcreat.c | 4 | ||||
-rw-r--r-- | lib/reqsign.c | 2 | ||||
-rw-r--r-- | lib/yytrans | 4 |
9 files changed, 590 insertions, 2 deletions
diff --git a/lib/.gitignore b/lib/.gitignore index e0d9b22..e96121b 100644 --- a/lib/.gitignore +++ b/lib/.gitignore @@ -2,3 +2,7 @@ forlangrm.c forlangrm.h forlangrm.output forlanlex.c +jsongrm.c +jsongrm.h +jsongrm.output +jsonlex.c diff --git a/lib/Makefile.am b/lib/Makefile.am index f3a9d42..428de49 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -42,6 +42,10 @@ libeclat_a_SOURCES=\ forlangrm.h\ forlangrm.y\ forlanlex.l\ + json.h\ + jsongrm.h\ + jsongrm.y\ + jsonlex.l\ getans.c\ getyn.c\ hmac_sha1.c\ @@ -68,8 +72,14 @@ AM_CPPFLAGS = -I$(top_srcdir)/grecs/src/ $(CURL_CFLAGS) forlanlex.c: forlangrm.h forlangrm.c forlangrm.h: forlangrm.y +jsonlex.c: jsongrm.h +jsongrm.c jsongrm.h: jsongrm.y + AM_YFLAGS=-tdv AM_LFLAGS=-dp +LEXCOMPILE = $(top_srcdir)/@GRECS_SUBDIR@/build-aux/yyrename '$(LEX) $(LFLAGS) $(AM_LFLAGS)' +YACCCOMPILE = $(top_srcdir)/@GRECS_SUBDIR@/build-aux/yyrename '$(YACC) $(YFLAGS) $(AM_YFLAGS)' + diff --git a/lib/json.h b/lib/json.h new file mode 100644 index 0000000..36ca243 --- /dev/null +++ b/lib/json.h @@ -0,0 +1,66 @@ +/* This file is part of Eclat. + Copyright (C) 2012-2015 Sergey Poznyakoff. + + Eclat is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + Eclat is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Eclat. If not, see <http://www.gnu.org/licenses/>. */ + +#include <grecs.h> + +enum json_object_type +{ + json_null, + json_bool, + json_number, + json_string, + json_arr, + json_obj +}; + +struct json_object; +struct json_array { + size_t oc; + struct json_object **ov; +}; + +struct json_object { + enum json_object_type type; + union { + int b; /* json_bool */ + double n; /* json_number */ + char *s; /* json_string */ + struct json_array *a; /* json_arr */ + struct grecs_symtab *o; /* json_o */ + } v; +}; + +struct json_pair { + char *k; + struct json_object *v; +}; + +extern char const *json_err_diag; +extern char const *json_err_ptr; +extern struct json_object *json_return_obj; + +void jsonlex_setup(char const *s, size_t l); +void jsonlex_diag(const char *s, size_t off); +struct json_object *json_object_create(int type); +struct grecs_symtab *json_assoc_create(void); +void json_object_free(struct json_object *obj); + +struct json_object *json_parse_string(char const *input, size_t len); + +struct json_object *json_object_lookup(struct json_object *obj, + const char *ident); + + diff --git a/lib/jsongrm.y b/lib/jsongrm.y new file mode 100644 index 0000000..398d2e7 --- /dev/null +++ b/lib/jsongrm.y @@ -0,0 +1,316 @@ +%{ +/* This file is part of Eclat. + Copyright (C) 2012-2015 Sergey Poznyakoff. + + Eclat is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + Eclat is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Eclat. If not, see <http://www.gnu.org/licenses/>. */ + +#include "libeclat.h" +#include <string.h> +#include "jsongrm.h" +#include "json.h" + +struct json_object *json_return_obj; + +static int yyerror(char const *s); + +static struct json_pair * +pairdup(struct json_pair *in) +{ + struct json_pair *out = grecs_malloc(sizeof(*out)); + out->k = in->k; + out->v = in->v; + return out; +} + +static void +pairfree(void *ptr) +{ + struct json_pair *p = ptr; + free(p->k); + json_object_free(p->v); + free(p); +} + +static void +objfree(void *ptr) +{ + struct json_object *o = ptr; + json_object_free(o); +} + +%} +%token <n> T_NUMBER +%token <s> T_STRING +%token <b> T_BOOL +%token T_NULL T_ERR + +%type <a> array +%type <list> objects objlist pairs pairlist +%type <p> pair +%type <obj> object +%type <o> assoc + +%union { + int b; + double n; + char *s; + struct json_array *a; + struct grecs_symtab *o; + struct json_object *obj; + struct grecs_list *list; + struct json_pair *p; +} +%% + +input : object + { + json_return_obj = $1; + } + ; + +object : T_NUMBER + { + $$ = json_object_create(json_number); + $$->v.n = $1; + } + | T_STRING + { + $$ = json_object_create(json_string); + $$->v.s = $1; + } + | T_BOOL + { + $$ = json_object_create(json_bool); + $$->v.b = $1; + } + | T_NULL + { + $$ = json_object_create(json_null); + } + | array + { + $$ = json_object_create(json_arr); + $$->v.a = $1; + } + | assoc + { + $$ = json_object_create(json_obj); + $$->v.o = $1; + } + ; + +array : '[' objects ']' + { + struct json_array *a = grecs_malloc(sizeof(*a)); + if (!$2) { + a->oc = 0; + a->ov = NULL; + } else { + size_t i; + struct grecs_list_entry *ep; + a->oc = $2->count; + a->ov = grecs_calloc(a->oc, sizeof(a->ov)); + for (i = 0, ep = $2->head; ep; i++, ep = ep->next) { + struct json_object *p = ep->data; + a->ov[i] = p; + } + } + $$ = a; + } + ; + +objects : /* empty */ + { + $$ = NULL; + } + | objlist + ; + +objlist : object + { + $$ = grecs_list_create(); + $$->free_entry = objfree; + grecs_list_append($$, $1); + } + | objlist ',' object + { + grecs_list_append($1, $3); + } + ; + +assoc : '{' pairs '}' + { + struct grecs_symtab *s; + + s = json_assoc_create(); + if ($2) { + struct grecs_list_entry *ep; + for (ep = $2->head; ep; ep = ep->next) { + struct json_pair *p = ep->data; + int install = 1; + grecs_symtab_lookup_or_install(s, p, &install); + if (install) { + p->k = NULL; + p->v = NULL; + } + } + grecs_list_free($2); + } + $$ = s; + } + ; + +pairs : /* empty */ + { + $$ = NULL; + } + | pairlist + ; + +pairlist: pair + { + $$ = grecs_list_create(); + $$->free_entry = pairfree; + grecs_list_append($$, $1); + } + | pairlist ',' pair + { + grecs_list_append($1, $3); + } + ; + +pair : T_STRING ':' object + { + struct json_pair *p = grecs_malloc(sizeof(*p)); + p->k = $1; + p->v = $3; + $$ = p; + } + ; +%% + +static int +yyerror(char const *s) +{ + jsonlex_diag(s, 0); + return 0; +} + +struct json_object * +json_object_create(int type) +{ + struct json_object *obj = grecs_zalloc(sizeof(*obj)); + obj->type = type; + return obj; +} + +void +json_object_free(struct json_object *obj) +{ + size_t i; + + if (!obj) + return; + + switch (obj->type) { + case json_bool: + case json_number: + break; + case json_string: + free(obj->v.s); + break; + case json_arr: + for (i = 0; i < obj->v.a->oc; i++) + json_object_free(obj->v.a->ov[i]); + free(obj->v.a); + break; + case json_obj: + grecs_symtab_free(obj->v.o); + } + free(obj); +} + +static unsigned +json_st_hash(void *data, unsigned long n_buckets) +{ + struct json_pair *p = data; + return grecs_hash_string(p->k, n_buckets); +} + +static int +json_st_cmp(const void *a, const void *b) +{ + struct json_pair const *pa = a; + struct json_pair const *pb = b; + return strcmp(pa->k, pb->k); +} + +static int +json_st_copy(void *a, void *b) +{ + struct json_pair *pa = a; + struct json_pair *pb = b; + memcpy(pa, pb, sizeof(*pa)); + return 0; +} + +static void +json_st_free(void *ptr) +{ + struct json_pair *p = ptr; +// printf("FREE %s\n", p->k); + free(p->k); + json_object_free(p->v); + free(p); +} + +struct grecs_symtab * +json_assoc_create() +{ + return grecs_symtab_create(sizeof(struct json_pair), + json_st_hash, + json_st_cmp, + json_st_copy, + NULL, + json_st_free); +} + +struct json_object * +json_parse_string(char const *input, size_t len) +{ + jsonlex_setup(input, len); + if (yyparse()) { + /* FIXME: error recovery */ + return NULL; + } + return json_return_obj; +} + +struct json_object * +json_object_lookup(struct json_object *obj, const char *ident) +{ + struct json_pair key, *p; + if (!obj || obj->type != json_obj) + return NULL; + key.k = ident; + p = grecs_symtab_lookup_or_install(obj->v.o, &key, NULL); + if (!p) + return NULL; + return p->v; +} + + + + + diff --git a/lib/jsonlex.l b/lib/jsonlex.l new file mode 100644 index 0000000..322b05d --- /dev/null +++ b/lib/jsonlex.l @@ -0,0 +1,183 @@ +%{ +/* This file is part of Eclat. + Copyright (C) 2012-2015 Sergey Poznyakoff. + + Eclat is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + Eclat is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Eclat. If not, see <http://www.gnu.org/licenses/>. */ + +#include "libeclat.h" +#include "jsongrm.h" +#include "json.h" + +static char const *input_ptr; +static size_t input_size; + +char const *json_err_diag; +char const *json_err_ptr; + +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + do { \ + size_t n = (max_size > input_size) ? input_size : max_size; \ + if (n) { \ + memcpy(buf, input_ptr, n); \ + input_ptr += n; \ + input_size -= n; \ + } \ + result = n; \ + } while(0) + +void +jsonlex_setup(char const *s, size_t l) +{ + input_ptr = s; + input_size = l; + json_err_diag = NULL; + json_err_ptr = NULL; + yy_flex_debug = 0; +} + +void +jsonlex_diag(const char *s, size_t off) +{ + if (!json_err_diag) { + json_err_diag = s; + json_err_ptr = input_ptr - off; + } +} + +static int +utf8_wctomb(char *u) +{ + unsigned int wc = strtoul(u, NULL, 16); + int count; + char r[6]; + + if (wc < 0x80) + count = 1; + else if (wc < 0x800) + count = 2; + else if (wc < 0x10000) + count = 3; + else if (wc < 0x200000) + count = 4; + else if (wc < 0x4000000) + count = 5; + else if (wc <= 0x7fffffff) + count = 6; + else + return -1; + + switch (count) { + /* Note: code falls through cases! */ + case 6: + r[5] = 0x80 | (wc & 0x3f); + wc = wc >> 6; + wc |= 0x4000000; + case 5: + r[4] = 0x80 | (wc & 0x3f); + wc = wc >> 6; + wc |= 0x200000; + case 4: + r[3] = 0x80 | (wc & 0x3f); + wc = wc >> 6; + wc |= 0x10000; + case 3: + r[2] = 0x80 | (wc & 0x3f); + wc = wc >> 6; + wc |= 0x800; + case 2: + r[1] = 0x80 | (wc & 0x3f); + wc = wc >> 6; + wc |= 0xc0; + case 1: + r[0] = wc; + } + grecs_line_acc_grow(r, count); + return count; +} + +static int +unescape(int c, int *o) +{ + static char transtab[] = "\\\\\"\"//b\bf\fn\nr\rt\t"; + char *p; + + for (p = transtab; *p; p += 2) { + if (*p == c) { + *o = p[1]; + return 0; + } + } + return -1; +} + +#define YY_SKIP_YYWRAP 1 +static int +yywrap() +{ + return 1; +} +%} +D [0-9] +X [0-9a-fA-F] +%x STR +%% +"-"?{D}{D}*(.{D}{D}*)?([eE][-+]?{D}{D}*)? { + yylval.n = strtod(yytext, NULL); + return T_NUMBER; + } +\"[^\\\"]*\" { grecs_line_begin(); + grecs_line_add(yytext + 1, yyleng - 2); + yylval.s = grecs_line_finish(); + return T_STRING; } +\"[^\\\"]*\\{X}{4} { BEGIN(STR); + grecs_line_begin(); + grecs_line_add(yytext + 1, yyleng - 5); + utf8_wctomb(yytext + yyleng - 4); + } +\"[^\\\"]*\\. { int c; + BEGIN(STR); + grecs_line_begin(); + grecs_line_acc_grow(yytext + 1, yyleng - 2); + if (unescape(yytext[yyleng - 1], &c)) { + jsonlex_diag("invalid UTF-8 codepoint", 5); + return T_ERR; + } + grecs_line_acc_grow_char(c); + } +<STR>[^\\\"]*\" { BEGIN(INITIAL); + if (yyleng > 1) + grecs_line_acc_grow(yytext, yyleng - 1); + yylval.s = grecs_line_finish(); + return T_STRING; } +<STR>[^\\\"]*\\{X}{4} { + grecs_line_add(yytext, yyleng - 5); + utf8_wctomb(yytext + yyleng - 4); +} +<STR>[^\\\"]*\\. { + int c; + grecs_line_acc_grow(yytext, yyleng - 2); + if (unescape(yytext[yyleng - 1], &c)) { + jsonlex_diag("invalid UTF-8 codepoint", 5); + return T_ERR; + } + grecs_line_acc_grow_char(c); } + +null { return T_NULL; } +true { yylval.b = 1; return T_BOOL; } +false { yylval.b = 0; return T_BOOL; } +"{"|"}"|"["|"]"|":"|"," return yytext[0]; +[ \t\n]* ; +. { jsonlex_diag("bogus character", 0); + return T_ERR; } diff --git a/lib/libeclat.h b/lib/libeclat.h index b7dc189..2265a7b 100644 --- a/lib/libeclat.h +++ b/lib/libeclat.h @@ -86,12 +86,13 @@ struct ec2_query { struct grecs_list *headers; /* Query headers */ char *region; char *access_key; + char *token; unsigned long ttl; /* Time-to-live in seconds */ }; struct ec2_query *eclat_query_create(int flags, const char *endpoint, const char *uri, char const *region, - char const *access_key); + char const *access_key, char const *token); void eclat_query_free(struct ec2_query *); void eclat_query_add_param(struct ec2_query *q, const char *name, const char *value); diff --git a/lib/qcreat.c b/lib/qcreat.c index 32471a0..c2898a5 100644 --- a/lib/qcreat.c +++ b/lib/qcreat.c @@ -29,7 +29,8 @@ ec2_param_free(void *ptr) struct ec2_query * eclat_query_create(int flags, const char *endpoint, const char *uri, - char const *region, char const *access_key) + char const *region, char const *access_key, + char const *token) { struct ec2_query *q = grecs_zalloc(sizeof(*q)); q->flags = flags; @@ -45,5 +46,6 @@ eclat_query_create(int flags, const char *endpoint, const char *uri, q->ttl = 5; q->region = grecs_strdup(region ? region : "us-east-1"); q->access_key = grecs_strdup(access_key); + q->token = token ? grecs_strdup(token) : NULL; return q; } diff --git a/lib/reqsign.c b/lib/reqsign.c index 397f6c8..4250907 100644 --- a/lib/reqsign.c +++ b/lib/reqsign.c @@ -64,6 +64,8 @@ querysign2(struct ec2_query *req, char *secret) eclat_query_add_param(req, "AWSAccessKeyId", req->access_key); eclat_query_add_param(req, "SignatureMethod", "HmacSHA256"); eclat_query_add_param(req, "SignatureVersion", "2"); + if (req->token) + eclat_query_add_param(req, "SecurityToken", req->token); time(&t); strftime(tsbuf, sizeof(tsbuf), "%Y-%m-%dT%H:%M:%SZ", gmtime(&t)); diff --git a/lib/yytrans b/lib/yytrans new file mode 100644 index 0000000..9e5979c --- /dev/null +++ b/lib/yytrans @@ -0,0 +1,4 @@ +forlangrm forlan_yy_ +forlanlex forlan_yy_ +jsongrm json_yy_ +jsonlex json_yy_ |