Revert "Fix afs_AccessOK for dropbox case"
[openafs.git] / src / afs / VNOPS / afs_vnop_access.c
index 24912cb..0a31ac8 100644 (file)
  */
 
 #include <afsconfig.h>
-#include "../afs/param.h"
+#include "afs/param.h"
 
-RCSID("$Header$");
 
-#include "../afs/sysincludes.h"        /* Standard vendor system headers */
-#include "../afs/afsincludes.h"        /* Afs-based standard headers */
-#include "../afs/afs_stats.h" /* statistics */
-#include "../afs/afs_cbqueue.h"
-#include "../afs/nfsclient.h"
-#include "../afs/afs_osidnlc.h"
+#include "afs/sysincludes.h"   /* Standard vendor system headers */
+#include "afsincludes.h"       /* Afs-based standard headers */
+#include "afs/afs_stats.h"     /* statistics */
+#include "afs/afs_cbqueue.h"
+#include "afs/nfsclient.h"
+#include "afs/afs_osidnlc.h"
 
 #ifndef ANONYMOUSID
-#define ANONYMOUSID     32766 /* make sure this is same as in ptserver.h */
+#define ANONYMOUSID     32766  /* make sure this is same as in ptserver.h */
 #endif
 
 
@@ -51,53 +50,55 @@ static char fileModeMap[8] = {
 };
 
 /* avc must be held.  Returns bit map of mode bits.  Ignores file mode bits */
-afs_int32 afs_GetAccessBits (avc, arights, areq)
-    register struct vcache *avc;
-    register afs_int32 arights;
-    register struct vrequest *areq; 
+afs_int32
+afs_GetAccessBits(register struct vcache *avc, register afs_int32 arights,
+                 register struct vrequest *areq)
 {
     AFS_STATCNT(afs_GetAccessBits);
     /* see if anyuser has the required access bits */
-    if ((arights & avc->anyAccess) == arights) {
+    if ((arights & avc->f.anyAccess) == arights) {
        return arights;
     }
 
     /* look in per-pag cache */
-    if (avc->Access) {  /* not beautiful, but Sun's cc will tolerate it */
-      struct axscache *ac;
+    if (avc->Access) {         /* not beautiful, but Sun's cc will tolerate it */
+       struct axscache *ac;
 
-      ac = afs_FindAxs(avc->Access, areq->uid);
-      if (ac) {
-       return (arights & ac->axess);
-      }
+       ac = afs_FindAxs(avc->Access, areq->uid);
+       if (ac) {
+           return (arights & ac->axess);
+       }
     }
 
-    if (!(avc->states & CForeign)) { 
-      /* If there aren't any bits cached for this user (but the vnode
-       * _is_ cached, obviously), make sure this user has valid tokens
-       * before bothering with the RPC.  */
-      struct unixuser *tu;
-      extern struct unixuser *afs_FindUser();
-      tu = afs_FindUser( areq->uid, avc->fid.Cell, READ_LOCK );
-      if (!tu) {
-       return (arights & avc->anyAccess);
-      }
-      if ((tu->vid == UNDEFVID) || !(tu->states & UHasTokens) ||
-         (tu->states & UTokensBad)) {
-       afs_PutUser(tu, READ_LOCK);
-       return (arights & avc->anyAccess);
-      }
-      else {
-       afs_PutUser(tu, READ_LOCK);
-      }
+    if (!(avc->f.states & CForeign)) {
+       /* If there aren't any bits cached for this user (but the vnode
+        * _is_ cached, obviously), make sure this user has valid tokens
+        * before bothering with the RPC.  */
+       struct unixuser *tu;
+       tu = afs_FindUser(areq->uid, avc->f.fid.Cell, READ_LOCK);
+       if (!tu) {
+           return (arights & avc->f.anyAccess);
+       }
+       if ((tu->vid == UNDEFVID) || !(tu->states & UHasTokens)
+           || (tu->states & UTokensBad)) {
+           afs_PutUser(tu, READ_LOCK);
+           return (arights & avc->f.anyAccess);
+       } else {
+           afs_PutUser(tu, READ_LOCK);
+       }
     }
 
-    { /* Ok, user has valid tokens, go ask the server. */
-      struct AFSFetchStatus OutStatus;
-      afs_int32 code;
-    
-      code = afs_FetchStatus(avc, &avc->fid, areq, &OutStatus);
-      return (code ? 0 : OutStatus.CallerAccess & arights);
+    if (AFS_IS_DISCONNECTED && !AFS_IN_SYNC) {
+       /* If we get this far, we have to ask the network. But we can't, so
+        * they're out of luck... */
+       return 0;
+    } else
+    {                          /* Ok, user has valid tokens, go ask the server. */
+       struct AFSFetchStatus OutStatus;
+       afs_int32 code;
+
+       code = afs_FetchStatus(avc, &avc->f.fid, areq, &OutStatus);
+       return (code ? 0 : OutStatus.CallerAccess & arights);
     }
 }
 
@@ -105,10 +106,10 @@ afs_int32 afs_GetAccessBits (avc, arights, areq)
 /* the new access ok function.  AVC must be held but not locked. if avc is a
  * file, its parent need not be held, and should not be locked. */
 
-afs_AccessOK(avc, arights, areq, check_mode_bits)
-struct vcache *avc;
-afs_int32 arights, check_mode_bits;
-struct vrequest *areq; {
+int
+afs_AccessOK(struct vcache *avc, afs_int32 arights, struct vrequest *areq,
+            afs_int32 check_mode_bits)
+{
     register struct vcache *tvc;
     struct VenusFid dirFid;
     register afs_int32 mask;
@@ -117,11 +118,20 @@ struct vrequest *areq; {
 
     AFS_STATCNT(afs_AccessOK);
 
-    if ((vType(avc) == VDIR) || (avc->states & CForeign)) {
-      /* rights are just those from acl */
-      return (arights == afs_GetAccessBits(avc, arights, areq));
-    }
-    else {
+    if ((vType(avc) == VDIR) || (avc->f.states & CForeign)) {
+       /* rights are just those from acl */
+       if (afs_InReadDir(avc)) {
+           /* if we are already in readdir, then they may have read and
+            * lookup, and nothing else, and nevermind the real ACL.
+            * Otherwise we might end up with problems trying to call
+            * FetchStatus on the vnode readdir is working on, and that
+            * would be a real mess.
+            */
+           dirBits = PRSFS_LOOKUP | PRSFS_READ;
+           return (arights == (dirBits & arights));
+       }
+       return (arights == afs_GetAccessBits(avc, arights, areq));
+    } else {
        /* some rights come from dir and some from file.  Specifically, you 
         * have "a" rights to a file if you are its owner, which comes
         * back as "a" rights to the file. You have other rights just
@@ -130,20 +140,18 @@ struct vrequest *areq; {
         * rights for free. These rights will then be restricted by
         * the access mask. */
        dirBits = 0;
-       if (avc->parentVnode) {
-           dirFid.Cell = avc->fid.Cell;
-           dirFid.Fid.Volume = avc->fid.Fid.Volume;
-           dirFid.Fid.Vnode = avc->parentVnode;
-           dirFid.Fid.Unique = avc->parentUnique;
+       if (avc->f.parent.vnode) {
+           dirFid.Cell = avc->f.fid.Cell;
+           dirFid.Fid.Volume = avc->f.fid.Fid.Volume;
+           dirFid.Fid.Vnode = avc->f.parent.vnode;
+           dirFid.Fid.Unique = avc->f.parent.unique;
            /* Avoid this GetVCache call */
-           tvc = afs_GetVCache(&dirFid, areq, (afs_int32 *)0,
-                               (struct vcache*)0, WRITE_LOCK);
+           tvc = afs_GetVCache(&dirFid, areq, NULL, NULL);
            if (tvc) {
                dirBits = afs_GetAccessBits(tvc, arights, areq);
-               afs_PutVCache(tvc, WRITE_LOCK);
+               afs_PutVCache(tvc);
            }
-       }
-       else
+       } else
            dirBits = 0xffffffff;       /* assume OK; this is a race condition */
        if (arights & PRSFS_ADMINISTER)
            fileBits = afs_GetAccessBits(avc, arights, areq);
@@ -151,25 +159,28 @@ struct vrequest *areq; {
            fileBits = 0;       /* don't make call if results don't matter */
 
        /* compute basic rights in fileBits, taking A from file bits */
-       fileBits = (fileBits & PRSFS_ADMINISTER) | (dirBits & ~PRSFS_ADMINISTER);
+       fileBits =
+           (fileBits & PRSFS_ADMINISTER) | (dirBits & ~PRSFS_ADMINISTER);
 
        /* for files, throw in R and W if have I and A (owner).  This makes
-          insert-only dirs work properly */
-       if (vType(avc) != VDIR && (fileBits & (PRSFS_ADMINISTER | PRSFS_INSERT)) ==
+        * insert-only dirs work properly */
+       if (vType(avc) != VDIR
+           && (fileBits & (PRSFS_ADMINISTER | PRSFS_INSERT)) ==
            (PRSFS_ADMINISTER | PRSFS_INSERT))
            fileBits |= (PRSFS_READ | PRSFS_WRITE);
 
        if (check_mode_bits & CHECK_MODE_BITS) {
            /* owner mode bits are further restrictions on the access mode
-             * The mode bits are mapped to protection bits through the
-             * fileModeMap. If CMB_ALLOW_EXEC_AS_READ is set, it's from the
-             * NFS translator and we don't know if it's a read or execute
-             * on the NFS client, but both need to read the data.
-             */
-           mask = (avc->m.Mode & 0700) >> 6;   /* file restrictions to use */
+            * The mode bits are mapped to protection bits through the
+            * fileModeMap. If CMB_ALLOW_EXEC_AS_READ is set, it's from the
+            * NFS translator and we don't know if it's a read or execute
+            * on the NFS client, but both need to read the data.
+            */
+           mask = (avc->f.m.Mode & 0700) >> 6; /* file restrictions to use */
            fileBits &= ~fileModeMap[mask];
            if (check_mode_bits & CMB_ALLOW_EXEC_AS_READ) {
-                if (avc->m.Mode & 0100) fileBits |= PRSFS_READ;
+               if (avc->f.m.Mode & 0100)
+                   fileBits |= PRSFS_READ;
            }
        }
        return ((fileBits & arights) == arights);       /* true if all rights bits are on */
@@ -177,47 +188,75 @@ struct vrequest *areq; {
 }
 
 
-#if    defined(AFS_SUN5_ENV) || (defined(AFS_SGI_ENV) && !defined(AFS_SGI65_ENV))
-afs_access(OSI_VC_ARG(avc), amode, flags, acred)
-    int flags;         
+#if defined(AFS_SUN5_ENV) || (defined(AFS_SGI_ENV) && !defined(AFS_SGI65_ENV))
+int
+afs_access(OSI_VC_DECL(avc), register afs_int32 amode, int flags,
+          afs_ucred_t *acred)
 #else
-afs_access(OSI_VC_ARG(avc), amode, acred)
+int
+afs_access(OSI_VC_DECL(avc), register afs_int32 amode,
+          afs_ucred_t *acred)
 #endif
-    OSI_VC_DECL(avc);
-    register afs_int32 amode;
-    struct AFS_UCRED *acred; {
+{
     register afs_int32 code;
     struct vrequest treq;
     struct afs_fakestat_state fakestate;
-    OSI_VC_CONVERT(avc)
+    OSI_VC_CONVERT(avc);
 
     AFS_STATCNT(afs_access);
-    afs_Trace3(afs_iclSetp, CM_TRACE_ACCESS, ICL_TYPE_POINTER, avc, 
-               ICL_TYPE_INT32, amode,
-               ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length));
+    afs_Trace3(afs_iclSetp, CM_TRACE_ACCESS, ICL_TYPE_POINTER, avc,
+              ICL_TYPE_INT32, amode, ICL_TYPE_OFFSET,
+              ICL_HANDLE_OFFSET(avc->f.m.Length));
     afs_InitFakeStat(&fakestate);
-    if (code = afs_InitReq(&treq, acred)) return code;
+    if ((code = afs_InitReq(&treq, acred)))
+       return code;
+
+    AFS_DISCON_LOCK();
+
+    if (afs_fakestat_enable && avc->mvstat == 1) {
+       code = afs_TryEvalFakeStat(&avc, &fakestate, &treq);
+        if (code == 0 && avc->mvstat == 1) {
+           afs_PutFakeStat(&fakestate);
+           AFS_DISCON_UNLOCK();
+           return 0;
+        }
+    } else {
+       code = afs_EvalFakeStat(&avc, &fakestate, &treq);
+    }
 
-    code = afs_EvalFakeStat(&avc, &fakestate, &treq);
     if (code) {
        afs_PutFakeStat(&fakestate);
+       AFS_DISCON_UNLOCK();
        return code;
     }
 
-    code = afs_VerifyVCache(avc, &treq);
-    if (code) {
-      afs_PutFakeStat(&fakestate);
-      code = afs_CheckCode(code, &treq, 16);
-      return code; 
+    if (vType(avc) != VDIR || !afs_InReadDir(avc)) {
+       code = afs_VerifyVCache(avc, &treq);
+       if (code) {
+           afs_PutFakeStat(&fakestate);
+           AFS_DISCON_UNLOCK();
+           code = afs_CheckCode(code, &treq, 16);
+           return code;
+       }
     }
 
     /* if we're looking for write access and we have a read-only file system, report it */
-    if ((amode & VWRITE) && (avc->states & CRO)) {
+    if ((amode & VWRITE) && (avc->f.states & CRO)) {
        afs_PutFakeStat(&fakestate);
+       AFS_DISCON_UNLOCK();
        return EROFS;
     }
-    code = 1;          /* Default from here on in is access ok. */
-    if (avc->states & CForeign) {
+    
+    /* If we're looking for write access, and we're disconnected without logging, forget it */
+    if ((amode & VWRITE) && (AFS_IS_DISCONNECTED && !AFS_IS_DISCON_RW)) {
+        afs_PutFakeStat(&fakestate);
+       AFS_DISCON_UNLOCK();
+       printf("Network is down in afs_vnop_access\n");
+        return ENETDOWN;
+    }
+    
+    code = 1;                  /* Default from here on in is access ok. */
+    if (avc->f.states & CForeign) {
        /* In the dfs xlator the EXEC bit is mapped to LOOKUP */
        if (amode & VEXEC)
            code = afs_AccessOK(avc, PRSFS_LOOKUP, &treq, CHECK_MODE_BITS);
@@ -225,66 +264,70 @@ afs_access(OSI_VC_ARG(avc), amode, acred)
            code = afs_AccessOK(avc, PRSFS_WRITE, &treq, CHECK_MODE_BITS);
            if (code && (vType(avc) == VDIR)) {
                if (code)
-                   code = afs_AccessOK(avc, PRSFS_INSERT, &treq, CHECK_MODE_BITS);
-               if (!code) 
-                   code = afs_AccessOK(avc, PRSFS_DELETE, &treq, CHECK_MODE_BITS);
-           }   
-       }       
-       if (code && (amode & VREAD)) 
+                   code =
+                       afs_AccessOK(avc, PRSFS_INSERT, &treq,
+                                    CHECK_MODE_BITS);
+               if (!code)
+                   code =
+                       afs_AccessOK(avc, PRSFS_DELETE, &treq,
+                                    CHECK_MODE_BITS);
+           }
+       }
+       if (code && (amode & VREAD))
            code = afs_AccessOK(avc, PRSFS_READ, &treq, CHECK_MODE_BITS);
     } else {
        if (vType(avc) == VDIR) {
-           if (amode & VEXEC) 
-              code = afs_AccessOK(avc, PRSFS_LOOKUP, &treq, CHECK_MODE_BITS);
+           if (amode & VEXEC)
+               code =
+                   afs_AccessOK(avc, PRSFS_LOOKUP, &treq, CHECK_MODE_BITS);
            if (code && (amode & VWRITE)) {
-               code = afs_AccessOK(avc, PRSFS_INSERT, &treq, CHECK_MODE_BITS);
-               if (!code) 
-                  code = afs_AccessOK(avc, PRSFS_DELETE, &treq, CHECK_MODE_BITS);
+               code =
+                   afs_AccessOK(avc, PRSFS_INSERT, &treq, CHECK_MODE_BITS);
+               if (!code)
+                   code =
+                       afs_AccessOK(avc, PRSFS_DELETE, &treq,
+                                    CHECK_MODE_BITS);
            }
            if (code && (amode & VREAD))
-               code = afs_AccessOK(avc, PRSFS_LOOKUP, &treq, CHECK_MODE_BITS);
+               code =
+                   afs_AccessOK(avc, PRSFS_LOOKUP, &treq, CHECK_MODE_BITS);
        } else {
            if (amode & VEXEC) {
                code = afs_AccessOK(avc, PRSFS_READ, &treq, CHECK_MODE_BITS);
                if (code) {
-#ifdef AFS_OSF_ENV
-                   /*
-                    * The nfs server in read operations for non-owner of a file
-                    * will also check the access with the VEXEC (along with VREAD)
-                    * because for them exec is the same as read over the net because of
-                    * demand loading. But this means if the mode bit is '-rw' the call
-                    * will fail below; so for this particular case where both modes are
-                    * specified (only in rfs_read so far) and from the xlator requests
-                    * we return succes.
-                    */
-                   if (!((amode & VREAD) && AFS_NFSXLATORREQ(acred)))
-#endif
-                   if ((avc->m.Mode & 0100) == 0) code = 0;
-               } else if (avc->m.Mode & 0100) code = 1;
+                       if ((avc->f.m.Mode & 0100) == 0)
+                           code = 0;
+               } else if (avc->f.m.Mode & 0100)
+                   code = 1;
            }
-           if (code && (amode & VWRITE)) 
-           {
-              code = afs_AccessOK(avc, PRSFS_WRITE, &treq, CHECK_MODE_BITS);
-
-              /* The above call fails when the NFS translator tries to copy
-              ** a file with r--r--r-- permissions into a directory which
-               ** has system:anyuser acl. This is because the destination file
-              ** file is first created with r--r--r-- permissions through an
-              ** unauthenticated connectin.  hence, the above afs_AccessOK
-              ** call returns failure. hence, we retry without any file 
-              ** mode bit checking */
-              if ( !code && AFS_NFSXLATORREQ(acred) && avc->m.Owner == ANONYMOUSID)
-               code=afs_AccessOK(avc,PRSFS_WRITE, &treq, DONT_CHECK_MODE_BITS);
+           if (code && (amode & VWRITE)) {
+               code = afs_AccessOK(avc, PRSFS_WRITE, &treq, CHECK_MODE_BITS);
+
+               /* The above call fails when the NFS translator tries to copy
+                ** a file with r--r--r-- permissions into a directory which
+                ** has system:anyuser acl. This is because the destination file
+                ** file is first created with r--r--r-- permissions through an
+                ** unauthenticated connectin.  hence, the above afs_AccessOK
+                ** call returns failure. hence, we retry without any file 
+                ** mode bit checking */
+               if (!code && AFS_NFSXLATORREQ(acred)
+                   && avc->f.m.Owner == ANONYMOUSID)
+                   code =
+                       afs_AccessOK(avc, PRSFS_WRITE, &treq,
+                                    DONT_CHECK_MODE_BITS);
            }
-           if (code && (amode & VREAD)) 
-              code = afs_AccessOK(avc, PRSFS_READ, &treq, CHECK_MODE_BITS);
+           if (code && (amode & VREAD))
+               code = afs_AccessOK(avc, PRSFS_READ, &treq, CHECK_MODE_BITS);
        }
     }
     afs_PutFakeStat(&fakestate);
+
+    AFS_DISCON_UNLOCK();
+    
     if (code) {
        return 0;               /* if access is ok */
     } else {
-       code = afs_CheckCode(EACCES, &treq, 17);             /* failure code */
+       code = afs_CheckCode(EACCES, &treq, 17);        /* failure code */
        return code;
     }
 }
@@ -294,21 +337,21 @@ afs_access(OSI_VC_ARG(avc), amode, acred)
  * afs_getRights
  * This function is just an interface to afs_GetAccessBits
  */
-int afs_getRights(OSI_VC_ARG(avc), arights, acred)
-    OSI_VC_DECL(avc);
-    register afs_int32 arights;
-    struct AFS_UCRED *acred;
+int
+afs_getRights(OSI_VC_DECL(avc), register afs_int32 arights,
+             afs_ucred_t *acred)
 {
     register afs_int32 code;
     struct vrequest treq;
-    OSI_VC_CONVERT(avc)
+    OSI_VC_CONVERT(avc);
 
-    if (code = afs_InitReq(&treq, acred)) return code;
+    if ((code = afs_InitReq(&treq, acred)))
+       return code;
 
     code = afs_VerifyVCache(avc, &treq);
     if (code) {
-      code = afs_CheckCode(code, &treq, 16);
-      return code; 
+       code = afs_CheckCode(code, &treq, 16);
+       return code;
     }
 
     return afs_GetAccessBits(avc, arights, &treq);