2244 lines
54 KiB
C
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;
|
|
}
|
|
|
|
|
|
|
|
|
|
|