[Devel] [PATCH RHEL8 COMMIT] fs/fuse kio: make pcs auth socket independent

Konstantin Khorenko khorenko at virtuozzo.com
Thu Oct 15 10:37:34 MSK 2020


The commit is pushed to "branch-rh8-4.18.0-193.6.3.vz8.4.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh8-4.18.0-193.6.3.vz8.4.13
------>
commit cb802bbeb20353e788c58aada2b15413e0702733
Author: Ildar Ismagilov <ildar.ismagilov at virtuozzo.com>
Date:   Thu Oct 15 10:37:34 2020 +0300

    fs/fuse kio: make pcs auth socket independent
    
    https://pmc.acronis.com/browse/VSTOR-4310
    
    Signed-off-by: Ildar Ismagilov <ildar.ismagilov at virtuozzo.com>
    Signed-off-by: Ildar Ismagilov <Ildar.Ismagilov at acronis.com>
---
 fs/fuse/Makefile                |   3 +-
 fs/fuse/kio/pcs/pcs_auth.c      | 465 ++++++++++++++++++++++++++++++++++++
 fs/fuse/kio/pcs/pcs_auth.h      |  12 +
 fs/fuse/kio/pcs/pcs_net.h       |   6 +
 fs/fuse/kio/pcs/pcs_sock_conn.c | 508 +---------------------------------------
 fs/fuse/kio/pcs/pcs_sock_io.c   |  65 +++++
 6 files changed, 553 insertions(+), 506 deletions(-)

diff --git a/fs/fuse/Makefile b/fs/fuse/Makefile
index 1dd2d73d48f6..8ac6c4cfe114 100644
--- a/fs/fuse/Makefile
+++ b/fs/fuse/Makefile
@@ -27,7 +27,8 @@ fuse_kio_pcs-objs := kio/pcs/pcs_fuse_kdirect.o \
 	kio/pcs/pcs_cs.o \
 	kio/pcs/fuse_io.o \
 	kio/pcs/fuse_stat.o \
-	kio/pcs/pcs_sock_conn.o
+	kio/pcs/pcs_sock_conn.o \
+	kio/pcs/pcs_auth.o
 
 fuse-objs := dev.o dir.o file.o inode.o control.o xattr.o acl.o readdir.o
 virtiofs-y += virtio_fs.o
diff --git a/fs/fuse/kio/pcs/pcs_auth.c b/fs/fuse/kio/pcs/pcs_auth.c
new file mode 100644
index 000000000000..5e891504a950
--- /dev/null
+++ b/fs/fuse/kio/pcs/pcs_auth.c
@@ -0,0 +1,465 @@
+#include <linux/fs.h>
+#include <linux/types.h>
+
+#include <crypto/hash.h>
+#include <crypto/md5.h>
+
+#include "pcs_types.h"
+#include "pcs_rpc.h"
+#include "pcs_auth.h"
+#include "log.h"
+
+#define PCS_CFG_DIR		"/etc/vstorage"
+#define AUTH_DIGEST_NAME	"digest"
+#define AUTH_DIGEST_NAME_LEN	(sizeof(AUTH_DIGEST_NAME) - 1)
+#define PCS_KEYPATH_FMT		(PCS_CFG_DIR"/clusters/%s/auth_digest.key")
+#define LOCK_FILE_PATH_FMT	(PCS_CFG_DIR"/clusters/%s/.digest_auth.lock")
+
+enum
+{
+	PCS_AUTH_INITIAL = 0,	/* Basic states of auth handshake required for establish SSL connection,
+				 * other authentication protocols can require more states
+				 */
+	PCS_AUTH_SEND_HELLO,	/* Client sends hello at connect */
+	PCS_AUTH_SEND_SRV_CERT,	/* Server sends its cert. to client */
+	PCS_AUTH_SEND_CN_CERT,	/* Client sends its cert. to server */
+	PCS_AUTH_SRV_ACCEPT,	/* Server accept client's cert. */
+};
+
+#define DIGEST_AUTH_ID_LEN 32
+#define DIGEST_SALT_LEN 16
+#define DIGEST_KEY_LEN 32
+
+__pre_packed struct digest_hello_msg {
+	unsigned char md5_cn[MD5_DIGEST_SIZE];
+} __packed;
+
+__pre_packed struct digest_srv_salt_msg {
+	unsigned char salt[DIGEST_SALT_LEN];
+	unsigned char id[DIGEST_AUTH_ID_LEN];
+} __packed;
+
+#define HMAC_SHA512_HSIZE 64U
+
+__pre_packed struct digest_hmac_msg {
+	unsigned int size;
+	unsigned char data[HMAC_SHA512_HSIZE];
+} __packed;
+
+__pre_packed struct digest_msg {
+	unsigned char id[DIGEST_AUTH_ID_LEN];
+	struct digest_hmac_msg hmac;
+} __packed;
+
+static int pcs_generate_hmac(u8 *key, size_t key_sz, u8 *in, size_t in_sz,
+			     u8 *out, u32 *out_sz)
+{
+	struct crypto_shash *hmacalg;
+	struct shash_desc *shash;
+	int ret;
+
+	hmacalg = crypto_alloc_shash("hmac(sha1)", 0, 0);
+	if (IS_ERR(hmacalg)) {
+		TRACE("hmacalg: could not allocate crypto %ld", PTR_ERR(hmacalg));
+		return PTR_ERR(hmacalg);
+	}
+
+	ret = crypto_shash_setkey(hmacalg, key, key_sz);
+	if (ret) {
+		TRACE("crypto_shash_setkey failed: err %d", ret);
+		goto fail1;
+	}
+
+	shash = kzalloc(sizeof(*shash) + crypto_shash_descsize(hmacalg),
+			GFP_NOIO);
+	if (!shash) {
+		ret = -ENOMEM;
+		goto fail1;
+	}
+
+	shash->tfm = hmacalg;
+	shash->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+	ret = crypto_shash_digest(shash, in, in_sz, out);
+	if (ret)
+		TRACE("crypto_shash_digest failed: %d", ret);
+
+	*out_sz = crypto_shash_alg(shash->tfm)->digestsize;
+	kfree(shash);
+fail1:
+	crypto_free_shash(hmacalg);
+	return ret;
+}
+
+static int pcs_validate_hmac(struct digest_msg *digest, u8 *key, size_t key_sz,
+			     u8 *data, u32 data_sz)
+{
+	u8 hmac[HMAC_SHA512_HSIZE];
+	int err;
+
+	err = pcs_generate_hmac(key, key_sz, digest->id, sizeof(digest->id),
+				hmac, &data_sz);
+	if (err)
+		return err;
+
+	return !memcmp(hmac, data, min(data_sz, HMAC_SHA512_HSIZE));
+}
+
+static int pcs_md5_hash(char *result, char *data, size_t len)
+{
+	struct crypto_shash *tfm;
+	struct shash_desc *desc;
+	int err;
+
+	tfm = crypto_alloc_shash("md5", 0, 0);
+	if(IS_ERR(tfm)) {
+		TRACE("md5: could not allocate crypto %ld", PTR_ERR(tfm));
+		return PTR_ERR(tfm);
+	}
+
+	desc = kzalloc(sizeof(*desc) + crypto_shash_descsize(tfm),
+		       GFP_NOIO);
+	if (!desc) {
+		err = -ENOMEM;
+		goto fail1;
+	}
+
+	desc->tfm = tfm;
+	desc->flags = 0;
+
+	err = crypto_shash_init(desc);
+	if (err)
+		goto fail2;
+	err = crypto_shash_update(desc, data, len);
+	if (err)
+		goto fail2;
+	err = crypto_shash_final(desc, result);
+fail2:
+	kfree(desc);
+fail1:
+	crypto_free_shash(tfm);
+
+	return err;
+}
+
+static struct file *lock_key_file(char *cluster_name)
+{
+	char lockfile[sizeof(LOCK_FILE_PATH_FMT) + NAME_MAX];
+	struct file_lock *lock;
+	struct file *f;
+	int err;
+
+	snprintf(lockfile, sizeof(lockfile) - 1, LOCK_FILE_PATH_FMT,
+		 cluster_name);
+	f = filp_open(lockfile, O_CREAT | O_RDONLY | O_CLOEXEC,
+		      S_IRUSR | S_IRGRP | S_IROTH);
+	if (IS_ERR(f))
+		return f;
+
+	lock = locks_alloc_lock();
+	if (!lock) {
+		filp_close(f, NULL);
+		return ERR_PTR(-ENOMEM);
+	}
+	lock->fl_file = f;
+	lock->fl_pid = current->tgid;
+	lock->fl_flags = FL_FLOCK/* | FL_SLEEP*/;
+	lock->fl_type = F_RDLCK;
+	lock->fl_end = OFFSET_MAX;
+
+	err = locks_lock_file_wait(f, lock);
+	if (err < 0) {
+		filp_close(f, NULL);
+		return ERR_PTR(err);
+	}
+	return f;
+}
+
+static int pcs_load_keyfile_auth(char *cluster_name, u8 *key_out, u32 len)
+{
+	char keyfile[sizeof(PCS_KEYPATH_FMT) + NAME_MAX];
+	struct file *f, *flock;
+	u64 offs = 0;
+	int err;
+
+	flock = lock_key_file(cluster_name);
+	if (IS_ERR(flock)) {
+		TRACE("Lock keyfile failed: %ld", PTR_ERR(flock));
+		return PTR_ERR(flock);
+	}
+
+	snprintf(keyfile, sizeof(keyfile) - 1, PCS_KEYPATH_FMT, cluster_name);
+
+	f = filp_open(keyfile, O_RDONLY, 0);
+	if (IS_ERR(f)) {
+		err = PTR_ERR(f);
+		TRACE("Can't open keyfile auth: %s, err: %d", keyfile, err);
+		goto out;
+	}
+
+	err = kernel_read(f, key_out, len, &offs);
+	if (err < 0) {
+		TRACE("Can't read keyfile: %s, err: %d", keyfile, err);
+	} else if (err != len)
+		TRACE("Can't read full key(req: %d, read: %d)", len, err);
+	filp_close(f, NULL);
+out:
+	filp_close(flock, NULL);
+
+	return err < 0 ? err : 0;
+}
+
+#define __str_len(s) (ARRAY_SIZE(s) - sizeof(*(s)))
+
+/* Multiple payloads are supported. They are expected to have fixed alignment in between. */
+#define PCS_RPC_AUTH_PAYLOAD_ALIGN 8
+
+#define PCS_BUILD_VERSION "unknown"
+#define MAX_BUILD_VERSION_LENGTH 30
+
+static struct {
+	struct pcs_rpc_payload p;
+	char build_version[MAX_BUILD_VERSION_LENGTH+1];
+} s_version_data = {
+	{
+		.len = __str_len(PCS_BUILD_VERSION),
+		.type = PCS_RPC_BUILD_VERSION_PAYLOAD,
+	},
+	.build_version = PCS_BUILD_VERSION
+};
+
+static inline unsigned rpc_auth_payload_size(struct pcs_rpc_payload const* p) {
+	return sizeof(*p) + p->len;
+}
+
+static inline unsigned rpc_auth_payload_size_aligned(struct pcs_rpc_payload const* p) {
+	return round_up(rpc_auth_payload_size(p), PCS_RPC_AUTH_PAYLOAD_ALIGN);
+}
+
+static inline struct pcs_rpc_payload* rpc_auth_payload_next(struct pcs_rpc_payload* p) {
+	return (void*)p + rpc_auth_payload_size_aligned(p);
+}
+
+#define PCS_RPC_DIGEST_PAYLOAD 13
+
+struct pcs_rpc_auth
+{
+	struct pcs_rpc_hdr hdr;
+
+	PCS_CLUSTER_ID_T cluster_id;	/* Cluster identity */
+	PCS_NODE_ID_T sender_id;	/* Identity of sender */
+	PCS_NODE_ID_T recipient_id;	/* Expected identity of recipient */
+	u8 sender_role;			/* Role of sender (TEST/CN/CS/MDS) */
+	u8 recipient_role;		/* Expected role of recipient */
+	u8 flags;			/* Flags */
+	u8 state;			/* State of auth handshake */
+	u32 version;			/* Protocol version */
+	struct pcs_host_info host;
+	u32 reserved[3];
+	u32 npayloads;
+	struct pcs_rpc_payload payload;
+} __attribute__((aligned(8)));
+
+
+#define PCS_RPC_AUTH_REQ 8
+#define PCS_RPC_AUTH_RESP (PCS_RPC_AUTH_REQ | PCS_RPC_DIRECTION)
+
+static int send_auth_msg(struct pcs_rpc *ep, void *data, size_t size, int state)
+{
+	struct pcs_rpc_engine *eng = ep->eng;
+	struct pcs_netio *netio = (struct pcs_netio *)ep->conn;
+	struct pcs_rpc_auth *au;
+	size_t msg_sz = sizeof(struct pcs_rpc_auth) +
+			round_up(size, PCS_RPC_AUTH_PAYLOAD_ALIGN) +
+			rpc_auth_payload_size_aligned(&s_version_data.p);
+	struct pcs_msg *msg;
+	int err;
+
+	msg = pcs_rpc_alloc_output_msg(msg_sz);
+	if (!msg) {
+		TRACE("Can't alloc auth msg");
+		return -ENOMEM;
+	}
+
+	au = (struct pcs_rpc_auth *)msg->_inline_buffer;
+	*au = (struct pcs_rpc_auth) {
+		.hdr.type = PCS_RPC_AUTH_REQ,
+		.hdr.len = msg_sz,
+		.cluster_id = eng->cluster_id,
+		.sender_id = eng->local_id,
+		.recipient_id = ep->peer_id,
+		.recipient_role = ep->peer_role,
+		.version = PCS_VERSION_CURRENT,
+		.state = state,
+		.host = eng->my_host,
+		.npayloads = 2,
+	};
+	pcs_rpc_get_new_xid(eng, &au->hdr.xid);
+
+	if (size) {
+		au->payload.type = PCS_RPC_DIGEST_PAYLOAD;
+		au->payload.len = size;
+		memcpy(au + 1, data, size);
+	}
+	memcpy(rpc_auth_payload_next(&au->payload), &s_version_data,
+	       rpc_auth_payload_size(&s_version_data.p));
+
+	if (!(ep->flags & PCS_RPC_F_PEER_ID))
+		au->flags |= PCS_RPC_AUTH_F_VOID_RECIPIENT;
+	if (!(eng->flags & PCS_KNOWN_MYID)) {
+		au->flags |= PCS_RPC_AUTH_F_VOID_SENDER;
+		if (ep->flags & PCS_RPC_F_ACQ_ID)
+			au->flags |= PCS_RPC_AUTH_F_ACQ_SENDER;
+	}
+
+	if (!(eng->flags & PCS_KNOWN_CLUSTERID))
+		au->flags |= PCS_RPC_AUTH_F_VOID_CLUSTERID;
+
+	TRACE("state=%d, type=%d, len=%d, msg_sz: %lu",
+	      au->state, au->payload.type, au->payload.len, msg_sz);
+
+	err = netio->tops->sync_send(netio, msg);
+	if (err)
+		TRACE("Can't send au msg, err: %d", err);
+	pcs_free_msg(msg);
+
+	return err;
+}
+
+static int recv_auth_msg(struct pcs_rpc *ep, void *data, size_t size, int state)
+{
+	struct pcs_netio *netio = (struct pcs_netio *)ep->conn;
+	struct pcs_rpc_auth *au;
+	size_t fixed_sz = sizeof(struct pcs_rpc_auth) +
+			  round_up(size, PCS_RPC_AUTH_PAYLOAD_ALIGN);
+	struct pcs_msg *msg = NULL;
+	int err;
+
+	err = netio->tops->sync_recv(netio, &msg);
+	if (err) {
+		TRACE("Can't recv auth msg, err: %d", err);
+		goto fail;
+	}
+	au = (struct pcs_rpc_auth *)msg->_inline_buffer;
+
+	/* Fatal stream format error */
+	if (msg->size < fixed_sz || au->hdr.len < fixed_sz ||
+	    au->hdr.len > ep->params.max_msg_size) {
+		TRACE("Bad message header %d %u %u\n", msg->size, au->hdr.len,
+		      au->hdr.type);
+		err = -EPROTO;
+		goto fail;
+	}
+	WARN_ON_ONCE(au->hdr.type != PCS_RPC_AUTH_RESP &&
+		     au->hdr.type != PCS_RPC_ERROR_RESP);
+
+	TRACE("state=%d, payloads:=%u, type=%d, len=%d", au->state,
+	      au->npayloads, au->payload.type, au->payload.len);
+	if (au->state != state) {
+		TRACE("Unexpected state %d, should be %d", au->state, state);
+		err = -EPROTO;
+		goto fail;
+	}
+	if (au->flags & PCS_RPC_AUTH_F_VOID_CLUSTERID)
+		TRACE("Wrong: auth void cluster");
+
+	WARN_ON_ONCE(au->npayloads != 2);
+	if (au->payload.len != size) {
+		TRACE("Wrong auth payload %u %u, data_sz: %lu\n",
+		      au->payload.len, au->payload.type, size);
+		err = -EPROTO;
+		goto fail;
+	}
+	WARN_ON_ONCE(au->payload.type != PCS_RPC_DIGEST_PAYLOAD);
+	memcpy(data, &au->payload + 1, size);
+
+fail:
+	if (msg)
+		pcs_free_msg(msg);
+	return err;
+}
+
+static int pcs_do_auth_digest(struct pcs_rpc *ep, char *cluster_name)
+{
+	struct {
+		u8 key[DIGEST_KEY_LEN];
+		u8 salt[DIGEST_SALT_LEN];
+	} auth_cfg;
+	struct digest_hello_msg hi;
+	struct digest_srv_salt_msg slt;
+	struct digest_msg digest;
+	struct digest_hmac_msg hmac;
+	int err;
+
+	err = pcs_load_keyfile_auth(cluster_name, (u8*)&auth_cfg, sizeof(auth_cfg));
+	if (err)
+		return err;
+
+	err = pcs_md5_hash(hi.md5_cn, cluster_name, strlen(cluster_name));
+	if (err) {
+		TRACE("Can't calculate md5 from cluster name, err: %d", err);
+		return err;
+	}
+
+	err = send_auth_msg(ep, &hi, sizeof(hi), PCS_AUTH_SEND_HELLO);
+	if (err) {
+		TRACE("Can't send hello auth msg, err: %d", err);
+		return err;
+	}
+
+	err = recv_auth_msg(ep, &slt, sizeof(slt), PCS_AUTH_SEND_SRV_CERT);
+	if (err) {
+		TRACE("Can't receive salt auth msg, err: %d", err);
+		return err;
+	}
+
+	if (memcmp(slt.salt, auth_cfg.salt, sizeof(auth_cfg.salt))) {
+		TRACE("Server use different salt");
+		return -EPROTO;
+	}
+
+	get_random_bytes(digest.id, sizeof(digest.id));
+	digest.hmac.size = sizeof(digest.hmac.data);
+	err = pcs_generate_hmac(auth_cfg.key, sizeof(auth_cfg.key), slt.id,
+				sizeof(slt.id), digest.hmac.data,
+				&digest.hmac.size);
+	if (err) {
+		TRACE("HMAC generate fail %d", err);
+		return err;
+	}
+
+	err = send_auth_msg(ep, &digest, sizeof(digest), PCS_AUTH_SEND_CN_CERT);
+	if (err) {
+		TRACE("Can't send digest msg, err: %d", err);
+		return err;
+	}
+
+	err = recv_auth_msg(ep, &hmac, sizeof(hmac), PCS_AUTH_SRV_ACCEPT);
+	if (err) {
+		TRACE("Can't receive hmac auth msg, err: %d", err);
+		return err;
+	}
+
+	if (!pcs_validate_hmac(&digest, auth_cfg.key, sizeof(auth_cfg.key),
+			       hmac.data, hmac.size)) {
+		TRACE("Received bad digest");
+		return -EPROTO;
+	}
+
+	err = send_auth_msg(ep, NULL, 0, PCS_AUTH_SRV_ACCEPT + 1);
+	if (err)
+		TRACE("Can't send auth srv accept msg, err: %d", err);
+
+	return err;
+}
+
+int rpc_client_start_auth(struct pcs_rpc *ep, int auth_type, char *cluster_name)
+{
+	switch (auth_type) {
+		case PCS_AUTH_DIGEST:
+			return pcs_do_auth_digest(ep, cluster_name);
+		default:
+			BUG();
+	}
+	return -EOPNOTSUPP;
+}
diff --git a/fs/fuse/kio/pcs/pcs_auth.h b/fs/fuse/kio/pcs/pcs_auth.h
new file mode 100644
index 000000000000..4247c6193ba6
--- /dev/null
+++ b/fs/fuse/kio/pcs/pcs_auth.h
@@ -0,0 +1,12 @@
+#ifndef _PCS_AUTH_H_
+#define _PCS_AUTH_H_ 1
+
+#include "pcs_rpc.h"
+
+enum {
+	PCS_AUTH_DIGEST = 0,
+};
+
+int rpc_client_start_auth(struct pcs_rpc *ep, int auth_type, char *cluster_name);
+
+#endif /* _PCS_AUTH_H_ */
diff --git a/fs/fuse/kio/pcs/pcs_net.h b/fs/fuse/kio/pcs/pcs_net.h
index 64a20be482f3..9ab7df1bb0ee 100644
--- a/fs/fuse/kio/pcs/pcs_net.h
+++ b/fs/fuse/kio/pcs/pcs_net.h
@@ -32,6 +32,12 @@ struct pcs_netio_tops {
 
 	/* get next timeout */
 	unsigned long (*next_timeout)(struct pcs_netio *netio);
+
+	/* synchronous send message */
+	int   (*sync_send)(struct pcs_netio *netio, struct pcs_msg *msg);
+
+	/* synchronous receive message */
+	int   (*sync_recv)(struct pcs_netio *netio, struct pcs_msg **msg);
 };
 
 struct pcs_netio {
diff --git a/fs/fuse/kio/pcs/pcs_sock_conn.c b/fs/fuse/kio/pcs/pcs_sock_conn.c
index 83043177fb92..756875864a8e 100644
--- a/fs/fuse/kio/pcs/pcs_sock_conn.c
+++ b/fs/fuse/kio/pcs/pcs_sock_conn.c
@@ -3,209 +3,14 @@
 #include <linux/types.h>
 #include <linux/tcp.h>
 
-#include <crypto/hash.h>
-#include <crypto/md5.h>
-
 #include "pcs_types.h"
 #include "pcs_sock_io.h"
 #include "pcs_rpc.h"
 #include "pcs_cluster.h"
+#include "pcs_auth.h"
 #include "log.h"
 #include "fuse_ktrace.h"
 
-#define PCS_CFG_DIR		"/etc/vstorage"
-#define AUTH_DIGEST_NAME	"digest"
-#define AUTH_DIGEST_NAME_LEN	(sizeof(AUTH_DIGEST_NAME) - 1)
-#define PCS_KEYPATH_FMT		(PCS_CFG_DIR"/clusters/%s/auth_digest.key")
-#define LOCK_FILE_PATH_FMT	(PCS_CFG_DIR"/clusters/%s/.digest_auth.lock")
-
-enum
-{
-	PCS_AUTH_INITIAL = 0,	/* Basic states of auth handshake required for establish SSL connection,
-				 * other authentication protocols can require more states
-				 */
-	PCS_AUTH_SEND_HELLO,	/* Client sends hello at connect */
-	PCS_AUTH_SEND_SRV_CERT,	/* Server sends its cert. to client */
-	PCS_AUTH_SEND_CN_CERT,	/* Client sends its cert. to server */
-	PCS_AUTH_SRV_ACCEPT,	/* Server accept client's cert. */
-};
-
-#define DIGEST_AUTH_ID_LEN 32
-#define DIGEST_SALT_LEN 16
-#define DIGEST_KEY_LEN 32
-
-__pre_packed struct digest_hello_msg {
-	unsigned char md5_cn[MD5_DIGEST_SIZE];
-} __packed;
-
-__pre_packed struct digest_srv_salt_msg {
-	unsigned char salt[DIGEST_SALT_LEN];
-	unsigned char id[DIGEST_AUTH_ID_LEN];
-} __packed;
-
-#define HMAC_SHA512_HSIZE 64U
-
-__pre_packed struct digest_hmac_msg {
-	unsigned int size;
-	unsigned char data[HMAC_SHA512_HSIZE];
-} __packed;
-
-__pre_packed struct digest_msg {
-	unsigned char id[DIGEST_AUTH_ID_LEN];
-	struct digest_hmac_msg hmac;
-} __packed;
-
-static int pcs_generate_hmac(u8 *key, size_t key_sz, u8 *in, size_t in_sz,
-			     u8 *out, u32 *out_sz)
-{
-	struct crypto_shash *hmacalg;
-	struct shash_desc *shash;
-	int ret;
-
-	hmacalg = crypto_alloc_shash("hmac(sha1)", 0, 0);
-	if (IS_ERR(hmacalg)) {
-		TRACE("hmacalg: could not allocate crypto %ld", PTR_ERR(hmacalg));
-		return PTR_ERR(hmacalg);
-	}
-
-	ret = crypto_shash_setkey(hmacalg, key, key_sz);
-	if (ret) {
-		TRACE("crypto_shash_setkey failed: err %d", ret);
-		goto fail1;
-	}
-
-	shash = kzalloc(sizeof(*shash) + crypto_shash_descsize(hmacalg),
-			GFP_KERNEL);
-	if (!shash) {
-		ret = -ENOMEM;
-		goto fail1;
-	}
-
-	shash->tfm = hmacalg;
-	shash->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
-
-	ret = crypto_shash_digest(shash, in, in_sz, out);
-	if (ret)
-		TRACE("crypto_shash_digest failed: %d", ret);
-
-	*out_sz = crypto_shash_alg(shash->tfm)->digestsize;
-	kfree(shash);
-fail1:
-	crypto_free_shash(hmacalg);
-	return ret;
-}
-
-static int pcs_validate_hmac(struct digest_msg *digest, u8 *key, size_t key_sz,
-			     u8 *data, u32 data_sz)
-{
-	u8 hmac[HMAC_SHA512_HSIZE];
-	int err;
-
-	err = pcs_generate_hmac(key, key_sz, digest->id, sizeof(digest->id),
-				hmac, &data_sz);
-	if (err)
-		return err;
-
-	return !memcmp(hmac, data, min(data_sz, HMAC_SHA512_HSIZE));
-}
-
-static int pcs_md5_hash(char *result, char *data, size_t len)
-{
-	struct shash_desc *desc;
-	int err;
-
-	desc = kmalloc(sizeof(*desc), GFP_KERNEL);
-	if (!desc)
-		return -ENOMEM;
-
-	desc->tfm = crypto_alloc_shash("md5", 0, CRYPTO_ALG_ASYNC);
-	if(IS_ERR(desc->tfm)) {
-		err = PTR_ERR(desc->tfm);
-		goto fail1;
-	}
-
-	err = crypto_shash_init(desc);
-	if (err)
-		goto fail2;
-	err = crypto_shash_update(desc, data, len);
-	if (err)
-		goto fail2;
-	err = crypto_shash_final(desc, result);
-fail2:
-	crypto_free_shash(desc->tfm);
-fail1:
-	kfree(desc);
-
-	return err;
-}
-
-static struct file *lock_key_file(char *cluster_name)
-{
-	char lockfile[sizeof(LOCK_FILE_PATH_FMT) + NAME_MAX];
-	struct file_lock *lock;
-	struct file *f;
-	int err;
-
-	snprintf(lockfile, sizeof(lockfile) - 1, LOCK_FILE_PATH_FMT,
-		 cluster_name);
-	f = filp_open(lockfile, O_CREAT | O_RDONLY | O_CLOEXEC,
-		      S_IRUSR | S_IRGRP | S_IROTH);
-	if (IS_ERR(f))
-		return f;
-
-	lock = locks_alloc_lock();
-	if (!lock) {
-		filp_close(f, NULL);
-		return ERR_PTR(-ENOMEM);
-	}
-	lock->fl_file = f;
-	lock->fl_pid = current->tgid;
-	lock->fl_flags = FL_FLOCK;
-	lock->fl_type = F_WRLCK;
-	lock->fl_end = OFFSET_MAX;
-
-	err = locks_lock_file_wait(f, lock);
-	if (err < 0) {
-		filp_close(f, NULL);
-		return ERR_PTR(err);
-	}
-	return f;
-}
-
-static int pcs_load_keyfile_auth(char *cluster_name, u8 *key_out, u32 len)
-{
-	char keyfile[sizeof(PCS_KEYPATH_FMT) + NAME_MAX];
-	struct file *f, *flock;
-	u64 offs = 0;
-	int err;
-
-	flock = lock_key_file(cluster_name);
-	if (IS_ERR(flock)) {
-		TRACE("Lock keyfile failed: %ld", PTR_ERR(flock));
-		return PTR_ERR(flock);
-	}
-
-	snprintf(keyfile, sizeof(keyfile) - 1, PCS_KEYPATH_FMT, cluster_name);
-
-	f = filp_open(keyfile, O_RDONLY, 0);
-	if (IS_ERR(f)) {
-		err = PTR_ERR(f);
-		TRACE("Can't open keyfile auth: %s, err: %d", keyfile, err);
-		goto out;
-	}
-
-	err = kernel_read(f, key_out, len, &offs);
-	if (err < 0) {
-		TRACE("Can't read keyfile: %s, err: %d", keyfile, err);
-	} else if (err != len)
-		TRACE("Can't read full key(req: %d, read: %d)", len, err);
-	filp_close(f, NULL);
-out:
-	filp_close(flock, NULL);
-
-	return err < 0 ? err : 0;
-}
-
 static inline void pcs_sock_keepalive(struct socket *sock)
 {
 	int val;
@@ -240,314 +45,6 @@ static inline void pcs_sock_nodelay(struct socket *sock)
 			  sizeof(val));
 }
 
-static int send_buf(struct socket *sock, u8 *buf, size_t size)
-{
-	struct msghdr msg = {
-		.msg_flags = MSG_WAITALL | MSG_NOSIGNAL,
-	};
-	struct kvec iov = {
-		.iov_base = buf,
-		.iov_len = size,
-	};
-	int ret = kernel_sendmsg(sock, &msg, &iov, 1, size);
-	return ret < 0 ? ret : 0;
-}
-
-static int recv_buf(struct socket *sock, u8 *buf, size_t size)
-{
-	struct msghdr msg = {
-		.msg_flags = MSG_WAITALL | MSG_NOSIGNAL,
-	};
-	struct kvec iov = {
-		.iov_base = buf,
-		.iov_len = size,
-	};
-	int ret = kernel_recvmsg(sock, &msg, &iov, 1, size,
-				 MSG_WAITALL | MSG_NOSIGNAL);
-	if (ret < 0)
-		return ret;
-	return ret != size ? -EPROTO : 0;
-}
-
-#define __str_len(s) (ARRAY_SIZE(s) - sizeof(*(s)))
-
-/* Multiple payloads are supported. They are expected to have fixed alignment in between. */
-#define PCS_RPC_AUTH_PAYLOAD_ALIGN 8
-
-#define PCS_BUILD_VERSION "unknown"
-#define MAX_BUILD_VERSION_LENGTH 30
-
-static struct {
-	struct pcs_rpc_payload p;
-	char build_version[MAX_BUILD_VERSION_LENGTH+1];
-} s_version_data = {
-	{
-		.len = __str_len(PCS_BUILD_VERSION),
-		.type = PCS_RPC_BUILD_VERSION_PAYLOAD,
-	},
-	.build_version = PCS_BUILD_VERSION
-};
-
-static inline unsigned rpc_auth_payload_size(struct pcs_rpc_payload const* p) {
-	return sizeof(*p) + p->len;
-}
-
-static inline unsigned rpc_auth_payload_size_aligned(struct pcs_rpc_payload const* p) {
-	return round_up(rpc_auth_payload_size(p), PCS_RPC_AUTH_PAYLOAD_ALIGN);
-}
-
-static inline struct pcs_rpc_payload* rpc_auth_payload_next(struct pcs_rpc_payload* p) {
-	return (void*)p + rpc_auth_payload_size_aligned(p);
-}
-
-#define PCS_RPC_DIGEST_PAYLOAD 13
-
-struct pcs_rpc_auth
-{
-	struct pcs_rpc_hdr hdr;
-
-	PCS_CLUSTER_ID_T cluster_id;	/* Cluster identity */
-	PCS_NODE_ID_T sender_id;	/* Identity of sender */
-	PCS_NODE_ID_T recipient_id;	/* Expected identity of recipient */
-	u8 sender_role;			/* Role of sender (TEST/CN/CS/MDS) */
-	u8 recipient_role;		/* Expected role of recipient */
-	u8 flags;			/* Flags */
-	u8 state;			/* State of auth handshake */
-	u32 version;			/* Protocol version */
-	struct pcs_host_info host;
-	u32 reserved[3];
-	u32 npayloads;
-	struct pcs_rpc_payload payload;
-} __attribute__((aligned(8)));
-
-
-#define PCS_RPC_AUTH_REQ 8
-#define PCS_RPC_AUTH_RESP (PCS_RPC_AUTH_REQ | PCS_RPC_DIRECTION)
-
-static int send_auth_msg(struct pcs_rpc *ep, void *data, size_t size, int state)
-{
-	struct pcs_rpc_engine *eng = ep->eng;
-	struct pcs_sockio *sio = sio_from_ioconn(ep->conn);
-	struct pcs_rpc_auth *au;
-	size_t msg_sz = sizeof(struct pcs_rpc_auth) +
-			round_up(size, PCS_RPC_AUTH_PAYLOAD_ALIGN) +
-			rpc_auth_payload_size_aligned(&s_version_data.p);
-	struct pcs_msg *msg;
-	int err;
-
-	msg = pcs_rpc_alloc_output_msg(msg_sz);
-	if (!msg) {
-		TRACE("Can't alloc auth msg");
-		return -ENOMEM;
-	}
-
-	au = (struct pcs_rpc_auth *)msg->_inline_buffer;
-	*au = (struct pcs_rpc_auth) {
-		.hdr.type = PCS_RPC_AUTH_REQ,
-		.hdr.len = msg_sz,
-		.cluster_id = eng->cluster_id,
-		.sender_id = eng->local_id,
-		.recipient_id = ep->peer_id,
-		.recipient_role = ep->peer_role,
-		.version = PCS_VERSION_CURRENT,
-		.state = state,
-		.host = eng->my_host,
-		.npayloads = 2,
-	};
-	pcs_rpc_get_new_xid(eng, &au->hdr.xid);
-
-	if (size) {
-		au->payload.type = PCS_RPC_DIGEST_PAYLOAD;
-		au->payload.len = size;
-		memcpy(au + 1, data, size);
-	}
-	memcpy(rpc_auth_payload_next(&au->payload), &s_version_data,
-	       rpc_auth_payload_size(&s_version_data.p));
-
-	if (!(ep->flags & PCS_RPC_F_PEER_ID))
-		au->flags |= PCS_RPC_AUTH_F_VOID_RECIPIENT;
-	if (!(eng->flags & PCS_KNOWN_MYID)) {
-		au->flags |= PCS_RPC_AUTH_F_VOID_SENDER;
-		if (ep->flags & PCS_RPC_F_ACQ_ID)
-			au->flags |= PCS_RPC_AUTH_F_ACQ_SENDER;
-	}
-
-	if (!(eng->flags & PCS_KNOWN_CLUSTERID))
-		au->flags |= PCS_RPC_AUTH_F_VOID_CLUSTERID;
-
-	TRACE("state=%d, type=%d, len=%d, msg_sz: %lu",
-	      au->state, au->payload.type, au->payload.len, msg_sz);
-
-	err = send_buf(sio->socket, (u8*)au, msg_sz);
-	if (err)
-		TRACE("Can't send au msg, err: %d", err);
-	pcs_free_msg(msg);
-
-	return err;
-}
-
-static int recv_auth_msg(struct pcs_rpc *ep, void *data, size_t size, int state)
-{
-	struct pcs_sockio *sio = sio_from_ioconn(ep->conn);
-	struct pcs_rpc_auth *au;
-	size_t fixed_sz = sizeof(struct pcs_rpc_auth) +
-			  round_up(size, PCS_RPC_AUTH_PAYLOAD_ALIGN);
-	struct pcs_msg *msg;
-	int err;
-
-	msg = pcs_rpc_alloc_output_msg(fixed_sz);
-	if (!msg) {
-		TRACE("Can't alloc auth msg");
-		return -ENOMEM;
-	}
-
-	err = recv_buf(sio->socket, msg->_inline_buffer, fixed_sz);
-	if (err) {
-		TRACE("Can't recv auth msg(%d), err: %lu", err, fixed_sz);
-		goto fail;
-	}
-	au = (struct pcs_rpc_auth *)msg->_inline_buffer;
-
-	/* Fatal stream format error */
-	if (au->hdr.len < sizeof(au->hdr) || au->hdr.len > ep->params.max_msg_size) {
-		TRACE("Bad message header %u %u\n", au->hdr.len, au->hdr.type);
-		err = -EPROTO;
-		goto fail;
-	}
-	WARN_ON_ONCE(au->hdr.type != PCS_RPC_AUTH_RESP &&
-		     au->hdr.type != PCS_RPC_ERROR_RESP);
-
-	TRACE("state=%d, payloads:=%u, type=%d, len=%d", au->state,
-	      au->npayloads, au->payload.type, au->payload.len);
-	if (au->state != state) {
-		TRACE("Unexpected state %d, should be %d", au->state, state);
-		err = -EPROTO;
-		goto fail;
-	}
-	if (au->flags & PCS_RPC_AUTH_F_VOID_CLUSTERID)
-		TRACE("Wrong: auth void cluster");
-
-	WARN_ON_ONCE(au->npayloads != 2);
-	if (au->payload.len != size) {
-		TRACE("Wrong auth payload %u %u, data_sz: %lu\n",
-		       au->payload.len, au->payload.type, size);
-		err = -EPROTO;
-		goto fail;
-	}
-	WARN_ON_ONCE(au->payload.type != PCS_RPC_DIGEST_PAYLOAD);
-	memcpy(data, &au->payload + 1, size);
-
-	/* Load rest of the message if needed */
-	if (au->hdr.len > fixed_sz) {
-		size_t rest_sz = au->hdr.len - fixed_sz;
-		while (rest_sz) {
-			size_t recv_sz = min(fixed_sz, rest_sz);
-			err = recv_buf(sio->socket, msg->_inline_buffer,
-				       recv_sz);
-			if (err) {
-				TRACE("Can't recv auth msg(%d), err: %lu",
-				      err, recv_sz);
-				goto fail;
-			}
-			rest_sz -= recv_sz;
-		}
-	}
-
-fail:
-	pcs_free_msg(msg);
-	return err;
-}
-
-static int pcs_do_auth_digest(struct pcs_rpc *ep)
-{
-	struct {
-		u8 key[DIGEST_KEY_LEN];
-		u8 salt[DIGEST_SALT_LEN];
-	} auth_cfg;
-	struct digest_hello_msg hi;
-	struct digest_srv_salt_msg slt;
-	struct digest_msg digest;
-	struct digest_hmac_msg hmac;
-	char *cluster_name = cc_from_rpc(ep->eng)->cluster_name;
-	int err;
-
-	err = pcs_load_keyfile_auth(cluster_name, (u8*)&auth_cfg, sizeof(auth_cfg));
-	if (err)
-		return err;
-
-	err = pcs_md5_hash(hi.md5_cn, cluster_name, strlen(cluster_name));
-	if (err) {
-		TRACE("Can't calculate md5 from cluster name, err: %d", err);
-		return err;
-	}
-
-	err = send_auth_msg(ep, &hi, sizeof(hi), PCS_AUTH_SEND_HELLO);
-	if (err) {
-		TRACE("Can't send hello auth msg, err: %d", err);
-		return err;
-	}
-
-	err = recv_auth_msg(ep, &slt, sizeof(slt), PCS_AUTH_SEND_SRV_CERT);
-	if (err) {
-		TRACE("Can't receive salt auth msg, err: %d", err);
-		return err;
-	}
-
-	if (memcmp(slt.salt, auth_cfg.salt, sizeof(auth_cfg.salt))) {
-		TRACE("Server use different salt");
-		return -EPROTO;
-	}
-
-	get_random_bytes(digest.id, sizeof(digest.id));
-	digest.hmac.size = sizeof(digest.hmac.data);
-	err = pcs_generate_hmac(auth_cfg.key, sizeof(auth_cfg.key), slt.id,
-				sizeof(slt.id), digest.hmac.data,
-				&digest.hmac.size);
-	if (err) {
-		TRACE("HMAC generate fail %d", err);
-		return err;
-	}
-
-	err = send_auth_msg(ep, &digest, sizeof(digest), PCS_AUTH_SEND_CN_CERT);
-	if (err) {
-		TRACE("Can't send digest msg, err: %d", err);
-		return err;
-	}
-
-	err = recv_auth_msg(ep, &hmac, sizeof(hmac), PCS_AUTH_SRV_ACCEPT);
-	if (err) {
-		TRACE("Can't receive hmac auth msg, err: %d", err);
-		return err;
-	}
-
-	if (!pcs_validate_hmac(&digest, auth_cfg.key, sizeof(auth_cfg.key),
-			       hmac.data, hmac.size)) {
-		TRACE("Received bad digest");
-		return -EPROTO;
-	}
-
-	err = send_auth_msg(ep, NULL, 0, PCS_AUTH_SRV_ACCEPT + 1);
-	if (err)
-		TRACE("Can't send auth srv accept msg, err: %d", err);
-
-	return err;
-}
-
-enum {
-	PCS_AUTH_DIGEST = 0,
-};
-
-static int rpc_client_start_auth(struct pcs_rpc *ep, int auth_type)
-{
-	switch (auth_type) {
-		case PCS_AUTH_DIGEST:
-			return pcs_do_auth_digest(ep);
-		default:
-			BUG();
-	}
-	return -EOPNOTSUPP;
-}
-
 int pcs_netaddr2sockaddr(PCS_NET_ADDR_T const* addr, struct sockaddr *sa, int *salen)
 {
 	BUG_ON(!sa);
@@ -632,7 +129,8 @@ void pcs_sockconnect_start(struct pcs_rpc *ep)
 		ep->flags |= PCS_RPC_F_PEER_ID;
 
 	ep->state = PCS_RPC_AUTH;
-	err = rpc_client_start_auth(ep, PCS_AUTH_DIGEST);
+	err = rpc_client_start_auth(ep, PCS_AUTH_DIGEST,
+				    cc_from_rpc(ep->eng)->cluster_name);
 	if (err < 0) {
 		FUSE_KLOG(cc_from_rpc(ep->eng)->fc, LOG_ERR,
 			  "Authorization failed: %d", err);
diff --git a/fs/fuse/kio/pcs/pcs_sock_io.c b/fs/fuse/kio/pcs/pcs_sock_io.c
index 33feb33ecec0..00a935c61faf 100644
--- a/fs/fuse/kio/pcs/pcs_sock_io.c
+++ b/fs/fuse/kio/pcs/pcs_sock_io.c
@@ -755,6 +755,69 @@ static unsigned long pcs_sock_next_timeout(struct pcs_netio *netio)
 	return msg->start_time + sio->send_timeout;
 }
 
+static int pcs_sock_send_buf(struct socket *sock, void *buf, size_t size)
+{
+	struct msghdr msg = {
+		.msg_flags = MSG_WAITALL | MSG_NOSIGNAL,
+	};
+	struct kvec iov = {
+		.iov_base = buf,
+		.iov_len = size,
+	};
+	int ret = kernel_sendmsg(sock, &msg, &iov, 1, size);
+	return ret < 0 ? ret : 0;
+}
+
+static int pcs_sock_recv_buf(struct socket *sock, void *buf, size_t size)
+{
+	struct msghdr msg = {
+		.msg_flags = MSG_WAITALL | MSG_NOSIGNAL,
+	};
+	struct kvec iov = {
+		.iov_base = buf,
+		.iov_len = size,
+	};
+	int ret = kernel_recvmsg(sock, &msg, &iov, 1, size,
+				 MSG_WAITALL | MSG_NOSIGNAL);
+	if (ret < 0)
+		return ret;
+	return ret != size ? -EPROTO : 0;
+}
+
+static int pcs_sock_sync_send(struct pcs_netio *netio, struct pcs_msg *msg)
+{
+	struct pcs_sockio *sio = sio_from_netio(netio);
+
+	return pcs_sock_send_buf(sio->socket, msg->_inline_buffer, msg->size);
+}
+
+static int pcs_sock_sync_recv(struct pcs_netio *netio, struct pcs_msg **msg)
+{
+	struct pcs_sockio *sio = sio_from_netio(netio);
+	struct pcs_rpc_hdr hdr;
+	int err;
+
+	err = pcs_sock_recv_buf(sio->socket, &hdr, sizeof(hdr));
+	if (err)
+		return err;
+
+	*msg = pcs_rpc_alloc_output_msg(hdr.len);
+	if (!*msg)
+		return -ENOMEM;
+
+	memcpy((*msg)->_inline_buffer, &hdr, sizeof(hdr));
+
+	err = pcs_sock_recv_buf(sio->socket, (*msg)->_inline_buffer +
+				sizeof(hdr), hdr.len - sizeof(hdr));
+	if (err) {
+		pcs_free_msg(*msg);
+		*msg = NULL;
+		return err;
+	}
+
+	return 0;
+}
+
 struct pcs_netio_tops pcs_sock_netio_tops = {
 	.throttle		= pcs_sock_throttle,
 	.unthrottle		= pcs_sock_unthrottle,
@@ -764,4 +827,6 @@ struct pcs_netio_tops pcs_sock_netio_tops = {
 	.xmit			= pcs_sockio_xmit,
 	.flush			= pcs_sockio_flush,
 	.next_timeout		= pcs_sock_next_timeout,
+	.sync_send		= pcs_sock_sync_send,
+	.sync_recv		= pcs_sock_sync_recv,
 };


More information about the Devel mailing list