summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2019-08-15 17:27:19 +0100
committerDavid Howells <dhowells@redhat.com>2020-07-16 21:51:11 +0100
commite91461275060bc7557ed11d608b85426d92804ca (patch)
tree5c9f2468bd830933d0fcd6fb01d49105c35c076b
parentbc7248bf1712f8b839b0ef10062ffa1fa82116dc (diff)
downloadkeyutils-e91461275060bc7557ed11d608b85426d92804ca.tar.gz
Add a keyctl command for granting a permit on a key
Add a keyctl command to allow permits to be granted or removed on a key for a specific subject. The kernel maintains the ACL internally from these alterations, but the ACL isn't directly accessible. The command looks like: keyctl grant <keyid> <subject> <permits> where subject can currently be one of pos - Permits available to a possessor of the key own - Permits available to key's owner grp - Permits available to key's group ID all - Permits available to everyone and permits can be any combination of the following letters: v - Permit the subject to view the key's attributes r - Permit the subject to read the key's payload w - Permit the subject to change the key's payload s - Permit the subject to find the key in a search l - Permit the subject to create a link to the key I - Permit the subject to invalidate the key R - Permit the subject to revoke the key S - Permit the subject to change the key's security j - Permit the subject to join the session keyring c - Permit the subject to clear the keyring For example: $ keyctl grant @s own j will grant the key's owner a permit to join the key as its session keyring, but will remove all other permits for the owner directly, such as view, read, etc.. Signed-off-by: David Howells <dhowells@redhat.com>
-rw-r--r--keyctl.c77
-rw-r--r--keyutils.c6
-rw-r--r--keyutils.h37
-rw-r--r--man/keyctl.32
-rw-r--r--man/keyctl_grant_permission.3155
-rw-r--r--man/keyctl_setperm.37
-rw-r--r--tests/keyctl/grant/bad-args/runtest.sh45
-rw-r--r--tests/keyctl/grant/noargs/runtest.sh27
-rw-r--r--tests/keyctl/grant/valid/runtest.sh160
-rw-r--r--tests/keyctl/grant/valid2/runtest.sh180
-rw-r--r--tests/keyctl/grant/valid3/runtest.sh180
-rw-r--r--tests/keyctl/grant/valid4/runtest.sh180
-rw-r--r--tests/keyctl/grant/valid5/runtest.sh200
-rw-r--r--tests/prepare.inc.sh1
-rw-r--r--tests/toolbox.inc.sh46
-rw-r--r--version.lds1
16 files changed, 1301 insertions, 3 deletions
diff --git a/keyctl.c b/keyctl.c
index f5fa3eb..5ae50b6 100644
--- a/keyctl.c
+++ b/keyctl.c
@@ -84,6 +84,7 @@ 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[]);
+static nr void act_keyctl_grant(int argc, char *argv[]);
static const struct command commands[] = {
{ act_keyctl___version, "--version", "" },
@@ -96,6 +97,7 @@ static const struct command commands[] = {
{ act_keyctl_dh_compute_kdf, "dh_compute_kdf", "<private> <prime> <base> <len> <hash_name>" },
{ act_keyctl_dh_compute_kdf_oi, "dh_compute_kdf_oi", "[-x] <private> <prime> <base> <len> <hash_name>" },
{ act_keyctl_get_persistent, "get_persistent", "<keyring> [<uid>]" },
+ { act_keyctl_grant, "grant", "<key> <subject> <perms>" },
{ act_keyctl_id, "id", "<key>" },
{ act_keyctl_instantiate, "instantiate","[-x] <key> <data> <keyring>" },
{ act_keyctl_invalidate,"invalidate", "<key>" },
@@ -133,7 +135,7 @@ static const struct command commands[] = {
{ act_keyctl_session, "session", "" },
{ NULL, "session", "- [<prog> <arg1> <arg2> ...]" },
{ NULL, "session", "<name> [<prog> <arg1> <arg2> ...]" },
- { act_keyctl_setperm, "setperm", "<key> <mask>" },
+ { act_keyctl_setperm, "setperm", "<key> <mask> -- DEPRECATED" },
{ act_keyctl_show, "show", "[-x] [<keyring>]" },
{ act_keyctl_supports, "supports", "[<cap> | --raw]" },
{ act_keyctl_timeout, "timeout", "<key> <timeout>" },
@@ -2292,6 +2294,7 @@ static const struct capability_def capabilities[] = {
{ "ns_key_tag", 1, KEYCTL_CAPS1_NS_KEY_TAG },
{ "notify", 1, KEYCTL_CAPS1_NOTIFICATIONS },
{ "acl", 1, KEYCTL_CAPS1_ACL },
+ { "grant", 1, KEYCTL_CAPS1_GRANT_PERMISSION },
{}
};
@@ -2332,6 +2335,78 @@ static void act_keyctl_supports(int argc, char *argv[])
}
}
+/*
+ * Grant permits to a subject for using a key.
+ */
+static void act_keyctl_grant(int argc, char *argv[])
+{
+ enum key_ace_subject_type type;
+ key_serial_t key;
+ unsigned subj, mask = 0;
+ char *id, *perms;
+
+ if (argc != 4)
+ format();
+
+ key = get_key_id(argv[1]);
+ id = argv[2];
+ perms = argv[3];
+
+ if (strcmp(id, "all") == 0) {
+ type = KEY_ACE_SUBJ_STANDARD;
+ subj = KEY_ACE_EVERYONE;
+ } else if (strcmp(id, "grp") == 0) {
+ type = KEY_ACE_SUBJ_STANDARD;
+ subj = KEY_ACE_GROUP;
+ } else if (strcmp(id, "own") == 0) {
+ type = KEY_ACE_SUBJ_STANDARD;
+ subj = KEY_ACE_OWNER;
+ } else if (strcmp(id, "pos") == 0) {
+ type = KEY_ACE_SUBJ_STANDARD;
+ subj = KEY_ACE_POSSESSOR;
+ } else {
+ fprintf(stderr, "Invalid subject type\n");
+ exit(2);
+ }
+
+ if (isdigit(*perms)) {
+ char *p;
+ unsigned long ltmp = strtoul(perms, &p, 0);
+ if (ltmp & ~(unsigned long)KEY_ACE__PERMS)
+ goto invalid_permits;
+ if (*p)
+ goto invalid_permits;
+ mask |= ltmp;
+ } else if (strcmp(perms, "all") == 0) {
+ mask |= KEY_ACE__PERMS;
+ } else {
+ for (; *perms; perms++) {
+ switch (*perms) {
+ case 'v': mask |= KEY_ACE_VIEW; break;
+ case 'r': mask |= KEY_ACE_READ; break;
+ case 'w': mask |= KEY_ACE_WRITE; break;
+ case 's': mask |= KEY_ACE_SEARCH; break;
+ case 'l': mask |= KEY_ACE_LINK; break;
+ case 'I': mask |= KEY_ACE_INVAL; break;
+ case 'R': mask |= KEY_ACE_REVOKE; break;
+ case 'S': mask |= KEY_ACE_SET_SECURITY; break;
+ case 'j': mask |= KEY_ACE_JOIN; break;
+ case 'c': mask |= KEY_ACE_CLEAR; break;
+ default: goto invalid_permits;
+ }
+ }
+ }
+
+ if (keyctl_grant_permission(key, type, subj, mask) < 0)
+ error("keyctl_grant_permission");
+
+ exit(0);
+
+invalid_permits:
+ fprintf(stderr, "Invalid permits\n");
+ exit(2);
+}
+
/*****************************************************************************/
/*
* parse a key identifier
diff --git a/keyutils.c b/keyutils.c
index 48b779e..980de93 100644
--- a/keyutils.c
+++ b/keyutils.c
@@ -390,6 +390,12 @@ long keyctl_watch_key(key_serial_t id, int watch_queue_fd, int watch_id)
return keyctl(KEYCTL_WATCH_KEY, id, watch_queue_fd, watch_id);
}
+long keyctl_grant_permission(key_serial_t id, enum key_ace_subject_type type,
+ unsigned int subject, unsigned int perm)
+{
+ return keyctl(KEYCTL_GRANT_PERMISSION, id, type, subject, perm);
+}
+
/*****************************************************************************/
/*
* fetch key description into an allocated buffer
diff --git a/keyutils.h b/keyutils.h
index 508456c..44cf667 100644
--- a/keyutils.h
+++ b/keyutils.h
@@ -44,7 +44,38 @@ typedef int32_t key_serial_t;
#define KEY_REQKEY_DEFL_USER_SESSION_KEYRING 5
#define KEY_REQKEY_DEFL_GROUP_KEYRING 6
-/* key handle permissions mask */
+
+/*
+ * Keyring permission grant definitions
+ */
+enum key_ace_subject_type {
+ KEY_ACE_SUBJ_STANDARD = 0, /* subject is one of key_ace_standard_subject */
+ nr__key_ace_subject_type
+};
+
+enum key_ace_standard_subject {
+ KEY_ACE_EVERYONE = 0, /* Everyone, including owner and group */
+ KEY_ACE_GROUP = 1, /* The key's group */
+ KEY_ACE_OWNER = 2, /* The owner of the key */
+ KEY_ACE_POSSESSOR = 3, /* Any process that possesses of the key */
+ nr__key_ace_standard_subject
+};
+
+#define KEY_ACE_VIEW 0x00000001 /* Can describe the key */
+#define KEY_ACE_READ 0x00000002 /* Can read the key content */
+#define KEY_ACE_WRITE 0x00000004 /* Can update/modify the key content */
+#define KEY_ACE_SEARCH 0x00000008 /* Can find the key by search */
+#define KEY_ACE_LINK 0x00000010 /* Can make a link to the key */
+#define KEY_ACE_SET_SECURITY 0x00000020 /* Can set owner, group, ACL */
+#define KEY_ACE_INVAL 0x00000040 /* Can invalidate the key */
+#define KEY_ACE_REVOKE 0x00000080 /* Can revoke the key */
+#define KEY_ACE_JOIN 0x00000100 /* Can join keyring */
+#define KEY_ACE_CLEAR 0x00000200 /* Can clear keyring */
+#define KEY_ACE__PERMS 0xffffffff
+
+/*
+ * Old-style permissions mask, deprecated in favour of ACL.
+ */
typedef uint32_t key_perm_t;
#define KEY_POS_VIEW 0x01000000 /* possessor can view a key's attributes */
@@ -113,6 +144,7 @@ typedef uint32_t key_perm_t;
#define KEYCTL_MOVE 30 /* Move keys between keyrings */
#define KEYCTL_CAPABILITIES 31 /* Find capabilities of keyrings subsystem */
#define KEYCTL_WATCH_KEY 32 /* Watch a key or ring of keys for changes */
+#define KEYCTL_GRANT_PERMISSION 33 /* Grant a permit to a key */
/* keyctl structures */
struct keyctl_dh_params {
@@ -171,6 +203,7 @@ struct keyctl_pkey_params {
#define KEYCTL_CAPS1_NS_KEY_TAG 0x02 /* Key indexing can include a namespace tag */
#define KEYCTL_CAPS1_NOTIFICATIONS 0x04 /* Keys generate watchable notifications */
#define KEYCTL_CAPS1_ACL 0x08 /* Keys have ACLs rather than a p-u-g-o bitmask */
+#define KEYCTL_CAPS1_GRANT_PERMISSION 0x10 /* KEYCTL_GRANT_PERMISSION is supported */
/*
* syscall wrappers
@@ -259,6 +292,8 @@ extern long keyctl_move(key_serial_t id,
unsigned int flags);
extern long keyctl_capabilities(unsigned char *buffer, size_t buflen);
extern long keyctl_watch_key(key_serial_t id, int watch_queue_fd, int watch_id);
+extern long keyctl_grant_permission(key_serial_t id, enum key_ace_subject_type type,
+ unsigned int subject, unsigned int perm);
/*
* utilities
diff --git a/man/keyctl.3 b/man/keyctl.3
index fda0363..17f36aa 100644
--- a/man/keyctl.3
+++ b/man/keyctl.3
@@ -57,6 +57,8 @@ and then telling the linker it should link in the library:
.br
.BR keyctl_get_security_alloc (3)
.br
+.BR keyctl_grant_permission (3)
+.br
.BR keyctl_instantiate (3)
.br
.BR keyctl_instantiate_iov (3)
diff --git a/man/keyctl_grant_permission.3 b/man/keyctl_grant_permission.3
new file mode 100644
index 0000000..bcaedcd
--- /dev/null
+++ b/man/keyctl_grant_permission.3
@@ -0,0 +1,155 @@
+.\"
+.\" 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_GRANT_PERMISSION 3 "15 Aug 2019" Linux "Linux Key Management Calls"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH NAME
+keyctl_grant_permission \- Alter the ACL on a key
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SYNOPSIS
+.nf
+.B #include <keyutils.h>
+.sp
+.BI "long keyctl_grant_permission(key_serial_t " key ,
+.BI " enum key_ace_subject_type " type
+.BI " unsigned int " subject ,
+.BI " unsigned int " perm ");"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH DESCRIPTION
+.BR keyctl_grant_permission ()
+alters the ACL attached to a key to grant or remove permissions to a specific
+subject. This supersedes
+.BR keyctl_setperm ().
+The Linux kernel maintains the ACL, allowing this call to add, modify or delete
+a single ACE to, in or from the ACL.
+.P
+A process that does not have the
+.B SysAdmin
+capability may not change the permissions mask on a key that doesn't have the
+same UID as the caller.
+.P
+The caller must have
+.B SET_SECURITY
+permission on a key to be able change the ACL.
+.P
+The subject is specified by a combination of the
+.IR type " and " subject
+parameters. The type is one of:
+.TP
+.B KEY_ACE_SUBJ_STANDARD
+This indicates that the subject specifies one of a number 'macroised'
+subjects:
+.RS
+.TP
+.B KEY_ACE_EVERYONE
+Unconditially grant permits to every process on the system.
+.TP
+.B KEY_ACE_OWNER
+Grant permits to any process whose
+.I fsuid
+matches the owner of the key.
+.TP
+.B KEY_ACE_GROUP
+Grant permits to any process for whom the key's group matches the process's
+.I fsgid
+or one of its
+.I groups
+list.
+.TP
+.B KEY_ACE_POSSESSOR
+Grant permits to any process that has the key somewhere in it's keyrings.
+.RE
+.P
+The permissions mask
+.I perm
+is a bitwise-OR of the following permits, where any permit not given will be
+removed from the ACE for the specified subject.
+.TP
+.B KEY_ACE_VIEW
+Grant permission to view the attributes of a key.
+.TP
+.B KEY_ACE_READ
+Grant permission to read the payload of a key or to list a keyring.
+.TP
+.B KEY_ACE_WRITE
+Grant permission to modify the payload of a key or to add or remove links
+to/from a keyring.
+.TP
+.B KEY_ACE_SEARCH
+Grant permission to find a key or to search a keyring.
+.TP
+.B KEY_ACE_LINK
+Grant permission to make links to a key.
+.TP
+.B KEY_ACE_SET_SECURITY
+Grant permission to change the ownership and ACL of a key.
+.TP
+.B KEY_ACE_INVAL
+Grant permission to invalidate a key.
+.TP
+.B KEY_ACE_REVOKE
+Grant permission to revoke a key.
+.TP
+.B KEY_ACE_JOIN
+Grant permission to join a keyring.
+.TP
+.B KEY_ACE_CLEAR
+Grant permission to clear a keyring.
+.TP
+.B KEY_ACE__PERMS
+Grant all the above.
+.P
+All grants are cumulative. There are currently no ACEs that explicitly deny
+access to a permit.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH RETURN VALUE
+On success
+.BR keyctl_grant_permission ()
+returns
+.B 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 specified key does not exist.
+.TP
+.B EKEYEXPIRED
+The specified key has expired.
+.TP
+.B EKEYREVOKED
+The specified key has been revoked.
+.TP
+.B EACCES
+The named key exists, but does not grant
+.B setattr
+permission to the calling process.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.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 keyctl_setperm (3),
+.BR keyrings (7),
+.BR keyutils (7)
diff --git a/man/keyctl_setperm.3 b/man/keyctl_setperm.3
index e4134d9..0b342db 100644
--- a/man/keyctl_setperm.3
+++ b/man/keyctl_setperm.3
@@ -11,6 +11,8 @@
.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
.SH NAME
keyctl_setperm \- change the permissions mask on a key
+.P
+This function is deprecated.
.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
.SH SYNOPSIS
.nf
@@ -20,7 +22,9 @@ keyctl_setperm \- change the permissions mask on a key
.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
.SH DESCRIPTION
.BR keyctl_setperm ()
-overwrites the ACL on a key.
+overwrites the ACL on a key. Note that this function is deprecated and that
+.BR keyctl_grant_permission (3)
+should be used instead.
.P
A process that does not have the
.B SysAdmin
@@ -121,5 +125,6 @@ should be specified to the linker.
.BR keyctl (2),
.BR request_key (2),
.BR keyctl (3),
+.BR keyctl_grant_permission (3),
.BR keyrings (7),
.BR keyutils (7)
diff --git a/tests/keyctl/grant/bad-args/runtest.sh b/tests/keyctl/grant/bad-args/runtest.sh
new file mode 100644
index 0000000..6e8e1a2
--- /dev/null
+++ b/tests/keyctl/grant/bad-args/runtest.sh
@@ -0,0 +1,45 @@
+#!/bin/bash
+
+. ../../../prepare.inc.sh
+. ../../../toolbox.inc.sh
+
+
+# ---- do the actual testing ----
+
+result=PASS
+echo "++++ BEGINNING TEST" >$OUTPUTFILE
+
+if [ $have_grant = 0 ]
+then
+ toolbox_skip_test $TEST "SKIPPING DUE TO LACK OF GRANT PERMIT"
+ exit 0
+fi
+
+# check that a bad key ID fails correctly
+marker "CHECK BAD KEY ID"
+grant_key_permit --fail 0 all all
+expect_error EINVAL
+
+# create a non-keyring
+marker "CREATE KEY"
+create_key user lizard gizzard @s
+expect_keyid keyid
+
+# check that unsupported permissions aren't permitted
+marker "CHECK PERMS"
+grant_key_permit --fail2 $keyid all foo
+grant_key_permit --fail2 $keyid foo all
+
+# dispose of the key we just made
+marker "UNLINK KEY"
+unlink_key --wait $keyid @s
+
+# check that a non-existent key ID fails correctly
+marker "CHECK NON-EXISTENT KEY ID"
+grant_key_permit --fail $keyid all all
+expect_error ENOKEY
+
+echo "++++ FINISHED TEST: $result" >>$OUTPUTFILE
+
+# --- then report the results in the database ---
+toolbox_report_result $TEST $result
diff --git a/tests/keyctl/grant/noargs/runtest.sh b/tests/keyctl/grant/noargs/runtest.sh
new file mode 100644
index 0000000..0f62735
--- /dev/null
+++ b/tests/keyctl/grant/noargs/runtest.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+. ../../../prepare.inc.sh
+. ../../../toolbox.inc.sh
+
+
+# ---- do the actual testing ----
+
+result=PASS
+echo "++++ BEGINNING TEST" >$OUTPUTFILE
+
+marker "NO ARGS"
+expect_args_error keyctl grant
+
+marker "ONE ARG"
+expect_args_error keyctl grant 0
+
+marker "TWO ARGS"
+expect_args_error keyctl grant 0 0
+
+marker "FOUR ARGS"
+expect_args_error keyctl grant 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/grant/valid/runtest.sh b/tests/keyctl/grant/valid/runtest.sh
new file mode 100644
index 0000000..ddd7e2a
--- /dev/null
+++ b/tests/keyctl/grant/valid/runtest.sh
@@ -0,0 +1,160 @@
+#!/bin/bash
+
+. ../../../prepare.inc.sh
+. ../../../toolbox.inc.sh
+
+
+# ---- do the actual testing ----
+
+if [ $have_grant = 0 ]
+then
+ toolbox_skip_test $TEST "SKIPPING DUE TO LACK OF GRANT PERMIT"
+ exit 0
+fi
+
+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
+
+# Create a key and remove most permissions from the key; just leave setsec for
+# the owner.
+marker "ADD KEY"
+create_key user lizard gizzard $keyringid
+expect_keyid keyid
+marker "REMOVE PERMITS"
+grant_key_permit $keyid own S
+grant_key_permit $keyid pos 0
+grant_key_permit $keyid grp 0
+grant_key_permit $keyid all 0
+
+# Test the View permit
+marker "TEST VIEW"
+describe_key --fail $keyid
+expect_error EACCES
+grant_key_permit $keyid all v
+describe_key $keyid
+grant_key_permit $keyid all 0
+describe_key --fail $keyid
+expect_error EACCES
+
+# Test the Read permit
+marker "TEST READ"
+read_key --fail $keyid
+expect_error EACCES
+grant_key_permit $keyid all r
+read_key $keyid
+grant_key_permit $keyid all 0
+read_key --fail $keyid
+expect_error EACCES
+
+# Test the Write permit
+marker "TEST WRITE"
+update_key --fail $keyid "lizard"
+expect_error EACCES
+grant_key_permit $keyid all w
+update_key $keyid "lizard"
+grant_key_permit $keyid all 0
+update_key --fail $keyid "lizard"
+expect_error EACCES
+
+# Test the Search permit (we're allowed to read a key we can search out)
+marker "TEST SEARCH"
+read_key --fail $keyid
+expect_error EACCES
+grant_key_permit $keyid pos s
+read_key $keyid
+grant_key_permit $keyid pos 0
+read_key --fail $keyid
+expect_error EACCES
+
+# Test the Link permit
+marker "TEST LINK"
+link_key --fail $keyid @s
+expect_error EACCES
+grant_key_permit $keyid all l
+link_key $keyid @s
+grant_key_permit $keyid all 0
+link_key --fail $keyid @s
+expect_error EACCES
+unlink_key $keyid @s
+
+# Test the Clear permit
+marker "TEST CLEAR"
+clear_keyring --fail $keyid
+expect_error EACCES
+grant_key_permit $keyid all c
+clear_keyring --fail $keyid
+expect_error ENOTDIR
+grant_key_permit $keyid all 0
+clear_keyring --fail $keyid
+expect_error EACCES
+
+# Test the Join permit
+marker "TEST JOIN"
+grant_key_permit $keyid all j
+grant_key_permit $keyid all 0
+
+# Test the Invalidate permit
+marker "TEST INVAL"
+invalidate_key --fail $keyid
+expect_error EACCES
+grant_key_permit $keyid all I
+invalidate_key $keyid
+grant_key_permit --fail $keyid all 0
+expect_error ENOKEY
+invalidate_key --fail $keyid
+expect_error ENOKEY
+
+# Create a key and remove most permissions from the key; just leave setsec for
+# the owner.
+marker "ADD KEY 2"
+create_key user lizard gizzard $keyringid
+expect_keyid keyid
+marker "REMOVE PERMITS 2"
+grant_key_permit $keyid own S
+grant_key_permit $keyid pos 0
+grant_key_permit $keyid grp 0
+grant_key_permit $keyid all 0
+
+# Test the Revoke permit
+marker "TEST REVOKE"
+revoke_key --fail $keyid
+expect_error EACCES
+grant_key_permit $keyid all R
+revoke_key $keyid
+grant_key_permit --fail $keyid all 0
+expect_error EKEYREVOKED
+revoke_key --fail $keyid
+expect_error EKEYREVOKED
+
+# Create a key and remove most permissions from the key; just leave setsec and
+# view for the owner.
+marker "ADD KEY 3"
+create_key user lizard gizzard $keyringid
+expect_keyid keyid
+marker "REMOVE PERMITS 3"
+grant_key_permit $keyid own Sv
+grant_key_permit $keyid pos 0
+grant_key_permit $keyid grp 0
+grant_key_permit $keyid all 0
+
+# Test the Set Security permit
+marker "TEST SET SECURITY"
+describe_key $keyid
+grant_key_permit $keyid own v
+describe_key $keyid
+grant_key_permit --fail $keyid own Sv
+expect_error EACCES
+
+# remove the keyring we added
+marker "UNLINK KEYRING"
+unlink_key $keyringid @s
+
+echo "++++ FINISHED TEST: $result" >>$OUTPUTFILE
+
+# --- then report the results in the database ---
+toolbox_report_result $TEST $result
diff --git a/tests/keyctl/grant/valid2/runtest.sh b/tests/keyctl/grant/valid2/runtest.sh
new file mode 100644
index 0000000..51091be
--- /dev/null
+++ b/tests/keyctl/grant/valid2/runtest.sh
@@ -0,0 +1,180 @@
+#!/bin/bash
+
+. ../../../prepare.inc.sh
+. ../../../toolbox.inc.sh
+
+
+# ---- do the actual testing ----
+
+if [ $have_grant = 0 ]
+then
+ toolbox_skip_test $TEST "SKIPPING DUE TO LACK OF GRANT PERMIT"
+ exit 0
+fi
+
+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
+
+# Create a keyring and remove most permissions from it; leaving just
+# setsec for the owner.
+marker "ADD KEYRING"
+create_keyring lizard $keyringid
+expect_keyid keyid
+marker "REMOVE PERMITS"
+grant_key_permit $keyid own S
+grant_key_permit $keyid pos 0
+grant_key_permit $keyid grp 0
+grant_key_permit $keyid all 0
+
+# Test the View permit
+marker "TEST VIEW"
+describe_key --fail $keyid
+expect_error EACCES
+grant_key_permit $keyid all v
+describe_key $keyid
+grant_key_permit $keyid all 0
+describe_key --fail $keyid
+expect_error EACCES
+
+# Test the Read permit
+marker "TEST READ"
+list_keyring --fail $keyid
+expect_error EACCES
+grant_key_permit $keyid all r
+list_keyring $keyid
+grant_key_permit $keyid all 0
+list_keyring --fail $keyid
+expect_error EACCES
+
+# Test the Write permit
+marker "TEST WRITE"
+create_key --fail user lizard gizzard $keyid
+expect_error EACCES
+grant_key_permit $keyid all w
+create_key user lizard gizzard $keyid
+expect_keyid keyid2
+grant_key_permit $keyid all 0
+unlink_key --fail $keyid $keyid2
+expect_error EACCES
+create_key --fail user lizard gizzard $keyid
+expect_error EACCES
+
+# Test the Search permit (we're allowed to read a key we can search out)
+marker "TEST SEARCH"
+search_for_key --fail $keyid user lizard
+expect_error EACCES
+grant_key_permit $keyid pos s
+search_for_key $keyid user lizard
+grant_key_permit $keyid pos 0
+search_for_key --fail $keyid user lizard
+expect_error EACCES
+
+marker "TEST SEARCH 2"
+search_for_key --fail @s user lizard
+expect_error ENOKEY
+grant_key_permit $keyid pos s
+search_for_key @s user lizard
+grant_key_permit $keyid pos 0
+search_for_key --fail @s user lizard
+expect_error ENOKEY
+
+# Test the Link permit
+marker "TEST LINK"
+link_key --fail $keyid @s
+expect_error EACCES
+grant_key_permit $keyid all l
+link_key $keyid @s
+grant_key_permit $keyid all 0
+link_key --fail $keyid @s
+expect_error EACCES
+unlink_key $keyid @s
+
+# Test the Clear permit
+marker "TEST CLEAR"
+clear_keyring --fail $keyid
+expect_error EACCES
+grant_key_permit $keyid all c
+clear_keyring $keyid
+grant_key_permit $keyid all 0
+clear_keyring --fail $keyid
+expect_error EACCES
+
+# Test the Join permit
+marker "TEST JOIN"
+new_session lizard /bin/true
+expect_joined_session ses
+if [ $ses = $keyid ]; then failed; fi
+grant_key_permit $keyid all j
+new_session lizard /bin/true
+expect_joined_session ses
+if [ $ses != $keyid ]; then failed; fi
+grant_key_permit $keyid all 0
+new_session lizard /bin/true
+expect_joined_session ses
+if [ $ses = $keyid ]; then failed; fi
+
+# Test the Invalidate permit
+marker "TEST INVAL"
+invalidate_key --fail $keyid
+expect_error EACCES
+grant_key_permit $keyid all I
+invalidate_key $keyid
+grant_key_permit --fail $keyid all 0
+expect_error ENOKEY
+invalidate_key --fail $keyid
+expect_error ENOKEY
+
+# Create a keyring and remove most permissions from it; leaving just
+# setsec for the owner.
+marker "ADD KEYRING 2"
+create_keyring lizard $keyringid
+expect_keyid keyid
+marker "REMOVE PERMITS 2"
+grant_key_permit $keyid own S
+grant_key_permit $keyid pos 0
+grant_key_permit $keyid grp 0
+grant_key_permit $keyid all 0
+
+# Test the Revoke permit
+marker "TEST REVOKE"
+revoke_key --fail $keyid
+expect_error EACCES
+grant_key_permit $keyid all R
+revoke_key $keyid
+grant_key_permit --fail $keyid all 0
+expect_error EKEYREVOKED
+revoke_key --fail $keyid
+expect_error EKEYREVOKED
+
+# Create a keyring and remove most permissions from it; leaving just
+# setsec for the owner.
+marker "ADD KEYRING 3"
+create_keyring lizard $keyringid
+expect_keyid keyid
+marker "REMOVE PERMITS 3"
+grant_key_permit $keyid all Sv
+grant_key_permit $keyid own 0
+grant_key_permit $keyid pos 0
+grant_key_permit $keyid grp 0
+
+# Test the Set Security permit
+marker "TEST SET SECURITY"
+describe_key $keyid
+grant_key_permit $keyid all v
+describe_key $keyid
+grant_key_permit --fail $keyid all Sv
+expect_error EACCES
+
+# remove the keyring we added
+marker "UNLINK KEYRING"
+unlink_key $keyringid @s
+
+echo "++++ FINISHED TEST: $result" >>$OUTPUTFILE
+
+# --- then report the results in the database ---
+toolbox_report_result $TEST $result
diff --git a/tests/keyctl/grant/valid3/runtest.sh b/tests/keyctl/grant/valid3/runtest.sh
new file mode 100644
index 0000000..e2003f2
--- /dev/null
+++ b/tests/keyctl/grant/valid3/runtest.sh
@@ -0,0 +1,180 @@
+#!/bin/bash
+
+. ../../../prepare.inc.sh
+. ../../../toolbox.inc.sh
+
+
+# ---- do the actual testing ----
+
+if [ $have_grant = 0 ]
+then
+ toolbox_skip_test $TEST "SKIPPING DUE TO LACK OF GRANT PERMIT"
+ exit 0
+fi
+
+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
+
+# Create a keyring and remove most permissions from it; leaving just
+# setsec for everyone.
+marker "ADD KEYRING"
+create_keyring lizard $keyringid
+expect_keyid keyid
+marker "REMOVE PERMITS"
+grant_key_permit $keyid all S
+grant_key_permit $keyid own 0
+grant_key_permit $keyid pos 0
+grant_key_permit $keyid grp 0
+
+# Test the View permit
+marker "TEST VIEW"
+describe_key --fail $keyid
+expect_error EACCES
+grant_key_permit $keyid own v
+describe_key $keyid
+grant_key_permit $keyid own 0
+describe_key --fail $keyid
+expect_error EACCES
+
+# Test the Read permit
+marker "TEST READ"
+list_keyring --fail $keyid
+expect_error EACCES
+grant_key_permit $keyid own r
+list_keyring $keyid
+grant_key_permit $keyid own 0
+list_keyring --fail $keyid
+expect_error EACCES
+
+# Test the Write permit
+marker "TEST WRITE"
+create_key --fail user lizard gizzard $keyid
+expect_error EACCES
+grant_key_permit $keyid own w
+create_key user lizard gizzard $keyid
+expect_keyid keyid2
+grant_key_permit $keyid own 0
+unlink_key --fail $keyid $keyid2
+expect_error EACCES
+create_key --fail user lizard gizzard $keyid
+expect_error EACCES
+
+# Test the Search permit (we're allowed to read a key we can search out)
+marker "TEST SEARCH"
+search_for_key --fail $keyid user lizard
+expect_error EACCES
+grant_key_permit $keyid pos s
+search_for_key $keyid user lizard
+grant_key_permit $keyid pos 0
+search_for_key --fail $keyid user lizard
+expect_error EACCES
+
+marker "TEST SEARCH 2"
+search_for_key --fail @s user lizard
+expect_error ENOKEY
+grant_key_permit $keyid pos s
+search_for_key @s user lizard
+grant_key_permit $keyid pos 0
+search_for_key --fail @s user lizard
+expect_error ENOKEY
+
+# Test the Link permit
+marker "TEST LINK"
+link_key --fail $keyid @s
+expect_error EACCES
+grant_key_permit $keyid own l
+link_key $keyid @s
+grant_key_permit $keyid own 0
+link_key --fail $keyid @s
+expect_error EACCES
+unlink_key $keyid @s
+
+# Test the Clear permit
+marker "TEST CLEAR"
+clear_keyring --fail $keyid
+expect_error EACCES
+grant_key_permit $keyid own c
+clear_keyring $keyid
+grant_key_permit $keyid own 0
+clear_keyring --fail $keyid
+expect_error EACCES
+
+# Test the Join permit
+marker "TEST JOIN"
+new_session lizard /bin/true
+expect_joined_session ses
+if [ $ses = $keyid ]; then failed; fi
+grant_key_permit $keyid own j
+new_session lizard /bin/true
+expect_joined_session ses
+if [ $ses != $keyid ]; then failed; fi
+grant_key_permit $keyid own 0
+new_session lizard /bin/true
+expect_joined_session ses
+if [ $ses = $keyid ]; then failed; fi
+
+# Test the Invalidate permit
+marker "TEST INVAL"
+invalidate_key --fail $keyid
+expect_error EACCES
+grant_key_permit $keyid own I
+invalidate_key $keyid
+grant_key_permit --fail $keyid all 0
+expect_error ENOKEY
+invalidate_key --fail $keyid
+expect_error ENOKEY
+
+# Create a keyring and remove most permissions from it; leaving just
+# setsec for the owner.
+marker "ADD KEYRING 2"
+create_keyring lizard $keyringid
+expect_keyid keyid
+marker "REMOVE PERMITS 2"
+grant_key_permit $keyid all S
+grant_key_permit $keyid own 0
+grant_key_permit $keyid pos 0
+grant_key_permit $keyid grp 0
+
+# Test the Revoke permit
+marker "TEST REVOKE"
+revoke_key --fail $keyid
+expect_error EACCES
+grant_key_permit $keyid own R
+revoke_key $keyid
+grant_key_permit --fail $keyid all 0
+expect_error EKEYREVOKED
+revoke_key --fail $keyid
+expect_error EKEYREVOKED
+
+# Create a keyring and remove most permissions from it; leaving just
+# setsec for the owner.
+marker "ADD KEYRING 3"
+create_keyring lizard $keyringid
+expect_keyid keyid
+marker "REMOVE PERMITS 3"
+grant_key_permit $keyid own Sv
+grant_key_permit $keyid pos 0
+grant_key_permit $keyid grp 0
+grant_key_permit $keyid all 0
+
+# Test the Set Security permit
+marker "TEST SET SECURITY"
+describe_key $keyid
+grant_key_permit $keyid own v
+describe_key $keyid
+grant_key_permit --fail $keyid own Sv
+expect_error EACCES
+
+# remove the keyring we added
+marker "UNLINK KEYRING"
+unlink_key $keyringid @s
+
+echo "++++ FINISHED TEST: $result" >>$OUTPUTFILE
+
+# --- then report the results in the database ---
+toolbox_report_result $TEST $result
diff --git a/tests/keyctl/grant/valid4/runtest.sh b/tests/keyctl/grant/valid4/runtest.sh
new file mode 100644
index 0000000..aabcc3b
--- /dev/null
+++ b/tests/keyctl/grant/valid4/runtest.sh
@@ -0,0 +1,180 @@
+#!/bin/bash
+
+. ../../../prepare.inc.sh
+. ../../../toolbox.inc.sh
+
+
+# ---- do the actual testing ----
+
+if [ $have_grant = 0 ]
+then
+ toolbox_skip_test $TEST "SKIPPING DUE TO LACK OF GRANT PERMIT"
+ exit 0
+fi
+
+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
+
+# Create a keyring and remove most permissions from it; leaving just
+# setsec for the owner.
+marker "ADD KEYRING"
+create_keyring lizard $keyringid
+expect_keyid keyid
+marker "REMOVE PERMITS"
+grant_key_permit $keyid own S
+grant_key_permit $keyid pos 0
+grant_key_permit $keyid grp 0
+grant_key_permit $keyid all 0
+
+# Test the View permit
+marker "TEST VIEW"
+describe_key --fail $keyid
+expect_error EACCES
+grant_key_permit $keyid grp v
+describe_key $keyid
+grant_key_permit $keyid grp 0
+describe_key --fail $keyid
+expect_error EACCES
+
+# Test the Read permit
+marker "TEST READ"
+list_keyring --fail $keyid
+expect_error EACCES
+grant_key_permit $keyid grp r
+list_keyring $keyid
+grant_key_permit $keyid grp 0
+list_keyring --fail $keyid
+expect_error EACCES
+
+# Test the Write permit
+marker "TEST WRITE"
+create_key --fail user lizard gizzard $keyid
+expect_error EACCES
+grant_key_permit $keyid grp w
+create_key user lizard gizzard $keyid
+expect_keyid keyid2
+grant_key_permit $keyid grp 0
+unlink_key --fail $keyid $keyid2
+expect_error EACCES
+create_key --fail user lizard gizzard $keyid
+expect_error EACCES
+
+# Test the Search permit (we're allowed to read a key we can search out)
+marker "TEST SEARCH"
+search_for_key --fail $keyid user lizard
+expect_error EACCES
+grant_key_permit $keyid pos s
+search_for_key $keyid user lizard
+grant_key_permit $keyid pos 0
+search_for_key --fail $keyid user lizard
+expect_error EACCES
+
+marker "TEST SEARCH 2"
+search_for_key --fail @s user lizard
+expect_error ENOKEY
+grant_key_permit $keyid pos s
+search_for_key @s user lizard
+grant_key_permit $keyid pos 0
+search_for_key --fail @s user lizard
+expect_error ENOKEY
+
+# Test the Link permit
+marker "TEST LINK"
+link_key --fail $keyid @s
+expect_error EACCES
+grant_key_permit $keyid grp l
+link_key $keyid @s
+grant_key_permit $keyid grp 0
+link_key --fail $keyid @s
+expect_error EACCES
+unlink_key $keyid @s
+
+# Test the Clear permit
+marker "TEST CLEAR"
+clear_keyring --fail $keyid
+expect_error EACCES
+grant_key_permit $keyid grp c
+clear_keyring $keyid
+grant_key_permit $keyid grp 0
+clear_keyring --fail $keyid
+expect_error EACCES
+
+# Test the Join permit
+marker "TEST JOIN"
+new_session lizard /bin/true
+expect_joined_session ses
+if [ $ses = $keyid ]; then failed; fi
+grant_key_permit $keyid grp j
+new_session lizard /bin/true
+expect_joined_session ses
+if [ $ses != $keyid ]; then failed; fi
+grant_key_permit $keyid grp 0
+new_session lizard /bin/true
+expect_joined_session ses
+if [ $ses = $keyid ]; then failed; fi
+
+# Test the Invalidate permit
+marker "TEST INVAL"
+invalidate_key --fail $keyid
+expect_error EACCES
+grant_key_permit $keyid grp I
+invalidate_key $keyid
+grant_key_permit --fail $keyid grp 0
+expect_error ENOKEY
+invalidate_key --fail $keyid
+expect_error ENOKEY
+
+# Create a keyring and remove most permissions from it; leaving just
+# setsec for the owner.
+marker "ADD KEYRING 2"
+create_keyring lizard $keyringid
+expect_keyid keyid
+marker "REMOVE PERMITS 2"
+grant_key_permit $keyid own S
+grant_key_permit $keyid pos 0
+grant_key_permit $keyid grp 0
+grant_key_permit $keyid all 0
+
+# Test the Revoke permit
+marker "TEST REVOKE"
+revoke_key --fail $keyid
+expect_error EACCES
+grant_key_permit $keyid grp R
+revoke_key $keyid
+grant_key_permit --fail $keyid grp 0
+expect_error EKEYREVOKED
+revoke_key --fail $keyid
+expect_error EKEYREVOKED
+
+# Create a keyring and remove most permissions from it; leaving just
+# setsec for the owner.
+marker "ADD KEYRING 3"
+create_keyring lizard $keyringid
+expect_keyid keyid
+marker "REMOVE PERMITS 3"
+grant_key_permit $keyid grp Sv
+grant_key_permit $keyid own 0
+grant_key_permit $keyid pos 0
+grant_key_permit $keyid all 0
+
+# Test the Set Security permit
+marker "TEST SET SECURITY"
+describe_key $keyid
+grant_key_permit $keyid grp v
+describe_key $keyid
+grant_key_permit --fail $keyid grp Sv
+expect_error EACCES
+
+# remove the keyring we added
+marker "UNLINK KEYRING"
+unlink_key $keyringid @s
+
+echo "++++ FINISHED TEST: $result" >>$OUTPUTFILE
+
+# --- then report the results in the database ---
+toolbox_report_result $TEST $result
diff --git a/tests/keyctl/grant/valid5/runtest.sh b/tests/keyctl/grant/valid5/runtest.sh
new file mode 100644
index 0000000..1d2b6b4
--- /dev/null
+++ b/tests/keyctl/grant/valid5/runtest.sh
@@ -0,0 +1,200 @@
+#!/bin/bash
+
+. ../../../prepare.inc.sh
+. ../../../toolbox.inc.sh
+
+
+# ---- do the actual testing ----
+
+if [ $have_grant = 0 ]
+then
+ toolbox_skip_test $TEST "SKIPPING DUE TO LACK OF GRANT PERMIT"
+ exit 0
+fi
+
+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
+
+# Create a keyring and remove most permissions from it; leaving just
+# setsec for the owner.
+marker "ADD KEYRING"
+create_keyring lizard $keyringid
+expect_keyid keyid
+marker "REMOVE PERMITS"
+grant_key_permit $keyid own S
+grant_key_permit $keyid pos 0
+grant_key_permit $keyid grp 0
+grant_key_permit $keyid all 0
+
+# Test the View permit
+marker "TEST VIEW"
+describe_key --fail $keyid
+expect_error EACCES
+grant_key_permit $keyid pos v
+describe_key --fail $keyid
+expect_error EACCES
+grant_key_permit $keyid pos vs
+describe_key $keyid
+grant_key_permit $keyid pos 0
+describe_key --fail $keyid
+expect_error EACCES
+
+# Test the Read permit
+marker "TEST READ"
+list_keyring --fail $keyid
+expect_error EACCES
+grant_key_permit $keyid pos r
+list_keyring --fail $keyid
+expect_error EACCES
+grant_key_permit $keyid pos rs
+list_keyring $keyid
+grant_key_permit $keyid pos 0
+list_keyring --fail $keyid
+expect_error EACCES
+
+# Test the Write permit
+marker "TEST WRITE"
+create_key --fail user lizard gizzard $keyid
+expect_error EACCES
+grant_key_permit $keyid pos ws
+create_key user lizard gizzard $keyid
+expect_keyid keyid2
+grant_key_permit $keyid pos 0
+unlink_key --fail $keyid $keyid2
+expect_error EACCES
+create_key --fail user lizard gizzard $keyid
+expect_error EACCES
+
+# Test the Search permit (we're allowed to read a key we can search out)
+marker "TEST SEARCH"
+search_for_key --fail $keyid user lizard
+expect_error EACCES
+grant_key_permit $keyid pos s
+search_for_key $keyid user lizard
+grant_key_permit $keyid pos 0
+search_for_key --fail $keyid user lizard
+expect_error EACCES
+
+marker "TEST SEARCH 2"
+search_for_key --fail @s user lizard
+expect_error ENOKEY
+grant_key_permit $keyid pos s
+search_for_key @s user lizard
+grant_key_permit $keyid pos 0
+search_for_key --fail @s user lizard
+expect_error ENOKEY
+
+# Test the Link permit
+marker "TEST LINK"
+link_key --fail $keyid @s
+expect_error EACCES
+grant_key_permit $keyid pos l
+link_key --fail $keyid @s
+expect_error EACCES
+grant_key_permit $keyid pos ls
+link_key $keyid @s
+grant_key_permit $keyid pos 0
+link_key --fail $keyid @s
+expect_error EACCES
+unlink_key $keyid @s
+
+# Test the Clear permit
+marker "TEST CLEAR"
+clear_keyring --fail $keyid
+expect_error EACCES
+grant_key_permit $keyid pos c
+clear_keyring --fail $keyid
+expect_error EACCES
+grant_key_permit $keyid pos cs
+clear_keyring $keyid
+grant_key_permit $keyid pos 0
+clear_keyring --fail $keyid
+expect_error EACCES
+
+# Test the Join permit. The possessor join permit is ineffective by
+# design.
+marker "TEST JOIN"
+new_session lizard /bin/true
+expect_joined_session ses
+if [ $ses = $keyid ]; then failed; fi
+pause_till_key_destroyed $ses
+grant_key_permit $keyid pos j
+new_session lizard /bin/true
+expect_joined_session ses
+if [ $ses = $keyid ]; then failed; fi
+grant_key_permit $keyid pos 0
+new_session lizard /bin/true
+expect_joined_session ses
+if [ $ses = $keyid ]; then failed; fi
+
+# Test the Invalidate permit
+marker "TEST INVAL"
+invalidate_key --fail $keyid
+expect_error EACCES
+grant_key_permit $keyid pos I
+invalidate_key --fail $keyid
+expect_error EACCES
+grant_key_permit $keyid pos Is
+invalidate_key $keyid
+grant_key_permit --fail $keyid pos 0
+expect_error ENOKEY
+invalidate_key --fail $keyid
+expect_error ENOKEY
+
+# Create a keyring and remove most permissions from it; leaving just
+# setsec for the owner.
+marker "ADD KEYRING 2"
+create_keyring lizard $keyringid
+expect_keyid keyid
+marker "REMOVE PERMITS 2"
+grant_key_permit $keyid own S
+grant_key_permit $keyid pos 0
+grant_key_permit $keyid grp 0
+grant_key_permit $keyid all 0
+
+# Test the Revoke permit
+marker "TEST REVOKE"
+revoke_key --fail $keyid
+expect_error EACCES
+grant_key_permit $keyid pos R
+revoke_key --fail $keyid
+expect_error EACCES
+grant_key_permit $keyid pos Rs
+revoke_key $keyid
+grant_key_permit --fail $keyid pos 0
+expect_error EKEYREVOKED
+revoke_key --fail $keyid
+expect_error EKEYREVOKED
+
+# Create a keyring and remove most permissions from it; leaving just
+# setsec for the owner.
+marker "ADD KEYRING 3"
+create_keyring lizard $keyringid
+expect_keyid keyid
+marker "REMOVE PERMITS 3"
+grant_key_permit $keyid pos Ssv
+grant_key_permit $keyid own 0
+grant_key_permit $keyid grp 0
+grant_key_permit $keyid all 0
+
+# Test the Set Security permit
+marker "TEST SET SECURITY"
+describe_key $keyid
+grant_key_permit $keyid pos sv
+describe_key $keyid
+grant_key_permit --fail $keyid pos Ssv
+expect_error EACCES
+
+# remove the keyring we added
+marker "UNLINK KEYRING"
+unlink_key $keyringid @s
+
+echo "++++ FINISHED TEST: $result" >>$OUTPUTFILE
+
+# --- then report the results in the database ---
+toolbox_report_result $TEST $result
diff --git a/tests/prepare.inc.sh b/tests/prepare.inc.sh
index 9aa2187..2b263be 100644
--- a/tests/prepare.inc.sh
+++ b/tests/prepare.inc.sh
@@ -98,6 +98,7 @@ have_dh_compute=0
have_restrict_keyring=0
have_notify=0
have_acl=0
+have_grant=0
if keyctl supports capabilities >&/dev/null
then
diff --git a/tests/toolbox.inc.sh b/tests/toolbox.inc.sh
index 609a6c7..4af465f 100644
--- a/tests/toolbox.inc.sh
+++ b/tests/toolbox.inc.sh
@@ -1404,6 +1404,32 @@ function search_for_key ()
###############################################################################
#
+# Grant permits on a key.
+#
+###############################################################################
+function grant_key_permit ()
+{
+ my_exitval=0
+ if [ "x$1" = "x--fail" ]
+ then
+ my_exitval=1
+ shift
+ elif [ "x$1" = "x--fail2" ]
+ then
+ my_exitval=2
+ shift
+ fi
+
+ echo keyctl grant "$@" >>$OUTPUTFILE
+ keyctl grant "$@" >>$OUTPUTFILE 2>&1
+ if [ $? != $my_exitval ]
+ then
+ failed
+ fi
+}
+
+###############################################################################
+#
# set the permissions mask on a key
#
###############################################################################
@@ -1532,6 +1558,26 @@ function new_session_to_parent ()
###############################################################################
#
+# Extract the joined session ID from the log.
+#
+###############################################################################
+function expect_joined_session ()
+{
+ my_varname=$1
+
+ my_session="`tail -1 $OUTPUTFILE`"
+
+ if ! expr "$my_session" : '^Joined session keyring: [0-9][0-9]*$' >&/dev/null
+ then
+ failed
+ fi
+
+ my_session=`echo $my_session | awk '{printf $4}'`
+ eval $my_varname="\"$my_session\""
+}
+
+###############################################################################
+#
# instantiate a key
#
###############################################################################
diff --git a/version.lds b/version.lds
index 6c34adf..bfa77a5 100644
--- a/version.lds
+++ b/version.lds
@@ -102,5 +102,6 @@ KEYUTILS_1.9 {
KEYUTILS_1.10 {
/* Management functions */
keyctl_watch_key;
+ keyctl_grant_permission;
} KEYUTILS_1.9;