aboutsummaryrefslogtreecommitdiffstats
path: root/net/rxrpc/ar-security.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2007-04-26 18:48:28 -0400
committerDavid S. Miller <davem@davemloft.net>2007-04-26 18:48:28 -0400
commit17926a79320afa9b95df6b977b40cca6d8713cea (patch)
tree5cedff43b69520ad17b86783d3752053686ec99c /net/rxrpc/ar-security.c
parente19dff1fdd99a25819af74cf0710e147fff4fd3a (diff)
[AF_RXRPC]: Provide secure RxRPC sockets for use by userspace and kernel both
Provide AF_RXRPC sockets that can be used to talk to AFS servers, or serve answers to AFS clients. KerberosIV security is fully supported. The patches and some example test programs can be found in: http://people.redhat.com/~dhowells/rxrpc/ This will eventually replace the old implementation of kernel-only RxRPC currently resident in net/rxrpc/. Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/rxrpc/ar-security.c')
-rw-r--r--net/rxrpc/ar-security.c258
1 files changed, 258 insertions, 0 deletions
diff --git a/net/rxrpc/ar-security.c b/net/rxrpc/ar-security.c
new file mode 100644
index 000000000000..60d1d364430a
--- /dev/null
+++ b/net/rxrpc/ar-security.c
@@ -0,0 +1,258 @@
1/* RxRPC security handling
2 *
3 * Copyright (C) 2007 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#include <linux/module.h>
13#include <linux/net.h>
14#include <linux/skbuff.h>
15#include <linux/udp.h>
16#include <linux/crypto.h>
17#include <net/sock.h>
18#include <net/af_rxrpc.h>
19#include "ar-internal.h"
20
21static LIST_HEAD(rxrpc_security_methods);
22static DECLARE_RWSEM(rxrpc_security_sem);
23
24/*
25 * get an RxRPC security module
26 */
27static struct rxrpc_security *rxrpc_security_get(struct rxrpc_security *sec)
28{
29 return try_module_get(sec->owner) ? sec : NULL;
30}
31
32/*
33 * release an RxRPC security module
34 */
35static void rxrpc_security_put(struct rxrpc_security *sec)
36{
37 module_put(sec->owner);
38}
39
40/*
41 * look up an rxrpc security module
42 */
43struct rxrpc_security *rxrpc_security_lookup(u8 security_index)
44{
45 struct rxrpc_security *sec = NULL;
46
47 _enter("");
48
49 down_read(&rxrpc_security_sem);
50
51 list_for_each_entry(sec, &rxrpc_security_methods, link) {
52 if (sec->security_index == security_index) {
53 if (unlikely(!rxrpc_security_get(sec)))
54 break;
55 goto out;
56 }
57 }
58
59 sec = NULL;
60out:
61 up_read(&rxrpc_security_sem);
62 _leave(" = %p [%s]", sec, sec ? sec->name : "");
63 return sec;
64}
65
66/**
67 * rxrpc_register_security - register an RxRPC security handler
68 * @sec: security module
69 *
70 * register an RxRPC security handler for use by RxRPC
71 */
72int rxrpc_register_security(struct rxrpc_security *sec)
73{
74 struct rxrpc_security *psec;
75 int ret;
76
77 _enter("");
78 down_write(&rxrpc_security_sem);
79
80 ret = -EEXIST;
81 list_for_each_entry(psec, &rxrpc_security_methods, link) {
82 if (psec->security_index == sec->security_index)
83 goto out;
84 }
85
86 list_add(&sec->link, &rxrpc_security_methods);
87
88 printk(KERN_NOTICE "RxRPC: Registered security type %d '%s'\n",
89 sec->security_index, sec->name);
90 ret = 0;
91
92out:
93 up_write(&rxrpc_security_sem);
94 _leave(" = %d", ret);
95 return ret;
96}
97
98EXPORT_SYMBOL_GPL(rxrpc_register_security);
99
100/**
101 * rxrpc_unregister_security - unregister an RxRPC security handler
102 * @sec: security module
103 *
104 * unregister an RxRPC security handler
105 */
106void rxrpc_unregister_security(struct rxrpc_security *sec)
107{
108
109 _enter("");
110 down_write(&rxrpc_security_sem);
111 list_del_init(&sec->link);
112 up_write(&rxrpc_security_sem);
113
114 printk(KERN_NOTICE "RxRPC: Unregistered security type %d '%s'\n",
115 sec->security_index, sec->name);
116}
117
118EXPORT_SYMBOL_GPL(rxrpc_unregister_security);
119
120/*
121 * initialise the security on a client connection
122 */
123int rxrpc_init_client_conn_security(struct rxrpc_connection *conn)
124{
125 struct rxrpc_security *sec;
126 struct key *key = conn->key;
127 int ret;
128
129 _enter("{%d},{%x}", conn->debug_id, key_serial(key));
130
131 if (!key)
132 return 0;
133
134 ret = key_validate(key);
135 if (ret < 0)
136 return ret;
137
138 sec = rxrpc_security_lookup(key->type_data.x[0]);
139 if (!sec)
140 return -EKEYREJECTED;
141 conn->security = sec;
142
143 ret = conn->security->init_connection_security(conn);
144 if (ret < 0) {
145 rxrpc_security_put(conn->security);
146 conn->security = NULL;
147 return ret;
148 }
149
150 _leave(" = 0");
151 return 0;
152}
153
154/*
155 * initialise the security on a server connection
156 */
157int rxrpc_init_server_conn_security(struct rxrpc_connection *conn)
158{
159 struct rxrpc_security *sec;
160 struct rxrpc_local *local = conn->trans->local;
161 struct rxrpc_sock *rx;
162 struct key *key;
163 key_ref_t kref;
164 char kdesc[5+1+3+1];
165
166 _enter("");
167
168 sprintf(kdesc, "%u:%u", ntohs(conn->service_id), conn->security_ix);
169
170 sec = rxrpc_security_lookup(conn->security_ix);
171 if (!sec) {
172 _leave(" = -ENOKEY [lookup]");
173 return -ENOKEY;
174 }
175
176 /* find the service */
177 read_lock_bh(&local->services_lock);
178 list_for_each_entry(rx, &local->services, listen_link) {
179 if (rx->service_id == conn->service_id)
180 goto found_service;
181 }
182
183 /* the service appears to have died */
184 read_unlock_bh(&local->services_lock);
185 rxrpc_security_put(sec);
186 _leave(" = -ENOENT");
187 return -ENOENT;
188
189found_service:
190 if (!rx->securities) {
191 read_unlock_bh(&local->services_lock);
192 rxrpc_security_put(sec);
193 _leave(" = -ENOKEY");
194 return -ENOKEY;
195 }
196
197 /* look through the service's keyring */
198 kref = keyring_search(make_key_ref(rx->securities, 1UL),
199 &key_type_rxrpc_s, kdesc);
200 if (IS_ERR(kref)) {
201 read_unlock_bh(&local->services_lock);
202 rxrpc_security_put(sec);
203 _leave(" = %ld [search]", PTR_ERR(kref));
204 return PTR_ERR(kref);
205 }
206
207 key = key_ref_to_ptr(kref);
208 read_unlock_bh(&local->services_lock);
209
210 conn->server_key = key;
211 conn->security = sec;
212
213 _leave(" = 0");
214 return 0;
215}
216
217/*
218 * secure a packet prior to transmission
219 */
220int rxrpc_secure_packet(const struct rxrpc_call *call,
221 struct sk_buff *skb,
222 size_t data_size,
223 void *sechdr)
224{
225 if (call->conn->security)
226 return call->conn->security->secure_packet(
227 call, skb, data_size, sechdr);
228 return 0;
229}
230
231/*
232 * secure a packet prior to transmission
233 */
234int rxrpc_verify_packet(const struct rxrpc_call *call, struct sk_buff *skb,
235 u32 *_abort_code)
236{
237 if (call->conn->security)
238 return call->conn->security->verify_packet(
239 call, skb, _abort_code);
240 return 0;
241}
242
243/*
244 * clear connection security
245 */
246void rxrpc_clear_conn_security(struct rxrpc_connection *conn)
247{
248 _enter("{%d}", conn->debug_id);
249
250 if (conn->security) {
251 conn->security->clear(conn);
252 rxrpc_security_put(conn->security);
253 conn->security = NULL;
254 }
255
256 key_put(conn->key);
257 key_put(conn->server_key);
258}