3a9d44eee941a4396c8063db36df467c509021a3
[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         if (result) {
264                 pr_err("auth protocol '%s' mauth authentication failed: %d\n",
265                        ceph_auth_proto_name(ac->protocol), result);
266                 ret = result;
267                 goto out;
268         }
269
270         ret = ac->ops->handle_reply(ac, payload, payload_end,
271                                     NULL, NULL, NULL, NULL);
272         if (ret == -EAGAIN) {
273                 ret = build_request(ac, true, reply_buf, reply_len);
274                 goto out;
275         } else if (ret) {
276                 goto out;
277         }
278
279         set_global_id(ac, global_id);
280
281 out:
282         mutex_unlock(&ac->mutex);
283         return ret;
284
285 bad:
286         pr_err("failed to decode auth msg\n");
287         ret = -EINVAL;
288         goto out;
289 }
290
291 int ceph_build_auth(struct ceph_auth_client *ac,
292                     void *msg_buf, size_t msg_len)
293 {
294         int ret = 0;
295
296         mutex_lock(&ac->mutex);
297         if (ac->ops->should_authenticate(ac))
298                 ret = build_request(ac, true, msg_buf, msg_len);
299         mutex_unlock(&ac->mutex);
300         return ret;
301 }
302
303 int ceph_auth_is_authenticated(struct ceph_auth_client *ac)
304 {
305         int ret = 0;
306
307         mutex_lock(&ac->mutex);
308         if (ac->ops)
309                 ret = ac->ops->is_authenticated(ac);
310         mutex_unlock(&ac->mutex);
311         return ret;
312 }
313 EXPORT_SYMBOL(ceph_auth_is_authenticated);
314
315 int __ceph_auth_get_authorizer(struct ceph_auth_client *ac,
316                                struct ceph_auth_handshake *auth,
317                                int peer_type, bool force_new,
318                                int *proto, int *pref_mode, int *fallb_mode)
319 {
320         int ret;
321
322         mutex_lock(&ac->mutex);
323         if (force_new && auth->authorizer) {
324                 ceph_auth_destroy_authorizer(auth->authorizer);
325                 auth->authorizer = NULL;
326         }
327         if (!auth->authorizer)
328                 ret = ac->ops->create_authorizer(ac, peer_type, auth);
329         else if (ac->ops->update_authorizer)
330                 ret = ac->ops->update_authorizer(ac, peer_type, auth);
331         else
332                 ret = 0;
333         if (ret)
334                 goto out;
335
336         *proto = ac->protocol;
337         if (pref_mode && fallb_mode) {
338                 *pref_mode = ac->preferred_mode;
339                 *fallb_mode = ac->fallback_mode;
340         }
341
342 out:
343         mutex_unlock(&ac->mutex);
344         return ret;
345 }
346 EXPORT_SYMBOL(__ceph_auth_get_authorizer);
347
348 void ceph_auth_destroy_authorizer(struct ceph_authorizer *a)
349 {
350         a->destroy(a);
351 }
352 EXPORT_SYMBOL(ceph_auth_destroy_authorizer);
353
354 int ceph_auth_add_authorizer_challenge(struct ceph_auth_client *ac,
355                                        struct ceph_authorizer *a,
356                                        void *challenge_buf,
357                                        int challenge_buf_len)
358 {
359         int ret = 0;
360
361         mutex_lock(&ac->mutex);
362         if (ac->ops && ac->ops->add_authorizer_challenge)
363                 ret = ac->ops->add_authorizer_challenge(ac, a, challenge_buf,
364                                                         challenge_buf_len);
365         mutex_unlock(&ac->mutex);
366         return ret;
367 }
368 EXPORT_SYMBOL(ceph_auth_add_authorizer_challenge);
369
370 int ceph_auth_verify_authorizer_reply(struct ceph_auth_client *ac,
371                                       struct ceph_authorizer *a,
372                                       void *reply, int reply_len,
373                                       u8 *session_key, int *session_key_len,
374                                       u8 *con_secret, int *con_secret_len)
375 {
376         int ret = 0;
377
378         mutex_lock(&ac->mutex);
379         if (ac->ops && ac->ops->verify_authorizer_reply)
380                 ret = ac->ops->verify_authorizer_reply(ac, a,
381                         reply, reply_len, session_key, session_key_len,
382                         con_secret, con_secret_len);
383         mutex_unlock(&ac->mutex);
384         return ret;
385 }
386 EXPORT_SYMBOL(ceph_auth_verify_authorizer_reply);
387
388 void ceph_auth_invalidate_authorizer(struct ceph_auth_client *ac, int peer_type)
389 {
390         mutex_lock(&ac->mutex);
391         if (ac->ops && ac->ops->invalidate_authorizer)
392                 ac->ops->invalidate_authorizer(ac, peer_type);
393         mutex_unlock(&ac->mutex);
394 }
395 EXPORT_SYMBOL(ceph_auth_invalidate_authorizer);
396
397 /*
398  * msgr2 authentication
399  */
400
401 static bool contains(const int *arr, int cnt, int val)
402 {
403         int i;
404
405         for (i = 0; i < cnt; i++) {
406                 if (arr[i] == val)
407                         return true;
408         }
409
410         return false;
411 }
412
413 static int encode_con_modes(void **p, void *end, int pref_mode, int fallb_mode)
414 {
415         WARN_ON(pref_mode == CEPH_CON_MODE_UNKNOWN);
416         if (fallb_mode != CEPH_CON_MODE_UNKNOWN) {
417                 ceph_encode_32_safe(p, end, 2, e_range);
418                 ceph_encode_32_safe(p, end, pref_mode, e_range);
419                 ceph_encode_32_safe(p, end, fallb_mode, e_range);
420         } else {
421                 ceph_encode_32_safe(p, end, 1, e_range);
422                 ceph_encode_32_safe(p, end, pref_mode, e_range);
423         }
424
425         return 0;
426
427 e_range:
428         return -ERANGE;
429 }
430
431 /*
432  * Similar to ceph_auth_build_hello().
433  */
434 int ceph_auth_get_request(struct ceph_auth_client *ac, void *buf, int buf_len)
435 {
436         int proto = ac->key ? CEPH_AUTH_CEPHX : CEPH_AUTH_NONE;
437         void *end = buf + buf_len;
438         void *lenp;
439         void *p;
440         int ret;
441
442         mutex_lock(&ac->mutex);
443         if (ac->protocol == CEPH_AUTH_UNKNOWN) {
444                 ret = init_protocol(ac, proto);
445                 if (ret) {
446                         pr_err("auth protocol '%s' init failed: %d\n",
447                                ceph_auth_proto_name(proto), ret);
448                         goto out;
449                 }
450         } else {
451                 WARN_ON(ac->protocol != proto);
452                 ac->ops->reset(ac);
453         }
454
455         p = buf;
456         ceph_encode_32_safe(&p, end, ac->protocol, e_range);
457         ret = encode_con_modes(&p, end, ac->preferred_mode, ac->fallback_mode);
458         if (ret)
459                 goto out;
460
461         lenp = p;
462         p += 4;  /* space for len */
463
464         ceph_encode_8_safe(&p, end, CEPH_AUTH_MODE_MON, e_range);
465         ret = ceph_auth_entity_name_encode(ac->name, &p, end);
466         if (ret)
467                 goto out;
468
469         ceph_encode_64_safe(&p, end, ac->global_id, e_range);
470         ceph_encode_32(&lenp, p - lenp - 4);
471         ret = p - buf;
472
473 out:
474         mutex_unlock(&ac->mutex);
475         return ret;
476
477 e_range:
478         ret = -ERANGE;
479         goto out;
480 }
481
482 int ceph_auth_handle_reply_more(struct ceph_auth_client *ac, void *reply,
483                                 int reply_len, void *buf, int buf_len)
484 {
485         int ret;
486
487         mutex_lock(&ac->mutex);
488         ret = ac->ops->handle_reply(ac, reply, reply + reply_len,
489                                     NULL, NULL, NULL, NULL);
490         if (ret == -EAGAIN)
491                 ret = build_request(ac, false, buf, buf_len);
492         else
493                 WARN_ON(ret >= 0);
494         mutex_unlock(&ac->mutex);
495         return ret;
496 }
497
498 int ceph_auth_handle_reply_done(struct ceph_auth_client *ac,
499                                 u64 global_id, void *reply, int reply_len,
500                                 u8 *session_key, int *session_key_len,
501                                 u8 *con_secret, int *con_secret_len)
502 {
503         int ret;
504
505         mutex_lock(&ac->mutex);
506         ret = ac->ops->handle_reply(ac, reply, reply + reply_len,
507                                     session_key, session_key_len,
508                                     con_secret, con_secret_len);
509         if (!ret)
510                 set_global_id(ac, global_id);
511         mutex_unlock(&ac->mutex);
512         return ret;
513 }
514
515 bool ceph_auth_handle_bad_method(struct ceph_auth_client *ac,
516                                  int used_proto, int result,
517                                  const int *allowed_protos, int proto_cnt,
518                                  const int *allowed_modes, int mode_cnt)
519 {
520         mutex_lock(&ac->mutex);
521         WARN_ON(used_proto != ac->protocol);
522
523         if (result == -EOPNOTSUPP) {
524                 if (!contains(allowed_protos, proto_cnt, ac->protocol)) {
525                         pr_err("auth protocol '%s' not allowed\n",
526                                ceph_auth_proto_name(ac->protocol));
527                         goto not_allowed;
528                 }
529                 if (!contains(allowed_modes, mode_cnt, ac->preferred_mode) &&
530                     (ac->fallback_mode == CEPH_CON_MODE_UNKNOWN ||
531                      !contains(allowed_modes, mode_cnt, ac->fallback_mode))) {
532                         pr_err("preferred mode '%s' not allowed\n",
533                                ceph_con_mode_name(ac->preferred_mode));
534                         if (ac->fallback_mode == CEPH_CON_MODE_UNKNOWN)
535                                 pr_err("no fallback mode\n");
536                         else
537                                 pr_err("fallback mode '%s' not allowed\n",
538                                        ceph_con_mode_name(ac->fallback_mode));
539                         goto not_allowed;
540                 }
541         }
542
543         WARN_ON(result == -EOPNOTSUPP || result >= 0);
544         pr_err("auth protocol '%s' msgr authentication failed: %d\n",
545                ceph_auth_proto_name(ac->protocol), result);
546
547         mutex_unlock(&ac->mutex);
548         return true;
549
550 not_allowed:
551         mutex_unlock(&ac->mutex);
552         return false;
553 }
554
555 int ceph_auth_get_authorizer(struct ceph_auth_client *ac,
556                              struct ceph_auth_handshake *auth,
557                              int peer_type, void *buf, int *buf_len)
558 {
559         void *end = buf + *buf_len;
560         int pref_mode, fallb_mode;
561         int proto;
562         void *p;
563         int ret;
564
565         ret = __ceph_auth_get_authorizer(ac, auth, peer_type, true, &proto,
566                                          &pref_mode, &fallb_mode);
567         if (ret)
568                 return ret;
569
570         p = buf;
571         ceph_encode_32_safe(&p, end, proto, e_range);
572         ret = encode_con_modes(&p, end, pref_mode, fallb_mode);
573         if (ret)
574                 return ret;
575
576         ceph_encode_32_safe(&p, end, auth->authorizer_buf_len, e_range);
577         *buf_len = p - buf;
578         return 0;
579
580 e_range:
581         return -ERANGE;
582 }
583 EXPORT_SYMBOL(ceph_auth_get_authorizer);
584
585 int ceph_auth_handle_svc_reply_more(struct ceph_auth_client *ac,
586                                     struct ceph_auth_handshake *auth,
587                                     void *reply, int reply_len,
588                                     void *buf, int *buf_len)
589 {
590         void *end = buf + *buf_len;
591         void *p;
592         int ret;
593
594         ret = ceph_auth_add_authorizer_challenge(ac, auth->authorizer,
595                                                  reply, reply_len);
596         if (ret)
597                 return ret;
598
599         p = buf;
600         ceph_encode_32_safe(&p, end, auth->authorizer_buf_len, e_range);
601         *buf_len = p - buf;
602         return 0;
603
604 e_range:
605         return -ERANGE;
606 }
607 EXPORT_SYMBOL(ceph_auth_handle_svc_reply_more);
608
609 int ceph_auth_handle_svc_reply_done(struct ceph_auth_client *ac,
610                                     struct ceph_auth_handshake *auth,
611                                     void *reply, int reply_len,
612                                     u8 *session_key, int *session_key_len,
613                                     u8 *con_secret, int *con_secret_len)
614 {
615         return ceph_auth_verify_authorizer_reply(ac, auth->authorizer,
616                 reply, reply_len, session_key, session_key_len,
617                 con_secret, con_secret_len);
618 }
619 EXPORT_SYMBOL(ceph_auth_handle_svc_reply_done);
620
621 bool ceph_auth_handle_bad_authorizer(struct ceph_auth_client *ac,
622                                      int peer_type, int used_proto, int result,
623                                      const int *allowed_protos, int proto_cnt,
624                                      const int *allowed_modes, int mode_cnt)
625 {
626         mutex_lock(&ac->mutex);
627         WARN_ON(used_proto != ac->protocol);
628
629         if (result == -EOPNOTSUPP) {
630                 if (!contains(allowed_protos, proto_cnt, ac->protocol)) {
631                         pr_err("auth protocol '%s' not allowed by %s\n",
632                                ceph_auth_proto_name(ac->protocol),
633                                ceph_entity_type_name(peer_type));
634                         goto not_allowed;
635                 }
636                 if (!contains(allowed_modes, mode_cnt, ac->preferred_mode) &&
637                     (ac->fallback_mode == CEPH_CON_MODE_UNKNOWN ||
638                      !contains(allowed_modes, mode_cnt, ac->fallback_mode))) {
639                         pr_err("preferred mode '%s' not allowed by %s\n",
640                                ceph_con_mode_name(ac->preferred_mode),
641                                ceph_entity_type_name(peer_type));
642                         if (ac->fallback_mode == CEPH_CON_MODE_UNKNOWN)
643                                 pr_err("no fallback mode\n");
644                         else
645                                 pr_err("fallback mode '%s' not allowed by %s\n",
646                                        ceph_con_mode_name(ac->fallback_mode),
647                                        ceph_entity_type_name(peer_type));
648                         goto not_allowed;
649                 }
650         }
651
652         WARN_ON(result == -EOPNOTSUPP || result >= 0);
653         pr_err("auth protocol '%s' authorization to %s failed: %d\n",
654                ceph_auth_proto_name(ac->protocol),
655                ceph_entity_type_name(peer_type), result);
656
657         if (ac->ops->invalidate_authorizer)
658                 ac->ops->invalidate_authorizer(ac, peer_type);
659
660         mutex_unlock(&ac->mutex);
661         return true;
662
663 not_allowed:
664         mutex_unlock(&ac->mutex);
665         return false;
666 }
667 EXPORT_SYMBOL(ceph_auth_handle_bad_authorizer);