Commit 457117f0 authored by Jeff Layton's avatar Jeff Layton Committed by Ilya Dryomov
Browse files

ceph: add helpers for converting names for userland presentation



Define a new ceph_fname struct that we can use to carry information
about encrypted dentry names. Add helpers for working with these
objects, including ceph_fname_to_usr which formats an encrypted filename
for userland presentation.

[ xiubli: fix resulting name length check -- neither name_len nor
  ctext_len should exceed NAME_MAX ]

Signed-off-by: default avatarJeff Layton <jlayton@kernel.org>
Reviewed-by: default avatarXiubo Li <xiubli@redhat.com>
Reviewed-and-tested-by: default avatarLuís Henriques <lhenriques@suse.de>
Reviewed-by: default avatarMilind Changire <mchangir@redhat.com>
Signed-off-by: default avatarIlya Dryomov <idryomov@gmail.com>
parent c5267601
Loading
Loading
Loading
Loading
+77 −0
Original line number Diff line number Diff line
@@ -244,3 +244,80 @@ int ceph_encode_encrypted_fname(const struct inode *parent,
	dout("base64-encoded ciphertext name = %.*s\n", elen, buf);
	return elen;
}

/**
 * ceph_fname_to_usr - convert a filename for userland presentation
 * @fname: ceph_fname to be converted
 * @tname: temporary name buffer to use for conversion (may be NULL)
 * @oname: where converted name should be placed
 * @is_nokey: set to true if key wasn't available during conversion (may be NULL)
 *
 * Given a filename (usually from the MDS), format it for presentation to
 * userland. If @parent is not encrypted, just pass it back as-is.
 *
 * Otherwise, base64 decode the string, and then ask fscrypt to format it
 * for userland presentation.
 *
 * Returns 0 on success or negative error code on error.
 */
int ceph_fname_to_usr(const struct ceph_fname *fname, struct fscrypt_str *tname,
		      struct fscrypt_str *oname, bool *is_nokey)
{
	int ret;
	struct fscrypt_str _tname = FSTR_INIT(NULL, 0);
	struct fscrypt_str iname;

	if (!IS_ENCRYPTED(fname->dir)) {
		oname->name = fname->name;
		oname->len = fname->name_len;
		return 0;
	}

	/* Sanity check that the resulting name will fit in the buffer */
	if (fname->name_len > NAME_MAX || fname->ctext_len > NAME_MAX)
		return -EIO;

	ret = __fscrypt_prepare_readdir(fname->dir);
	if (ret)
		return ret;

	/*
	 * Use the raw dentry name as sent by the MDS instead of
	 * generating a nokey name via fscrypt.
	 */
	if (!fscrypt_has_encryption_key(fname->dir)) {
		memcpy(oname->name, fname->name, fname->name_len);
		oname->len = fname->name_len;
		if (is_nokey)
			*is_nokey = true;
		return 0;
	}

	if (fname->ctext_len == 0) {
		int declen;

		if (!tname) {
			ret = fscrypt_fname_alloc_buffer(NAME_MAX, &_tname);
			if (ret)
				return ret;
			tname = &_tname;
		}

		declen = ceph_base64_decode(fname->name, fname->name_len,
					    tname->name);
		if (declen <= 0) {
			ret = -EIO;
			goto out;
		}
		iname.name = tname->name;
		iname.len = declen;
	} else {
		iname.name = fname->ctext;
		iname.len = fname->ctext_len;
	}

	ret = fscrypt_fname_disk_to_usr(fname->dir, 0, 0, &iname, oname);
out:
	fscrypt_fname_free_buffer(&_tname);
	return ret;
}
+46 −0
Original line number Diff line number Diff line
@@ -13,6 +13,14 @@ struct ceph_fs_client;
struct ceph_acl_sec_ctx;
struct ceph_mds_request;

struct ceph_fname {
	struct inode	*dir;
	char		*name;		// b64 encoded, possibly hashed
	unsigned char	*ctext;		// binary crypttext (if any)
	u32		name_len;	// length of name buffer
	u32		ctext_len;	// length of crypttext
};

struct ceph_fscrypt_auth {
	__le32	cfa_version;
	__le32	cfa_blob_len;
@@ -71,6 +79,24 @@ void ceph_fscrypt_as_ctx_to_req(struct ceph_mds_request *req,
int ceph_encode_encrypted_fname(const struct inode *parent,
				struct dentry *dentry, char *buf);

static inline int ceph_fname_alloc_buffer(struct inode *parent,
					  struct fscrypt_str *fname)
{
	if (!IS_ENCRYPTED(parent))
		return 0;
	return fscrypt_fname_alloc_buffer(NAME_MAX, fname);
}

static inline void ceph_fname_free_buffer(struct inode *parent,
					  struct fscrypt_str *fname)
{
	if (IS_ENCRYPTED(parent))
		fscrypt_fname_free_buffer(fname);
}

int ceph_fname_to_usr(const struct ceph_fname *fname, struct fscrypt_str *tname,
		      struct fscrypt_str *oname, bool *is_nokey);

#else /* CONFIG_FS_ENCRYPTION */

static inline void ceph_fscrypt_set_ops(struct super_block *sb)
@@ -100,6 +126,26 @@ static inline int ceph_encode_encrypted_fname(const struct inode *parent,
{
	return -EOPNOTSUPP;
}

static inline int ceph_fname_alloc_buffer(struct inode *parent,
					  struct fscrypt_str *fname)
{
	return 0;
}

static inline void ceph_fname_free_buffer(struct inode *parent,
					  struct fscrypt_str *fname)
{
}

static inline int ceph_fname_to_usr(const struct ceph_fname *fname,
				    struct fscrypt_str *tname,
				    struct fscrypt_str *oname, bool *is_nokey)
{
	oname->name = fname->name;
	oname->len = fname->name_len;
	return 0;
}
#endif /* CONFIG_FS_ENCRYPTION */

#endif