Merge branch 'asoc-4.19' into asoc-4.20 for rcar dep
[linux-2.6-microblaze.git] / net / ceph / auth.c
1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/ceph/ceph_debug.h>
3
4 #include <linux/module.h>
5 #include <linux/err.h>
6 #include <linux/slab.h>
7
8 #include <linux/ceph/types.h>
9 #include <linux/ceph/decode.h>
10 #include <linux/ceph/libceph.h>
11 #include <linux/ceph/messenger.h>
12 #include "auth_none.h"
13 #include "auth_x.h"
14
15
16 /*
17  * get protocol handler
18  */
19 static u32 supported_protocols[] = {
20         CEPH_AUTH_NONE,
21         CEPH_AUTH_CEPHX
22 };
23
24 static int ceph_auth_init_protocol(struct ceph_auth_client *ac, int protocol)
25 {
26         switch (protocol) {
27         case CEPH_AUTH_NONE:
28                 return ceph_auth_none_init(ac);
29         case CEPH_AUTH_CEPHX:
30                 return ceph_x_init(ac);
31         default:
32                 return -ENOENT;
33         }
34 }
35
36 /*
37  * setup, teardown.
38  */
39 struct ceph_auth_client *ceph_auth_init(const char *name, const struct ceph_crypto_key *key)
40 {
41         struct ceph_auth_client *ac;
42         int ret;
43
44         dout("auth_init name '%s'\n", name);
45
46         ret = -ENOMEM;
47         ac = kzalloc(sizeof(*ac), GFP_NOFS);
48         if (!ac)
49                 goto out;
50
51         mutex_init(&ac->mutex);
52         ac->negotiating = true;
53         if (name)
54                 ac->name = name;
55         else
56                 ac->name = CEPH_AUTH_NAME_DEFAULT;
57         dout("auth_init name %s\n", ac->name);
58         ac->key = key;
59         return ac;
60
61 out:
62         return ERR_PTR(ret);
63 }
64
65 void ceph_auth_destroy(struct ceph_auth_client *ac)
66 {
67         dout("auth_destroy %p\n", ac);
68         if (ac->ops)
69                 ac->ops->destroy(ac);
70         kfree(ac);
71 }
72
73 /*
74  * Reset occurs when reconnecting to the monitor.
75  */
76 void ceph_auth_reset(struct ceph_auth_client *ac)
77 {
78         mutex_lock(&ac->mutex);
79         dout("auth_reset %p\n", ac);
80         if (ac->ops && !ac->negotiating)
81                 ac->ops->reset(ac);
82         ac->negotiating = true;
83         mutex_unlock(&ac->mutex);
84 }
85
86 /*
87  * EntityName, not to be confused with entity_name_t
88  */
89 int ceph_auth_entity_name_encode(const char *name, void **p, void *end)
90 {
91         int len = strlen(name);
92
93         if (*p + 2*sizeof(u32) + len > end)
94                 return -ERANGE;
95         ceph_encode_32(p, CEPH_ENTITY_TYPE_CLIENT);
96         ceph_encode_32(p, len);
97         ceph_encode_copy(p, name, len);
98         return 0;
99 }
100
101 /*
102  * Initiate protocol negotiation with monitor.  Include entity name
103  * and list supported protocols.
104  */
105 int ceph_auth_build_hello(struct ceph_auth_client *ac, void *buf, size_t len)
106 {
107         struct ceph_mon_request_header *monhdr = buf;
108         void *p = monhdr + 1, *end = buf + len, *lenp;
109         int i, num;
110         int ret;
111
112         mutex_lock(&ac->mutex);
113         dout("auth_build_hello\n");
114         monhdr->have_version = 0;
115         monhdr->session_mon = cpu_to_le16(-1);
116         monhdr->session_mon_tid = 0;
117
118         ceph_encode_32(&p, CEPH_AUTH_UNKNOWN);  /* no protocol, yet */
119
120         lenp = p;
121         p += sizeof(u32);
122
123         ceph_decode_need(&p, end, 1 + sizeof(u32), bad);
124         ceph_encode_8(&p, 1);
125         num = ARRAY_SIZE(supported_protocols);
126         ceph_encode_32(&p, num);
127         ceph_decode_need(&p, end, num * sizeof(u32), bad);
128         for (i = 0; i < num; i++)
129                 ceph_encode_32(&p, supported_protocols[i]);
130
131         ret = ceph_auth_entity_name_encode(ac->name, &p, end);
132         if (ret < 0)
133                 goto out;
134         ceph_decode_need(&p, end, sizeof(u64), bad);
135         ceph_encode_64(&p, ac->global_id);
136
137         ceph_encode_32(&lenp, p - lenp - sizeof(u32));
138         ret = p - buf;
139 out:
140         mutex_unlock(&ac->mutex);
141         return ret;
142
143 bad:
144         ret = -ERANGE;
145         goto out;
146 }
147
148 static int ceph_build_auth_request(struct ceph_auth_client *ac,
149                                    void *msg_buf, size_t msg_len)
150 {
151         struct ceph_mon_request_header *monhdr = msg_buf;
152         void *p = monhdr + 1;
153         void *end = msg_buf + msg_len;
154         int ret;
155
156         monhdr->have_version = 0;
157         monhdr->session_mon = cpu_to_le16(-1);
158         monhdr->session_mon_tid = 0;
159
160         ceph_encode_32(&p, ac->protocol);
161
162         ret = ac->ops->build_request(ac, p + sizeof(u32), end);
163         if (ret < 0) {
164                 pr_err("error %d building auth method %s request\n", ret,
165                        ac->ops->name);
166                 goto out;
167         }
168         dout(" built request %d bytes\n", ret);
169         ceph_encode_32(&p, ret);
170         ret = p + ret - msg_buf;
171 out:
172         return ret;
173 }
174
175 /*
176  * Handle auth message from monitor.
177  */
178 int ceph_handle_auth_reply(struct ceph_auth_client *ac,
179                            void *buf, size_t len,
180                            void *reply_buf, size_t reply_len)
181 {
182         void *p = buf;
183         void *end = buf + len;
184         int protocol;
185         s32 result;
186         u64 global_id;
187         void *payload, *payload_end;
188         int payload_len;
189         char *result_msg;
190         int result_msg_len;
191         int ret = -EINVAL;
192
193         mutex_lock(&ac->mutex);
194         dout("handle_auth_reply %p %p\n", p, end);
195         ceph_decode_need(&p, end, sizeof(u32) * 3 + sizeof(u64), bad);
196         protocol = ceph_decode_32(&p);
197         result = ceph_decode_32(&p);
198         global_id = ceph_decode_64(&p);
199         payload_len = ceph_decode_32(&p);
200         payload = p;
201         p += payload_len;
202         ceph_decode_need(&p, end, sizeof(u32), bad);
203         result_msg_len = ceph_decode_32(&p);
204         result_msg = p;
205         p += result_msg_len;
206         if (p != end)
207                 goto bad;
208
209         dout(" result %d '%.*s' gid %llu len %d\n", result, result_msg_len,
210              result_msg, global_id, payload_len);
211
212         payload_end = payload + payload_len;
213
214         if (global_id && ac->global_id != global_id) {
215                 dout(" set global_id %lld -> %lld\n", ac->global_id, global_id);
216                 ac->global_id = global_id;
217         }
218
219         if (ac->negotiating) {
220                 /* server does not support our protocols? */
221                 if (!protocol && result < 0) {
222                         ret = result;
223                         goto out;
224                 }
225                 /* set up (new) protocol handler? */
226                 if (ac->protocol && ac->protocol != protocol) {
227                         ac->ops->destroy(ac);
228                         ac->protocol = 0;
229                         ac->ops = NULL;
230                 }
231                 if (ac->protocol != protocol) {
232                         ret = ceph_auth_init_protocol(ac, protocol);
233                         if (ret) {
234                                 pr_err("error %d on auth protocol %d init\n",
235                                        ret, protocol);
236                                 goto out;
237                         }
238                 }
239
240                 ac->negotiating = false;
241         }
242
243         ret = ac->ops->handle_reply(ac, result, payload, payload_end);
244         if (ret == -EAGAIN) {
245                 ret = ceph_build_auth_request(ac, reply_buf, reply_len);
246         } else if (ret) {
247                 pr_err("auth method '%s' error %d\n", ac->ops->name, ret);
248         }
249
250 out:
251         mutex_unlock(&ac->mutex);
252         return ret;
253
254 bad:
255         pr_err("failed to decode auth msg\n");
256         ret = -EINVAL;
257         goto out;
258 }
259
260 int ceph_build_auth(struct ceph_auth_client *ac,
261                     void *msg_buf, size_t msg_len)
262 {
263         int ret = 0;
264
265         mutex_lock(&ac->mutex);
266         if (ac->ops->should_authenticate(ac))
267                 ret = ceph_build_auth_request(ac, msg_buf, msg_len);
268         mutex_unlock(&ac->mutex);
269         return ret;
270 }
271
272 int ceph_auth_is_authenticated(struct ceph_auth_client *ac)
273 {
274         int ret = 0;
275
276         mutex_lock(&ac->mutex);
277         if (ac->ops)
278                 ret = ac->ops->is_authenticated(ac);
279         mutex_unlock(&ac->mutex);
280         return ret;
281 }
282 EXPORT_SYMBOL(ceph_auth_is_authenticated);
283
284 int ceph_auth_create_authorizer(struct ceph_auth_client *ac,
285                                 int peer_type,
286                                 struct ceph_auth_handshake *auth)
287 {
288         int ret = 0;
289
290         mutex_lock(&ac->mutex);
291         if (ac->ops && ac->ops->create_authorizer)
292                 ret = ac->ops->create_authorizer(ac, peer_type, auth);
293         mutex_unlock(&ac->mutex);
294         return ret;
295 }
296 EXPORT_SYMBOL(ceph_auth_create_authorizer);
297
298 void ceph_auth_destroy_authorizer(struct ceph_authorizer *a)
299 {
300         a->destroy(a);
301 }
302 EXPORT_SYMBOL(ceph_auth_destroy_authorizer);
303
304 int ceph_auth_update_authorizer(struct ceph_auth_client *ac,
305                                 int peer_type,
306                                 struct ceph_auth_handshake *a)
307 {
308         int ret = 0;
309
310         mutex_lock(&ac->mutex);
311         if (ac->ops && ac->ops->update_authorizer)
312                 ret = ac->ops->update_authorizer(ac, peer_type, a);
313         mutex_unlock(&ac->mutex);
314         return ret;
315 }
316 EXPORT_SYMBOL(ceph_auth_update_authorizer);
317
318 int ceph_auth_add_authorizer_challenge(struct ceph_auth_client *ac,
319                                        struct ceph_authorizer *a,
320                                        void *challenge_buf,
321                                        int challenge_buf_len)
322 {
323         int ret = 0;
324
325         mutex_lock(&ac->mutex);
326         if (ac->ops && ac->ops->add_authorizer_challenge)
327                 ret = ac->ops->add_authorizer_challenge(ac, a, challenge_buf,
328                                                         challenge_buf_len);
329         mutex_unlock(&ac->mutex);
330         return ret;
331 }
332 EXPORT_SYMBOL(ceph_auth_add_authorizer_challenge);
333
334 int ceph_auth_verify_authorizer_reply(struct ceph_auth_client *ac,
335                                       struct ceph_authorizer *a)
336 {
337         int ret = 0;
338
339         mutex_lock(&ac->mutex);
340         if (ac->ops && ac->ops->verify_authorizer_reply)
341                 ret = ac->ops->verify_authorizer_reply(ac, a);
342         mutex_unlock(&ac->mutex);
343         return ret;
344 }
345 EXPORT_SYMBOL(ceph_auth_verify_authorizer_reply);
346
347 void ceph_auth_invalidate_authorizer(struct ceph_auth_client *ac, int peer_type)
348 {
349         mutex_lock(&ac->mutex);
350         if (ac->ops && ac->ops->invalidate_authorizer)
351                 ac->ops->invalidate_authorizer(ac, peer_type);
352         mutex_unlock(&ac->mutex);
353 }
354 EXPORT_SYMBOL(ceph_auth_invalidate_authorizer);