Commit | Line | Data |
---|---|---|
3e30148c DH |
1 | /* request_key_auth.c: request key authorisation controlling key def |
2 | * | |
3 | * Copyright (C) 2005 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. | |
f1a9badc DH |
10 | * |
11 | * See Documentation/keys-request-key.txt | |
3e30148c DH |
12 | */ |
13 | ||
14 | #include <linux/module.h> | |
15 | #include <linux/sched.h> | |
16 | #include <linux/err.h> | |
17 | #include <linux/seq_file.h> | |
b5f545c8 | 18 | #include <asm/uaccess.h> |
3e30148c DH |
19 | #include "internal.h" |
20 | ||
21 | static int request_key_auth_instantiate(struct key *, const void *, size_t); | |
22 | static void request_key_auth_describe(const struct key *, struct seq_file *); | |
23 | static void request_key_auth_destroy(struct key *); | |
b5f545c8 | 24 | static long request_key_auth_read(const struct key *, char __user *, size_t); |
3e30148c DH |
25 | |
26 | /* | |
27 | * the request-key authorisation key type definition | |
28 | */ | |
29 | struct key_type key_type_request_key_auth = { | |
30 | .name = ".request_key_auth", | |
31 | .def_datalen = sizeof(struct request_key_auth), | |
32 | .instantiate = request_key_auth_instantiate, | |
33 | .describe = request_key_auth_describe, | |
34 | .destroy = request_key_auth_destroy, | |
b5f545c8 | 35 | .read = request_key_auth_read, |
3e30148c DH |
36 | }; |
37 | ||
38 | /*****************************************************************************/ | |
39 | /* | |
b5f545c8 | 40 | * instantiate a request-key authorisation key |
3e30148c DH |
41 | */ |
42 | static int request_key_auth_instantiate(struct key *key, | |
43 | const void *data, | |
44 | size_t datalen) | |
45 | { | |
b5f545c8 DH |
46 | key->payload.data = (struct request_key_auth *) data; |
47 | return 0; | |
3e30148c DH |
48 | |
49 | } /* end request_key_auth_instantiate() */ | |
50 | ||
51 | /*****************************************************************************/ | |
52 | /* | |
b5f545c8 | 53 | * reading a request-key authorisation key retrieves the callout information |
3e30148c DH |
54 | */ |
55 | static void request_key_auth_describe(const struct key *key, | |
56 | struct seq_file *m) | |
57 | { | |
58 | struct request_key_auth *rka = key->payload.data; | |
59 | ||
60 | seq_puts(m, "key:"); | |
61 | seq_puts(m, key->description); | |
b5f545c8 | 62 | seq_printf(m, " pid:%d ci:%zu", rka->pid, strlen(rka->callout_info)); |
3e30148c DH |
63 | |
64 | } /* end request_key_auth_describe() */ | |
65 | ||
b5f545c8 DH |
66 | /*****************************************************************************/ |
67 | /* | |
68 | * read the callout_info data | |
69 | * - the key's semaphore is read-locked | |
70 | */ | |
71 | static long request_key_auth_read(const struct key *key, | |
72 | char __user *buffer, size_t buflen) | |
73 | { | |
74 | struct request_key_auth *rka = key->payload.data; | |
75 | size_t datalen; | |
76 | long ret; | |
77 | ||
78 | datalen = strlen(rka->callout_info); | |
79 | ret = datalen; | |
80 | ||
81 | /* we can return the data as is */ | |
82 | if (buffer && buflen > 0) { | |
83 | if (buflen > datalen) | |
84 | buflen = datalen; | |
85 | ||
86 | if (copy_to_user(buffer, rka->callout_info, buflen) != 0) | |
87 | ret = -EFAULT; | |
88 | } | |
89 | ||
90 | return ret; | |
91 | ||
92 | } /* end request_key_auth_read() */ | |
93 | ||
3e30148c DH |
94 | /*****************************************************************************/ |
95 | /* | |
96 | * destroy an instantiation authorisation token key | |
97 | */ | |
98 | static void request_key_auth_destroy(struct key *key) | |
99 | { | |
100 | struct request_key_auth *rka = key->payload.data; | |
101 | ||
102 | kenter("{%d}", key->serial); | |
103 | ||
104 | key_put(rka->target_key); | |
74fd92c5 | 105 | kfree(rka); |
3e30148c DH |
106 | |
107 | } /* end request_key_auth_destroy() */ | |
108 | ||
109 | /*****************************************************************************/ | |
110 | /* | |
b5f545c8 DH |
111 | * create an authorisation token for /sbin/request-key or whoever to gain |
112 | * access to the caller's security data | |
3e30148c | 113 | */ |
b5f545c8 | 114 | struct key *request_key_auth_new(struct key *target, const char *callout_info) |
3e30148c | 115 | { |
b5f545c8 DH |
116 | struct request_key_auth *rka, *irka; |
117 | struct key *authkey = NULL; | |
3e30148c DH |
118 | char desc[20]; |
119 | int ret; | |
120 | ||
121 | kenter("%d,", target->serial); | |
122 | ||
b5f545c8 DH |
123 | /* allocate a auth record */ |
124 | rka = kmalloc(sizeof(*rka), GFP_KERNEL); | |
125 | if (!rka) { | |
126 | kleave(" = -ENOMEM"); | |
127 | return ERR_PTR(-ENOMEM); | |
128 | } | |
3e30148c | 129 | |
b5f545c8 DH |
130 | /* see if the calling process is already servicing the key request of |
131 | * another process */ | |
132 | if (current->request_key_auth) { | |
133 | /* it is - use that instantiation context here too */ | |
134 | irka = current->request_key_auth->payload.data; | |
135 | rka->context = irka->context; | |
136 | rka->pid = irka->pid; | |
3e30148c | 137 | } |
b5f545c8 DH |
138 | else { |
139 | /* it isn't - use this process as the context */ | |
140 | rka->context = current; | |
141 | rka->pid = current->pid; | |
142 | } | |
143 | ||
144 | rka->target_key = key_get(target); | |
145 | rka->callout_info = callout_info; | |
3e30148c DH |
146 | |
147 | /* allocate the auth key */ | |
148 | sprintf(desc, "%x", target->serial); | |
149 | ||
b5f545c8 | 150 | authkey = key_alloc(&key_type_request_key_auth, desc, |
d720024e | 151 | current->fsuid, current->fsgid, current, |
b5f545c8 DH |
152 | KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH | |
153 | KEY_USR_VIEW, 1); | |
154 | if (IS_ERR(authkey)) { | |
155 | ret = PTR_ERR(authkey); | |
156 | goto error_alloc; | |
3e30148c DH |
157 | } |
158 | ||
159 | /* construct and attach to the keyring */ | |
b5f545c8 DH |
160 | ret = key_instantiate_and_link(authkey, rka, 0, NULL, NULL); |
161 | if (ret < 0) | |
162 | goto error_inst; | |
3e30148c | 163 | |
b5f545c8 DH |
164 | kleave(" = {%d})", authkey->serial); |
165 | return authkey; | |
166 | ||
167 | error_inst: | |
168 | key_revoke(authkey); | |
169 | key_put(authkey); | |
170 | error_alloc: | |
171 | key_put(rka->target_key); | |
172 | kfree(rka); | |
173 | kleave("= %d", ret); | |
174 | return ERR_PTR(ret); | |
3e30148c DH |
175 | |
176 | } /* end request_key_auth_new() */ | |
177 | ||
b5f545c8 DH |
178 | /*****************************************************************************/ |
179 | /* | |
180 | * see if an authorisation key is associated with a particular key | |
181 | */ | |
182 | static int key_get_instantiation_authkey_match(const struct key *key, | |
183 | const void *_id) | |
184 | { | |
185 | struct request_key_auth *rka = key->payload.data; | |
186 | key_serial_t id = (key_serial_t)(unsigned long) _id; | |
187 | ||
188 | return rka->target_key->serial == id; | |
189 | ||
190 | } /* end key_get_instantiation_authkey_match() */ | |
191 | ||
3e30148c DH |
192 | /*****************************************************************************/ |
193 | /* | |
194 | * get the authorisation key for instantiation of a specific key if attached to | |
195 | * the current process's keyrings | |
196 | * - this key is inserted into a keyring and that is set as /sbin/request-key's | |
197 | * session keyring | |
198 | * - a target_id of zero specifies any valid token | |
199 | */ | |
200 | struct key *key_get_instantiation_authkey(key_serial_t target_id) | |
201 | { | |
b5f545c8 DH |
202 | struct key *authkey; |
203 | key_ref_t authkey_ref; | |
204 | ||
205 | authkey_ref = search_process_keyrings( | |
206 | &key_type_request_key_auth, | |
207 | (void *) (unsigned long) target_id, | |
208 | key_get_instantiation_authkey_match, | |
209 | current); | |
210 | ||
211 | if (IS_ERR(authkey_ref)) { | |
212 | authkey = ERR_PTR(PTR_ERR(authkey_ref)); | |
213 | goto error; | |
214 | } | |
3e30148c | 215 | |
b5f545c8 DH |
216 | authkey = key_ref_to_ptr(authkey_ref); |
217 | if (test_bit(KEY_FLAG_REVOKED, &authkey->flags)) { | |
218 | key_put(authkey); | |
219 | authkey = ERR_PTR(-EKEYREVOKED); | |
220 | } | |
3e30148c | 221 | |
b5f545c8 DH |
222 | error: |
223 | return authkey; | |
3e30148c DH |
224 | |
225 | } /* end key_get_instantiation_authkey() */ |