windows-nt/Source/XPSP1/NT/base/cluster/resdll/ndquorum/srvcom.c
2020-09-26 16:20:57 +08:00

2244 lines
54 KiB
C

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
srvcom.c
Abstract:
Implements com smb packets
Author:
Ahmed Mohamed (ahmedm) 1-Feb-2000
Revision History:
--*/
#include "srv.h"
#define UPDATE_OUT_LEN(msg, resp_type, resp) \
(msg->out.valid += SIZEOF_SMB_PARAMS(resp_type, resp->ByteCount))
#define UPDATE_FOR_NEXT_ANDX(msg, req_type, req, resp_type, resp) { \
resp->AndXCommand = req->AndXCommand; \
resp->AndXReserved = 0; \
resp->AndXOffset = UPDATE_OUT_LEN(msg, resp_type, resp); \
msg->in.command = req->AndXCommand; \
msg->in.offset += SIZEOF_SMB_PARAMS(req_type, req->ByteCount); \
}
#define SET_REQ(type, name, msg) \
name = ((type)(((PUCHAR) msg->in.smb)+msg->in.offset))
#define SET_RESP(type, name, msg) \
name = ((type)(((PUCHAR) msg->out.smb)+msg->out.valid))
#define SET_TYPE(type, name) \
type name
extern DWORD dm_close(USHORT);
BOOL
SrvComUnknown(
Packet_t * msg
)
{
if (msg == NULL)
return FALSE;
SrvLog(("(------ CANNOT HANDLE THIS COMMAND %x ------)\n",
msg->in.command));
SET_DOSERROR(msg, SERVER, NO_SUPPORT);
return TRUE;
}
#define SRV_DIALECT_STRING "LM1.2X002"
BOOL
SrvComNegotiate(
Packet_t * msg
)
{
LPCSTR szDialect = NULL;
int offset;
USHORT dialect;
BOOL found;
EndPoint_t *ep;
SET_TYPE(PREQ_NEGOTIATE, pReq);
if (msg == NULL)
return FALSE;
ep = msg->endpoint;
SET_REQ(PREQ_NEGOTIATE, pReq, msg);
offset = sizeof(UCHAR);
dialect = 0;
found = FALSE;
while (offset < pReq->ByteCount) {
szDialect = (LPCSTR)NEXT_LOCATION(pReq, REQ_NEGOTIATE, offset);
if (!lstrcmp(szDialect, SRV_DIALECT_STRING)) {
SrvLog(("Using dialect %s\n", szDialect));
found = TRUE;
break;
}
dialect++;
offset += lstrlen(szDialect) + 1 + sizeof(UCHAR);
}
if (found) {
SET_TYPE(PRESP_NEGOTIATE, pResp);
SET_RESP(PRESP_NEGOTIATE, pResp, msg);
// LM1.2X002
msg->out.smb->Flags |= SMB_FLAGS_LOCK_AND_READ_OK;
// spew back the dialect we want...
pResp->WordCount = 13;
pResp->DialectIndex = dialect;
pResp->SecurityMode = NEGOTIATE_ENCRYPT_PASSWORDS|NEGOTIATE_USER_SECURITY;
pResp->MaxBufferSize = (USHORT)msg->out.size;
pResp->MaxMpxCount = (USHORT)SRV_NUM_WORKERS;
pResp->MaxNumberVcs = 1;
pResp->RawMode = 0;
pResp->SessionKey = 1;
pResp->ServerTime.Ushort = 0;
pResp->ServerDate.Ushort = 0;
pResp->ServerTimeZone = 0;
pResp->EncryptionKeyLength = 0;
pResp->Reserved = 0;
pResp->ByteCount = 0;
{
UINT sz;
found = LsaGetChallenge(ep->SrvCtx->LsaHandle,
ep->SrvCtx->LsaPack,
ep->ChallengeBuffer,
sizeof(ep->ChallengeBuffer),
&sz);
if (found == TRUE) {
pResp->ByteCount = (SHORT) sz;
pResp->EncryptionKeyLength = (SHORT) sz;
ep->ChallengeBufferSz = sz;
memcpy(pResp->Buffer, ep->ChallengeBuffer, sz);
UPDATE_OUT_LEN(msg, RESP_NEGOTIATE, pResp);
}
}
}
if (!found) {
// spew back an error to the client...
SET_TYPE(PRESP_OLD_NEGOTIATE, pOldResp);
SET_RESP(PRESP_OLD_NEGOTIATE, pOldResp, msg);
pOldResp->WordCount = 1;
pOldResp->DialectIndex = 0xFFFF;
pOldResp->ByteCount = 0;
msg->out.valid += sizeof(PRESP_OLD_NEGOTIATE);
UPDATE_OUT_LEN(msg, RESP_OLD_NEGOTIATE, pOldResp);
}
return TRUE;
}
BOOL
SrvComSessionSetupAndx(
Packet_t * msg
)
{
PCHAR szAccountName = NULL;
PCHAR szDomainName = NULL;
PCHAR pAccountPassword = NULL;
int offset = 0;
int pwdlen;
BOOL found;
DWORD error;
HANDLE token;
LUID logonid;
EndPoint_t *ep;
SET_TYPE(PRESP_SESSION_SETUP_ANDX, pResp);
SET_TYPE(PREQ_SESSION_SETUP_ANDX, pReq);
if (msg == NULL)
return FALSE;
ep = msg->endpoint;
SET_RESP(PRESP_SESSION_SETUP_ANDX, pResp, msg);
SET_REQ(PREQ_SESSION_SETUP_ANDX, pReq, msg);
pResp->WordCount = 3;
pResp->Action = 0;
pResp->ByteCount = 0;
if (pReq->WordCount == 12)
return FALSE;
SrvLog(("MxBuf: %x MxMpx: %d Key: %x Count: %d\n", pReq->MaxBufferSize,
pReq->MaxMpxCount, pReq->SessionKey, pReq->ByteCount));
SrvLog(("Count: %d Pwd %d\n", pReq->ByteCount, pReq->PasswordLength));
if (pReq->WordCount == 13) {
PREQ_NT_SESSION_SETUP_ANDX pNtReq = (PREQ_NT_SESSION_SETUP_ANDX) pReq;
if (pNtReq->ByteCount > offset) {
pAccountPassword = (PCHAR)
NEXT_LOCATION(pNtReq, REQ_NT_SESSION_SETUP_ANDX, offset);
offset += pNtReq->CaseInsensitivePasswordLength;
offset += pNtReq->CaseSensitivePasswordLength;
}
if (pNtReq->ByteCount > offset) {
szAccountName = (PCHAR)
NEXT_LOCATION(pNtReq, REQ_NT_SESSION_SETUP_ANDX, offset);
offset += lstrlen(szAccountName) + 1;
}
pwdlen = pNtReq->CaseInsensitivePasswordLength;
}
else if (pReq->WordCount == 10) {
if (pReq->ByteCount > offset) {
pAccountPassword = (PCHAR)
NEXT_LOCATION(pReq, REQ_SESSION_SETUP_ANDX, offset);
offset += pReq->PasswordLength;
}
if (pReq->ByteCount > offset) {
szAccountName = (PCHAR)
NEXT_LOCATION(pReq, REQ_SESSION_SETUP_ANDX, offset);
offset += lstrlen(szAccountName) + 1;
}
if (pReq->ByteCount > offset) {
szDomainName = (PCHAR)
NEXT_LOCATION(pReq, REQ_SESSION_SETUP_ANDX, offset);
offset += lstrlen(szDomainName) + 1;
}
pwdlen = pReq->PasswordLength;
}
SrvLog(("setup username: %s\n", szAccountName));
SrvLog(("setup domainname: %s\n", szDomainName));
found = LsaValidateLogon(ep->SrvCtx->LsaHandle,
ep->SrvCtx->LsaPack,
ep->ChallengeBuffer, ep->ChallengeBufferSz,
pAccountPassword, pwdlen,
szAccountName, szDomainName,
&logonid, &token);
if (found == TRUE) {
// we need to remember the token and use it for all io operations
error = FsLogonUser(ep->SrvCtx->FsCtx, token, logonid,
&msg->out.smb->Uid);
if (error != ERROR_SUCCESS) {
SrvLog(("DOSERROR: user logon failed %d\n", error));
SET_DOSERROR(msg, SERVER, TOO_MANY_UIDS);
} else {
// remember logon for this endpoint
ep->LogonId = logonid;
msg->in.smb->Uid = msg->out.smb->Uid;
SrvLog(("Setting up uid %d\n", msg->out.smb->Uid));
}
} else {
SrvLogError(("DOSERROR: could not authenticate user\n"));
SET_DOSERROR(msg, SERVER, BAD_PASSWORD);
}
if (pReq->WordCount == 10) {
UPDATE_FOR_NEXT_ANDX(msg,
REQ_SESSION_SETUP_ANDX, pReq,
RESP_SESSION_SETUP_ANDX, pResp);
} else {
UPDATE_FOR_NEXT_ANDX(msg,
REQ_NT_SESSION_SETUP_ANDX, pReq,
RESP_SESSION_SETUP_ANDX, pResp);
}
return SrvDispatch(msg);
}
BOOL
SrvComTreeConnectAndx(
Packet_t * msg
)
{
PUCHAR pPassword = NULL;
PCHAR szPath = NULL;
PCHAR szService = NULL;
int offset = 0;
DWORD error;
SET_TYPE(PREQ_TREE_CONNECT_ANDX, pReq);
SET_TYPE(PRESP_TREE_CONNECT_ANDX, pResp);
if (msg == NULL)
return FALSE;
SET_REQ(PREQ_TREE_CONNECT_ANDX, pReq, msg);
SET_RESP(PRESP_TREE_CONNECT_ANDX, pResp, msg);
SrvLog(("TreeConnect pwdlen %d cnt %d\n", pReq->PasswordLength, pReq->ByteCount));
if (pReq->ByteCount > offset) {
pPassword = (PUCHAR)
NEXT_LOCATION(pReq, REQ_TREE_CONNECT_ANDX, offset);
offset += pReq->PasswordLength;
}
if (pReq->ByteCount > offset) {
szPath = (PCHAR)
NEXT_LOCATION(pReq, REQ_TREE_CONNECT_ANDX, offset);
offset += lstrlen(szPath) + 1;
}
if (pReq->ByteCount > offset) {
szService = (PCHAR)
NEXT_LOCATION(pReq, REQ_TREE_CONNECT_ANDX, offset);
}
if (szPath != NULL) {
PCHAR s = strrchr(szPath, '\\');
if (s != NULL) {
szPath = s + 1;
}
SrvLog(("Path %s\n", szPath));
}
if (szService != NULL) {
szService[4] = '\0';
SrvLog(("Service %s\n", szService));
}
if (szPath != NULL) {
// convert name to unicode
int wsz;
LPWSTR wpath;
SRV_ASCII_TO_WCHAR(wpath, wsz, szPath, strlen(szPath));
if (wpath)
// Get tree id
error = FsMount(msg->endpoint->SrvCtx->FsCtx,
wpath, msg->in.smb->Uid, &msg->out.smb->Tid);
else
error = ERROR_NOT_ENOUGH_MEMORY;
SRV_ASCII_FREE(wpath);
} else {
error = ERROR_PATH_NOT_FOUND;
}
// it turns out that we can get away with an older-style reply...hehe
pResp->AndXCommand = 0xff;
pResp->AndXReserved = 0;
pResp->WordCount = 2;
if (error == ERROR_SUCCESS) {
pResp->ByteCount = 3;
strcpy((char*)pResp->Buffer, "A:");
SrvLog(("FsMount tid %d\n", msg->out.smb->Tid));
} else {
pResp->ByteCount = 0;
SrvLogError(("WIN32ERROR: FsMount error 0x%08X\n", error));
SET_WIN32ERROR(msg, error);
}
UPDATE_FOR_NEXT_ANDX(msg,
REQ_TREE_CONNECT_ANDX, pReq,
RESP_TREE_CONNECT_ANDX, pResp);
return SrvDispatch(msg);
}
BOOL
SrvComNoAndx(
Packet_t * msg
)
{
return TRUE;
}
BOOL
SrvComTrans(
Packet_t * msg
)
{
return SrvComUnknown(msg);
}
BOOL
SrvComTrans2(
Packet_t * msg
)
{
PUSHORT pSetup;
int iSetup;
Trans2_t t2b;
SET_TYPE(PREQ_TRANSACTION, pReq);
SET_TYPE(PRESP_TRANSACTION, pResp);
if (msg == NULL)
return FALSE;
SET_REQ(PREQ_TRANSACTION, pReq, msg);
SET_RESP(PRESP_TRANSACTION, pResp, msg);
pSetup = (PUSHORT) NEXT_LOCATION(pReq, REQ_TRANSACTION, 0);
for (iSetup = 0; iSetup < pReq->SetupCount; iSetup++)
SrvLog(("Setup[0x%02x] : 0x%04x (%s)\n",
iSetup, pSetup[iSetup],
SrvUnparseTrans2(pSetup[iSetup])));
if (pReq->SetupCount > 1) {
SrvLog(("SetupCount > 1!!!\n"));
SET_DOSERROR(msg, SERVER, ERROR); // ok?
return TRUE;
}
RtlZeroMemory(pResp, sizeof(RESP_TRANSACTION));
pResp->WordCount = 10 + pReq->SetupCount;
pResp->SetupCount = pReq->SetupCount;
RtlCopyMemory((PUSHORT) NEXT_LOCATION(pResp, RESP_TRANSACTION, 0),
pSetup, pResp->SetupCount*sizeof(USHORT));
t2b.in.pReq = pReq;
t2b.in.pParameters = ((PUCHAR)msg->in.smb) + pReq->ParameterOffset;
t2b.in.pData = ((PUCHAR)msg->in.smb) + pReq->DataOffset;
t2b.out.pResp = pResp;
t2b.out.ParameterBytesLeft = pReq->MaxParameterCount;
t2b.out.DataBytesLeft = pReq->MaxDataCount;
t2b.out.pByteCount =
(PUSHORT)NEXT_LOCATION(pResp, RESP_TRANSACTION,
pResp->SetupCount*sizeof(USHORT));
*(t2b.out.pByteCount) = 0;
// initialize parameter and data offset. xxx: todo: need pad
pResp->ParameterOffset = (USHORT) (((PUCHAR)pResp) - (PUCHAR)(msg->out.smb));
pResp->ParameterOffset += sizeof(*pResp);
pResp->ParameterOffset += SIZEOF_TRANS2_RESP_HEADER(pResp);
pResp->DataOffset = pResp->ParameterOffset;
// we increment:
// pResp->WordCount
// pResp->TotalParameterCount
// pResp->TotalDataCount
// pResp->ParameterCount
// pResp->ParameterOffset
// pResp->ParameterDisplacement -- not really, since we do not honor max
// pResp->DataCount
// pResp->DataOffset
// pResp->DataDisplacement -- not really, since we do not honor max
// *(t2b.out.pByteCount)
msg->out.valid += sizeof(RESP_TRANSACTION) + sizeof(USHORT);
// dispatch each transaction...
for (iSetup = 0; iSetup < pReq->SetupCount; iSetup++) {
msg->out.valid += sizeof(USHORT);
msg->in.command = pSetup[iSetup];
if (!Trans2Dispatch(msg, &t2b)) {
// someone bellow us set an error, so we need to stop the loop
// and return TRUE so the packet gets sent.
break;
}
}
SrvLog(("Trans2 %d %d %d %d %d %d %d %d %d %d\n",
pResp->WordCount, pResp->SetupCount,
pResp->TotalParameterCount,
pResp->TotalDataCount,
pResp->ParameterCount,
pResp->ParameterOffset,
pResp->DataCount,
pResp->DataOffset,
*((PUSHORT) pResp->Buffer),
1[((PUSHORT) pResp->Buffer)]));
// need to set length stuff
return TRUE;
}
BOOL
SrvComQueryInformation(
Packet_t * msg
)
{
PVOID fshdl;
USHORT tid;
USHORT uid;
PVOID fsctx;
FsDispatchTable* pDisp;
DWORD error;
PCHAR file_name;
fattr_t attribs;
USHORT sz;
SET_TYPE(PREQ_QUERY_INFORMATION, pReq);
SET_TYPE(PRESP_QUERY_INFORMATION, pResp);
if (msg == NULL)
return FALSE;
tid = msg->in.smb->Tid;
uid = msg->in.smb->Uid;
fsctx = SRV_GET_FS_HANDLE(msg);
pDisp = FsGetHandle(fsctx, tid, uid, &fshdl);
SET_REQ(PREQ_QUERY_INFORMATION, pReq, msg);
SET_RESP(PRESP_QUERY_INFORMATION, pResp, msg);
pResp->WordCount = 10;
pResp->ByteCount = 0;
if (!pDisp) {
SrvLogError(("DOSERROR: could not find dispatch table for uid %d\n", uid));
SET_DOSERROR(msg, SERVER, BAD_UID);
return TRUE;
}
if (pReq->ByteCount < 2) {
SrvLogError(("DOSERROR: ByteCount < 2\n"));
SET_DOSERROR(msg, SERVER, ERROR); // OK?
return TRUE;
}
file_name = (PCHAR)NEXT_LOCATION(pReq,
REQ_QUERY_INFORMATION,
sizeof(UCHAR));
sz = (USHORT) (((char *)file_name) - ((char *)&pReq->Buffer[0]));
if (pReq->ByteCount > sz)
sz = pReq->ByteCount - sz;
else
sz = 1;
if (sz == 0)
file_name = "";
{
// convert name to unicode
int wsz;
LPWSTR wfile_name;
SRV_ASCII_TO_WCHAR(wfile_name, wsz, file_name, sz);
if (wfile_name)
error = pDisp->FsLookup(fshdl, wfile_name, (USHORT)wsz, &attribs);
else
error = ERROR_NOT_ENOUGH_MEMORY;
SRV_ASCII_FREE(wfile_name);
}
if (error) {
SrvLog(("WIN32ERROR: lookup error 0x%08X\n", error));
SET_WIN32ERROR(msg, error);
UPDATE_OUT_LEN(msg, RESP_QUERY_INFORMATION, pResp);
return TRUE;
}
pResp->FileAttributes = attribs_to_smb_attribs(attribs.attributes);
pResp->LastWriteTimeInSeconds = time64_to_smb_timedate(&attribs.mod_time);
RtlZeroMemory(pResp->Reserved, sizeof(pResp->Reserved));
pResp->FileSize = (ULONG) attribs.file_size;
UPDATE_OUT_LEN(msg, RESP_QUERY_INFORMATION, pResp);
return TRUE;
}
BOOL
SrvComSetInformation(
Packet_t * msg
)
{
PVOID fshdl;
USHORT tid;
USHORT uid;
PVOID fsctx;
FsDispatchTable* pDisp;
fattr_t attribs;
DWORD error;
PCHAR file_name;
USHORT sz;
SET_TYPE(PREQ_SET_INFORMATION, pReq);
SET_TYPE(PRESP_SET_INFORMATION, pResp);
if (msg == NULL)
return FALSE;
tid = msg->in.smb->Tid;
uid = msg->in.smb->Uid;
fsctx = SRV_GET_FS_HANDLE(msg);
pDisp = FsGetHandle(fsctx, tid, uid, &fshdl);
SET_REQ(PREQ_SET_INFORMATION, pReq, msg);
SET_RESP(PRESP_SET_INFORMATION, pResp, msg);
pResp->WordCount = 0;
pResp->ByteCount = 0;
if (!pDisp) {
SrvLogError(("DOSERROR: could not find dispatch table for uid %d\n", uid));
SET_DOSERROR(msg, SERVER, BAD_UID);
return TRUE;
}
if (pReq->ByteCount < 2) {
SrvLogError(("DOSERROR: ByteCount < 2\n"));
SET_DOSERROR(msg, SERVER, ERROR); // ok?
return TRUE;
}
file_name = (PCHAR)NEXT_LOCATION(pReq,
REQ_SET_INFORMATION,
sizeof(UCHAR));
attribs.file_size = INVALID_UINT64;
attribs.alloc_size = INVALID_UINT64;
attribs.access_time = INVALID_TIME64;
attribs.create_time = INVALID_TIME64;
attribs.mod_time = INVALID_TIME64;
if (pReq->LastWriteTimeInSeconds)
attribs.mod_time = smb_timedate_to_time64(pReq->LastWriteTimeInSeconds);
attribs.attributes = smb_attribs_to_attribs(pReq->FileAttributes);
sz = (USHORT) (((char *)file_name) - ((char *)&pReq->Buffer[0]));
if (pReq->ByteCount > sz)
sz = pReq->ByteCount - sz;
else
sz = 1;
if (sz == 0)
file_name = "";
{
// convert name to unicode
int wsz;
LPWSTR wfile_name;
SRV_ASCII_TO_WCHAR(wfile_name, wsz, file_name, sz);
if (wfile_name)
error = pDisp->FsSetAttr2(fshdl, wfile_name, (USHORT)wsz, &attribs);
else
error = ERROR_NOT_ENOUGH_MEMORY;
SRV_ASCII_FREE(wfile_name);
}
if (error) {
SrvLog(("WIN32ERROR: set_attr error 0x%08X\n", error));
SET_WIN32ERROR(msg, error);
}
UPDATE_OUT_LEN(msg, RESP_SET_INFORMATION, pResp);
return TRUE;
}
BOOL
SrvComCheckDirectory(
Packet_t * msg
)
{
PVOID fshdl;
USHORT tid;
USHORT uid;
PVOID fsctx;
FsDispatchTable* pDisp;
fattr_t attribs;
DWORD error;
PCHAR file_name;
USHORT sz;
SET_TYPE(PREQ_CHECK_DIRECTORY, pReq);
SET_TYPE(PRESP_CHECK_DIRECTORY, pResp);
if (msg == NULL)
return FALSE;
tid = msg->in.smb->Tid;
uid = msg->in.smb->Uid;
fsctx = SRV_GET_FS_HANDLE(msg);
pDisp = FsGetHandle(fsctx, tid, uid, &fshdl);
SET_REQ(PREQ_CHECK_DIRECTORY, pReq, msg);
SET_RESP(PRESP_CHECK_DIRECTORY, pResp, msg);
pResp->WordCount = 0;
pResp->ByteCount = 0;
if (!pDisp) {
SrvLogError(("DOSERROR: could not find dispatch table for uid %d\n", uid));
SET_DOSERROR(msg, SERVER, BAD_UID);
return TRUE;
}
if (pReq->ByteCount < 2) {
SrvLogError(("DOSERROR: ByteCount < 2\n"));
SET_DOSERROR(msg, SERVER, ERROR); // ok?
return TRUE;
}
file_name = (PCHAR)NEXT_LOCATION(pReq,
REQ_QUERY_INFORMATION,
sizeof(UCHAR));
sz = (USHORT) (((char *)file_name) - ((char *)&pReq->Buffer[0]));
if (pReq->ByteCount > sz)
sz = pReq->ByteCount - sz;
else
sz = 1;
if (sz == 0)
file_name = "";
{
// convert name to unicode
int wsz;
LPWSTR wfile_name;
SRV_ASCII_TO_WCHAR(wfile_name, wsz, file_name, sz);
if (wfile_name)
error = pDisp->FsLookup(fshdl, wfile_name, (USHORT)wsz, &attribs);
else
error = ERROR_NOT_ENOUGH_MEMORY;
SRV_ASCII_FREE(wfile_name);
}
if (error) {
SrvLog(("ERROR: lookup error 0x%08X\n", error));
SET_WIN32ERROR(msg, error);
} else if (!(attribs.attributes & ATTR_DIRECTORY)) {
SrvLog(("ERROR: lookup error 0x%08X\n", error));
SET_DOSERROR(msg, DOS, BAD_PATH);
}
UPDATE_OUT_LEN(msg, RESP_CHECK_DIRECTORY, pResp);
return TRUE;
}
BOOL
SrvComFindClose2(
Packet_t * msg
)
{
PVOID fshdl;
USHORT tid;
USHORT uid;
PVOID fsctx;
FsDispatchTable* pDisp;
DWORD error;
SET_TYPE(PREQ_FIND_CLOSE2, pReq);
SET_TYPE(PRESP_FIND_CLOSE2, pResp);
if (msg == NULL)
return FALSE;
tid = msg->in.smb->Tid;
uid = msg->in.smb->Uid;
fsctx = SRV_GET_FS_HANDLE(msg);
pDisp = FsGetHandle(fsctx, tid, uid, &fshdl);
SET_REQ(PREQ_FIND_CLOSE2, pReq, msg);
SET_RESP(PRESP_FIND_CLOSE2, pResp, msg);
pResp->WordCount = 0;
pResp->ByteCount = 0;
if (!pDisp) {
SrvLogError(("DOSERROR: could not find dispatch table for uid %d\n", uid));
SET_DOSERROR(msg, SERVER, BAD_UID);
return TRUE;
}
if (pReq->WordCount != 1) {
SrvLogError(("DOSERROR: WordCount != 1\n"));
SET_DOSERROR(msg, SERVER, ERROR); // ok?
return TRUE;
}
error = dm_close(pReq->Sid);
if (error) {
SrvLog(("WIN32ERROR: findclose2 error 0x%08X\n", error));
SET_WIN32ERROR(msg, error);
return TRUE;
}
UPDATE_OUT_LEN(msg, RESP_FIND_CLOSE2, pResp);
return TRUE;
}
BOOL
SrvComFindNotifyClose(
Packet_t * msg
)
{
PVOID fshdl;
USHORT tid;
USHORT uid;
PVOID fsctx;
FsDispatchTable* pDisp;
DWORD error;
SET_TYPE(PREQ_FIND_NOTIFY_CLOSE, pReq);
SET_TYPE(PRESP_FIND_NOTIFY_CLOSE, pResp);
if (msg == NULL)
return FALSE;
tid = msg->in.smb->Tid;
uid = msg->in.smb->Uid;
fsctx = SRV_GET_FS_HANDLE(msg);
pDisp = FsGetHandle(fsctx, tid, uid, &fshdl);
SET_REQ(PREQ_FIND_NOTIFY_CLOSE, pReq, msg);
SET_RESP(PRESP_FIND_NOTIFY_CLOSE, pResp, msg);
pResp->WordCount = 0;
pResp->ByteCount = 0;
if (!pDisp) {
SrvLogError(("DOSERROR: could not find dispatch table for uid %d\n", uid));
SET_DOSERROR(msg, SERVER, BAD_UID);
return TRUE;
}
if (pReq->WordCount != 1) {
SrvLogError(("DOSERROR: WordCount != 1 got %d handle %x\n", pReq->WordCount, pReq->Handle));
SET_DOSERROR(msg, SERVER, ERROR); // ok?
return TRUE;
}
error = dm_close(pReq->Handle);
if (error) {
SrvLog(("WIN32ERROR: notifyclose error 0x%08X\n", error));
SET_WIN32ERROR(msg, error);
return TRUE;
}
UPDATE_OUT_LEN(msg, RESP_FIND_NOTIFY_CLOSE, pResp);
return TRUE;
}
BOOL
SrvComDelete(
Packet_t * msg
)
{
PVOID fshdl;
USHORT tid;
USHORT uid;
PVOID fsctx;
FsDispatchTable* pDisp;
PCHAR file_name;
DWORD error;
USHORT sz;
SET_TYPE(PREQ_DELETE, pReq);
SET_TYPE(PRESP_DELETE, pResp);
if (msg == NULL)
return FALSE;
tid = msg->in.smb->Tid;
uid = msg->in.smb->Uid;
fsctx = SRV_GET_FS_HANDLE(msg);
pDisp = FsGetHandle(fsctx, tid, uid, &fshdl);
SET_REQ(PREQ_DELETE, pReq, msg);
SET_RESP(PRESP_DELETE, pResp, msg);
pResp->WordCount = 0;
pResp->ByteCount = 0;
if (!pDisp) {
SrvLogError(("DOSERROR: could not find dispatch table for uid %d\n", uid));
SET_DOSERROR(msg, SERVER, BAD_UID);
return TRUE;
}
if (pReq->ByteCount < 2) {
SrvLogError(("DOSERROR: ByteCount < 2\n"));
SET_DOSERROR(msg, SERVER, ERROR); // ok?
return TRUE;
}
file_name = (PCHAR)NEXT_LOCATION(pReq,
REQ_DELETE,
sizeof(UCHAR));
sz = (USHORT) (((char *)file_name) - ((char *)&pReq->Buffer[0]));
if (pReq->ByteCount > sz)
sz = pReq->ByteCount - sz;
else
sz = 1;
if (sz == 0)
file_name = "";
{
// convert name to unicode
int wsz;
LPWSTR wfile_name;
SRV_ASCII_TO_WCHAR(wfile_name, wsz, file_name, sz);
if (wfile_name)
error = pDisp->FsRemove(fshdl, wfile_name, (USHORT)wsz);
else
error = ERROR_NOT_ENOUGH_MEMORY;
SRV_ASCII_FREE(wfile_name);
}
if (error) {
SrvLog(("WIN32EROR: remove error 0x%08X\n", error));
SET_WIN32ERROR(msg, error);
}
UPDATE_OUT_LEN(msg, RESP_DELETE, pResp);
return TRUE;
}
BOOL
SrvComRename(
Packet_t * msg
)
{
PVOID fshdl;
USHORT tid;
USHORT uid;
PVOID fsctx;
FsDispatchTable* pDisp;
DWORD error;
PCHAR to_name, from_name;
SET_TYPE(PREQ_RENAME, pReq);
SET_TYPE(PRESP_RENAME, pResp);
if (msg == NULL)
return FALSE;
tid = msg->in.smb->Tid;
uid = msg->in.smb->Uid;
fsctx = SRV_GET_FS_HANDLE(msg);
pDisp = FsGetHandle(fsctx, tid, uid, &fshdl);
SET_REQ(PREQ_RENAME, pReq, msg);
SET_RESP(PRESP_RENAME, pResp, msg);
pResp->WordCount = 0;
pResp->ByteCount = 0;
if (!pDisp) {
SrvLogError(("DOSERROR: could not find dispatch table for uid %d\n", uid));
SET_DOSERROR(msg, SERVER, BAD_UID);
return TRUE;
}
if (pReq->ByteCount < 4) {
SrvLogError(("DOSERROR: ByteCount < 4\n"));
SET_DOSERROR(msg, SERVER, ERROR); // ok?
return TRUE;
}
from_name = (PCHAR)NEXT_LOCATION(pReq,
REQ_RENAME,
sizeof(UCHAR));
to_name = (PCHAR)NEXT_LOCATION(pReq,
REQ_RENAME,
2*sizeof(UCHAR)+
lstrlen(from_name)+1);
SrvLog(("Rename: attrib %x\n", pReq->SearchAttributes));
{
// convert name to unicode
int wfsz, wtsz;
LPWSTR wfrom_name, wto_name;
SRV_ASCII_TO_WCHAR(wfrom_name, wfsz, from_name, lstrlen(from_name));
SRV_ASCII_TO_WCHAR(wto_name, wtsz, to_name, lstrlen(to_name));
if (wfrom_name && wto_name)
error = pDisp->FsRename(fshdl, wfrom_name, (USHORT)wfsz,
wto_name, (USHORT) wtsz);
else
error = ERROR_NOT_ENOUGH_MEMORY;
SRV_ASCII_FREE(wfrom_name);
SRV_ASCII_FREE(wto_name);
}
if (error) {
SrvLog(("WIN32ERROR: rename error 0x%08X\n", error));
SET_WIN32ERROR(msg, error);
}
UPDATE_OUT_LEN(msg, RESP_RENAME, pResp);
return TRUE;
}
BOOL
SrvComCreateDirectory(
Packet_t * msg
)
{
DWORD error;
PVOID fshdl;
USHORT tid;
USHORT uid;
PVOID fsctx;
FsDispatchTable* pDisp;
SET_TYPE(PREQ_CREATE_DIRECTORY, pReq);
SET_TYPE(PRESP_CREATE_DIRECTORY, pResp);
if (msg == NULL)
return FALSE;
tid = msg->in.smb->Tid;
uid = msg->in.smb->Uid;
fsctx = SRV_GET_FS_HANDLE(msg);
pDisp = FsGetHandle(fsctx, tid, uid, &fshdl);
SET_REQ(PREQ_CREATE_DIRECTORY, pReq, msg);
SET_RESP(PRESP_CREATE_DIRECTORY, pResp, msg);
pResp->WordCount = 0;
pResp->ByteCount = 0;
if (!pDisp) {
SrvLogError(("DOSERROR: could not find dispatch table for uid %d\n", uid));
SET_DOSERROR(msg, SERVER, BAD_UID);
return TRUE;
}
if (pReq->ByteCount >= 2) {
USHORT sz;
PCHAR file_name = (PCHAR)NEXT_LOCATION(pReq,
REQ_CREATE_DIRECTORY,
sizeof(UCHAR));
sz = (USHORT) (((char *)file_name) - ((char *)&pReq->Buffer[0]));
if (pReq->ByteCount > sz)
sz = pReq->ByteCount - sz;
else
sz = 1;
{
// convert name to unicode
int wsz;
LPWSTR wfile_name;
SRV_ASCII_TO_WCHAR(wfile_name, wsz, file_name, sz);
if (wfile_name)
error = pDisp->FsMkdir(fshdl, wfile_name, (USHORT)wsz, 0);
else
error = ERROR_NOT_ENOUGH_MEMORY;
SRV_ASCII_FREE(wfile_name);
}
} else {
error = ERROR_BAD_NETPATH;
}
if (error) {
SrvLog(("WIN32ERROR: mkdir error 0x%08X\n", error));
SET_WIN32ERROR(msg, error);
}
UPDATE_OUT_LEN(msg, RESP_CREATE_DIRECTORY, pResp);
return TRUE;
}
BOOL
SrvComDeleteDirectory(
Packet_t * msg
)
{
PVOID fshdl;
USHORT tid;
USHORT uid;
PVOID fsctx;
FsDispatchTable* pDisp;
DWORD error;
PCHAR file_name;
USHORT sz;
SET_TYPE(PREQ_DELETE_DIRECTORY, pReq);
SET_TYPE(PRESP_DELETE_DIRECTORY, pResp);
if (msg == NULL)
return FALSE;
tid = msg->in.smb->Tid;
uid = msg->in.smb->Uid;
fsctx = SRV_GET_FS_HANDLE(msg);
pDisp = FsGetHandle(fsctx, tid, uid, &fshdl);
SET_REQ(PREQ_DELETE_DIRECTORY, pReq, msg);
SET_RESP(PRESP_DELETE_DIRECTORY, pResp, msg);
pResp->WordCount = 0;
pResp->ByteCount = 0;
if (!pDisp) {
SrvLogError(("DOSERROR: could not find dispatch table for uid %d\n", uid));
SET_DOSERROR(msg, SERVER, BAD_UID);
return TRUE;
}
if (pReq->ByteCount < 2) {
SrvLogError(("DOSERROR: ByteCount < 2\n"));
SET_DOSERROR(msg, SERVER, ERROR); // ok?
return TRUE;
}
file_name = (PCHAR)NEXT_LOCATION(pReq,
REQ_DELETE_DIRECTORY,
sizeof(UCHAR));
sz = (USHORT) (((char *)file_name) - ((char *)&pReq->Buffer[0]));
if (pReq->ByteCount > sz)
sz = pReq->ByteCount - sz;
else
sz = 1;
{
// convert name to unicode
int wsz;
LPWSTR wfile_name;
SRV_ASCII_TO_WCHAR(wfile_name, wsz, file_name, sz);
if (wfile_name)
error = pDisp->FsRmdir(fshdl, wfile_name, (USHORT)wsz);
else
error = ERROR_NOT_ENOUGH_MEMORY;
SRV_ASCII_FREE(wfile_name);
}
if (error) {
SrvLog(("WIN32ERROR: rmdir error 0x%08X\n", error));
SET_WIN32ERROR(msg, error);
}
UPDATE_OUT_LEN(msg, RESP_DELETE_DIRECTORY, pResp);
return TRUE;
}
BOOL
SrvComOpenAndx(
Packet_t * msg
)
{
PVOID fshdl;
USHORT tid;
USHORT uid;
PVOID fsctx;
FsDispatchTable* pDisp;
PCHAR file_name;
BOOL additional_info;
UINT32 flags;
fattr_t attr;
DWORD error;
USHORT sz;
UINT32 action;
SET_TYPE(PREQ_OPEN_ANDX, pReq);
SET_TYPE(PRESP_OPEN_ANDX, pResp);
if (msg == NULL)
return FALSE;
tid = msg->in.smb->Tid;
uid = msg->in.smb->Uid;
fsctx = SRV_GET_FS_HANDLE(msg);
pDisp = FsGetHandle(fsctx, tid, uid, &fshdl);
SET_REQ(PREQ_OPEN_ANDX, pReq, msg);
SET_RESP(PRESP_OPEN_ANDX, pResp, msg);
pResp->WordCount = 15;
pResp->AndXCommand = 0xff;
pResp->AndXReserved = 0;
pResp->FileType = 0;
pResp->DeviceState = 0;
// XXX - for actual Action value, need to do a lookup beforehand...
pResp->Action = 0;
// XXX - is ServerFid = 0 really ok? It seems like it never gets used...
pResp->ServerFid = 0;
pResp->Reserved = 0;
pResp->ByteCount = 0;
if (!pDisp) {
SrvLogError(("DOSERROR: could not find dispatch table for uid %d\n", uid));
SET_DOSERROR(msg, SERVER, BAD_UID);
return TRUE;
}
if (pReq->WordCount != 15) {
SrvLogError(("DOSERROR: WordCount != 15\n"));
SET_DOSERROR(msg, SERVER, ERROR); // ok?
return TRUE;
}
file_name = (PCHAR)NEXT_LOCATION(pReq,
REQ_OPEN_ANDX,
sizeof(UCHAR));
SrvLog(("OpenX: Flags %x Access %x Srch %x Attr %x Open %x Size %x\n",
pReq->Flags, pReq->DesiredAccess, pReq->SearchAttributes,
pReq->FileAttributes, pReq->OpenFunction, pReq->AllocationSize));
additional_info = (pReq->Flags & SMB_OPEN_QUERY_INFORMATION);
flags = smb_access_to_flags(pReq->DesiredAccess) | smb_openfunc_to_flags(pReq->OpenFunction);
if (!(flags & FS_DISP_MASK)) {
// XXX --- error!!!
SrvLog(("DOSERROR: nothing to do!!!!\n"));
SET_DOSERROR(msg, SERVER, ERROR); // ok
return TRUE;
}
attr.file_size = INVALID_UINT64;
attr.alloc_size = INVALID_UINT64;
attr.create_time = smb_timedate_to_time64(pReq->CreationTimeInSeconds);
attr.access_time = INVALID_TIME64;
attr.mod_time = INVALID_TIME64;
attr.attributes = smb_attribs_to_attribs(pReq->FileAttributes);
if (*file_name == '\\') {
file_name++;
}
sz = (USHORT) (((char *)file_name) - ((char *)&pReq->Buffer[0]));
if (pReq->ByteCount > sz)
sz = pReq->ByteCount - sz;
else
sz = 1;
if (sz == 0)
file_name = "";
{
// convert name to unicode
int wsz;
LPWSTR wfile_name;
SRV_ASCII_TO_WCHAR(wfile_name, wsz, file_name, sz);
if (wfile_name) {
fhandle_t fid;
error = pDisp->FsCreate(fshdl,
wfile_name, (USHORT)wsz,
flags,
&attr,
&fid,
&action);
pResp->Fid = fid;
} else {
error = ERROR_NOT_ENOUGH_MEMORY;
}
SRV_ASCII_FREE(wfile_name);
}
if (error) {
SrvLog(("WIN32ERROR: create error 0x%08X\n", error));
SET_WIN32ERROR(msg, error);
UPDATE_OUT_LEN(msg, RESP_OPEN_ANDX, pResp);
return TRUE;
}
if (additional_info) {
error = pDisp->FsGetAttr(fshdl, pResp->Fid, &attr);
if (error) {
SrvLog(("WIN32ERROR: get_attr error 0x%08X\n", error));
SET_WIN32ERROR(msg, error);
return TRUE;
}
pResp->FileAttributes = attribs_to_smb_attribs(attr.attributes);
pResp->LastWriteTimeInSeconds = time64_to_smb_timedate(&attr.mod_time);
pResp->DataSize = (ULONG) attr.file_size;
} else {
pResp->FileAttributes = 0;
pResp->LastWriteTimeInSeconds = 0;
pResp->DataSize = 0;
}
pResp->WordCount = 15;
pResp->GrantedAccess = pReq->DesiredAccess & SMB_DA_FCB_MASK;
if (!(action & ACCESS_WRITE)) {
if ((pResp->GrantedAccess & SMB_DA_ACCESS_MASK) == SMB_DA_ACCESS_WRITE) {
pResp->GrantedAccess &= ~SMB_DA_ACCESS_WRITE;
}
if ((pResp->GrantedAccess & SMB_DA_ACCESS_MASK) == SMB_DA_ACCESS_READ_WRITE) {
pResp->GrantedAccess &= ~SMB_DA_ACCESS_READ_WRITE;
}
}
pResp->Action = action & ~FS_ACCESS_MASK;
SrvLog(("GrantAccess 0x%x DesiredAccess %x addition %d sz %d\n", pResp->GrantedAccess,
pReq->DesiredAccess, additional_info, pResp->DataSize));
UPDATE_FOR_NEXT_ANDX(msg,
REQ_OPEN_ANDX, pReq,
RESP_OPEN_ANDX, pResp);
return SrvDispatch(msg);
}
BOOL
SrvComOpen(
Packet_t * msg
)
{
PVOID fshdl;
USHORT tid;
USHORT uid;
PVOID fsctx;
FsDispatchTable* pDisp;
UINT32 flags;
fattr_t attr;
DWORD error;
UINT32 action;
USHORT sz;
PCHAR file_name;
SET_TYPE(PREQ_OPEN, pReq);
SET_TYPE(PRESP_OPEN, pResp);
if (msg == NULL)
return FALSE;
tid = msg->in.smb->Tid;
uid = msg->in.smb->Uid;
fsctx = SRV_GET_FS_HANDLE(msg);
pDisp = FsGetHandle(fsctx, tid, uid, &fshdl);
SET_REQ(PREQ_OPEN, pReq, msg);
SET_RESP(PRESP_OPEN, pResp, msg);
pResp->WordCount = 7;
// XXX - is ServerFid = 0 really ok? It seems like it never gets used...
pResp->Fid = 0xffff;
pResp->ByteCount = 0;
if (!pDisp) {
SrvLogError(("DOSERROR: could not find dispatch table for uid %d\n", uid));
SET_DOSERROR(msg, SERVER, BAD_UID);
return TRUE;
}
if (pReq->WordCount != 2) {
SrvLogError(("DOSERROR: WordCount != 2\n"));
SET_DOSERROR(msg, SERVER, ERROR); // ok?
return TRUE;
}
file_name = (PCHAR)NEXT_LOCATION(pReq,
REQ_OPEN,
sizeof(UCHAR));
flags = DISP_OPEN_EXISTING | smb_access_to_flags(pReq->DesiredAccess);
if (*file_name == '\\') {
file_name++;
}
sz = (USHORT) (((char *)file_name) - ((char *)&pReq->Buffer[0]));
if (pReq->ByteCount > sz)
sz = pReq->ByteCount - sz;
else
sz = 1;
if (sz == 0)
file_name = "";
{
// convert name to unicode
int wsz;
LPWSTR wfile_name;
SRV_ASCII_TO_WCHAR(wfile_name, wsz, file_name, sz);
if (wfile_name) {
fhandle_t fid;
error = pDisp->FsCreate(fshdl,
wfile_name, (USHORT)wsz,
flags,
NULL,
&fid,
&action);
pResp->Fid = fid;
} else {
error = ERROR_NOT_ENOUGH_MEMORY;
}
SRV_ASCII_FREE(wfile_name);
}
if (error) {
SrvLog(("WIN32ERROR: create error 0x%08X\n", error));
SET_WIN32ERROR(msg, error);
UPDATE_OUT_LEN(msg, RESP_OPEN, pResp);
return TRUE;
}
error = pDisp->FsGetAttr(fshdl, pResp->Fid, &attr);
if (error) {
SrvLog(("WIN32ERROR: get_attr error 0x%08X\n", error));
SET_WIN32ERROR(msg, error);
UPDATE_OUT_LEN(msg, RESP_OPEN, pResp);
return TRUE;
}
pResp->FileAttributes = attribs_to_smb_attribs(attr.attributes);
pResp->LastWriteTimeInSeconds = time64_to_smb_timedate(&attr.mod_time);
pResp->DataSize = (ULONG)attr.file_size;
pResp->GrantedAccess = pReq->DesiredAccess & SMB_DA_FCB_MASK;
if (!(action & ACCESS_WRITE)) {
if ((pResp->GrantedAccess & SMB_DA_ACCESS_MASK) == SMB_DA_ACCESS_WRITE) {
pResp->GrantedAccess &= ~SMB_DA_ACCESS_WRITE;
}
if ((pResp->GrantedAccess & SMB_DA_ACCESS_MASK) == SMB_DA_ACCESS_READ_WRITE) {
pResp->GrantedAccess &= ~SMB_DA_ACCESS_READ_WRITE;
}
}
SrvLog(("GrantAccess 0x%x DesiredAccess %x sz %d\n", pResp->GrantedAccess,
pReq->DesiredAccess, pResp->DataSize));
UPDATE_OUT_LEN(msg, RESP_OPEN, pResp);
return TRUE;
}
BOOL
SrvComWrite(
Packet_t * msg
)
{
PVOID fshdl;
USHORT tid;
USHORT uid;
PVOID fsctx;
FsDispatchTable* pDisp;
ULONG offset;
DWORD error;
USHORT count, actual_count;
void *data;
SET_TYPE(PREQ_WRITE, pReq);
SET_TYPE(PRESP_WRITE, pResp);
if (msg == NULL)
return FALSE;
tid = msg->in.smb->Tid;
uid = msg->in.smb->Uid;
fsctx = SRV_GET_FS_HANDLE(msg);
pDisp = FsGetHandle(fsctx, tid, uid, &fshdl);
SET_REQ(PREQ_WRITE, pReq, msg);
SET_RESP(PRESP_WRITE, pResp, msg);
if (!pDisp) {
SrvLogError(("DOSERROR: could not find dispatch table for uid %d\n", uid));
SET_DOSERROR(msg, SERVER, BAD_UID);
return TRUE;
}
if (pReq->WordCount != 5) {
SrvLogError(("DOSERROR: WordCount != 5\n"));
SET_DOSERROR(msg, SERVER, ERROR); // ok?
return TRUE;
}
count = pReq->Count;
offset = pReq->Offset;
// NOTE -- it turns out that the BufferFormat and DataLength fields
// do not exist!
data = (void*)NEXT_LOCATION(pReq,
REQ_WRITE,
0);
actual_count = count;
error = pDisp->FsWrite(fshdl, pReq->Fid, offset, &actual_count, data, NULL);
if (error) {
SrvLog(("WIN32ERROR: write error 0x%08X\n", error));
SET_WIN32ERROR(msg, error);
}
pResp->WordCount = 1;
pResp->Count = actual_count;
pResp->ByteCount = 0;
UPDATE_OUT_LEN(msg, RESP_WRITE, pResp);
return TRUE;
}
BOOL
SrvComClose(
Packet_t * msg
)
{
PVOID fshdl;
USHORT tid;
USHORT uid;
PVOID fsctx;
FsDispatchTable* pDisp;
DWORD error;
SET_TYPE(PREQ_CLOSE, pReq);
SET_TYPE(PRESP_CLOSE, pResp);
if (msg == NULL)
return FALSE;
tid = msg->in.smb->Tid;
uid = msg->in.smb->Uid;
fsctx = SRV_GET_FS_HANDLE(msg);
pDisp = FsGetHandle(fsctx, tid, uid, &fshdl);
SET_REQ(PREQ_CLOSE, pReq, msg);
SET_RESP(PRESP_CLOSE, pResp, msg);
if (!pDisp) {
SrvLogError(("DOSERROR: could not find dispatch table for uid %d\n", uid));
SET_DOSERROR(msg, SERVER, BAD_UID);
return TRUE;
}
error = pDisp->FsClose(fshdl, pReq->Fid);
if (error) {
SrvLog(("WIN32ERROR: close error 0x%08X\n", error));
SET_WIN32ERROR(msg, error);
}
pResp->WordCount = 0;
pResp->ByteCount = 0;
UPDATE_OUT_LEN(msg, RESP_CLOSE, pResp);
return TRUE;
}
void
WINAPI
SrvReadContinue(PVOID p, UINT32 status, UINT32 length)
{
Packet_t *msg = (Packet_t *) p;
SET_TYPE(PREQ_READ_ANDX, pReq);
SET_TYPE(PRESP_READ_ANDX, pResp);
DWORD consumed;
if (msg == NULL)
return;
SET_REQ(PREQ_READ_ANDX, pReq, msg);
SET_RESP(PRESP_READ_ANDX, pResp, msg);
consumed = (DWORD)(pResp->Buffer - (PUCHAR)msg->out.smb);
if (status == ERROR_SUCCESS) {
pResp->WordCount = 12;
pResp->Remaining = 0;
pResp->DataCompactionMode = 0;
pResp->Reserved = 0;
pResp->Reserved2 = 0;
RtlZeroMemory(pResp->Reserved3, sizeof(pResp->Reserved3));
pResp->DataLength = (USHORT) length;
pResp->DataOffset = (USHORT) consumed;
pResp->ByteCount = (USHORT) length;
UPDATE_FOR_NEXT_ANDX(msg,
REQ_READ_ANDX, pReq,
RESP_READ_ANDX, pResp);
if (msg->in.command != 0xFF)
SrvDispatch(msg);
} else {
SrvLog(("WIN32ERROR: read error 0x%08X\n", status));
SET_WIN32ERROR(msg, status);
pResp->ByteCount = 0;
UPDATE_OUT_LEN(msg, RESP_READ_ANDX, pResp);
}
SrvFinalize(msg);
}
BOOL
SrvComReadAndx(
Packet_t * msg
)
{
PVOID fshdl;
USHORT tid;
USHORT uid;
PVOID fsctx;
FsDispatchTable* pDisp;
DWORD consumed;
DWORD remaining;
USHORT MinCount;
USHORT MaxCount;
USHORT actual_count;
ULONG offset;
DWORD error;
SET_TYPE(PREQ_READ_ANDX, pReq);
SET_TYPE(PRESP_READ_ANDX, pResp);
if (msg == NULL)
return FALSE;
tid = msg->in.smb->Tid;
uid = msg->in.smb->Uid;
fsctx = SRV_GET_FS_HANDLE(msg);
pDisp = FsGetHandle(fsctx, tid, uid, &fshdl);
SET_REQ(PREQ_READ_ANDX, pReq, msg);
SET_RESP(PRESP_READ_ANDX, pResp, msg);
if (!pDisp) {
SrvLogError(("DOSERROR: could not find dispatch table for uid %d\n", uid));
SET_DOSERROR(msg, SERVER, BAD_UID);
return TRUE;
}
if (pReq->WordCount != 10) {
SrvLogError(("DOSERROR: WordCount != 10\n"));
SET_DOSERROR(msg, SERVER, ERROR); // ok
return TRUE;
}
consumed = (DWORD)(pResp->Buffer - (PUCHAR)msg->out.smb);
remaining = msg->out.size - consumed;
MinCount = pReq->MinCount;
MaxCount = pReq->MaxCount;
offset = pReq->Offset;
SrvLog(("Fid %d MaxCount = %d, MinCount = %d\n", pReq->Fid, MaxCount, MinCount));
if (MaxCount > remaining) {
SrvLog(("DOSERROR: MaxCount (%d) > remaining (%d)\n", MaxCount, remaining));
SET_DOSERROR(msg, SERVER, ERROR); // XXX -- ok?
return TRUE;
}
actual_count = MaxCount;
msg->tag = ERROR_IO_PENDING;
msg->completion = SrvReadContinue;
error = pDisp->FsRead(fshdl, pReq->Fid, offset, &actual_count, pResp->Buffer, (PVOID)msg);
if (error) {
if (error == ERROR_IO_PENDING) {
return ERROR_IO_PENDING;
}
SrvLog(("WIN32ERROR: read error 0x%08X\n", error));
SET_WIN32ERROR(msg, error);
pResp->ByteCount = 0;
UPDATE_OUT_LEN(msg, RESP_READ_ANDX, pResp);
return TRUE;
}
msg->tag = 0;
pResp->WordCount = 12;
pResp->Remaining = 0;
pResp->DataCompactionMode = 0;
pResp->Reserved = 0;
pResp->Reserved2 = 0;
RtlZeroMemory(pResp->Reserved3, sizeof(pResp->Reserved3));
pResp->DataLength = actual_count;
pResp->DataOffset = (USHORT) consumed;
pResp->ByteCount = actual_count;
UPDATE_FOR_NEXT_ANDX(msg,
REQ_READ_ANDX, pReq,
RESP_READ_ANDX, pResp);
return SrvDispatch(msg);
}
BOOL
SrvComQueryInformation2(
Packet_t * msg
)
{
PVOID fshdl;
USHORT tid;
USHORT uid;
PVOID fsctx;
FsDispatchTable* pDisp;
fattr_t attribs;
DWORD error;
SET_TYPE(PREQ_QUERY_INFORMATION2, pReq);
SET_TYPE(PRESP_QUERY_INFORMATION2, pResp);
if (msg == NULL)
return FALSE;
tid = msg->in.smb->Tid;
uid = msg->in.smb->Uid;
fsctx = SRV_GET_FS_HANDLE(msg);
pDisp = FsGetHandle(fsctx, tid, uid, &fshdl);
SET_REQ(PREQ_QUERY_INFORMATION2, pReq, msg);
SET_RESP(PRESP_QUERY_INFORMATION2, pResp, msg);
pResp->WordCount = 11;
pResp->ByteCount = 0;
if (!pDisp) {
SrvLogError(("DOSERROR: could not find dispatch table for uid %d\n", uid));
SET_DOSERROR(msg, SERVER, BAD_UID);
return TRUE;
}
if (pReq->WordCount != 1) {
SrvLogError(("DOSERROR: WordCount != 1\n"));
SET_DOSERROR(msg, SERVER, ERROR); // ok?
return TRUE;
}
error = pDisp->FsGetAttr(fshdl, pReq->Fid, &attribs);
if (error) {
SrvLog(("WIN32ERROR: get_attr error 0x%08X\n", error));
SET_WIN32ERROR(msg, error);
UPDATE_OUT_LEN(msg, RESP_QUERY_INFORMATION2, pResp);
return TRUE;
}
RtlZeroMemory(&pResp->CreationDate, sizeof(USHORT) * 6);
time64_to_smb_datetime(&attribs.create_time,
&pResp->CreationDate.Ushort,
&pResp->CreationTime.Ushort);
time64_to_smb_datetime(&attribs.access_time,
&pResp->LastAccessDate.Ushort,
&pResp->LastAccessTime.Ushort);
time64_to_smb_datetime(&attribs.mod_time,
&pResp->LastWriteDate.Ushort,
&pResp->LastWriteTime.Ushort);
pResp->FileDataSize = (ULONG) attribs.file_size;
pResp->FileAllocationSize = (ULONG)attribs.alloc_size;
pResp->FileAttributes = attribs_to_smb_attribs(attribs.attributes);
UPDATE_OUT_LEN(msg, RESP_QUERY_INFORMATION2, pResp);
return TRUE;
}
BOOL
SrvComSetInformation2(
Packet_t * msg
)
{
PVOID fshdl;
USHORT tid;
USHORT uid;
PVOID fsctx;
FsDispatchTable* pDisp;
fattr_t attribs;
DWORD error;
SET_TYPE(PREQ_SET_INFORMATION2, pReq);
SET_TYPE(PRESP_SET_INFORMATION2, pResp);
if (msg == NULL)
return FALSE;
tid = msg->in.smb->Tid;
uid = msg->in.smb->Uid;
fsctx = SRV_GET_FS_HANDLE(msg);
pDisp = FsGetHandle(fsctx, tid, uid, &fshdl);
SET_REQ(PREQ_SET_INFORMATION2, pReq, msg);
SET_RESP(PRESP_SET_INFORMATION2, pResp, msg);
if (!pDisp) {
SrvLogError(("DOSERROR: could not find dispatch table for uid %d\n", uid));
SET_DOSERROR(msg, SERVER, BAD_UID);
return TRUE;
}
if (pReq->WordCount != 7) {
SrvLogError(("DOSERROR: WordCount != 7\n"));
SET_DOSERROR(msg, SERVER, ERROR); // ok?
return TRUE;
}
attribs.file_size = INVALID_UINT64;
attribs.alloc_size = INVALID_UINT64;
attribs.access_time = INVALID_TIME64;
attribs.create_time = INVALID_TIME64;
attribs.mod_time = INVALID_TIME64;
attribs.attributes = INVALID_UINT32;
if (pReq->CreationDate.Ushort || pReq->CreationTime.Ushort) {
smb_datetime_to_time64(pReq->CreationDate.Ushort,
pReq->CreationTime.Ushort,
&attribs.create_time);
}
if (pReq->LastAccessDate.Ushort || pReq->LastAccessTime.Ushort) {
smb_datetime_to_time64(pReq->LastAccessDate.Ushort,
pReq->LastAccessTime.Ushort,
&attribs.access_time);
}
if (pReq->LastWriteDate.Ushort || pReq->LastWriteTime.Ushort) {
smb_datetime_to_time64(pReq->LastWriteDate.Ushort,
pReq->LastWriteTime.Ushort,
&attribs.mod_time);
}
error = pDisp->FsSetAttr(fshdl, pReq->Fid, &attribs);
if (error) {
SrvLog(("WIN32ERROR: set_attr error 0x%08X\n", error));
SET_WIN32ERROR(msg, error);
}
pResp->WordCount = 0;
pResp->ByteCount = 0;
UPDATE_OUT_LEN(msg, RESP_SET_INFORMATION2, pResp);
return TRUE;
}
void
WINAPI
SrvLockContinue(PVOID p, UINT32 status, UINT32 length)
{
Packet_t *msg = (Packet_t *) p;
SET_TYPE(PREQ_LOCKING_ANDX, pReq);
SET_TYPE(PRESP_LOCKING_ANDX, pResp);
DWORD consumed;
if (msg == NULL)
return;
SET_REQ(PREQ_LOCKING_ANDX, pReq, msg);
SET_RESP(PRESP_LOCKING_ANDX, pResp, msg);
consumed = (DWORD)(pResp->Buffer - (PUCHAR)msg->out.smb);
pResp->WordCount = 2;
pResp->ByteCount = 0;
UPDATE_FOR_NEXT_ANDX(msg,
REQ_LOCKING_ANDX, pReq,
RESP_LOCKING_ANDX, pResp);
if (status == ERROR_SUCCESS) {
if (msg->in.command != 0xFF)
SrvDispatch(msg);
} else {
SrvLog(("WIN32ERROR: read error 0x%08X\n", status));
SET_WIN32ERROR(msg, status);
}
SrvFinalize(msg);
}
BOOL
SrvComLockingAndx(
Packet_t * msg
)
{
PVOID fshdl;
USHORT tid;
USHORT uid;
PVOID fsctx;
FsDispatchTable* pDisp;
int i;
ULONG flags;
int offset;
PLOCKING_ANDX_RANGE pUnlocks, pLocks;
BOOL bShared;
USHORT nulocks, nlocks;
DWORD error;
SET_TYPE(PREQ_LOCKING_ANDX, pReq);
SET_TYPE(PRESP_LOCKING_ANDX, pResp);
if (msg == NULL)
return FALSE;
tid = msg->in.smb->Tid;
uid = msg->in.smb->Uid;
fsctx = SRV_GET_FS_HANDLE(msg);
pDisp = FsGetHandle(fsctx, tid, uid, &fshdl);
SET_REQ(PREQ_LOCKING_ANDX, pReq, msg);
SET_RESP(PRESP_LOCKING_ANDX, pResp, msg);
if (pReq->WordCount != 8) {
SrvLogError(("DOSERROR: WordCount != 8\n"));
SET_DOSERROR(msg, SERVER, ERROR); // ok?
return TRUE;
}
if (!pDisp) {
SrvLogError(("DOSERROR: could not find dispatch table for uid %d\n", uid));
SET_DOSERROR(msg, SERVER, BAD_UID);
return TRUE;
}
bShared = pReq->LockType; // & LOCKING_ANDX_SHARED_LOCK;
nulocks= pReq->NumberOfUnlocks;
nlocks = pReq->NumberOfLocks;
pLocks = NULL;
pUnlocks = NULL;
offset = 0;
if (pReq->ByteCount > offset) {
pUnlocks = (PLOCKING_ANDX_RANGE)
NEXT_LOCATION(pReq, REQ_LOCKING_ANDX, offset);
offset += (pReq->NumberOfUnlocks * sizeof(LOCKING_ANDX_RANGE));
}
if (pReq->ByteCount > offset) {
pLocks = (PLOCKING_ANDX_RANGE)
NEXT_LOCATION(pReq, REQ_LOCKING_ANDX, offset);
}
flags = 0;
if (pReq->Timeout != 0) {
flags |= 0x1; // wait
}
if (pReq->LockType & LOCKING_ANDX_SHARED_LOCK) {
flags |= 0x2; // shared
}
SET_WIN32ERROR(msg, ERROR_INVALID_PARAMETER);
if (pLocks != NULL) {
for (i = 0; i < nlocks; i++) {
SrvLog(("Lock: %d pid %d offset %d len %d flags %x (%x,%d)\n", i,
pLocks[i].Pid, pLocks[i].Offset, pLocks[i].Length, flags,
pReq->LockType, pReq->Timeout));
msg->tag = ERROR_IO_PENDING;
msg->completion = SrvLockContinue;
error = pDisp->FsLock(fshdl, pReq->Fid,
pLocks[i].Offset, pLocks[i].Length,
flags,
(PVOID) msg);
if (error == ERROR_IO_PENDING) {
return ERROR_IO_PENDING;
}
SET_WIN32ERROR(msg, error);
}
}
if (pUnlocks != NULL) {
for (i = 0; i < nulocks; i++) {
SrvLog(("Unlock: %d pid %d offset %d len %d\n", i,
pUnlocks[i].Pid, pUnlocks[i].Offset, pUnlocks[i].Length));
error = pDisp->FsUnlock(fshdl, pReq->Fid,
pUnlocks[i].Offset, pUnlocks[i].Length);
SET_WIN32ERROR(msg, error);
}
}
pResp->WordCount = 2;
pResp->ByteCount = 0;
UPDATE_FOR_NEXT_ANDX(msg,
REQ_LOCKING_ANDX, pReq,
RESP_LOCKING_ANDX, pResp);
return SrvDispatch(msg);
}
BOOL
SrvComSeek(
Packet_t * msg
)
{
PVOID fshdl;
USHORT tid;
USHORT uid;
PVOID fsctx;
FsDispatchTable* pDisp;
ULONG offset;
fattr_t attribs;
DWORD error;
BOOL bStart;
USHORT mode;
SET_TYPE(PREQ_SEEK, pReq);
SET_TYPE(PRESP_SEEK, pResp);
if (msg == NULL)
return FALSE;
tid = msg->in.smb->Tid;
uid = msg->in.smb->Uid;
fsctx = SRV_GET_FS_HANDLE(msg);
pDisp = FsGetHandle(fsctx, tid, uid, &fshdl);
SET_REQ(PREQ_SEEK, pReq, msg);
SET_RESP(PRESP_SEEK, pResp, msg);
pResp->WordCount = 2;
pResp->ByteCount = 0;
if (!pDisp) {
SrvLogError(("DOSERROR: could not find dispatch table for uid %d\n", uid));
SET_DOSERROR(msg, SERVER, BAD_UID);
return TRUE;
}
if (pReq->WordCount != 4) {
SrvLogError(("DOSERROR: WordCount != 4\n"));
SET_DOSERROR(msg, SERVER, ERROR); // ok?
return TRUE;
}
mode = pReq->Mode;
if (mode && (mode != 2)) {
SrvLog(("DOSERROR: only support modes 0 & 2 (not %d)\n", mode));
SET_DOSERROR(msg, SERVER, ERROR);
return TRUE;
}
bStart = !mode;
offset = pReq->Offset;
error = pDisp->FsGetAttr(fshdl, pReq->Fid, &attribs);
if (error) {
SrvLog(("WIN32ERROR: get_attr error 0x%08X\n", error));
SET_WIN32ERROR(msg, error);
return TRUE;
}
pResp->Offset = 0;
UPDATE_OUT_LEN(msg, RESP_SEEK, pResp);
return TRUE;
}
BOOL
SrvComFlush(
Packet_t * msg
)
{
PVOID fshdl;
USHORT tid;
USHORT uid;
PVOID fsctx;
FsDispatchTable* pDisp;
DWORD error;
SET_TYPE(PREQ_FLUSH, pReq);
SET_TYPE(PRESP_FLUSH, pResp);
if (msg == NULL)
return FALSE;
tid = msg->in.smb->Tid;
uid = msg->in.smb->Uid;
fsctx = SRV_GET_FS_HANDLE(msg);
pDisp = FsGetHandle(fsctx, tid, uid, &fshdl);
SET_REQ(PREQ_FLUSH, pReq, msg);
SET_RESP(PRESP_FLUSH, pResp, msg);
if (pReq->WordCount != 1) {
SrvLogError(("DOSERROR: WordCount != 1\n"));
SET_DOSERROR(msg, SERVER, ERROR); // ok?
return TRUE;
}
if (pReq->ByteCount != 0) {
SrvLogError(("DOSERROR: ByteCount != 0\n"));
SET_DOSERROR(msg, SERVER, ERROR); // ok?
return TRUE;
}
if (!pDisp) {
SrvLogError(("DOSERROR: could not find dispatch table for uid %d\n", uid));
SET_DOSERROR(msg, SERVER, BAD_UID);
return TRUE;
}
error = pDisp->FsFlush(fshdl, pReq->Fid);
if (error) {
SrvLog(("WIN32ERROR: flush error 0x%08X\n", error));
SET_WIN32ERROR(msg, error);
}
pResp->WordCount = 0;
pResp->ByteCount = 0;
UPDATE_OUT_LEN(msg, RESP_FLUSH, pResp);
return TRUE;
}
BOOL
SrvComLogoffAndx(
Packet_t * msg
)
{
USHORT tid;
USHORT uid;
PVOID fsctx;
SET_TYPE(PREQ_LOGOFF_ANDX, pReq);
SET_TYPE(PRESP_LOGOFF_ANDX, pResp);
if (msg == NULL)
return FALSE;
tid = msg->in.smb->Tid;
uid = msg->in.smb->Uid;
fsctx = SRV_GET_FS_HANDLE(msg);
SET_REQ(PREQ_LOGOFF_ANDX, pReq, msg);
SET_RESP(PRESP_LOGOFF_ANDX, pResp, msg);
memcpy(pResp, pReq, sizeof(PRESP_LOGOFF_ANDX));
FsDisMount(fsctx, uid, tid);
UPDATE_OUT_LEN(msg, RESP_LOGOFF_ANDX, pResp);
return TRUE;
}
BOOL
SrvComTreeDisconnect(
Packet_t * msg
)
{
USHORT uid;
USHORT tid;
PVOID fsctx;
SET_TYPE(PREQ_TREE_DISCONNECT, pReq);
SET_TYPE(PRESP_TREE_DISCONNECT, pResp);
if (msg == NULL)
return FALSE;
uid = msg->in.smb->Uid;
tid = msg->in.smb->Tid;
fsctx = SRV_GET_FS_HANDLE(msg);
SET_REQ(PREQ_TREE_DISCONNECT, pReq, msg);
SET_RESP(PRESP_TREE_DISCONNECT, pResp, msg);
pResp->WordCount = 0;
pResp->ByteCount = 0;
FsDisMount(fsctx, uid, tid);
UPDATE_OUT_LEN(msg, RESP_TREE_DISCONNECT, pResp);
return TRUE;
}
BOOL
SrvComSearch(
Packet_t * msg
)
{
PVOID fshdl;
USHORT tid;
USHORT uid;
SET_TYPE(PREQ_SEARCH, pReq);
SET_TYPE(PRESP_SEARCH, pResp);
if (msg == NULL)
return FALSE;
tid = msg->in.smb->Tid;
uid = msg->in.smb->Uid;
SET_REQ(PREQ_SEARCH, pReq, msg);
SET_RESP(PRESP_SEARCH, pResp, msg);
// this call is not supported in our dialect, so no worries.
UPDATE_OUT_LEN(msg, RESP_SEARCH, pResp);
return TRUE;
}
BOOL
SrvComIoctl(
Packet_t * msg
)
{
SET_TYPE(PREQ_IOCTL, pReq);
SET_TYPE(PRESP_IOCTL, pResp);
if (msg == NULL)
return FALSE;
SET_REQ(PREQ_IOCTL, pReq, msg);
SET_RESP(PRESP_IOCTL, pResp, msg);
if (pReq->WordCount != 14) {
SrvLogError(("DOSERROR: WordCount != 1\n"));
SET_DOSERROR(msg, SERVER, ERROR); // ok?
return TRUE;
}
SrvLog(("Ioctl: fid %d category %d function %d tpc %d tdc %d mpc %d mdc %d pc %d po %d dc %d do %d bc %d\n",
pReq->Fid,
pReq->Category,
pReq->Function,
pReq->TotalParameterCount,
pReq->TotalDataCount,
pReq->MaxParameterCount,
pReq->MaxDataCount,
pReq->ParameterCount,
pReq->DataCount,
pReq->DataOffset,
pReq->ByteCount));
memset((char *)pResp, 0, sizeof(*pResp));
pResp->WordCount = 8;
UPDATE_OUT_LEN(msg, RESP_IOCTL, pResp);
return TRUE;
}
BOOL
SrvComEcho(
Packet_t * msg
)
{
SET_TYPE(PREQ_ECHO, pReq);
SET_TYPE(PRESP_ECHO, pResp);
if (msg == NULL)
return FALSE;
SET_REQ(PREQ_ECHO, pReq, msg);
SET_RESP(PRESP_ECHO, pResp, msg);
if (pReq->WordCount != 1) {
SrvLogError(("DOSERROR: WordCount != 1\n"));
SET_DOSERROR(msg, SERVER, ERROR); // ok?
return TRUE;
}
SrvLog(("Echo: count %d bytecount %d\n", pReq->EchoCount, pReq->ByteCount));
pResp->WordCount = 1;
pResp->SequenceNumber = 1;
pResp->ByteCount = pReq->ByteCount;
memcpy(pResp->Buffer, pReq->Buffer, pReq->ByteCount);
UPDATE_OUT_LEN(msg, RESP_ECHO, pResp);
return TRUE;
}