aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2019-05-30 15:23:02 +0100
committerDavid Howells <dhowells@redhat.com>2019-06-19 13:42:09 +0100
commitf9761a6a9abec83c7fd7a9cbc96237f7cd344808 (patch)
treed861c399235c4ebb6934c82aac884b84bbccf4b5
parent0f70f77491bb6976a2bf761224fec1a9cc6cfb87 (diff)
downloadkeyutils-f9761a6a9abec83c7fd7a9cbc96237f7cd344808.tar.gz
Provide the ability to query subsystem capabilities
Provide the ability to query the capabilities of the keyrings subsystem. Signed-off-by: David Howells <dhowells@redhat.com>
-rw-r--r--keyctl.c48
-rw-r--r--keyutils.c50
-rw-r--r--keyutils.h15
-rw-r--r--man/keyctl.156
-rw-r--r--man/keyctl.32
-rw-r--r--man/keyctl_capabilities.3109
-rw-r--r--tests/keyctl/supports/bad-args/runtest.sh23
-rw-r--r--tests/keyctl/supports/valid/runtest.sh23
-rw-r--r--tests/toolbox.inc.sh28
-rw-r--r--version.lds1
10 files changed, 355 insertions, 0 deletions
diff --git a/keyctl.c b/keyctl.c
index c9c1740..4c5d91c 100644
--- a/keyctl.c
+++ b/keyctl.c
@@ -79,6 +79,7 @@ static nr void act_keyctl_pkey_decrypt(int argc, char *argv[]);
static nr void act_keyctl_pkey_sign(int argc, char *argv[]);
static nr void act_keyctl_pkey_verify(int argc, char *argv[]);
static nr void act_keyctl_move(int argc, char *argv[]);
+static nr void act_keyctl_supports(int argc, char *argv[]);
const struct command commands[] = {
{ act_keyctl___version, "--version", "" },
@@ -129,6 +130,7 @@ const struct command commands[] = {
{ NULL, "session", "<name> [<prog> <arg1> <arg2> ...]" },
{ act_keyctl_setperm, "setperm", "<key> <mask>" },
{ act_keyctl_show, "show", "[-x] [<keyring>]" },
+ { act_keyctl_supports, "supports", "[<cap>]" },
{ act_keyctl_timeout, "timeout", "<key> <timeout>" },
{ act_keyctl_unlink, "unlink", "<key> [<keyring>]" },
{ act_keyctl_update, "update", "<key> <data>" },
@@ -2098,6 +2100,52 @@ static void act_keyctl_move(int argc, char *argv[])
exit(0);
}
+struct capability_def {
+ const char *name; /* Textual name of capability */
+ unsigned int index; /* Index in capabilities array */
+ unsigned char mask; /* Mask on capabilities array element */
+};
+
+static const struct capability_def capabilities[] = {
+ { "capabilities", 0, KEYCTL_CAPS0_CAPABILITIES },
+ { "persistent_keyrings", 0, KEYCTL_CAPS0_PERSISTENT_KEYRINGS },
+ { "dh_compute", 0, KEYCTL_CAPS0_DIFFIE_HELLMAN },
+ { "public_key", 0, KEYCTL_CAPS0_PUBLIC_KEY },
+ { "big_key_type", 0, KEYCTL_CAPS0_BIG_KEY },
+ { "key_invalidate", 0, KEYCTL_CAPS0_INVALIDATE },
+ { "restrict_keyring", 0, KEYCTL_CAPS0_RESTRICT_KEYRING },
+ { "move_key", 0, KEYCTL_CAPS0_MOVE },
+ {}
+};
+
+/*
+ * Detect/list capabilities.
+ */
+static void act_keyctl_supports(int argc, char *argv[])
+{
+ const struct capability_def *p;
+ unsigned char caps[256];
+
+ if (argc < 1 || argc > 2)
+ format();
+
+ if (keyctl_capabilities(caps, sizeof(caps)) < 0)
+ error("keyctl_capabilities");
+
+ if (argc == 1) {
+ for (p = capabilities; p->name; p++)
+ printf("have_%s=%c\n",
+ p->name,
+ (caps[p->index] & p->mask) ? '1' : '0');
+ exit(0);
+ } else {
+ for (p = capabilities; p->name; p++)
+ if (strcmp(argv[1], p->name) == 0)
+ exit((caps[p->index] & p->mask) ? 0 : 1);
+ exit(3);
+ }
+}
+
/*****************************************************************************/
/*
* parse a key identifier
diff --git a/keyutils.c b/keyutils.c
index bb90cc8..9c37256 100644
--- a/keyutils.c
+++ b/keyutils.c
@@ -335,6 +335,56 @@ long keyctl_move(key_serial_t id,
return keyctl(KEYCTL_MOVE, id, from_ringid, to_ringid, flags);
}
+long keyctl_capabilities(unsigned char *buffer, size_t buflen)
+{
+ long n;
+
+ n = keyctl(KEYCTL_CAPABILITIES, buffer, buflen);
+ if (n != -1 || errno != EOPNOTSUPP)
+ return n;
+
+ /* Emulate the operation */
+ if (buflen > 0) {
+ memset(buffer, 0, buflen);
+
+ errno = 0;
+ keyctl_get_persistent(-1, 0);
+ if (errno != EOPNOTSUPP)
+ buffer[0] |= KEYCTL_CAPS0_PERSISTENT_KEYRINGS;
+
+ errno = 0;
+ keyctl_dh_compute(0, 0, 0, NULL, 0);
+ if (errno != EOPNOTSUPP)
+ buffer[0] |= KEYCTL_CAPS0_DIFFIE_HELLMAN;
+
+ errno = 0;
+ keyctl_pkey_query(0, NULL, NULL);
+ if (errno != EOPNOTSUPP)
+ buffer[0] |= KEYCTL_CAPS0_PUBLIC_KEY;
+
+ /* Can't emulate KEYCTL_CAPS0_BIG_KEY without a valid
+ * destination keyring.
+ */
+
+ errno = 0;
+ keyctl_invalidate(0);
+ if (errno != EOPNOTSUPP)
+ buffer[0] |= KEYCTL_CAPS0_INVALIDATE;
+
+ errno = 0;
+ keyctl_restrict_keyring(0, NULL, NULL);
+ if (errno != EOPNOTSUPP)
+ buffer[0] |= KEYCTL_CAPS0_RESTRICT_KEYRING;
+
+ errno = 0;
+ keyctl_move(0, 0, 0, 0);
+ if (errno != EOPNOTSUPP)
+ buffer[0] |= KEYCTL_CAPS0_MOVE;
+ }
+
+ return sizeof(unsigned char);
+}
+
/*****************************************************************************/
/*
* fetch key description into an allocated buffer
diff --git a/keyutils.h b/keyutils.h
index d3ef0e4..887cbf2 100644
--- a/keyutils.h
+++ b/keyutils.h
@@ -107,6 +107,7 @@ typedef uint32_t key_perm_t;
#define KEYCTL_PKEY_VERIFY 28 /* Verify a public key signature */
#define KEYCTL_RESTRICT_KEYRING 29 /* Restrict keys allowed to link to a keyring */
#define KEYCTL_MOVE 30 /* Move keys between keyrings */
+#define KEYCTL_CAPABILITIES 31 /* Find capabilities of keyrings subsystem */
/* keyctl structures */
struct keyctl_dh_params {
@@ -150,6 +151,19 @@ struct keyctl_pkey_params {
#define KEYCTL_MOVE_EXCL 0x00000001 /* Do not displace from the to-keyring */
/*
+ * Capabilities flags. The capabilities list is an array of 8-bit integers;
+ * each integer can carry up to 8 flags.
+ */
+#define KEYCTL_CAPS0_CAPABILITIES 0x01 /* KEYCTL_CAPABILITIES supported */
+#define KEYCTL_CAPS0_PERSISTENT_KEYRINGS 0x02 /* Persistent keyrings enabled */
+#define KEYCTL_CAPS0_DIFFIE_HELLMAN 0x04 /* Diffie-Hellman ops enabled */
+#define KEYCTL_CAPS0_PUBLIC_KEY 0x08 /* Public key ops enabled */
+#define KEYCTL_CAPS0_BIG_KEY 0x10 /* big_key-type enabled */
+#define KEYCTL_CAPS0_INVALIDATE 0x20 /* KEYCTL_INVALIDATE supported */
+#define KEYCTL_CAPS0_RESTRICT_KEYRING 0x40 /* KEYCTL_RESTRICT_KEYRING supported */
+#define KEYCTL_CAPS0_MOVE 0x80 /* KEYCTL_MOVE supported */
+
+/*
* syscall wrappers
*/
extern key_serial_t add_key(const char *type,
@@ -234,6 +248,7 @@ extern long keyctl_move(key_serial_t id,
key_serial_t from_ringid,
key_serial_t to_ringid,
unsigned int flags);
+extern long keyctl_capabilities(unsigned char *buffer, size_t buflen);
/*
* utilities
diff --git a/man/keyctl.1 b/man/keyctl.1
index bf841aa..1c8f569 100644
--- a/man/keyctl.1
+++ b/man/keyctl.1
@@ -13,6 +13,8 @@ keyctl \- key management facility control
.SH SYNOPSIS
\fBkeyctl\fR \-\-version
.br
+\fBkeyctl\fR supports [<cap>]
+.br
\fBkeyctl\fR show [\-x] [<keyring>]
.br
\fBkeyctl\fR add <type> <desc> <data> <keyring>
@@ -177,6 +179,60 @@ $ keyctl \-\-version
keyctl from keyutils\-1.5.3 (Built 2011\-08\-24)
.fi
.RE
+.SS Query subsystem capabilities
+\fBkeyctl\fR supports [<cap>]
+
+This command can list the available capabilities:
+
+.RS
+.nf
+$ keyctl supports
+have_capabilities=0
+have_persistent_keyrings=1
+have_dh_compute=1
+have_public_key=1
+...
+.fi
+.RE
+.P
+And it can query a capability:
+
+.RS
+.nf
+$ keyctl supports pkey
+echo $?
+0
+.fi
+.RE
+
+which returns 0 if the capability is supported, 1 if it isn't and 3 if the
+name is not recognised. The capabilities supported are:
+.TP
+.B capabilities
+The kernel supports capability querying. If not, the other capabilities will
+be queried as best libkeyutils can manage.
+.TP
+.B persistent_keyrings
+The kernel supports persistent keyrings.
+.TP
+.B dh_compute
+The kernel supports Diffie-Hellman computation operations.
+.TP
+.B public_key
+The kernel supports public key operations.
+.TP
+.B big_key_type
+The kernel supports the big_key key type.
+.TP
+.B key_invalidate
+The kernel supports the invalidate key operaiton.
+.TP
+.B restrict_keyring
+The kernel supports the restrict_keyring operation.
+.TP
+.B move_key
+The kernel supports the move key operation.
+
.SS Show process keyrings
\fBkeyctl show [\-x] [<keyring>]\fR
diff --git a/man/keyctl.3 b/man/keyctl.3
index dcef9c6..b0f5fdc 100644
--- a/man/keyctl.3
+++ b/man/keyctl.3
@@ -37,6 +37,8 @@ and then telling the linker it should link in the library:
.br
.BR keyctl_chown (3)
.br
+.BR keyctl_capabilities (3)
+.br
.BR keyctl_clear (3)
.br
.BR keyctl_describe (3)
diff --git a/man/keyctl_capabilities.3 b/man/keyctl_capabilities.3
new file mode 100644
index 0000000..cc4d86c
--- /dev/null
+++ b/man/keyctl_capabilities.3
@@ -0,0 +1,109 @@
+.\"
+.\" Copyright (C) 2019 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_CAPABILITIES 3 "30 May 2019" Linux "Linux Key Management Calls"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH NAME
+keyctl_capabilities \- Query subsystem capabilities
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SYNOPSIS
+.nf
+.B #include <keyutils.h>
+.sp
+.BI "long keyctl_capabilities(unsigned char *" buffer ", size_t " buflen ");"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH DESCRIPTION
+.BR keyctl_capabilities ()
+queries the keyrings subsystem in the kernel to ask about its capabilities and
+fills in the array in the buffer with bits that indicate the presence or
+absence of specific features in the keyrings subsystem.
+.P
+The function returns the amount of data the kernel has available, irrespective
+of the amount of buffer space available. If the buffer is shorter than the
+data, a short copy will be made; if the buffer is larger than the data, the
+excess space will be cleared.
+.P
+If this operation is not available in the kernel, the keyutils library will be
+emulate it as best it can and the capability bit that indicates if the kernel
+operation is available will be cleared.
+.P
+In
+.IR buffer[0] ,
+the following capabilities exist:
+.TP
+.B KEYCTL_CAPS0_CAPABILITIES
+This is set if the kernel supports this operation and cleared otherwise. If
+it is cleared, the rest of the flags are emulated.
+.TP
+.B KEYCTL_CAPS0_PERSISTENT_KEYRINGS
+This is set if the kernel supports persistent keyrings and cleared otherwise.
+See
+.BR keyctl_get_persistent ( 3 ).
+.TP
+.B KEYCTL_CAPS0_DIFFIE_HELLMAN
+This is set if the kernel supports Diffie-Hellman calculation and cleared
+otherwise. See
+.BR keyctl_dh_compute ( 3 ).
+.TP
+.B KEYCTL_CAPS0_PUBLIC_KEY
+This is set if the kernel supports public-key operations and cleared
+otherwise. See
+.BR keyctl_pkey_query ( 3 ).
+.TP
+.B KEYCTL_CAPS0_BIG_KEY
+This is set if the kernel supports the big_key key type and cleared otherwise.
+.TP
+.B KEYCTL_CAPS0_INVALIDATE
+This is set if the kernel supports key invalidation and cleared otherwise.
+See
+.BR keyctl_invalidate ( 3 ).
+.TP
+.B KEYCTL_CAPS0_RESTRICT_KEYRING
+This is set if the kernel supports restrictions on keyrings and cleared
+otherwise. See
+.BR keyctl_restrict_keyring ( 3 ).
+.TP
+.B KEYCTL_CAPS0_MOVE
+This is set if the kernel supports the move key operation and cleared
+otherwise. See
+.BR keyctl_move ( 3 ).
+.P
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH RETURN VALUE
+On success
+.BR keyctl_capabilities ()
+returns the size of the data it has available, irrespective of the size of the
+buffer. On error, the value
+.B -1
+will be returned and
+.I errno
+will have been set to an appropriate error.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH ERRORS
+.TP
+.B EFAULT
+The buffer cannot be written to.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.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
+.ad l
+.nh
+.BR keyctl (1),
+.BR add_key (2),
+.BR keyctl (2),
+.BR request_key (2),
+.BR keyctl (3),
+.BR keyrings (7),
+.BR keyutils (7)
diff --git a/tests/keyctl/supports/bad-args/runtest.sh b/tests/keyctl/supports/bad-args/runtest.sh
new file mode 100644
index 0000000..05581a4
--- /dev/null
+++ b/tests/keyctl/supports/bad-args/runtest.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+. ../../../prepare.inc.sh
+. ../../../toolbox.inc.sh
+
+
+# ---- do the actual testing ----
+
+result=PASS
+echo "++++ BEGINNING TEST" >$OUTPUTFILE
+
+# check that two arguments fails correctly
+marker "TWO ARGS"
+expect_args_error keyctl support 0 0
+
+# check that three arguments fails correctly
+marker "THREE ARGS"
+expect_args_error keyctl support 0 0 0
+
+echo "++++ FINISHED TEST: $result" >>$OUTPUTFILE
+
+# --- then report the results in the database ---
+toolbox_report_result $TEST $result
diff --git a/tests/keyctl/supports/valid/runtest.sh b/tests/keyctl/supports/valid/runtest.sh
new file mode 100644
index 0000000..2c62ef2
--- /dev/null
+++ b/tests/keyctl/supports/valid/runtest.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+. ../../../prepare.inc.sh
+. ../../../toolbox.inc.sh
+
+
+# ---- do the actual testing ----
+
+result=PASS
+echo "++++ BEGINNING TEST" >$OUTPUTFILE
+
+# Check that listing caps works
+marker "LIST CAPS"
+supports
+
+# check that querying a cap works
+marker "QUERY CAP"
+supports --unrecognised xxx
+
+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 a0bdd51..e7b9635 100644
--- a/tests/toolbox.inc.sh
+++ b/tests/toolbox.inc.sh
@@ -1203,6 +1203,34 @@ function move_key ()
###############################################################################
#
+# Query supported features
+#
+###############################################################################
+function supports ()
+{
+ my_exitval=0
+ if [ "x$1" = "x--fail" ]
+ then
+ my_exitval=1
+ shift
+ elif [ "x$1" = "x--unrecognised" ]
+ then
+ my_exitval=3
+ shift
+ fi
+
+ echo keyctl supports $* >>$OUTPUTFILE
+ keyctl supports $* >>$OUTPUTFILE 2>&1
+ err=$?
+ if [ $err != $my_exitval ]
+ then
+ echo exitcode=$err >>$OUTPUTFILE
+ failed
+ fi
+}
+
+###############################################################################
+#
# Make sure we sleep at least N seconds
#
###############################################################################
diff --git a/version.lds b/version.lds
index 9e78ea2..d2e4d26 100644
--- a/version.lds
+++ b/version.lds
@@ -95,5 +95,6 @@ KEYUTILS_1.8 {
KEYUTILS_1.9 {
/* Management functions */
keyctl_move;
+ keyctl_capabilities;
} KEYUTILS_1.8;