diff options
author | David Howells <dhowells@redhat.com> | 2010-02-22 15:37:25 +0000 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2010-02-22 15:37:25 +0000 |
commit | 5291796474869579f151f7821410e3ef96d1fa7e (patch) | |
tree | 0b0fa1646e27a7403017dfcbb09c161ce77e22da /keyctl.c | |
download | keyutils-5291796474869579f151f7821410e3ef96d1fa7e.tar.gz |
keyutils historical version 0.1v0.1
Diffstat (limited to 'keyctl.c')
-rw-r--r-- | keyctl.c | 1127 |
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() */ |