1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
23d14c5d2SYehuda Sadeh #include <linux/ceph/ceph_debug.h>
33d14c5d2SYehuda Sadeh
43d14c5d2SYehuda Sadeh #include <linux/module.h>
53d14c5d2SYehuda Sadeh #include <linux/err.h>
63d14c5d2SYehuda Sadeh #include <linux/slab.h>
73d14c5d2SYehuda Sadeh
83d14c5d2SYehuda Sadeh #include <linux/ceph/types.h>
93d14c5d2SYehuda Sadeh #include <linux/ceph/decode.h>
103d14c5d2SYehuda Sadeh #include <linux/ceph/libceph.h>
113d14c5d2SYehuda Sadeh #include <linux/ceph/messenger.h>
123d14c5d2SYehuda Sadeh #include "auth_none.h"
133d14c5d2SYehuda Sadeh #include "auth_x.h"
143d14c5d2SYehuda Sadeh
153d14c5d2SYehuda Sadeh
163d14c5d2SYehuda Sadeh /*
173d14c5d2SYehuda Sadeh * get protocol handler
183d14c5d2SYehuda Sadeh */
193d14c5d2SYehuda Sadeh static u32 supported_protocols[] = {
203d14c5d2SYehuda Sadeh CEPH_AUTH_NONE,
213d14c5d2SYehuda Sadeh CEPH_AUTH_CEPHX
223d14c5d2SYehuda Sadeh };
233d14c5d2SYehuda Sadeh
init_protocol(struct ceph_auth_client * ac,int proto)2459711f9eSIlya Dryomov static int init_protocol(struct ceph_auth_client *ac, int proto)
253d14c5d2SYehuda Sadeh {
2659711f9eSIlya Dryomov dout("%s proto %d\n", __func__, proto);
2759711f9eSIlya Dryomov
2859711f9eSIlya Dryomov switch (proto) {
293d14c5d2SYehuda Sadeh case CEPH_AUTH_NONE:
303d14c5d2SYehuda Sadeh return ceph_auth_none_init(ac);
313d14c5d2SYehuda Sadeh case CEPH_AUTH_CEPHX:
323d14c5d2SYehuda Sadeh return ceph_x_init(ac);
333d14c5d2SYehuda Sadeh default:
3459711f9eSIlya Dryomov pr_err("bad auth protocol %d\n", proto);
3559711f9eSIlya Dryomov return -EINVAL;
363d14c5d2SYehuda Sadeh }
373d14c5d2SYehuda Sadeh }
383d14c5d2SYehuda Sadeh
ceph_auth_set_global_id(struct ceph_auth_client * ac,u64 global_id)3903af4c7bSIlya Dryomov void ceph_auth_set_global_id(struct ceph_auth_client *ac, u64 global_id)
4061ca49a9SIlya Dryomov {
4161ca49a9SIlya Dryomov dout("%s global_id %llu\n", __func__, global_id);
4261ca49a9SIlya Dryomov
4361ca49a9SIlya Dryomov if (!global_id)
4461ca49a9SIlya Dryomov pr_err("got zero global_id\n");
4561ca49a9SIlya Dryomov
4661ca49a9SIlya Dryomov if (ac->global_id && global_id != ac->global_id)
4761ca49a9SIlya Dryomov pr_err("global_id changed from %llu to %llu\n", ac->global_id,
4861ca49a9SIlya Dryomov global_id);
4961ca49a9SIlya Dryomov
5061ca49a9SIlya Dryomov ac->global_id = global_id;
5161ca49a9SIlya Dryomov }
5261ca49a9SIlya Dryomov
533d14c5d2SYehuda Sadeh /*
543d14c5d2SYehuda Sadeh * setup, teardown.
553d14c5d2SYehuda Sadeh */
ceph_auth_init(const char * name,const struct ceph_crypto_key * key,const int * con_modes)5600498b99SIlya Dryomov struct ceph_auth_client *ceph_auth_init(const char *name,
5700498b99SIlya Dryomov const struct ceph_crypto_key *key,
5800498b99SIlya Dryomov const int *con_modes)
593d14c5d2SYehuda Sadeh {
603d14c5d2SYehuda Sadeh struct ceph_auth_client *ac;
613d14c5d2SYehuda Sadeh
623d14c5d2SYehuda Sadeh ac = kzalloc(sizeof(*ac), GFP_NOFS);
633d14c5d2SYehuda Sadeh if (!ac)
64*da6ebb4dSzuoqilin return ERR_PTR(-ENOMEM);
653d14c5d2SYehuda Sadeh
66e9966076SSage Weil mutex_init(&ac->mutex);
673d14c5d2SYehuda Sadeh ac->negotiating = true;
683d14c5d2SYehuda Sadeh if (name)
693d14c5d2SYehuda Sadeh ac->name = name;
703d14c5d2SYehuda Sadeh else
713d14c5d2SYehuda Sadeh ac->name = CEPH_AUTH_NAME_DEFAULT;
728323c3aaSTommi Virtanen ac->key = key;
7300498b99SIlya Dryomov ac->preferred_mode = con_modes[0];
7400498b99SIlya Dryomov ac->fallback_mode = con_modes[1];
7500498b99SIlya Dryomov
7600498b99SIlya Dryomov dout("%s name '%s' preferred_mode %d fallback_mode %d\n", __func__,
7700498b99SIlya Dryomov ac->name, ac->preferred_mode, ac->fallback_mode);
783d14c5d2SYehuda Sadeh return ac;
793d14c5d2SYehuda Sadeh }
803d14c5d2SYehuda Sadeh
ceph_auth_destroy(struct ceph_auth_client * ac)813d14c5d2SYehuda Sadeh void ceph_auth_destroy(struct ceph_auth_client *ac)
823d14c5d2SYehuda Sadeh {
833d14c5d2SYehuda Sadeh dout("auth_destroy %p\n", ac);
843d14c5d2SYehuda Sadeh if (ac->ops)
853d14c5d2SYehuda Sadeh ac->ops->destroy(ac);
863d14c5d2SYehuda Sadeh kfree(ac);
873d14c5d2SYehuda Sadeh }
883d14c5d2SYehuda Sadeh
893d14c5d2SYehuda Sadeh /*
903d14c5d2SYehuda Sadeh * Reset occurs when reconnecting to the monitor.
913d14c5d2SYehuda Sadeh */
ceph_auth_reset(struct ceph_auth_client * ac)923d14c5d2SYehuda Sadeh void ceph_auth_reset(struct ceph_auth_client *ac)
933d14c5d2SYehuda Sadeh {
94e9966076SSage Weil mutex_lock(&ac->mutex);
953d14c5d2SYehuda Sadeh dout("auth_reset %p\n", ac);
963d14c5d2SYehuda Sadeh if (ac->ops && !ac->negotiating)
973d14c5d2SYehuda Sadeh ac->ops->reset(ac);
983d14c5d2SYehuda Sadeh ac->negotiating = true;
99e9966076SSage Weil mutex_unlock(&ac->mutex);
1003d14c5d2SYehuda Sadeh }
1013d14c5d2SYehuda Sadeh
102f01d5cb2SIlya Dryomov /*
103f01d5cb2SIlya Dryomov * EntityName, not to be confused with entity_name_t
104f01d5cb2SIlya Dryomov */
ceph_auth_entity_name_encode(const char * name,void ** p,void * end)105f01d5cb2SIlya Dryomov int ceph_auth_entity_name_encode(const char *name, void **p, void *end)
1063d14c5d2SYehuda Sadeh {
1073d14c5d2SYehuda Sadeh int len = strlen(name);
1083d14c5d2SYehuda Sadeh
1093d14c5d2SYehuda Sadeh if (*p + 2*sizeof(u32) + len > end)
1103d14c5d2SYehuda Sadeh return -ERANGE;
1113d14c5d2SYehuda Sadeh ceph_encode_32(p, CEPH_ENTITY_TYPE_CLIENT);
1123d14c5d2SYehuda Sadeh ceph_encode_32(p, len);
1133d14c5d2SYehuda Sadeh ceph_encode_copy(p, name, len);
1143d14c5d2SYehuda Sadeh return 0;
1153d14c5d2SYehuda Sadeh }
1163d14c5d2SYehuda Sadeh
1173d14c5d2SYehuda Sadeh /*
1183d14c5d2SYehuda Sadeh * Initiate protocol negotiation with monitor. Include entity name
1193d14c5d2SYehuda Sadeh * and list supported protocols.
1203d14c5d2SYehuda Sadeh */
ceph_auth_build_hello(struct ceph_auth_client * ac,void * buf,size_t len)1213d14c5d2SYehuda Sadeh int ceph_auth_build_hello(struct ceph_auth_client *ac, void *buf, size_t len)
1223d14c5d2SYehuda Sadeh {
1233d14c5d2SYehuda Sadeh struct ceph_mon_request_header *monhdr = buf;
1243d14c5d2SYehuda Sadeh void *p = monhdr + 1, *end = buf + len, *lenp;
1253d14c5d2SYehuda Sadeh int i, num;
1263d14c5d2SYehuda Sadeh int ret;
1273d14c5d2SYehuda Sadeh
128e9966076SSage Weil mutex_lock(&ac->mutex);
1293d14c5d2SYehuda Sadeh dout("auth_build_hello\n");
1303d14c5d2SYehuda Sadeh monhdr->have_version = 0;
1313d14c5d2SYehuda Sadeh monhdr->session_mon = cpu_to_le16(-1);
1323d14c5d2SYehuda Sadeh monhdr->session_mon_tid = 0;
1333d14c5d2SYehuda Sadeh
134fdc723e7SIlya Dryomov ceph_encode_32(&p, CEPH_AUTH_UNKNOWN); /* no protocol, yet */
1353d14c5d2SYehuda Sadeh
1363d14c5d2SYehuda Sadeh lenp = p;
1373d14c5d2SYehuda Sadeh p += sizeof(u32);
1383d14c5d2SYehuda Sadeh
1393d14c5d2SYehuda Sadeh ceph_decode_need(&p, end, 1 + sizeof(u32), bad);
1403d14c5d2SYehuda Sadeh ceph_encode_8(&p, 1);
1413d14c5d2SYehuda Sadeh num = ARRAY_SIZE(supported_protocols);
1423d14c5d2SYehuda Sadeh ceph_encode_32(&p, num);
1433d14c5d2SYehuda Sadeh ceph_decode_need(&p, end, num * sizeof(u32), bad);
1443d14c5d2SYehuda Sadeh for (i = 0; i < num; i++)
1453d14c5d2SYehuda Sadeh ceph_encode_32(&p, supported_protocols[i]);
1463d14c5d2SYehuda Sadeh
147f01d5cb2SIlya Dryomov ret = ceph_auth_entity_name_encode(ac->name, &p, end);
1483d14c5d2SYehuda Sadeh if (ret < 0)
149e9966076SSage Weil goto out;
1503d14c5d2SYehuda Sadeh ceph_decode_need(&p, end, sizeof(u64), bad);
1513d14c5d2SYehuda Sadeh ceph_encode_64(&p, ac->global_id);
1523d14c5d2SYehuda Sadeh
1533d14c5d2SYehuda Sadeh ceph_encode_32(&lenp, p - lenp - sizeof(u32));
154e9966076SSage Weil ret = p - buf;
155e9966076SSage Weil out:
156e9966076SSage Weil mutex_unlock(&ac->mutex);
157e9966076SSage Weil return ret;
1583d14c5d2SYehuda Sadeh
1593d14c5d2SYehuda Sadeh bad:
160e9966076SSage Weil ret = -ERANGE;
161e9966076SSage Weil goto out;
1623d14c5d2SYehuda Sadeh }
1633d14c5d2SYehuda Sadeh
build_request(struct ceph_auth_client * ac,bool add_header,void * buf,int buf_len)16459711f9eSIlya Dryomov static int build_request(struct ceph_auth_client *ac, bool add_header,
16559711f9eSIlya Dryomov void *buf, int buf_len)
1663d14c5d2SYehuda Sadeh {
16759711f9eSIlya Dryomov void *end = buf + buf_len;
16859711f9eSIlya Dryomov void *p;
1693d14c5d2SYehuda Sadeh int ret;
1703d14c5d2SYehuda Sadeh
17159711f9eSIlya Dryomov p = buf;
17259711f9eSIlya Dryomov if (add_header) {
17359711f9eSIlya Dryomov /* struct ceph_mon_request_header + protocol */
17459711f9eSIlya Dryomov ceph_encode_64_safe(&p, end, 0, e_range);
17559711f9eSIlya Dryomov ceph_encode_16_safe(&p, end, -1, e_range);
17659711f9eSIlya Dryomov ceph_encode_64_safe(&p, end, 0, e_range);
17759711f9eSIlya Dryomov ceph_encode_32_safe(&p, end, ac->protocol, e_range);
17859711f9eSIlya Dryomov }
1793d14c5d2SYehuda Sadeh
18059711f9eSIlya Dryomov ceph_encode_need(&p, end, sizeof(u32), e_range);
1813d14c5d2SYehuda Sadeh ret = ac->ops->build_request(ac, p + sizeof(u32), end);
1823d14c5d2SYehuda Sadeh if (ret < 0) {
18359711f9eSIlya Dryomov pr_err("auth protocol '%s' building request failed: %d\n",
18459711f9eSIlya Dryomov ceph_auth_proto_name(ac->protocol), ret);
18559711f9eSIlya Dryomov return ret;
1863d14c5d2SYehuda Sadeh }
1873d14c5d2SYehuda Sadeh dout(" built request %d bytes\n", ret);
1883d14c5d2SYehuda Sadeh ceph_encode_32(&p, ret);
18959711f9eSIlya Dryomov return p + ret - buf;
19059711f9eSIlya Dryomov
19159711f9eSIlya Dryomov e_range:
19259711f9eSIlya Dryomov return -ERANGE;
1933d14c5d2SYehuda Sadeh }
1943d14c5d2SYehuda Sadeh
1953d14c5d2SYehuda Sadeh /*
1963d14c5d2SYehuda Sadeh * Handle auth message from monitor.
1973d14c5d2SYehuda Sadeh */
ceph_handle_auth_reply(struct ceph_auth_client * ac,void * buf,size_t len,void * reply_buf,size_t reply_len)1983d14c5d2SYehuda Sadeh int ceph_handle_auth_reply(struct ceph_auth_client *ac,
1993d14c5d2SYehuda Sadeh void *buf, size_t len,
2003d14c5d2SYehuda Sadeh void *reply_buf, size_t reply_len)
2013d14c5d2SYehuda Sadeh {
2023d14c5d2SYehuda Sadeh void *p = buf;
2033d14c5d2SYehuda Sadeh void *end = buf + len;
2043d14c5d2SYehuda Sadeh int protocol;
2053d14c5d2SYehuda Sadeh s32 result;
2063d14c5d2SYehuda Sadeh u64 global_id;
2073d14c5d2SYehuda Sadeh void *payload, *payload_end;
2083d14c5d2SYehuda Sadeh int payload_len;
2093d14c5d2SYehuda Sadeh char *result_msg;
2103d14c5d2SYehuda Sadeh int result_msg_len;
2113d14c5d2SYehuda Sadeh int ret = -EINVAL;
2123d14c5d2SYehuda Sadeh
213e9966076SSage Weil mutex_lock(&ac->mutex);
2143d14c5d2SYehuda Sadeh dout("handle_auth_reply %p %p\n", p, end);
2153d14c5d2SYehuda Sadeh ceph_decode_need(&p, end, sizeof(u32) * 3 + sizeof(u64), bad);
2163d14c5d2SYehuda Sadeh protocol = ceph_decode_32(&p);
2173d14c5d2SYehuda Sadeh result = ceph_decode_32(&p);
2183d14c5d2SYehuda Sadeh global_id = ceph_decode_64(&p);
2193d14c5d2SYehuda Sadeh payload_len = ceph_decode_32(&p);
2203d14c5d2SYehuda Sadeh payload = p;
2213d14c5d2SYehuda Sadeh p += payload_len;
2223d14c5d2SYehuda Sadeh ceph_decode_need(&p, end, sizeof(u32), bad);
2233d14c5d2SYehuda Sadeh result_msg_len = ceph_decode_32(&p);
2243d14c5d2SYehuda Sadeh result_msg = p;
2253d14c5d2SYehuda Sadeh p += result_msg_len;
2263d14c5d2SYehuda Sadeh if (p != end)
2273d14c5d2SYehuda Sadeh goto bad;
2283d14c5d2SYehuda Sadeh
2293d14c5d2SYehuda Sadeh dout(" result %d '%.*s' gid %llu len %d\n", result, result_msg_len,
2303d14c5d2SYehuda Sadeh result_msg, global_id, payload_len);
2313d14c5d2SYehuda Sadeh
2323d14c5d2SYehuda Sadeh payload_end = payload + payload_len;
2333d14c5d2SYehuda Sadeh
2343d14c5d2SYehuda Sadeh if (ac->negotiating) {
2353d14c5d2SYehuda Sadeh /* server does not support our protocols? */
2363d14c5d2SYehuda Sadeh if (!protocol && result < 0) {
2373d14c5d2SYehuda Sadeh ret = result;
2383d14c5d2SYehuda Sadeh goto out;
2393d14c5d2SYehuda Sadeh }
2403d14c5d2SYehuda Sadeh /* set up (new) protocol handler? */
2413d14c5d2SYehuda Sadeh if (ac->protocol && ac->protocol != protocol) {
2423d14c5d2SYehuda Sadeh ac->ops->destroy(ac);
2433d14c5d2SYehuda Sadeh ac->protocol = 0;
2443d14c5d2SYehuda Sadeh ac->ops = NULL;
2453d14c5d2SYehuda Sadeh }
2463d14c5d2SYehuda Sadeh if (ac->protocol != protocol) {
24759711f9eSIlya Dryomov ret = init_protocol(ac, protocol);
2483d14c5d2SYehuda Sadeh if (ret) {
24959711f9eSIlya Dryomov pr_err("auth protocol '%s' init failed: %d\n",
25059711f9eSIlya Dryomov ceph_auth_proto_name(protocol), ret);
2513d14c5d2SYehuda Sadeh goto out;
2523d14c5d2SYehuda Sadeh }
2533d14c5d2SYehuda Sadeh }
2543d14c5d2SYehuda Sadeh
2553d14c5d2SYehuda Sadeh ac->negotiating = false;
2563d14c5d2SYehuda Sadeh }
2573d14c5d2SYehuda Sadeh
2583c0d0894SIlya Dryomov if (result) {
2593c0d0894SIlya Dryomov pr_err("auth protocol '%s' mauth authentication failed: %d\n",
2603c0d0894SIlya Dryomov ceph_auth_proto_name(ac->protocol), result);
2613c0d0894SIlya Dryomov ret = result;
2623c0d0894SIlya Dryomov goto out;
2633c0d0894SIlya Dryomov }
2643c0d0894SIlya Dryomov
26503af4c7bSIlya Dryomov ret = ac->ops->handle_reply(ac, global_id, payload, payload_end,
266285ea34fSIlya Dryomov NULL, NULL, NULL, NULL);
26761ca49a9SIlya Dryomov if (ret == -EAGAIN) {
26859711f9eSIlya Dryomov ret = build_request(ac, true, reply_buf, reply_len);
26961ca49a9SIlya Dryomov goto out;
27061ca49a9SIlya Dryomov } else if (ret) {
27161ca49a9SIlya Dryomov goto out;
27261ca49a9SIlya Dryomov }
27361ca49a9SIlya Dryomov
274e9966076SSage Weil out:
275e9966076SSage Weil mutex_unlock(&ac->mutex);
276e9966076SSage Weil return ret;
2773d14c5d2SYehuda Sadeh
2783d14c5d2SYehuda Sadeh bad:
2793d14c5d2SYehuda Sadeh pr_err("failed to decode auth msg\n");
280e9966076SSage Weil ret = -EINVAL;
281e9966076SSage Weil goto out;
2823d14c5d2SYehuda Sadeh }
2833d14c5d2SYehuda Sadeh
ceph_build_auth(struct ceph_auth_client * ac,void * msg_buf,size_t msg_len)2843d14c5d2SYehuda Sadeh int ceph_build_auth(struct ceph_auth_client *ac,
2853d14c5d2SYehuda Sadeh void *msg_buf, size_t msg_len)
2863d14c5d2SYehuda Sadeh {
287e9966076SSage Weil int ret = 0;
288e9966076SSage Weil
289e9966076SSage Weil mutex_lock(&ac->mutex);
290464691bdSIlya Dryomov if (ac->ops->should_authenticate(ac))
29159711f9eSIlya Dryomov ret = build_request(ac, true, msg_buf, msg_len);
292e9966076SSage Weil mutex_unlock(&ac->mutex);
293e9966076SSage Weil return ret;
2943d14c5d2SYehuda Sadeh }
2953d14c5d2SYehuda Sadeh
ceph_auth_is_authenticated(struct ceph_auth_client * ac)2963d14c5d2SYehuda Sadeh int ceph_auth_is_authenticated(struct ceph_auth_client *ac)
2973d14c5d2SYehuda Sadeh {
298e9966076SSage Weil int ret = 0;
299e9966076SSage Weil
300e9966076SSage Weil mutex_lock(&ac->mutex);
301e9966076SSage Weil if (ac->ops)
302e9966076SSage Weil ret = ac->ops->is_authenticated(ac);
303e9966076SSage Weil mutex_unlock(&ac->mutex);
304e9966076SSage Weil return ret;
3053d14c5d2SYehuda Sadeh }
30627859f97SSage Weil EXPORT_SYMBOL(ceph_auth_is_authenticated);
30727859f97SSage Weil
__ceph_auth_get_authorizer(struct ceph_auth_client * ac,struct ceph_auth_handshake * auth,int peer_type,bool force_new,int * proto,int * pref_mode,int * fallb_mode)308cd1a677cSIlya Dryomov int __ceph_auth_get_authorizer(struct ceph_auth_client *ac,
309cd1a677cSIlya Dryomov struct ceph_auth_handshake *auth,
310cd1a677cSIlya Dryomov int peer_type, bool force_new,
311cd1a677cSIlya Dryomov int *proto, int *pref_mode, int *fallb_mode)
312cd1a677cSIlya Dryomov {
313cd1a677cSIlya Dryomov int ret;
314cd1a677cSIlya Dryomov
315cd1a677cSIlya Dryomov mutex_lock(&ac->mutex);
316cd1a677cSIlya Dryomov if (force_new && auth->authorizer) {
317cd1a677cSIlya Dryomov ceph_auth_destroy_authorizer(auth->authorizer);
318cd1a677cSIlya Dryomov auth->authorizer = NULL;
319cd1a677cSIlya Dryomov }
320cd1a677cSIlya Dryomov if (!auth->authorizer)
321cd1a677cSIlya Dryomov ret = ac->ops->create_authorizer(ac, peer_type, auth);
322cd1a677cSIlya Dryomov else if (ac->ops->update_authorizer)
323cd1a677cSIlya Dryomov ret = ac->ops->update_authorizer(ac, peer_type, auth);
324cd1a677cSIlya Dryomov else
325cd1a677cSIlya Dryomov ret = 0;
326cd1a677cSIlya Dryomov if (ret)
327cd1a677cSIlya Dryomov goto out;
328cd1a677cSIlya Dryomov
329cd1a677cSIlya Dryomov *proto = ac->protocol;
330cd1a677cSIlya Dryomov if (pref_mode && fallb_mode) {
331cd1a677cSIlya Dryomov *pref_mode = ac->preferred_mode;
332cd1a677cSIlya Dryomov *fallb_mode = ac->fallback_mode;
333cd1a677cSIlya Dryomov }
334cd1a677cSIlya Dryomov
335cd1a677cSIlya Dryomov out:
336cd1a677cSIlya Dryomov mutex_unlock(&ac->mutex);
337cd1a677cSIlya Dryomov return ret;
338cd1a677cSIlya Dryomov }
339cd1a677cSIlya Dryomov EXPORT_SYMBOL(__ceph_auth_get_authorizer);
340cd1a677cSIlya Dryomov
ceph_auth_destroy_authorizer(struct ceph_authorizer * a)3416c1ea260SIlya Dryomov void ceph_auth_destroy_authorizer(struct ceph_authorizer *a)
34227859f97SSage Weil {
3436c1ea260SIlya Dryomov a->destroy(a);
34427859f97SSage Weil }
34527859f97SSage Weil EXPORT_SYMBOL(ceph_auth_destroy_authorizer);
34627859f97SSage Weil
ceph_auth_add_authorizer_challenge(struct ceph_auth_client * ac,struct ceph_authorizer * a,void * challenge_buf,int challenge_buf_len)3476daca13dSIlya Dryomov int ceph_auth_add_authorizer_challenge(struct ceph_auth_client *ac,
3486daca13dSIlya Dryomov struct ceph_authorizer *a,
3496daca13dSIlya Dryomov void *challenge_buf,
3506daca13dSIlya Dryomov int challenge_buf_len)
3516daca13dSIlya Dryomov {
3526daca13dSIlya Dryomov int ret = 0;
3536daca13dSIlya Dryomov
3546daca13dSIlya Dryomov mutex_lock(&ac->mutex);
3556daca13dSIlya Dryomov if (ac->ops && ac->ops->add_authorizer_challenge)
3566daca13dSIlya Dryomov ret = ac->ops->add_authorizer_challenge(ac, a, challenge_buf,
3576daca13dSIlya Dryomov challenge_buf_len);
3586daca13dSIlya Dryomov mutex_unlock(&ac->mutex);
3596daca13dSIlya Dryomov return ret;
3606daca13dSIlya Dryomov }
3616daca13dSIlya Dryomov EXPORT_SYMBOL(ceph_auth_add_authorizer_challenge);
3626daca13dSIlya Dryomov
ceph_auth_verify_authorizer_reply(struct ceph_auth_client * ac,struct ceph_authorizer * a,void * reply,int reply_len,u8 * session_key,int * session_key_len,u8 * con_secret,int * con_secret_len)36327859f97SSage Weil int ceph_auth_verify_authorizer_reply(struct ceph_auth_client *ac,
364285ea34fSIlya Dryomov struct ceph_authorizer *a,
365285ea34fSIlya Dryomov void *reply, int reply_len,
366285ea34fSIlya Dryomov u8 *session_key, int *session_key_len,
367285ea34fSIlya Dryomov u8 *con_secret, int *con_secret_len)
36827859f97SSage Weil {
369e9966076SSage Weil int ret = 0;
370e9966076SSage Weil
371e9966076SSage Weil mutex_lock(&ac->mutex);
37227859f97SSage Weil if (ac->ops && ac->ops->verify_authorizer_reply)
373285ea34fSIlya Dryomov ret = ac->ops->verify_authorizer_reply(ac, a,
374285ea34fSIlya Dryomov reply, reply_len, session_key, session_key_len,
375285ea34fSIlya Dryomov con_secret, con_secret_len);
376e9966076SSage Weil mutex_unlock(&ac->mutex);
377e9966076SSage Weil return ret;
37827859f97SSage Weil }
37927859f97SSage Weil EXPORT_SYMBOL(ceph_auth_verify_authorizer_reply);
38027859f97SSage Weil
ceph_auth_invalidate_authorizer(struct ceph_auth_client * ac,int peer_type)38127859f97SSage Weil void ceph_auth_invalidate_authorizer(struct ceph_auth_client *ac, int peer_type)
38227859f97SSage Weil {
383e9966076SSage Weil mutex_lock(&ac->mutex);
38427859f97SSage Weil if (ac->ops && ac->ops->invalidate_authorizer)
38527859f97SSage Weil ac->ops->invalidate_authorizer(ac, peer_type);
386e9966076SSage Weil mutex_unlock(&ac->mutex);
38727859f97SSage Weil }
38827859f97SSage Weil EXPORT_SYMBOL(ceph_auth_invalidate_authorizer);
389cd1a677cSIlya Dryomov
390cd1a677cSIlya Dryomov /*
391cd1a677cSIlya Dryomov * msgr2 authentication
392cd1a677cSIlya Dryomov */
393cd1a677cSIlya Dryomov
contains(const int * arr,int cnt,int val)394cd1a677cSIlya Dryomov static bool contains(const int *arr, int cnt, int val)
395cd1a677cSIlya Dryomov {
396cd1a677cSIlya Dryomov int i;
397cd1a677cSIlya Dryomov
398cd1a677cSIlya Dryomov for (i = 0; i < cnt; i++) {
399cd1a677cSIlya Dryomov if (arr[i] == val)
400cd1a677cSIlya Dryomov return true;
401cd1a677cSIlya Dryomov }
402cd1a677cSIlya Dryomov
403cd1a677cSIlya Dryomov return false;
404cd1a677cSIlya Dryomov }
405cd1a677cSIlya Dryomov
encode_con_modes(void ** p,void * end,int pref_mode,int fallb_mode)406cd1a677cSIlya Dryomov static int encode_con_modes(void **p, void *end, int pref_mode, int fallb_mode)
407cd1a677cSIlya Dryomov {
408cd1a677cSIlya Dryomov WARN_ON(pref_mode == CEPH_CON_MODE_UNKNOWN);
409cd1a677cSIlya Dryomov if (fallb_mode != CEPH_CON_MODE_UNKNOWN) {
410cd1a677cSIlya Dryomov ceph_encode_32_safe(p, end, 2, e_range);
411cd1a677cSIlya Dryomov ceph_encode_32_safe(p, end, pref_mode, e_range);
412cd1a677cSIlya Dryomov ceph_encode_32_safe(p, end, fallb_mode, e_range);
413cd1a677cSIlya Dryomov } else {
414cd1a677cSIlya Dryomov ceph_encode_32_safe(p, end, 1, e_range);
415cd1a677cSIlya Dryomov ceph_encode_32_safe(p, end, pref_mode, e_range);
416cd1a677cSIlya Dryomov }
417cd1a677cSIlya Dryomov
418cd1a677cSIlya Dryomov return 0;
419cd1a677cSIlya Dryomov
420cd1a677cSIlya Dryomov e_range:
421cd1a677cSIlya Dryomov return -ERANGE;
422cd1a677cSIlya Dryomov }
423cd1a677cSIlya Dryomov
424cd1a677cSIlya Dryomov /*
425cd1a677cSIlya Dryomov * Similar to ceph_auth_build_hello().
426cd1a677cSIlya Dryomov */
ceph_auth_get_request(struct ceph_auth_client * ac,void * buf,int buf_len)427cd1a677cSIlya Dryomov int ceph_auth_get_request(struct ceph_auth_client *ac, void *buf, int buf_len)
428cd1a677cSIlya Dryomov {
429cd1a677cSIlya Dryomov int proto = ac->key ? CEPH_AUTH_CEPHX : CEPH_AUTH_NONE;
430cd1a677cSIlya Dryomov void *end = buf + buf_len;
431cd1a677cSIlya Dryomov void *lenp;
432cd1a677cSIlya Dryomov void *p;
433cd1a677cSIlya Dryomov int ret;
434cd1a677cSIlya Dryomov
435cd1a677cSIlya Dryomov mutex_lock(&ac->mutex);
436cd1a677cSIlya Dryomov if (ac->protocol == CEPH_AUTH_UNKNOWN) {
437cd1a677cSIlya Dryomov ret = init_protocol(ac, proto);
438cd1a677cSIlya Dryomov if (ret) {
439cd1a677cSIlya Dryomov pr_err("auth protocol '%s' init failed: %d\n",
440cd1a677cSIlya Dryomov ceph_auth_proto_name(proto), ret);
441cd1a677cSIlya Dryomov goto out;
442cd1a677cSIlya Dryomov }
443cd1a677cSIlya Dryomov } else {
444cd1a677cSIlya Dryomov WARN_ON(ac->protocol != proto);
445cd1a677cSIlya Dryomov ac->ops->reset(ac);
446cd1a677cSIlya Dryomov }
447cd1a677cSIlya Dryomov
448cd1a677cSIlya Dryomov p = buf;
449cd1a677cSIlya Dryomov ceph_encode_32_safe(&p, end, ac->protocol, e_range);
450cd1a677cSIlya Dryomov ret = encode_con_modes(&p, end, ac->preferred_mode, ac->fallback_mode);
451cd1a677cSIlya Dryomov if (ret)
452cd1a677cSIlya Dryomov goto out;
453cd1a677cSIlya Dryomov
454cd1a677cSIlya Dryomov lenp = p;
455cd1a677cSIlya Dryomov p += 4; /* space for len */
456cd1a677cSIlya Dryomov
457cd1a677cSIlya Dryomov ceph_encode_8_safe(&p, end, CEPH_AUTH_MODE_MON, e_range);
458cd1a677cSIlya Dryomov ret = ceph_auth_entity_name_encode(ac->name, &p, end);
459cd1a677cSIlya Dryomov if (ret)
460cd1a677cSIlya Dryomov goto out;
461cd1a677cSIlya Dryomov
462cd1a677cSIlya Dryomov ceph_encode_64_safe(&p, end, ac->global_id, e_range);
463cd1a677cSIlya Dryomov ceph_encode_32(&lenp, p - lenp - 4);
464cd1a677cSIlya Dryomov ret = p - buf;
465cd1a677cSIlya Dryomov
466cd1a677cSIlya Dryomov out:
467cd1a677cSIlya Dryomov mutex_unlock(&ac->mutex);
468cd1a677cSIlya Dryomov return ret;
469cd1a677cSIlya Dryomov
470cd1a677cSIlya Dryomov e_range:
471cd1a677cSIlya Dryomov ret = -ERANGE;
472cd1a677cSIlya Dryomov goto out;
473cd1a677cSIlya Dryomov }
474cd1a677cSIlya Dryomov
ceph_auth_handle_reply_more(struct ceph_auth_client * ac,void * reply,int reply_len,void * buf,int buf_len)475cd1a677cSIlya Dryomov int ceph_auth_handle_reply_more(struct ceph_auth_client *ac, void *reply,
476cd1a677cSIlya Dryomov int reply_len, void *buf, int buf_len)
477cd1a677cSIlya Dryomov {
478cd1a677cSIlya Dryomov int ret;
479cd1a677cSIlya Dryomov
480cd1a677cSIlya Dryomov mutex_lock(&ac->mutex);
48103af4c7bSIlya Dryomov ret = ac->ops->handle_reply(ac, 0, reply, reply + reply_len,
482cd1a677cSIlya Dryomov NULL, NULL, NULL, NULL);
483cd1a677cSIlya Dryomov if (ret == -EAGAIN)
484cd1a677cSIlya Dryomov ret = build_request(ac, false, buf, buf_len);
485cd1a677cSIlya Dryomov else
486cd1a677cSIlya Dryomov WARN_ON(ret >= 0);
487cd1a677cSIlya Dryomov mutex_unlock(&ac->mutex);
488cd1a677cSIlya Dryomov return ret;
489cd1a677cSIlya Dryomov }
490cd1a677cSIlya Dryomov
ceph_auth_handle_reply_done(struct ceph_auth_client * ac,u64 global_id,void * reply,int reply_len,u8 * session_key,int * session_key_len,u8 * con_secret,int * con_secret_len)491cd1a677cSIlya Dryomov int ceph_auth_handle_reply_done(struct ceph_auth_client *ac,
492cd1a677cSIlya Dryomov u64 global_id, void *reply, int reply_len,
493cd1a677cSIlya Dryomov u8 *session_key, int *session_key_len,
494cd1a677cSIlya Dryomov u8 *con_secret, int *con_secret_len)
495cd1a677cSIlya Dryomov {
496cd1a677cSIlya Dryomov int ret;
497cd1a677cSIlya Dryomov
498cd1a677cSIlya Dryomov mutex_lock(&ac->mutex);
49903af4c7bSIlya Dryomov ret = ac->ops->handle_reply(ac, global_id, reply, reply + reply_len,
500cd1a677cSIlya Dryomov session_key, session_key_len,
501cd1a677cSIlya Dryomov con_secret, con_secret_len);
50203af4c7bSIlya Dryomov WARN_ON(ret == -EAGAIN || ret > 0);
503cd1a677cSIlya Dryomov mutex_unlock(&ac->mutex);
504cd1a677cSIlya Dryomov return ret;
505cd1a677cSIlya Dryomov }
506cd1a677cSIlya Dryomov
ceph_auth_handle_bad_method(struct ceph_auth_client * ac,int used_proto,int result,const int * allowed_protos,int proto_cnt,const int * allowed_modes,int mode_cnt)507cd1a677cSIlya Dryomov bool ceph_auth_handle_bad_method(struct ceph_auth_client *ac,
508cd1a677cSIlya Dryomov int used_proto, int result,
509cd1a677cSIlya Dryomov const int *allowed_protos, int proto_cnt,
510cd1a677cSIlya Dryomov const int *allowed_modes, int mode_cnt)
511cd1a677cSIlya Dryomov {
512cd1a677cSIlya Dryomov mutex_lock(&ac->mutex);
513cd1a677cSIlya Dryomov WARN_ON(used_proto != ac->protocol);
514cd1a677cSIlya Dryomov
515cd1a677cSIlya Dryomov if (result == -EOPNOTSUPP) {
516cd1a677cSIlya Dryomov if (!contains(allowed_protos, proto_cnt, ac->protocol)) {
517cd1a677cSIlya Dryomov pr_err("auth protocol '%s' not allowed\n",
518cd1a677cSIlya Dryomov ceph_auth_proto_name(ac->protocol));
519cd1a677cSIlya Dryomov goto not_allowed;
520cd1a677cSIlya Dryomov }
521cd1a677cSIlya Dryomov if (!contains(allowed_modes, mode_cnt, ac->preferred_mode) &&
522cd1a677cSIlya Dryomov (ac->fallback_mode == CEPH_CON_MODE_UNKNOWN ||
523cd1a677cSIlya Dryomov !contains(allowed_modes, mode_cnt, ac->fallback_mode))) {
524cd1a677cSIlya Dryomov pr_err("preferred mode '%s' not allowed\n",
525cd1a677cSIlya Dryomov ceph_con_mode_name(ac->preferred_mode));
526cd1a677cSIlya Dryomov if (ac->fallback_mode == CEPH_CON_MODE_UNKNOWN)
527cd1a677cSIlya Dryomov pr_err("no fallback mode\n");
528cd1a677cSIlya Dryomov else
529cd1a677cSIlya Dryomov pr_err("fallback mode '%s' not allowed\n",
530cd1a677cSIlya Dryomov ceph_con_mode_name(ac->fallback_mode));
531cd1a677cSIlya Dryomov goto not_allowed;
532cd1a677cSIlya Dryomov }
533cd1a677cSIlya Dryomov }
534cd1a677cSIlya Dryomov
535cd1a677cSIlya Dryomov WARN_ON(result == -EOPNOTSUPP || result >= 0);
536cd1a677cSIlya Dryomov pr_err("auth protocol '%s' msgr authentication failed: %d\n",
537cd1a677cSIlya Dryomov ceph_auth_proto_name(ac->protocol), result);
538cd1a677cSIlya Dryomov
539cd1a677cSIlya Dryomov mutex_unlock(&ac->mutex);
540cd1a677cSIlya Dryomov return true;
541cd1a677cSIlya Dryomov
542cd1a677cSIlya Dryomov not_allowed:
543cd1a677cSIlya Dryomov mutex_unlock(&ac->mutex);
544cd1a677cSIlya Dryomov return false;
545cd1a677cSIlya Dryomov }
546cd1a677cSIlya Dryomov
ceph_auth_get_authorizer(struct ceph_auth_client * ac,struct ceph_auth_handshake * auth,int peer_type,void * buf,int * buf_len)547cd1a677cSIlya Dryomov int ceph_auth_get_authorizer(struct ceph_auth_client *ac,
548cd1a677cSIlya Dryomov struct ceph_auth_handshake *auth,
549cd1a677cSIlya Dryomov int peer_type, void *buf, int *buf_len)
550cd1a677cSIlya Dryomov {
551cd1a677cSIlya Dryomov void *end = buf + *buf_len;
552cd1a677cSIlya Dryomov int pref_mode, fallb_mode;
553cd1a677cSIlya Dryomov int proto;
554cd1a677cSIlya Dryomov void *p;
555cd1a677cSIlya Dryomov int ret;
556cd1a677cSIlya Dryomov
557cd1a677cSIlya Dryomov ret = __ceph_auth_get_authorizer(ac, auth, peer_type, true, &proto,
558cd1a677cSIlya Dryomov &pref_mode, &fallb_mode);
559cd1a677cSIlya Dryomov if (ret)
560cd1a677cSIlya Dryomov return ret;
561cd1a677cSIlya Dryomov
562cd1a677cSIlya Dryomov p = buf;
563cd1a677cSIlya Dryomov ceph_encode_32_safe(&p, end, proto, e_range);
564cd1a677cSIlya Dryomov ret = encode_con_modes(&p, end, pref_mode, fallb_mode);
565cd1a677cSIlya Dryomov if (ret)
566cd1a677cSIlya Dryomov return ret;
567cd1a677cSIlya Dryomov
568cd1a677cSIlya Dryomov ceph_encode_32_safe(&p, end, auth->authorizer_buf_len, e_range);
569cd1a677cSIlya Dryomov *buf_len = p - buf;
570cd1a677cSIlya Dryomov return 0;
571cd1a677cSIlya Dryomov
572cd1a677cSIlya Dryomov e_range:
573cd1a677cSIlya Dryomov return -ERANGE;
574cd1a677cSIlya Dryomov }
575cd1a677cSIlya Dryomov EXPORT_SYMBOL(ceph_auth_get_authorizer);
576cd1a677cSIlya Dryomov
ceph_auth_handle_svc_reply_more(struct ceph_auth_client * ac,struct ceph_auth_handshake * auth,void * reply,int reply_len,void * buf,int * buf_len)577cd1a677cSIlya Dryomov int ceph_auth_handle_svc_reply_more(struct ceph_auth_client *ac,
578cd1a677cSIlya Dryomov struct ceph_auth_handshake *auth,
579cd1a677cSIlya Dryomov void *reply, int reply_len,
580cd1a677cSIlya Dryomov void *buf, int *buf_len)
581cd1a677cSIlya Dryomov {
582cd1a677cSIlya Dryomov void *end = buf + *buf_len;
583cd1a677cSIlya Dryomov void *p;
584cd1a677cSIlya Dryomov int ret;
585cd1a677cSIlya Dryomov
586cd1a677cSIlya Dryomov ret = ceph_auth_add_authorizer_challenge(ac, auth->authorizer,
587cd1a677cSIlya Dryomov reply, reply_len);
588cd1a677cSIlya Dryomov if (ret)
589cd1a677cSIlya Dryomov return ret;
590cd1a677cSIlya Dryomov
591cd1a677cSIlya Dryomov p = buf;
592cd1a677cSIlya Dryomov ceph_encode_32_safe(&p, end, auth->authorizer_buf_len, e_range);
593cd1a677cSIlya Dryomov *buf_len = p - buf;
594cd1a677cSIlya Dryomov return 0;
595cd1a677cSIlya Dryomov
596cd1a677cSIlya Dryomov e_range:
597cd1a677cSIlya Dryomov return -ERANGE;
598cd1a677cSIlya Dryomov }
599cd1a677cSIlya Dryomov EXPORT_SYMBOL(ceph_auth_handle_svc_reply_more);
600cd1a677cSIlya Dryomov
ceph_auth_handle_svc_reply_done(struct ceph_auth_client * ac,struct ceph_auth_handshake * auth,void * reply,int reply_len,u8 * session_key,int * session_key_len,u8 * con_secret,int * con_secret_len)601cd1a677cSIlya Dryomov int ceph_auth_handle_svc_reply_done(struct ceph_auth_client *ac,
602cd1a677cSIlya Dryomov struct ceph_auth_handshake *auth,
603cd1a677cSIlya Dryomov void *reply, int reply_len,
604cd1a677cSIlya Dryomov u8 *session_key, int *session_key_len,
605cd1a677cSIlya Dryomov u8 *con_secret, int *con_secret_len)
606cd1a677cSIlya Dryomov {
607cd1a677cSIlya Dryomov return ceph_auth_verify_authorizer_reply(ac, auth->authorizer,
608cd1a677cSIlya Dryomov reply, reply_len, session_key, session_key_len,
609cd1a677cSIlya Dryomov con_secret, con_secret_len);
610cd1a677cSIlya Dryomov }
611cd1a677cSIlya Dryomov EXPORT_SYMBOL(ceph_auth_handle_svc_reply_done);
612cd1a677cSIlya Dryomov
ceph_auth_handle_bad_authorizer(struct ceph_auth_client * ac,int peer_type,int used_proto,int result,const int * allowed_protos,int proto_cnt,const int * allowed_modes,int mode_cnt)613cd1a677cSIlya Dryomov bool ceph_auth_handle_bad_authorizer(struct ceph_auth_client *ac,
614cd1a677cSIlya Dryomov int peer_type, int used_proto, int result,
615cd1a677cSIlya Dryomov const int *allowed_protos, int proto_cnt,
616cd1a677cSIlya Dryomov const int *allowed_modes, int mode_cnt)
617cd1a677cSIlya Dryomov {
618cd1a677cSIlya Dryomov mutex_lock(&ac->mutex);
619cd1a677cSIlya Dryomov WARN_ON(used_proto != ac->protocol);
620cd1a677cSIlya Dryomov
621cd1a677cSIlya Dryomov if (result == -EOPNOTSUPP) {
622cd1a677cSIlya Dryomov if (!contains(allowed_protos, proto_cnt, ac->protocol)) {
623cd1a677cSIlya Dryomov pr_err("auth protocol '%s' not allowed by %s\n",
624cd1a677cSIlya Dryomov ceph_auth_proto_name(ac->protocol),
625cd1a677cSIlya Dryomov ceph_entity_type_name(peer_type));
626cd1a677cSIlya Dryomov goto not_allowed;
627cd1a677cSIlya Dryomov }
628cd1a677cSIlya Dryomov if (!contains(allowed_modes, mode_cnt, ac->preferred_mode) &&
629cd1a677cSIlya Dryomov (ac->fallback_mode == CEPH_CON_MODE_UNKNOWN ||
630cd1a677cSIlya Dryomov !contains(allowed_modes, mode_cnt, ac->fallback_mode))) {
631cd1a677cSIlya Dryomov pr_err("preferred mode '%s' not allowed by %s\n",
632cd1a677cSIlya Dryomov ceph_con_mode_name(ac->preferred_mode),
633cd1a677cSIlya Dryomov ceph_entity_type_name(peer_type));
634cd1a677cSIlya Dryomov if (ac->fallback_mode == CEPH_CON_MODE_UNKNOWN)
635cd1a677cSIlya Dryomov pr_err("no fallback mode\n");
636cd1a677cSIlya Dryomov else
637cd1a677cSIlya Dryomov pr_err("fallback mode '%s' not allowed by %s\n",
638cd1a677cSIlya Dryomov ceph_con_mode_name(ac->fallback_mode),
639cd1a677cSIlya Dryomov ceph_entity_type_name(peer_type));
640cd1a677cSIlya Dryomov goto not_allowed;
641cd1a677cSIlya Dryomov }
642cd1a677cSIlya Dryomov }
643cd1a677cSIlya Dryomov
644cd1a677cSIlya Dryomov WARN_ON(result == -EOPNOTSUPP || result >= 0);
645cd1a677cSIlya Dryomov pr_err("auth protocol '%s' authorization to %s failed: %d\n",
646cd1a677cSIlya Dryomov ceph_auth_proto_name(ac->protocol),
647cd1a677cSIlya Dryomov ceph_entity_type_name(peer_type), result);
648cd1a677cSIlya Dryomov
649cd1a677cSIlya Dryomov if (ac->ops->invalidate_authorizer)
650cd1a677cSIlya Dryomov ac->ops->invalidate_authorizer(ac, peer_type);
651cd1a677cSIlya Dryomov
652cd1a677cSIlya Dryomov mutex_unlock(&ac->mutex);
653cd1a677cSIlya Dryomov return true;
654cd1a677cSIlya Dryomov
655cd1a677cSIlya Dryomov not_allowed:
656cd1a677cSIlya Dryomov mutex_unlock(&ac->mutex);
657cd1a677cSIlya Dryomov return false;
658cd1a677cSIlya Dryomov }
659cd1a677cSIlya Dryomov EXPORT_SYMBOL(ceph_auth_handle_bad_authorizer);
660