1 /* keyctl.c: key control program
3 * Copyright (C) 2005, 2011 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
21 #include <asm/unistd.h>
25 int (*action)(int argc, char *argv[]);
30 static int act_keyctl_show(int argc, char *argv[]);
31 static int act_keyctl_add(int argc, char *argv[]);
32 static int act_keyctl_padd(int argc, char *argv[]);
33 static int act_keyctl_request(int argc, char *argv[]);
34 static int act_keyctl_request2(int argc, char *argv[]);
35 static int act_keyctl_prequest2(int argc, char *argv[]);
36 static int act_keyctl_update(int argc, char *argv[]);
37 static int act_keyctl_pupdate(int argc, char *argv[]);
38 static int act_keyctl_newring(int argc, char *argv[]);
39 static int act_keyctl_revoke(int argc, char *argv[]);
40 static int act_keyctl_clear(int argc, char *argv[]);
41 static int act_keyctl_link(int argc, char *argv[]);
42 static int act_keyctl_unlink(int argc, char *argv[]);
43 static int act_keyctl_search(int argc, char *argv[]);
44 static int act_keyctl_read(int argc, char *argv[]);
45 static int act_keyctl_pipe(int argc, char *argv[]);
46 static int act_keyctl_print(int argc, char *argv[]);
47 static int act_keyctl_list(int argc, char *argv[]);
48 static int act_keyctl_rlist(int argc, char *argv[]);
49 static int act_keyctl_describe(int argc, char *argv[]);
50 static int act_keyctl_rdescribe(int argc, char *argv[]);
51 static int act_keyctl_chown(int argc, char *argv[]);
52 static int act_keyctl_chgrp(int argc, char *argv[]);
53 static int act_keyctl_setperm(int argc, char *argv[]);
54 static int act_keyctl_session(int argc, char *argv[]);
55 static int act_keyctl_instantiate(int argc, char *argv[]);
56 static int act_keyctl_pinstantiate(int argc, char *argv[]);
57 static int act_keyctl_negate(int argc, char *argv[]);
58 static int act_keyctl_timeout(int argc, char *argv[]);
59 static int act_keyctl_security(int argc, char *argv[]);
60 static int act_keyctl_new_session(int argc, char *argv[]);
61 static int act_keyctl_reject(int argc, char *argv[]);
62 static int act_keyctl_reap(int argc, char *argv[]);
63 static int act_keyctl_purge(int argc, char *argv[]);
65 const struct command commands[] = {
66 { act_keyctl_add, "add", "<type> <desc> <data> <keyring>" },
67 { act_keyctl_chgrp, "chgrp", "<key> <gid>" },
68 { act_keyctl_chown, "chown", "<key> <uid>" },
69 { act_keyctl_clear, "clear", "<keyring>" },
70 { act_keyctl_describe, "describe", "<keyring>" },
71 { act_keyctl_instantiate, "instantiate","<key> <data> <keyring>" },
72 { act_keyctl_link, "link", "<key> <keyring>" },
73 { act_keyctl_list, "list", "<keyring>" },
74 { act_keyctl_negate, "negate", "<key> <timeout> <keyring>" },
75 { act_keyctl_new_session, "new_session", "" },
76 { act_keyctl_newring, "newring", "<name> <keyring>" },
77 { act_keyctl_padd, "padd", "<type> <desc> <keyring>" },
78 { act_keyctl_pinstantiate, "pinstantiate","<key> <keyring>" },
79 { act_keyctl_pipe, "pipe", "<key>" },
80 { act_keyctl_prequest2, "prequest2", "<type> <desc> [<dest_keyring>]" },
81 { act_keyctl_print, "print", "<key>" },
82 { act_keyctl_pupdate, "pupdate", "<key>" },
83 { act_keyctl_purge, "purge", "<type>" },
84 { NULL, "purge", "[-p] [-i] <type> <desc>" },
85 { NULL, "purge", "-s <type> <desc>" },
86 { act_keyctl_rdescribe, "rdescribe", "<keyring> [sep]" },
87 { act_keyctl_read, "read", "<key>" },
88 { act_keyctl_reap, "reap", "[-v]" },
89 { act_keyctl_reject, "reject", "<key> <timeout> <error> <keyring>" },
90 { act_keyctl_request, "request", "<type> <desc> [<dest_keyring>]" },
91 { act_keyctl_request2, "request2", "<type> <desc> <info> [<dest_keyring>]" },
92 { act_keyctl_revoke, "revoke", "<key>" },
93 { act_keyctl_rlist, "rlist", "<keyring>" },
94 { act_keyctl_search, "search", "<keyring> <type> <desc> [<dest_keyring>]" },
95 { act_keyctl_security, "security", "<key>" },
96 { act_keyctl_session, "session", "" },
97 { NULL, "session", "- [<prog> <arg1> <arg2> ...]" },
98 { NULL, "session", "<name> [<prog> <arg1> <arg2> ...]" },
99 { act_keyctl_setperm, "setperm", "<key> <mask>" },
100 { act_keyctl_show, "show", "" },
101 { act_keyctl_timeout, "timeout", "<key> <timeout>" },
102 { act_keyctl_unlink, "unlink", "<key> [<keyring>]" },
103 { act_keyctl_update, "update", "<key> <data>" },
107 static int dump_key_tree(key_serial_t keyring, const char *name);
108 static void format(void) __attribute__((noreturn));
109 static void error(const char *msg) __attribute__((noreturn));
110 static key_serial_t get_key_id(const char *arg);
113 static gid_t mygid, *mygroups;
114 static int myngroups;
117 /*****************************************************************************/
121 static inline void error(const char *msg)
128 /*****************************************************************************/
130 * execute the appropriate subcommand
132 int main(int argc, char *argv[])
134 const struct command *cmd, *best;
143 /* find the best fit command */
147 for (cmd = commands; cmd->name; cmd++) {
150 if (memcmp(cmd->name, *argv, n) != 0)
153 if (cmd->name[n] == 0) {
161 fprintf(stderr, "Ambiguous command\n");
169 fprintf(stderr, "Unknown command\n");
173 /* grab my UID, GID and groups */
176 myngroups = getgroups(0, NULL);
178 if (myuid == -1 || mygid == -1 || myngroups == -1)
179 error("Unable to get UID/GID/#Groups\n");
181 mygroups = calloc(myngroups, sizeof(gid_t));
185 myngroups = getgroups(myngroups, mygroups);
187 error("Unable to get Groups\n");
189 return best->action(argc, argv);
193 /*****************************************************************************/
195 * display command format information
197 static void format(void)
199 const struct command *cmd;
201 fprintf(stderr, "Format:\n");
203 for (cmd = commands; cmd->name; cmd++)
204 fprintf(stderr, " keyctl %s %s\n", cmd->name, cmd->format);
206 fprintf(stderr, "\n");
207 fprintf(stderr, "Key/keyring ID:\n");
208 fprintf(stderr, " <nnn> numeric keyring ID\n");
209 fprintf(stderr, " @t thread keyring\n");
210 fprintf(stderr, " @p process keyring\n");
211 fprintf(stderr, " @s session keyring\n");
212 fprintf(stderr, " @u user keyring\n");
213 fprintf(stderr, " @us user default session keyring\n");
214 fprintf(stderr, " @g group keyring\n");
215 fprintf(stderr, " @a assumed request_key authorisation key\n");
216 fprintf(stderr, "\n");
217 fprintf(stderr, "<type> can be \"user\" for a user-defined keyring\n");
218 fprintf(stderr, "If you do this, prefix the description with \"<subtype>:\"\n");
224 /*****************************************************************************/
226 * grab data from stdin
228 static char *grab_stdin(void)
230 static char input[65536 + 1];
235 tmp = read(0, input + n, sizeof(input) - 1 - n);
244 } while (n < sizeof(input));
246 if (n >= sizeof(input)) {
247 fprintf(stderr, "Too much data read on stdin\n");
255 } /* end grab_stdin() */
257 /*****************************************************************************/
259 * convert the permissions mask to a string representing the permissions we
260 * have actually been granted
262 static void calc_perms(char *pretty, key_perm_t perm, uid_t uid, gid_t gid)
268 perms = (perm & KEY_POS_ALL) >> 24;
271 perms |= (perm & KEY_USR_ALL) >> 16;
277 perms |= (perm & KEY_GRP_ALL) >> 8;
282 for (loop = myngroups; loop > 0; loop--, pg++) {
284 perms |= (perm & KEY_GRP_ALL) >> 8;
290 perms |= (perm & KEY_OTH_ALL);
293 sprintf(pretty, "--%c%c%c%c%c%c",
294 perms & KEY_OTH_SETATTR ? 'a' : '-',
295 perms & KEY_OTH_LINK ? 'l' : '-',
296 perms & KEY_OTH_SEARCH ? 's' : '-',
297 perms & KEY_OTH_WRITE ? 'w' : '-',
298 perms & KEY_OTH_READ ? 'r' : '-',
299 perms & KEY_OTH_VIEW ? 'v' : '-');
301 } /* end calc_perms() */
303 /*****************************************************************************/
305 * show the parent process's session keyring
307 static int act_keyctl_show(int argc, char *argv[])
312 dump_key_tree(KEY_SPEC_SESSION_KEYRING, "Session Keyring");
315 } /* end act_keyctl_show() */
317 /*****************************************************************************/
321 static int act_keyctl_add(int argc, char *argv[])
329 dest = get_key_id(argv[4]);
331 ret = add_key(argv[1], argv[2], argv[3], strlen(argv[3]), dest);
335 /* print the resulting key ID */
339 } /* end act_keyctl_add() */
341 /*****************************************************************************/
343 * add a key, reading from a pipe
345 static int act_keyctl_padd(int argc, char *argv[])
355 args[3] = grab_stdin();
359 return act_keyctl_add(5, args);
361 } /* end act_keyctl_padd() */
363 /*****************************************************************************/
367 static int act_keyctl_request(int argc, char *argv[])
372 if (argc != 3 && argc != 4)
377 dest = get_key_id(argv[3]);
379 ret = request_key(argv[1], argv[2], NULL, dest);
381 error("request_key");
383 /* print the resulting key ID */
387 } /* end act_keyctl_request() */
389 /*****************************************************************************/
391 * request a key, with recourse to /sbin/request-key
393 static int act_keyctl_request2(int argc, char *argv[])
398 if (argc != 4 && argc != 5)
403 dest = get_key_id(argv[4]);
405 ret = request_key(argv[1], argv[2], argv[3], dest);
407 error("request_key");
409 /* print the resulting key ID */
413 } /* end act_keyctl_request2() */
415 /*****************************************************************************/
417 * request a key, with recourse to /sbin/request-key, reading the callout info
420 static int act_keyctl_prequest2(int argc, char *argv[])
424 if (argc != 3 && argc != 4)
430 args[3] = grab_stdin();
434 return act_keyctl_request2(argc + 1, args);
436 } /* end act_keyctl_prequest2() */
438 /*****************************************************************************/
442 static int act_keyctl_update(int argc, char *argv[])
449 key = get_key_id(argv[1]);
451 if (keyctl_update(key, argv[2], strlen(argv[2])) < 0)
452 error("keyctl_update");
456 } /* end act_keyctl_update() */
458 /*****************************************************************************/
460 * update a key, reading from a pipe
462 static int act_keyctl_pupdate(int argc, char *argv[])
471 args[2] = grab_stdin();
474 return act_keyctl_update(3, args);
476 } /* end act_keyctl_pupdate() */
478 /*****************************************************************************/
480 * create a new keyring
482 static int act_keyctl_newring(int argc, char *argv[])
490 dest = get_key_id(argv[2]);
492 ret = add_key("keyring", argv[1], NULL, 0, dest);
499 } /* end act_keyctl_newring() */
501 /*****************************************************************************/
505 static int act_keyctl_revoke(int argc, char *argv[])
512 key = get_key_id(argv[1]);
514 if (keyctl_revoke(key) < 0)
515 error("keyctl_revoke");
519 } /* end act_keyctl_revoke() */
521 /*****************************************************************************/
525 static int act_keyctl_clear(int argc, char *argv[])
527 key_serial_t keyring;
532 keyring = get_key_id(argv[1]);
534 if (keyctl_clear(keyring) < 0)
535 error("keyctl_clear");
539 } /* end act_keyctl_clear() */
541 /*****************************************************************************/
543 * link a key to a keyring
545 static int act_keyctl_link(int argc, char *argv[])
547 key_serial_t keyring, key;
552 key = get_key_id(argv[1]);
553 keyring = get_key_id(argv[2]);
555 if (keyctl_link(key, keyring) < 0)
556 error("keyctl_link");
560 } /* end act_keyctl_link() */
563 * Attempt to unlink a key matching the ID
565 static int act_keyctl_unlink_func(key_serial_t parent, key_serial_t key,
566 char *desc, int desc_len, void *data)
568 key_serial_t *target = data;
571 return keyctl_unlink(key, parent) < 0 ? 0 : 1;
576 * Unlink a key from a keyring or from the session keyring tree.
578 static int act_keyctl_unlink(int argc, char *argv[])
580 key_serial_t keyring, key;
583 if (argc != 2 && argc != 3)
586 key = get_key_id(argv[1]);
589 keyring = get_key_id(argv[2]);
590 if (keyctl_unlink(key, keyring) < 0)
591 error("keyctl_unlink");
593 n = recursive_session_key_scan(act_keyctl_unlink_func, &key);
594 printf("%d links removed\n", n);
600 /*****************************************************************************/
602 * search a keyring for a key
604 static int act_keyctl_search(int argc, char *argv[])
606 key_serial_t keyring, dest;
609 if (argc != 4 && argc != 5)
612 keyring = get_key_id(argv[1]);
616 dest = get_key_id(argv[4]);
618 ret = keyctl_search(keyring, argv[2], argv[3], dest);
620 error("keyctl_search");
622 /* print the ID of the key we found */
626 } /* end act_keyctl_search() */
628 /*****************************************************************************/
632 static int act_keyctl_read(int argc, char *argv[])
642 key = get_key_id(argv[1]);
644 /* read the key payload data */
645 ret = keyctl_read_alloc(key, &buffer);
647 error("keyctl_read_alloc");
650 printf("No data in key\n");
654 /* hexdump the contents */
655 printf("%u bytes of data in key:\n", ret);
667 printf("%02hhx", *p);
673 else if (col % 4 == 0)
681 } /* end act_keyctl_read() */
683 /*****************************************************************************/
685 * read a key and dump raw to stdout
687 static int act_keyctl_pipe(int argc, char *argv[])
696 key = get_key_id(argv[1]);
698 /* read the key payload data */
699 ret = keyctl_read_alloc(key, &buffer);
701 error("keyctl_read_alloc");
703 if (ret > 0 && write(1, buffer, ret) < 0)
707 } /* end act_keyctl_pipe() */
709 /*****************************************************************************/
711 * read a key and dump to stdout in printable form
713 static int act_keyctl_print(int argc, char *argv[])
723 key = get_key_id(argv[1]);
725 /* read the key payload data */
726 ret = keyctl_read_alloc(key, &buffer);
728 error("keyctl_read_alloc");
730 /* see if it's printable */
732 for (loop = ret; loop > 0; loop--, p++)
737 printf("%s\n", (char *) buffer);
744 for (loop = ret; loop > 0; loop--, p++)
745 printf("%02hhx", *p);
749 } /* end act_keyctl_print() */
751 /*****************************************************************************/
755 static int act_keyctl_list(int argc, char *argv[])
757 key_serial_t keyring, key, *pk;
760 char *buffer, pretty_mask[9];
763 int count, tlen, dpos, n, ret;
768 keyring = get_key_id(argv[1]);
770 /* read the key payload data */
771 count = keyctl_read_alloc(keyring, &keylist);
773 error("keyctl_read_alloc");
775 count /= sizeof(key_serial_t);
778 printf("keyring is empty\n");
782 /* list the keys in the keyring */
784 printf("1 key in keyring:\n");
786 printf("%u keys in keyring:\n", count);
792 ret = keyctl_describe_alloc(key, &buffer);
794 printf("%9d: key inaccessible (%m)\n", key);
805 n = sscanf((char *) buffer, "%*[^;]%n;%d;%d;%x;%n",
806 &tlen, &uid, &gid, &perm, &dpos);
808 fprintf(stderr, "Unparseable description obtained for key %d\n", key);
812 calc_perms(pretty_mask, perm, uid, gid);
814 printf("%9d: %s %5d %5d %*.*s: %s\n",
827 } /* end act_keyctl_list() */
829 /*****************************************************************************/
831 * produce a raw list of a keyring
833 static int act_keyctl_rlist(int argc, char *argv[])
835 key_serial_t keyring, key, *pk;
842 keyring = get_key_id(argv[1]);
844 /* read the key payload data */
845 count = keyctl_read_alloc(keyring, &keylist);
847 error("keyctl_read_alloc");
849 count /= sizeof(key_serial_t);
851 /* list the keys in the keyring */
857 for (; count > 0; count--) {
859 printf("%d%c", key, count == 1 ? '\n' : ' ');
865 } /* end act_keyctl_rlist() */
867 /*****************************************************************************/
871 static int act_keyctl_describe(int argc, char *argv[])
878 int tlen, dpos, n, ret;
883 key = get_key_id(argv[1]);
885 /* get key description */
886 ret = keyctl_describe_alloc(key, &buffer);
888 error("keyctl_describe");
898 n = sscanf(buffer, "%*[^;]%n;%d;%d;%x;%n",
899 &tlen, &uid, &gid, &perm, &dpos);
901 fprintf(stderr, "Unparseable description obtained for key %d\n", key);
907 " %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c"
908 " %5d %5d %*.*s: %s\n",
910 perm & KEY_POS_SETATTR ? 'a' : '-',
911 perm & KEY_POS_LINK ? 'l' : '-',
912 perm & KEY_POS_SEARCH ? 's' : '-',
913 perm & KEY_POS_WRITE ? 'w' : '-',
914 perm & KEY_POS_READ ? 'r' : '-',
915 perm & KEY_POS_VIEW ? 'v' : '-',
917 perm & KEY_USR_SETATTR ? 'a' : '-',
918 perm & KEY_USR_LINK ? 'l' : '-',
919 perm & KEY_USR_SEARCH ? 's' : '-',
920 perm & KEY_USR_WRITE ? 'w' : '-',
921 perm & KEY_USR_READ ? 'r' : '-',
922 perm & KEY_USR_VIEW ? 'v' : '-',
924 perm & KEY_GRP_SETATTR ? 'a' : '-',
925 perm & KEY_GRP_LINK ? 'l' : '-',
926 perm & KEY_GRP_SEARCH ? 's' : '-',
927 perm & KEY_GRP_WRITE ? 'w' : '-',
928 perm & KEY_GRP_READ ? 'r' : '-',
929 perm & KEY_GRP_VIEW ? 'v' : '-',
931 perm & KEY_OTH_SETATTR ? 'a' : '-',
932 perm & KEY_OTH_LINK ? 'l' : '-',
933 perm & KEY_OTH_SEARCH ? 's' : '-',
934 perm & KEY_OTH_WRITE ? 'w' : '-',
935 perm & KEY_OTH_READ ? 'r' : '-',
936 perm & KEY_OTH_VIEW ? 'v' : '-',
943 } /* end act_keyctl_describe() */
945 /*****************************************************************************/
947 * get raw key description
949 static int act_keyctl_rdescribe(int argc, char *argv[])
955 if (argc != 2 && argc != 3)
957 if (argc == 3 && !argv[2][0])
960 key = get_key_id(argv[1]);
962 /* get key description */
963 ret = keyctl_describe_alloc(key, &buffer);
965 error("keyctl_describe");
967 /* replace semicolon separators with requested alternative */
969 for (q = buffer; *q; q++)
974 /* display raw description */
975 printf("%s\n", buffer);
978 } /* end act_keyctl_rdescribe() */
980 /*****************************************************************************/
982 * change a key's ownership
984 static int act_keyctl_chown(int argc, char *argv[])
993 key = get_key_id(argv[1]);
995 uid = strtoul(argv[2], &q, 0);
997 fprintf(stderr, "Unparsable uid: '%s'\n", argv[2]);
1001 if (keyctl_chown(key, uid, -1) < 0)
1002 error("keyctl_chown");
1006 } /* end act_keyctl_chown() */
1008 /*****************************************************************************/
1010 * change a key's group ownership
1012 static int act_keyctl_chgrp(int argc, char *argv[])
1021 key = get_key_id(argv[1]);
1023 gid = strtoul(argv[2], &q, 0);
1025 fprintf(stderr, "Unparsable gid: '%s'\n", argv[2]);
1029 if (keyctl_chown(key, -1, gid) < 0)
1030 error("keyctl_chown");
1034 } /* end act_keyctl_chgrp() */
1036 /*****************************************************************************/
1038 * set the permissions on a key
1040 static int act_keyctl_setperm(int argc, char *argv[])
1049 key = get_key_id(argv[1]);
1050 perm = strtoul(argv[2], &q, 0);
1052 fprintf(stderr, "Unparsable permissions: '%s'\n", argv[2]);
1056 if (keyctl_setperm(key, perm) < 0)
1057 error("keyctl_setperm");
1061 } /* end act_keyctl_setperm() */
1063 /*****************************************************************************/
1065 * start a process in a new session
1067 static int act_keyctl_session(int argc, char *argv[])
1075 /* no extra arguments signifies a standard shell in an anonymous
1079 /* a dash signifies an anonymous session */
1081 if (strcmp(p, "-") == 0)
1088 /* create a new session keyring */
1089 ret = keyctl_join_session_keyring(p);
1091 error("keyctl_join_session_keyring");
1093 fprintf(stderr, "Joined session keyring: %d\n", ret);
1095 /* run the standard shell if no arguments */
1097 q = getenv("SHELL");
1104 /* run the command specified */
1105 execvp(argv[0], argv);
1108 } /* end act_keyctl_session() */
1110 /*****************************************************************************/
1112 * instantiate a key that's under construction
1114 static int act_keyctl_instantiate(int argc, char *argv[])
1116 key_serial_t key, dest;
1121 key = get_key_id(argv[1]);
1122 dest = get_key_id(argv[3]);
1124 if (keyctl_instantiate(key, argv[2], strlen(argv[2]), dest) < 0)
1125 error("keyctl_instantiate");
1129 } /* end act_keyctl_instantiate() */
1131 /*****************************************************************************/
1133 * instantiate a key, reading from a pipe
1135 static int act_keyctl_pinstantiate(int argc, char *argv[])
1144 args[2] = grab_stdin();
1148 return act_keyctl_instantiate(4, args);
1150 } /* end act_keyctl_pinstantiate() */
1152 /*****************************************************************************/
1154 * negate a key that's under construction
1156 static int act_keyctl_negate(int argc, char *argv[])
1158 unsigned long timeout;
1159 key_serial_t key, dest;
1165 key = get_key_id(argv[1]);
1167 timeout = strtoul(argv[2], &q, 10);
1169 fprintf(stderr, "Unparsable timeout: '%s'\n", argv[2]);
1173 dest = get_key_id(argv[3]);
1175 if (keyctl_negate(key, timeout, dest) < 0)
1176 error("keyctl_negate");
1180 } /* end act_keyctl_negate() */
1182 /*****************************************************************************/
1184 * set a key's timeout
1186 static int act_keyctl_timeout(int argc, char *argv[])
1188 unsigned long timeout;
1195 key = get_key_id(argv[1]);
1197 timeout = strtoul(argv[2], &q, 10);
1199 fprintf(stderr, "Unparsable timeout: '%s'\n", argv[2]);
1203 if (keyctl_set_timeout(key, timeout) < 0)
1204 error("keyctl_set_timeout");
1208 } /* end act_keyctl_timeout() */
1210 /*****************************************************************************/
1212 * get a key's security label
1214 static int act_keyctl_security(int argc, char *argv[])
1223 key = get_key_id(argv[1]);
1225 /* get key description */
1226 ret = keyctl_get_security_alloc(key, &buffer);
1228 error("keyctl_getsecurity");
1230 printf("%s\n", buffer);
1234 /*****************************************************************************/
1236 * install a new session keyring on the parent process
1238 static int act_keyctl_new_session(int argc, char *argv[])
1240 key_serial_t keyring;
1245 if (keyctl_join_session_keyring(NULL) < 0)
1246 error("keyctl_join_session_keyring");
1248 if (keyctl_session_to_parent() < 0)
1249 error("keyctl_session_to_parent");
1251 keyring = keyctl_get_keyring_ID(KEY_SPEC_SESSION_KEYRING, 0);
1253 error("keyctl_get_keyring_ID");
1255 /* print the resulting key ID */
1256 printf("%d\n", keyring);
1260 /*****************************************************************************/
1262 * reject a key that's under construction
1264 static int act_keyctl_reject(int argc, char *argv[])
1266 unsigned long timeout;
1267 key_serial_t key, dest;
1268 unsigned long rejerr;
1274 key = get_key_id(argv[1]);
1276 timeout = strtoul(argv[2], &q, 10);
1278 fprintf(stderr, "Unparsable timeout: '%s'\n", argv[2]);
1282 if (strcmp(argv[3], "rejected") == 0) {
1283 rejerr = EKEYREJECTED;
1284 } else if (strcmp(argv[3], "revoked") == 0) {
1285 rejerr = EKEYREVOKED;
1286 } else if (strcmp(argv[3], "expired") == 0) {
1287 rejerr = EKEYEXPIRED;
1289 rejerr = strtoul(argv[3], &q, 10);
1291 fprintf(stderr, "Unparsable error: '%s'\n", argv[3]);
1296 dest = get_key_id(argv[4]);
1298 if (keyctl_reject(key, timeout, rejerr, dest) < 0)
1299 error("keyctl_negate");
1305 * Attempt to unlink a key if we can't read it for reasons other than we don't
1308 static int act_keyctl_reap_func(key_serial_t parent, key_serial_t key,
1309 char *desc, int desc_len, void *data)
1311 if (desc_len < 0 && errno != EACCES) {
1313 printf("Reap %d", key);
1314 if (keyctl_unlink(key, parent) < 0) {
1316 printf("... failed %m\n");
1328 * Reap the dead keys from the session keyring tree
1330 static int act_keyctl_reap(int argc, char *argv[])
1334 if (argc > 1 && strcmp(argv[1], "-v") == 0) {
1343 n = recursive_session_key_scan(act_keyctl_reap_func, NULL);
1344 printf("%d keys reaped\n", n);
1358 * Attempt to unlink a key matching the type
1360 static int act_keyctl_purge_type_func(key_serial_t parent, key_serial_t key,
1361 char *raw, int raw_len, void *data)
1363 const struct purge_data *purge = data;
1366 if (parent == 0 || !raw)
1369 /* type is everything before the first semicolon */
1371 p = memchr(raw, ';', raw_len);
1375 if (strcmp(type, purge->type) != 0)
1378 return keyctl_unlink(key, parent) < 0 ? 0 : 1;
1382 * Attempt to unlink a key matching the type and description literally
1384 static int act_keyctl_purge_literal_func(key_serial_t parent, key_serial_t key,
1385 char *raw, int raw_len, void *data)
1387 const struct purge_data *purge = data;
1389 char *p, *type, *desc;
1391 if (parent == 0 || !raw)
1394 /* type is everything before the first semicolon */
1396 p = memchr(type, ';', raw_len);
1401 if (tlen != purge->type_len)
1403 if (memcmp(type, purge->type, tlen) != 0)
1406 /* description is everything after the last semicolon */
1408 desc = memrchr(p, ';', raw + raw_len - p);
1413 if (purge->prefix_match) {
1414 if (raw_len - (desc - raw) < purge->desc_len)
1417 if (raw_len - (desc - raw) != purge->desc_len)
1421 if (purge->case_indep) {
1422 if (strncasecmp(purge->desc, desc, purge->desc_len) != 0)
1425 if (memcmp(purge->desc, desc, purge->desc_len) != 0)
1429 printf("%*.*s '%s'\n", (int)tlen, (int)tlen, type, desc);
1431 return keyctl_unlink(key, parent) < 0 ? 0 : 1;
1435 * Attempt to unlink a key matching the type and description literally
1437 static int act_keyctl_purge_search_func(key_serial_t parent, key_serial_t keyring,
1438 char *raw, int raw_len, void *data)
1440 const struct purge_data *purge = data;
1444 if (!raw || memcmp(raw, "keyring;", 8) != 0)
1448 key = keyctl_search(keyring, purge->type, purge->desc, 0);
1449 if (keyctl_unlink(key, keyring) < 0)
1457 * Purge matching keys from a keyring
1459 static int act_keyctl_purge(int argc, char *argv[])
1461 recursive_key_scanner_t func;
1462 struct purge_data purge = {
1466 int n = 0, search_mode = 0;
1470 while (argc > 0 && argv[0][0] == '-') {
1471 if (argv[0][1] == 's')
1473 else if (argv[0][1] == 'p')
1474 purge.prefix_match = 1;
1475 else if (argv[0][1] == 'i')
1476 purge.case_indep = 1;
1486 purge.type = argv[0];
1487 purge.desc = argv[1];
1488 purge.type_len = strlen(purge.type);
1489 purge.desc_len = purge.desc ? strlen(purge.desc) : 0;
1491 if (search_mode == 1) {
1492 if (argc != 2 || purge.prefix_match || purge.case_indep)
1494 /* purge all keys of a specific type and description, according
1495 * to the kernel's comparator */
1496 func = act_keyctl_purge_search_func;
1497 } else if (argc == 1) {
1498 if (purge.prefix_match || purge.case_indep)
1500 /* purge all keys of a specific type */
1501 func = act_keyctl_purge_type_func;
1502 } else if (argc == 2) {
1503 /* purge all keys of a specific type with literally matching
1505 func = act_keyctl_purge_literal_func;
1510 n = recursive_session_key_scan(func, &purge);
1511 printf("purged %d keys\n", n);
1515 /*****************************************************************************/
1517 * parse a key identifier
1519 static key_serial_t get_key_id(const char *arg)
1524 /* handle a special keyring name */
1525 if (arg[0] == '@') {
1526 if (strcmp(arg, "@t" ) == 0) return KEY_SPEC_THREAD_KEYRING;
1527 if (strcmp(arg, "@p" ) == 0) return KEY_SPEC_PROCESS_KEYRING;
1528 if (strcmp(arg, "@s" ) == 0) return KEY_SPEC_SESSION_KEYRING;
1529 if (strcmp(arg, "@u" ) == 0) return KEY_SPEC_USER_KEYRING;
1530 if (strcmp(arg, "@us") == 0) return KEY_SPEC_USER_SESSION_KEYRING;
1531 if (strcmp(arg, "@g" ) == 0) return KEY_SPEC_GROUP_KEYRING;
1532 if (strcmp(arg, "@a" ) == 0) return KEY_SPEC_REQKEY_AUTH_KEY;
1534 fprintf(stderr, "Unknown special key: '%s'\n", arg);
1538 /* handle a numeric key ID */
1539 id = strtoul(arg, &end, 0);
1541 fprintf(stderr, "Unparsable key: '%s'\n", arg);
1547 } /* end get_key_id() */
1549 /*****************************************************************************/
1551 * recursively display a key/keyring tree
1553 static int dump_key_tree_aux(key_serial_t key, int depth, int more)
1555 static char dumpindent[64];
1558 size_t ringlen, desclen;
1560 char *desc, type[255], pretty_mask[9];
1561 int uid, gid, ret, n, dpos, rdepth, kcount = 0;
1566 /* find out how big this key's description is */
1567 ret = keyctl_describe(key, NULL, 0);
1569 printf("%d: key inaccessible (%m)\n", key);
1574 desc = malloc(desclen);
1578 /* read the description */
1579 ret = keyctl_describe(key, desc, desclen);
1581 printf("%d: key inaccessible (%m)\n", key);
1586 desclen = ret < desclen ? ret : desclen;
1596 n = sscanf(desc, "%[^;];%d;%d;%x;%n",
1597 type, &uid, &gid, &perm, &dpos);
1600 fprintf(stderr, "Unparseable description obtained for key %d\n", key);
1605 calc_perms(pretty_mask, perm, uid, gid);
1607 printf("%9d %s %5d %5d %s%s%s: %s\n",
1612 depth > 0 ? "\\_ " : "",
1615 /* if it's a keyring then we're going to want to recursively
1616 * display it if we can */
1617 if (strcmp(type, "keyring") == 0) {
1618 /* find out how big the keyring is */
1619 ret = keyctl_read(key, NULL, 0);
1621 error("keyctl_read");
1626 /* read its contents */
1627 payload = malloc(ringlen);
1631 ret = keyctl_read(key, payload, ringlen);
1633 error("keyctl_read");
1635 ringlen = ret < ringlen ? ret : ringlen;
1636 kcount = ringlen / sizeof(key_serial_t);
1638 /* walk the keyring */
1643 /* recurse into nexted keyrings */
1644 if (strcmp(type, "keyring") == 0) {
1647 dumpindent[rdepth++] = ' ';
1648 dumpindent[rdepth] = 0;
1652 dumpindent[rdepth++] = ' ';
1653 dumpindent[rdepth++] = ' ';
1654 dumpindent[rdepth++] = ' ';
1655 dumpindent[rdepth++] = ' ';
1656 dumpindent[rdepth] = 0;
1660 dumpindent[depth + 0] = '|';
1662 kcount += dump_key_tree_aux(key,
1664 ringlen - 4 >= sizeof(key_serial_t));
1667 } while (ringlen -= 4, ringlen >= sizeof(key_serial_t));
1675 } /* end dump_key_tree_aux() */
1677 /*****************************************************************************/
1679 * recursively list a keyring's contents
1681 static int dump_key_tree(key_serial_t keyring, const char *name)
1683 printf("%s\n", name);
1684 return dump_key_tree_aux(keyring, 0, 0);
1686 } /* end dump_key_tree() */