Add support for keyctl_alter()
Add support for keyctl_alter() in the library:
long keyctl_alter(key_serial_t id,
const char *command,
const void *data,
size_t data_size);
and expose this through the keyctl command:
keyctl alter <key> <type> <command> [<data>]
echo <data> | keyctl palter <key> <type> <command>
Signed-off-by: David Howells <dhowells@redhat.com>
diff --git a/keyctl.c b/keyctl.c
index 7e5ce6f..12826bd 100644
--- a/keyctl.c
+++ b/keyctl.c
@@ -66,10 +66,13 @@
static nr void act_keyctl_purge(int argc, char *argv[]);
static nr void act_keyctl_invalidate(int argc, char *argv[]);
static nr void act_keyctl_get_persistent(int argc, char *argv[]);
+static nr void act_keyctl_alter(int argc, char *argv[]);
+static nr void act_keyctl_palter(int argc, char *argv[]);
const struct command commands[] = {
{ act_keyctl___version, "--version", "" },
{ act_keyctl_add, "add", "<type> <desc> <data> <keyring>" },
+ { act_keyctl_alter, "alter", "<key> <type> <cmd> [<data>]" },
{ act_keyctl_chgrp, "chgrp", "<key> <gid>" },
{ act_keyctl_chown, "chown", "<key> <uid>" },
{ act_keyctl_clear, "clear", "<keyring>" },
@@ -83,6 +86,7 @@
{ act_keyctl_new_session, "new_session", "" },
{ act_keyctl_newring, "newring", "<name> <keyring>" },
{ act_keyctl_padd, "padd", "<type> <desc> <keyring>" },
+ { act_keyctl_palter, "palter", "<key> <type> <cmd>" },
{ act_keyctl_pinstantiate, "pinstantiate","<key> <keyring>" },
{ act_keyctl_pipe, "pipe", "<key>" },
{ act_keyctl_prequest2, "prequest2", "<type> <desc> [<dest_keyring>]" },
@@ -1627,6 +1631,112 @@
/*****************************************************************************/
/*
+ * Alter a key
+ */
+static void act_keyctl_alter(int argc, char *argv[])
+{
+ key_serial_t key;
+ size_t data_size, tsz, csz;
+ char *command, *data;
+ long ret;
+
+ if (argc < 4 || argc > 5)
+ format();
+
+ tsz = strlen(argv[2]);
+ csz = strlen(argv[3]);
+ if (!tsz || !csz ||
+ tsz >= 4096 - 1 ||
+ csz > 4096 - (1 + tsz + 1))
+ goto cmd_limit;
+
+ if (memchr(argv[2], ' ', tsz) != NULL)
+ format();
+
+ if (argc == 5) {
+ data = argv[4];
+ data_size = strlen(argv[4]);
+ if (data_size > 1024 * 1024)
+ goto data_limit;
+ } else {
+ data = NULL;
+ data_size = 0;
+ }
+
+ key = get_key_id(argv[1]);
+
+ command = malloc(4096);
+ if (!command)
+ error("malloc");
+
+ memcpy(command, argv[2], tsz);
+ command[tsz] = ' ';
+ memcpy(command + tsz + 1, argv[3] + 1, csz);
+
+ ret = keyctl_alter(key, command, data, data_size);
+ if (ret < 0)
+ error("keyctl_alter");
+
+ exit(0);
+
+cmd_limit:
+ fprintf(stderr, "Type and command strings are limited to 4KB-1 in total\n");
+ exit(2);
+
+data_limit:
+ fprintf(stderr, "The data is limited to 1MB in total\n");
+ exit(2);
+}
+
+/*****************************************************************************/
+/*
+ * Alter a key with data read from stdin.
+ */
+static void act_keyctl_palter(int argc, char *argv[])
+{
+ key_serial_t key;
+ size_t data_size, tsz, csz;
+ char *command, *data;
+ long ret;
+
+ if (argc != 4)
+ format();
+
+ tsz = strlen(argv[2]);
+ csz = strlen(argv[3]);
+ if (!tsz || !csz ||
+ tsz >= 4096 - 1 ||
+ csz > 4096 - (1 + tsz + 1))
+ goto cmd_limit;
+
+ if (memchr(argv[2], ' ', tsz) != NULL)
+ format();
+
+ data = grab_stdin(&data_size);
+
+ key = get_key_id(argv[1]);
+
+ command = malloc(4096);
+ if (!command)
+ error("malloc");
+
+ memcpy(command, argv[2], tsz);
+ command[tsz] = ' ';
+ memcpy(command + tsz + 1, argv[3] + 1, csz);
+
+ ret = keyctl_alter(key, command, data, data_size);
+ if (ret < 0)
+ error("keyctl_alter");
+
+ exit(0);
+
+cmd_limit:
+ fprintf(stderr, "Type and command strings are limited to 4KB-1 in total\n");
+ exit(2);
+}
+
+/*****************************************************************************/
+/*
* parse a key identifier
*/
static key_serial_t get_key_id(char *arg)
diff --git a/keyutils.c b/keyutils.c
index 8856c8a..359073c 100644
--- a/keyutils.c
+++ b/keyutils.c
@@ -234,6 +234,14 @@
return keyctl(KEYCTL_GET_PERSISTENT, uid, id);
}
+long keyctl_alter(key_serial_t id,
+ const char *command,
+ const void *data,
+ size_t data_size)
+{
+ return keyctl(KEYCTL_ALTER, id, command, data, data_size);
+}
+
/*****************************************************************************/
/*
* fetch key description into an allocated buffer
diff --git a/keyutils.h b/keyutils.h
index b9ff7e8..b4aada6 100644
--- a/keyutils.h
+++ b/keyutils.h
@@ -98,6 +98,7 @@
#define KEYCTL_INSTANTIATE_IOV 20 /* instantiate a partially constructed key */
#define KEYCTL_INVALIDATE 21 /* invalidate a key */
#define KEYCTL_GET_PERSISTENT 22 /* get a user's persistent keyring */
+#define KEYCTL_ALTER 23 /* alter a key */
/*
* syscall wrappers
@@ -152,6 +153,10 @@
key_serial_t ringid);
extern long keyctl_invalidate(key_serial_t id);
extern long keyctl_get_persistent(uid_t uid, key_serial_t id);
+extern long keyctl_alter(key_serial_t id,
+ const char *command,
+ const void *data,
+ size_t data_size);
/*
* utilities
diff --git a/keyutils.spec b/keyutils.spec
index 3312f84..895e085 100644
--- a/keyutils.spec
+++ b/keyutils.spec
@@ -2,7 +2,7 @@
%define verminor 5.9
%define version %{vermajor}.%{verminor}
%define libapivermajor 1
-%define libapiversion %{libapivermajor}.5
+%define libapiversion %{libapivermajor}.6
# % define buildid .local
diff --git a/man/keyctl.1 b/man/keyctl.1
index 4d6cbe5..1abc089 100644
--- a/man/keyctl.1
+++ b/man/keyctl.1
@@ -90,6 +90,10 @@
\fBkeyctl\fR purge -s <type> <desc>
.br
\fBkeyctl\fR get_persistent <keyring> [<uid>]
+.br
+\fBkeyctl\fR alter <key> <type> <cmd> [<data>]
+.br
+\fBkeyctl\fR palter <key> <type> <cmd>
.SH DESCRIPTION
This program is used to control the key management facility in various ways
using a variety of subcommands.
@@ -745,6 +749,22 @@
If a UID other than the process's real or effective UIDs is specified, then an
error will be given if the process does not have the CAP_SETUID capability.
.P
+(*) \fBAlter a key in a type-dependent fashion\fR
+.P
+\fBkeyctl\fR alter <key> <type> <cmd> [<data>]
+.br
+\fBkeyctl\fR palter <key> <type> <cmd>
+.P
+This command performs a type-dependent alteration of the nominated key. The
+key to be operated on is supplied as the first regular argument, then the
+expected key type name and then the name of the command.
+.P
+In the \fBalter\fR variant of the command, supplementary data may be passed as
+an additional argument.
+.P
+The \fBpalter\fR variant of the command reads the supplementary data from stdin
+rather than taking it from the command line.
+.P
.SH ERRORS
.P
There are a number of common errors returned by this program:
diff --git a/man/keyctl.3 b/man/keyctl.3
index 440c270..1bcdfcf 100644
--- a/man/keyctl.3
+++ b/man/keyctl.3
@@ -33,6 +33,8 @@
.RE
.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
.SH KEYCTL FUNCTIONS
+.BR keyctl_alter (3)
+.br
.BR keyctl_assume_authority (3)
.br
.BR keyctl_chown (3)
diff --git a/man/keyctl_alter.3 b/man/keyctl_alter.3
new file mode 100644
index 0000000..9259347
--- /dev/null
+++ b/man/keyctl_alter.3
@@ -0,0 +1,94 @@
+.\"
+.\" Copyright (C) 2014 Red Hat, Inc. All Rights Reserved.
+.\" Written by David Howells (dhowells@redhat.com)
+.\"
+.\" This program is free software; you can redistribute it and/or
+.\" modify it under the terms of the GNU General Public License
+.\" as published by the Free Software Foundation; either version
+.\" 2 of the License, or (at your option) any later version.
+.\"
+.TH KEYCTL_ALTER 3 "10 Mar 2014" Linux "Linux Key Management Calls"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH NAME
+keyctl_alter \- Alter a key
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SYNOPSIS
+.nf
+.B #include <keyutils.h>
+.sp
+.BI "long keyctl_alter(key_serial_t " key ", const char *" command ","
+.BI " const void *" data ", size_t " data_size ");"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH DESCRIPTION
+.BR keyctl_alter ()
+allows the user to make some type-specific alteration to a
+.IR key .
+.P
+The caller must have
+.B write
+permission on the key to perform this.
+.P
+The
+.B command
+argument is a printable string that begins with the name of the target type,
+then a space then a command indicating the alteration to be performed. The
+command string, including the NUL terminator, may not exceed 4KB in size.
+.P
+The
+.BR data " and " data_size
+arguments indicate an optional buffer of supplementary data for use by the
+command. The supplementary data may not exceed 1MB in size. It need not be
+NUL terminated.
+.P
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH RETURN VALUE
+On success
+.BR keyctl_alter ()
+returns 0.
+.P
+On error, the value
+.B -1
+will be returned and errno will have been set to an appropriate error.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH ERRORS
+.TP
+.B ENOKEY
+The key specified is invalid.
+.TP
+.B EKEYEXPIRED
+The key specified has expired.
+.TP
+.B EKEYREVOKED
+The key specified had been revoked.
+.TP
+.B EACCES
+The key exists, but is not
+.B writable
+by the calling process.
+.TP
+.B EOPNOTSUPP
+The key type does not support the control operation.
+.P
+The key type may also return other errors in response to the given command.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH LINKING
+This is a library function that can be found in
+.IR libkeyutils .
+When linking,
+.B -lkeyutils
+should be specified to the linker.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SEE ALSO
+.BR keyctl (1),
+.br
+.BR add_key (2),
+.br
+.BR keyctl (2),
+.br
+.BR request_key (2),
+.br
+.BR keyctl (3),
+.br
+.BR keyutils (7),
+.br
+.BR keyrings (7)
diff --git a/tests/keyctl/alter/bad-args/runtest.sh b/tests/keyctl/alter/bad-args/runtest.sh
new file mode 100644
index 0000000..eca6e70
--- /dev/null
+++ b/tests/keyctl/alter/bad-args/runtest.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+
+. ../../../prepare.inc.sh
+. ../../../toolbox.inc.sh
+
+
+# ---- do the actual testing ----
+
+result=PASS
+echo "++++ BEGINNING TEST" >$OUTPUTFILE
+
+# check that an empty key id fails correctly
+marker "CHECK EMPTY KEY ID"
+alter_key --fail "" some-type do-something
+expect_error EINVAL
+
+# check that an invalid key id fails correctly
+marker "CHECK INVALID KEY ID"
+alter_key --fail 0 some-type do-something
+expect_error EINVAL
+
+# check that an empty key type fails correctly
+marker "CHECK EMPTY KEY TYPE"
+alter_key --fail @s "" do-something
+expect_error EINVAL
+
+# check that an empty command fails correctly
+marker "CHECK EMPTY COMMAND"
+alter_key --fail @s some-type ""
+expect_error EINVAL
+
+# check that an empty data argument fails correctly
+marker "CHECK EMPTY DATA"
+alter_key --fail @s some-type do-something ""
+expect_error EINVAL
+
+echo "++++ FINISHED TEST: $result" >>$OUTPUTFILE
+
+# --- then report the results in the database ---
+toolbox_report_result $TEST $result
diff --git a/tests/keyctl/alter/noargs/runtest.sh b/tests/keyctl/alter/noargs/runtest.sh
new file mode 100644
index 0000000..53c312b
--- /dev/null
+++ b/tests/keyctl/alter/noargs/runtest.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+. ../../../prepare.inc.sh
+. ../../../toolbox.inc.sh
+
+
+# ---- do the actual testing ----
+
+result=PASS
+echo "++++ BEGINNING TEST" >$OUTPUTFILE
+
+# check that no arguments fails correctly
+marker "ADD NO ARGS"
+expect_args_error keyctl alter
+
+# check that one argument fails correctly
+marker "ADD ONE ARG"
+expect_args_error keyctl alter @s
+
+# check that two arguments fail correctly
+marker "ADD TWO ARGS"
+expect_args_error keyctl alter @s keyring
+
+# check that five arguments fail correctly
+marker "ADD FIVE ARGS"
+expect_args_error keyctl alter @s keyring do-something some-data foo
+
+echo "++++ FINISHED TEST: $result" >>$OUTPUTFILE
+
+# --- then report the results in the database ---
+toolbox_report_result $TEST $result
diff --git a/tests/keyctl/palter/bad-args/runtest.sh b/tests/keyctl/palter/bad-args/runtest.sh
new file mode 100644
index 0000000..6253cf6
--- /dev/null
+++ b/tests/keyctl/palter/bad-args/runtest.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+
+. ../../../prepare.inc.sh
+. ../../../toolbox.inc.sh
+
+
+# ---- do the actual testing ----
+
+result=PASS
+echo "++++ BEGINNING TEST" >$OUTPUTFILE
+
+# check that an empty key id fails correctly
+marker "CHECK EMPTY KEY ID"
+palter_key --fail some-data "" some-type do-something
+expect_error EINVAL
+
+# check that an invalid key id fails correctly
+marker "CHECK INVALID KEY ID"
+palter_key --fail some-data 0 some-type do-something
+expect_error EINVAL
+
+# check that an empty key type fails correctly
+marker "CHECK EMPTY KEY TYPE"
+palter_key --fail some-data @s "" do-something
+expect_error EINVAL
+
+# check that an empty command fails correctly
+marker "CHECK EMPTY COMMAND"
+palter_key --fail some-data @s some-type ""
+expect_error EINVAL
+
+# check that an empty data argument fails correctly
+marker "CHECK EMPTY DATA"
+palter_key --fail "" @s some-type do-something
+expect_error EINVAL
+
+echo "++++ FINISHED TEST: $result" >>$OUTPUTFILE
+
+# --- then report the results in the database ---
+toolbox_report_result $TEST $result
diff --git a/tests/keyctl/palter/noargs/runtest.sh b/tests/keyctl/palter/noargs/runtest.sh
new file mode 100644
index 0000000..bd394b6
--- /dev/null
+++ b/tests/keyctl/palter/noargs/runtest.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+. ../../../prepare.inc.sh
+. ../../../toolbox.inc.sh
+
+
+# ---- do the actual testing ----
+
+result=PASS
+echo "++++ BEGINNING TEST" >$OUTPUTFILE
+
+# check that no arguments fails correctly
+marker "ADD NO ARGS"
+expect_args_error keyctl palter
+
+# check that one argument fails correctly
+marker "ADD ONE ARG"
+expect_args_error keyctl palter @s
+
+# check that two arguments fail correctly
+marker "ADD TWO ARGS"
+expect_args_error keyctl palter @s keyring
+
+# check that five arguments fail correctly
+marker "ADD FOUR ARGS"
+expect_args_error keyctl palter @s keyring do-something foo
+
+echo "++++ FINISHED TEST: $result" >>$OUTPUTFILE
+
+# --- then report the results in the database ---
+toolbox_report_result $TEST $result
diff --git a/tests/toolbox.inc.sh b/tests/toolbox.inc.sh
index 88608a3..d0e4e14 100644
--- a/tests/toolbox.inc.sh
+++ b/tests/toolbox.inc.sh
@@ -1053,6 +1053,53 @@
###############################################################################
#
+# Alter a key
+#
+###############################################################################
+function alter_key ()
+{
+ my_exitval=0
+ if [ "x$1" = "x--fail" ]
+ then
+ my_exitval=1
+ shift
+ fi
+
+ echo keyctl alter "$@" >>$OUTPUTFILE
+ keyctl alter "$@" >>$OUTPUTFILE 2>&1
+ if [ $? != $my_exitval ]
+ then
+ failed
+ fi
+}
+
+###############################################################################
+#
+# Alter a key, piping in the data
+#
+###############################################################################
+function palter_key ()
+{
+ my_exitval=0
+ if [ "x$1" = "x--fail" ]
+ then
+ my_exitval=1
+ shift
+ fi
+
+ data="$1"
+ shift
+
+ echo echo -n $data \| keyctl palter "$@" >>$OUTPUTFILE
+ echo -n $data | keyctl palter "$@" >>$OUTPUTFILE 2>&1
+ if [ $? != $my_exitval ]
+ then
+ failed
+ fi
+}
+
+###############################################################################
+#
# Make sure we sleep at least N seconds
#
###############################################################################
diff --git a/version.lds b/version.lds
index 5f07463..27653a9 100644
--- a/version.lds
+++ b/version.lds
@@ -61,3 +61,9 @@
find_key_by_type_and_desc;
} KEYUTILS_1.4;
+
+KEYUTILS_1.6 {
+ /* management functions */
+ keyctl_control;
+
+} KEYUTILS_1.5;