summaryrefslogtreecommitdiff
path: root/keyctl.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2010-02-22 15:37:25 +0000
committerDavid Howells <dhowells@redhat.com>2010-02-22 15:37:25 +0000
commit5291796474869579f151f7821410e3ef96d1fa7e (patch)
tree0b0fa1646e27a7403017dfcbb09c161ce77e22da /keyctl.c
downloadkeyutils-5291796474869579f151f7821410e3ef96d1fa7e.tar.gz
keyutils historical version 0.1v0.1
Diffstat (limited to 'keyctl.c')
-rw-r--r--keyctl.c1127
1 files changed, 1127 insertions, 0 deletions
diff --git a/keyctl.c b/keyctl.c
new file mode 100644
index 0000000..f3e54bc
--- /dev/null
+++ b/keyctl.c
@@ -0,0 +1,1127 @@
+/* keyctl.c: key control program
+ *
+ * Copyright (C) 2005 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <errno.h>
+#include <asm/unistd.h>
+#include "keyutil.h"
+
+struct command {
+ int (*action)(int argc, char *argv[]);
+ const char *name;
+ const char *format;
+};
+
+static int act_keyctl_show(int argc, char *argv[]);
+static int act_keyctl_add(int argc, char *argv[]);
+static int act_keyctl_request(int argc, char *argv[]);
+static int act_keyctl_request2(int argc, char *argv[]);
+static int act_keyctl_update(int argc, char *argv[]);
+static int act_keyctl_newring(int argc, char *argv[]);
+static int act_keyctl_revoke(int argc, char *argv[]);
+static int act_keyctl_clear(int argc, char *argv[]);
+static int act_keyctl_link(int argc, char *argv[]);
+static int act_keyctl_unlink(int argc, char *argv[]);
+static int act_keyctl_search(int argc, char *argv[]);
+static int act_keyctl_read(int argc, char *argv[]);
+static int act_keyctl_pipe(int argc, char *argv[]);
+static int act_keyctl_print(int argc, char *argv[]);
+static int act_keyctl_list(int argc, char *argv[]);
+static int act_keyctl_rlist(int argc, char *argv[]);
+static int act_keyctl_describe(int argc, char *argv[]);
+static int act_keyctl_rdescribe(int argc, char *argv[]);
+static int act_keyctl_chown(int argc, char *argv[]);
+static int act_keyctl_chgrp(int argc, char *argv[]);
+static int act_keyctl_setperm(int argc, char *argv[]);
+static int act_keyctl_session(int argc, char *argv[]);
+static int act_keyctl_instantiate(int argc, char *argv[]);
+static int act_keyctl_negate(int argc, char *argv[]);
+
+const struct command commands[] = {
+ { act_keyctl_show, "show", "" },
+ { act_keyctl_add, "add", "<type> <desc> <data> <keyring>" },
+ { act_keyctl_request, "request", "<type> <desc> [<dest_keyring>]" },
+ { act_keyctl_request2, "request2", "<type> <desc> <info> [<dest_keyring>]" },
+ { act_keyctl_update, "update", "<key> <data>" },
+ { act_keyctl_newring, "newring", "<name> <keyring>" },
+ { act_keyctl_revoke, "revoke", "<key>" },
+ { act_keyctl_clear, "clear", "<keyring>" },
+ { act_keyctl_link, "link", "<key> <keyring>" },
+ { act_keyctl_unlink, "unlink", "<key> <keyring>" },
+ { act_keyctl_search, "search", "<keyring> <type> <desc> [<dest_keyring>]" },
+ { act_keyctl_read, "read", "<key>" },
+ { act_keyctl_pipe, "pipe", "<key>" },
+ { act_keyctl_print, "print", "<key>" },
+ { act_keyctl_list, "list", "<keyring>" },
+ { act_keyctl_rlist, "rlist", "<keyring>" },
+ { act_keyctl_describe, "describe", "<keyring>" },
+ { act_keyctl_rdescribe, "rdescribe", "<keyring> [sep]" },
+ { act_keyctl_chown, "chown", "<key> <uid>" },
+ { act_keyctl_chgrp, "chgrp", "<key> <gid>" },
+ { act_keyctl_setperm, "setperm", "<key> <mask>" },
+ { act_keyctl_session, "session", "" },
+ { act_keyctl_session, "session", "- [<prog> <arg1> <arg2> ...]" },
+ { act_keyctl_session, "session", "<name> [<prog> <arg1> <arg2> ...]" },
+ { act_keyctl_instantiate, "instantiate","<key> <data> <keyring>" },
+ { act_keyctl_negate, "negate", "<key> <timeout> <keyring>" },
+ { NULL, NULL, NULL }
+};
+
+static int dump_key_tree(key_serial_t keyring, const char *name);
+static void format(void) __attribute__((noreturn));
+static void error(const char *msg) __attribute__((noreturn));
+static key_serial_t get_key_id(const char *arg);
+
+/*****************************************************************************/
+/*
+ * execute the appropriate subcommand
+ */
+int main(int argc, char *argv[])
+{
+ const struct command *cmd, *best;
+ int n;
+
+ argv++;
+ argc--;
+
+ if (argc == 0)
+ format();
+
+ /* find the best fit command */
+ best = NULL;
+ n = strlen(*argv);
+
+ for (cmd = commands; cmd->action; cmd++) {
+ if (memcmp(cmd->name, *argv, n) != 0)
+ continue;
+
+ if (cmd->name[n] == 0) {
+ /* exact match */
+ best = cmd;
+ break;
+ }
+
+ /* partial match */
+ if (best) {
+ fprintf(stderr, "Ambiguous command\n");
+ exit(2);
+ }
+
+ best = cmd;
+ }
+
+ if (!best) {
+ fprintf(stderr, "Unknown command\n");
+ exit(2);
+ }
+
+ return best->action(argc, argv);
+
+} /* end main() */
+
+/*****************************************************************************/
+/*
+ * display command format information
+ */
+static void format(void)
+{
+ const struct command *cmd;
+
+ fprintf(stderr, "Format:\n");
+
+ for (cmd = commands; cmd->action; cmd++)
+ fprintf(stderr, " keyctl %s %s\n", cmd->name, cmd->format);
+
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Key/keyring ID:\n");
+ fprintf(stderr, " <nnn> numeric keyring ID\n");
+ fprintf(stderr, " @t thread keyring\n");
+ fprintf(stderr, " @p process keyring\n");
+ fprintf(stderr, " @s session keyring\n");
+ fprintf(stderr, " @u user keyring\n");
+ fprintf(stderr, " @us user default session keyring\n");
+ fprintf(stderr, " @g group keyring\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "<type> can be \"user\" for a user-defined keyring\n");
+ fprintf(stderr, "If you do this, prefix the description with \"<subtype>:\"\n");
+
+ exit(2);
+
+} /* end format() */
+
+/*****************************************************************************/
+/*
+ * handle an error
+ */
+static inline void error(const char *msg)
+{
+ perror(msg);
+ exit(1);
+
+} /* end error() */
+
+/*****************************************************************************/
+/*
+ * show the parent process's session keyring
+ */
+static int act_keyctl_show(int argc, char *argv[])
+{
+ if (argc != 1)
+ format();
+
+ dump_key_tree(KEY_SPEC_SESSION_KEYRING, "Session Keyring");
+ return 0;
+
+} /* end act_keyctl_show() */
+
+/*****************************************************************************/
+/*
+ * add a key
+ */
+static int act_keyctl_add(int argc, char *argv[])
+{
+ key_serial_t dest;
+ int ret;
+
+ if (argc != 5)
+ format();
+
+ dest = get_key_id(argv[4]);
+
+ ret = add_key(argv[1], argv[2], argv[3], strlen(argv[3]), dest);
+ if (ret < 0)
+ error("add_key");
+
+ /* print the resulting key ID */
+ printf("%d\n", ret);
+ return 0;
+
+} /* end act_keyctl_add() */
+
+/*****************************************************************************/
+/*
+ * request a key
+ */
+static int act_keyctl_request(int argc, char *argv[])
+{
+ key_serial_t dest;
+ int ret;
+
+ if (argc != 3 && argc != 4)
+ format();
+
+ dest = 0;
+ if (argc == 4)
+ dest = get_key_id(argv[3]);
+
+ ret = request_key(argv[1], argv[2], NULL, dest);
+ if (ret < 0)
+ error("request_key");
+
+ /* print the resulting key ID */
+ printf("%d\n", ret);
+ return 0;
+
+} /* end act_keyctl_request() */
+
+/*****************************************************************************/
+/*
+ * request a key, with recourse to /sbin/request-key
+ */
+static int act_keyctl_request2(int argc, char *argv[])
+{
+ key_serial_t dest;
+ int ret;
+
+ if (argc != 4 && argc != 5)
+ format();
+
+ dest = 0;
+ if (argc == 5)
+ dest = get_key_id(argv[4]);
+
+ ret = request_key(argv[1], argv[2], argv[3], dest);
+ if (ret < 0)
+ error("request_key");
+
+ /* print the resulting key ID */
+ printf("%d\n", ret);
+ return 0;
+
+} /* end act_keyctl_request2() */
+
+/*****************************************************************************/
+/*
+ * update a key
+ */
+static int act_keyctl_update(int argc, char *argv[])
+{
+ key_serial_t key;
+
+ if (argc != 3)
+ format();
+
+ key = get_key_id(argv[1]);
+
+ if (keyctl_update(key, argv[2], strlen(argv[2])) < 0)
+ error("keyctl_update");
+
+ return 0;
+
+} /* end act_keyctl_update() */
+
+/*****************************************************************************/
+/*
+ * create a new keyring
+ */
+static int act_keyctl_newring(int argc, char *argv[])
+{
+ key_serial_t dest;
+ int ret;
+
+ if (argc != 3)
+ format();
+
+ dest = get_key_id(argv[2]);
+
+ ret = add_key("keyring", argv[1], NULL, 0, dest);
+ if (ret < 0)
+ error("add_key");
+
+ printf("%d\n", ret);
+ return 0;
+
+} /* end act_keyctl_newring() */
+
+/*****************************************************************************/
+/*
+ * revoke a key
+ */
+static int act_keyctl_revoke(int argc, char *argv[])
+{
+ key_serial_t key;
+
+ if (argc != 2)
+ format();
+
+ key = get_key_id(argv[1]);
+
+ if (keyctl_revoke(key) < 0)
+ error("keyctl_revoke");
+
+ return 0;
+
+} /* end act_keyctl_revoke() */
+
+/*****************************************************************************/
+/*
+ * clear a keyring
+ */
+static int act_keyctl_clear(int argc, char *argv[])
+{
+ key_serial_t keyring;
+
+ if (argc != 2)
+ format();
+
+ keyring = get_key_id(argv[1]);
+
+ if (keyctl_clear(keyring) < 0)
+ error("keyctl_clear");
+
+ return 0;
+
+} /* end act_keyctl_clear() */
+
+/*****************************************************************************/
+/*
+ * link a key to a keyring
+ */
+static int act_keyctl_link(int argc, char *argv[])
+{
+ key_serial_t keyring, key;
+
+ if (argc != 3)
+ format();
+
+ key = get_key_id(argv[1]);
+ keyring = get_key_id(argv[2]);
+
+ if (keyctl_link(key, keyring) < 0)
+ error("keyctl_link");
+
+ return 0;
+
+} /* end act_keyctl_link() */
+
+/*****************************************************************************/
+/*
+ * unlink a key from a keyrign
+ */
+static int act_keyctl_unlink(int argc, char *argv[])
+{
+ key_serial_t keyring, key;
+
+ if (argc != 3)
+ format();
+
+ key = get_key_id(argv[1]);
+ keyring = get_key_id(argv[2]);
+
+ if (keyctl_unlink(key, keyring) < 0)
+ error("keyctl_unlink");
+
+ return 0;
+
+} /* end act_keyctl_unlink() */
+
+/*****************************************************************************/
+/*
+ * search a keyring for a key
+ */
+static int act_keyctl_search(int argc, char *argv[])
+{
+ key_serial_t keyring, dest;
+ int ret;
+
+ if (argc != 4 && argc != 5)
+ format();
+
+ keyring = get_key_id(argv[1]);
+
+ dest = 0;
+ if (argc == 5)
+ dest = get_key_id(argv[4]);
+
+ ret = keyctl_search(keyring, argv[2], argv[3], dest);
+ if (ret < 0)
+ error("keyctl_search");
+
+ /* print the ID of the key we found */
+ printf("%d\n", ret);
+ return 0;
+
+} /* end act_keyctl_search() */
+
+/*****************************************************************************/
+/*
+ * read a key
+ */
+static int act_keyctl_read(int argc, char *argv[])
+{
+ key_serial_t key;
+ void *buffer;
+ char *p;
+ int ret, sep, col;
+
+ if (argc != 2)
+ format();
+
+ key = get_key_id(argv[1]);
+
+ /* read the key payload data */
+ ret = keyctl_read_alloc(key, &buffer);
+ if (ret < 0)
+ error("keyctl_read_alloc");
+
+ if (ret == 0) {
+ printf("No data in key\n");
+ return 0;
+ }
+
+ /* hexdump the contents */
+ printf("%u bytes of data in key:\n", ret);
+
+ sep = 0;
+ col = 0;
+ p = buffer;
+
+ do {
+ if (sep) {
+ putchar(sep);
+ sep = 0;
+ }
+
+ printf("%02hhx", *p);
+ p++;
+
+ col++;
+ if (col % 32 == 0)
+ sep = '\n';
+ else if (col % 4 == 0)
+ sep = ' ';
+
+ } while (--ret > 0);
+
+ printf("\n");
+ return 0;
+
+} /* end act_keyctl_read() */
+
+/*****************************************************************************/
+/*
+ * read a key and dump raw to stdout
+ */
+static int act_keyctl_pipe(int argc, char *argv[])
+{
+ key_serial_t key;
+ void *buffer;
+ int ret;
+
+ if (argc != 2)
+ format();
+
+ key = get_key_id(argv[1]);
+
+ /* read the key payload data */
+ ret = keyctl_read_alloc(key, &buffer);
+ if (ret < 0)
+ error("keyctl_read_alloc");
+
+ if (ret > 0)
+ write(1, buffer, ret);
+ return 0;
+
+} /* end act_keyctl_pipe() */
+
+/*****************************************************************************/
+/*
+ * read a key and dump to stdout in printable form
+ */
+static int act_keyctl_print(int argc, char *argv[])
+{
+ key_serial_t key;
+ void *buffer;
+ char *p;
+ int loop, ret;
+
+ if (argc != 2)
+ format();
+
+ key = get_key_id(argv[1]);
+
+ /* read the key payload data */
+ ret = keyctl_read_alloc(key, &buffer);
+ if (ret < 0)
+ error("keyctl_read_alloc");
+
+ /* see if it's printable */
+ p = buffer;
+ for (loop = ret; loop > 0; loop--, p++)
+ if (!isprint(*p))
+ goto not_printable;
+
+ /* it is */
+ printf("%s\n", (char *) buffer);
+ return 0;
+
+not_printable:
+ /* it isn't */
+ printf(":hex:");
+ p = buffer;
+ for (loop = ret; loop > 0; loop--, p++)
+ printf("%02hhx", *p);
+ printf("\n");
+ return 0;
+
+} /* end act_keyctl_print() */
+
+/*****************************************************************************/
+/*
+ * list a keyring
+ */
+static int act_keyctl_list(int argc, char *argv[])
+{
+ key_serial_t keyring, key, *pk;
+ key_perm_t perm;
+ void *keylist;
+ char *buffer;
+ uid_t uid;
+ gid_t gid;
+ int count, tlen, dpos, dlen, ret;
+
+ if (argc != 2)
+ format();
+
+ keyring = get_key_id(argv[1]);
+
+ /* read the key payload data */
+ count = keyctl_read_alloc(keyring, &keylist);
+ if (count < 0)
+ error("keyctl_read_alloc");
+
+ count /= sizeof(key_serial_t);
+
+ if (count == 0) {
+ printf("keyring is empty\n");
+ return 0;
+ }
+
+ /* list the keys in the keyring */
+ if (count == 1)
+ printf("1 key in keyring:\n");
+ else
+ printf("%u keys in keyring:\n", count);
+
+ pk = keylist;
+ do {
+ key = *pk++;
+
+ ret = keyctl_describe_alloc(key, &buffer);
+ if (ret < 0) {
+ printf("%9d: key inaccessible (%m)\n", key);
+ continue;
+ }
+
+ uid = 0;
+ gid = 0;
+ perm = 0;
+
+ tlen = -1;
+ dpos = -1;
+ dlen = -1;
+
+ sscanf((char *) buffer, "%*[^;]%n;%d;%d;%x;%n%*[^;]%n",
+ &tlen, &uid, &gid, &perm, &dpos, &dlen);
+ if (dlen == -1) {
+ fprintf(stderr, "Unparseable description obtained for key %d\n", key);
+ exit(3);
+ }
+
+ printf("%9d: %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c %5d %5d %*.*s: %s\n",
+ key,
+ perm & KEY_USR_VIEW ? 'v' : '-',
+ perm & KEY_USR_READ ? 'r' : '-',
+ perm & KEY_USR_WRITE ? 'w' : '-',
+ perm & KEY_USR_SEARCH ? 's' : '-',
+ perm & KEY_USR_LINK ? 'l' : '-',
+ perm & KEY_GRP_VIEW ? 'v' : '-',
+ perm & KEY_GRP_READ ? 'r' : '-',
+ perm & KEY_GRP_WRITE ? 'w' : '-',
+ perm & KEY_GRP_SEARCH ? 's' : '-',
+ perm & KEY_GRP_LINK ? 'l' : '-',
+ perm & KEY_OTH_VIEW ? 'v' : '-',
+ perm & KEY_OTH_READ ? 'r' : '-',
+ perm & KEY_OTH_WRITE ? 'w' : '-',
+ perm & KEY_OTH_SEARCH ? 's' : '-',
+ perm & KEY_OTH_LINK ? 'l' : '-',
+ uid, gid,
+ tlen, tlen, buffer,
+ buffer + dpos);
+
+ free(buffer);
+
+ } while (--count);
+
+ return 0;
+
+} /* end act_keyctl_list() */
+
+/*****************************************************************************/
+/*
+ * produce a raw list of a keyring
+ */
+static int act_keyctl_rlist(int argc, char *argv[])
+{
+ key_serial_t keyring, key, *pk;
+ void *keylist;
+ int count;
+
+ if (argc != 2)
+ format();
+
+ keyring = get_key_id(argv[1]);
+
+ /* read the key payload data */
+ count = keyctl_read_alloc(keyring, &keylist);
+ if (count < 0)
+ error("keyctl_read_alloc");
+
+ count /= sizeof(key_serial_t);
+
+ /* list the keys in the keyring */
+ pk = keylist;
+ do {
+ key = *pk++;
+ printf("%d%c", key, count == 1 ? '\n' : ' ');
+ } while (--count);
+
+ return 0;
+
+} /* end act_keyctl_rlist() */
+
+/*****************************************************************************/
+/*
+ * describe a key
+ */
+static int act_keyctl_describe(int argc, char *argv[])
+{
+ key_serial_t key;
+ key_perm_t perm;
+ char *buffer;
+ uid_t uid;
+ gid_t gid;
+ int tlen, dpos, dlen, ret;
+
+ if (argc != 2)
+ format();
+
+ key = get_key_id(argv[1]);
+
+ /* get key description */
+ ret = keyctl_describe_alloc(key, &buffer);
+ if (ret < 0)
+ error("keyctl_describe");
+
+ /* parse it */
+ uid = 0;
+ gid = 0;
+ perm = 0;
+
+ tlen = -1;
+ dpos = -1;
+ dlen = -1;
+
+ sscanf(buffer, "%*[^;]%n;%d;%d;%x;%n%*[^;]%n",
+ &tlen, &uid, &gid, &perm, &dpos, &dlen);
+ if (dlen == -1) {
+ fprintf(stderr, "Unparseable description obtained for key %d\n", key);
+ exit(3);
+ }
+
+ /* display it */
+ printf("%9d: %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c %5d %5d %*.*s: %s\n",
+ key,
+ perm & KEY_USR_VIEW ? 'v' : '-',
+ perm & KEY_USR_READ ? 'r' : '-',
+ perm & KEY_USR_WRITE ? 'w' : '-',
+ perm & KEY_USR_SEARCH ? 's' : '-',
+ perm & KEY_USR_LINK ? 'l' : '-',
+ perm & KEY_GRP_VIEW ? 'v' : '-',
+ perm & KEY_GRP_READ ? 'r' : '-',
+ perm & KEY_GRP_WRITE ? 'w' : '-',
+ perm & KEY_GRP_SEARCH ? 's' : '-',
+ perm & KEY_GRP_LINK ? 'l' : '-',
+ perm & KEY_OTH_VIEW ? 'v' : '-',
+ perm & KEY_OTH_READ ? 'r' : '-',
+ perm & KEY_OTH_WRITE ? 'w' : '-',
+ perm & KEY_OTH_SEARCH ? 's' : '-',
+ perm & KEY_OTH_LINK ? 'l' : '-',
+ uid, gid,
+ tlen, tlen, buffer,
+ buffer + dpos);
+
+ return 0;
+
+} /* end act_keyctl_describe() */
+
+/*****************************************************************************/
+/*
+ * get raw key description
+ */
+static int act_keyctl_rdescribe(int argc, char *argv[])
+{
+ key_serial_t key;
+ char *buffer, *q;
+ int ret;
+
+ if (argc != 2 && argc != 3)
+ format();
+ if (argc == 3 && !argv[2][0])
+ format();
+
+ key = get_key_id(argv[1]);
+
+ /* get key description */
+ ret = keyctl_describe_alloc(key, &buffer);
+ if (ret < 0)
+ error("keyctl_describe");
+
+ /* replace semicolon separators with requested alternative */
+ if (argc == 3) {
+ for (q = buffer; *q; q++)
+ if (*q == ';')
+ *q = argv[2][0];
+ }
+
+ /* display raw description */
+ printf("%s\n", buffer);
+ return 0;
+
+} /* end act_keyctl_rdescribe() */
+
+/*****************************************************************************/
+/*
+ * change a key's ownership
+ */
+static int act_keyctl_chown(int argc, char *argv[])
+{
+ key_serial_t key;
+ uid_t uid;
+ char *q;
+
+ if (argc != 3)
+ format();
+
+ key = get_key_id(argv[1]);
+
+ uid = strtoul(argv[2], &q, 0);
+ if (*q) {
+ fprintf(stderr, "Unparsable uid: '%s'\n", argv[2]);
+ exit(2);
+ }
+
+ if (keyctl_chown(key, uid, -1) < 0)
+ error("keyctl_chown");
+
+ return 0;
+
+} /* end act_keyctl_chown() */
+
+/*****************************************************************************/
+/*
+ * change a key's group ownership
+ */
+static int act_keyctl_chgrp(int argc, char *argv[])
+{
+ key_serial_t key;
+ gid_t gid;
+ char *q;
+
+ if (argc != 3)
+ format();
+
+ key = get_key_id(argv[1]);
+
+ gid = strtoul(argv[2], &q, 0);
+ if (*q) {
+ fprintf(stderr, "Unparsable gid: '%s'\n", argv[2]);
+ exit(2);
+ }
+
+ if (keyctl_chown(key, -1, gid) < 0)
+ error("keyctl_chown");
+
+ return 0;
+
+} /* end act_keyctl_chgrp() */
+
+/*****************************************************************************/
+/*
+ * set the permissions on a key
+ */
+static int act_keyctl_setperm(int argc, char *argv[])
+{
+ key_serial_t key;
+ key_perm_t perm;
+ char *q;
+
+ if (argc != 3)
+ format();
+
+ key = get_key_id(argv[1]);
+ perm = strtoul(argv[2], &q, 0);
+ if (*q) {
+ fprintf(stderr, "Unparsable permissions: '%s'\n", argv[2]);
+ exit(2);
+ }
+
+ if (keyctl_setperm(key, perm) < 0)
+ error("keyctl_setperm");
+
+ return 0;
+
+} /* end act_keyctl_setperm() */
+
+/*****************************************************************************/
+/*
+ * start a process in a new session
+ */
+static int act_keyctl_session(int argc, char *argv[])
+{
+ char *p, *q;
+ int ret;
+
+ argv++;
+ argc--;
+
+ /* no extra arguments signifies a standard shell in an anonymous
+ * session */
+ p = NULL;
+ if (argc != 0) {
+ /* a dash signifies an anonymous session */
+ p = *argv;
+ if (strcmp(p, "-") == 0)
+ p = NULL;
+
+ argv++;
+ argc--;
+ }
+
+ /* create a new session keyring */
+ ret = keyctl_join_session_keyring(p);
+ if (ret < 0)
+ error("keyctl_join_session_keyring");
+
+ fprintf(stderr, "Joined session keyring: %d\n", ret);
+
+ /* run the standard shell if no arguments */
+ if (argc == 0) {
+ q = getenv("SHELL");
+ if (!q)
+ q = "/bin/sh";
+ execl(q, q, NULL);
+ error(q);
+ }
+
+ /* run the command specified */
+ execvp(argv[0], argv);
+ error(argv[0]);
+
+} /* end act_keyctl_session() */
+
+/*****************************************************************************/
+/*
+ * instantiate a key that's under construction
+ */
+static int act_keyctl_instantiate(int argc, char *argv[])
+{
+ key_serial_t key, dest;
+
+ if (argc != 4)
+ format();
+
+ key = get_key_id(argv[1]);
+ dest = get_key_id(argv[3]);
+
+ if (keyctl_instantiate(key, argv[2], strlen(argv[2]), dest) < 0)
+ error("keyctl_instantiate");
+
+ return 0;
+
+} /* end act_keyctl_instantiate() */
+
+/*****************************************************************************/
+/*
+ * negate a key that's under construction
+ */
+static int act_keyctl_negate(int argc, char *argv[])
+{
+ unsigned long timeout;
+ key_serial_t key, dest;
+ char *q;
+
+ if (argc != 4)
+ format();
+
+ key = get_key_id(argv[1]);
+
+ timeout = strtoul(argv[2], &q, 10);
+ if (*q) {
+ fprintf(stderr, "Unparsable timeout: '%s'\n", argv[2]);
+ exit(2);
+ }
+
+ dest = get_key_id(argv[3]);
+
+ if (keyctl_negate(key, timeout, dest) < 0)
+ error("keyctl_negate");
+
+ return 0;
+
+} /* end act_keyctl_negate() */
+
+/*****************************************************************************/
+/*
+ * parse a key identifier
+ */
+static key_serial_t get_key_id(const char *arg)
+{
+ key_serial_t id;
+ char *end;
+
+ /* handle a special keyring name */
+ if (arg[0] == '@') {
+ if (strcmp(arg, "@t" ) == 0) return KEY_SPEC_THREAD_KEYRING;
+ if (strcmp(arg, "@p" ) == 0) return KEY_SPEC_PROCESS_KEYRING;
+ if (strcmp(arg, "@s" ) == 0) return KEY_SPEC_SESSION_KEYRING;
+ if (strcmp(arg, "@u" ) == 0) return KEY_SPEC_USER_KEYRING;
+ if (strcmp(arg, "@us") == 0) return KEY_SPEC_USER_SESSION_KEYRING;
+ if (strcmp(arg, "@g" ) == 0) return KEY_SPEC_GROUP_KEYRING;
+
+ fprintf(stderr, "Unknown special key: '%s'\n", arg);
+ exit(2);
+ }
+
+ /* handle a numeric key ID */
+ id = strtoul(arg, &end, 0);
+ if (*end) {
+ fprintf(stderr, "Unparsable key: '%s'\n", arg);
+ exit(2);
+ }
+
+ return id;
+
+} /* end get_key_id() */
+
+/*****************************************************************************/
+/*
+ * recursively display a key/keyring tree
+ */
+static int dump_key_tree_aux(key_serial_t key, int depth, int more)
+{
+ static char dumpindent[64];
+ key_serial_t *pk;
+ key_perm_t perm;
+ size_t ringlen, desclen;
+ void *payload;
+ char *desc, type[255];
+ int uid, gid, ret, n, rdepth, kcount = 0;
+
+ if (depth > 8)
+ return 0;
+
+ /* find out how big this key's description is */
+ ret = keyctl_describe(key, NULL, 0);
+ if (ret < 0) {
+ printf("%d: key inaccessible (%m)\n", key);
+ return 0;
+ }
+ desclen = ret + 1;
+
+ desc = malloc(desclen);
+ if (!desc)
+ error("malloc");
+
+ /* read the description */
+ ret = keyctl_describe(key, desc, desclen);
+ if (ret < 0) {
+ printf("%d: key inaccessible (%m)\n", key);
+ free(desc);
+ return 0;
+ }
+
+ desclen = ret < desclen ? ret : desclen;
+
+ desc[desclen] = 0;
+
+ /* parse */
+ type[0] = 0;
+ uid = 0;
+ gid = 0;
+ perm = 0;
+ sscanf(desc, "%[^;];%d;%d;%x;%n",
+ type, &uid, &gid, &perm, &n);
+
+ /* and print */
+ printf("%9d"
+ " %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c %5d %5d "
+ " %s%s%s: %s\n"
+ ,
+ key,
+ perm & KEY_USR_LINK ? 'l' : '-',
+ perm & KEY_USR_SEARCH ? 's' : '-',
+ perm & KEY_USR_WRITE ? 'w' : '-',
+ perm & KEY_USR_READ ? 'r' : '-',
+ perm & KEY_USR_VIEW ? 'v' : '-',
+ perm & KEY_GRP_LINK ? 'l' : '-',
+ perm & KEY_GRP_SEARCH ? 's' : '-',
+ perm & KEY_GRP_WRITE ? 'w' : '-',
+ perm & KEY_GRP_READ ? 'r' : '-',
+ perm & KEY_GRP_VIEW ? 'v' : '-',
+ perm & KEY_OTH_LINK ? 'l' : '-',
+ perm & KEY_OTH_SEARCH ? 's' : '-',
+ perm & KEY_OTH_WRITE ? 'w' : '-',
+ perm & KEY_OTH_READ ? 'r' : '-',
+ perm & KEY_OTH_VIEW ? 'v' : '-',
+ uid, gid,
+ dumpindent,
+ depth > 0 ? "\\_ " : "",
+ type, desc + n);
+
+ /* if it's a keyring then we're going to want to recursively
+ * display it if we can */
+ if (strcmp(type, "keyring") == 0) {
+ /* find out how big the keyring is */
+ ret = keyctl_read(key, NULL, 0);
+ if (ret < 0)
+ error("keyctl_read");
+ if (ret == 0)
+ return 0;
+ ringlen = ret;
+
+ /* read its contents */
+ payload = malloc(ringlen);
+ if (!payload)
+ error("malloc");
+
+ ret = keyctl_read(key, payload, ringlen);
+ if (ret < 0)
+ error("keyctl_read");
+
+ ringlen = ret < ringlen ? ret : ringlen;
+ kcount = ringlen / sizeof(key_serial_t);
+
+ /* walk the keyring */
+ pk = payload;
+ do {
+ key = *pk++;
+
+ /* recurse into nexted keyrings */
+ if (strcmp(type, "keyring") == 0) {
+ if (depth == 0) {
+ rdepth = depth;
+ dumpindent[rdepth++] = ' ';
+ dumpindent[rdepth] = 0;
+ }
+ else {
+ rdepth = depth;
+ dumpindent[rdepth++] = ' ';
+ dumpindent[rdepth++] = ' ';
+ dumpindent[rdepth++] = ' ';
+ dumpindent[rdepth++] = ' ';
+ dumpindent[rdepth] = 0;
+ }
+
+ if (more)
+ dumpindent[depth + 0] = '|';
+
+ kcount += dump_key_tree_aux(key,
+ rdepth,
+ ringlen - 4 >= sizeof(key_serial_t));
+ }
+
+ } while (ringlen -= 4, ringlen >= sizeof(key_serial_t));
+
+ free(payload);
+ }
+
+ free(desc);
+ return kcount;
+
+} /* end dump_key_tree_aux() */
+
+/*****************************************************************************/
+/*
+ * recursively list a keyring's contents
+ */
+static int dump_key_tree(key_serial_t keyring, const char *name)
+{
+ printf("%s\n", name);
+ return dump_key_tree_aux(keyring, 0, 0);
+
+} /* end dump_key_tree() */