From: Xavi Hernandez Date: Sat, 26 Jul 2025 19:33:55 +0000 (+0200) Subject: libcephfs_proxy: implement client side support for embedded perms X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=68505c3e3a3f7c00bcc6a0b2e90932bf52d09575;p=ceph.git libcephfs_proxy: implement client side support for embedded perms Implement the code to handle embedded perms or not depending on a feature flag negotiated during connection. If embedded permissions are enabled, ceph_userperm_new() will allocate a local structure with the provided credentials instead of sending it to the server. ceph_userperm_destroy() will just destroy the allocated structure. If it's disabled, these function will work as any other function, sending the request to the server. Signed-off-by: Xavi Hernandez --- diff --git a/src/libcephfs_proxy/libcephfs_proxy.c b/src/libcephfs_proxy/libcephfs_proxy.c index 6b898d06dee..2d9fc51dfdc 100644 --- a/src/libcephfs_proxy/libcephfs_proxy.c +++ b/src/libcephfs_proxy/libcephfs_proxy.c @@ -8,6 +8,16 @@ #include "proxy_requests.h" #include "proxy_async.h" +/* We override the definition of UserPerm structure to contain internal user + * credentials. This is already a black box for libcephfs users, so this won't + * be noticed. */ +struct UserPerm { + uid_t uid; + gid_t gid; + uint32_t count; + gid_t groups[]; +}; + /* We override the definition of the ceph_mount_info structure to contain * internal proxy information. This is already a black box for libcephfs users, * so this won't be noticed. */ @@ -121,6 +131,31 @@ static int32_t proxy_check(struct ceph_mount_info *cmount, int32_t err, __err; \ }) +#define PROXY_EMBED_PERMS(_client, _req, _perms) \ + do { \ + if (proxy_embed_perms(_client, &_req.v0.userperm, _perms)) { \ + _req.v1.ngroups = _perms->count; \ + CEPH_BUFF_ADD(_req, _perms->groups, \ + sizeof(gid_t) * _perms->count); \ + } else { \ + _req.v1.ngroups = 0; \ + } \ + } while (false) + +static bool proxy_embed_perms(struct ceph_mount_info *cmount, + embedded_perms_t *embed, const UserPerm *perms) +{ + if ((cmount->neg.v1.enabled & PROXY_FEAT_EMBEDDED_PERMS) != 0) { + embed->uid = perms->uid; + embed->gid = perms->gid; + return true; + } + + embed->ptr = ptr_value(perms); + + return false; +} + __public int ceph_chdir(struct ceph_mount_info *cmount, const char *path) { CEPH_REQ(ceph_chdir, req, 1, ans, 0); @@ -264,10 +299,11 @@ __public int ceph_ll_create(struct ceph_mount_info *cmount, Inode *parent, unsigned want, unsigned lflags, const UserPerm *perms) { - CEPH_REQ(ceph_ll_create, req, 1, ans, 1); + CEPH_REQ(ceph_ll_create, req, 2, ans, 1); int32_t err; - req.v0.userperm.ptr = ptr_value(perms); + PROTO_VERSION(&cmount->neg, req, PROXY_PROTOCOL_V1); + req.v0.parent = ptr_value(parent); req.v0.mode = mode; req.v0.oflags = oflags; @@ -275,6 +311,8 @@ __public int ceph_ll_create(struct ceph_mount_info *cmount, Inode *parent, req.v0.flags = lflags; CEPH_STR_ADD(req, v0.name, name); + PROXY_EMBED_PERMS(cmount, req, perms); + CEPH_BUFF_ADD(ans, stx, sizeof(*stx)); err = CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_CREATE, req, ans); @@ -314,13 +352,16 @@ __public int ceph_ll_getattr(struct ceph_mount_info *cmount, struct Inode *in, struct ceph_statx *stx, unsigned int want, unsigned int flags, const UserPerm *perms) { - CEPH_REQ(ceph_ll_getattr, req, 0, ans, 1); + CEPH_REQ(ceph_ll_getattr, req, 1, ans, 1); + + PROTO_VERSION(&cmount->neg, req, PROXY_PROTOCOL_V1); - req.v0.userperm.ptr = ptr_value(perms); req.v0.inode = ptr_value(in); req.v0.want = want; req.v0.flags = flags; + PROXY_EMBED_PERMS(cmount, req, perms); + CEPH_BUFF_ADD(ans, stx, sizeof(*stx)); return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_GETATTR, req, ans); @@ -330,12 +371,15 @@ __public int ceph_ll_getxattr(struct ceph_mount_info *cmount, struct Inode *in, const char *name, void *value, size_t size, const UserPerm *perms) { - CEPH_REQ(ceph_ll_getxattr, req, 1, ans, 1); + CEPH_REQ(ceph_ll_getxattr, req, 2, ans, 1); + + PROTO_VERSION(&cmount->neg, req, PROXY_PROTOCOL_V1); - req.v0.userperm.ptr = ptr_value(perms); req.v0.inode = ptr_value(in); req.v0.size = size; + CEPH_STR_ADD(req, v0.name, name); + PROXY_EMBED_PERMS(cmount, req, perms); CEPH_BUFF_ADD(ans, value, size); @@ -346,12 +390,15 @@ __public int ceph_ll_link(struct ceph_mount_info *cmount, struct Inode *in, struct Inode *newparent, const char *name, const UserPerm *perms) { - CEPH_REQ(ceph_ll_link, req, 1, ans, 0); + CEPH_REQ(ceph_ll_link, req, 2, ans, 0); + + PROTO_VERSION(&cmount->neg, req, PROXY_PROTOCOL_V1); - req.v0.userperm.ptr = ptr_value(perms); req.v0.inode = ptr_value(in); req.v0.parent = ptr_value(newparent); + CEPH_STR_ADD(req, v0.name, name); + PROXY_EMBED_PERMS(cmount, req, perms); return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_LINK, req, ans); } @@ -360,13 +407,16 @@ __public int ceph_ll_listxattr(struct ceph_mount_info *cmount, struct Inode *in, char *list, size_t buf_size, size_t *list_size, const UserPerm *perms) { - CEPH_REQ(ceph_ll_listxattr, req, 0, ans, 1); + CEPH_REQ(ceph_ll_listxattr, req, 1, ans, 1); int32_t err; - req.v0.userperm.ptr = ptr_value(perms); + PROTO_VERSION(&cmount->neg, req, PROXY_PROTOCOL_V1); + req.v0.inode = ptr_value(in); req.v0.size = buf_size; + PROXY_EMBED_PERMS(cmount, req, perms); + CEPH_BUFF_ADD(ans, list, buf_size); err = CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_LISTXATTR, req, ans); @@ -382,14 +432,17 @@ __public int ceph_ll_lookup(struct ceph_mount_info *cmount, Inode *parent, struct ceph_statx *stx, unsigned want, unsigned flags, const UserPerm *perms) { - CEPH_REQ(ceph_ll_lookup, req, 1, ans, 1); + CEPH_REQ(ceph_ll_lookup, req, 2, ans, 1); int32_t err; - req.v0.userperm.ptr = ptr_value(perms); + PROTO_VERSION(&cmount->neg, req, PROXY_PROTOCOL_V1); + req.v0.parent = ptr_value(parent); req.v0.want = want; req.v0.flags = flags; + CEPH_STR_ADD(req, v0.name, name); + PROXY_EMBED_PERMS(cmount, req, perms); CEPH_BUFF_ADD(ans, stx, sizeof(*stx)); @@ -453,15 +506,18 @@ __public int ceph_ll_mkdir(struct ceph_mount_info *cmount, Inode *parent, struct ceph_statx *stx, unsigned want, unsigned flags, const UserPerm *perms) { - CEPH_REQ(ceph_ll_mkdir, req, 1, ans, 1); + CEPH_REQ(ceph_ll_mkdir, req, 2, ans, 1); int32_t err; - req.v0.userperm.ptr = ptr_value(perms); + PROTO_VERSION(&cmount->neg, req, PROXY_PROTOCOL_V1); + req.v0.parent = ptr_value(parent); req.v0.mode = mode; req.v0.want = want; req.v0.flags = flags; + CEPH_STR_ADD(req, v0.name, name); + PROXY_EMBED_PERMS(cmount, req, perms); CEPH_BUFF_ADD(ans, stx, sizeof(*stx)); @@ -478,16 +534,19 @@ __public int ceph_ll_mknod(struct ceph_mount_info *cmount, Inode *parent, Inode **out, struct ceph_statx *stx, unsigned want, unsigned flags, const UserPerm *perms) { - CEPH_REQ(ceph_ll_mknod, req, 1, ans, 1); + CEPH_REQ(ceph_ll_mknod, req, 2, ans, 1); int32_t err; - req.v0.userperm.ptr = ptr_value(perms); + PROTO_VERSION(&cmount->neg, req, PROXY_PROTOCOL_V1); + req.v0.parent = ptr_value(parent); req.v0.mode = mode; req.v0.rdev = rdev; req.v0.want = want; req.v0.flags = flags; + CEPH_STR_ADD(req, v0.name, name); + PROXY_EMBED_PERMS(cmount, req, perms); CEPH_BUFF_ADD(ans, stx, sizeof(*stx)); @@ -502,13 +561,16 @@ __public int ceph_ll_mknod(struct ceph_mount_info *cmount, Inode *parent, __public int ceph_ll_open(struct ceph_mount_info *cmount, struct Inode *in, int flags, struct Fh **fh, const UserPerm *perms) { - CEPH_REQ(ceph_ll_open, req, 0, ans, 0); + CEPH_REQ(ceph_ll_open, req, 1, ans, 0); int32_t err; - req.v0.userperm.ptr = ptr_value(perms); + PROTO_VERSION(&cmount->neg, req, PROXY_PROTOCOL_V1); + req.v0.inode = ptr_value(in); req.v0.flags = flags; + PROXY_EMBED_PERMS(cmount, req, perms); + err = CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_OPEN, req, ans); if (err >= 0) { *fh = value_ptr(ans.v0.fh); @@ -521,12 +583,15 @@ __public int ceph_ll_opendir(struct ceph_mount_info *cmount, struct Inode *in, struct ceph_dir_result **dirpp, const UserPerm *perms) { - CEPH_REQ(ceph_ll_opendir, req, 0, ans, 0); + CEPH_REQ(ceph_ll_opendir, req, 1, ans, 0); int32_t err; - req.v0.userperm.ptr = ptr_value(perms); + PROTO_VERSION(&cmount->neg, req, PROXY_PROTOCOL_V1); + req.v0.inode = ptr_value(in); + PROXY_EMBED_PERMS(cmount, req, perms); + err = CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_OPENDIR, req, ans); if (err >= 0) { *dirpp = value_ptr(ans.v0.dir); @@ -561,12 +626,15 @@ __public int ceph_ll_read(struct ceph_mount_info *cmount, struct Fh *filehandle, __public int ceph_ll_readlink(struct ceph_mount_info *cmount, struct Inode *in, char *buf, size_t bufsize, const UserPerm *perms) { - CEPH_REQ(ceph_ll_readlink, req, 0, ans, 1); + CEPH_REQ(ceph_ll_readlink, req, 1, ans, 1); + + PROTO_VERSION(&cmount->neg, req, PROXY_PROTOCOL_V1); - req.v0.userperm.ptr = ptr_value(perms); req.v0.inode = ptr_value(in); req.v0.size = bufsize; + PROXY_EMBED_PERMS(cmount, req, perms); + CEPH_BUFF_ADD(ans, buf, bufsize); return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_READLINK, req, ans); @@ -586,11 +654,14 @@ __public int ceph_ll_removexattr(struct ceph_mount_info *cmount, struct Inode *in, const char *name, const UserPerm *perms) { - CEPH_REQ(ceph_ll_removexattr, req, 1, ans, 0); + CEPH_REQ(ceph_ll_removexattr, req, 2, ans, 0); + + PROTO_VERSION(&cmount->neg, req, PROXY_PROTOCOL_V1); - req.v0.userperm.ptr = ptr_value(perms); req.v0.inode = ptr_value(in); + CEPH_STR_ADD(req, v0.name, name); + PROXY_EMBED_PERMS(cmount, req, perms); return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_REMOVEXATTR, req, ans); } @@ -600,13 +671,16 @@ __public int ceph_ll_rename(struct ceph_mount_info *cmount, struct Inode *newparent, const char *newname, const UserPerm *perms) { - CEPH_REQ(ceph_ll_rename, req, 2, ans, 0); + CEPH_REQ(ceph_ll_rename, req, 3, ans, 0); + + PROTO_VERSION(&cmount->neg, req, PROXY_PROTOCOL_V1); - req.v0.userperm.ptr = ptr_value(perms); req.v0.old_parent = ptr_value(parent); req.v0.new_parent = ptr_value(newparent); + CEPH_STR_ADD(req, v0.old_name, name); CEPH_STR_ADD(req, v0.new_name, newname); + PROXY_EMBED_PERMS(cmount, req, perms); return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_RENAME, req, ans); } @@ -624,11 +698,14 @@ __public void ceph_rewinddir(struct ceph_mount_info *cmount, __public int ceph_ll_rmdir(struct ceph_mount_info *cmount, struct Inode *in, const char *name, const UserPerm *perms) { - CEPH_REQ(ceph_ll_rmdir, req, 1, ans, 0); + CEPH_REQ(ceph_ll_rmdir, req, 2, ans, 0); + + PROTO_VERSION(&cmount->neg, req, PROXY_PROTOCOL_V1); - req.v0.userperm.ptr = ptr_value(perms); req.v0.parent = ptr_value(in); + CEPH_STR_ADD(req, v0.name, name); + PROXY_EMBED_PERMS(cmount, req, perms); return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_RMDIR, req, ans); } @@ -637,12 +714,15 @@ __public int ceph_ll_setattr(struct ceph_mount_info *cmount, struct Inode *in, struct ceph_statx *stx, int mask, const UserPerm *perms) { - CEPH_REQ(ceph_ll_setattr, req, 1, ans, 0); + CEPH_REQ(ceph_ll_setattr, req, 2, ans, 0); + + PROTO_VERSION(&cmount->neg, req, PROXY_PROTOCOL_V1); - req.v0.userperm.ptr = ptr_value(perms); req.v0.inode = ptr_value(in); req.v0.mask = mask; + CEPH_BUFF_ADD(req, stx, sizeof(*stx)); + PROXY_EMBED_PERMS(cmount, req, perms); return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_SETATTR, req, ans); } @@ -651,14 +731,17 @@ __public int ceph_ll_setxattr(struct ceph_mount_info *cmount, struct Inode *in, const char *name, const void *value, size_t size, int flags, const UserPerm *perms) { - CEPH_REQ(ceph_ll_setxattr, req, 2, ans, 0); + CEPH_REQ(ceph_ll_setxattr, req, 3, ans, 0); + + PROTO_VERSION(&cmount->neg, req, PROXY_PROTOCOL_V1); - req.v0.userperm.ptr = ptr_value(perms); req.v0.inode = ptr_value(in); req.v0.size = size; req.v0.flags = flags; + CEPH_STR_ADD(req, v0.name, name); CEPH_BUFF_ADD(req, value, size); + PROXY_EMBED_PERMS(cmount, req, perms); return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_SETXATTR, req, ans); } @@ -680,15 +763,18 @@ __public int ceph_ll_symlink(struct ceph_mount_info *cmount, Inode *in, struct ceph_statx *stx, unsigned want, unsigned flags, const UserPerm *perms) { - CEPH_REQ(ceph_ll_symlink, req, 2, ans, 1); + CEPH_REQ(ceph_ll_symlink, req, 3, ans, 1); int32_t err; - req.v0.userperm.ptr = ptr_value(perms); + PROTO_VERSION(&cmount->neg, req, PROXY_PROTOCOL_V1); + req.v0.parent = ptr_value(in); req.v0.want = want; req.v0.flags = flags; + CEPH_STR_ADD(req, v0.name, name); CEPH_STR_ADD(req, v0.target, value); + PROXY_EMBED_PERMS(cmount, req, perms); CEPH_BUFF_ADD(req, stx, sizeof(*stx)); @@ -703,11 +789,14 @@ __public int ceph_ll_symlink(struct ceph_mount_info *cmount, Inode *in, __public int ceph_ll_unlink(struct ceph_mount_info *cmount, struct Inode *in, const char *name, const UserPerm *perms) { - CEPH_REQ(ceph_ll_unlink, req, 1, ans, 0); + CEPH_REQ(ceph_ll_unlink, req, 2, ans, 0); + + PROTO_VERSION(&cmount->neg, req, PROXY_PROTOCOL_V1); - req.v0.userperm.ptr = ptr_value(perms); req.v0.parent = ptr_value(in); + CEPH_STR_ADD(req, v0.name, name); + PROXY_EMBED_PERMS(cmount, req, perms); return CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_UNLINK, req, ans); } @@ -716,13 +805,16 @@ __public int ceph_ll_walk(struct ceph_mount_info *cmount, const char *name, Inode **i, struct ceph_statx *stx, unsigned int want, unsigned int flags, const UserPerm *perms) { - CEPH_REQ(ceph_ll_walk, req, 1, ans, 1); + CEPH_REQ(ceph_ll_walk, req, 2, ans, 1); int32_t err; - req.v0.userperm.ptr = ptr_value(perms); + PROTO_VERSION(&cmount->neg, req, PROXY_PROTOCOL_V1); + req.v0.want = want; req.v0.flags = flags; + CEPH_STR_ADD(req, v0.path, name); + PROXY_EMBED_PERMS(cmount, req, perms); CEPH_BUFF_ADD(ans, stx, sizeof(*stx)); @@ -833,27 +925,56 @@ __public void ceph_userperm_destroy(UserPerm *perms) { CEPH_REQ(ceph_userperm_destroy, req, 0, ans, 0); - req.v0.userperm = ptr_value(perms); + /* We need to make use of the negotiation of the global mount since we + * don't have access to cmount here. Both negotiations should have + * the same setting for the embedded perms feature. */ + if ((global_cmount.neg.v1.enabled & PROXY_FEAT_EMBEDDED_PERMS) != 0) { + proxy_free(perms); + } else { + req.v0.userperm = ptr_value(perms); - CEPH_RUN(&global_cmount, LIBCEPHFSD_OP_USERPERM_DESTROY, req, ans); + CEPH_RUN(&global_cmount, LIBCEPHFSD_OP_USERPERM_DESTROY, req, + ans); + } } __public UserPerm *ceph_userperm_new(uid_t uid, gid_t gid, int ngids, gid_t *gidlist) { CEPH_REQ(ceph_userperm_new, req, 1, ans, 0); + UserPerm *perms; int32_t err; + err = proxy_global_connect(); + if (err < 0) { + errno = -err; + return NULL; + } + + /* We need to make use of the negotiation of the global mount since we + * don't have access to cmount here. Both negotiations should have + * the same setting for the embedded perms feature. */ + if ((global_cmount.neg.v1.enabled & PROXY_FEAT_EMBEDDED_PERMS) != 0) { + perms = proxy_malloc(sizeof(UserPerm) + sizeof(gid_t) * ngids); + if (perms == NULL) { + errno = -ENOMEM; + return NULL; + } + + perms->uid = uid; + perms->gid = gid; + perms->count = ngids; + memcpy(perms->groups, gidlist, sizeof(gid_t) * ngids); + + return perms; + } + req.v0.uid = uid; req.v0.gid = gid; req.v0.groups = ngids; CEPH_BUFF_ADD(req, gidlist, sizeof(gid_t) * ngids); - err = proxy_global_connect(); - if (err >= 0) { - err = CEPH_RUN(&global_cmount, LIBCEPHFSD_OP_USERPERM_NEW, req, - ans); - } + err = CEPH_RUN(&global_cmount, LIBCEPHFSD_OP_USERPERM_NEW, req, ans); if (err >= 0) { return value_ptr(ans.v0.userperm); } @@ -905,6 +1026,11 @@ __public UserPerm *ceph_mount_perms(struct ceph_mount_info *cmount) CEPH_REQ(ceph_mount_perms, req, 0, ans, 0); int32_t err; + if ((cmount->neg.v1.enabled & PROXY_FEAT_EMBEDDED_PERMS) != 0) { + errno = -EOPNOTSUPP; + return NULL; + } + err = CEPH_PROCESS(cmount, LIBCEPHFSD_OP_MOUNT_PERMS, req, ans); if (err < 0) { errno = -err;