rxrpc: Permit multiple service binding
[platform/kernel/linux-exynos.git] / net / rxrpc / security.c
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 <keys/rxrpc-type.h>
20 #include "ar-internal.h"
21
22 static LIST_HEAD(rxrpc_security_methods);
23 static DECLARE_RWSEM(rxrpc_security_sem);
24
25 static const struct rxrpc_security *rxrpc_security_types[] = {
26         [RXRPC_SECURITY_NONE]   = &rxrpc_no_security,
27 #ifdef CONFIG_RXKAD
28         [RXRPC_SECURITY_RXKAD]  = &rxkad,
29 #endif
30 };
31
32 int __init rxrpc_init_security(void)
33 {
34         int i, ret;
35
36         for (i = 0; i < ARRAY_SIZE(rxrpc_security_types); i++) {
37                 if (rxrpc_security_types[i]) {
38                         ret = rxrpc_security_types[i]->init();
39                         if (ret < 0)
40                                 goto failed;
41                 }
42         }
43
44         return 0;
45
46 failed:
47         for (i--; i >= 0; i--)
48                 if (rxrpc_security_types[i])
49                         rxrpc_security_types[i]->exit();
50         return ret;
51 }
52
53 void rxrpc_exit_security(void)
54 {
55         int i;
56
57         for (i = 0; i < ARRAY_SIZE(rxrpc_security_types); i++)
58                 if (rxrpc_security_types[i])
59                         rxrpc_security_types[i]->exit();
60 }
61
62 /*
63  * look up an rxrpc security module
64  */
65 static const struct rxrpc_security *rxrpc_security_lookup(u8 security_index)
66 {
67         if (security_index >= ARRAY_SIZE(rxrpc_security_types))
68                 return NULL;
69         return rxrpc_security_types[security_index];
70 }
71
72 /*
73  * initialise the security on a client connection
74  */
75 int rxrpc_init_client_conn_security(struct rxrpc_connection *conn)
76 {
77         const struct rxrpc_security *sec;
78         struct rxrpc_key_token *token;
79         struct key *key = conn->params.key;
80         int ret;
81
82         _enter("{%d},{%x}", conn->debug_id, key_serial(key));
83
84         if (!key)
85                 return 0;
86
87         ret = key_validate(key);
88         if (ret < 0)
89                 return ret;
90
91         token = key->payload.data[0];
92         if (!token)
93                 return -EKEYREJECTED;
94
95         sec = rxrpc_security_lookup(token->security_index);
96         if (!sec)
97                 return -EKEYREJECTED;
98         conn->security = sec;
99
100         ret = conn->security->init_connection_security(conn);
101         if (ret < 0) {
102                 conn->security = &rxrpc_no_security;
103                 return ret;
104         }
105
106         _leave(" = 0");
107         return 0;
108 }
109
110 /*
111  * initialise the security on a server connection
112  */
113 int rxrpc_init_server_conn_security(struct rxrpc_connection *conn)
114 {
115         const struct rxrpc_security *sec;
116         struct rxrpc_local *local = conn->params.local;
117         struct rxrpc_sock *rx;
118         struct key *key;
119         key_ref_t kref;
120         char kdesc[5 + 1 + 3 + 1];
121
122         _enter("");
123
124         sprintf(kdesc, "%u:%u", conn->service_id, conn->security_ix);
125
126         sec = rxrpc_security_lookup(conn->security_ix);
127         if (!sec) {
128                 _leave(" = -ENOKEY [lookup]");
129                 return -ENOKEY;
130         }
131
132         /* find the service */
133         read_lock(&local->services_lock);
134         rx = rcu_dereference_protected(local->service,
135                                        lockdep_is_held(&local->services_lock));
136         if (rx && (rx->srx.srx_service == conn->service_id ||
137                    rx->second_service == conn->service_id))
138                 goto found_service;
139
140         /* the service appears to have died */
141         read_unlock(&local->services_lock);
142         _leave(" = -ENOENT");
143         return -ENOENT;
144
145 found_service:
146         if (!rx->securities) {
147                 read_unlock(&local->services_lock);
148                 _leave(" = -ENOKEY");
149                 return -ENOKEY;
150         }
151
152         /* look through the service's keyring */
153         kref = keyring_search(make_key_ref(rx->securities, 1UL),
154                               &key_type_rxrpc_s, kdesc);
155         if (IS_ERR(kref)) {
156                 read_unlock(&local->services_lock);
157                 _leave(" = %ld [search]", PTR_ERR(kref));
158                 return PTR_ERR(kref);
159         }
160
161         key = key_ref_to_ptr(kref);
162         read_unlock(&local->services_lock);
163
164         conn->server_key = key;
165         conn->security = sec;
166
167         _leave(" = 0");
168         return 0;
169 }