Skip to content
Snippets Groups Projects
Commit 1ea7ab05 authored by ale's avatar ale
Browse files

use x-form-www-urlencoded for POST (more appropriate than multipart)

parent 2f28ee41
No related branches found
No related tags found
No related merge requests found
......@@ -9,7 +9,7 @@
#include <curl/curl.h>
#include "auth_client.h"
static const char *kAuthApiPath = "/api/v1/auth";
static const char *kAuthApiPath = "/api/1/auth";
struct auth_client {
CURL *c;
......@@ -68,86 +68,130 @@ const char *auth_client_strerror(int err) {
}
}
struct responsebuf {
/*
* A dynamically sized memory buffer that can be appended to, and will
* grow accordingly. It is optimized to perform well for a specific
* size (the initial allocation).
*/
struct cbuf {
char *buf;
int size;
size_t alloc, size;
};
static void responsebuf_init(struct responsebuf *rbuf) {
rbuf->buf = (char *)malloc(1);
rbuf->size = 0;
static void cbuf_init(struct cbuf *cbuf, size_t alloc) {
cbuf->buf = (char *)malloc(alloc);
cbuf->alloc = alloc;
cbuf->size = 0;
}
static void responsebuf_free(struct responsebuf *rbuf) {
free(rbuf->buf);
static void cbuf_free(struct cbuf *cbuf) {
free(cbuf->buf);
}
static void cbuf_append(struct cbuf *cbuf, void *data, size_t size) {
// Resize if necessary.
size_t required_alloc = cbuf->size + size + 1;
if (required_alloc > cbuf->alloc) {
size_t new_alloc = cbuf->alloc;
while (new_alloc < required_alloc) {
new_alloc *= 2;
}
cbuf->buf = (char *)realloc(cbuf->buf, new_alloc);
cbuf->alloc = new_alloc;
}
// Append data to the buffer.
memcpy(cbuf->buf + cbuf->size, data, size);
cbuf->size += size;
cbuf->buf[cbuf->size] = '\0';
}
static char *quote(const char *s) {
char *out = (char *)malloc(strlen(s) * 3 + 1), *optr;
for (optr = out; *s; s++) {
switch (*s) {
case ';':
case '/':
case '?':
case ':':
case '@':
case '&':
case '=':
case '+':
case '$':
case ',':
sprintf(optr, "%%%02X", (int)(*s));
optr += 3;
break;
default:
*optr++ = *s;
}
}
return out;
}
static size_t responsebuf_callback(void *contents, size_t size, size_t nmemb, void *userp) {
size_t realsize = size * nmemb;
struct responsebuf *rbuf = (struct responsebuf *)userp;
struct cbuf *cbuf = (struct cbuf *)userp;
rbuf->buf = (char *)realloc(rbuf->buf, rbuf->size + realsize + 1);
if (rbuf->buf == NULL) {
return 0;
}
memcpy(rbuf->buf + rbuf->size, contents, realsize);
rbuf->size += realsize;
rbuf->buf[rbuf->size] = 0;
cbuf_append(cbuf, contents, realsize);
return realsize;
}
static void post_field_add(struct cbuf *form_data, const char *key, const char *value) {
char *quoted_key = quote(key), *quoted_value = quote(value);
if (form_data->size != 0) {
cbuf_append(form_data, "&", 1);
}
cbuf_append(form_data, quoted_key, strlen(quoted_key));
cbuf_append(form_data, "&", 1);
cbuf_append(form_data, quoted_value, strlen(quoted_value));
free(quoted_key);
free(quoted_value);
}
int auth_client_authenticate(auth_client_t ac,
const char *username,
const char *password,
const char *otp_token,
const char *source_ip) {
struct curl_httppost *formpost = NULL;
struct curl_httppost *formlast = NULL;
struct responsebuf rbuf;
struct curl_slist *headers = NULL;
struct cbuf form;
struct cbuf responsebuf;
CURLcode res;
int retval;
// Build the POST request contents.
curl_formadd(&formpost, &formlast,
CURLFORM_COPYNAME, "service",
CURLFORM_COPYCONTENTS, ac->service,
CURLFORM_END);
curl_formadd(&formpost, &formlast,
CURLFORM_COPYNAME, "username",
CURLFORM_COPYCONTENTS, username,
CURLFORM_END);
cbuf_init(&form, 256);
post_field_add(&form, "service", ac->service);
post_field_add(&form, "username", username);
if (password) {
curl_formadd(&formpost, &formlast,
CURLFORM_COPYNAME, "password",
CURLFORM_COPYCONTENTS, password,
CURLFORM_END);
post_field_add(&form, "password", password);
}
if (otp_token) {
curl_formadd(&formpost, &formlast,
CURLFORM_COPYNAME, "otp",
CURLFORM_COPYCONTENTS, otp_token,
CURLFORM_END);
post_field_add(&form, "otp", otp_token);
}
if (source_ip) {
curl_formadd(&formpost, &formlast,
CURLFORM_COPYNAME, "source_ip",
CURLFORM_COPYCONTENTS, source_ip,
CURLFORM_END);
post_field_add(&form, "source_ip", source_ip);
}
curl_easy_setopt(ac->c, CURLOPT_HTTPPOST, formpost);
curl_easy_setopt(ac->c, CURLOPT_POSTFIELDS, form.buf);
// Set request headers.
curl_slist_append(headers, "Content-Type: application/x-form-www-urlencoded");
curl_easy_setopt(ac->c, CURLOPT_HTTPHEADER, headers);
responsebuf_init(&rbuf);
cbuf_init(&responsebuf, 64);
curl_easy_setopt(ac->c, CURLOPT_WRITEFUNCTION, responsebuf_callback);
curl_easy_setopt(ac->c, CURLOPT_WRITEDATA, (void *)&rbuf);
curl_easy_setopt(ac->c, CURLOPT_WRITEDATA, (void *)&responsebuf);
res = curl_easy_perform(ac->c);
if (res == CURLE_OK) {
// Check the auth server response.
if (!strncmp(rbuf.buf, "OK", 2)) {
if (!strncmp(responsebuf.buf, "OK", 2)) {
retval = AC_OK;
} else if (!strncmp(rbuf.buf, "OTP_REQUIRED", 12)) {
} else if (!strncmp(responsebuf.buf, "OTP_REQUIRED", 12)) {
retval = AC_ERR_OTP_REQUIRED;
} else if (!strncmp(rbuf.buf, "ERROR", 5)) {
} else if (!strncmp(responsebuf.buf, "ERROR", 5)) {
retval = AC_ERR_AUTHENTICATION_FAILURE;
} else {
retval = AC_ERR_BAD_RESPONSE;
......@@ -156,8 +200,9 @@ int auth_client_authenticate(auth_client_t ac,
retval = auth_client_err_from_curl(res);
}
curl_formfree(formpost);
responsebuf_free(&rbuf);
cbuf_free(&form);
cbuf_free(&responsebuf);
curl_slist_free_all(headers);
return retval;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment