]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
client: refactor permission check for opening files
authorYan, Zheng <zyan@redhat.com>
Tue, 29 Sep 2015 08:11:34 +0000 (16:11 +0800)
committerYan, Zheng <zyan@redhat.com>
Tue, 12 Jan 2016 09:21:01 +0000 (17:21 +0800)
Signed-off-by: Yan, Zheng <zyan@redhat.com>
src/client/Client.cc
src/client/Client.h
src/client/SyntheticClient.cc
src/client/fuse_ll.cc
src/libcephfs.cc

index e64e42a874a76d47cb82769b05f415ac417413d1..c3ddda64e12df6881df7b7622408f99abf3c56b2 100644 (file)
@@ -4829,29 +4829,64 @@ int Client::_getgrouplist(gid_t** sgids, int uid, int gid)
 #endif
 }
 
-int Client::check_permissions(Inode *in, int flags, int uid, int gid)
+int Client::inode_permission(Inode *in, uid_t uid, UserGroups& groups, unsigned want)
+{
+  if (uid == 0)
+    return 0;
+
+  int ret;
+  if (uid != in->uid && (in->mode & S_IRWXG)) {
+    ret = _posix_acl_permission(in, uid, groups, want);
+    if (ret != -EAGAIN)
+      return ret;
+  }
+
+  // check permissions before doing anything else
+  if (!in->check_mode(uid, groups, want))
+    return -EACCES;
+  return 0;
+}
+
+int Client::may_open(Inode *in, int flags, int uid, int gid)
 {
   unsigned want = 0;
+
   if ((flags & O_ACCMODE) == O_WRONLY)
     want = MAY_WRITE;
   else if ((flags & O_ACCMODE) == O_RDWR)
     want = MAY_READ | MAY_WRITE;
   else if ((flags & O_ACCMODE) == O_RDONLY)
     want = MAY_READ;
+  if (flags & O_TRUNC)
+    want |= MAY_WRITE;
 
+  if (uid < 0)
+    uid = get_uid();
+  if (gid < 0)
+    gid = get_gid();
   RequestUserGroups groups(this, uid, gid);
 
-  int ret = _posix_acl_permission(in, uid, groups, want);
-  if (ret != -EAGAIN)
-    return ret;
+  int r = 0;
+  switch (in->mode & S_IFMT) {
+    case S_IFLNK:
+      r = -ELOOP;
+      goto out;
+    case S_IFDIR:
+      if (want & MAY_WRITE) {
+       r = -EISDIR;
+       goto out;
+      }
+      break;
+  }
 
-  // check permissions before doing anything else
-  if (uid == 0 || in->check_mode(uid, groups, want))
-    ret = 0;
-  else
-    ret = -EACCES;
+  r = _getattr(in, CEPH_STAT_CAP_MODE, uid, gid);
+  if (r < 0)
+    goto out;
 
-  return ret;
+  r = inode_permission(in, uid, groups, want);
+out:
+  ldout(cct, 3) << __func__ << " " << in << " = " << r <<  dendl;
+  return r;
 }
 
 vinodeno_t Client::_get_vino(Inode *in)
@@ -7027,9 +7062,7 @@ int Client::open(const char *relpath, int flags, mode_t mode, int stripe_unit,
 
   if (!created) {
     // posix says we can only check permissions of existing files
-    uid_t uid = get_uid();
-    gid_t gid = get_gid();
-    r = check_permissions(in.get(), flags, uid, gid);
+    r = may_open(in.get(), flags);
     if (r < 0)
       goto out;
   }
@@ -10457,7 +10490,8 @@ uint64_t Client::ll_get_internal_offset(Inode *in, uint64_t blockno)
   return (blockno % stripes_per_object) * su;
 }
 
-int Client::ll_opendir(Inode *in, dir_result_t** dirpp, int uid, int gid)
+int Client::ll_opendir(Inode *in, int flags, dir_result_t** dirpp,
+                      int uid, int gid)
 {
   Mutex::Locker lock(client_lock);
 
@@ -10467,6 +10501,12 @@ int Client::ll_opendir(Inode *in, dir_result_t** dirpp, int uid, int gid)
   tout(cct) << "ll_opendir" << std::endl;
   tout(cct) << vino.ino.val << std::endl;
 
+  if (!cct->_conf->fuse_default_permissions) {
+    int r = may_open(in, flags, uid, gid);
+    if (r < 0)
+      return r;
+  }
+
   int r = 0;
   if (vino.snapid == CEPH_SNAPDIR) {
     *dirpp = new dir_result_t(in);
@@ -10520,7 +10560,7 @@ int Client::ll_open(Inode *in, int flags, Fh **fhp, int uid, int gid)
     gid = get_gid();
   }
   if (!cct->_conf->fuse_default_permissions) {
-    r = check_permissions(in, flags, uid, gid);
+    r = may_open(in, flags, uid, gid);
     if (r < 0)
       goto out;
   }
@@ -10574,7 +10614,7 @@ int Client::ll_create(Inode *parent, const char *name, mode_t mode,
   ldout(cct, 20) << "ll_create created = " << created << dendl;
   if (!created) {
     if (!cct->_conf->fuse_default_permissions) {
-      r = check_permissions(in.get(), flags, uid, gid);
+      r = may_open(in.get(), flags, uid, gid);
       if (r < 0) {
        if (fhp && *fhp) {
          int release_r = _release_fh(*fhp);
@@ -11595,9 +11635,7 @@ int Client::_posix_acl_permission(Inode *in, uid_t uid, UserGroups& groups, unsi
 
     if (in->xattrs.count(ACL_EA_ACCESS)) {
       const bufferptr& access_acl = in->xattrs[ACL_EA_ACCESS];
-      if (in->mode & S_IRWXG)
-       return posix_acl_permits(access_acl, in->uid, in->gid,
-                                uid, groups, want);
+      return posix_acl_permits(access_acl, in->uid, in->gid, uid, groups, want);
     }
   }
   return -EAGAIN;
index 16f525ad9aed49a1d312c7710908d45461835c1b..0752e864d01b84219ff3a05ed17648adb232397e 100644 (file)
@@ -782,7 +782,8 @@ private:
     int get_gids(const gid_t **out);
   };
 
-  int check_permissions(Inode *in, int flags, int uid, int gid);
+  int inode_permission(Inode *in, uid_t uid, UserGroups& groups, unsigned want);
+  int may_open(Inode *in, int flags, int uid=-1, int gid=-1);
   int _getgrouplist(gid_t **sgids, int uid=-1, int gid=-1);
 
   int check_data_pool_exist(string name, string value, const OSDMap *osdmap);
@@ -1025,7 +1026,7 @@ public:
                  int flags, int uid=-1, int gid=-1);
   int ll_removexattr(Inode *in, const char *name, int uid=-1, int gid=-1);
   int ll_listxattr(Inode *in, char *list, size_t size, int uid=-1, int gid=-1);
-  int ll_opendir(Inode *in, dir_result_t **dirpp, int uid = -1, int gid = -1);
+  int ll_opendir(Inode *in, int flags, dir_result_t **dirpp, int uid = -1, int gid = -1);
   int ll_releasedir(dir_result_t* dirp);
   int ll_fsyncdir(dir_result_t* dirp);
   int ll_readlink(Inode *in, char *buf, size_t bufsize, int uid = -1, int gid = -1);
index d2ab7ecc576fc1eac27448918faa40cd93536e20..9d1888b019e88a49967d5f9302ffa982ea29d293 100644 (file)
@@ -1348,7 +1348,7 @@ int SyntheticClient::play_trace(Trace& t, string& prefix, bool metadata_only)
       dir_result_t *dirp;
       if (ll_inos.count(i)) {
        i1 = client->ll_get_inode(vinodeno_t(ll_inos[i],CEPH_NOSNAP));
-       if (client->ll_opendir(i1, &dirp) == 0)
+       if (client->ll_opendir(i1, O_RDONLY, &dirp) == 0)
          ll_dirs[r] = dirp;
        client->ll_put(i1);
       }
index 866a9ffd20bf5f06b295f5bd620166bd986b891c..77d696e7204499f57b5060ca1981a79e76914fb0 100644 (file)
@@ -266,7 +266,7 @@ static void fuse_ll_opendir(fuse_req_t req, fuse_ino_t ino,
   Inode *in = cfuse->iget(ino);
   void *dirp;
 
-  int r = cfuse->client->ll_opendir(in, (dir_result_t **)&dirp,
+  int r = cfuse->client->ll_opendir(in, fi->flags, (dir_result_t **)&dirp,
                                    ctx->uid, ctx->gid);
   if (r >= 0) {
     fi->fh = (long)dirp;
index 849b1c0a66505bb9ca040b10194083663ce97d14..6d8bee99e53de5098fd59e94db3a40d474278919 100644 (file)
@@ -1528,8 +1528,8 @@ extern "C" int ceph_ll_opendir(class ceph_mount_info *cmount,
                               struct ceph_dir_result **dirpp,
                               int uid, int gid)
 {
-  return (cmount->get_client()->ll_opendir(in, (dir_result_t**) dirpp, uid,
-                                          gid));
+  return (cmount->get_client()->ll_opendir(in, O_RDONLY, (dir_result_t**) dirpp,
+                                          uid, gid));
 }
 
 extern "C" int ceph_ll_releasedir(class ceph_mount_info *cmount,