aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2014-07-09 13:01:57 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2014-07-09 23:20:17 +0300
commit131b6ab56cbec838346fd493f3fe96438e3b58e7 (patch)
tree1a30a33f6447fcbeba9810542121dc7003d3129a
parent7f40bb8674983f8e4fc11fbebe56f88daa812c1a (diff)
downloadeclat-131b6ab56cbec838346fd493f3fe96438e3b58e7.tar.gz
eclat-131b6ab56cbec838346fd493f3fe96438e3b58e7.tar.bz2
Implement signature version 4 signing process
* lib/libeclat.h (ec2_param) <encoded>: New member. (ec2_query) <signature>: Remove. <headers,region,access_key>: New members (eclat_query_create): Take two more arguments. All uses changed. (eclat_query_add_param_encoded) (eclat_query_add_header): New functions. * lib/q2url.c (eclat_query_to_url): Don't create Signature param: it is already in the param list (for v2 process). * lib/qaddparm.c (eclat_query_add_param_encoded): New function. (eclat_query_add_header): New function. * lib/qcreat.c (eclat_query_create): Take region and access key as additional parameters. * lib/qencode.c (encode_param): Skip parameters that have encoded set to true. * lib/reqsign.c (querysign2): Store access key in AWSAccessKeyId and the generated signature in the Signature parameters. (eclat_hex_encode): New function. (querysign4): Implement signature version 4 signing process. * src/ec2map.c: Update call to eclat_query_create. * src/eclat.c: Likewise. * src/util.c (eclat_send_query): Sign the query and add requested headers prior to sending. * doc/eclat.conf.5: Document signature-version. * NEWS: Likewise.
-rw-r--r--NEWS9
-rw-r--r--doc/eclat.conf.56
-rw-r--r--lib/libeclat.h12
-rw-r--r--lib/q2url.c33
-rw-r--r--lib/qaddparm.c48
-rw-r--r--lib/qcreat.c5
-rw-r--r--lib/qencode.c3
-rw-r--r--lib/reqsign.c230
-rw-r--r--src/ec2map.c3
-rw-r--r--src/eclat.c3
-rw-r--r--src/util.c41
11 files changed, 355 insertions, 38 deletions
diff --git a/NEWS b/NEWS
index 3c6c74d..be9c4a8 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,4 @@
-Eclat NEWS -- history of user-visible changes. 2014-02-04
+Eclat NEWS -- history of user-visible changes. 2014-07-09
Copyright (C) 2012-2014 Sergey Poznyakoff
See the end of file for copying conditions.
@@ -12,6 +12,13 @@ Version 1.0.90, (Git)
lsaattr describe-image-attribute
setaattr modify-image-attribute
+* Implement signature version 4 signing
+
+The signature version 4 signing process is enabled by adding the
+following statement in the eclat configuration file:
+
+ signature-version 4;
+
Version 1.0, 2013-12-20
diff --git a/doc/eclat.conf.5 b/doc/eclat.conf.5
index 59ac541..feb504f 100644
--- a/doc/eclat.conf.5
+++ b/doc/eclat.conf.5
@@ -13,7 +13,7 @@
.\"
.\" You should have received a copy of the GNU General Public License
.\" along with Eclat. If not, see <http://www.gnu.org/licenses/>.
-.TH ECLAT.CONF 5 "February 13, 2014" "ECLAT" "Eclat User Reference"
+.TH ECLAT.CONF 5 "July 9, 2014" "ECLAT" "Eclat User Reference"
.SH NAME
eclat.conf \- configuration file for
.BR eclat (1).
@@ -396,6 +396,10 @@ algorithm described below. If an access file cannot be opened due to
insufficient privileges, no error message is issued (unless the
debugging level \fBmain.1\fR or higher is requested). This allows you
to have different access files for use by different groups of users.
+.TP
+\fBsignature\-version\fR \fIN\fR;
+Declares the signature version. Valid values for \fIN\fR are \fB2\fR,
+which is the default, and \fB4\fR, which provides a better security.
.SS SSL CONFIGURATION
The \fBssl\fR statement has two forms, and can be used as scalar or as
a block statement. In scalar form it is used to enable SSL:
diff --git a/lib/libeclat.h b/lib/libeclat.h
index 51728e1..b7dc189 100644
--- a/lib/libeclat.h
+++ b/lib/libeclat.h
@@ -70,6 +70,7 @@ int eclat_base64_decode(const unsigned char *input, size_t input_len,
struct ec2_param {
char *name;
char *value;
+ int encoded;
};
#define EC2_API_VERSION "2013-02-01"
@@ -82,15 +83,22 @@ struct ec2_query {
char *endpoint; /* endpoint */
char *uri; /* URI without parameters */
struct grecs_symtab *params; /* Query parameters */
- char *signature;
+ struct grecs_list *headers; /* Query headers */
+ char *region;
+ char *access_key;
unsigned long ttl; /* Time-to-live in seconds */
};
struct ec2_query *eclat_query_create(int flags, const char *endpoint,
- const char *uri);
+ const char *uri, char const *region,
+ char const *access_key);
void eclat_query_free(struct ec2_query *);
void eclat_query_add_param(struct ec2_query *q, const char *name,
const char *value);
+void eclat_query_add_param_encoded(struct ec2_query *q, const char *name,
+ const char *value);
+void eclat_query_add_header(struct ec2_query *q, const char *name,
+ const char *value);
void eclat_query_sign(struct ec2_query *req, char *secret, char *version);
diff --git a/lib/q2url.c b/lib/q2url.c
index f5d8863..da0ebdc 100644
--- a/lib/q2url.c
+++ b/lib/q2url.c
@@ -19,17 +19,24 @@
#include "libeclat.h"
#include "grecs.h"
+struct param_closure {
+ struct grecs_txtacc *acc;
+ int count;
+};
+
static int
add_param(void *sym, void *data)
{
struct ec2_param *p = sym;
- struct grecs_txtacc *acc = data;
+ struct param_closure *pc = data;
- grecs_txtacc_grow_char(acc, '&');
- grecs_txtacc_grow(acc, p->name, strlen(p->name));
+ if (pc->count)
+ grecs_txtacc_grow_char(pc->acc, '&');
+ ++pc->count;
+ grecs_txtacc_grow_string(pc->acc, p->name);
if (p->value) {
- grecs_txtacc_grow_char(acc, '=');
- grecs_txtacc_grow(acc, p->value, strlen(p->value));
+ grecs_txtacc_grow_char(pc->acc, '=');
+ grecs_txtacc_grow_string(pc->acc, p->value);
}
return 0;
@@ -40,7 +47,8 @@ eclat_query_to_url(struct ec2_query *req, char **post_params)
{
struct grecs_txtacc *acc;
char *ret = NULL, *p;
-
+ struct param_closure pc;
+
acc = grecs_txtacc_create();
grecs_txtacc_grow(acc, "http", 4);
@@ -57,16 +65,10 @@ eclat_query_to_url(struct ec2_query *req, char **post_params)
grecs_txtacc_grow_char(acc, '?');
}
- /* Add signature */
- grecs_txtacc_grow(acc, "Signature", sizeof("Signature")-1);
- grecs_txtacc_grow_char(acc, '=');
-
- urlencode(req->signature, strlen(req->signature), &p, NULL);
- grecs_txtacc_grow(acc, p, strlen(p));
- free(p);
-
/* Add other parameters */
- grecs_symtab_enumerate(req->params, add_param, acc);
+ pc.acc = acc;
+ pc.count = 0;
+ grecs_symtab_enumerate(req->params, add_param, &pc);
grecs_txtacc_grow_char(acc, 0);
@@ -79,3 +81,4 @@ eclat_query_to_url(struct ec2_query *req, char **post_params)
return ret;
}
+
diff --git a/lib/qaddparm.c b/lib/qaddparm.c
index 6048d32..e1e339a 100644
--- a/lib/qaddparm.c
+++ b/lib/qaddparm.c
@@ -20,7 +20,8 @@
#include "grecs.h"
void
-eclat_query_add_param(struct ec2_query *q, const char *name, const char *value)
+eclat_query_add_param0(struct ec2_query *q, const char *name,
+ const char *value, int encoded)
{
struct ec2_param *p, key;
int install = 1;
@@ -30,4 +31,49 @@ eclat_query_add_param(struct ec2_query *q, const char *name, const char *value)
if (!install)
free(p->value);
p->value = value ? grecs_strdup(value) : NULL;
+ p->encoded = encoded;
+}
+
+void
+eclat_query_add_param(struct ec2_query *q, const char *name, const char *value)
+{
+ eclat_query_add_param0(q, name, value, 0);
+}
+
+void
+eclat_query_add_param_encoded(struct ec2_query *q, const char *name,
+ const char *value)
+{
+ if (value) {
+ char *str;
+ urlencode(value, strlen(value), &str, NULL);
+ eclat_query_add_param0(q, name, str, 1);
+ free(str);
+ } else
+ eclat_query_add_param0(q, name, value, 1);
+}
+
+
+static void
+free_header(void *data)
+{
+ struct ec2_param *p = data;
+ free(p->name);
+ free(p->value);
+ free(p);
+}
+
+void
+eclat_query_add_header(struct ec2_query *q, const char *name, const char *value)
+{
+ struct ec2_param *ent;
+
+ if (!q->headers) {
+ q->headers = grecs_list_create();
+ q->headers->free_entry = free_header;
+ }
+ ent = grecs_malloc(sizeof(*ent));
+ ent->name = grecs_strdup(name);
+ ent->value = value ? grecs_strdup(value) : NULL;
+ grecs_list_append(q->headers, ent);
}
diff --git a/lib/qcreat.c b/lib/qcreat.c
index c90c3fe..32471a0 100644
--- a/lib/qcreat.c
+++ b/lib/qcreat.c
@@ -28,7 +28,8 @@ ec2_param_free(void *ptr)
}
struct ec2_query *
-eclat_query_create(int flags, const char *endpoint, const char *uri)
+eclat_query_create(int flags, const char *endpoint, const char *uri,
+ char const *region, char const *access_key)
{
struct ec2_query *q = grecs_zalloc(sizeof(*q));
q->flags = flags;
@@ -42,5 +43,7 @@ eclat_query_create(int flags, const char *endpoint, const char *uri)
q->endpoint = grecs_strdup(endpoint);
q->uri = grecs_strdup(uri);
q->ttl = 5;
+ q->region = grecs_strdup(region ? region : "us-east-1");
+ q->access_key = grecs_strdup(access_key);
return q;
}
diff --git a/lib/qencode.c b/lib/qencode.c
index a0f6ab6..d30ffd1 100644
--- a/lib/qencode.c
+++ b/lib/qencode.c
@@ -25,10 +25,11 @@ encode_param(void *sym, void *data)
struct ec2_param *p = sym;
char *enc;
- if (p->value) {
+ if (!p->encoded && p->value) {
urlencode(p->value, strlen(p->value), &enc, NULL);
free(p->value);
p->value = enc;
+ p->encoded = 1;
}
return 0;
}
diff --git a/lib/reqsign.c b/lib/reqsign.c
index d09b938..774f69b 100644
--- a/lib/reqsign.c
+++ b/lib/reqsign.c
@@ -52,6 +52,7 @@ querysign2(struct ec2_query *req, char *secret)
struct pname pn;
char *str;
char digest[SHA256_DIGEST_SIZE];
+ char *signature;
size_t siglen;
const char *verb;
char tsbuf[22];
@@ -60,6 +61,7 @@ querysign2(struct ec2_query *req, char *secret)
acc = grecs_txtacc_create();
/* Add default parameters */
+ eclat_query_add_param(req, "AWSAccessKeyId", req->access_key);
eclat_query_add_param(req, "SignatureMethod", "HmacSHA256");
eclat_query_add_param(req, "SignatureVersion", "2");
@@ -78,11 +80,11 @@ querysign2(struct ec2_query *req, char *secret)
qsort(pnames, n, sizeof(pnames[0]), compnames);
verb = (req->flags & EC2_QF_POST) ? "POST" : "GET";
- grecs_txtacc_grow(acc, verb, strlen(verb));
+ grecs_txtacc_grow_string(acc, verb);
grecs_txtacc_grow_char(acc, '\n');
- grecs_txtacc_grow(acc, req->endpoint, strlen(req->endpoint));
+ grecs_txtacc_grow_string(acc, req->endpoint);
grecs_txtacc_grow_char(acc, '\n');
- grecs_txtacc_grow(acc, req->uri, strlen(req->uri));
+ grecs_txtacc_grow_string(acc, req->uri);
grecs_txtacc_grow_char(acc, '\n');
/* Append a canonicalized query string */
@@ -95,10 +97,10 @@ querysign2(struct ec2_query *req, char *secret)
abort();
if (i != 0)
grecs_txtacc_grow_char(acc, '&');
- grecs_txtacc_grow(acc, p->name, strlen(p->name));
+ grecs_txtacc_grow_string(acc, p->name);
if (p->value) {
grecs_txtacc_grow_char(acc, '=');
- grecs_txtacc_grow(acc, p->value, strlen(p->value));
+ grecs_txtacc_grow_string(acc, p->value);
}
}
grecs_txtacc_grow_char(acc, 0);
@@ -107,8 +109,10 @@ querysign2(struct ec2_query *req, char *secret)
hmac_sha256(str, strlen(str), secret, strlen(secret), digest);
eclat_base64_encode((unsigned char *)digest, sizeof(digest),
- (unsigned char**) &req->signature, &siglen);
-
+ (unsigned char**) &signature, &siglen);
+ eclat_query_add_param_encoded(req, "Signature", signature);
+ free(signature);
+
grecs_txtacc_free(acc);
free(pnames);
@@ -119,10 +123,220 @@ querysign2(struct ec2_query *req, char *secret)
*/
}
+void
+eclat_hex_encode(unsigned char *input, size_t inlen,
+ char **poutput, size_t *poutlen)
+{
+ size_t l = inlen * 2;
+ char *p = grecs_malloc(l + 1);
+
+ *poutput = p;
+ *poutlen = l;
+
+ while (inlen--) {
+ static char xdig[] = "0123456789abcdef";
+ unsigned c = *input++;
+
+ *p++ = xdig[c >> 4];
+ *p++ = xdig[c & 0xf];
+ }
+}
+
+/* Ref. http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
+ */
static void
querysign4(struct ec2_query *req, char *secret)
{
- abort();
+ char **pnames;
+ struct pname pn;
+ size_t i, n;
+ struct grecs_txtacc *acc;
+ char digest[SHA256_DIGEST_SIZE];
+ size_t siglen;
+ const char *verb;
+ char tsbuf[22];
+ time_t t;
+ char const *p;
+ char const *payload;
+ unsigned char *plhash = NULL;
+ size_t plsize = 0;
+ char *string_to_sign;
+ static char algostr[] = "AWS4-HMAC-SHA256";
+ static char termstr[] = "aws4_request";
+ char *canonical_req;
+ char *signed_headers;
+ char *credential;
+ char *signature;
+ struct sha256_ctx ctx;
+ char *service;
+ size_t service_len;
+
+ service = req->endpoint;
+ service_len = strcspn(service, ".");
+
+ /* Create text accumulator */
+ acc = grecs_txtacc_create();
+
+ /* Timestamp */
+ time(&t);
+ strftime(tsbuf, sizeof(tsbuf), "%Y%m%dT%H%M%SZ", gmtime(&t));
+
+ /* Build credential */
+ grecs_txtacc_grow_string(acc, req->access_key);
+ grecs_txtacc_grow_char(acc, '/');
+ grecs_txtacc_grow(acc, tsbuf, 8); /* %Y%m%d part only */
+ grecs_txtacc_grow_char(acc, '/');
+ grecs_txtacc_grow_string(acc, req->region);
+ grecs_txtacc_grow_char(acc, '/');
+ grecs_txtacc_grow(acc, service, service_len);
+ grecs_txtacc_grow_char(acc, '/');
+ grecs_txtacc_grow_string(acc, termstr);
+ grecs_txtacc_grow_char(acc, 0);
+ credential = grecs_txtacc_finish(acc, 0);
+
+ /* Signed headers */
+ grecs_txtacc_grow_string(acc, "host");
+ grecs_txtacc_grow_char(acc, 0);
+ signed_headers = grecs_txtacc_finish(acc, 0);
+
+ eclat_query_add_header(req, "Host", req->endpoint);
+ if (!(req->flags & EC2_QF_POST)) {
+ eclat_query_add_param(req, "X-Amz-Algorithm", algostr);
+ eclat_query_add_param(req, "X-Amz-Date", tsbuf);
+ eclat_query_add_param(req, "X-Amz-SignedHeaders",
+ signed_headers);
+ eclat_query_add_param(req, "X-Amz-Credential", credential);
+ }
+
+ /* Encode the query */
+ eclat_query_encode(req);
+
+ /* Collect and sort parameter names */
+ n = grecs_symtab_count_entries(req->params);
+ pnames = grecs_calloc(n, sizeof(pnames[0]));
+ pn.i = 0;
+ pn.a = pnames;
+ grecs_symtab_enumerate(req->params, get_param_name, &pn);
+ qsort(pnames, n, sizeof(pnames[0]), compnames);
+
+ /* Create a canonical request */
+ verb = (req->flags & EC2_QF_POST) ? "POST" : "GET";
+ grecs_txtacc_grow_string(acc, verb);
+ grecs_txtacc_grow_char(acc, '\n');
+ grecs_txtacc_grow_string(acc, req->uri);
+ grecs_txtacc_grow_char(acc, '\n');
+ /* Append a canonicalized query string */
+ for (i = 0; i < n; i++) {
+ struct ec2_param *p, key;
+
+ key.name = pnames[i];
+ p = grecs_symtab_lookup_or_install(req->params, &key, NULL);
+ if (!p)
+ abort();
+ if (i != 0)
+ grecs_txtacc_grow_char(acc, '&');
+ grecs_txtacc_grow_string(acc, p->name);
+ if (p->value) {
+ grecs_txtacc_grow_char(acc, '=');
+ grecs_txtacc_grow_string(acc, p->value);
+ }
+ }
+ grecs_txtacc_grow_char(acc, '\n');
+
+ /* CanonicalHeaders */
+ grecs_txtacc_grow_string(acc, "host:");
+ grecs_txtacc_grow_string(acc, req->endpoint);
+ grecs_txtacc_grow_char(acc, '\n');
+ /* end of headers */
+ grecs_txtacc_grow_char(acc, '\n');
+ /* Signed Headers */
+ grecs_txtacc_grow_string(acc, signed_headers);
+ grecs_txtacc_grow_char(acc, '\n');
+ /* Payload hash */
+ if (req->flags & EC2_QF_POST)
+ /* FIXME: payload = req->query */;
+ else
+ payload = "";
+
+ sha256_init_ctx(&ctx);
+ sha256_process_bytes(payload, strlen(payload), &ctx);
+ sha256_finish_ctx(&ctx, digest);
+
+ eclat_hex_encode((unsigned char *)digest, sizeof(digest),
+ &plhash, &plsize);
+ grecs_txtacc_grow(acc, plhash, plsize);
+ free(plhash);
+
+ grecs_txtacc_grow_char(acc, 0);
+ canonical_req = grecs_txtacc_finish(acc, 0);
+
+ sha256_init_ctx(&ctx);
+ sha256_process_bytes(canonical_req, strlen(canonical_req), &ctx);
+ sha256_finish_ctx(&ctx, digest);
+ eclat_hex_encode((unsigned char *)digest, sizeof(digest),
+ &canonical_req, &plsize);
+
+ /* Create a string to sign */
+ grecs_txtacc_grow_string(acc, algostr);
+ grecs_txtacc_grow_char(acc, '\n');
+ grecs_txtacc_grow_string(acc, tsbuf);
+ grecs_txtacc_grow_char(acc, '\n');
+ /* credential scope: */
+ grecs_txtacc_grow(acc, tsbuf, 8); /* %Y%m%d part only */
+ grecs_txtacc_grow_char(acc, '/');
+ grecs_txtacc_grow_string(acc, req->region);
+ grecs_txtacc_grow_char(acc, '/');
+ grecs_txtacc_grow(acc, service, service_len);
+ grecs_txtacc_grow_char(acc, '/');
+ grecs_txtacc_grow_string(acc, termstr);
+ grecs_txtacc_grow_char(acc, '\n');
+
+ /* hashed request */
+ grecs_txtacc_grow_string(acc, canonical_req);
+
+ grecs_txtacc_grow_char(acc, 0);
+ string_to_sign = grecs_txtacc_finish(acc, 0);
+
+ /* Derive a signing key */
+ grecs_txtacc_grow_string(acc, "AWS4");
+ grecs_txtacc_grow_string(acc, secret);
+ grecs_txtacc_grow_char(acc, 0);
+ p = grecs_txtacc_finish(acc, 0);
+
+ hmac_sha256(tsbuf, 8, p, strlen(p), digest);
+ hmac_sha256(req->region, strlen(req->region), digest, sizeof(digest),
+ digest);
+ hmac_sha256(service, service_len, digest, sizeof(digest),
+ digest);
+ hmac_sha256(termstr, strlen(termstr), digest, sizeof(digest),
+ digest);
+
+ /* Calculate the signature */
+ hmac_sha256(string_to_sign, strlen(string_to_sign),
+ digest, sizeof(digest),
+ digest);
+ eclat_hex_encode((unsigned char *)digest, sizeof(digest),
+ &signature, &plsize);
+
+ if (req->flags & EC2_QF_POST) {
+ /* Build authorization header */
+ grecs_txtacc_grow_string(acc, algostr);
+ grecs_txtacc_grow_string(acc, " Credential=");
+ grecs_txtacc_grow_string(acc, credential);
+ grecs_txtacc_grow_string(acc, ", SignedHeaders=");
+ grecs_txtacc_grow_string(acc, signed_headers);
+ grecs_txtacc_grow_string(acc, ", Signature=");
+ grecs_txtacc_grow_string(acc, signature);
+ grecs_txtacc_grow_char(acc, 0);
+ p = grecs_txtacc_finish(acc, 0);
+ eclat_query_add_header(req, "Authorization", p);
+ } else {
+ eclat_query_add_param(req, "X-Amz-Signature", signature);
+ }
+ free(signature);
+ grecs_txtacc_free(acc);
+ /* Encode the query */
+ eclat_query_encode(req);
}
diff --git a/src/ec2map.c b/src/ec2map.c
index f7bda6b..eb1d37b 100644
--- a/src/ec2map.c
+++ b/src/ec2map.c
@@ -146,7 +146,8 @@ ec2_map_get(int dbg, int dir, void *data, const char *key, char **return_value)
struct grecs_node *tree, *node;
int rc;
- q = eclat_query_create(use_ssl ? EC2_QF_HTTPS : 0, endpoint, "/");
+ q = eclat_query_create(use_ssl ? EC2_QF_HTTPS : 0, endpoint, "/",
+ region_name, access_key);
eclat_query_add_param(q, "Action", map->action);
env[0] = "key";
diff --git a/src/eclat.c b/src/eclat.c
index 3791573..566a5ba 100644
--- a/src/eclat.c
+++ b/src/eclat.c
@@ -644,7 +644,8 @@ eclat_do_command(eclat_command_env_t *env, struct eclat_command *command,
if (!(command->flags & CMD_NOQRY)) {
env->query = eclat_query_create(use_ssl ? EC2_QF_HTTPS : 0,
- endpoint, "/");
+ endpoint, "/",
+ region_name, access_key);
}
if (command->tag)
diff --git a/src/util.c b/src/util.c
index 1a0a6d0..641d304 100644
--- a/src/util.c
+++ b/src/util.c
@@ -222,17 +222,44 @@ eclat_send_query(CURL *curl, struct ec2_query *q)
char *url;
CURLcode res;
int rc = 0;
+ struct curl_slist *headers = NULL;
- eclat_query_add_param(q, "AWSAccessKeyId", access_key);
-
+ /* Prepare the request */
eclat_query_sign(q, secret_key, signature_version);
url = eclat_query_to_url(q, NULL);
-
- debug(ECLAT_DEBCAT_MAIN, 1, ("using URL: %s", url));
curl_easy_setopt(curl, CURLOPT_URL, url);
-
+ debug(ECLAT_DEBCAT_MAIN, 1, ("using URL: %s", url));
free(url);
- eclat_query_free(q);
+ if (q->headers) {
+ struct grecs_list_entry *ep;
+ struct grecs_txtacc *acc;
+ int rc;
+
+ acc = grecs_txtacc_create();
+
+ for (ep = q->headers->head; ep; ep = ep->next) {
+ struct ec2_param *p = ep->data;
+ char *str;
+
+ grecs_txtacc_grow_string(acc, p->name);
+ grecs_txtacc_grow_char(acc, ':');
+ grecs_txtacc_grow_string(acc, p->value);
+ grecs_txtacc_grow_char(acc, 0);
+ str = grecs_txtacc_finish(acc, 0);
+ debug(ECLAT_DEBCAT_MAIN, 1, ("HDR: %s", str));
+
+ headers = curl_slist_append(headers, str);
+ grecs_txtacc_free_string(acc, str);
+ }
+
+ rc = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
+ grecs_txtacc_free(acc);
+
+ if (rc)
+ die(EX_SOFTWARE,
+ "failed to add headers: %s",
+ curl_easy_strerror(rc));
+ }
if (dry_run_mode)
debug(ECLAT_DEBCAT_MAIN, 1, ("not sending request"));
@@ -244,6 +271,8 @@ eclat_send_query(CURL *curl, struct ec2_query *q)
rc = 1;
}
}
+ eclat_query_free(q);
+ curl_slist_free_all(headers);
return rc;
}

Return to:

Send suggestions and report system problems to the System administrator.