summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2019-05-29 23:37:15 +0100
committerDavid Howells <dhowells@redhat.com>2019-06-19 13:42:05 +0100
commit0f70f77491bb6976a2bf761224fec1a9cc6cfb87 (patch)
treef617713714470fdae7de2fe33208f88546b4795e
parent7afeb339062d42e5bae49e68c870971a2672333f (diff)
downloadkeyutils-0f70f77491bb6976a2bf761224fec1a9cc6cfb87.tar.gz
Add support for KEYCTL_MOVE
Signed-off-by: David Howells <dhowells@redhat.com>
-rw-r--r--keyctl.c31
-rw-r--r--keyutils.c8
-rw-r--r--keyutils.h7
-rw-r--r--keyutils.spec7
-rw-r--r--man/keyctl.119
-rw-r--r--man/keyctl.32
-rw-r--r--man/keyctl_move.3109
-rw-r--r--tests/keyctl/move/bad-args/runtest.sh64
-rw-r--r--tests/keyctl/move/noargs/runtest.sh39
-rw-r--r--tests/keyctl/move/recursion/runtest.sh213
-rw-r--r--tests/keyctl/move/valid/runtest.sh230
-rw-r--r--tests/toolbox.inc.sh22
-rw-r--r--version.lds6
13 files changed, 755 insertions, 2 deletions
diff --git a/keyctl.c b/keyctl.c
index 8c0b57f..c9c1740 100644
--- a/keyctl.c
+++ b/keyctl.c
@@ -78,6 +78,7 @@ static nr void act_keyctl_pkey_encrypt(int argc, char *argv[]);
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[]);
const struct command commands[] = {
{ act_keyctl___version, "--version", "" },
@@ -94,6 +95,7 @@ const struct command commands[] = {
{ act_keyctl_get_persistent, "get_persistent", "<keyring> [<uid>]" },
{ act_keyctl_link, "link", "<key> <keyring>" },
{ act_keyctl_list, "list", "<keyring>" },
+ { act_keyctl_move, "move", "[-f] <key> <from_keyring> <to_keyring>" },
{ act_keyctl_negate, "negate", "<key> <timeout> <keyring>" },
{ act_keyctl_new_session, "new_session", "" },
{ act_keyctl_newring, "newring", "<name> <keyring>" },
@@ -2067,6 +2069,35 @@ static void act_keyctl_pkey_verify(int argc, char *argv[])
exit(0);
}
+/*
+ * Move a key between keyrings.
+ */
+static void act_keyctl_move(int argc, char *argv[])
+{
+ key_serial_t key, from_keyring, to_keyring;
+ unsigned int flags = KEYCTL_MOVE_EXCL;
+
+ if (argc > 4) {
+ if (strcmp("-f", argv[1]) == 0) {
+ flags &= ~KEYCTL_MOVE_EXCL;
+ argc--;
+ argv++;
+ }
+ }
+
+ if (argc != 4)
+ format();
+
+ key = get_key_id(argv[1]);
+ from_keyring = get_key_id(argv[2]);
+ to_keyring = get_key_id(argv[3]);
+
+ if (keyctl_move(key, from_keyring, to_keyring, flags) < 0)
+ error("keyctl_move");
+
+ exit(0);
+}
+
/*****************************************************************************/
/*
* parse a key identifier
diff --git a/keyutils.c b/keyutils.c
index fd72eac..bb90cc8 100644
--- a/keyutils.c
+++ b/keyutils.c
@@ -327,6 +327,14 @@ long keyctl_pkey_verify(key_serial_t key_id,
return keyctl(KEYCTL_PKEY_VERIFY, &params, info, data, sig);
}
+long keyctl_move(key_serial_t id,
+ key_serial_t from_ringid,
+ key_serial_t to_ringid,
+ unsigned int flags)
+{
+ return keyctl(KEYCTL_MOVE, id, from_ringid, to_ringid, flags);
+}
+
/*****************************************************************************/
/*
* fetch key description into an allocated buffer
diff --git a/keyutils.h b/keyutils.h
index 911e93e..d3ef0e4 100644
--- a/keyutils.h
+++ b/keyutils.h
@@ -106,6 +106,7 @@ typedef uint32_t key_perm_t;
#define KEYCTL_PKEY_SIGN 27 /* Create a public key signature */
#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 */
/* keyctl structures */
struct keyctl_dh_params {
@@ -146,6 +147,8 @@ struct keyctl_pkey_params {
unsigned int __spare[7];
};
+#define KEYCTL_MOVE_EXCL 0x00000001 /* Do not displace from the to-keyring */
+
/*
* syscall wrappers
*/
@@ -227,6 +230,10 @@ extern long keyctl_pkey_verify(key_serial_t key_id,
const char *info,
const void *data, size_t data_len,
const void *sig, size_t sig_len);
+extern long keyctl_move(key_serial_t id,
+ key_serial_t from_ringid,
+ key_serial_t to_ringid,
+ unsigned int flags);
/*
* utilities
diff --git a/keyutils.spec b/keyutils.spec
index 07047db..0fd5c05 100644
--- a/keyutils.spec
+++ b/keyutils.spec
@@ -1,8 +1,8 @@
%define vermajor 1
-%define verminor 6
+%define verminor 6.1
%define version %{vermajor}.%{verminor}
%define libapivermajor 1
-%define libapiversion %{libapivermajor}.8
+%define libapiversion %{libapivermajor}.9
# % define buildid .local
@@ -99,6 +99,9 @@ make \
%{_libdir}/pkgconfig/libkeyutils.pc
%changelog
+* Wed May 29 2019 David Howells <dhowells@redhat.com> - 1.6.1-1
+- Add support for keyctl_move().
+
* Tue Nov 13 2018 David Howells <dhowells@redhat.com> - 1.6-1
- Apply various specfile cleanups from Fedora.
- request-key: Provide a command line option to suppress helper execution.
diff --git a/man/keyctl.1 b/man/keyctl.1
index 9eacfd2..bf841aa 100644
--- a/man/keyctl.1
+++ b/man/keyctl.1
@@ -39,6 +39,8 @@ keyctl \- key management facility control
.br
\fBkeyctl\fR unlink <key> [<keyring>]
.br
+\fBkeyctl\fR move [-f] <key> <from_keyring> <to_keyring>
+.br
\fBkeyctl\fR search <keyring> <type> <desc> [<dest_keyring>]
.br
\fBkeyctl\fR restrict_keyring <keyring> [<type> [<restriction>]]
@@ -344,6 +346,23 @@ unlinks before exiting.
$ keyctl unlink 23 27
.fi
.RE
+.SS Move a key between keyrings.
+\fBkeyctl move\fR [-f] <key> <from_keyring> <to_keyring>
+
+This command moves a key from one keyring to another, atomically combining
+"keyctl unlink <key> <from_keyring>" and "keyctl link <key> <to_keyring>".
+
+If the "-f" flag is present, any matching key will be displaced from
+"to_keyring"; if not present, the command will fail with the error message
+"File exists" if the key would otherwise displace another key from
+"to_keyring".
+
+.RS
+.nf
+$ keyctl move 23 27 29
+$ keyctl move -f 71 @u @s
+.fi
+.RE
.SS Search a keyring
\fBkeyctl search\fR <keyring> <type> <desc> [<dest_keyring>]
diff --git a/man/keyctl.3 b/man/keyctl.3
index ef3d09b..dcef9c6 100644
--- a/man/keyctl.3
+++ b/man/keyctl.3
@@ -65,6 +65,8 @@ and then telling the linker it should link in the library:
.br
.BR keyctl_link (3)
.br
+.BR keyctl_move (3)
+.br
.BR keyctl_negate (3)
.br
.BR keyctl_pkey_dec (3)
diff --git a/man/keyctl_move.3 b/man/keyctl_move.3
new file mode 100644
index 0000000..b241f70
--- /dev/null
+++ b/man/keyctl_move.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_MOVE 3 "29 May 2019" Linux "Linux Key Management Calls"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH NAME
+keyctl_move \- Move a key between keyrings
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SYNOPSIS
+.nf
+.B #include <keyutils.h>
+.sp
+.BI "long keyctl_move(key_serial_t " key ", key_serial_t " from_keyring ","
+.br
+.BI " key_serial_t " to_keyring ", unsigned int " flags ");"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH DESCRIPTION
+.BR keyctl_move ()
+atomically unlinks
+.I key
+from
+.I from_keyring
+and links it into
+.I to_keyring
+in a single operation. Depending on the flags set, a link to any matching key
+in to_keyring may get displaced.
+.P
+.I flags
+is a bitwise-OR of zero or more of the following flags:
+.P
+.TP
+.B KEYCTL_MOVE_EXCL
+If there's a matching key in to_keyring, don't displace it but rather return
+an error.
+.P
+The caller must have
+.B write
+permission on both keyring to be able create or remove links in them.
+.P
+The caller must have
+.B link
+permission on a key to be able to create a new link to it.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH RETURN VALUE
+On success
+.BR keyctl_move ()
+return
+.BR 0 .
+On error, the value
+.B -1
+will be returned and
+.I errno
+will have been set to an appropriate error.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH ERRORS
+.TP
+.B ENOKEY
+The key or one of the keyrings specified are invalid.
+.TP
+.B ENOKEY
+A key with the same type and description is present in to_keyring and
+KEYCTL_MOVE_EXCL is set.
+.TP
+.B EKEYEXPIRED
+The key or one of the keyrings specified have expired.
+.TP
+.B EKEYREVOKED
+The key or one of the keyrings specified have been revoked.
+.TP
+.B EACCES
+The key exists, but is not
+.B linkable
+by the calling process.
+.TP
+.B EACCES
+The keyrings exist, but are not
+.B writable
+by the calling process.
+.TP
+.B ENOMEM
+Insufficient memory to effect the changes.
+.TP
+.B EDQUOT
+Expanding to_keyring would exceed the keyring owner's quota.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.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/move/bad-args/runtest.sh b/tests/keyctl/move/bad-args/runtest.sh
new file mode 100644
index 0000000..8ce62ff
--- /dev/null
+++ b/tests/keyctl/move/bad-args/runtest.sh
@@ -0,0 +1,64 @@
+#!/bin/bash
+
+. ../../../prepare.inc.sh
+. ../../../toolbox.inc.sh
+
+
+# ---- do the actual testing ----
+
+result=PASS
+echo "++++ BEGINNING TEST" >$OUTPUTFILE
+
+# check that a bad key ID fails correctly
+marker "CHECK MOVE OF BAD KEY ID"
+move_key --fail 0 @u @s
+expect_error EINVAL
+
+marker "CHECK MOVE FROM BAD KEYRING ID"
+move_key --fail @u 0 @s
+expect_error EINVAL
+
+marker "CHECK MOVE TO BAD KEYRING ID"
+move_key --fail @u @s 0
+expect_error EINVAL
+
+marker "CHECK FORCED MOVE OF BAD KEY ID"
+move_key --fail -f 0 @u @s
+expect_error EINVAL
+
+marker "CHECK FORCED MOVE FROM BAD KEYRING ID"
+move_key --fail -f @u 0 @s
+expect_error EINVAL
+
+marker "CHECK FORCED MOVE TO BAD KEYRING ID"
+move_key --fail -f @u @s 0
+expect_error EINVAL
+
+# create a pair of non-keyrings
+marker "CREATE KEY"
+create_key user lizard gizzard @s
+expect_keyid keyid
+
+marker "CREATE KEY2"
+create_key user zebra stripes @s
+expect_keyid keyid2
+
+# check that linking to a non-keyring ID fails correctly
+marker "CHECK MOVE FROM NON-KEYRING KEY"
+move_key --fail $keyid $keyid2 @s
+expect_error ENOTDIR
+
+marker "CHECK MOVE TO NON-KEYRING KEY"
+move_key --fail $keyid @s $keyid2
+expect_error ENOTDIR
+
+# dispose of the keys we were using
+marker "UNLINK KEY"
+unlink_key --wait $keyid @s
+marker "UNLINK KEY2"
+unlink_key --wait $keyid2 @s
+
+echo "++++ FINISHED TEST: $result" >>$OUTPUTFILE
+
+# --- then report the results in the database ---
+toolbox_report_result $TEST $result
diff --git a/tests/keyctl/move/noargs/runtest.sh b/tests/keyctl/move/noargs/runtest.sh
new file mode 100644
index 0000000..29a91f1
--- /dev/null
+++ b/tests/keyctl/move/noargs/runtest.sh
@@ -0,0 +1,39 @@
+#!/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 "NO ARGS"
+expect_args_error keyctl move
+marker "NO ARGS (F)"
+expect_args_error keyctl move -f
+
+# check that one argument fails correctly
+marker "ONE ARGS"
+expect_args_error keyctl move 0
+marker "ONE ARGS (F)"
+expect_args_error keyctl move -f 0
+
+# check that two arguments fails correctly
+marker "TWO ARGS"
+expect_args_error keyctl move 0 0
+marker "TWO ARGS (F)"
+expect_args_error keyctl move -f 0 0
+
+# check that four arguments fails correctly
+marker "FOUR ARGS"
+expect_args_error keyctl link 0 0 0 0
+marker "FOUR ARGS (F)"
+expect_args_error keyctl link -f 0 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/move/recursion/runtest.sh b/tests/keyctl/move/recursion/runtest.sh
new file mode 100644
index 0000000..1e68963
--- /dev/null
+++ b/tests/keyctl/move/recursion/runtest.sh
@@ -0,0 +1,213 @@
+#!/bin/bash
+
+. ../../../prepare.inc.sh
+. ../../../toolbox.inc.sh
+
+
+# ---- do the actual testing ----
+
+result=PASS
+echo "++++ BEGINNING TEST" >$OUTPUTFILE
+
+# create a keyring and attach it to the session keyring
+marker "CREATE KEYRING 1"
+create_keyring "first" @s
+expect_keyid keyringid
+set_key_perm $keyringid 0x3f3f0000
+
+# attempt to move a keyring to itself
+marker "RECURSE 1"
+move_key --fail $keyringid @s $keyringid
+expect_error EDEADLK
+marker "RECURSE 1F"
+move_key --fail -f $keyringid @s $keyringid
+expect_error EDEADLK
+
+# create a second keyring in the first
+marker "CREATE KEYRING 2"
+create_keyring "second" $keyringid
+expect_keyid keyring2id
+set_key_perm $keyring2id 0x3f3f0000
+
+# attempt to move a keyring to its child keyring
+marker "RECURSE 2"
+move_key --fail $keyringid @s $keyring2id
+expect_error EDEADLK
+marker "RECURSE 2F"
+move_key --fail -f $keyringid @s $keyring2id
+expect_error EDEADLK
+
+# create a third keyring in the second
+marker "CREATE KEYRING 3"
+create_keyring "third" $keyring2id
+expect_keyid keyring3id
+set_key_perm $keyring3id 0x3f3f0000
+
+# attempt to move a keyring to its grandchild keyring
+marker "RECURSE 3"
+move_key --fail $keyringid @s $keyring3id
+expect_error EDEADLK
+marker "RECURSE 3F"
+move_key --fail -f $keyringid @s $keyring3id
+expect_error EDEADLK
+
+# create a fourth keyring in the third
+marker "CREATE KEYRING 4"
+create_keyring "fourth" $keyring3id
+expect_keyid keyring4id
+set_key_perm $keyring4id 0x3f3f0000
+
+# attempt to move a keyring to its great grandchild keyring
+marker "RECURSE 4"
+move_key --fail $keyringid @s $keyring4id
+expect_error EDEADLK
+marker "RECURSE 4F"
+move_key --fail -f $keyringid @s $keyring4id
+expect_error EDEADLK
+
+# create a fifth keyring in the fourth
+marker "CREATE KEYRING 5"
+create_keyring "fifth" $keyring4id
+expect_keyid keyring5id
+set_key_perm $keyring5id 0x3f3f0000
+
+# attempt to move a keyring to its great great grandchild keyring
+marker "RECURSE 5"
+move_key --fail $keyringid @s $keyring5id
+expect_error EDEADLK
+marker "RECURSE 5F"
+move_key --fail -f $keyringid @s $keyring5id
+expect_error EDEADLK
+
+# create a sixth keyring in the fifth
+marker "CREATE KEYRING 6"
+create_keyring "sixth" $keyring5id
+expect_keyid keyring6id
+set_key_perm $keyring6id 0x3f3f0000
+
+# attempt to move a keyring to its great great great grandchild keyring
+marker "RECURSE 6"
+move_key --fail $keyringid @s $keyring6id
+expect_error EDEADLK
+marker "RECURSE 6F"
+move_key --fail -f $keyringid @s $keyring6id
+expect_error EDEADLK
+
+# create a seventh keyring in the sixth
+marker "CREATE KEYRING 7"
+create_keyring "seventh" $keyring6id
+expect_keyid keyring7id
+set_key_perm $keyring7id 0x3f3f0000
+
+# attempt to move a keyring to its great great great great grandchild keyring
+marker "RECURSE 7"
+move_key --fail $keyringid @s $keyring7id
+expect_error EDEADLK
+marker "RECURSE 7F"
+move_key --fail -f $keyringid @s $keyring7id
+expect_error EDEADLK
+
+# create an eigth keyring in the seventh
+marker "CREATE KEYRING 8"
+create_keyring "eighth" @s
+expect_keyid keyring8id
+set_key_perm $keyring8id 0x3f3f0000
+move_key $keyring8id @s $keyring7id
+
+# attempt to move a keyring to its great great great great great grandchild keyring
+marker "RECURSE 8"
+move_key --fail $keyringid @s $keyring8id
+expect_error EDEADLK
+
+# create a ninth keyring in the eighth
+marker "CREATE KEYRING 9"
+create_keyring "ninth" @s
+expect_keyid keyring9id
+set_key_perm $keyring9id 0x3f3f0000
+move_key $keyring9id @s $keyring8id
+
+# attempt to move a keyring to its great great great great great great grandchild keyring
+marker "RECURSE 9"
+move_key --fail $keyringid @s $keyring9id
+expect_error ELOOP
+marker "RECURSE 9F"
+move_key --fail -f $keyringid @s $keyring9id
+expect_error ELOOP
+
+# remove the first keyring we added
+marker "UNLINK KEYRING"
+unlink_key $keyringid @s
+
+# create two stacks of keyrings
+marker "CREATE KEYRING STACKS"
+create_keyring "A1" @s
+expect_keyid aroot
+create_keyring "B1" @s
+expect_keyid broot
+a=$aroot
+b=$broot
+
+for ((i=2; i<=4; i++))
+ do
+ create_keyring "A$i" $a
+ expect_keyid a
+ create_keyring "B$i" $b
+ expect_keyid b
+done
+
+# make sure we can't create a cycle by linking the two stacks together
+marker "LINK A TO B"
+link_key $aroot $b
+
+marker "MOVE B TO A"
+move_key --fail $broot @s $a
+expect_error EDEADLK
+marker "FORCE MOVE B TO A"
+move_key --fail -f $broot @s $a
+expect_error EDEADLK
+
+marker "UNLINK A FROM B"
+unlink_key $aroot $b
+
+marker "LINK B TO A"
+link_key $broot $a
+
+marker "MOVE A TO B"
+move_key --fail $aroot @s $b
+expect_error EDEADLK
+marker "FORCE MOVE A TO B"
+move_key --fail -f $aroot @s $b
+expect_error EDEADLK
+
+marker "UNLINK B FROM A"
+unlink_key $broot $a
+
+# extend the stacks
+marker "EXTEND STACKS"
+create_keyring "A5" $a
+expect_keyid a
+create_keyring "B5" $b
+expect_keyid b
+
+# make sure we can't hide a cycle by linking the two bigger stacks together
+marker "CHECK MAXDEPTH A TO B"
+link_key $aroot $b
+move_key --fail $broot @s $a
+expect_error ELOOP
+unlink_key $aroot $b
+
+marker "CHECK MAXDEPTH B TO A"
+link_key $broot $a
+move_key --fail $aroot @s $b
+expect_error ELOOP
+unlink_key $broot $a
+
+# remove the two stacks
+marker "UNLINK STACKS"
+unlink_key $aroot @s
+unlink_key $broot @s
+
+echo "++++ FINISHED TEST: $result" >>$OUTPUTFILE
+
+# --- then report the results in the database ---
+toolbox_report_result $TEST $result
diff --git a/tests/keyctl/move/valid/runtest.sh b/tests/keyctl/move/valid/runtest.sh
new file mode 100644
index 0000000..73bf7c2
--- /dev/null
+++ b/tests/keyctl/move/valid/runtest.sh
@@ -0,0 +1,230 @@
+#!/bin/bash
+
+. ../../../prepare.inc.sh
+. ../../../toolbox.inc.sh
+
+
+# ---- do the actual testing ----
+
+result=PASS
+echo "++++ BEGINNING TEST" >$OUTPUTFILE
+
+# create a keyring and attach it to the session keyring
+marker "ADD KEYRING"
+create_keyring wibble @s
+expect_keyid keyringid
+
+# stick a key in the keyring
+marker "ADD KEY"
+create_key user lizard gizzard $keyringid
+expect_keyid keyid
+
+# check that we can list it
+marker "LIST KEYRING WITH ONE"
+list_keyring $keyringid
+expect_keyring_rlist rlist $keyid
+
+# move the key across to the session keyring
+marker "MOVE KEY 1"
+move_key $keyid $keyringid @s
+
+marker "CHECK KEY LINKAGE"
+list_keyring @s
+expect_keyring_rlist srlist $keyid
+
+marker "CHECK KEY REMOVED"
+list_keyring $keyringid
+expect_keyring_rlist rlist $keyid --absent
+
+# Repeating the move should fail
+marker "MOVE KEY 2"
+move_key --fail $keyid $keyringid @s
+expect_error ENOENT
+
+marker "FORCE MOVE KEY 2"
+move_key --fail -f $keyid $keyringid @s
+expect_error ENOENT
+
+# Move the key back again
+marker "MOVE KEY 3"
+move_key $keyid @s $keyringid
+
+marker "MOVE KEY 4"
+move_key --fail -f $keyid @s $keyringid
+expect_error ENOENT
+
+# Create a conflicting key and try to have an unforced move displace it
+marker "ADD KEY 2"
+create_key user lizard gizzard @s
+expect_keyid keyid2
+
+marker "MOVE KEY 5"
+move_key --fail $keyid $keyringid @s
+expect_error EEXIST
+
+marker "CHECK KEY UNMOVED"
+list_keyring $keyringid
+expect_keyring_rlist rlist $keyid
+
+marker "CHECK KEY UNDISPLACED"
+list_keyring @s
+expect_keyring_rlist srlist $keyid --absent
+expect_keyring_rlist srlist $keyid2
+
+# Now try a forced move
+marker "FORCE MOVE KEY 6"
+move_key -f $keyid $keyringid @s
+
+marker "CHECK KEY REMOVED"
+list_keyring $keyringid
+expect_keyring_rlist rlist $keyid --absent
+expect_keyring_rlist rlist $keyid2 --absent
+
+marker "CHECK KEY DISPLACED"
+list_keyring @s
+expect_keyring_rlist srlist $keyid
+expect_keyring_rlist srlist $keyid2 --absent
+
+# Remove the link (the key should be destroyed)
+marker "UNLINK KEY FROM SESSION"
+unlink_key --wait $keyid @s
+
+# Removing again should fail
+unlink_key --fail $keyid @s
+expect_error ENOKEY
+
+# Remove that key from the keyring should also fail
+marker "UNLINK KEY FROM KEYRING"
+unlink_key --fail $keyid $keyringid
+expect_error ENOKEY
+
+###############################################################################
+# Create a second keyring in the first
+create_keyring "zebra" $keyringid
+expect_keyid keyring2id
+
+# Move thrice between the session keyring and back
+marker "LINK 2ND KEYRING TO SESSION"
+move_key $keyring2id $keyringid @s
+move_key $keyring2id @s $keyringid
+move_key $keyring2id $keyringid @s
+
+# Subsequent links should displace earlier links, giving us a maximum of 1 link
+marker "COUNT KEYRING LINKS"
+list_keyring @s
+expect_keyring_rlist srlist
+
+nlinks=0
+for i in $srlist
+ do
+ if [ "x$i" = "x$keyring2id" ]
+ then
+ nlinks=$(($nlinks + 1))
+ fi
+done
+
+if [ $nlinks != 1 ]
+then
+ failed
+fi
+
+# Remove the keyring links, destroying it
+marker "UNLINK 2ND KEYRING FROM SESSION"
+unlink_key --wait $keyring2id @s
+
+# Removing again should fail
+marker "RE-UNLINK"
+unlink_key --fail $keyring2id @s
+expect_error ENOKEY
+marker "RE-UNLINK 2"
+unlink_key --fail $keyring2id $keyringid
+expect_error ENOKEY
+
+###############################################################################
+# Create a second keyring in the session keyring
+create_keyring "zebra" @s
+expect_keyid keyring2id
+
+# Add a key to the session keyring and link it into each keyring
+marker "ADD KEY 3"
+create_key user lizard gizzard @s
+expect_keyid keyid
+
+marker "LINK KEY"
+link_key $keyid $keyringid
+marker "LINK KEY 2"
+link_key $keyid $keyring2id
+
+# Try to move the links from the keyrings into the session keyring
+marker "MOVE LINK"
+move_key --fail $keyid $keyringid @s
+expect_error EEXIST
+
+marker "CHECK LINK"
+list_keyring $keyringid
+expect_keyring_rlist rlist $keyid
+
+marker "MOVE LINK 2"
+move_key --fail $keyid $keyring2id @s
+expect_error EEXIST
+
+marker "CHECK LINK 2"
+list_keyring $keyring2id
+expect_keyring_rlist rlist $keyid
+
+marker "MOVE LINK 3"
+move_key $keyid @s @s
+
+marker "CHECK LINK 3"
+list_keyring @s
+expect_keyring_rlist srlist $keyid
+
+# Try to force move the links from the keyrings into the session keyring
+marker "FORCE MOVE LINK"
+move_key -f $keyid $keyringid @s
+
+marker "CHECK LINK 4"
+list_keyring $keyringid
+expect_keyring_rlist rlist $keyid --absent
+
+marker "CHECK LINK 4s"
+list_keyring @s
+expect_keyring_rlist srlist $keyid
+
+marker "FORCE MOVE LINK 2"
+move_key -f $keyid $keyring2id @s
+
+marker "CHECK LINK 5"
+list_keyring $keyring2id
+expect_keyring_rlist rlist $keyid --absent
+
+marker "CHECK LINK 5s"
+list_keyring @s
+expect_keyring_rlist srlist $keyid
+
+marker "FORCE MOVE LINK 3"
+move_key -f $keyid @s @s
+
+marker "CHECK LINK 6"
+list_keyring @s
+expect_keyring_rlist srlist $keyid
+
+# Move the key between keyrings
+marker "ROTATE"
+move_key $keyid @s $keyringid
+move_key $keyid $keyringid $keyring2id
+move_key $keyid $keyring2id @s
+
+marker "UNLINK KEY"
+unlink_key $keyid @s
+
+# remove the keyrings
+marker "UNLINK KEYRING 1"
+unlink_key --wait $keyringid @s
+marker "UNLINK KEYRING 2"
+unlink_key --wait $keyring2id @s
+
+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 0ce6db0..a0bdd51 100644
--- a/tests/toolbox.inc.sh
+++ b/tests/toolbox.inc.sh
@@ -1181,6 +1181,28 @@ function dh_compute_kdf_oi ()
###############################################################################
#
+# Move a key between keyrings
+#
+###############################################################################
+function move_key ()
+{
+ my_exitval=0
+ if [ "x$1" = "x--fail" ]
+ then
+ my_exitval=1
+ shift
+ fi
+
+ echo keyctl move $* >>$OUTPUTFILE
+ keyctl move $* >>$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 9317222..9e78ea2 100644
--- a/version.lds
+++ b/version.lds
@@ -91,3 +91,9 @@ KEYUTILS_1.8 {
keyctl_pkey_verify;
} KEYUTILS_1.7;
+
+KEYUTILS_1.9 {
+ /* Management functions */
+ keyctl_move;
+
+} KEYUTILS_1.8;