return inp;
}
-/*DEBUG do not checkin*/
void OutputDebugF(char * format, ...) {
va_list args;
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};
&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;
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)
{
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;
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;
return 0;
}
+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;
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);
fidp = smb_FindFID(vcp, fid, 0);
if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
+ osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
return CM_ERROR_BADFD;
}
/* set inp->fid so that later read calls in same msg can find fid */
CM_SCACHESYNC_NEEDCALLBACK
| CM_SCACHESYNC_GETSTATUS
| CM_SCACHESYNC_LOCK);
- if (code)
+ if (code) {
+ osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
goto doneSync;
+ }
LockType = smb_GetSMBParm(inp, 3) & 0xff;
Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
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; i<NumberOfUnlocks; i++) {
- if (LockType & LOCKING_ANDX_LARGE_FILES) {
- /* Large Files */
- LOffset.HighPart = *((LONG *)(op + 4));
- LOffset.LowPart = *((DWORD *)(op + 8));
- LLength.HighPart = *((LONG *)(op + 12));
- LLength.LowPart = *((DWORD *)(op + 16));
- op += 20;
- }
- else {
- /* Not Large Files */
- LOffset.HighPart = 0;
- LOffset.LowPart = *((DWORD *)(op + 2));
- LLength.HighPart = 0;
- LLength.LowPart = *((DWORD *)(op + 6));
- op += 10;
- }
- if (LargeIntegerNotEqualToZero(LOffset))
- continue;
- /* Do not check length -- length check done in cm_Unlock */
+ smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
- code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
- if (code) goto done;
- }
+ key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
+
+ code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
+
+ if (code)
+ goto done;
+ }
+
+ op_locks = op;
for (i=0; i<NumberOfLocks; i++) {
- if (LockType & LOCKING_ANDX_LARGE_FILES) {
- /* Large Files */
- LOffset.HighPart = *((LONG *)(op + 4));
- LOffset.LowPart = *((DWORD *)(op + 8));
- LLength.HighPart = *((LONG *)(op + 12));
- LLength.LowPart = *((DWORD *)(op + 16));
- op += 20;
- }
- else {
- /* Not Large Files */
- LOffset.HighPart = 0;
- LOffset.LowPart = *((DWORD *)(op + 2));
- LLength.HighPart = 0;
- LLength.LowPart = *((DWORD *)(op + 6));
- op += 10;
- }
- if (LargeIntegerNotEqualToZero(LOffset))
- continue;
- if (LargeIntegerLessThan(LOffset, scp->length))
- continue;
+ smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
+
+ key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
- code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
+ 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;
+ 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) wLock);
+
+ code = 0;
+ continue;
+ }
+
+ if (code) {
+ osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
+ break;
+ }
+ }
+
+ if (code) {
+
+ /* 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,
- &waitingLock->q);
+ &wlRequest->q);
osi_Wakeup((long) &smb_allWaitingLocks);
lock_ReleaseWrite(&smb_globalLock);
+
/* don't send reply immediately */
outp->flags |= SMB_PACKETFLAG_NOSEND;
}
- if (code)
- break;
- }
- if (code) {
- /* release any locks acquired before the failure */
- }
- else
smb_SetSMBDataLength(outp, 0);
+ }
+
done:
cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
+
doneSync:
lock_ReleaseMutex(&scp->mx);
cm_ReleaseUser(userp);
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);
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,
unsigned int extAttributes;
unsigned int createDisp;
unsigned int createOptions;
+ unsigned int shareAccess;
int initialModeBits;
unsigned short baseFid;
smb_fid_t *baseFidp;
| (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)
* extended attributes
*/
initialModeBits = 0666;
- if (extAttributes & 1)
+ if (extAttributes & SMB_ATTR_READONLY)
initialModeBits &= ~0222;
pathp = smb_GetSMBData(inp, NULL);
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
free(hexp);
}
#endif
+
userp = smb_GetUser(vcp, inp);
if (!userp) {
osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
fidflags |= SMB_FID_OPENREAD;
if (desiredAccess & AFS_ACCESS_WRITE)
fidflags |= SMB_FID_OPENWRITE;
+ 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;
/* 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
if ( createDisp == FILE_OVERWRITE ||
createDisp == FILE_OVERWRITE_IF) {
+
setAttr.mask = CM_ATTRMASK_LENGTH;
setAttr.length.LowPart = 0;
setAttr.length.HighPart = 0;
/* 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 */
cm_ReleaseSCache(dscp);
dscp = NULL;
}
+
cm_Open(scp, 0, userp);
/* set inp->fid so that later read calls in same msg can find fid */
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;
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
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
fidflags |= SMB_FID_OPENREAD;
if (desiredAccess & AFS_ACCESS_WRITE)
fidflags |= SMB_FID_OPENWRITE;
+ 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;
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;