File Index
Files and directories
Sign in
FILE

auth.c

File preview with syntax highlighting.

linux-6.19.14/net/ceph/auth.c 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 */
 19static u32 supported_protocols[] = {
 20	CEPH_AUTH_NONE,
 21	CEPH_AUTH_CEPHX
 22};
 23
 24static 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
 39void 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 */
 56struct 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
 81void 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 */
 92void 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 */
105int 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 */
121int 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;
155out:
156	mutex_unlock(&ac->mutex);
157	return ret;
158
159bad:
160	ret = -ERANGE;
161	goto out;
162}
163
164static 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
191e_range:
192	return -ERANGE;
193}
194
195/*
196 * Handle auth message from monitor.
197 */
198int 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	u32 payload_len;
209	char *result_msg;
210	u32 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	ceph_decode_need(&p, end, payload_len, bad);
221	payload = p;
222	p += payload_len;
223	ceph_decode_need(&p, end, sizeof(u32), bad);
224	result_msg_len = ceph_decode_32(&p);
225	ceph_decode_need(&p, end, result_msg_len, bad);
226	result_msg = p;
227	p += result_msg_len;
228	if (p != end)
229		goto bad;
230
231	dout(" result %d '%.*s' gid %llu len %d\n", result, result_msg_len,
232	     result_msg, global_id, payload_len);
233
234	payload_end = payload + payload_len;
235
236	if (ac->negotiating) {
237		/* server does not support our protocols? */
238		if (!protocol && result < 0) {
239			ret = result;
240			goto out;
241		}
242		/* set up (new) protocol handler? */
243		if (ac->protocol && ac->protocol != protocol) {
244			ac->ops->destroy(ac);
245			ac->protocol = 0;
246			ac->ops = NULL;
247		}
248		if (ac->protocol != protocol) {
249			ret = init_protocol(ac, protocol);
250			if (ret) {
251				pr_err("auth protocol '%s' init failed: %d\n",
252				       ceph_auth_proto_name(protocol), ret);
253				goto out;
254			}
255		}
256
257		ac->negotiating = false;
258	}
259
260	if (result) {
261		pr_err("auth protocol '%s' mauth authentication failed: %d\n",
262		       ceph_auth_proto_name(ac->protocol), result);
263		ret = result;
264		goto out;
265	}
266
267	ret = ac->ops->handle_reply(ac, global_id, payload, payload_end,
268				    NULL, NULL, NULL, NULL);
269	if (ret == -EAGAIN) {
270		ret = build_request(ac, true, reply_buf, reply_len);
271		goto out;
272	} else if (ret) {
273		goto out;
274	}
275
276out:
277	mutex_unlock(&ac->mutex);
278	return ret;
279
280bad:
281	pr_err("failed to decode auth msg\n");
282	ret = -EINVAL;
283	goto out;
284}
285
286int 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
298int 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}
308EXPORT_SYMBOL(ceph_auth_is_authenticated);
309
310int __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
337out:
338	mutex_unlock(&ac->mutex);
339	return ret;
340}
341EXPORT_SYMBOL(__ceph_auth_get_authorizer);
342
343void ceph_auth_destroy_authorizer(struct ceph_authorizer *a)
344{
345	a->destroy(a);
346}
347EXPORT_SYMBOL(ceph_auth_destroy_authorizer);
348
349int 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}
363EXPORT_SYMBOL(ceph_auth_add_authorizer_challenge);
364
365int 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}
381EXPORT_SYMBOL(ceph_auth_verify_authorizer_reply);
382
383void 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}
390EXPORT_SYMBOL(ceph_auth_invalidate_authorizer);
391
392/*
393 * msgr2 authentication
394 */
395
396static 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
408static 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
422e_range:
423	return -ERANGE;
424}
425
426/*
427 * Similar to ceph_auth_build_hello().
428 */
429int 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
468out:
469	mutex_unlock(&ac->mutex);
470	return ret;
471
472e_range:
473	ret = -ERANGE;
474	goto out;
475}
476
477int 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
493int 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, global_id, reply, reply + reply_len,
502				    session_key, session_key_len,
503				    con_secret, con_secret_len);
504	WARN_ON(ret == -EAGAIN || ret > 0);
505	mutex_unlock(&ac->mutex);
506	return ret;
507}
508
509bool ceph_auth_handle_bad_method(struct ceph_auth_client *ac,
510				 int used_proto, int result,
511				 const int *allowed_protos, int proto_cnt,
512				 const int *allowed_modes, int mode_cnt)
513{
514	mutex_lock(&ac->mutex);
515	WARN_ON(used_proto != ac->protocol);
516
517	if (result == -EOPNOTSUPP) {
518		if (!contains(allowed_protos, proto_cnt, ac->protocol)) {
519			pr_err("auth protocol '%s' not allowed\n",
520			       ceph_auth_proto_name(ac->protocol));
521			goto not_allowed;
522		}
523		if (!contains(allowed_modes, mode_cnt, ac->preferred_mode) &&
524		    (ac->fallback_mode == CEPH_CON_MODE_UNKNOWN ||
525		     !contains(allowed_modes, mode_cnt, ac->fallback_mode))) {
526			pr_err("preferred mode '%s' not allowed\n",
527			       ceph_con_mode_name(ac->preferred_mode));
528			if (ac->fallback_mode == CEPH_CON_MODE_UNKNOWN)
529				pr_err("no fallback mode\n");
530			else
531				pr_err("fallback mode '%s' not allowed\n",
532				       ceph_con_mode_name(ac->fallback_mode));
533			goto not_allowed;
534		}
535	}
536
537	WARN_ON(result == -EOPNOTSUPP || result >= 0);
538	pr_err("auth protocol '%s' msgr authentication failed: %d\n",
539	       ceph_auth_proto_name(ac->protocol), result);
540
541	mutex_unlock(&ac->mutex);
542	return true;
543
544not_allowed:
545	mutex_unlock(&ac->mutex);
546	return false;
547}
548
549int ceph_auth_get_authorizer(struct ceph_auth_client *ac,
550			     struct ceph_auth_handshake *auth,
551			     int peer_type, void *buf, int *buf_len)
552{
553	void *end = buf + *buf_len;
554	int pref_mode, fallb_mode;
555	int proto;
556	void *p;
557	int ret;
558
559	ret = __ceph_auth_get_authorizer(ac, auth, peer_type, true, &proto,
560					 &pref_mode, &fallb_mode);
561	if (ret)
562		return ret;
563
564	p = buf;
565	ceph_encode_32_safe(&p, end, proto, e_range);
566	ret = encode_con_modes(&p, end, pref_mode, fallb_mode);
567	if (ret)
568		return ret;
569
570	ceph_encode_32_safe(&p, end, auth->authorizer_buf_len, e_range);
571	*buf_len = p - buf;
572	return 0;
573
574e_range:
575	return -ERANGE;
576}
577EXPORT_SYMBOL(ceph_auth_get_authorizer);
578
579int ceph_auth_handle_svc_reply_more(struct ceph_auth_client *ac,
580				    struct ceph_auth_handshake *auth,
581				    void *reply, int reply_len,
582				    void *buf, int *buf_len)
583{
584	void *end = buf + *buf_len;
585	void *p;
586	int ret;
587
588	ret = ceph_auth_add_authorizer_challenge(ac, auth->authorizer,
589						 reply, reply_len);
590	if (ret)
591		return ret;
592
593	p = buf;
594	ceph_encode_32_safe(&p, end, auth->authorizer_buf_len, e_range);
595	*buf_len = p - buf;
596	return 0;
597
598e_range:
599	return -ERANGE;
600}
601EXPORT_SYMBOL(ceph_auth_handle_svc_reply_more);
602
603int ceph_auth_handle_svc_reply_done(struct ceph_auth_client *ac,
604				    struct ceph_auth_handshake *auth,
605				    void *reply, int reply_len,
606				    u8 *session_key, int *session_key_len,
607				    u8 *con_secret, int *con_secret_len)
608{
609	return ceph_auth_verify_authorizer_reply(ac, auth->authorizer,
610		reply, reply_len, session_key, session_key_len,
611		con_secret, con_secret_len);
612}
613EXPORT_SYMBOL(ceph_auth_handle_svc_reply_done);
614
615bool ceph_auth_handle_bad_authorizer(struct ceph_auth_client *ac,
616				     int peer_type, int used_proto, int result,
617				     const int *allowed_protos, int proto_cnt,
618				     const int *allowed_modes, int mode_cnt)
619{
620	mutex_lock(&ac->mutex);
621	WARN_ON(used_proto != ac->protocol);
622
623	if (result == -EOPNOTSUPP) {
624		if (!contains(allowed_protos, proto_cnt, ac->protocol)) {
625			pr_err("auth protocol '%s' not allowed by %s\n",
626			       ceph_auth_proto_name(ac->protocol),
627			       ceph_entity_type_name(peer_type));
628			goto not_allowed;
629		}
630		if (!contains(allowed_modes, mode_cnt, ac->preferred_mode) &&
631		    (ac->fallback_mode == CEPH_CON_MODE_UNKNOWN ||
632		     !contains(allowed_modes, mode_cnt, ac->fallback_mode))) {
633			pr_err("preferred mode '%s' not allowed by %s\n",
634			       ceph_con_mode_name(ac->preferred_mode),
635			       ceph_entity_type_name(peer_type));
636			if (ac->fallback_mode == CEPH_CON_MODE_UNKNOWN)
637				pr_err("no fallback mode\n");
638			else
639				pr_err("fallback mode '%s' not allowed by %s\n",
640				       ceph_con_mode_name(ac->fallback_mode),
641				       ceph_entity_type_name(peer_type));
642			goto not_allowed;
643		}
644	}
645
646	WARN_ON(result == -EOPNOTSUPP || result >= 0);
647	pr_err("auth protocol '%s' authorization to %s failed: %d\n",
648	       ceph_auth_proto_name(ac->protocol),
649	       ceph_entity_type_name(peer_type), result);
650
651	if (ac->ops->invalidate_authorizer)
652		ac->ops->invalidate_authorizer(ac, peer_type);
653
654	mutex_unlock(&ac->mutex);
655	return true;
656
657not_allowed:
658	mutex_unlock(&ac->mutex);
659	return false;
660}
661EXPORT_SYMBOL(ceph_auth_handle_bad_authorizer);
~/ Read-only file preview.