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