Windows: Enforce Share Access
[openafs.git] / src / WINNT / afsd / cm_vnodeops.c
index d0c04e9..365720e 100644 (file)
@@ -178,16 +178,30 @@ long cm_CheckOpen(cm_scache_t *scp, int openMode, int trunc, cm_user_t *userp,
 }
 
 /* return success if we can open this file in this mode */
-long cm_CheckNTOpen(cm_scache_t *scp, unsigned int desiredAccess,
-                    unsigned int createDisp, cm_user_t *userp, cm_req_t *reqp,
+long cm_CheckNTOpen(cm_scache_t *scp,
+                    unsigned int desiredAccess,
+                    unsigned int shareAccess,
+                    unsigned int createDisp,
+                    afs_offs_t process_id,
+                    afs_offs_t handle_id,
+                    cm_user_t *userp, cm_req_t *reqp,
                    cm_lock_data_t **ldpp)
 {
     long rights;
     long code = 0;
+    afs_uint16 session_id;
 
     osi_assertx(ldpp != NULL, "null cm_lock_data_t");
     *ldpp = NULL;
 
+    /* compute the session id */
+    if (reqp->flags & CM_REQ_SOURCE_SMB)
+        session_id = CM_SESSION_SMB;
+    else if (reqp->flags & CM_REQ_SOURCE_REDIR)
+        session_id = CM_SESSION_IFS;
+    else
+        session_id = CM_SESSION_CMINT;
+
     /* Ignore the SYNCHRONIZE privilege */
     desiredAccess &= ~SYNCHRONIZE;
 
@@ -197,6 +211,10 @@ long cm_CheckNTOpen(cm_scache_t *scp, unsigned int desiredAccess,
     if (desiredAccess == DELETE)
         goto done_2;
 
+    /* Always allow reading attributes (Hidden, System, Readonly, ...) */
+    if (desiredAccess == FILE_READ_ATTRIBUTES)
+        goto done_2;
+
     if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
         rights |= (scp->fileType == CM_SCACHETYPE_DIRECTORY ? PRSFS_LOOKUP : PRSFS_READ);
 
@@ -227,8 +245,9 @@ long cm_CheckNTOpen(cm_scache_t *scp, unsigned int desiredAccess,
         code = CM_ERROR_NOACCESS;
 
     if (code == 0 &&
-             ((rights & PRSFS_WRITE) || (rights & PRSFS_READ)) &&
-             scp->fileType == CM_SCACHETYPE_FILE) {
+        !(shareAccess & FILE_SHARE_WRITE) &&
+        ((rights & PRSFS_WRITE) || (rights & PRSFS_READ)) &&
+        scp->fileType == CM_SCACHETYPE_FILE) {
         cm_key_t key;
         unsigned int sLockType;
         LARGE_INTEGER LOffset, LLength;
@@ -236,12 +255,13 @@ long cm_CheckNTOpen(cm_scache_t *scp, unsigned int desiredAccess,
         /* Check if there's some sort of lock on the file at the
            moment. */
 
-        key = cm_GenerateKey(CM_SESSION_CMINT,0,0);
         if (rights & PRSFS_WRITE)
             sLockType = 0;
         else
             sLockType = LOCKING_ANDX_SHARED_LOCK;
 
+        key = cm_GenerateKey(session_id, process_id, 0);
+
         /* single byte lock at offset 0x0100 0000 0000 0000 */
         LOffset.HighPart = CM_FLSHARE_OFFSET_HIGH;
         LOffset.LowPart  = CM_FLSHARE_OFFSET_LOW;
@@ -251,29 +271,30 @@ long cm_CheckNTOpen(cm_scache_t *scp, unsigned int desiredAccess,
         code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, reqp, NULL);
 
         if (code == 0) {
-           (*ldpp) = (cm_lock_data_t *)malloc(sizeof(cm_lock_data_t));
-           if (!*ldpp) {
-               code = ENOMEM;
-               goto _done;
-           }
+            (*ldpp) = (cm_lock_data_t *)malloc(sizeof(cm_lock_data_t));
+            if (!*ldpp) {
+                code = ENOMEM;
+                goto _done;
+            }
 
-           (*ldpp)->key = key;
-           (*ldpp)->sLockType = sLockType;
-           (*ldpp)->LOffset.HighPart = LOffset.HighPart;
-           (*ldpp)->LOffset.LowPart = LOffset.LowPart;
-           (*ldpp)->LLength.HighPart = LLength.HighPart;
-           (*ldpp)->LLength.LowPart = LLength.LowPart;
+            (*ldpp)->key = key;
+            (*ldpp)->sLockType = sLockType;
+            (*ldpp)->LOffset.HighPart = LOffset.HighPart;
+            (*ldpp)->LOffset.LowPart = LOffset.LowPart;
+            (*ldpp)->LLength.HighPart = LLength.HighPart;
+            (*ldpp)->LLength.LowPart = LLength.LowPart;
         } else {
-            /* In this case, we allow the file open to go through even
-               though we can't enforce mandatory locking on the
-               file. */
+            /*
+             * In this case, we allow the file open to go through even
+             * though we can't enforce mandatory locking on the
+             * file. */
             if (code == CM_ERROR_NOACCESS &&
-                !(rights & PRSFS_WRITE))
+                 !(rights & PRSFS_WRITE))
                 code = 0;
             else {
-               if (code == CM_ERROR_LOCK_NOT_GRANTED)
-                   code = CM_ERROR_SHARING_VIOLATION;
-           }
+                if (code == CM_ERROR_LOCK_NOT_GRANTED)
+                    code = CM_ERROR_SHARING_VIOLATION;
+            }
         }
     } else if (code != 0) {
         goto _done;
@@ -290,9 +311,9 @@ long cm_CheckNTOpen(cm_scache_t *scp, unsigned int desiredAccess,
 extern long cm_CheckNTOpenDone(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp,
                               cm_lock_data_t ** ldpp)
 {
-    osi_Log2(afsd_logp,"cm_CheckNTOpenDone scp 0x%p ldp 0x%p", scp, *ldpp);
+       osi_Log2(afsd_logp,"cm_CheckNTOpenDone scp 0x%p ldp 0x%p", scp, ldpp ? *ldpp : 0);
     lock_ObtainWrite(&scp->rw);
-    if (*ldpp) {
+    if (ldpp && *ldpp) {
        cm_Unlock(scp, (*ldpp)->sLockType, (*ldpp)->LOffset, (*ldpp)->LLength,
                  (*ldpp)->key, 0, userp, reqp);
        free(*ldpp);
@@ -1327,10 +1348,16 @@ notfound:
     return code;
 }
 
-int cm_ExpandSysName(clientchar_t *inp, clientchar_t *outp, long outSizeCch, unsigned int index)
+int cm_ExpandSysName(cm_req_t * reqp, clientchar_t *inp, clientchar_t *outp, long outSizeCch, unsigned int index)
 {
     clientchar_t *tp;
     int prefixCount;
+#ifdef _WIN64
+    int use_sysname64 = 0;
+
+    if (cm_sysName64Count > 0 && reqp && (reqp->flags & CM_REQ_WOW64) && (reqp->flags & CM_REQ_SOURCE_REDIR))
+        use_sysname64 = 1;
+#endif
 
     tp = cm_ClientStrRChr(inp, '@');
     if (tp == NULL)
@@ -1343,6 +1370,11 @@ int cm_ExpandSysName(clientchar_t *inp, clientchar_t *outp, long outSizeCch, uns
     if (outp == NULL)
         return 1;
 
+#ifdef _WIN64
+    if (use_sysname64 && index >= cm_sysName64Count)
+        return -1;
+    else
+#endif
     if (index >= cm_sysNameCount)
         return -1;
 
@@ -1350,8 +1382,14 @@ int cm_ExpandSysName(clientchar_t *inp, clientchar_t *outp, long outSizeCch, uns
     prefixCount = (int)(tp - inp);
 
     cm_ClientStrCpyN(outp, outSizeCch, inp, prefixCount);      /* copy out "a." from "a.@sys" */
-    outp[prefixCount] = 0;             /* null terminate the "a." */
-    cm_ClientStrCat(outp, outSizeCch, cm_sysNameList[index]);/* append i386_nt40 */
+    outp[prefixCount] = 0;                                     /* null terminate the "a." */
+#ifdef _WIN64
+    if (use_sysname64)
+        cm_ClientStrCat(outp, outSizeCch, cm_sysName64List[index]);
+    else
+#endif
+        cm_ClientStrCat(outp, outSizeCch, cm_sysNameList[index]);
+
     return 1;
 }
 
@@ -1494,9 +1532,9 @@ long cm_Lookup(cm_scache_t *dscp, clientchar_t *namep, long flags, cm_user_t *us
         return cm_EvaluateVolumeReference(namep, flags, userp, reqp, outScpp);
     }
 
-    if (cm_ExpandSysName(namep, NULL, 0, 0) > 0) {
+    if (cm_ExpandSysName(reqp, namep, NULL, 0, 0) > 0) {
         for ( sysNameIndex = 0; sysNameIndex < MAXNUMSYSNAMES; sysNameIndex++) {
-            code = cm_ExpandSysName(namep, tname, lengthof(tname), sysNameIndex);
+            code = cm_ExpandSysName(reqp, namep, tname, lengthof(tname), sysNameIndex);
             if (code > 0) {
                 code = cm_LookupInternal(dscp, tname, flags, userp, reqp, &scp);
 #ifdef DEBUG_REFCOUNT
@@ -1654,6 +1692,11 @@ long cm_Unlink(cm_scache_t *dscp, fschar_t *fnamep, clientchar_t * cnamep,
     cm_dnlcRemove(dscp, cnamep);
     if (code == 0) {
         cm_MergeStatus(NULL, dscp, &newDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
+        if (RDR_Initialized &&
+            scp->fileType != CM_SCACHETYPE_FILE && scp->fileType != CM_SCACHETYPE_DIRECTORY)
+            RDR_InvalidateObject(dscp->fid.cell, dscp->fid.volume, dscp->fid.vnode,
+                                 dscp->fid.unique, dscp->fid.hash,
+                                 dscp->fileType, AFS_INVALIDATE_DATA_VERSION);
     } else if (code == CM_ERROR_NOSUCHFILE) {
        /* windows would not have allowed the request to delete the file
         * if it did not believe the file existed.  therefore, we must
@@ -1685,6 +1728,11 @@ long cm_Unlink(cm_scache_t *dscp, fschar_t *fnamep, clientchar_t * cnamep,
             }
             cm_DiscardSCache(scp);
            lock_ReleaseWrite(&scp->rw);
+            if (RDR_Initialized && !(reqp->flags & CM_REQ_SOURCE_REDIR) &&
+                !RDR_InvalidateObject(scp->fid.cell, scp->fid.volume, scp->fid.vnode,
+                                      scp->fid.unique, scp->fid.hash,
+                                      scp->fileType, AFS_INVALIDATE_DELETED))
+                buf_ClearRDRFlag(scp, "unlink");
         }
     }
 
@@ -2789,7 +2837,7 @@ long cm_Create(cm_scache_t *dscp, clientchar_t *cnamep, long flags, cm_attr_t *a
     /* can't create names with @sys in them; must expand it manually first.
      * return "invalid request" if they try.
      */
-    if (cm_ExpandSysName(cnamep, NULL, 0, 0)) {
+    if (cm_ExpandSysName(NULL, cnamep, NULL, 0, 0)) {
         return CM_ERROR_ATSYS;
     }
 
@@ -2973,7 +3021,7 @@ long cm_MakeDir(cm_scache_t *dscp, clientchar_t *cnamep, long flags, cm_attr_t *
     /* can't create names with @sys in them; must expand it manually first.
      * return "invalid request" if they try.
      */
-    if (cm_ExpandSysName(cnamep, NULL, 0, 0)) {
+    if (cm_ExpandSysName(NULL, cnamep, NULL, 0, 0)) {
         return CM_ERROR_ATSYS;
     }
 
@@ -3171,6 +3219,10 @@ long cm_Link(cm_scache_t *dscp, clientchar_t *cnamep, cm_scache_t *sscp, long fl
     lock_ObtainWrite(&dscp->rw);
     if (code == 0) {
         cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
+        if (RDR_Initialized)
+            RDR_InvalidateObject(dscp->fid.cell, dscp->fid.volume, dscp->fid.vnode,
+                                 dscp->fid.unique, dscp->fid.hash,
+                                 dscp->fileType, AFS_INVALIDATE_DATA_VERSION);
     }
     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
     lock_ReleaseWrite(&dscp->rw);
@@ -3452,6 +3504,11 @@ long cm_RemoveDir(cm_scache_t *dscp, fschar_t *fnamep, clientchar_t *cnamep, cm_
             cm_RemoveSCacheFromHashTable(scp);
             lock_ReleaseWrite(&cm_scacheLock);
            lock_ReleaseWrite(&scp->rw);
+            if (RDR_Initialized && !(reqp->flags & CM_REQ_SOURCE_REDIR) &&
+                !RDR_InvalidateObject(scp->fid.cell, scp->fid.volume, scp->fid.vnode,
+                                      scp->fid.unique, scp->fid.hash,
+                                      scp->fileType, AFS_INVALIDATE_DELETED))
+                buf_ClearRDRFlag(scp, "rmdir");
         }
     }
 
@@ -3546,21 +3603,31 @@ long cm_Rename(cm_scache_t *oldDscp, fschar_t *oldNamep, clientchar_t *cOldNamep
         goto done;
     }
 
-    code = cm_Lookup(newDscp, cNewNamep, CM_FLAG_CASEFOLD, userp, reqp, &newScp);
-    if (code == 0) {
-        /* found a matching object with the new name */
-        if (cm_FidCmp(&oldScp->fid, &newScp->fid)) {
-            /* and they don't match so return an error */
-            osi_Log2(afsd_logp, "cm_Rename newDscp 0x%p cNewName %S new name already exists",
-                      newDscp, osi_LogSaveStringW(afsd_logp, cNewNamep));
+    /* Case sensitive lookup.  If this succeeds we are done. */
+    code = cm_Lookup(newDscp, cNewNamep, 0, userp, reqp, &newScp);
+    if (code) {
+        /*
+         * Case insensitive lookup.  If this succeeds, it could have found the
+         * same file with a name that differs only by case or it could be a
+         * different file entirely.
+         */
+        code = cm_Lookup(newDscp, cNewNamep, CM_FLAG_CASEFOLD, userp, reqp, &newScp);
+        if (code == 0) {
+            /* found a matching object with the new name */
+            if (cm_FidCmp(&oldScp->fid, &newScp->fid)) {
+                /* and they don't match so return an error */
+                osi_Log2(afsd_logp, "cm_Rename newDscp 0x%p cNewName %S new name already exists",
+                          newDscp, osi_LogSaveStringW(afsd_logp, cNewNamep));
+                code = CM_ERROR_EXISTS;
+            }
+            cm_ReleaseSCache(newScp);
+            newScp = NULL;
+        } else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
             code = CM_ERROR_EXISTS;
+        } else {
+            /* The target does not exist.  Clear the error and perform the rename. */
+            code = 0;
         }
-        cm_ReleaseSCache(newScp);
-        newScp = NULL;
-    } else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
-        code = CM_ERROR_EXISTS;
-    } else {
-        code = 0;
     }
 
     /* Check for RO volume */
@@ -3830,6 +3897,9 @@ long cm_Rename(cm_scache_t *oldDscp, fschar_t *oldNamep, clientchar_t *cOldNamep
     cm_DiscardSCache(oldScp);
     lock_ReleaseWrite(&oldScp->rw);
 
+    if (RDR_Initialized)
+        RDR_InvalidateObject(oldScp->fid.cell, oldScp->fid.volume, oldScp->fid.vnode, oldScp->fid.unique,
+                              oldScp->fid.hash, oldScp->fileType, AFS_INVALIDATE_CALLBACK);
   done:
     if (oldScp)
         cm_ReleaseSCache(oldScp);
@@ -4364,6 +4434,16 @@ long cm_IntSetLock(cm_scache_t * scp, cm_user_t * userp, int lockType,
     AFSVolSync volSync;
     afs_uint32 reqflags = reqp->flags;
 
+    osi_Log2(afsd_logp, "CALL SetLock scp 0x%p for lock %d", scp, lockType);
+
+       if ((lockType != LOCKING_ANDX_SHARED_LOCK && scp->fsLockCount != 0) ||
+               (lockType == LOCKING_ANDX_SHARED_LOCK && scp->fsLockCount < 0))
+       {
+               code = CM_ERROR_LOCK_NOT_GRANTED;
+        osi_Log2(afsd_logp, "CALL SetLock FAILURE, fsLockCount %d code 0x%x", scp->fsLockCount, code);
+               return code;
+       }
+
     memset(&volSync, 0, sizeof(volSync));
 
     tfid.Volume = scp->fid.volume;
@@ -4371,8 +4451,6 @@ long cm_IntSetLock(cm_scache_t * scp, cm_user_t * userp, int lockType,
     tfid.Unique = scp->fid.unique;
     cfid = scp->fid;
 
-    osi_Log2(afsd_logp, "CALL SetLock scp 0x%p for lock %d", scp, lockType);
-
     reqp->flags |= CM_REQ_NORETRY;
     lock_ReleaseWrite(&scp->rw);
 
@@ -5108,6 +5186,12 @@ long cm_UnlockByKey(cm_scache_t * scp,
 
             fileLock->flags |= CM_FILELOCK_FLAG_DELETED;
 
+            cm_ReleaseUser(fileLock->userp);
+            cm_ReleaseSCacheNoLock(scp);
+
+            fileLock->userp = NULL;
+            fileLock->scp = NULL;
+
             n_unlocks++;
         }
     }
@@ -5122,9 +5206,9 @@ long cm_UnlockByKey(cm_scache_t * scp,
         return 0;
     }
 
-    osi_Log1(afsd_logp, "cm_UnlockByKey done with %d locks", n_unlocks);
-
+    code = cm_IntUnlock(scp, userp, reqp);
     osi_Log1(afsd_logp, "cm_UnlockByKey code 0x%x", code);
+
     osi_Log4(afsd_logp, "   Leaving scp with excl[%d], shared[%d], client[%d], serverLock[%d]",
              scp->exclusiveLocks, scp->sharedLocks, scp->clientLocks,
              (int)(signed char) scp->serverLock);
@@ -5132,6 +5216,7 @@ long cm_UnlockByKey(cm_scache_t * scp,
     return code;
 }
 
+/* Called with scp->rw held */
 long cm_Unlock(cm_scache_t *scp,
                unsigned char sLockType,
                LARGE_INTEGER LOffset, LARGE_INTEGER LLength,
@@ -5234,8 +5319,20 @@ long cm_Unlock(cm_scache_t *scp,
     }
 
     fileLock->flags |= CM_FILELOCK_FLAG_DELETED;
+
+    if (userp != NULL) {
+        cm_ReleaseUser(fileLock->userp);
+    } else {
+        userp = fileLock->userp;
+        release_userp = TRUE;
+    }
+    cm_ReleaseSCacheNoLock(scp);
+    fileLock->userp = NULL;
+    fileLock->scp = NULL;
     lock_ReleaseWrite(&cm_scacheLock);
 
+    code = cm_IntUnlock(scp, userp, reqp);
+
     if (release_userp) {
         cm_ReleaseUser(userp);
         release_userp = FALSE;
@@ -5321,15 +5418,16 @@ void cm_CheckLocks()
             fileLock->userp = NULL;
             fileLock->scp = NULL;
 
-            lock_ReleaseWrite(&cm_scacheLock);
-            lock_ObtainWrite(&scp->rw);
-            code = cm_IntUnlock(scp, userp, &req);
-            lock_ReleaseWrite(&scp->rw);
-
-            cm_ReleaseUser(fileLock->userp);
-            lock_ObtainWrite(&cm_scacheLock);
-            cm_ReleaseSCacheNoLock(scp);
+            if (scp && userp) {
+                lock_ReleaseWrite(&cm_scacheLock);
+                lock_ObtainWrite(&scp->rw);
+                code = cm_IntUnlock(scp, userp, &req);
+                lock_ReleaseWrite(&scp->rw);
 
+                cm_ReleaseUser(userp);
+                lock_ObtainWrite(&cm_scacheLock);
+                cm_ReleaseSCacheNoLock(scp);
+            }
             osi_QRemove(&cm_allFileLocks, q);
             cm_PutFileLock(fileLock);
 
@@ -5816,7 +5914,7 @@ long cm_RetryLock(cm_file_lock_t *oldFileLock, int client_is_dead)
     return code;
 }
 
-cm_key_t cm_GenerateKey(afs_uint16 session_id, afs_offs_t process_id, afs_uint16 file_id)
+cm_key_t cm_GenerateKey(afs_uint16 session_id, afs_offs_t process_id, afs_uint64 file_id)
 {
     cm_key_t key;
 
@@ -5830,7 +5928,7 @@ cm_key_t cm_GenerateKey(afs_uint16 session_id, afs_offs_t process_id, afs_uint16
 int cm_KeyEquals(cm_key_t *k1, cm_key_t *k2, int flags)
 {
     return (k1->session_id == k2->session_id) && (k1->file_id == k2->file_id) &&
-        ((flags & CM_UNLOCK_BY_FID) || (k1->process_id == k2->process_id));
+        ((flags & CM_UNLOCK_FLAG_BY_FID) || (k1->process_id == k2->process_id));
 }
 
 void cm_ReleaseAllLocks(void)