X-Git-Url: http://git.openafs.org/?p=openafs.git;a=blobdiff_plain;f=src%2FWINNT%2Fafsd%2Fsmb3.c;h=149c740fc9b08df0c0b9d55f619ae36e925dd12e;hp=389449b22c8f26b957bc0599363e5609e863e058;hb=14408c7e88c198d80ce89e90e209f48685da89da;hpb=a09b27d0a0bdb9d967220388f76379ece4c7b5cb diff --git a/src/WINNT/afsd/smb3.c b/src/WINNT/afsd/smb3.c index 389449b..149c740 100644 --- a/src/WINNT/afsd/smb3.c +++ b/src/WINNT/afsd/smb3.c @@ -121,7 +121,6 @@ unsigned char *smb_ParseString(unsigned char *inp, char **chainpp) return inp; } -/*DEBUG do not checkin*/ void OutputDebugF(char * format, ...) { va_list args; int len; @@ -174,9 +173,9 @@ void OutputDebugHexDump(unsigned char * buffer, int len) { OutputDebugString(buf); } } -/**/ #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate" + void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) { SECURITY_STATUS status, istatus; CredHandle creds = {0,0}; @@ -201,7 +200,7 @@ void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) { &creds, &expiry); - if (status != SEC_E_OK) { + if (status != SEC_E_OK) { /* Really bad. We return an empty security blob */ OutputDebugF("AcquireCredentialsHandle failed with %lX", status); goto nes_0; @@ -649,11 +648,12 @@ long smb_GetNormalizedUsername(char * usern, const char * accountName, const cha return 0; } -/* When using SMB auth, all SMB sessions have to pass through here first to - * authenticate the user. - * Caveat: If not use the SMB auth the protocol does not require sending a - * session setup packet, which means that we can't rely on a UID in subsequent - * packets. Though in practice we get one anyway. +/* When using SMB auth, all SMB sessions have to pass through here + * first to authenticate the user. + * + * Caveat: If not using SMB auth, the protocol does not require + * sending a session setup packet, which means that we can't rely on a + * UID in subsequent packets. Though in practice we get one anyway. */ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) { @@ -3185,7 +3185,6 @@ smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t char requestFileName[1024] = ""; smb_tran2Packet_t *outp = 0; cm_user_t *userp = 0; - cm_scache_t *scp; cm_req_t req; CPINFO CodePageInfo; int i, nbnLen, reqLen; @@ -4512,17 +4511,17 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) scp = NULL; - extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */ - openFun = smb_GetSMBParm(inp, 8); /* open function */ + extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */ + openFun = smb_GetSMBParm(inp, 8); /* open function */ excl = ((openFun & 3) == 0); - trunc = ((openFun & 3) == 2); /* truncate it */ + trunc = ((openFun & 3) == 2); /* truncate it */ openMode = (smb_GetSMBParm(inp, 3) & 0x7); - openAction = 0; /* tracks what we did */ + openAction = 0; /* tracks what we did */ attributes = smb_GetSMBParm(inp, 5); dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16); - /* compute initial mode bits based on read-only flag in attributes */ + /* compute initial mode bits based on read-only flag in attributes */ initialModeBits = 0666; if (attributes & 1) initialModeBits &= ~0222; @@ -4783,15 +4782,32 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) return 0; } -/* The file locking code is incomplete and that which is implemented in cm_Lock() - * is broken. What exists functions only because it is rarely if ever called. - * The tests activated by FULL_LOCKS_ONLY ensure that cm_Lock() is only called - * if the lock covers the entire file. Therefore, RXAFS_SetLock is only called - * rarely. That means that AFS locks are ignored by Windows clients. - * When cm_Lock is re-written, undefine or better yet remove, the FULL_LOCKS_ONLY - * code. - */ -#define FULL_LOCKS_ONLY +static void smb_GetLockParams(unsigned char LockType, + char ** buf, + unsigned int * ppid, + LARGE_INTEGER * pOffset, + LARGE_INTEGER * pLength) +{ + if (LockType & LOCKING_ANDX_LARGE_FILES) { + /* Large Files */ + *ppid = *((USHORT *) *buf); + pOffset->HighPart = *((LONG *)(*buf + 4)); + pOffset->LowPart = *((DWORD *)(*buf + 8)); + pLength->HighPart = *((LONG *)(*buf + 12)); + pLength->LowPart = *((DWORD *)(*buf + 16)); + *buf += 20; + } + else { + /* Not Large Files */ + *ppid = *((USHORT *) *buf); + pOffset->HighPart = 0; + pOffset->LowPart = *((DWORD *)(*buf + 2)); + pLength->HighPart = 0; + pLength->LowPart = *((DWORD *)(*buf + 6)); + *buf += 10; + } +} + long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) { cm_req_t req; @@ -4801,13 +4817,16 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) cm_scache_t *scp; unsigned char LockType; unsigned short NumberOfUnlocks, NumberOfLocks; - unsigned long Timeout; + long Timeout; char *op; + char *op_locks; LARGE_INTEGER LOffset, LLength; - smb_waitingLock_t *waitingLock; - void *lockp; + smb_waitingLockRequest_t *wlRequest = NULL; + cm_file_lock_t *lockp; long code = 0; int i; + cm_key_t key; + unsigned int pid; cm_InitReq(&req); @@ -4841,103 +4860,186 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) NumberOfUnlocks = smb_GetSMBParm(inp, 6); NumberOfLocks = smb_GetSMBParm(inp, 7); + if ((LockType & LOCKING_ANDX_CANCEL_LOCK) || + (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE)) { + + /* We don't support these requests. Apparently, we can safely + not deal with them too. */ + osi_Log1(smb_logp, "smb_ReceiveV3Locking received unsupported request [%s]", + ((LockType & LOCKING_ANDX_CANCEL_LOCK)? + "LOCKING_ANDX_CANCEL_LOCK": + "LOCKING_ANDX_CHANGE_LOCKTYPE")); + /* No need to call osi_LogSaveString since these are string + constants.*/ + + code = CM_ERROR_BADOP; + goto done; + + } + op = smb_GetSMBData(inp, NULL); for (i=0; ivcID, pid, fidp->fid); + + code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req); + + if (code) + goto done; + } + + op_locks = op; for (i=0; ilength)) { - osi_Log3(smb_logp, "smb_ReceiveV3Locking Unlock %d offset 0x%x < 0x%x", - i, (long)LOffset.QuadPart, (long)scp->length.QuadPart); - continue; - } -#endif /* FULL_LOCKS_ONLY */ - code = cm_Lock(scp, LockType, LOffset, LLength, Timeout, + smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength); + + key = cm_GenerateKey(vcp->vcID, pid, fidp->fid); + + code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0), userp, &req, &lockp); + if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) { + smb_waitingLock_t * wLock; + /* Put on waiting list */ - waitingLock = malloc(sizeof(smb_waitingLock_t)); - waitingLock->vcp = vcp; - smb_HoldVC(vcp); - waitingLock->inp = smb_CopyPacket(inp); - waitingLock->outp = smb_CopyPacket(outp); - waitingLock->timeRemaining = Timeout; - waitingLock->lockp = lockp; - lock_ObtainWrite(&smb_globalLock); - osi_QAdd((osi_queue_t **)&smb_allWaitingLocks, - &waitingLock->q); - osi_Wakeup((long) &smb_allWaitingLocks); - lock_ReleaseWrite(&smb_globalLock); - /* don't send reply immediately */ - outp->flags |= SMB_PACKETFLAG_NOSEND; + if(wlRequest == NULL) { + int j; + char * opt; + cm_key_t tkey; + LARGE_INTEGER tOffset, tLength; + + wlRequest = malloc(sizeof(smb_waitingLockRequest_t)); + + osi_assert(wlRequest != NULL); + + wlRequest->vcp = vcp; + smb_HoldVC(vcp); + wlRequest->scp = scp; + cm_HoldSCache(scp); + wlRequest->inp = smb_CopyPacket(inp); + wlRequest->outp = smb_CopyPacket(outp); + wlRequest->lockType = LockType; + wlRequest->timeRemaining = Timeout; + wlRequest->locks = NULL; + + /* The waiting lock request needs to have enough + information to undo all the locks in the request. + We do the following to store info about locks that + have already been granted. Sure, we can get most + of the info from the packet, but the packet doesn't + hold the result of cm_Lock call. In practice we + only receive packets with one or two locks, so we + are only wasting a few bytes here and there and + only for a limited period of time until the waiting + lock times out or is freed. */ + + for(opt = op_locks, j=i; j > 0; j--) { + smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength); + + tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid); + + wLock = malloc(sizeof(smb_waitingLock_t)); + + osi_assert(wLock != NULL); + + wLock->key = tkey; + wLock->LOffset = tOffset; + wLock->LLength = tLength; + wLock->lockp = NULL; + wLock->state = SMB_WAITINGLOCKSTATE_DONE; + osi_QAdd((osi_queue_t **) &wlRequest->locks, + &wLock->q); + } + } + + wLock = malloc(sizeof(smb_waitingLock_t)); + + osi_assert(wLock != NULL); + + wLock->key = key; + wLock->LOffset = LOffset; + wLock->LLength = LLength; + wLock->lockp = lockp; + wLock->state = SMB_WAITINGLOCKSTATE_WAITING; + osi_QAdd((osi_queue_t **) &wlRequest->locks, + &wLock->q); + osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%x", - (long) waitingLock); + (long) wLock); + + code = 0; continue; } + if (code) { osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code); break; } - } + } if (code) { - /* release any locks acquired before the failure */ - osi_Log0(smb_logp, "smb_ReceiveV3Locking - failure; should be releasing locks but don't!!!!"); - } - else + + /* Since something went wrong with the lock number i, we now + have to go ahead and release any locks acquired before the + failure. All locks before lock number i (of which there + are i of them) have either been successful or are waiting. + Either case requires calling cm_Unlock(). */ + + /* And purge the waiting lock */ + if(wlRequest != NULL) { + smb_waitingLock_t * wl; + smb_waitingLock_t * wlNext; + long ul_code; + + for(wl = wlRequest->locks; wl; wl = wlNext) { + + wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q); + + ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req); + + if(ul_code != 0) { + osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code); + } else { + osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful"); + } + + osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q); + free(wl); + + } + + smb_ReleaseVC(wlRequest->vcp); + cm_ReleaseSCache(wlRequest->scp); + smb_FreePacket(wlRequest->inp); + smb_FreePacket(wlRequest->outp); + + free(wlRequest); + + wlRequest = NULL; + } + + } else { + + if (wlRequest != NULL) { + + lock_ObtainWrite(&smb_globalLock); + osi_QAdd((osi_queue_t **)&smb_allWaitingLocks, + &wlRequest->q); + osi_Wakeup((long) &smb_allWaitingLocks); + lock_ReleaseWrite(&smb_globalLock); + + /* don't send reply immediately */ + outp->flags |= SMB_PACKETFLAG_NOSEND; + } + smb_SetSMBDataLength(outp, 0); + } + done: cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK); + doneSync: lock_ReleaseMutex(&scp->mx); cm_ReleaseUser(userp); @@ -5064,11 +5166,14 @@ long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t * long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) { osi_hyper_t offset; - long count, finalCount; + long count; + long finalCount = 0; unsigned short fd; + unsigned pid; smb_fid_t *fidp; long code = 0; cm_user_t *userp; + cm_key_t key; char *op; fd = smb_GetSMBParm(inp, 2); @@ -5084,13 +5189,34 @@ long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) if (!fidp) { return CM_ERROR_BADFD; } + + pid = ((smb_t *) inp)->pid; + key = cm_GenerateKey(vcp->vcID, pid, fd); + { + LARGE_INTEGER LOffset, LLength; + + LOffset.HighPart = offset.HighPart; + LOffset.LowPart = offset.LowPart; + LLength.HighPart = 0; + LLength.LowPart = count; + + lock_ObtainMutex(&fidp->scp->mx); + code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key); + lock_ReleaseMutex(&fidp->scp->mx); + } + + if (code) { + smb_ReleaseFID(fidp); + return code; + } + /* set inp->fid so that later read calls in same msg can find fid */ inp->fid = fd; if (fidp->flags & SMB_FID_IOCTL) { return smb_IoctlV3Read(fidp, vcp, inp, outp); } - + userp = smb_GetUser(vcp, inp); /* 0 and 1 are reserved for request chaining, were setup by our caller, @@ -5185,6 +5311,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) unsigned int extAttributes; unsigned int createDisp; unsigned int createOptions; + unsigned int shareAccess; int initialModeBits; unsigned short baseFid; smb_fid_t *baseFidp; @@ -5229,6 +5356,8 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) | (smb_GetSMBOffsetParm(inp, 8, 1) << 16); extAttributes = smb_GetSMBOffsetParm(inp, 13, 1) | (smb_GetSMBOffsetParm(inp, 14, 1) << 16); + shareAccess = smb_GetSMBOffsetParm(inp, 15, 1) + | (smb_GetSMBOffsetParm(inp, 16, 1) << 16); createDisp = smb_GetSMBOffsetParm(inp, 17, 1) | (smb_GetSMBOffsetParm(inp, 18, 1) << 16); createOptions = smb_GetSMBOffsetParm(inp, 19, 1) @@ -5249,7 +5378,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) * extended attributes */ initialModeBits = 0666; - if (extAttributes & 1) + if (extAttributes & SMB_ATTR_READONLY) initialModeBits &= ~0222; pathp = smb_GetSMBData(inp, NULL); @@ -5265,7 +5394,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp)); osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions); - osi_Log2(smb_logp,"... flags=[%x] lastNamep=[%s]", flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null"))); + osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%s]", shareAccess, flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null"))); if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) { /* special case magic file name for receiving IOCTL requests @@ -5313,6 +5442,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) free(hexp); } #endif + userp = smb_GetUser(vcp, inp); if (!userp) { osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid); @@ -5361,6 +5491,12 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) if (createOptions & FILE_DELETE_ON_CLOSE) fidflags |= SMB_FID_DELONCLOSE; + /* and the share mode */ + if (shareAccess & FILE_SHARE_READ) + fidflags |= SMB_FID_SHARE_READ; + if (shareAccess & FILE_SHARE_WRITE) + fidflags |= SMB_FID_SHARE_WRITE; + code = 0; /* For an exclusive create, we want to do a case sensitive match for the last component. */ @@ -5536,7 +5672,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) /* we have scp but not dscp */ if (baseFid != 0) smb_ReleaseFID(baseFidp); - } + } /* if we get here, if code is 0, the file exists and is represented by * scp. Otherwise, we have to create it. The dir may be represented @@ -5557,6 +5693,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) if ( createDisp == FILE_OVERWRITE || createDisp == FILE_OVERWRITE_IF) { + setAttr.mask = CM_ATTRMASK_LENGTH; setAttr.length.LowPart = 0; setAttr.length.HighPart = 0; @@ -5781,6 +5918,46 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) /* open the file itself */ fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE); osi_assert(fidp); + + /* If we are restricting sharing, we should do so with a suitable + share lock. */ + if (scp->fileType == CM_SCACHETYPE_FILE && + !(fidflags & SMB_FID_SHARE_WRITE)) { + cm_key_t key; + LARGE_INTEGER LOffset, LLength; + int sLockType; + + LOffset.HighPart = SMB_FID_QLOCK_HIGH; + LOffset.LowPart = SMB_FID_QLOCK_LOW; + LLength.HighPart = 0; + LLength.LowPart = SMB_FID_QLOCK_LENGTH; + + if (fidflags & SMB_FID_SHARE_READ) { + sLockType = LOCKING_ANDX_SHARED_LOCK; + } else { + sLockType = 0; + } + + key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid); + + lock_ObtainMutex(&scp->mx); + code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL); + lock_ReleaseMutex(&scp->mx); + + if (code) { + fidp->flags = SMB_FID_DELETE; + smb_ReleaseFID(fidp); + + cm_ReleaseSCache(scp); + if (dscp) + cm_ReleaseSCache(dscp); + cm_ReleaseUser(userp); + free(realPathp); + + return CM_ERROR_SHARING_VIOLATION; + } + } + /* save a pointer to the vnode */ fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */ @@ -5800,6 +5977,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) cm_ReleaseSCache(dscp); dscp = NULL; } + cm_Open(scp, 0, userp); /* set inp->fid so that later read calls in same msg can find fid */ @@ -5834,7 +6012,8 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) cm_ReleaseUser(userp); - /* Can't free realPathp if we get here since fidp->NTopen_wholepathp is pointing there */ + /* Can't free realPathp if we get here since + fidp->NTopen_wholepathp is pointing there */ /* leave scp held since we put it in fidp->scp */ return 0; @@ -5865,8 +6044,8 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out unsigned int desiredAccess; #ifdef DEBUG_VERBOSE unsigned int allocSize; - unsigned int shareAccess; #endif + unsigned int shareAccess; unsigned int extAttributes; unsigned int createDisp; #ifdef DEBUG_VERBOSE @@ -5918,9 +6097,7 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out allocSize = lparmp[3]; #endif /* DEBUG_VERSOSE */ extAttributes = lparmp[5]; -#ifdef DEBUG_VEROSE shareAccess = lparmp[6]; -#endif createDisp = lparmp[7]; createOptions = lparmp[8]; #ifdef DEBUG_VERBOSE @@ -6024,6 +6201,12 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out if (createOptions & FILE_DELETE_ON_CLOSE) fidflags |= SMB_FID_DELONCLOSE; + /* And the share mode */ + if (shareAccess & FILE_SHARE_READ) + fidflags |= SMB_FID_SHARE_READ; + if (shareAccess & FILE_SHARE_WRITE) + fidflags |= SMB_FID_SHARE_WRITE; + dscp = NULL; code = 0; if ( createDisp == FILE_OPEN || @@ -6324,6 +6507,43 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE); osi_assert(fidp); + /* If we are restricting sharing, we should do so with a suitable + share lock. */ + if (scp->fileType == CM_SCACHETYPE_FILE && + !(fidflags & SMB_FID_SHARE_WRITE)) { + cm_key_t key; + LARGE_INTEGER LOffset, LLength; + int sLockType; + + LOffset.HighPart = SMB_FID_QLOCK_HIGH; + LOffset.LowPart = SMB_FID_QLOCK_LOW; + LLength.HighPart = 0; + LLength.LowPart = SMB_FID_QLOCK_LENGTH; + + if (fidflags & SMB_FID_SHARE_READ) { + sLockType = LOCKING_ANDX_SHARED_LOCK; + } else { + sLockType = 0; + } + + key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid); + + lock_ObtainMutex(&scp->mx); + code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL); + lock_ReleaseMutex(&scp->mx); + + if (code) { + fidp->flags = SMB_FID_DELETE; + smb_ReleaseFID(fidp); + + cm_ReleaseSCache(scp); + cm_ReleaseUser(userp); + free(realPathp); + + return CM_ERROR_SHARING_VIOLATION; + } + } + /* save a pointer to the vnode */ fidp->scp = scp;