xen/events: reset active flag for lateeoi events later
[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 init_protocol(struct ceph_auth_client *ac, int proto)
25 {
26         dout("%s proto %d\n", __func__, proto);
27
28         switch (proto) {
29         case CEPH_AUTH_NONE:
30                 return ceph_auth_none_init(ac);
31         case CEPH_AUTH_CEPHX:
32                 return ceph_x_init(ac);
33         default:
34                 pr_err("bad auth protocol %d\n", proto);
35                 return -EINVAL;
36         }
37 }
38
39 static void set_global_id(struct ceph_auth_client *ac, u64 global_id)
40 {
41         dout("%s global_id %llu\n", __func__, global_id);
42
43         if (!global_id)
44                 pr_err("got zero global_id\n");
45
46         if (ac->global_id && global_id != ac->global_id)
47                 pr_err("global_id changed from %llu to %llu\n", ac->global_id,
48                        global_id);
49
50         ac->global_id = global_id;
51 }
52
53 /*
54  * setup, teardown.
55  */
56 struct ceph_auth_client *ceph_auth_init(const char *name,
57                                         const struct ceph_crypto_key *key,
58                                         const int *con_modes)
59 {
60         struct ceph_auth_client *ac;
61         int ret;
62
63         ret = -ENOMEM;
64         ac = kzalloc(sizeof(*ac), GFP_NOFS);
65         if (!ac)
66                 goto out;
67
68         mutex_init(&ac->mutex);
69         ac->negotiating = true;
70         if (name)
71                 ac->name = name;
72         else
73                 ac->name = CEPH_AUTH_NAME_DEFAULT;
74         ac->key = key;
75         ac->preferred_mode = con_modes[0];
76         ac->fallback_mode = con_modes[1];
77
78         dout("%s name '%s' preferred_mode %d fallback_mode %d\n", __func__,
79              ac->name, ac->preferred_mode, ac->fallback_mode);
80         return ac;
81
82 out:
83         return ERR_PTR(ret);
84 }
85
86 void ceph_auth_destroy(struct ceph_auth_client *ac)
87 {
88         dout("auth_destroy %p\n", ac);
89         if (ac->ops)
90                 ac->ops->destroy(ac);
91         kfree(ac);
92 }
93
94 /*
95  * Reset occurs when reconnecting to the monitor.
96  */
97 void ceph_auth_reset(struct ceph_auth_client *ac)
98 {
99         mutex_lock(&ac->mutex);
100         dout("auth_reset %p\n", ac);
101         if (ac->ops && !ac->negotiating)
102                 ac->ops->reset(ac);
103         ac->negotiating = true;
104         mutex_unlock(&ac->mutex);
105 }
106
107 /*
108  * EntityName, not to be confused with entity_name_t
109  */
110 int ceph_auth_entity_name_encode(const char *name, void **p, void *end)
111 {
112         int len = strlen(name);
113
114         if (*p + 2*sizeof(u32) + len > end)
115                 return -ERANGE;
116         ceph_encode_32(p, CEPH_ENTITY_TYPE_CLIENT);
117         ceph_encode_32(p, len);
118         ceph_encode_copy(p, name, len);
119         return 0;
120 }
121
122 /*
123  * Initiate protocol negotiation with monitor.  Include entity name
124  * and list supported protocols.
125  */
126 int ceph_auth_build_hello(struct ceph_auth_client *ac, void *buf, size_t len)
127 {
128         struct ceph_mon_request_header *monhdr = buf;
129         void *p = monhdr + 1, *end = buf + len, *lenp;
130         int i, num;
131         int ret;
132
133         mutex_lock(&ac->mutex);
134         dout("auth_build_hello\n");
135         monhdr->have_version = 0;
136         monhdr->session_mon = cpu_to_le16(-1);
137         monhdr->session_mon_tid = 0;
138
139         ceph_encode_32(&p, CEPH_AUTH_UNKNOWN);  /* no protocol, yet */
140
141         lenp = p;
142         p += sizeof(u32);
143
144         ceph_decode_need(&p, end, 1 + sizeof(u32), bad);
145         ceph_encode_8(&p, 1);
146         num = ARRAY_SIZE(supported_protocols);
147         ceph_encode_32(&p, num);
148         ceph_decode_need(&p, end, num * sizeof(u32), bad);
149         for (i = 0; i < num; i++)
150                 ceph_encode_32(&p, supported_protocols[i]);
151
152         ret = ceph_auth_entity_name_encode(ac->name, &p, end);
153         if (ret < 0)
154                 goto out;
155         ceph_decode_need(&p, end, sizeof(u64), bad);
156         ceph_encode_64(&p, ac->global_id);
157
158         ceph_encode_32(&lenp, p - lenp - sizeof(u32));
159         ret = p - buf;
160 out:
161         mutex_unlock(&ac->mutex);
162         return ret;
163
164 bad:
165         ret = -ERANGE;
166         goto out;
167 }
168
169 static int build_request(struct ceph_auth_client *ac, bool add_header,
170                          void *buf, int buf_len)
171 {
172         void *end = buf + buf_len;
173         void *p;
174         int ret;
175
176         p = buf;
177         if (add_header) {
178                 /* struct ceph_mon_request_header + protocol */
179                 ceph_encode_64_safe(&p, end, 0, e_range);
180                 ceph_encode_16_safe(&p, end, -1, e_range);
181                 ceph_encode_64_safe(&p, end, 0, e_range);
182                 ceph_encode_32_safe(&p, end, ac->protocol, e_range);
183         }
184
185         ceph_encode_need(&p, end, sizeof(u32), e_range);
186         ret = ac->ops->build_request(ac, p + sizeof(u32), end);
187         if (ret < 0) {
188                 pr_err("auth protocol '%s' building request failed: %d\n",
189                        ceph_auth_proto_name(ac->protocol), ret);
190                 return ret;
191         }
192         dout(" built request %d bytes\n", ret);
193         ceph_encode_32(&p, ret);
194         return p + ret - buf;
195
196 e_range:
197         return -ERANGE;
198 }
199
200 /*
201  * Handle auth message from monitor.
202  */
203 int ceph_handle_auth_reply(struct ceph_auth_client *ac,
204                            void *buf, size_t len,
205                            void *reply_buf, size_t reply_len)
206 {
207         void *p = buf;
208         void *end = buf + len;
209         int protocol;
210         s32 result;
211         u64 global_id;
212         void *payload, *payload_end;
213         int payload_len;
214         char *result_msg;
215         int result_msg_len;
216         int ret = -EINVAL;
217
218         mutex_lock(&ac->mutex);
219         dout("handle_auth_reply %p %p\n", p, end);
220         ceph_decode_need(&p, end, sizeof(u32) * 3 + sizeof(u64), bad);
221         protocol = ceph_decode_32(&p);
222         result = ceph_decode_32(&p);
223         global_id = ceph_decode_64(&p);
224         payload_len = ceph_decode_32(&p);
225         payload = p;
226         p += payload_len;
227         ceph_decode_need(&p, end, sizeof(u32), bad);
228         result_msg_len = ceph_decode_32(&p);
229         result_msg = p;
230         p += result_msg_len;
231         if (p != end)
232                 goto bad;
233
234         dout(" result %d '%.*s' gid %llu len %d\n", result, result_msg_len,
235              result_msg, global_id, payload_len);
236
237         payload_end = payload + payload_len;
238
239         if (ac->negotiating) {
240                 /* server does not support our protocols? */
241                 if (!protocol && result < 0) {
242                         ret = result;
243                         goto out;
244                 }
245                 /* set up (new) protocol handler? */
246                 if (ac->protocol && ac->protocol != protocol) {
247                         ac->ops->destroy(ac);
248                         ac->protocol = 0;
249                         ac->ops = NULL;
250                 }
251                 if (ac->protocol != protocol) {
252                         ret = init_protocol(ac, protocol);
253                         if (ret) {
254                                 pr_err("auth protocol '%s' init failed: %d\n",
255                                        ceph_auth_proto_name(protocol), ret);
256                                 goto out;
257                         }
258                 }
259
260                 ac->negotiating = false;
261         }
262
263         ret = ac->ops->handle_reply(ac, result, payload, payload_end,
264                                     NULL, NULL, NULL, NULL);
265         if (ret == -EAGAIN) {
266                 ret = build_request(ac, true, reply_buf, reply_len);
267                 goto out;
268         } else if (ret) {
269                 pr_err("auth protocol '%s' mauth authentication failed: %d\n",
270                        ceph_auth_proto_name(ac->protocol), result);
271                 goto out;
272         }
273
274         set_global_id(ac, global_id);
275
276 out:
277         mutex_unlock(&ac->mutex);
278         return ret;
279
280 bad:
281         pr_err("failed to decode auth msg\n");
282         ret = -EINVAL;
283         goto out;
284 }
285
286 int ceph_build_auth(struct ceph_auth_client *ac,
287                     void *msg_buf, size_t msg_len)
288 {
289         int ret = 0;
290
291         mutex_lock(&ac->mutex);
292         if (ac->ops->should_authenticate(ac))
293                 ret = build_request(ac, true, msg_buf, msg_len);
294         mutex_unlock(&ac->mutex);
295         return ret;
296 }
297
298 int ceph_auth_is_authenticated(struct ceph_auth_client *ac)
299 {
300         int ret = 0;
301
302         mutex_lock(&ac->mutex);
303         if (ac->ops)
304                 ret = ac->ops->is_authenticated(ac);
305         mutex_unlock(&ac->mutex);
306         return ret;
307 }
308 EXPORT_SYMBOL(ceph_auth_is_authenticated);
309
310 int __ceph_auth_get_authorizer(struct ceph_auth_client *ac,
311                                struct ceph_auth_handshake *auth,
312                                int peer_type, bool force_new,
313                                int *proto, int *pref_mode, int *fallb_mode)
314 {
315         int ret;
316
317         mutex_lock(&ac->mutex);
318         if (force_new && auth->authorizer) {
319                 ceph_auth_destroy_authorizer(auth->authorizer);
320                 auth->authorizer = NULL;
321         }
322         if (!auth->authorizer)
323                 ret = ac->ops->create_authorizer(ac, peer_type, auth);
324         else if (ac->ops->update_authorizer)
325                 ret = ac->ops->update_authorizer(ac, peer_type, auth);
326         else
327                 ret = 0;
328         if (ret)
329                 goto out;
330
331         *proto = ac->protocol;
332         if (pref_mode && fallb_mode) {
333                 *pref_mode = ac->preferred_mode;
334                 *fallb_mode = ac->fallback_mode;
335         }
336
337 out:
338         mutex_unlock(&ac->mutex);
339         return ret;
340 }
341 EXPORT_SYMBOL(__ceph_auth_get_authorizer);
342
343 void ceph_auth_destroy_authorizer(struct ceph_authorizer *a)
344 {
345         a->destroy(a);
346 }
347 EXPORT_SYMBOL(ceph_auth_destroy_authorizer);
348
349 int ceph_auth_add_authorizer_challenge(struct ceph_auth_client *ac,
350                                        struct ceph_authorizer *a,
351                                        void *challenge_buf,
352                                        int challenge_buf_len)
353 {
354         int ret = 0;
355
356         mutex_lock(&ac->mutex);
357         if (ac->ops && ac->ops->add_authorizer_challenge)
358                 ret = ac->ops->add_authorizer_challenge(ac, a, challenge_buf,
359                                                         challenge_buf_len);
360         mutex_unlock(&ac->mutex);
361         return ret;
362 }
363 EXPORT_SYMBOL(ceph_auth_add_authorizer_challenge);
364
365 int ceph_auth_verify_authorizer_reply(struct ceph_auth_client *ac,
366                                       struct ceph_authorizer *a,
367                                       void *reply, int reply_len,
368                                       u8 *session_key, int *session_key_len,
369                                       u8 *con_secret, int *con_secret_len)
370 {
371         int ret = 0;
372
373         mutex_lock(&ac->mutex);
374         if (ac->ops && ac->ops->verify_authorizer_reply)
375                 ret = ac->ops->verify_authorizer_reply(ac, a,
376                         reply, reply_len, session_key, session_key_len,
377                         con_secret, con_secret_len);
378         mutex_unlock(&ac->mutex);
379         return ret;
380 }
381 EXPORT_SYMBOL(ceph_auth_verify_authorizer_reply);
382
383 void ceph_auth_invalidate_authorizer(struct ceph_auth_client *ac, int peer_type)
384 {
385         mutex_lock(&ac->mutex);
386         if (ac->ops && ac->ops->invalidate_authorizer)
387                 ac->ops->invalidate_authorizer(ac, peer_type);
388         mutex_unlock(&ac->mutex);
389 }
390 EXPORT_SYMBOL(ceph_auth_invalidate_authorizer);
391
392 /*
393  * msgr2 authentication
394  */
395
396 static bool contains(const int *arr, int cnt, int val)
397 {
398         int i;
399
400         for (i = 0; i < cnt; i++) {
401                 if (arr[i] == val)
402                         return true;
403         }
404
405         return false;
406 }
407
408 static int encode_con_modes(void **p, void *end, int pref_mode, int fallb_mode)
409 {
410         WARN_ON(pref_mode == CEPH_CON_MODE_UNKNOWN);
411         if (fallb_mode != CEPH_CON_MODE_UNKNOWN) {
412                 ceph_encode_32_safe(p, end, 2, e_range);
413                 ceph_encode_32_safe(p, end, pref_mode, e_range);
414                 ceph_encode_32_safe(p, end, fallb_mode, e_range);
415         } else {
416                 ceph_encode_32_safe(p, end, 1, e_range);
417                 ceph_encode_32_safe(p, end, pref_mode, e_range);
418         }
419
420         return 0;
421
422 e_range:
423         return -ERANGE;
424 }
425
426 /*
427  * Similar to ceph_auth_build_hello().
428  */
429 int ceph_auth_get_request(struct ceph_auth_client *ac, void *buf, int buf_len)
430 {
431         int proto = ac->key ? CEPH_AUTH_CEPHX : CEPH_AUTH_NONE;
432         void *end = buf + buf_len;
433         void *lenp;
434         void *p;
435         int ret;
436
437         mutex_lock(&ac->mutex);
438         if (ac->protocol == CEPH_AUTH_UNKNOWN) {
439                 ret = init_protocol(ac, proto);
440                 if (ret) {
441                         pr_err("auth protocol '%s' init failed: %d\n",
442                                ceph_auth_proto_name(proto), ret);
443                         goto out;
444                 }
445         } else {
446                 WARN_ON(ac->protocol != proto);
447                 ac->ops->reset(ac);
448         }
449
450         p = buf;
451         ceph_encode_32_safe(&p, end, ac->protocol, e_range);
452         ret = encode_con_modes(&p, end, ac->preferred_mode, ac->fallback_mode);
453         if (ret)
454                 goto out;
455
456         lenp = p;
457         p += 4;  /* space for len */
458
459         ceph_encode_8_safe(&p, end, CEPH_AUTH_MODE_MON, e_range);
460         ret = ceph_auth_entity_name_encode(ac->name, &p, end);
461         if (ret)
462                 goto out;
463
464         ceph_encode_64_safe(&p, end, ac->global_id, e_range);
465         ceph_encode_32(&lenp, p - lenp - 4);
466         ret = p - buf;
467
468 out:
469         mutex_unlock(&ac->mutex);
470         return ret;
471
472 e_range:
473         ret = -ERANGE;
474         goto out;
475 }
476
477 int ceph_auth_handle_reply_more(struct ceph_auth_client *ac, void *reply,
478                                 int reply_len, void *buf, int buf_len)
479 {
480         int ret;
481
482         mutex_lock(&ac->mutex);
483         ret = ac->ops->handle_reply(ac, 0, reply, reply + reply_len,
484                                     NULL, NULL, NULL, NULL);
485         if (ret == -EAGAIN)
486                 ret = build_request(ac, false, buf, buf_len);
487         else
488                 WARN_ON(ret >= 0);
489         mutex_unlock(&ac->mutex);
490         return ret;
491 }
492
493 int ceph_auth_handle_reply_done(struct ceph_auth_client *ac,
494                                 u64 global_id, void *reply, int reply_len,
495                                 u8 *session_key, int *session_key_len,
496                                 u8 *con_secret, int *con_secret_len)
497 {
498         int ret;
499
500         mutex_lock(&ac->mutex);
501         ret = ac->ops->handle_reply(ac, 0, reply, reply + reply_len,
502                                     session_key, session_key_len,
503                                     con_secret, con_secret_len);
504         if (!ret)
505                 set_global_id(ac, global_id);
506         mutex_unlock(&ac->mutex);
507         return ret;
508 }
509
510 bool ceph_auth_handle_bad_method(struct ceph_auth_client *ac,
511                                  int used_proto, int result,
512                                  const int *allowed_protos, int proto_cnt,
513                                  const int *allowed_modes, int mode_cnt)
514 {
515         mutex_lock(&ac->mutex);
516         WARN_ON(used_proto != ac->protocol);
517
518         if (result == -EOPNOTSUPP) {
519                 if (!contains(allowed_protos, proto_cnt, ac->protocol)) {
520                         pr_err("auth protocol '%s' not allowed\n",
521                                ceph_auth_proto_name(ac->protocol));
522                         goto not_allowed;
523                 }
524                 if (!contains(allowed_modes, mode_cnt, ac->preferred_mode) &&
525                     (ac->fallback_mode == CEPH_CON_MODE_UNKNOWN ||
526                      !contains(allowed_modes, mode_cnt, ac->fallback_mode))) {
527                         pr_err("preferred mode '%s' not allowed\n",
528                                ceph_con_mode_name(ac->preferred_mode));
529                         if (ac->fallback_mode == CEPH_CON_MODE_UNKNOWN)
530                                 pr_err("no fallback mode\n");
531                         else
532                                 pr_err("fallback mode '%s' not allowed\n",
533                                        ceph_con_mode_name(ac->fallback_mode));
534                         goto not_allowed;
535                 }
536         }
537
538         WARN_ON(result == -EOPNOTSUPP || result >= 0);
539         pr_err("auth protocol '%s' msgr authentication failed: %d\n",
540                ceph_auth_proto_name(ac->protocol), result);
541
542         mutex_unlock(&ac->mutex);
543         return true;
544
545 not_allowed:
546         mutex_unlock(&ac->mutex);
547         return false;
548 }
549
550 int ceph_auth_get_authorizer(struct ceph_auth_client *ac,
551                              struct ceph_auth_handshake *auth,
552                              int peer_type, void *buf, int *buf_len)
553 {
554         void *end = buf + *buf_len;
555         int pref_mode, fallb_mode;
556         int proto;
557         void *p;
558         int ret;
559
560         ret = __ceph_auth_get_authorizer(ac, auth, peer_type, true, &proto,
561                                          &pref_mode, &fallb_mode);
562         if (ret)
563                 return ret;
564
565         p = buf;
566         ceph_encode_32_safe(&p, end, proto, e_range);
567         ret = encode_con_modes(&p, end, pref_mode, fallb_mode);
568         if (ret)
569                 return ret;
570
571         ceph_encode_32_safe(&p, end, auth->authorizer_buf_len, e_range);
572         *buf_len = p - buf;
573         return 0;
574
575 e_range:
576         return -ERANGE;
577 }
578 EXPORT_SYMBOL(ceph_auth_get_authorizer);
579
580 int ceph_auth_handle_svc_reply_more(struct ceph_auth_client *ac,
581                                     struct ceph_auth_handshake *auth,
582                                     void *reply, int reply_len,
583                                     void *buf, int *buf_len)
584 {
585         void *end = buf + *buf_len;
586         void *p;
587         int ret;
588
589         ret = ceph_auth_add_authorizer_challenge(ac, auth->authorizer,
590                                                  reply, reply_len);
591         if (ret)
592                 return ret;
593
594         p = buf;
595         ceph_encode_32_safe(&p, end, auth->authorizer_buf_len, e_range);
596         *buf_len = p - buf;
597         return 0;
598
599 e_range:
600         return -ERANGE;
601 }
602 EXPORT_SYMBOL(ceph_auth_handle_svc_reply_more);
603
604 int ceph_auth_handle_svc_reply_done(struct ceph_auth_client *ac,
605                                     struct ceph_auth_handshake *auth,
606                                     void *reply, int reply_len,
607                                     u8 *session_key, int *session_key_len,
608                                     u8 *con_secret, int *con_secret_len)
609 {
610         return ceph_auth_verify_authorizer_reply(ac, auth->authorizer,
611                 reply, reply_len, session_key, session_key_len,
612                 con_secret, con_secret_len);
613 }
614 EXPORT_SYMBOL(ceph_auth_handle_svc_reply_done);
615
616 bool ceph_auth_handle_bad_authorizer(struct ceph_auth_client *ac,
617                                      int peer_type, int used_proto, int result,
618                                      const int *allowed_protos, int proto_cnt,
619                                      const int *allowed_modes, int mode_cnt)
620 {
621         mutex_lock(&ac->mutex);
622         WARN_ON(used_proto != ac->protocol);
623
624         if (result == -EOPNOTSUPP) {
625                 if (!contains(allowed_protos, proto_cnt, ac->protocol)) {
626                         pr_err("auth protocol '%s' not allowed by %s\n",
627                                ceph_auth_proto_name(ac->protocol),
628                                ceph_entity_type_name(peer_type));
629                         goto not_allowed;
630                 }
631                 if (!contains(allowed_modes, mode_cnt, ac->preferred_mode) &&
632                     (ac->fallback_mode == CEPH_CON_MODE_UNKNOWN ||
633                      !contains(allowed_modes, mode_cnt, ac->fallback_mode))) {
634                         pr_err("preferred mode '%s' not allowed by %s\n",
635                                ceph_con_mode_name(ac->preferred_mode),
636                                ceph_entity_type_name(peer_type));
637                         if (ac->fallback_mode == CEPH_CON_MODE_UNKNOWN)
638                                 pr_err("no fallback mode\n");
639                         else
640                                 pr_err("fallback mode '%s' not allowed by %s\n",
641                                        ceph_con_mode_name(ac->fallback_mode),
642                                        ceph_entity_type_name(peer_type));
643                         goto not_allowed;
644                 }
645         }
646
647         WARN_ON(result == -EOPNOTSUPP || result >= 0);
648         pr_err("auth protocol '%s' authorization to %s failed: %d\n",
649                ceph_auth_proto_name(ac->protocol),
650                ceph_entity_type_name(peer_type), result);
651
652         if (ac->ops->invalidate_authorizer)
653                 ac->ops->invalidate_authorizer(ac, peer_type);
654
655         mutex_unlock(&ac->mutex);
656         return true;
657
658 not_allowed:
659         mutex_unlock(&ac->mutex);
660         return false;
661 }
662 EXPORT_SYMBOL(ceph_auth_handle_bad_authorizer);