diff options
-rw-r--r-- | client/file.c | 20 | ||||
-rw-r--r-- | client/internal.h | 25 | ||||
-rw-r--r-- | client/remctl.c | 53 | ||||
-rw-r--r-- | client/wallet.c | 34 | ||||
-rw-r--r-- | tests/client/basic-t.in | 9 | ||||
-rw-r--r-- | tests/data/basic.conf | 1 | ||||
-rwxr-xr-x | tests/data/cmd-fake | 9 |
7 files changed, 100 insertions, 51 deletions
diff --git a/client/file.c b/client/file.c index c9edf3a..66d5f63 100644 --- a/client/file.c +++ b/client/file.c @@ -115,14 +115,13 @@ get_file(struct remctl *r, const char *prefix, const char *type, /* - * Read all of a file into memory and return the contents as a newly allocated - * string. Handles a file name of "-" to mean standard input. Dies on any - * failure. - * - * This will need modification later when we want to handle nul characters. + * Read all of a file into memory and return the contents in newly allocated + * memory. Returns the size of the file contents in the second argument if + * it's not NULL. Handles a file name of "-" to mean standard input. Dies on + * any failure. */ -char * -read_file(const char *name) +void * +read_file(const char *name, size_t *length) { char *contents; size_t size, offset; @@ -140,7 +139,7 @@ read_file(const char *name) sysdie("cannot open file %s", name); if (fstat(fd, &st) < 0) sysdie("cannot stat file %s", name); - size = st.st_size + 1; + size = st.st_size; contents = xmalloc(size); } offset = 0; @@ -157,8 +156,7 @@ read_file(const char *name) offset += status; } while (status > 0); close(fd); - contents[offset] = '\0'; - if (memchr(contents, '\0', offset) != NULL) - die("cannot yet handle file data containing nul characters"); + if (length != NULL) + *length = offset; return contents; } diff --git a/client/internal.h b/client/internal.h index 7fe962b..d82196c 100644 --- a/client/internal.h +++ b/client/internal.h @@ -17,6 +17,7 @@ /* Forward declarations to avoid unnecessary includes. */ struct remctl; +struct iovec; BEGIN_DECLS @@ -29,14 +30,18 @@ void kinit(krb5_context, const char *principal); void kdestroy(void); /* - * Given a remctl object, run a remctl command. If data is non-NULL, saves - * the standard output from the command into data with the length in length. - * Otherwise, prints it to standard output. Either way, prints standard error - * output and errors to standard error and returns the exit status or 255 for - * a remctl internal error. + * Given a remctl object, either a NULL-terminated array of strings or an + * array of iovecs and the number of elements in the array, and optional data + * and size output variables, run a remctl command. If data is non-NULL, + * saves the standard output from the command into data with the length in + * length. Otherwise, prints it to standard output. Either way, prints + * standard error output and errors to standard error and returns the exit + * status or 255 for a remctl internal error. */ int run_command(struct remctl *, const char **command, char **data, size_t *length); +int run_commandv(struct remctl *, const struct iovec *command, size_t count, + char **data, size_t *length); /* * Check whether an object exists using the exists wallet interface. Returns @@ -91,12 +96,12 @@ void write_srvtab(krb5_context, const char *srvtab, const char *principal, const char *keytab); /* - * Read all of a file into memory and return the contents as a newly allocated - * string. Handles a file name of "-" to mean standard input. Dies on any - * failure. This will need modification later when we want to handle nul - * characters. + * Read all of a file into memory and return the contents in newly allocated + * memory. Handles a file name of "-" to mean standard input. Stores the + * length of the data in the second argument if it isn't NULL. Dies on any + * failure. */ -char *read_file(const char *); +void *read_file(const char *, size_t *); END_DECLS diff --git a/client/remctl.c b/client/remctl.c index a4ff097..5a541d5 100644 --- a/client/remctl.c +++ b/client/remctl.c @@ -18,15 +18,14 @@ /* - * Given a remctl connection and a command, run the command. - * - * If data is non-NULL, save the output in it and return the length in length. - * Otherwise, send any output to stdout. Either way, send error output to - * stderr, and return the exit status (or 255 if there is an error). + * Retrieve the results of a remctl command, which should be issued prior to + * calling this function. If data is non-NULL, save the output in it and + * return the length in length. Otherwise, send any output to stdout. Either + * way, send error output to stderr, and return the exit status (or 255 if + * there is an error). */ -int -run_command(struct remctl *r, const char **command, char **data, - size_t *length) +static int +command_results(struct remctl *r, char **data, size_t *length) { struct remctl_output *output; int status = 255; @@ -35,10 +34,6 @@ run_command(struct remctl *r, const char **command, char **data, *data = NULL; if (length != NULL) *length = 0; - if (!remctl_command(r, command)) { - warn("%s", remctl_error(r)); - return 255; - } do { output = remctl_output(r); switch (output->type) { @@ -74,6 +69,40 @@ run_command(struct remctl *r, const char **command, char **data, /* + * Given a remctl connection and a NULL-terminated array of strings, run the + * command and return the results using command_results, optionally putting + * output into the data variable. + */ +int +run_command(struct remctl *r, const char **command, char **data, + size_t *length) +{ + if (!remctl_command(r, command)) { + warn("%s", remctl_error(r)); + return 255; + } + return command_results(r, data, length); +} + + +/* + * Given a remctl connection, an array of iovecs, and the length of the array, + * run the command and return the results using command_results, optionally + * putting output into the data variable. + */ +int +run_commandv(struct remctl *r, const struct iovec *command, size_t count, + char **data, size_t *length) +{ + if (!remctl_commandv(r, command, count)) { + warn("%s", remctl_error(r)); + return 255; + } + return command_results(r, data, length); +} + + +/* * Check whether an object exists using the exists wallet interface. Returns * true if it does, false if it doesn't, and dies on remctl errors. */ diff --git a/client/wallet.c b/client/wallet.c index ce0f4e7..dc4fe18 100644 --- a/client/wallet.c +++ b/client/wallet.c @@ -135,7 +135,8 @@ main(int argc, char *argv[]) krb5_error_code retval; struct options options; int option, i, status; - const char **command; + struct iovec *command; + size_t count, length; const char *file = NULL; const char *srvtab = NULL; struct remctl *r; @@ -241,24 +242,27 @@ main(int argc, char *argv[]) status = get_file(r, options.type, argv[1], argv[2], file); } } else { + count = argc + 1; if (strcmp(argv[0], "store") == 0) { if (argc > 4) die("too many arguments"); - else if (argc == 4) - command = xmalloc(sizeof(char *) * (argc + 2)); - else - command = xmalloc(sizeof(char *) * (argc + 3)); - } else - command = xmalloc(sizeof(char *) * (argc + 2)); - command[0] = options.type; - for (i = 0; i < argc; i++) - command[i + 1] = argv[i]; + else if (argc < 4) + count++; + } + command = xmalloc(sizeof(struct iovec) * count); + command[0].iov_base = (char *) options.type; + command[0].iov_len = strlen(options.type); + for (i = 0; i < argc; i++) { + command[i + 1].iov_base = argv[i]; + command[i + 1].iov_len = strlen(argv[i]); + } if (strcmp(argv[0], "store") == 0 && argc < 4) { - command[argc + 1] = read_file(file == NULL ? "-" : file); - command[argc + 2] = NULL; - } else - command[argc + 1] = NULL; - status = run_command(r, command, NULL, NULL); + if (file == NULL) + file = "-"; + command[argc + 1].iov_base = read_file(file, &length); + command[argc + 1].iov_len = length; + } + status = run_commandv(r, command, count, NULL, NULL); } remctl_close(r); krb5_free_context(ctx); diff --git a/tests/client/basic-t.in b/tests/client/basic-t.in index 30bc004..1ae3a70 100644 --- a/tests/client/basic-t.in +++ b/tests/client/basic-t.in @@ -50,7 +50,7 @@ if [ $? != 0 ] ; then elif [ -z '@REMCTLD@' ] ; then skip_all 'No remctld found' else - plan 34 + plan 36 fi remctld_start '@REMCTLD@' "$SOURCE/data/basic.conf" wallet="$BUILD/../client/wallet" @@ -141,6 +141,13 @@ ok_program 'store from a file' 0 '' \ "$wallet" -f store-input store file fake-test ok '...and the correct data was stored' cmp store-output store-correct rm -f store-input store-output store-correct +printf 'This is store input\000with a nul character' > store-input +echo 'file fake-nul' > store-correct +cat store-input >> store-correct +ok_program 'store from a file with a nul' 0 '' \ + "$wallet" -f store-input store file fake-nul +ok '...and the correct data was stored' cmp store-output store-correct +rm -f store-input store-output store-correct # Test various other client functions and errors. ok_program 'get output to stdout' 0 'This is a fake keytab.' \ diff --git a/tests/data/basic.conf b/tests/data/basic.conf index 3280ce9..5f3c2a3 100644 --- a/tests/data/basic.conf +++ b/tests/data/basic.conf @@ -1,3 +1,4 @@ # remctl configuration for wallet client tests. +fake-wallet store data/cmd-fake stdin=last ANYUSER fake-wallet ALL data/cmd-fake ANYUSER diff --git a/tests/data/cmd-fake b/tests/data/cmd-fake index 199bd57..add72fc 100755 --- a/tests/data/cmd-fake +++ b/tests/data/cmd-fake @@ -82,10 +82,15 @@ get) ;; store) if [ -n "$3" ] ; then - echo "Too many arguments" >&2 + echo 'Too many arguments' >&2 + exit 1 + fi + if [ -n "$2" ] ; then + echo 'stdin remctld configuration not supported' >&2 exit 1 fi - printf "$type $1\n$2" > store-output + printf "$type $1\n" > store-output + cat >> store-output ;; show) if [ -n "$2" ] ; then |