From 2129f5ddf65db4ee015263a3b3c0c4f4fef941fb Mon Sep 17 00:00:00 2001 From: ale <ale@incal.net> Date: Thu, 19 Jun 2014 09:34:53 +0100 Subject: [PATCH] move buffer-management code to its own module, with tests; fix memory corruption bug in quote() --- pam/.gitignore | 3 +++ pam/Makefile.am | 9 ++++++-- pam/auth_client.c | 46 +++++------------------------------------ pam/auth_client_test.cc | 19 +++++++++++++++-- pam/cbuf.c | 23 +++++++++++++++++++++ pam/cbuf.h | 21 +++++++++++++++++++ pam/cbuf_test.cc | 23 +++++++++++++++++++++ pam/configure.ac | 2 +- 8 files changed, 100 insertions(+), 46 deletions(-) create mode 100644 pam/cbuf.c create mode 100644 pam/cbuf.h create mode 100644 pam/cbuf_test.cc diff --git a/pam/.gitignore b/pam/.gitignore index 204f95f..cb79b5c 100644 --- a/pam/.gitignore +++ b/pam/.gitignore @@ -1,6 +1,7 @@ *.in aclocal.m4 autom4te.cache +compile config.guess config.sub configure @@ -26,5 +27,7 @@ libtool stamp-* Makefile auth_client_test +cbuf_test test-driver test-suite.log +.dirstamp diff --git a/pam/Makefile.am b/pam/Makefile.am index 87da913..3dfff69 100644 --- a/pam/Makefile.am +++ b/pam/Makefile.am @@ -8,7 +8,8 @@ pam_LTLIBRARIES = pam_authclient.la noinst_LIBRARIES = libgtest.a libauthclient_la_SOURCES = \ - auth_client.c auth_client.h + auth_client.c auth_client.h \ + cbuf.c cbuf.h libauthclient_la_includedir = $(includedir)/authclient libauthclient_la_include_HEADERS = auth_client.h @@ -18,7 +19,8 @@ pam_authclient_la_LDFLAGS = -module pam_authclient_la_LIBADD = libauthclient.la check_PROGRAMS = \ - auth_client_test + auth_client_test \ + cbuf_test TESTS = $(check_PROGRAMS) @@ -26,6 +28,9 @@ auth_client_test_CPPFLAGS = $(GTEST_CPPFLAGS) auth_client_test_LDADD = libauthclient.la libgtest.a auth_client_test_SOURCES = auth_client_test.cc +cbuf_test_CPPFLAGS = $(GTEST_CPPFLAGS) +cbuf_test_LDADD = libauthclient.la libgtest.a +cbuf_test_SOURCES = cbuf_test.cc # GTest sources. diff --git a/pam/auth_client.c b/pam/auth_client.c index dab6226..373d318 100644 --- a/pam/auth_client.c +++ b/pam/auth_client.c @@ -9,6 +9,7 @@ #include <sys/stat.h> #include <curl/curl.h> #include "auth_client.h" +#include "cbuf.h" #define CURL_CHECK(x) { \ int _err = (x); if (_err != CURLE_OK) { return auth_client_err_from_curl(_err); } \ @@ -106,44 +107,6 @@ const char *auth_client_strerror(int err) { } } -/* - * 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; - size_t alloc, size; -}; - -static void cbuf_init(struct cbuf *cbuf, size_t alloc) { - cbuf->buf = (char *)malloc(alloc); - cbuf->alloc = alloc; - cbuf->size = 0; -} - -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++) { @@ -165,6 +128,7 @@ static char *quote(const char *s) { *optr++ = *s; } } + *optr = '\0'; return out; } @@ -177,14 +141,13 @@ static size_t responsebuf_callback(void *contents, size_t size, size_t nmemb, vo } static void post_field_add(struct cbuf *form_data, const char *key, const char *value) { - char *quoted_key = quote(key), *quoted_value = quote(value); + char *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, key, strlen(key)); cbuf_append(form_data, "=", 1); cbuf_append(form_data, quoted_value, strlen(quoted_value)); - free(quoted_key); free(quoted_value); } @@ -217,6 +180,7 @@ int auth_client_authenticate(auth_client_t ac, post_field_add(&form, "shard", shard); } curl_easy_setopt(ac->c, CURLOPT_POSTFIELDS, form.buf); + curl_easy_setopt(ac->c, CURLOPT_POSTFIELDSIZE, form.size); // Set request headers. curl_slist_append(headers, "Content-Type: application/x-form-www-urlencoded"); diff --git a/pam/auth_client_test.cc b/pam/auth_client_test.cc index b8251e4..b3f0352 100644 --- a/pam/auth_client_test.cc +++ b/pam/auth_client_test.cc @@ -8,8 +8,8 @@ extern "C" { static const char *server = NULL; -static const char *ssl_ca = "../authserv/test/testca/ca.pem"; -static const char *ssl_cert = "../authserv/test/testca/certs/client.pem"; +static const char *ssl_ca = "../authserv/test/testca/public/ca.pem"; +static const char *ssl_cert = "../authserv/test/testca/public/certs/client.pem"; static const char *ssl_key = "../authserv/test/testca/private/client.key"; static const char *ssl_bad_ca = "../authserv/test/testca-bad/ca.pem"; static const char *ssl_bad_cert = "../authserv/test/testca-bad/certs/client.pem"; @@ -59,6 +59,21 @@ TEST_F(AuthClientTest, AuthOK) { << ", server=" << server; } +TEST_F(AuthClientTest, ManyAuthOK) { + int result; + + for (int i = 0; i < 3; i++) { + + result = auth_client_set_certificate(ac, ssl_ca, ssl_cert, ssl_key); + EXPECT_EQ(AC_OK, result) << "set_certificate() error: " << auth_client_strerror(result); + + result = auth_client_authenticate(ac, "user", "pass", NULL, "127.0.0.1", NULL); + EXPECT_EQ(AC_OK, result) << "authenticate() error: " << auth_client_strerror(result) + << ", server=" << server; + } + +} + TEST_F(AuthClientTest, AuthFail) { int result; diff --git a/pam/cbuf.c b/pam/cbuf.c new file mode 100644 index 0000000..96a0230 --- /dev/null +++ b/pam/cbuf.c @@ -0,0 +1,23 @@ + +#include <stdlib.h> +#include <memory.h> +#include "cbuf.h" + + +void cbuf_init(struct cbuf *cbuf, size_t alloc) { + cbuf->buf = (char *)malloc(1); + cbuf->buf[0] = '\0'; + cbuf->alloc = cbuf->size = 0; +} + +void cbuf_free(struct cbuf *cbuf) { + free(cbuf->buf); +} + +void cbuf_append(struct cbuf *cbuf, const char *data, size_t size) { + size_t new_alloc = cbuf->alloc + size; + cbuf->buf = (char *)realloc(cbuf->buf, new_alloc + 1); + memcpy(cbuf->buf + cbuf->size, data, size); + cbuf->alloc = cbuf->size = new_alloc; + cbuf->buf[cbuf->size] = '\0'; +} diff --git a/pam/cbuf.h b/pam/cbuf.h new file mode 100644 index 0000000..5485490 --- /dev/null +++ b/pam/cbuf.h @@ -0,0 +1,21 @@ +#ifndef __libauthclient_cbuf_h +#define __libauthclient_cbuf_h 1 + +#include <sys/types.h> + +/* + * 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; + size_t alloc, size; +}; + +void cbuf_init(struct cbuf *cbuf, size_t alloc); +void cbuf_free(struct cbuf *cbuf); +void cbuf_append(struct cbuf *cbuf, const char *data, size_t size); + +#endif diff --git a/pam/cbuf_test.cc b/pam/cbuf_test.cc new file mode 100644 index 0000000..81e3306 --- /dev/null +++ b/pam/cbuf_test.cc @@ -0,0 +1,23 @@ +// Tests for cbuf.c. + +#include <stdlib.h> +#include <string> +#include "gtest/gtest.h" +extern "C" { +#include "cbuf.h" +} + +TEST(Cbuf, Append) { + struct cbuf c; + cbuf_init(&c, 0); + cbuf_append(&c, "hello, ", 7); + cbuf_append(&c, "world", 5); + std::string a(c.buf); + EXPECT_EQ("hello, world", a); + cbuf_free(&c); +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/pam/configure.ac b/pam/configure.ac index 237ce3f..267505c 100644 --- a/pam/configure.ac +++ b/pam/configure.ac @@ -2,7 +2,7 @@ AC_INIT([libauthclient], [0.1], [info@autistici.org]) AC_CONFIG_SRCDIR([auth_client.h]) dnl AC_LANG(C) -AM_INIT_AUTOMAKE([foreign]) +AM_INIT_AUTOMAKE([foreign subdir-objects]) AC_CONFIG_HEADERS(config.h) AC_CONFIG_MACRO_DIR([m4]) AC_DISABLE_STATIC -- GitLab