diff options
author | Martin Willi <martin@revosec.ch> | 2013-11-21 12:19:20 +0100 |
---|---|---|
committer | Martin Willi <martin@revosec.ch> | 2014-01-23 15:55:32 +0100 |
commit | 1c4a3459f72da4391c1befe22e62356d838af46d (patch) | |
tree | a60e5be4cf8c95c05b891f84df5ffa1069ec65ef | |
parent | 595b6d9a828538072dcf65c276b848a02698fdfe (diff) | |
download | strongswan-1c4a3459f72da4391c1befe22e62356d838af46d.tar.bz2 strongswan-1c4a3459f72da4391c1befe22e62356d838af46d.tar.xz |
chunk: Use dynamically allocated buffer in chunk_from_fd()
When acting on files, we can use fstat() to estimate the buffer size. On
non-file FDs, we dynamically increase an allocated buffer.
Additionally we slightly change the function signature to properly handle
zero-length files and add appropriate unit tests.
-rw-r--r-- | src/libstrongswan/tests/suites/test_chunk.c | 84 | ||||
-rw-r--r-- | src/libstrongswan/utils/chunk.c | 53 | ||||
-rw-r--r-- | src/libstrongswan/utils/chunk.h | 7 | ||||
-rw-r--r-- | src/pki/commands/issue.c | 16 | ||||
-rw-r--r-- | src/pki/commands/keyid.c | 9 | ||||
-rw-r--r-- | src/pki/commands/print.c | 7 | ||||
-rw-r--r-- | src/pki/commands/pub.c | 9 | ||||
-rw-r--r-- | src/pki/commands/req.c | 7 | ||||
-rw-r--r-- | src/pki/commands/self.c | 8 | ||||
-rw-r--r-- | src/pki/commands/verify.c | 8 |
10 files changed, 183 insertions, 25 deletions
diff --git a/src/libstrongswan/tests/suites/test_chunk.c b/src/libstrongswan/tests/suites/test_chunk.c index 7971f5ca8..3492a7f7b 100644 --- a/src/libstrongswan/tests/suites/test_chunk.c +++ b/src/libstrongswan/tests/suites/test_chunk.c @@ -17,8 +17,13 @@ #include "test_suite.h" #include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> #include <utils/chunk.h> +#include <threading/thread.h> /******************************************************************************* * utilities @@ -813,6 +818,79 @@ START_TEST(test_chunk_map) END_TEST /******************************************************************************* + * test for chunk_from_fd + */ + +START_TEST(test_chunk_from_fd_file) +{ + chunk_t in, contents = chunk_from_chars(0x01,0x02,0x03,0x04,0x05); + char *path = "/tmp/strongswan-chunk-fd-test"; + int fd; + + ck_assert(chunk_write(contents, path, "chunk_fd", 022, TRUE)); + + fd = open(path, O_RDONLY); + ck_assert(fd != -1); + + ck_assert(chunk_from_fd(fd, &in)); + close(fd); + ck_assert_msg(chunk_equals(in, contents), "%B", &in); + unlink(path); + free(in.ptr); +} +END_TEST + +START_TEST(test_chunk_from_fd_skt) +{ + chunk_t in, contents = chunk_from_chars(0x01,0x02,0x03,0x04,0x05); + int s[2]; + + ck_assert(socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0); + ck_assert(write(s[1], contents.ptr, contents.len) == contents.len); + close(s[1]); + ck_assert_msg(chunk_from_fd(s[0], &in), "%s", strerror(errno)); + close(s[0]); + ck_assert_msg(chunk_equals(in, contents), "%B", &in); + free(in.ptr); +} +END_TEST + +#define FROM_FD_COUNT 8192 + +void *chunk_from_fd_run(void *data) +{ + int i, fd = (uintptr_t)data; + + for (i = 0; i < FROM_FD_COUNT; i++) + { + ck_assert(write(fd, &i, sizeof(i)) == sizeof(i)); + } + close(fd); + return NULL; +} + +START_TEST(test_chunk_from_fd_huge) +{ + thread_t *thread; + chunk_t in; + int s[2], i; + + ck_assert(socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0); + + thread = thread_create(chunk_from_fd_run, (void*)(uintptr_t)s[1]); + ck_assert_msg(chunk_from_fd(s[0], &in), "%s", strerror(errno)); + ck_assert_int_eq(in.len, FROM_FD_COUNT * sizeof(i)); + for (i = 0; i < FROM_FD_COUNT; i++) + { + ck_assert_int_eq(((int*)in.ptr)[i], i); + } + thread->join(thread); + close(s[0]); + free(in.ptr); +} +END_TEST + +/******************************************************************************* * printf_hook tests */ @@ -933,6 +1011,12 @@ Suite *chunk_suite_create() tcase_add_test(tc, test_chunk_map); suite_add_tcase(s, tc); + tc = tcase_create("chunk_from_fd"); + tcase_add_test(tc, test_chunk_from_fd_file); + tcase_add_test(tc, test_chunk_from_fd_skt); + tcase_add_test(tc, test_chunk_from_fd_huge); + suite_add_tcase(s, tc); + tc = tcase_create("printf_hook"); tcase_add_loop_test(tc, test_printf_hook_hash, 0, countof(printf_hook_data)); tcase_add_loop_test(tc, test_printf_hook_plus, 0, countof(printf_hook_data)); diff --git a/src/libstrongswan/utils/chunk.c b/src/libstrongswan/utils/chunk.c index 5c00c5b32..e308418df 100644 --- a/src/libstrongswan/utils/chunk.c +++ b/src/libstrongswan/utils/chunk.c @@ -247,33 +247,62 @@ bool chunk_write(chunk_t chunk, char *path, char *label, mode_t mask, bool force /** * Described in header. */ -chunk_t chunk_from_fd(int fd) +bool chunk_from_fd(int fd, chunk_t *out) { - char buf[8096]; - char *pos = buf; - ssize_t len, total = 0; + struct stat sb; + char *buf, *tmp; + ssize_t len, total = 0, bufsize; + + if (fstat(fd, &sb) == 0 && S_ISREG(sb.st_mode)) + { + bufsize = sb.st_size; + } + else + { + bufsize = 256; + } + buf = malloc(bufsize); + if (!buf) + { /* for huge files */ + return FALSE; + } while (TRUE) { - len = read(fd, pos, buf + sizeof(buf) - pos); + len = read(fd, buf + total, bufsize - total); if (len < 0) { - DBG1(DBG_LIB, "reading from file descriptor failed: %s", - strerror(errno)); - return chunk_empty; + free(buf); + return FALSE; } if (len == 0) { break; } total += len; - if (total == sizeof(buf)) + if (total == bufsize) { - DBG1(DBG_LIB, "buffer too small to read from file descriptor"); - return chunk_empty; + bufsize *= 2; + tmp = realloc(buf, bufsize); + if (!tmp) + { + free(buf); + return FALSE; + } + buf = tmp; } } - return chunk_clone(chunk_create(buf, total)); + if (total == 0) + { + free(buf); + buf = NULL; + } + else if (total < bufsize) + { + buf = realloc(buf, total); + } + *out = chunk_create(buf, total); + return TRUE; } /** diff --git a/src/libstrongswan/utils/chunk.h b/src/libstrongswan/utils/chunk.h index 92a96ffba..1228da30e 100644 --- a/src/libstrongswan/utils/chunk.h +++ b/src/libstrongswan/utils/chunk.h @@ -102,10 +102,13 @@ bool chunk_write(chunk_t chunk, char *path, char *label, mode_t mask, bool force /** * Store data read from FD into a chunk * + * On error, errno is set appropriately. + * * @param fd file descriptor to read from - * @return chunk or chunk_empty on failure + * @param chunk chunk receiving allocated buffer + * @return TRUE if successful, FALSE on failure */ -chunk_t chunk_from_fd(int fd); +bool chunk_from_fd(int fd, chunk_t *chunk); /** * mmap() a file to a chunk diff --git a/src/pki/commands/issue.c b/src/pki/commands/issue.c index 000f63d1a..d5c33b89f 100644 --- a/src/pki/commands/issue.c +++ b/src/pki/commands/issue.c @@ -14,6 +14,7 @@ */ #include <time.h> +#include <errno.h> #include "pki.h" @@ -382,7 +383,12 @@ static int issue() { chunk_t chunk; - chunk = chunk_from_fd(0); + if (!chunk_from_fd(0, &chunk)) + { + fprintf(stderr, "%s: ", strerror(errno)); + error = "reading certificate request failed"; + goto end; + } cert_req = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_PKCS10_REQUEST, BUILD_BLOB, chunk, BUILD_END); @@ -425,7 +431,12 @@ static int issue() { chunk_t chunk; - chunk = chunk_from_fd(0); + if (!chunk_from_fd(0, &chunk)) + { + fprintf(stderr, "%s: ", strerror(errno)); + error = "reading public key failed"; + goto end; + } public = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ANY, BUILD_BLOB, chunk, BUILD_END); free(chunk.ptr); @@ -562,4 +573,3 @@ static void __attribute__ ((constructor))reg() } }); } - diff --git a/src/pki/commands/keyid.c b/src/pki/commands/keyid.c index 353670e32..64bb3cc2c 100644 --- a/src/pki/commands/keyid.c +++ b/src/pki/commands/keyid.c @@ -13,6 +13,8 @@ * for more details. */ +#include <errno.h> + #include "pki.h" #include <credentials/certificates/certificate.h> @@ -89,7 +91,11 @@ static int keyid() { chunk_t chunk; - chunk = chunk_from_fd(0); + if (!chunk_from_fd(0, &chunk)) + { + fprintf(stderr, "reading input failed: %s\n", strerror(errno)); + return 1; + } cred = lib->creds->create(lib->creds, type, subtype, BUILD_BLOB, chunk, BUILD_END); free(chunk.ptr); @@ -165,4 +171,3 @@ static void __attribute__ ((constructor))reg() } }); } - diff --git a/src/pki/commands/print.c b/src/pki/commands/print.c index 2261e44ff..077c1ef3e 100644 --- a/src/pki/commands/print.c +++ b/src/pki/commands/print.c @@ -22,6 +22,7 @@ #include <selectors/traffic_selector.h> #include <time.h> +#include <errno.h> /** * Print public key information @@ -510,7 +511,11 @@ static int print() { chunk_t chunk; - chunk = chunk_from_fd(0); + if (!chunk_from_fd(0, &chunk)) + { + fprintf(stderr, "reading input failed: %s\n", strerror(errno)); + return 1; + } cred = lib->creds->create(lib->creds, type, subtype, BUILD_BLOB, chunk, BUILD_END); free(chunk.ptr); diff --git a/src/pki/commands/pub.c b/src/pki/commands/pub.c index 7f88055ef..260044c4e 100644 --- a/src/pki/commands/pub.c +++ b/src/pki/commands/pub.c @@ -13,6 +13,8 @@ * for more details. */ +#include <errno.h> + #include "pki.h" #include <credentials/certificates/certificate.h> @@ -108,7 +110,11 @@ static int pub() { chunk_t chunk; - chunk = chunk_from_fd(0); + if (!chunk_from_fd(0, &chunk)) + { + fprintf(stderr, "reading input failed: %s\n", strerror(errno)); + return 1; + } cred = lib->creds->create(lib->creds, type, subtype, BUILD_BLOB, chunk, BUILD_END); free(chunk.ptr); @@ -186,4 +192,3 @@ static void __attribute__ ((constructor))reg() } }); } - diff --git a/src/pki/commands/req.c b/src/pki/commands/req.c index 628463e7b..64609597d 100644 --- a/src/pki/commands/req.c +++ b/src/pki/commands/req.c @@ -16,6 +16,7 @@ */ #include <time.h> +#include <errno.h> #include "pki.h" @@ -118,7 +119,11 @@ static int req() { chunk_t chunk; - chunk = chunk_from_fd(0); + if (!chunk_from_fd(0, &chunk)) + { + fprintf(stderr, "reading private key failed: %s\n", strerror(errno)); + return 1; + } private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type, BUILD_BLOB, chunk, BUILD_END); free(chunk.ptr); diff --git a/src/pki/commands/self.c b/src/pki/commands/self.c index 6bf0b1353..c28c9c291 100644 --- a/src/pki/commands/self.c +++ b/src/pki/commands/self.c @@ -14,6 +14,7 @@ */ #include <time.h> +#include <errno.h> #include "pki.h" @@ -273,7 +274,12 @@ static int self() { chunk_t chunk; - chunk = chunk_from_fd(0); + if (!chunk_from_fd(0, &chunk)) + { + fprintf(stderr, "%s: ", strerror(errno)); + error = "reading private key failed"; + goto end; + } private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type, BUILD_BLOB, chunk, BUILD_END); free(chunk.ptr); diff --git a/src/pki/commands/verify.c b/src/pki/commands/verify.c index 96b2b5065..f30dda94d 100644 --- a/src/pki/commands/verify.c +++ b/src/pki/commands/verify.c @@ -13,6 +13,8 @@ * for more details. */ +#include <errno.h> + #include "pki.h" #include <credentials/certificates/certificate.h> @@ -57,7 +59,11 @@ static int verify() { chunk_t chunk; - chunk = chunk_from_fd(0); + if (!chunk_from_fd(0, &chunk)) + { + fprintf(stderr, "reading certificate failed: %s\n", strerror(errno)); + return 1; + } cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, BUILD_BLOB, chunk, BUILD_END); free(chunk.ptr); |