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  	
(1) Event cond_false: Condition "argc != 2", taking false branch
680  		if (argc != 2)
(2) Event if_end: End of if statement
681  			format();
682  	
683  		key = get_key_id(argv[1]);
684  	
685  		/* read the key payload data */
(3) Event alloc_arg: "keyctl_read_alloc(key_serial_t, void **)" allocates memory that is stored into "buffer". [details]
Also see events: [leaked_storage]
686  		ret = keyctl_read_alloc(key, &buffer);
(4) Event cond_false: Condition "ret < 0", taking false branch
687  		if (ret < 0)
(5) Event if_end: End of if statement
688  			error("keyctl_read_alloc");
689  	
(6) Event cond_true: Condition "ret == 0", taking true branch
690  		if (ret == 0) {
691  			printf("No data in key\n");
(7) Event leaked_storage: Variable "buffer" going out of scope leaks the storage it points to.
Also see events: [alloc_arg]
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  	
761  		if (argc != 2)
762  			format();
763  	
764  		key = get_key_id(argv[1]);
765  	
766  		/* read the key payload data */
767  		ret = keyctl_read_alloc(key, &buffer);
768  		if (ret < 0)
769  			error("keyctl_read_alloc");
770  	
771  		/* see if it's printable */
772  		p = buffer;
773  		for (loop = ret; loop > 0; loop--, p++)
774  			if (!isprint(*p))
775  				goto not_printable;
776  	
777  		/* it is */
778  		printf("%s\n", (char *) buffer);
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