Add PIE compilation flags
[platform/upstream/keyutils.git] / keyctl.c
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_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[]);
64
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>" },
104         { NULL,                 NULL,           NULL }
105 };
106
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);
111
112 static uid_t myuid;
113 static gid_t mygid, *mygroups;
114 static int myngroups;
115 static int verbose;
116
117 /*****************************************************************************/
118 /*
119  * handle an error
120  */
121 static inline void error(const char *msg)
122 {
123         perror(msg);
124         exit(1);
125
126 } /* end error() */
127
128 /*****************************************************************************/
129 /*
130  * execute the appropriate subcommand
131  */
132 int main(int argc, char *argv[])
133 {
134         const struct command *cmd, *best;
135         int n;
136
137         argv++;
138         argc--;
139
140         if (argc == 0)
141                 format();
142
143         /* find the best fit command */
144         best = NULL;
145         n = strlen(*argv);
146
147         for (cmd = commands; cmd->name; cmd++) {
148                 if (!cmd->action)
149                         continue;
150                 if (memcmp(cmd->name, *argv, n) != 0)
151                         continue;
152
153                 if (cmd->name[n] == 0) {
154                         /* exact match */
155                         best = cmd;
156                         break;
157                 }
158
159                 /* partial match */
160                 if (best) {
161                         fprintf(stderr, "Ambiguous command\n");
162                         exit(2);
163                 }
164
165                 best = cmd;
166         }
167
168         if (!best) {
169                 fprintf(stderr, "Unknown command\n");
170                 exit(2);
171         }
172
173         /* grab my UID, GID and groups */
174         myuid = geteuid();
175         mygid = getegid();
176         myngroups = getgroups(0, NULL);
177
178         if (myuid == -1 || mygid == -1 || myngroups == -1)
179                 error("Unable to get UID/GID/#Groups\n");
180
181         mygroups = calloc(myngroups, sizeof(gid_t));
182         if (!mygroups)
183                 error("calloc");
184
185         myngroups = getgroups(myngroups, mygroups);
186         if (myngroups < 0)
187                 error("Unable to get Groups\n");
188
189         return best->action(argc, argv);
190
191 } /* end main() */
192
193 /*****************************************************************************/
194 /*
195  * display command format information
196  */
197 static void format(void)
198 {
199         const struct command *cmd;
200
201         fprintf(stderr, "Format:\n");
202
203         for (cmd = commands; cmd->name; cmd++)
204                 fprintf(stderr, "  keyctl %s %s\n", cmd->name, cmd->format);
205
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");
219
220         exit(2);
221
222 } /* end format() */
223
224 /*****************************************************************************/
225 /*
226  * grab data from stdin
227  */
228 static char *grab_stdin(void)
229 {
230         static char input[65536 + 1];
231         int n, tmp;
232
233         n = 0;
234         do {
235                 tmp = read(0, input + n, sizeof(input) - 1 - n);
236                 if (tmp < 0)
237                         error("stdin");
238
239                 if (tmp == 0)
240                         break;
241
242                 n += tmp;
243
244         } while (n < sizeof(input));
245
246         if (n >= sizeof(input)) {
247                 fprintf(stderr, "Too much data read on stdin\n");
248                 exit(1);
249         }
250
251         input[n] = '\0';
252
253         return input;
254
255 } /* end grab_stdin() */
256
257 /*****************************************************************************/
258 /*
259  * convert the permissions mask to a string representing the permissions we
260  * have actually been granted
261  */
262 static void calc_perms(char *pretty, key_perm_t perm, uid_t uid, gid_t gid)
263 {
264         unsigned perms;
265         gid_t *pg;
266         int loop;
267
268         perms = (perm & KEY_POS_ALL) >> 24;
269
270         if (uid == myuid) {
271                 perms |= (perm & KEY_USR_ALL) >> 16;
272                 goto write_mask;
273         }
274
275         if (gid != -1) {
276                 if (gid == mygid) {
277                         perms |= (perm & KEY_GRP_ALL) >> 8;
278                         goto write_mask;
279                 }
280
281                 pg = mygroups;
282                 for (loop = myngroups; loop > 0; loop--, pg++) {
283                         if (gid == *pg) {
284                                 perms |= (perm & KEY_GRP_ALL) >> 8;
285                                 goto write_mask;
286                         }
287                 }
288         }
289
290         perms |= (perm & KEY_OTH_ALL);
291
292 write_mask:
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' : '-');
300
301 } /* end calc_perms() */
302
303 /*****************************************************************************/
304 /*
305  * show the parent process's session keyring
306  */
307 static int act_keyctl_show(int argc, char *argv[])
308 {
309         if (argc != 1)
310                 format();
311
312         dump_key_tree(KEY_SPEC_SESSION_KEYRING, "Session Keyring");
313         return 0;
314
315 } /* end act_keyctl_show() */
316
317 /*****************************************************************************/
318 /*
319  * add a key
320  */
321 static int act_keyctl_add(int argc, char *argv[])
322 {
323         key_serial_t dest;
324         int ret;
325
326         if (argc != 5)
327                 format();
328
329         dest = get_key_id(argv[4]);
330
331         ret = add_key(argv[1], argv[2], argv[3], strlen(argv[3]), dest);
332         if (ret < 0)
333                 error("add_key");
334
335         /* print the resulting key ID */
336         printf("%d\n", ret);
337         return 0;
338
339 } /* end act_keyctl_add() */
340
341 /*****************************************************************************/
342 /*
343  * add a key, reading from a pipe
344  */
345 static int act_keyctl_padd(int argc, char *argv[])
346 {
347         char *args[6];
348
349         if (argc != 4)
350                 format();
351
352         args[0] = argv[0];
353         args[1] = argv[1];
354         args[2] = argv[2];
355         args[3] = grab_stdin();
356         args[4] = argv[3];
357         args[5] = NULL;
358
359         return act_keyctl_add(5, args);
360
361 } /* end act_keyctl_padd() */
362
363 /*****************************************************************************/
364 /*
365  * request a key
366  */
367 static int act_keyctl_request(int argc, char *argv[])
368 {
369         key_serial_t dest;
370         int ret;
371
372         if (argc != 3 && argc != 4)
373                 format();
374
375         dest = 0;
376         if (argc == 4)
377                 dest = get_key_id(argv[3]);
378
379         ret = request_key(argv[1], argv[2], NULL, dest);
380         if (ret < 0)
381                 error("request_key");
382
383         /* print the resulting key ID */
384         printf("%d\n", ret);
385         return 0;
386
387 } /* end act_keyctl_request() */
388
389 /*****************************************************************************/
390 /*
391  * request a key, with recourse to /sbin/request-key
392  */
393 static int act_keyctl_request2(int argc, char *argv[])
394 {
395         key_serial_t dest;
396         int ret;
397
398         if (argc != 4 && argc != 5)
399                 format();
400
401         dest = 0;
402         if (argc == 5)
403                 dest = get_key_id(argv[4]);
404
405         ret = request_key(argv[1], argv[2], argv[3], dest);
406         if (ret < 0)
407                 error("request_key");
408
409         /* print the resulting key ID */
410         printf("%d\n", ret);
411         return 0;
412
413 } /* end act_keyctl_request2() */
414
415 /*****************************************************************************/
416 /*
417  * request a key, with recourse to /sbin/request-key, reading the callout info
418  * from a pipe
419  */
420 static int act_keyctl_prequest2(int argc, char *argv[])
421 {
422         char *args[6];
423
424         if (argc != 3 && argc != 4)
425                 format();
426
427         args[0] = argv[0];
428         args[1] = argv[1];
429         args[2] = argv[2];
430         args[3] = grab_stdin();
431         args[4] = argv[3];
432         args[5] = NULL;
433
434         return act_keyctl_request2(argc + 1, args);
435
436 } /* end act_keyctl_prequest2() */
437
438 /*****************************************************************************/
439 /*
440  * update a key
441  */
442 static int act_keyctl_update(int argc, char *argv[])
443 {
444         key_serial_t key;
445
446         if (argc != 3)
447                 format();
448
449         key = get_key_id(argv[1]);
450
451         if (keyctl_update(key, argv[2], strlen(argv[2])) < 0)
452                 error("keyctl_update");
453
454         return 0;
455
456 } /* end act_keyctl_update() */
457
458 /*****************************************************************************/
459 /*
460  * update a key, reading from a pipe
461  */
462 static int act_keyctl_pupdate(int argc, char *argv[])
463 {
464         char *args[4];
465
466         if (argc != 2)
467                 format();
468
469         args[0] = argv[0];
470         args[1] = argv[1];
471         args[2] = grab_stdin();
472         args[3] = NULL;
473
474         return act_keyctl_update(3, args);
475
476 } /* end act_keyctl_pupdate() */
477
478 /*****************************************************************************/
479 /*
480  * create a new keyring
481  */
482 static int act_keyctl_newring(int argc, char *argv[])
483 {
484         key_serial_t dest;
485         int ret;
486
487         if (argc != 3)
488                 format();
489
490         dest = get_key_id(argv[2]);
491
492         ret = add_key("keyring", argv[1], NULL, 0, dest);
493         if (ret < 0)
494                 error("add_key");
495
496         printf("%d\n", ret);
497         return 0;
498
499 } /* end act_keyctl_newring() */
500
501 /*****************************************************************************/
502 /*
503  * revoke a key
504  */
505 static int act_keyctl_revoke(int argc, char *argv[])
506 {
507         key_serial_t key;
508
509         if (argc != 2)
510                 format();
511
512         key = get_key_id(argv[1]);
513
514         if (keyctl_revoke(key) < 0)
515                 error("keyctl_revoke");
516
517         return 0;
518
519 } /* end act_keyctl_revoke() */
520
521 /*****************************************************************************/
522 /*
523  * clear a keyring
524  */
525 static int act_keyctl_clear(int argc, char *argv[])
526 {
527         key_serial_t keyring;
528
529         if (argc != 2)
530                 format();
531
532         keyring = get_key_id(argv[1]);
533
534         if (keyctl_clear(keyring) < 0)
535                 error("keyctl_clear");
536
537         return 0;
538
539 } /* end act_keyctl_clear() */
540
541 /*****************************************************************************/
542 /*
543  * link a key to a keyring
544  */
545 static int act_keyctl_link(int argc, char *argv[])
546 {
547         key_serial_t keyring, key;
548
549         if (argc != 3)
550                 format();
551
552         key = get_key_id(argv[1]);
553         keyring = get_key_id(argv[2]);
554
555         if (keyctl_link(key, keyring) < 0)
556                 error("keyctl_link");
557
558         return 0;
559
560 } /* end act_keyctl_link() */
561
562 /*
563  * Attempt to unlink a key matching the ID
564  */
565 static int act_keyctl_unlink_func(key_serial_t parent, key_serial_t key,
566                                   char *desc, int desc_len, void *data)
567 {
568         key_serial_t *target = data;
569
570         if (key == *target)
571                 return keyctl_unlink(key, parent) < 0 ? 0 : 1;
572         return 0;
573 }
574
575 /*
576  * Unlink a key from a keyring or from the session keyring tree.
577  */
578 static int act_keyctl_unlink(int argc, char *argv[])
579 {
580         key_serial_t keyring, key;
581         int n;
582
583         if (argc != 2 && argc != 3)
584                 format();
585
586         key = get_key_id(argv[1]);
587
588         if (argc == 3) {
589                 keyring = get_key_id(argv[2]);
590                 if (keyctl_unlink(key, keyring) < 0)
591                         error("keyctl_unlink");
592         } else {
593                 n = recursive_session_key_scan(act_keyctl_unlink_func, &key);
594                 printf("%d links removed\n", n);
595         }
596
597         return 0;
598 }
599
600 /*****************************************************************************/
601 /*
602  * search a keyring for a key
603  */
604 static int act_keyctl_search(int argc, char *argv[])
605 {
606         key_serial_t keyring, dest;
607         int ret;
608
609         if (argc != 4 && argc != 5)
610                 format();
611
612         keyring = get_key_id(argv[1]);
613
614         dest = 0;
615         if (argc == 5)
616                 dest = get_key_id(argv[4]);
617
618         ret = keyctl_search(keyring, argv[2], argv[3], dest);
619         if (ret < 0)
620                 error("keyctl_search");
621
622         /* print the ID of the key we found */
623         printf("%d\n", ret);
624         return 0;
625
626 } /* end act_keyctl_search() */
627
628 /*****************************************************************************/
629 /*
630  * read a key
631  */
632 static int act_keyctl_read(int argc, char *argv[])
633 {
634         key_serial_t key;
635         void *buffer;
636         char *p;
637         int ret, sep, col;
638
639         if (argc != 2)
640                 format();
641
642         key = get_key_id(argv[1]);
643
644         /* read the key payload data */
645         ret = keyctl_read_alloc(key, &buffer);
646         if (ret < 0)
647                 error("keyctl_read_alloc");
648
649         if (ret == 0) {
650                 printf("No data in key\n");
651                 return 0;
652         }
653
654         /* hexdump the contents */
655         printf("%u bytes of data in key:\n", ret);
656
657         sep = 0;
658         col = 0;
659         p = buffer;
660
661         do {
662                 if (sep) {
663                         putchar(sep);
664                         sep = 0;
665                 }
666
667                 printf("%02hhx", *p);
668                 p++;
669
670                 col++;
671                 if (col % 32 == 0)
672                         sep = '\n';
673                 else if (col % 4 == 0)
674                         sep = ' ';
675
676         } while (--ret > 0);
677
678         printf("\n");
679         return 0;
680
681 } /* end act_keyctl_read() */
682
683 /*****************************************************************************/
684 /*
685  * read a key and dump raw to stdout
686  */
687 static int act_keyctl_pipe(int argc, char *argv[])
688 {
689         key_serial_t key;
690         void *buffer;
691         int ret;
692
693         if (argc != 2)
694                 format();
695
696         key = get_key_id(argv[1]);
697
698         /* read the key payload data */
699         ret = keyctl_read_alloc(key, &buffer);
700         if (ret < 0)
701                 error("keyctl_read_alloc");
702
703         if (ret > 0 && write(1, buffer, ret) < 0)
704                 error("write");
705         return 0;
706
707 } /* end act_keyctl_pipe() */
708
709 /*****************************************************************************/
710 /*
711  * read a key and dump to stdout in printable form
712  */
713 static int act_keyctl_print(int argc, char *argv[])
714 {
715         key_serial_t key;
716         void *buffer;
717         char *p;
718         int loop, ret;
719
720         if (argc != 2)
721                 format();
722
723         key = get_key_id(argv[1]);
724
725         /* read the key payload data */
726         ret = keyctl_read_alloc(key, &buffer);
727         if (ret < 0)
728                 error("keyctl_read_alloc");
729
730         /* see if it's printable */
731         p = buffer;
732         for (loop = ret; loop > 0; loop--, p++)
733                 if (!isprint(*p))
734                         goto not_printable;
735
736         /* it is */
737         printf("%s\n", (char *) buffer);
738         return 0;
739
740 not_printable:
741         /* it isn't */
742         printf(":hex:");
743         p = buffer;
744         for (loop = ret; loop > 0; loop--, p++)
745                 printf("%02hhx", *p);
746         printf("\n");
747         return 0;
748
749 } /* end act_keyctl_print() */
750
751 /*****************************************************************************/
752 /*
753  * list a keyring
754  */
755 static int act_keyctl_list(int argc, char *argv[])
756 {
757         key_serial_t keyring, key, *pk;
758         key_perm_t perm;
759         void *keylist;
760         char *buffer, pretty_mask[9];
761         uid_t uid;
762         gid_t gid;
763         int count, tlen, dpos, n, ret;
764
765         if (argc != 2)
766                 format();
767
768         keyring = get_key_id(argv[1]);
769
770         /* read the key payload data */
771         count = keyctl_read_alloc(keyring, &keylist);
772         if (count < 0)
773                 error("keyctl_read_alloc");
774
775         count /= sizeof(key_serial_t);
776
777         if (count == 0) {
778                 printf("keyring is empty\n");
779                 return 0;
780         }
781
782         /* list the keys in the keyring */
783         if (count == 1)
784                 printf("1 key in keyring:\n");
785         else
786                 printf("%u keys in keyring:\n", count);
787
788         pk = keylist;
789         do {
790                 key = *pk++;
791
792                 ret = keyctl_describe_alloc(key, &buffer);
793                 if (ret < 0) {
794                         printf("%9d: key inaccessible (%m)\n", key);
795                         continue;
796                 }
797
798                 uid = 0;
799                 gid = 0;
800                 perm = 0;
801
802                 tlen = -1;
803                 dpos = -1;
804
805                 n = sscanf((char *) buffer, "%*[^;]%n;%d;%d;%x;%n",
806                            &tlen, &uid, &gid, &perm, &dpos);
807                 if (n != 3) {
808                         fprintf(stderr, "Unparseable description obtained for key %d\n", key);
809                         exit(3);
810                 }
811
812                 calc_perms(pretty_mask, perm, uid, gid);
813
814                 printf("%9d: %s %5d %5d %*.*s: %s\n",
815                        key,
816                        pretty_mask,
817                        uid, gid,
818                        tlen, tlen, buffer,
819                        buffer + dpos);
820
821                 free(buffer);
822
823         } while (--count);
824
825         return 0;
826
827 } /* end act_keyctl_list() */
828
829 /*****************************************************************************/
830 /*
831  * produce a raw list of a keyring
832  */
833 static int act_keyctl_rlist(int argc, char *argv[])
834 {
835         key_serial_t keyring, key, *pk;
836         void *keylist;
837         int count;
838
839         if (argc != 2)
840                 format();
841
842         keyring = get_key_id(argv[1]);
843
844         /* read the key payload data */
845         count = keyctl_read_alloc(keyring, &keylist);
846         if (count < 0)
847                 error("keyctl_read_alloc");
848
849         count /= sizeof(key_serial_t);
850
851         /* list the keys in the keyring */
852         if (count <= 0) {
853                 printf("\n");
854         }
855         else {
856                 pk = keylist;
857                 for (; count > 0; count--) {
858                         key = *pk++;
859                         printf("%d%c", key, count == 1 ? '\n' : ' ');
860                 }
861         }
862
863         return 0;
864
865 } /* end act_keyctl_rlist() */
866
867 /*****************************************************************************/
868 /*
869  * describe a key
870  */
871 static int act_keyctl_describe(int argc, char *argv[])
872 {
873         key_serial_t key;
874         key_perm_t perm;
875         char *buffer;
876         uid_t uid;
877         gid_t gid;
878         int tlen, dpos, n, ret;
879
880         if (argc != 2)
881                 format();
882
883         key = get_key_id(argv[1]);
884
885         /* get key description */
886         ret = keyctl_describe_alloc(key, &buffer);
887         if (ret < 0)
888                 error("keyctl_describe");
889
890         /* parse it */
891         uid = 0;
892         gid = 0;
893         perm = 0;
894
895         tlen = -1;
896         dpos = -1;
897
898         n = sscanf(buffer, "%*[^;]%n;%d;%d;%x;%n",
899                    &tlen, &uid, &gid, &perm, &dpos);
900         if (n != 3) {
901                 fprintf(stderr, "Unparseable description obtained for key %d\n", key);
902                 exit(3);
903         }
904
905         /* display it */
906         printf("%9d:"
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",
909                key,
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' : '-',
916
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' : '-',
923
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' : '-',
930
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' : '-',
937                uid, gid,
938                tlen, tlen, buffer,
939                buffer + dpos);
940
941         return 0;
942
943 } /* end act_keyctl_describe() */
944
945 /*****************************************************************************/
946 /*
947  * get raw key description
948  */
949 static int act_keyctl_rdescribe(int argc, char *argv[])
950 {
951         key_serial_t key;
952         char *buffer, *q;
953         int ret;
954
955         if (argc != 2 && argc != 3)
956                 format();
957         if (argc == 3 && !argv[2][0])
958                 format();
959
960         key = get_key_id(argv[1]);
961
962         /* get key description */
963         ret = keyctl_describe_alloc(key, &buffer);
964         if (ret < 0)
965                 error("keyctl_describe");
966
967         /* replace semicolon separators with requested alternative */
968         if (argc == 3) {
969                 for (q = buffer; *q; q++)
970                         if (*q == ';')
971                                 *q = argv[2][0];
972         }
973
974         /* display raw description */
975         printf("%s\n", buffer);
976         return 0;
977
978 } /* end act_keyctl_rdescribe() */
979
980 /*****************************************************************************/
981 /*
982  * change a key's ownership
983  */
984 static int act_keyctl_chown(int argc, char *argv[])
985 {
986         key_serial_t key;
987         uid_t uid;
988         char *q;
989
990         if (argc != 3)
991                 format();
992
993         key = get_key_id(argv[1]);
994
995         uid = strtoul(argv[2], &q, 0);
996         if (*q) {
997                 fprintf(stderr, "Unparsable uid: '%s'\n", argv[2]);
998                 exit(2);
999         }
1000
1001         if (keyctl_chown(key, uid, -1) < 0)
1002                 error("keyctl_chown");
1003
1004         return 0;
1005
1006 } /* end act_keyctl_chown() */
1007
1008 /*****************************************************************************/
1009 /*
1010  * change a key's group ownership
1011  */
1012 static int act_keyctl_chgrp(int argc, char *argv[])
1013 {
1014         key_serial_t key;
1015         gid_t gid;
1016         char *q;
1017
1018         if (argc != 3)
1019                 format();
1020
1021         key = get_key_id(argv[1]);
1022
1023         gid = strtoul(argv[2], &q, 0);
1024         if (*q) {
1025                 fprintf(stderr, "Unparsable gid: '%s'\n", argv[2]);
1026                 exit(2);
1027         }
1028
1029         if (keyctl_chown(key, -1, gid) < 0)
1030                 error("keyctl_chown");
1031
1032         return 0;
1033
1034 } /* end act_keyctl_chgrp() */
1035
1036 /*****************************************************************************/
1037 /*
1038  * set the permissions on a key
1039  */
1040 static int act_keyctl_setperm(int argc, char *argv[])
1041 {
1042         key_serial_t key;
1043         key_perm_t perm;
1044         char *q;
1045
1046         if (argc != 3)
1047                 format();
1048
1049         key = get_key_id(argv[1]);
1050         perm = strtoul(argv[2], &q, 0);
1051         if (*q) {
1052                 fprintf(stderr, "Unparsable permissions: '%s'\n", argv[2]);
1053                 exit(2);
1054         }
1055
1056         if (keyctl_setperm(key, perm) < 0)
1057                 error("keyctl_setperm");
1058
1059         return 0;
1060
1061 } /* end act_keyctl_setperm() */
1062
1063 /*****************************************************************************/
1064 /*
1065  * start a process in a new session
1066  */
1067 static int act_keyctl_session(int argc, char *argv[])
1068 {
1069         char *p, *q;
1070         int ret;
1071
1072         argv++;
1073         argc--;
1074
1075         /* no extra arguments signifies a standard shell in an anonymous
1076          * session */
1077         p = NULL;
1078         if (argc != 0) {
1079                 /* a dash signifies an anonymous session */
1080                 p = *argv;
1081                 if (strcmp(p, "-") == 0)
1082                         p = NULL;
1083
1084                 argv++;
1085                 argc--;
1086         }
1087
1088         /* create a new session keyring */
1089         ret = keyctl_join_session_keyring(p);
1090         if (ret < 0)
1091                 error("keyctl_join_session_keyring");
1092
1093         fprintf(stderr, "Joined session keyring: %d\n", ret);
1094
1095         /* run the standard shell if no arguments */
1096         if (argc == 0) {
1097                 q = getenv("SHELL");
1098                 if (!q)
1099                         q = "/bin/sh";
1100                 execl(q, q, NULL);
1101                 error(q);
1102         }
1103
1104         /* run the command specified */
1105         execvp(argv[0], argv);
1106         error(argv[0]);
1107
1108 } /* end act_keyctl_session() */
1109
1110 /*****************************************************************************/
1111 /*
1112  * instantiate a key that's under construction
1113  */
1114 static int act_keyctl_instantiate(int argc, char *argv[])
1115 {
1116         key_serial_t key, dest;
1117
1118         if (argc != 4)
1119                 format();
1120
1121         key = get_key_id(argv[1]);
1122         dest = get_key_id(argv[3]);
1123
1124         if (keyctl_instantiate(key, argv[2], strlen(argv[2]), dest) < 0)
1125                 error("keyctl_instantiate");
1126
1127         return 0;
1128
1129 } /* end act_keyctl_instantiate() */
1130
1131 /*****************************************************************************/
1132 /*
1133  * instantiate a key, reading from a pipe
1134  */
1135 static int act_keyctl_pinstantiate(int argc, char *argv[])
1136 {
1137         char *args[5];
1138
1139         if (argc != 3)
1140                 format();
1141
1142         args[0] = argv[0];
1143         args[1] = argv[1];
1144         args[2] = grab_stdin();
1145         args[3] = argv[2];
1146         args[4] = NULL;
1147
1148         return act_keyctl_instantiate(4, args);
1149
1150 } /* end act_keyctl_pinstantiate() */
1151
1152 /*****************************************************************************/
1153 /*
1154  * negate a key that's under construction
1155  */
1156 static int act_keyctl_negate(int argc, char *argv[])
1157 {
1158         unsigned long timeout;
1159         key_serial_t key, dest;
1160         char *q;
1161
1162         if (argc != 4)
1163                 format();
1164
1165         key = get_key_id(argv[1]);
1166
1167         timeout = strtoul(argv[2], &q, 10);
1168         if (*q) {
1169                 fprintf(stderr, "Unparsable timeout: '%s'\n", argv[2]);
1170                 exit(2);
1171         }
1172
1173         dest = get_key_id(argv[3]);
1174
1175         if (keyctl_negate(key, timeout, dest) < 0)
1176                 error("keyctl_negate");
1177
1178         return 0;
1179
1180 } /* end act_keyctl_negate() */
1181
1182 /*****************************************************************************/
1183 /*
1184  * set a key's timeout
1185  */
1186 static int act_keyctl_timeout(int argc, char *argv[])
1187 {
1188         unsigned long timeout;
1189         key_serial_t key;
1190         char *q;
1191
1192         if (argc != 3)
1193                 format();
1194
1195         key = get_key_id(argv[1]);
1196
1197         timeout = strtoul(argv[2], &q, 10);
1198         if (*q) {
1199                 fprintf(stderr, "Unparsable timeout: '%s'\n", argv[2]);
1200                 exit(2);
1201         }
1202
1203         if (keyctl_set_timeout(key, timeout) < 0)
1204                 error("keyctl_set_timeout");
1205
1206         return 0;
1207
1208 } /* end act_keyctl_timeout() */
1209
1210 /*****************************************************************************/
1211 /*
1212  * get a key's security label
1213  */
1214 static int act_keyctl_security(int argc, char *argv[])
1215 {
1216         key_serial_t key;
1217         char *buffer;
1218         int ret;
1219
1220         if (argc != 2)
1221                 format();
1222
1223         key = get_key_id(argv[1]);
1224
1225         /* get key description */
1226         ret = keyctl_get_security_alloc(key, &buffer);
1227         if (ret < 0)
1228                 error("keyctl_getsecurity");
1229
1230         printf("%s\n", buffer);
1231         return 0;
1232 }
1233
1234 /*****************************************************************************/
1235 /*
1236  * install a new session keyring on the parent process
1237  */
1238 static int act_keyctl_new_session(int argc, char *argv[])
1239 {
1240         key_serial_t keyring;
1241
1242         if (argc != 1)
1243                 format();
1244
1245         if (keyctl_join_session_keyring(NULL) < 0)
1246                 error("keyctl_join_session_keyring");
1247
1248         if (keyctl_session_to_parent() < 0)
1249                 error("keyctl_session_to_parent");
1250
1251         keyring = keyctl_get_keyring_ID(KEY_SPEC_SESSION_KEYRING, 0);
1252         if (keyring < 0)
1253                 error("keyctl_get_keyring_ID");
1254
1255         /* print the resulting key ID */
1256         printf("%d\n", keyring);
1257         return 0;
1258 }
1259
1260 /*****************************************************************************/
1261 /*
1262  * reject a key that's under construction
1263  */
1264 static int act_keyctl_reject(int argc, char *argv[])
1265 {
1266         unsigned long timeout;
1267         key_serial_t key, dest;
1268         unsigned long rejerr;
1269         char *q;
1270
1271         if (argc != 5)
1272                 format();
1273
1274         key = get_key_id(argv[1]);
1275
1276         timeout = strtoul(argv[2], &q, 10);
1277         if (*q) {
1278                 fprintf(stderr, "Unparsable timeout: '%s'\n", argv[2]);
1279                 exit(2);
1280         }
1281
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;
1288         } else {
1289                 rejerr = strtoul(argv[3], &q, 10);
1290                 if (*q) {
1291                         fprintf(stderr, "Unparsable error: '%s'\n", argv[3]);
1292                         exit(2);
1293                 }
1294         }
1295
1296         dest = get_key_id(argv[4]);
1297
1298         if (keyctl_reject(key, timeout, rejerr, dest) < 0)
1299                 error("keyctl_negate");
1300
1301         return 0;
1302 }
1303
1304 /*
1305  * Attempt to unlink a key if we can't read it for reasons other than we don't
1306  * have permission
1307  */
1308 static int act_keyctl_reap_func(key_serial_t parent, key_serial_t key,
1309                                 char *desc, int desc_len, void *data)
1310 {
1311         if (desc_len < 0 && errno != EACCES) {
1312                 if (verbose)
1313                         printf("Reap %d", key);
1314                 if (keyctl_unlink(key, parent) < 0) {
1315                         if (verbose)
1316                                 printf("... failed %m\n");
1317                         return 0;
1318                 } else {
1319                         if (verbose)
1320                                 printf("\n");
1321                         return 1;
1322                 };
1323         }
1324         return 0;
1325 }
1326
1327 /*
1328  * Reap the dead keys from the session keyring tree
1329  */
1330 static int act_keyctl_reap(int argc, char *argv[])
1331 {
1332         int n;
1333
1334         if (argc > 1 && strcmp(argv[1], "-v") == 0) {
1335                 verbose = 1;
1336                 argc--;
1337                 argv++;
1338         }
1339
1340         if (argc != 1)
1341                 format();
1342
1343         n = recursive_session_key_scan(act_keyctl_reap_func, NULL);
1344         printf("%d keys reaped\n", n);
1345         return 0;
1346 }
1347
1348 struct purge_data {
1349         const char      *type;
1350         const char      *desc;
1351         size_t          desc_len;
1352         size_t          type_len;
1353         char            prefix_match;
1354         char            case_indep;
1355 };
1356
1357 /*
1358  * Attempt to unlink a key matching the type
1359  */
1360 static int act_keyctl_purge_type_func(key_serial_t parent, key_serial_t key,
1361                                       char *raw, int raw_len, void *data)
1362 {
1363         const struct purge_data *purge = data;
1364         char *p, *type;
1365
1366         if (parent == 0 || !raw)
1367                 return 0;
1368
1369         /* type is everything before the first semicolon */
1370         type = raw;
1371         p = memchr(raw, ';', raw_len);
1372         if (!p)
1373                 return 0;
1374         *p = 0;
1375         if (strcmp(type, purge->type) != 0)
1376                 return 0;
1377
1378         return keyctl_unlink(key, parent) < 0 ? 0 : 1;
1379 }
1380
1381 /*
1382  * Attempt to unlink a key matching the type and description literally
1383  */
1384 static int act_keyctl_purge_literal_func(key_serial_t parent, key_serial_t key,
1385                                          char *raw, int raw_len, void *data)
1386 {
1387         const struct purge_data *purge = data;
1388         size_t tlen;
1389         char *p, *type, *desc;
1390
1391         if (parent == 0 || !raw)
1392                 return 0;
1393
1394         /* type is everything before the first semicolon */
1395         type = raw;
1396         p = memchr(type, ';', raw_len);
1397         if (!p)
1398                 return 0;
1399
1400         tlen = p - type;
1401         if (tlen != purge->type_len)
1402                 return 0;
1403         if (memcmp(type, purge->type, tlen) != 0)
1404                 return 0;
1405
1406         /* description is everything after the last semicolon */
1407         p++;
1408         desc = memrchr(p, ';', raw + raw_len - p);
1409         if (!desc)
1410                 return 0;
1411         desc++;
1412
1413         if (purge->prefix_match) {
1414                 if (raw_len - (desc - raw) < purge->desc_len)
1415                         return 0;
1416         } else {
1417                 if (raw_len - (desc - raw) != purge->desc_len)
1418                         return 0;
1419         }
1420
1421         if (purge->case_indep) {
1422                 if (strncasecmp(purge->desc, desc, purge->desc_len) != 0)
1423                         return 0;
1424         } else {
1425                 if (memcmp(purge->desc, desc, purge->desc_len) != 0)
1426                         return 0;
1427         }
1428
1429         printf("%*.*s '%s'\n", (int)tlen, (int)tlen, type, desc);
1430
1431         return keyctl_unlink(key, parent) < 0 ? 0 : 1;
1432 }
1433
1434 /*
1435  * Attempt to unlink a key matching the type and description literally
1436  */
1437 static int act_keyctl_purge_search_func(key_serial_t parent, key_serial_t keyring,
1438                                         char *raw, int raw_len, void *data)
1439 {
1440         const struct purge_data *purge = data;
1441         key_serial_t key;
1442         int kcount = 0;
1443
1444         if (!raw || memcmp(raw, "keyring;", 8) != 0)
1445                 return 0;
1446
1447         for (;;) {
1448                 key = keyctl_search(keyring, purge->type, purge->desc, 0);
1449                 if (keyctl_unlink(key, keyring) < 0)
1450                         return kcount;
1451                 kcount++;
1452         }
1453         return kcount;
1454 }
1455
1456 /*
1457  * Purge matching keys from a keyring
1458  */
1459 static int act_keyctl_purge(int argc, char *argv[])
1460 {
1461         recursive_key_scanner_t func;
1462         struct purge_data purge = {
1463                 .prefix_match   = 0,
1464                 .case_indep     = 0,
1465         };
1466         int n = 0, search_mode = 0;
1467
1468         argc--;
1469         argv++;
1470         while (argc > 0 && argv[0][0] == '-') {
1471                 if (argv[0][1] == 's')
1472                         search_mode = 1;
1473                 else if (argv[0][1] == 'p')
1474                         purge.prefix_match = 1;
1475                 else if (argv[0][1] == 'i')
1476                         purge.case_indep = 1;
1477                 else
1478                         format();
1479                 argc--;
1480                 argv++;
1481         }
1482
1483         if (argc < 1)
1484                 format();
1485
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;
1490
1491         if (search_mode == 1) {
1492                 if (argc != 2 || purge.prefix_match || purge.case_indep)
1493                         format();
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)
1499                         format();
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
1504                  * description */
1505                 func = act_keyctl_purge_literal_func;
1506         } else {
1507                 format();
1508         }
1509
1510         n = recursive_session_key_scan(func, &purge);
1511         printf("purged %d keys\n", n);
1512         return 0;
1513 }
1514
1515 /*****************************************************************************/
1516 /*
1517  * parse a key identifier
1518  */
1519 static key_serial_t get_key_id(const char *arg)
1520 {
1521         key_serial_t id;
1522         char *end;
1523
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;
1533
1534                 fprintf(stderr, "Unknown special key: '%s'\n", arg);
1535                 exit(2);
1536         }
1537
1538         /* handle a numeric key ID */
1539         id = strtoul(arg, &end, 0);
1540         if (*end) {
1541                 fprintf(stderr, "Unparsable key: '%s'\n", arg);
1542                 exit(2);
1543         }
1544
1545         return id;
1546
1547 } /* end get_key_id() */
1548
1549 /*****************************************************************************/
1550 /*
1551  * recursively display a key/keyring tree
1552  */
1553 static int dump_key_tree_aux(key_serial_t key, int depth, int more)
1554 {
1555         static char dumpindent[64];
1556         key_serial_t *pk;
1557         key_perm_t perm;
1558         size_t ringlen, desclen;
1559         void *payload;
1560         char *desc, type[255], pretty_mask[9];
1561         int uid, gid, ret, n, dpos, rdepth, kcount = 0;
1562
1563         if (depth > 8)
1564                 return 0;
1565
1566         /* find out how big this key's description is */
1567         ret = keyctl_describe(key, NULL, 0);
1568         if (ret < 0) {
1569                 printf("%d: key inaccessible (%m)\n", key);
1570                 return 0;
1571         }
1572         desclen = ret + 1;
1573
1574         desc = malloc(desclen);
1575         if (!desc)
1576                 error("malloc");
1577
1578         /* read the description */
1579         ret = keyctl_describe(key, desc, desclen);
1580         if (ret < 0) {
1581                 printf("%d: key inaccessible (%m)\n", key);
1582                 free(desc);
1583                 return 0;
1584         }
1585
1586         desclen = ret < desclen ? ret : desclen;
1587
1588         desc[desclen] = 0;
1589
1590         /* parse */
1591         type[0] = 0;
1592         uid = 0;
1593         gid = 0;
1594         perm = 0;
1595
1596         n = sscanf(desc, "%[^;];%d;%d;%x;%n",
1597                    type, &uid, &gid, &perm, &dpos);
1598
1599         if (n != 4) {
1600                 fprintf(stderr, "Unparseable description obtained for key %d\n", key);
1601                 exit(3);
1602         }
1603
1604         /* and print */
1605         calc_perms(pretty_mask, perm, uid, gid);
1606
1607         printf("%9d %s  %5d %5d  %s%s%s: %s\n",
1608                key,
1609                pretty_mask,
1610                uid, gid,
1611                dumpindent,
1612                depth > 0 ? "\\_ " : "",
1613                type, desc + dpos);
1614
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);
1620                 if (ret < 0)
1621                         error("keyctl_read");
1622                 if (ret == 0)
1623                         return 0;
1624                 ringlen = ret;
1625
1626                 /* read its contents */
1627                 payload = malloc(ringlen);
1628                 if (!payload)
1629                         error("malloc");
1630
1631                 ret = keyctl_read(key, payload, ringlen);
1632                 if (ret < 0)
1633                         error("keyctl_read");
1634
1635                 ringlen = ret < ringlen ? ret : ringlen;
1636                 kcount = ringlen / sizeof(key_serial_t);
1637
1638                 /* walk the keyring */
1639                 pk = payload;
1640                 do {
1641                         key = *pk++;
1642
1643                         /* recurse into nexted keyrings */
1644                         if (strcmp(type, "keyring") == 0) {
1645                                 if (depth == 0) {
1646                                         rdepth = depth;
1647                                         dumpindent[rdepth++] = ' ';
1648                                         dumpindent[rdepth] = 0;
1649                                 }
1650                                 else {
1651                                         rdepth = depth;
1652                                         dumpindent[rdepth++] = ' ';
1653                                         dumpindent[rdepth++] = ' ';
1654                                         dumpindent[rdepth++] = ' ';
1655                                         dumpindent[rdepth++] = ' ';
1656                                         dumpindent[rdepth] = 0;
1657                                 }
1658
1659                                 if (more)
1660                                         dumpindent[depth + 0] = '|';
1661
1662                                 kcount += dump_key_tree_aux(key,
1663                                                             rdepth,
1664                                                             ringlen - 4 >= sizeof(key_serial_t));
1665                         }
1666
1667                 } while (ringlen -= 4, ringlen >= sizeof(key_serial_t));
1668
1669                 free(payload);
1670         }
1671
1672         free(desc);
1673         return kcount;
1674
1675 } /* end dump_key_tree_aux() */
1676
1677 /*****************************************************************************/
1678 /*
1679  * recursively list a keyring's contents
1680  */
1681 static int dump_key_tree(key_serial_t keyring, const char *name)
1682 {
1683         printf("%s\n", name);
1684         return dump_key_tree_aux(keyring, 0, 0);
1685
1686 } /* end dump_key_tree() */