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