1/*
2 * Copyright (c) 2014-2015 Dmitry V. Levin <ldv@altlinux.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 *    derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "defs.h"
29
30typedef int32_t key_serial_t;
31
32#include "xlat/key_spec.h"
33
34static void
35print_keyring_serial_number(key_serial_t id)
36{
37	const char *str = xlookup(key_spec, id);
38
39	if (str)
40		tprints(str);
41	else
42		tprintf("%d", id);
43}
44
45SYS_FUNC(add_key)
46{
47	/* type */
48	printstr(tcp, tcp->u_arg[0], -1);
49	/* description */
50	tprints(", ");
51	printstr(tcp, tcp->u_arg[1], -1);
52	/* payload */
53	tprints(", ");
54	printstr(tcp, tcp->u_arg[2], tcp->u_arg[3]);
55	/* payload length */
56	tprintf(", %lu, ", tcp->u_arg[3]);
57	/* keyring serial number */
58	print_keyring_serial_number(tcp->u_arg[4]);
59
60	return RVAL_DECODED;
61}
62
63SYS_FUNC(request_key)
64{
65	/* type */
66	printstr(tcp, tcp->u_arg[0], -1);
67	/* description */
68	tprints(", ");
69	printstr(tcp, tcp->u_arg[1], -1);
70	/* callout_info */
71	tprints(", ");
72	printstr(tcp, tcp->u_arg[2], -1);
73	/* keyring serial number */
74	tprints(", ");
75	print_keyring_serial_number(tcp->u_arg[3]);
76
77	return RVAL_DECODED;
78}
79
80static void
81keyctl_get_keyring_id(struct tcb *tcp, key_serial_t id, int create)
82{
83	print_keyring_serial_number(id);
84	tprintf(", %d", create);
85}
86
87static void
88keyctl_update_key(struct tcb *tcp, key_serial_t id, long addr, long len)
89{
90	print_keyring_serial_number(id);
91	tprints(", ");
92	printstr(tcp, addr, len);
93	tprintf(", %lu", len);
94}
95
96static void
97keyctl_handle_key_key(struct tcb *tcp, key_serial_t id1, key_serial_t id2)
98{
99	print_keyring_serial_number(id1);
100	tprints(", ");
101	print_keyring_serial_number(id2);
102}
103
104static void
105keyctl_read_key(struct tcb *tcp, key_serial_t id, long addr, long len)
106{
107	if (entering(tcp)) {
108		print_keyring_serial_number(id);
109		tprints(", ");
110	} else {
111		if (syserror(tcp))
112			printaddr(addr);
113		else {
114			long rval = tcp->u_rval > len ?
115				    len : (tcp->u_rval ? -1 : 0);
116			printstr(tcp, addr, rval);
117		}
118		tprintf(", %lu", len);
119	}
120}
121
122static void
123keyctl_keyring_search(struct tcb *tcp, key_serial_t id1, long addr1,
124		      long addr2, key_serial_t id2)
125{
126	print_keyring_serial_number(id1);
127	tprints(", ");
128	printstr(tcp, addr1, -1);
129	tprints(", ");
130	printstr(tcp, addr2, -1);
131	tprints(", ");
132	print_keyring_serial_number(id2);
133}
134
135static void
136keyctl_chown_key(struct tcb *tcp, key_serial_t id, int user, int group)
137{
138	print_keyring_serial_number(id);
139	tprintf(", %d, %d", user, group);
140}
141
142static void
143keyctl_instantiate_key(struct tcb *tcp, key_serial_t id1, long addr,
144		       long len, key_serial_t id2)
145{
146	print_keyring_serial_number(id1);
147	tprints(", ");
148	printstr(tcp, addr, len);
149	tprintf(", %lu, ", len);
150	print_keyring_serial_number(id2);
151}
152
153static void
154keyctl_instantiate_key_iov(struct tcb *tcp, key_serial_t id1,
155			   long addr, long len, key_serial_t id2)
156{
157	print_keyring_serial_number(id1);
158	tprints(", ");
159	tprint_iov(tcp, len, addr, 1);
160	tprintf(", %lu, ", len);
161	print_keyring_serial_number(id2);
162}
163
164static void
165keyctl_negate_key(struct tcb *tcp, key_serial_t id1, unsigned timeout,
166		  key_serial_t id2)
167{
168	print_keyring_serial_number(id1);
169	tprintf(", %u, ", timeout);
170	print_keyring_serial_number(id2);
171}
172
173static void
174keyctl_reject_key(struct tcb *tcp, key_serial_t id1, unsigned timeout,
175		  unsigned error, key_serial_t id2)
176{
177	print_keyring_serial_number(id1);
178	tprintf(", %u, %u, ", timeout, error);
179	print_keyring_serial_number(id2);
180}
181
182static void
183keyctl_set_timeout(struct tcb *tcp, key_serial_t id, unsigned timeout)
184{
185	print_keyring_serial_number(id);
186	tprintf(", %u", timeout);
187}
188
189static void
190keyctl_get_persistent(struct tcb *tcp, int uid, key_serial_t id)
191{
192	tprintf("%d, ", uid);
193	print_keyring_serial_number(id);
194}
195
196#include "xlat/key_perms.h"
197
198static void
199keyctl_setperm_key(struct tcb *tcp, key_serial_t id, uint32_t perm)
200{
201	print_keyring_serial_number(id);
202	tprints(", ");
203	printflags(key_perms, perm, "KEY_???");
204}
205
206#include "xlat/key_reqkeys.h"
207#include "xlat/keyctl_commands.h"
208
209SYS_FUNC(keyctl)
210{
211	int cmd = tcp->u_arg[0];
212
213	if (entering(tcp)) {
214		printxval(keyctl_commands, cmd, "KEYCTL_???");
215		tprints(", ");
216	}
217
218	switch (cmd) {
219	case KEYCTL_GET_KEYRING_ID:
220		keyctl_get_keyring_id(tcp, tcp->u_arg[1], tcp->u_arg[2]);
221		break;
222
223	case KEYCTL_JOIN_SESSION_KEYRING:
224		printstr(tcp, tcp->u_arg[1], -1);
225		break;
226
227	case KEYCTL_UPDATE:
228		keyctl_update_key(tcp, tcp->u_arg[1],
229				  tcp->u_arg[2], tcp->u_arg[3]);
230		break;
231
232	case KEYCTL_REVOKE:
233	case KEYCTL_CLEAR:
234	case KEYCTL_INVALIDATE:
235	case KEYCTL_ASSUME_AUTHORITY:
236		print_keyring_serial_number(tcp->u_arg[1]);
237		break;
238
239	case KEYCTL_LINK:
240	case KEYCTL_UNLINK:
241		keyctl_handle_key_key(tcp, tcp->u_arg[1], tcp->u_arg[2]);
242		break;
243
244	case KEYCTL_DESCRIBE:
245	case KEYCTL_READ:
246	case KEYCTL_GET_SECURITY:
247		keyctl_read_key(tcp, tcp->u_arg[1],
248				tcp->u_arg[2], tcp->u_arg[3]);
249		return 0;
250
251	case KEYCTL_SEARCH:
252		keyctl_keyring_search(tcp, tcp->u_arg[1], tcp->u_arg[2],
253				      tcp->u_arg[3], tcp->u_arg[4]);
254		break;
255
256	case KEYCTL_CHOWN:
257		keyctl_chown_key(tcp, tcp->u_arg[1],
258				 tcp->u_arg[2], tcp->u_arg[3]);
259		break;
260
261	case KEYCTL_SETPERM:
262		keyctl_setperm_key(tcp, tcp->u_arg[1], tcp->u_arg[2]);
263		break;
264
265	case KEYCTL_INSTANTIATE:
266		keyctl_instantiate_key(tcp, tcp->u_arg[1], tcp->u_arg[2],
267				       tcp->u_arg[3], tcp->u_arg[4]);
268		break;
269
270	case KEYCTL_NEGATE:
271		keyctl_negate_key(tcp, tcp->u_arg[1],
272				  tcp->u_arg[2], tcp->u_arg[3]);
273		break;
274
275	case KEYCTL_SET_REQKEY_KEYRING:
276		printxval(key_reqkeys, tcp->u_arg[1], "KEY_REQKEY_DEFL_???");
277		break;
278
279	case KEYCTL_SET_TIMEOUT:
280		keyctl_set_timeout(tcp, tcp->u_arg[1], tcp->u_arg[2]);
281		break;
282
283	case KEYCTL_SESSION_TO_PARENT:
284		break;
285
286	case KEYCTL_REJECT:
287		keyctl_reject_key(tcp, tcp->u_arg[1], tcp->u_arg[2],
288				  tcp->u_arg[3], tcp->u_arg[4]);
289		break;
290
291	case KEYCTL_INSTANTIATE_IOV:
292		keyctl_instantiate_key_iov(tcp, tcp->u_arg[1],
293					   tcp->u_arg[2], tcp->u_arg[3],
294					   tcp->u_arg[4]);
295		break;
296
297	case KEYCTL_GET_PERSISTENT:
298		keyctl_get_persistent(tcp, tcp->u_arg[1], tcp->u_arg[2]);
299		break;
300
301	default:
302		tprintf("%#lx, %#lx, %#lx, %#lx",
303			tcp->u_arg[1], tcp->u_arg[2],
304			tcp->u_arg[3], tcp->u_arg[4]);
305		break;
306	}
307
308	return RVAL_DECODED;
309}
310