]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph-client.git/commitdiff
ceph: add helpers for converting names for userland presentation
authorJeff Layton <jlayton@kernel.org>
Fri, 26 Mar 2021 16:26:18 +0000 (12:26 -0400)
committerJeff Layton <jlayton@kernel.org>
Tue, 31 May 2022 15:49:59 +0000 (11:49 -0400)
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.

Reviewed-by: Xiubo Li <xiubli@redhat.com>
Signed-off-by: Jeff Layton <jlayton@kernel.org>
fs/ceph/crypto.c
fs/ceph/crypto.h

index 921e62f860c4d8b97ab25675df6091f48cab3360..7e1f66b350954231f4ab34be1e4999b5144368e0 100644 (file)
@@ -234,3 +234,79 @@ int ceph_encode_encrypted_fname(const struct inode *parent, struct dentry *dentr
        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 > FSCRYPT_BASE64URL_CHARS(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 = fscrypt_base64url_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;
+}
index 8abf10604722c6e4589e2953bfd8ae527f0be532..f231d6e3ba0f6bf82a88ad7a05162e3b1ba2af2b 100644 (file)
@@ -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;
@@ -69,6 +77,22 @@ int ceph_fscrypt_prepare_context(struct inode *dir, struct inode *inode,
 void ceph_fscrypt_as_ctx_to_req(struct ceph_mds_request *req, struct ceph_acl_sec_ctx *as);
 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)
@@ -97,6 +121,23 @@ 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