1 /* keyctl.c: key control program
2 *
3 * Copyright (C) 2005, 2011 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
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.
10 */
11
12 #define _GNU_SOURCE
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <stdint.h>
16 #include <stdarg.h>
17 #include <string.h>
18 #include <unistd.h>
19 #include <ctype.h>
20 #include <errno.h>
21 #include <asm/unistd.h>
22 #include "keyutils.h"
23
24 struct command {
25 int (*action)(int argc, char *argv[]);
26 const char *name;
27 const char *format;
28 };
29
30 static int act_keyctl___version(int argc, char *argv[]);
31 static int act_keyctl_show(int argc, char *argv[]);
32 static int act_keyctl_add(int argc, char *argv[]);
33 static int act_keyctl_padd(int argc, char *argv[]);
34 static int act_keyctl_request(int argc, char *argv[]);
35 static int act_keyctl_request2(int argc, char *argv[]);
36 static int act_keyctl_prequest2(int argc, char *argv[]);
37 static int act_keyctl_update(int argc, char *argv[]);
38 static int act_keyctl_pupdate(int argc, char *argv[]);
39 static int act_keyctl_newring(int argc, char *argv[]);
40 static int act_keyctl_revoke(int argc, char *argv[]);
41 static int act_keyctl_clear(int argc, char *argv[]);
42 static int act_keyctl_link(int argc, char *argv[]);
43 static int act_keyctl_unlink(int argc, char *argv[]);
44 static int act_keyctl_search(int argc, char *argv[]);
45 static int act_keyctl_read(int argc, char *argv[]);
46 static int act_keyctl_pipe(int argc, char *argv[]);
47 static int act_keyctl_print(int argc, char *argv[]);
48 static int act_keyctl_list(int argc, char *argv[]);
49 static int act_keyctl_rlist(int argc, char *argv[]);
50 static int act_keyctl_describe(int argc, char *argv[]);
51 static int act_keyctl_rdescribe(int argc, char *argv[]);
52 static int act_keyctl_chown(int argc, char *argv[]);
53 static int act_keyctl_chgrp(int argc, char *argv[]);
54 static int act_keyctl_setperm(int argc, char *argv[]);
55 static int act_keyctl_session(int argc, char *argv[]);
56 static int act_keyctl_instantiate(int argc, char *argv[]);
57 static int act_keyctl_pinstantiate(int argc, char *argv[]);
58 static int act_keyctl_negate(int argc, char *argv[]);
59 static int act_keyctl_timeout(int argc, char *argv[]);
60 static int act_keyctl_security(int argc, char *argv[]);
61 static int act_keyctl_new_session(int argc, char *argv[]);
62 static int act_keyctl_reject(int argc, char *argv[]);
63 static int act_keyctl_reap(int argc, char *argv[]);
64 static int act_keyctl_purge(int argc, char *argv[]);
65 static int act_keyctl_invalidate(int argc, char *argv[]);
66 static int act_keyctl_get_persistent(int argc, char *argv[]);
67
68 const struct command commands[] = {
69 { act_keyctl___version, "--version", "" },
70 { act_keyctl_add, "add", "<type> <desc> <data> <keyring>" },
71 { act_keyctl_chgrp, "chgrp", "<key> <gid>" },
72 { act_keyctl_chown, "chown", "<key> <uid>" },
73 { act_keyctl_clear, "clear", "<keyring>" },
74 { act_keyctl_describe, "describe", "<keyring>" },
75 { act_keyctl_instantiate, "instantiate","<key> <data> <keyring>" },
76 { act_keyctl_invalidate,"invalidate", "<key>" },
77 { act_keyctl_get_persistent, "get_persistent", "<keyring> [<uid>]" },
78 { act_keyctl_link, "link", "<key> <keyring>" },
79 { act_keyctl_list, "list", "<keyring>" },
80 { act_keyctl_negate, "negate", "<key> <timeout> <keyring>" },
81 { act_keyctl_new_session, "new_session", "" },
82 { act_keyctl_newring, "newring", "<name> <keyring>" },
83 { act_keyctl_padd, "padd", "<type> <desc> <keyring>" },
84 { act_keyctl_pinstantiate, "pinstantiate","<key> <keyring>" },
85 { act_keyctl_pipe, "pipe", "<key>" },
86 { act_keyctl_prequest2, "prequest2", "<type> <desc> [<dest_keyring>]" },
87 { act_keyctl_print, "print", "<key>" },
88 { act_keyctl_pupdate, "pupdate", "<key>" },
89 { act_keyctl_purge, "purge", "<type>" },
90 { NULL, "purge", "[-p] [-i] <type> <desc>" },
91 { NULL, "purge", "-s <type> <desc>" },
92 { act_keyctl_rdescribe, "rdescribe", "<keyring> [sep]" },
93 { act_keyctl_read, "read", "<key>" },
94 { act_keyctl_reap, "reap", "[-v]" },
95 { act_keyctl_reject, "reject", "<key> <timeout> <error> <keyring>" },
96 { act_keyctl_request, "request", "<type> <desc> [<dest_keyring>]" },
97 { act_keyctl_request2, "request2", "<type> <desc> <info> [<dest_keyring>]" },
98 { act_keyctl_revoke, "revoke", "<key>" },
99 { act_keyctl_rlist, "rlist", "<keyring>" },
100 { act_keyctl_search, "search", "<keyring> <type> <desc> [<dest_keyring>]" },
101 { act_keyctl_security, "security", "<key>" },
102 { act_keyctl_session, "session", "" },
103 { NULL, "session", "- [<prog> <arg1> <arg2> ...]" },
104 { NULL, "session", "<name> [<prog> <arg1> <arg2> ...]" },
105 { act_keyctl_setperm, "setperm", "<key> <mask>" },
106 { act_keyctl_show, "show", "[-x] [<keyring>]" },
107 { act_keyctl_timeout, "timeout", "<key> <timeout>" },
108 { act_keyctl_unlink, "unlink", "<key> [<keyring>]" },
109 { act_keyctl_update, "update", "<key> <data>" },
110 { NULL, NULL, NULL }
111 };
112
113 static int dump_key_tree(key_serial_t keyring, const char *name, int hex_key_IDs);
114 static void format(void) __attribute__((noreturn));
115 static void error(const char *msg) __attribute__((noreturn));
116 static key_serial_t get_key_id(char *arg);
117
118 static uid_t myuid;
119 static gid_t mygid, *mygroups;
120 static int myngroups;
121 static int verbose;
122
123 /*****************************************************************************/
124 /*
125 * handle an error
126 */
127 static inline void error(const char *msg)
128 {
129 perror(msg);
130 exit(1);
131
132 } /* end error() */
133
134 /*****************************************************************************/
135 /*
136 * execute the appropriate subcommand
137 */
138 int main(int argc, char *argv[])
139 {
140 const struct command *cmd, *best;
141 int n;
142
143 argv++;
144 argc--;
145
146 if (argc == 0)
147 format();
148
149 /* find the best fit command */
150 best = NULL;
151 n = strlen(*argv);
152
153 for (cmd = commands; cmd->name; cmd++) {
154 if (!cmd->action)
155 continue;
156 if (memcmp(cmd->name, *argv, n) != 0)
157 continue;
158
159 if (cmd->name[n] == 0) {
160 /* exact match */
161 best = cmd;
162 break;
163 }
164
165 /* partial match */
166 if (best) {
167 fprintf(stderr, "Ambiguous command\n");
168 exit(2);
169 }
170
171 best = cmd;
172 }
173
174 if (!best) {
175 fprintf(stderr, "Unknown command\n");
176 exit(2);
177 }
178
179 /* grab my UID, GID and groups */
180 myuid = geteuid();
181 mygid = getegid();
182 myngroups = getgroups(0, NULL);
183
184 if (myuid == -1 || mygid == -1 || myngroups == -1)
185 error("Unable to get UID/GID/#Groups\n");
186
187 mygroups = calloc(myngroups, sizeof(gid_t));
188 if (!mygroups)
189 error("calloc");
190
191 myngroups = getgroups(myngroups, mygroups);
192 if (myngroups < 0)
193 error("Unable to get Groups\n");
194
195 return best->action(argc, argv);
196
197 } /* end main() */
198
199 /*****************************************************************************/
200 /*
201 * display command format information
202 */
203 static void format(void)
204 {
205 const struct command *cmd;
206
207 fprintf(stderr, "Format:\n");
208
209 for (cmd = commands; cmd->name; cmd++)
210 fprintf(stderr, " keyctl %s %s\n", cmd->name, cmd->format);
211
212 fprintf(stderr, "\n");
213 fprintf(stderr, "Key/keyring ID:\n");
214 fprintf(stderr, " <nnn> numeric keyring ID\n");
215 fprintf(stderr, " @t thread keyring\n");
216 fprintf(stderr, " @p process keyring\n");
217 fprintf(stderr, " @s session keyring\n");
218 fprintf(stderr, " @u user keyring\n");
219 fprintf(stderr, " @us user default session keyring\n");
220 fprintf(stderr, " @g group keyring\n");
221 fprintf(stderr, " @a assumed request_key authorisation key\n");
222 fprintf(stderr, "\n");
223 fprintf(stderr, "<type> can be \"user\" for a user-defined keyring\n");
224 fprintf(stderr, "If you do this, prefix the description with \"<subtype>:\"\n");
225
226 exit(2);
227
228 } /* end format() */
229
230 /*****************************************************************************/
231 /*
232 * Display version information
233 */
234 static int act_keyctl___version(int argc, char *argv[])
235 {
236 printf("keyctl from %s (Built %s)\n",
237 keyutils_version_string, keyutils_build_string);
238 return 0;
239 }
240
241 /*****************************************************************************/
242 /*
243 * grab data from stdin
244 */
245 static char *grab_stdin(size_t *_size)
246 {
247 static char input[1024 * 1024 + 1];
248 int n, tmp;
249
250 n = 0;
251 do {
252 tmp = read(0, input + n, sizeof(input) - 1 - n);
253 if (tmp < 0)
254 error("stdin");
255
256 if (tmp == 0)
257 break;
258
259 n += tmp;
260
261 } while (n < sizeof(input));
262
263 if (n >= sizeof(input)) {
264 fprintf(stderr, "Too much data read on stdin\n");
265 exit(1);
266 }
267
268 input[n] = '\0';
269 *_size = n;
270
271 return input;
272
273 } /* end grab_stdin() */
274
275 /*****************************************************************************/
276 /*
277 * convert the permissions mask to a string representing the permissions we
278 * have actually been granted
279 */
280 static void calc_perms(char *pretty, key_perm_t perm, uid_t uid, gid_t gid)
281 {
282 unsigned perms;
283 gid_t *pg;
284 int loop;
285
286 perms = (perm & KEY_POS_ALL) >> 24;
287
288 if (uid == myuid) {
289 perms |= (perm & KEY_USR_ALL) >> 16;
290 goto write_mask;
291 }
292
293 if (gid != -1) {
294 if (gid == mygid) {
295 perms |= (perm & KEY_GRP_ALL) >> 8;
296 goto write_mask;
297 }
298
299 pg = mygroups;
300 for (loop = myngroups; loop > 0; loop--, pg++) {
301 if (gid == *pg) {
302 perms |= (perm & KEY_GRP_ALL) >> 8;
303 goto write_mask;
304 }
305 }
306 }
307
308 perms |= (perm & KEY_OTH_ALL);
309
310 write_mask:
311 sprintf(pretty, "--%c%c%c%c%c%c",
312 perms & KEY_OTH_SETATTR ? 'a' : '-',
313 perms & KEY_OTH_LINK ? 'l' : '-',
314 perms & KEY_OTH_SEARCH ? 's' : '-',
315 perms & KEY_OTH_WRITE ? 'w' : '-',
316 perms & KEY_OTH_READ ? 'r' : '-',
317 perms & KEY_OTH_VIEW ? 'v' : '-');
318
319 } /* end calc_perms() */
320
321 /*****************************************************************************/
322 /*
323 * show the parent process's session keyring
324 */
325 static int act_keyctl_show(int argc, char *argv[])
326 {
327 key_serial_t keyring = KEY_SPEC_SESSION_KEYRING;
328 int hex_key_IDs = 0;
329
330 if (argc >= 2 && strcmp(argv[1], "-x") == 0) {
331 hex_key_IDs = 1;
332 argc--;
333 argv++;
334 }
335
336 if (argc > 2)
337 format();
338
339 if (argc == 2)
340 keyring = get_key_id(argv[1]);
341
342 dump_key_tree(keyring, argc == 2 ? "Keyring" : "Session Keyring", hex_key_IDs);
343 return 0;
344
345 } /* end act_keyctl_show() */
346
347 /*****************************************************************************/
348 /*
349 * add a key
350 */
351 static int act_keyctl_add(int argc, char *argv[])
352 {
353 key_serial_t dest;
354 int ret;
355
356 if (argc != 5)
357 format();
358
359 dest = get_key_id(argv[4]);
360
361 ret = add_key(argv[1], argv[2], argv[3], strlen(argv[3]), dest);
362 if (ret < 0)
363 error("add_key");
364
365 /* print the resulting key ID */
366 printf("%d\n", ret);
367 return 0;
368
369 } /* end act_keyctl_add() */
370
371 /*****************************************************************************/
372 /*
373 * add a key, reading from a pipe
374 */
375 static int act_keyctl_padd(int argc, char *argv[])
376 {
377 key_serial_t dest;
378 size_t datalen;
379 void *data;
380 int ret;
381
382
383 if (argc != 4)
384 format();
385
386 dest = get_key_id(argv[3]);
387
388 data = grab_stdin(&datalen);
389
390 ret = add_key(argv[1], argv[2], data, datalen, dest);
391 if (ret < 0)
392 error("add_key");
393
394 /* print the resulting key ID */
395 printf("%d\n", ret);
396 return 0;
397
398 } /* end act_keyctl_padd() */
399
400 /*****************************************************************************/
401 /*
402 * request a key
403 */
404 static int act_keyctl_request(int argc, char *argv[])
405 {
406 key_serial_t dest;
407 int ret;
408
409 if (argc != 3 && argc != 4)
410 format();
411
412 dest = 0;
413 if (argc == 4)
414 dest = get_key_id(argv[3]);
415
416 ret = request_key(argv[1], argv[2], NULL, dest);
417 if (ret < 0)
418 error("request_key");
419
420 /* print the resulting key ID */
421 printf("%d\n", ret);
422 return 0;
423
424 } /* end act_keyctl_request() */
425
426 /*****************************************************************************/
427 /*
428 * request a key, with recourse to /sbin/request-key
429 */
430 static int act_keyctl_request2(int argc, char *argv[])
431 {
432 key_serial_t dest;
433 int ret;
434
435 if (argc != 4 && argc != 5)
436 format();
437
438 dest = 0;
439 if (argc == 5)
440 dest = get_key_id(argv[4]);
441
442 ret = request_key(argv[1], argv[2], argv[3], dest);
443 if (ret < 0)
444 error("request_key");
445
446 /* print the resulting key ID */
447 printf("%d\n", ret);
448 return 0;
449
450 } /* end act_keyctl_request2() */
451
452 /*****************************************************************************/
453 /*
454 * request a key, with recourse to /sbin/request-key, reading the callout info
455 * from a pipe
456 */
457 static int act_keyctl_prequest2(int argc, char *argv[])
458 {
459 char *args[6];
460 size_t datalen;
461
462 if (argc != 3 && argc != 4)
463 format();
464
465 args[0] = argv[0];
466 args[1] = argv[1];
467 args[2] = argv[2];
468 args[3] = grab_stdin(&datalen);
469 args[4] = argv[3];
470 args[5] = NULL;
471
472 return act_keyctl_request2(argc + 1, args);
473
474 } /* end act_keyctl_prequest2() */
475
476 /*****************************************************************************/
477 /*
478 * update a key
479 */
480 static int act_keyctl_update(int argc, char *argv[])
481 {
482 key_serial_t key;
483
484 if (argc != 3)
485 format();
486
487 key = get_key_id(argv[1]);
488
489 if (keyctl_update(key, argv[2], strlen(argv[2])) < 0)
490 error("keyctl_update");
491
492 return 0;
493
494 } /* end act_keyctl_update() */
495
496 /*****************************************************************************/
497 /*
498 * update a key, reading from a pipe
499 */
500 static int act_keyctl_pupdate(int argc, char *argv[])
501 {
502 key_serial_t key;
503 size_t datalen;
504 void *data;
505
506 if (argc != 2)
507 format();
508
509 key = get_key_id(argv[1]);
510 data = grab_stdin(&datalen);
511
512 if (keyctl_update(key, data, datalen) < 0)
513 error("keyctl_update");
514
515 return 0;
516
517 } /* end act_keyctl_pupdate() */
518
519 /*****************************************************************************/
520 /*
521 * create a new keyring
522 */
523 static int act_keyctl_newring(int argc, char *argv[])
524 {
525 key_serial_t dest;
526 int ret;
527
528 if (argc != 3)
529 format();
530
531 dest = get_key_id(argv[2]);
532
533 ret = add_key("keyring", argv[1], NULL, 0, dest);
534 if (ret < 0)
535 error("add_key");
536
537 printf("%d\n", ret);
538 return 0;
539
540 } /* end act_keyctl_newring() */
541
542 /*****************************************************************************/
543 /*
544 * revoke a key
545 */
546 static int act_keyctl_revoke(int argc, char *argv[])
547 {
548 key_serial_t key;
549
550 if (argc != 2)
551 format();
552
553 key = get_key_id(argv[1]);
554
555 if (keyctl_revoke(key) < 0)
556 error("keyctl_revoke");
557
558 return 0;
559
560 } /* end act_keyctl_revoke() */
561
562 /*****************************************************************************/
563 /*
564 * clear a keyring
565 */
566 static int act_keyctl_clear(int argc, char *argv[])
567 {
568 key_serial_t keyring;
569
570 if (argc != 2)
571 format();
572
573 keyring = get_key_id(argv[1]);
574
575 if (keyctl_clear(keyring) < 0)
576 error("keyctl_clear");
577
578 return 0;
579
580 } /* end act_keyctl_clear() */
581
582 /*****************************************************************************/
583 /*
584 * link a key to a keyring
585 */
586 static int act_keyctl_link(int argc, char *argv[])
587 {
588 key_serial_t keyring, key;
589
590 if (argc != 3)
591 format();
592
593 key = get_key_id(argv[1]);
594 keyring = get_key_id(argv[2]);
595
596 if (keyctl_link(key, keyring) < 0)
597 error("keyctl_link");
598
599 return 0;
600
601 } /* end act_keyctl_link() */
602
603 /*
604 * Attempt to unlink a key matching the ID
605 */
606 static int act_keyctl_unlink_func(key_serial_t parent, key_serial_t key,
607 char *desc, int desc_len, void *data)
608 {
609 key_serial_t *target = data;
610
611 if (key == *target)
612 return keyctl_unlink(key, parent) < 0 ? 0 : 1;
613 return 0;
614 }
615
616 /*
617 * Unlink a key from a keyring or from the session keyring tree.
618 */
619 static int act_keyctl_unlink(int argc, char *argv[])
620 {
621 key_serial_t keyring, key;
622 int n;
623
624 if (argc != 2 && argc != 3)
625 format();
626
627 key = get_key_id(argv[1]);
628
629 if (argc == 3) {
630 keyring = get_key_id(argv[2]);
631 if (keyctl_unlink(key, keyring) < 0)
632 error("keyctl_unlink");
633 } else {
634 n = recursive_session_key_scan(act_keyctl_unlink_func, &key);
635 printf("%d links removed\n", n);
636 }
637
638 return 0;
639 }
640
641 /*****************************************************************************/
642 /*
643 * search a keyring for a key
644 */
645 static int act_keyctl_search(int argc, char *argv[])
646 {
647 key_serial_t keyring, dest;
648 int ret;
649
650 if (argc != 4 && argc != 5)
651 format();
652
653 keyring = get_key_id(argv[1]);
654
655 dest = 0;
656 if (argc == 5)
657 dest = get_key_id(argv[4]);
658
659 ret = keyctl_search(keyring, argv[2], argv[3], dest);
660 if (ret < 0)
661 error("keyctl_search");
662
663 /* print the ID of the key we found */
664 printf("%d\n", ret);
665 return 0;
666
667 } /* end act_keyctl_search() */
668
669 /*****************************************************************************/
670 /*
671 * read a key
672 */
673 static int act_keyctl_read(int argc, char *argv[])
674 {
675 key_serial_t key;
676 void *buffer;
677 char *p;
678 int ret, sep, col;
679
680 if (argc != 2)
681 format();
682
683 key = get_key_id(argv[1]);
684
685 /* read the key payload data */
686 ret = keyctl_read_alloc(key, &buffer);
687 if (ret < 0)
688 error("keyctl_read_alloc");
689
690 if (ret == 0) {
691 printf("No data in key\n");
692 return 0;
693 }
694
695 /* hexdump the contents */
696 printf("%u bytes of data in key:\n", ret);
697
698 sep = 0;
699 col = 0;
700 p = buffer;
701
702 do {
703 if (sep) {
704 putchar(sep);
705 sep = 0;
706 }
707
708 printf("%02hhx", *p);
709 p++;
710
711 col++;
712 if (col % 32 == 0)
713 sep = '\n';
714 else if (col % 4 == 0)
715 sep = ' ';
716
717 } while (--ret > 0);
718
719 printf("\n");
720 return 0;
721
722 } /* end act_keyctl_read() */
723
724 /*****************************************************************************/
725 /*
726 * read a key and dump raw to stdout
727 */
728 static int act_keyctl_pipe(int argc, char *argv[])
729 {
730 key_serial_t key;
731 void *buffer;
732 int ret;
733
734 if (argc != 2)
735 format();
736
737 key = get_key_id(argv[1]);
738
739 /* read the key payload data */
740 ret = keyctl_read_alloc(key, &buffer);
741 if (ret < 0)
742 error("keyctl_read_alloc");
743
744 if (ret > 0 && write(1, buffer, ret) < 0)
745 error("write");
746 return 0;
747
748 } /* end act_keyctl_pipe() */
749
750 /*****************************************************************************/
751 /*
752 * read a key and dump to stdout in printable form
753 */
754 static int act_keyctl_print(int argc, char *argv[])
755 {
756 key_serial_t key;
757 void *buffer;
758 char *p;
759 int loop, ret;
760
(1) Event cond_false: |
Condition "argc != 2", taking false branch |
761 if (argc != 2)
(2) Event if_end: |
End of if statement |
762 format();
763
764 key = get_key_id(argv[1]);
765
766 /* read the key payload data */
767 ret = keyctl_read_alloc(key, &buffer);
(4) Event cond_false: |
Condition "ret < 0", taking false branch |
768 if (ret < 0)
(5) Event if_end: |
End of if statement |
769 error("keyctl_read_alloc");
770
771 /* see if it's printable */
772 p = buffer;
(7) Event cond_false: |
Condition "loop > 0", taking false branch |
773 for (loop = ret; loop > 0; loop--, p++)
774 if (!isprint(*p))
(8) Event loop_end: |
Reached end of loop |
775 goto not_printable;
776
777 /* it is */
778 printf("%s\n", (char *) buffer);
(10) Event leaked_storage: |
Variable "p" going out of scope leaks the storage it points to. |
(11) Event leaked_storage: |
Variable "buffer" going out of scope leaks the storage it points to. |
Also see events: |
[alloc_arg][var_assign][noescape] |
779 return 0;
780
781 not_printable:
782 /* it isn't */
783 printf(":hex:");
784 p = buffer;
785 for (loop = ret; loop > 0; loop--, p++)
786 printf("%02hhx", *p);
787 printf("\n");
788 return 0;
789
790 } /* end act_keyctl_print() */
791
792 /*****************************************************************************/
793 /*
794 * list a keyring
795 */
796 static int act_keyctl_list(int argc, char *argv[])
797 {
798 key_serial_t keyring, key, *pk;
799 key_perm_t perm;
800 void *keylist;
801 char *buffer, pretty_mask[9];
802 uid_t uid;
803 gid_t gid;
804 int count, tlen, dpos, n, ret;
805
806 if (argc != 2)
807 format();
808
809 keyring = get_key_id(argv[1]);
810
811 /* read the key payload data */
812 count = keyctl_read_alloc(keyring, &keylist);
813 if (count < 0)
814 error("keyctl_read_alloc");
815
816 count /= sizeof(key_serial_t);
817
818 if (count == 0) {
819 printf("keyring is empty\n");
820 return 0;
821 }
822
823 /* list the keys in the keyring */
824 if (count == 1)
825 printf("1 key in keyring:\n");
826 else
827 printf("%u keys in keyring:\n", count);
828
829 pk = keylist;
830 do {
831 key = *pk++;
832
833 ret = keyctl_describe_alloc(key, &buffer);
834 if (ret < 0) {
835 printf("%9d: key inaccessible (%m)\n", key);
836 continue;
837 }
838
839 uid = 0;
840 gid = 0;
841 perm = 0;
842
843 tlen = -1;
844 dpos = -1;
845
846 n = sscanf((char *) buffer, "%*[^;]%n;%d;%d;%x;%n",
847 &tlen, &uid, &gid, &perm, &dpos);
848 if (n != 3) {
849 fprintf(stderr, "Unparseable description obtained for key %d\n", key);
850 exit(3);
851 }
852
853 calc_perms(pretty_mask, perm, uid, gid);
854
855 printf("%9d: %s %5d %5d %*.*s: %s\n",
856 key,
857 pretty_mask,
858 uid, gid,
859 tlen, tlen, buffer,
860 buffer + dpos);
861
862 free(buffer);
863
864 } while (--count);
865
866 return 0;
867
868 } /* end act_keyctl_list() */
869
870 /*****************************************************************************/
871 /*
872 * produce a raw list of a keyring
873 */
874 static int act_keyctl_rlist(int argc, char *argv[])
875 {
876 key_serial_t keyring, key, *pk;
877 void *keylist;
878 int count;
879
880 if (argc != 2)
881 format();
882
883 keyring = get_key_id(argv[1]);
884
885 /* read the key payload data */
886 count = keyctl_read_alloc(keyring, &keylist);
887 if (count < 0)
888 error("keyctl_read_alloc");
889
890 count /= sizeof(key_serial_t);
891
892 /* list the keys in the keyring */
893 if (count <= 0) {
894 printf("\n");
895 }
896 else {
897 pk = keylist;
898 for (; count > 0; count--) {
899 key = *pk++;
900 printf("%d%c", key, count == 1 ? '\n' : ' ');
901 }
902 }
903
904 return 0;
905
906 } /* end act_keyctl_rlist() */
907
908 /*****************************************************************************/
909 /*
910 * describe a key
911 */
912 static int act_keyctl_describe(int argc, char *argv[])
913 {
914 key_serial_t key;
915 key_perm_t perm;
916 char *buffer;
917 uid_t uid;
918 gid_t gid;
919 int tlen, dpos, n, ret;
920
921 if (argc != 2)
922 format();
923
924 key = get_key_id(argv[1]);
925
926 /* get key description */
927 ret = keyctl_describe_alloc(key, &buffer);
928 if (ret < 0)
929 error("keyctl_describe");
930
931 /* parse it */
932 uid = 0;
933 gid = 0;
934 perm = 0;
935
936 tlen = -1;
937 dpos = -1;
938
939 n = sscanf(buffer, "%*[^;]%n;%d;%d;%x;%n",
940 &tlen, &uid, &gid, &perm, &dpos);
941 if (n != 3) {
942 fprintf(stderr, "Unparseable description obtained for key %d\n", key);
943 exit(3);
944 }
945
946 /* display it */
947 printf("%9d:"
948 " %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c"
949 " %5d %5d %*.*s: %s\n",
950 key,
951 perm & KEY_POS_SETATTR ? 'a' : '-',
952 perm & KEY_POS_LINK ? 'l' : '-',
953 perm & KEY_POS_SEARCH ? 's' : '-',
954 perm & KEY_POS_WRITE ? 'w' : '-',
955 perm & KEY_POS_READ ? 'r' : '-',
956 perm & KEY_POS_VIEW ? 'v' : '-',
957
958 perm & KEY_USR_SETATTR ? 'a' : '-',
959 perm & KEY_USR_LINK ? 'l' : '-',
960 perm & KEY_USR_SEARCH ? 's' : '-',
961 perm & KEY_USR_WRITE ? 'w' : '-',
962 perm & KEY_USR_READ ? 'r' : '-',
963 perm & KEY_USR_VIEW ? 'v' : '-',
964
965 perm & KEY_GRP_SETATTR ? 'a' : '-',
966 perm & KEY_GRP_LINK ? 'l' : '-',
967 perm & KEY_GRP_SEARCH ? 's' : '-',
968 perm & KEY_GRP_WRITE ? 'w' : '-',
969 perm & KEY_GRP_READ ? 'r' : '-',
970 perm & KEY_GRP_VIEW ? 'v' : '-',
971
972 perm & KEY_OTH_SETATTR ? 'a' : '-',
973 perm & KEY_OTH_LINK ? 'l' : '-',
974 perm & KEY_OTH_SEARCH ? 's' : '-',
975 perm & KEY_OTH_WRITE ? 'w' : '-',
976 perm & KEY_OTH_READ ? 'r' : '-',
977 perm & KEY_OTH_VIEW ? 'v' : '-',
978 uid, gid,
979 tlen, tlen, buffer,
980 buffer + dpos);
981
982 return 0;
983
984 } /* end act_keyctl_describe() */
985
986 /*****************************************************************************/
987 /*
988 * get raw key description
989 */
990 static int act_keyctl_rdescribe(int argc, char *argv[])
991 {
992 key_serial_t key;
993 char *buffer, *q;
994 int ret;
995
996 if (argc != 2 && argc != 3)
997 format();
998 if (argc == 3 && !argv[2][0])
999 format();
1000
1001 key = get_key_id(argv[1]);
1002
1003 /* get key description */
1004 ret = keyctl_describe_alloc(key, &buffer);
1005 if (ret < 0)
1006 error("keyctl_describe");
1007
1008 /* replace semicolon separators with requested alternative */
1009 if (argc == 3) {
1010 for (q = buffer; *q; q++)
1011 if (*q == ';')
1012 *q = argv[2][0];
1013 }
1014
1015 /* display raw description */
1016 printf("%s\n", buffer);
1017 return 0;
1018
1019 } /* end act_keyctl_rdescribe() */
1020
1021 /*****************************************************************************/
1022 /*
1023 * change a key's ownership
1024 */
1025 static int act_keyctl_chown(int argc, char *argv[])
1026 {
1027 key_serial_t key;
1028 uid_t uid;
1029 char *q;
1030
1031 if (argc != 3)
1032 format();
1033
1034 key = get_key_id(argv[1]);
1035
1036 uid = strtoul(argv[2], &q, 0);
1037 if (*q) {
1038 fprintf(stderr, "Unparsable uid: '%s'\n", argv[2]);
1039 exit(2);
1040 }
1041
1042 if (keyctl_chown(key, uid, -1) < 0)
1043 error("keyctl_chown");
1044
1045 return 0;
1046
1047 } /* end act_keyctl_chown() */
1048
1049 /*****************************************************************************/
1050 /*
1051 * change a key's group ownership
1052 */
1053 static int act_keyctl_chgrp(int argc, char *argv[])
1054 {
1055 key_serial_t key;
1056 gid_t gid;
1057 char *q;
1058
1059 if (argc != 3)
1060 format();
1061
1062 key = get_key_id(argv[1]);
1063
1064 gid = strtoul(argv[2], &q, 0);
1065 if (*q) {
1066 fprintf(stderr, "Unparsable gid: '%s'\n", argv[2]);
1067 exit(2);
1068 }
1069
1070 if (keyctl_chown(key, -1, gid) < 0)
1071 error("keyctl_chown");
1072
1073 return 0;
1074
1075 } /* end act_keyctl_chgrp() */
1076
1077 /*****************************************************************************/
1078 /*
1079 * set the permissions on a key
1080 */
1081 static int act_keyctl_setperm(int argc, char *argv[])
1082 {
1083 key_serial_t key;
1084 key_perm_t perm;
1085 char *q;
1086
1087 if (argc != 3)
1088 format();
1089
1090 key = get_key_id(argv[1]);
1091 perm = strtoul(argv[2], &q, 0);
1092 if (*q) {
1093 fprintf(stderr, "Unparsable permissions: '%s'\n", argv[2]);
1094 exit(2);
1095 }
1096
1097 if (keyctl_setperm(key, perm) < 0)
1098 error("keyctl_setperm");
1099
1100 return 0;
1101
1102 } /* end act_keyctl_setperm() */
1103
1104 /*****************************************************************************/
1105 /*
1106 * start a process in a new session
1107 */
1108 static int act_keyctl_session(int argc, char *argv[])
1109 {
1110 char *p, *q;
1111 int ret;
1112
1113 argv++;
1114 argc--;
1115
1116 /* no extra arguments signifies a standard shell in an anonymous
1117 * session */
1118 p = NULL;
1119 if (argc != 0) {
1120 /* a dash signifies an anonymous session */
1121 p = *argv;
1122 if (strcmp(p, "-") == 0)
1123 p = NULL;
1124
1125 argv++;
1126 argc--;
1127 }
1128
1129 /* create a new session keyring */
1130 ret = keyctl_join_session_keyring(p);
1131 if (ret < 0)
1132 error("keyctl_join_session_keyring");
1133
1134 fprintf(stderr, "Joined session keyring: %d\n", ret);
1135
1136 /* run the standard shell if no arguments */
1137 if (argc == 0) {
1138 q = getenv("SHELL");
1139 if (!q)
1140 q = "/bin/sh";
1141 execl(q, q, NULL);
1142 error(q);
1143 }
1144
1145 /* run the command specified */
1146 execvp(argv[0], argv);
1147 error(argv[0]);
1148
1149 } /* end act_keyctl_session() */
1150
1151 /*****************************************************************************/
1152 /*
1153 * instantiate a key that's under construction
1154 */
1155 static int act_keyctl_instantiate(int argc, char *argv[])
1156 {
1157 key_serial_t key, dest;
1158
1159 if (argc != 4)
1160 format();
1161
1162 key = get_key_id(argv[1]);
1163 dest = get_key_id(argv[3]);
1164
1165 if (keyctl_instantiate(key, argv[2], strlen(argv[2]), dest) < 0)
1166 error("keyctl_instantiate");
1167
1168 return 0;
1169
1170 } /* end act_keyctl_instantiate() */
1171
1172 /*****************************************************************************/
1173 /*
1174 * instantiate a key, reading from a pipe
1175 */
1176 static int act_keyctl_pinstantiate(int argc, char *argv[])
1177 {
1178 key_serial_t key, dest;
1179 size_t datalen;
1180 void *data;
1181
1182 if (argc != 3)
1183 format();
1184
1185 key = get_key_id(argv[1]);
1186 dest = get_key_id(argv[2]);
1187 data = grab_stdin(&datalen);
1188
1189 if (keyctl_instantiate(key, data, datalen, dest) < 0)
1190 error("keyctl_instantiate");
1191
1192 return 0;
1193
1194 } /* end act_keyctl_pinstantiate() */
1195
1196 /*****************************************************************************/
1197 /*
1198 * negate a key that's under construction
1199 */
1200 static int act_keyctl_negate(int argc, char *argv[])
1201 {
1202 unsigned long timeout;
1203 key_serial_t key, dest;
1204 char *q;
1205
1206 if (argc != 4)
1207 format();
1208
1209 key = get_key_id(argv[1]);
1210
1211 timeout = strtoul(argv[2], &q, 10);
1212 if (*q) {
1213 fprintf(stderr, "Unparsable timeout: '%s'\n", argv[2]);
1214 exit(2);
1215 }
1216
1217 dest = get_key_id(argv[3]);
1218
1219 if (keyctl_negate(key, timeout, dest) < 0)
1220 error("keyctl_negate");
1221
1222 return 0;
1223
1224 } /* end act_keyctl_negate() */
1225
1226 /*****************************************************************************/
1227 /*
1228 * set a key's timeout
1229 */
1230 static int act_keyctl_timeout(int argc, char *argv[])
1231 {
1232 unsigned long timeout;
1233 key_serial_t key;
1234 char *q;
1235
1236 if (argc != 3)
1237 format();
1238
1239 key = get_key_id(argv[1]);
1240
1241 timeout = strtoul(argv[2], &q, 10);
1242 if (*q) {
1243 fprintf(stderr, "Unparsable timeout: '%s'\n", argv[2]);
1244 exit(2);
1245 }
1246
1247 if (keyctl_set_timeout(key, timeout) < 0)
1248 error("keyctl_set_timeout");
1249
1250 return 0;
1251
1252 } /* end act_keyctl_timeout() */
1253
1254 /*****************************************************************************/
1255 /*
1256 * get a key's security label
1257 */
1258 static int act_keyctl_security(int argc, char *argv[])
1259 {
1260 key_serial_t key;
1261 char *buffer;
1262 int ret;
1263
1264 if (argc != 2)
1265 format();
1266
1267 key = get_key_id(argv[1]);
1268
1269 /* get key description */
1270 ret = keyctl_get_security_alloc(key, &buffer);
1271 if (ret < 0)
1272 error("keyctl_getsecurity");
1273
1274 printf("%s\n", buffer);
1275 return 0;
1276 }
1277
1278 /*****************************************************************************/
1279 /*
1280 * install a new session keyring on the parent process
1281 */
1282 static int act_keyctl_new_session(int argc, char *argv[])
1283 {
1284 key_serial_t keyring;
1285
1286 if (argc != 1)
1287 format();
1288
1289 if (keyctl_join_session_keyring(NULL) < 0)
1290 error("keyctl_join_session_keyring");
1291
1292 if (keyctl_session_to_parent() < 0)
1293 error("keyctl_session_to_parent");
1294
1295 keyring = keyctl_get_keyring_ID(KEY_SPEC_SESSION_KEYRING, 0);
1296 if (keyring < 0)
1297 error("keyctl_get_keyring_ID");
1298
1299 /* print the resulting key ID */
1300 printf("%d\n", keyring);
1301 return 0;
1302 }
1303
1304 /*****************************************************************************/
1305 /*
1306 * reject a key that's under construction
1307 */
1308 static int act_keyctl_reject(int argc, char *argv[])
1309 {
1310 unsigned long timeout;
1311 key_serial_t key, dest;
1312 unsigned long rejerr;
1313 char *q;
1314
1315 if (argc != 5)
1316 format();
1317
1318 key = get_key_id(argv[1]);
1319
1320 timeout = strtoul(argv[2], &q, 10);
1321 if (*q) {
1322 fprintf(stderr, "Unparsable timeout: '%s'\n", argv[2]);
1323 exit(2);
1324 }
1325
1326 if (strcmp(argv[3], "rejected") == 0) {
1327 rejerr = EKEYREJECTED;
1328 } else if (strcmp(argv[3], "revoked") == 0) {
1329 rejerr = EKEYREVOKED;
1330 } else if (strcmp(argv[3], "expired") == 0) {
1331 rejerr = EKEYEXPIRED;
1332 } else {
1333 rejerr = strtoul(argv[3], &q, 10);
1334 if (*q) {
1335 fprintf(stderr, "Unparsable error: '%s'\n", argv[3]);
1336 exit(2);
1337 }
1338 }
1339
1340 dest = get_key_id(argv[4]);
1341
1342 if (keyctl_reject(key, timeout, rejerr, dest) < 0)
1343 error("keyctl_negate");
1344
1345 return 0;
1346 }
1347
1348 /*
1349 * Attempt to unlink a key if we can't read it for reasons other than we don't
1350 * have permission
1351 */
1352 static int act_keyctl_reap_func(key_serial_t parent, key_serial_t key,
1353 char *desc, int desc_len, void *data)
1354 {
1355 if (desc_len < 0 && errno != EACCES) {
1356 if (verbose)
1357 printf("Reap %d", key);
1358 if (keyctl_unlink(key, parent) < 0) {
1359 if (verbose)
1360 printf("... failed %m\n");
1361 return 0;
1362 } else {
1363 if (verbose)
1364 printf("\n");
1365 return 1;
1366 };
1367 }
1368 return 0;
1369 }
1370
1371 /*
1372 * Reap the dead keys from the session keyring tree
1373 */
1374 static int act_keyctl_reap(int argc, char *argv[])
1375 {
1376 int n;
1377
1378 if (argc > 1 && strcmp(argv[1], "-v") == 0) {
1379 verbose = 1;
1380 argc--;
1381 argv++;
1382 }
1383
1384 if (argc != 1)
1385 format();
1386
1387 n = recursive_session_key_scan(act_keyctl_reap_func, NULL);
1388 printf("%d keys reaped\n", n);
1389 return 0;
1390 }
1391
1392 struct purge_data {
1393 const char *type;
1394 const char *desc;
1395 size_t desc_len;
1396 size_t type_len;
1397 char prefix_match;
1398 char case_indep;
1399 };
1400
1401 /*
1402 * Attempt to unlink a key matching the type
1403 */
1404 static int act_keyctl_purge_type_func(key_serial_t parent, key_serial_t key,
1405 char *raw, int raw_len, void *data)
1406 {
1407 const struct purge_data *purge = data;
1408 char *p, *type;
1409
1410 if (parent == 0 || !raw)
1411 return 0;
1412
1413 /* type is everything before the first semicolon */
1414 type = raw;
1415 p = memchr(raw, ';', raw_len);
1416 if (!p)
1417 return 0;
1418 *p = 0;
1419 if (strcmp(type, purge->type) != 0)
1420 return 0;
1421
1422 return keyctl_unlink(key, parent) < 0 ? 0 : 1;
1423 }
1424
1425 /*
1426 * Attempt to unlink a key matching the type and description literally
1427 */
1428 static int act_keyctl_purge_literal_func(key_serial_t parent, key_serial_t key,
1429 char *raw, int raw_len, void *data)
1430 {
1431 const struct purge_data *purge = data;
1432 size_t tlen;
1433 char *p, *type, *desc;
1434
1435 if (parent == 0 || !raw)
1436 return 0;
1437
1438 /* type is everything before the first semicolon */
1439 type = raw;
1440 p = memchr(type, ';', raw_len);
1441 if (!p)
1442 return 0;
1443
1444 tlen = p - type;
1445 if (tlen != purge->type_len)
1446 return 0;
1447 if (memcmp(type, purge->type, tlen) != 0)
1448 return 0;
1449
1450 /* description is everything after the last semicolon */
1451 p++;
1452 desc = memrchr(p, ';', raw + raw_len - p);
1453 if (!desc)
1454 return 0;
1455 desc++;
1456
1457 if (purge->prefix_match) {
1458 if (raw_len - (desc - raw) < purge->desc_len)
1459 return 0;
1460 } else {
1461 if (raw_len - (desc - raw) != purge->desc_len)
1462 return 0;
1463 }
1464
1465 if (purge->case_indep) {
1466 if (strncasecmp(purge->desc, desc, purge->desc_len) != 0)
1467 return 0;
1468 } else {
1469 if (memcmp(purge->desc, desc, purge->desc_len) != 0)
1470 return 0;
1471 }
1472
1473 printf("%*.*s '%s'\n", (int)tlen, (int)tlen, type, desc);
1474
1475 return keyctl_unlink(key, parent) < 0 ? 0 : 1;
1476 }
1477
1478 /*
1479 * Attempt to unlink a key matching the type and description literally
1480 */
1481 static int act_keyctl_purge_search_func(key_serial_t parent, key_serial_t keyring,
1482 char *raw, int raw_len, void *data)
1483 {
1484 const struct purge_data *purge = data;
1485 key_serial_t key;
1486 int kcount = 0;
1487
1488 if (!raw || memcmp(raw, "keyring;", 8) != 0)
1489 return 0;
1490
1491 for (;;) {
1492 key = keyctl_search(keyring, purge->type, purge->desc, 0);
1493 if (keyctl_unlink(key, keyring) < 0)
1494 return kcount;
1495 kcount++;
1496 }
1497 return kcount;
1498 }
1499
1500 /*
1501 * Purge matching keys from a keyring
1502 */
1503 static int act_keyctl_purge(int argc, char *argv[])
1504 {
1505 recursive_key_scanner_t func;
1506 struct purge_data purge = {
1507 .prefix_match = 0,
1508 .case_indep = 0,
1509 };
1510 int n = 0, search_mode = 0;
1511
1512 argc--;
1513 argv++;
1514 while (argc > 0 && argv[0][0] == '-') {
1515 if (argv[0][1] == 's')
1516 search_mode = 1;
1517 else if (argv[0][1] == 'p')
1518 purge.prefix_match = 1;
1519 else if (argv[0][1] == 'i')
1520 purge.case_indep = 1;
1521 else
1522 format();
1523 argc--;
1524 argv++;
1525 }
1526
1527 if (argc < 1)
1528 format();
1529
1530 purge.type = argv[0];
1531 purge.desc = argv[1];
1532 purge.type_len = strlen(purge.type);
1533 purge.desc_len = purge.desc ? strlen(purge.desc) : 0;
1534
1535 if (search_mode == 1) {
1536 if (argc != 2 || purge.prefix_match || purge.case_indep)
1537 format();
1538 /* purge all keys of a specific type and description, according
1539 * to the kernel's comparator */
1540 func = act_keyctl_purge_search_func;
1541 } else if (argc == 1) {
1542 if (purge.prefix_match || purge.case_indep)
1543 format();
1544 /* purge all keys of a specific type */
1545 func = act_keyctl_purge_type_func;
1546 } else if (argc == 2) {
1547 /* purge all keys of a specific type with literally matching
1548 * description */
1549 func = act_keyctl_purge_literal_func;
1550 } else {
1551 format();
1552 }
1553
1554 n = recursive_session_key_scan(func, &purge);
1555 printf("purged %d keys\n", n);
1556 return 0;
1557 }
1558
1559 /*****************************************************************************/
1560 /*
1561 * Invalidate a key
1562 */
1563 static int act_keyctl_invalidate(int argc, char *argv[])
1564 {
1565 key_serial_t key;
1566
1567 if (argc != 2)
1568 format();
1569
1570 key = get_key_id(argv[1]);
1571
1572 if (keyctl_invalidate(key) < 0)
1573 error("keyctl_invalidate");
1574
1575 return 0;
1576 }
1577
1578 /*****************************************************************************/
1579 /*
1580 * Get the per-UID persistent keyring
1581 */
1582 static int act_keyctl_get_persistent(int argc, char *argv[])
1583 {
1584 key_serial_t dest, ret;
1585 uid_t uid = -1;
1586 char *q;
1587
1588 if (argc != 2 && argc != 3)
1589 format();
1590
1591 dest = get_key_id(argv[1]);
1592
1593 if (argc > 2) {
1594 uid = strtoul(argv[2], &q, 0);
1595 if (*q) {
1596 fprintf(stderr, "Unparsable uid: '%s'\n", argv[2]);
1597 exit(2);
1598 }
1599 }
1600
1601 ret = keyctl_get_persistent(uid, dest);
1602 if (ret < 0)
1603 error("keyctl_get_persistent");
1604
1605 /* print the resulting key ID */
1606 printf("%d\n", ret);
1607 return 0;
1608 }
1609
1610 /*****************************************************************************/
1611 /*
1612 * parse a key identifier
1613 */
1614 static key_serial_t get_key_id(char *arg)
1615 {
1616 key_serial_t id;
1617 char *end;
1618
1619 /* handle a special keyring name */
1620 if (arg[0] == '@') {
1621 if (strcmp(arg, "@t" ) == 0) return KEY_SPEC_THREAD_KEYRING;
1622 if (strcmp(arg, "@p" ) == 0) return KEY_SPEC_PROCESS_KEYRING;
1623 if (strcmp(arg, "@s" ) == 0) return KEY_SPEC_SESSION_KEYRING;
1624 if (strcmp(arg, "@u" ) == 0) return KEY_SPEC_USER_KEYRING;
1625 if (strcmp(arg, "@us") == 0) return KEY_SPEC_USER_SESSION_KEYRING;
1626 if (strcmp(arg, "@g" ) == 0) return KEY_SPEC_GROUP_KEYRING;
1627 if (strcmp(arg, "@a" ) == 0) return KEY_SPEC_REQKEY_AUTH_KEY;
1628
1629 fprintf(stderr, "Unknown special key: '%s'\n", arg);
1630 exit(2);
1631 }
1632
1633 /* handle a lookup-by-name request "%<type>:<desc>", eg: "%keyring:_ses" */
1634 if (arg[0] == '%') {
1635 char *type;
1636
1637 arg++;
1638 if (!*arg)
1639 goto incorrect_key_by_name_spec;
1640
1641 if (*arg == ':') {
1642 type = "keyring";
1643 arg++;
1644 } else {
1645 type = arg;
1646 arg = strchr(arg, ':');
1647 if (!arg)
1648 goto incorrect_key_by_name_spec;
1649 *(arg++) = '\0';
1650 }
1651
1652 if (!*arg)
1653 goto incorrect_key_by_name_spec;
1654
1655 id = find_key_by_type_and_desc(type, arg, 0);
1656 if (id == -1) {
1657 fprintf(stderr, "Can't find '%s:%s'\n", type, arg);
1658 exit(1);
1659 }
1660 return id;
1661 }
1662
1663 /* handle a numeric key ID */
1664 id = strtoul(arg, &end, 0);
1665 if (*end) {
1666 fprintf(stderr, "Unparsable key: '%s'\n", arg);
1667 exit(2);
1668 }
1669
1670 return id;
1671
1672 incorrect_key_by_name_spec:
1673 fprintf(stderr, "Incorrect key-by-name spec\n");
1674 exit(2);
1675
1676 } /* end get_key_id() */
1677
1678 /*****************************************************************************/
1679 /*
1680 * recursively display a key/keyring tree
1681 */
1682 static int dump_key_tree_aux(key_serial_t key, int depth, int more, int hex_key_IDs)
1683 {
1684 static char dumpindent[64];
1685 key_serial_t *pk;
1686 key_perm_t perm;
1687 size_t ringlen, desclen;
1688 void *payload;
1689 char *desc, type[255], pretty_mask[9];
1690 int uid, gid, ret, n, dpos, rdepth, kcount = 0;
1691
1692 if (depth > 8 * 4)
1693 return 0;
1694
1695 /* find out how big this key's description is */
1696 ret = keyctl_describe(key, NULL, 0);
1697 if (ret < 0) {
1698 printf("%d: key inaccessible (%m)\n", key);
1699 return 0;
1700 }
1701 desclen = ret + 1;
1702
1703 desc = malloc(desclen);
1704 if (!desc)
1705 error("malloc");
1706
1707 /* read the description */
1708 ret = keyctl_describe(key, desc, desclen);
1709 if (ret < 0) {
1710 printf("%d: key inaccessible (%m)\n", key);
1711 free(desc);
1712 return 0;
1713 }
1714
1715 desclen = ret < desclen ? ret : desclen;
1716
1717 desc[desclen] = 0;
1718
1719 /* parse */
1720 type[0] = 0;
1721 uid = 0;
1722 gid = 0;
1723 perm = 0;
1724
1725 n = sscanf(desc, "%[^;];%d;%d;%x;%n",
1726 type, &uid, &gid, &perm, &dpos);
1727
1728 if (n != 4) {
1729 fprintf(stderr, "Unparseable description obtained for key %d\n", key);
1730 exit(3);
1731 }
1732
1733 /* and print */
1734 calc_perms(pretty_mask, perm, uid, gid);
1735
1736 if (hex_key_IDs)
1737 printf("0x%08x %s %5d %5d %s%s%s: %s\n",
1738 key,
1739 pretty_mask,
1740 uid, gid,
1741 dumpindent,
1742 depth > 0 ? "\\_ " : "",
1743 type, desc + dpos);
1744 else
1745 printf("%10d %s %5d %5d %s%s%s: %s\n",
1746 key,
1747 pretty_mask,
1748 uid, gid,
1749 dumpindent,
1750 depth > 0 ? "\\_ " : "",
1751 type, desc + dpos);
1752
1753 /* if it's a keyring then we're going to want to recursively
1754 * display it if we can */
1755 if (strcmp(type, "keyring") == 0) {
1756 /* find out how big the keyring is */
1757 ret = keyctl_read(key, NULL, 0);
1758 if (ret < 0)
1759 error("keyctl_read");
1760 if (ret == 0)
1761 return 0;
1762 ringlen = ret;
1763
1764 /* read its contents */
1765 payload = malloc(ringlen);
1766 if (!payload)
1767 error("malloc");
1768
1769 ret = keyctl_read(key, payload, ringlen);
1770 if (ret < 0)
1771 error("keyctl_read");
1772
1773 ringlen = ret < ringlen ? ret : ringlen;
1774 kcount = ringlen / sizeof(key_serial_t);
1775
1776 /* walk the keyring */
1777 pk = payload;
1778 do {
1779 key = *pk++;
1780
1781 /* recurse into nexted keyrings */
1782 if (strcmp(type, "keyring") == 0) {
1783 if (depth == 0) {
1784 rdepth = depth;
1785 dumpindent[rdepth++] = ' ';
1786 dumpindent[rdepth] = 0;
1787 }
1788 else {
1789 rdepth = depth;
1790 dumpindent[rdepth++] = ' ';
1791 dumpindent[rdepth++] = ' ';
1792 dumpindent[rdepth++] = ' ';
1793 dumpindent[rdepth++] = ' ';
1794 dumpindent[rdepth] = 0;
1795 }
1796
1797 if (more)
1798 dumpindent[depth + 0] = '|';
1799
1800 kcount += dump_key_tree_aux(key,
1801 rdepth,
1802 ringlen - 4 >= sizeof(key_serial_t),
1803 hex_key_IDs);
1804 }
1805
1806 } while (ringlen -= 4, ringlen >= sizeof(key_serial_t));
1807
1808 free(payload);
1809 }
1810
1811 free(desc);
1812 return kcount;
1813
1814 } /* end dump_key_tree_aux() */
1815
1816 /*****************************************************************************/
1817 /*
1818 * recursively list a keyring's contents
1819 */
1820 static int dump_key_tree(key_serial_t keyring, const char *name, int hex_key_IDs)
1821 {
1822 printf("%s\n", name);
1823
1824 keyring = keyctl_get_keyring_ID(keyring, 0);
1825 if (keyring == -1)
1826 error("Unable to dump key");
1827
1828 return dump_key_tree_aux(keyring, 0, 0, hex_key_IDs);
1829
1830 } /* end dump_key_tree() */
1831