Files
smbfst/rpc/srvsvc.c
2024-07-14 13:48:45 -05:00

153 lines
4.9 KiB
C

/*
* Copyright (c) 2024 Stephen Heumann
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#define USE_BLANK_SEG
#include "defs.h"
#include <uchar.h>
#include <stdio.h>
#include <memory.h>
#include "rpc/rpc.h"
#include "rpc/ndr.h"
#include "rpc/srvsvc.h"
#include "rpc/srvsvcproto.h"
#include "utils/guidutils.h"
// UUID and version for SRVSVC (see [MS-SRVS])
p_syntax_id_t srvsvcSyntax =
{.if_uuid = GUID(4b324fc8,1670,01d3,1278,5a47bf6ee188), 3};
/*
* This returns NULL on failure. Otherwise, it returns a locked handle to a
* ShareInfoRec containing information about the shares on the server.
* (The strings referenced in the ShareInfoRec are held later within the same
* handle.) It is the caller's responsibility to dispose of the handle.
*/
Handle EnumerateShares(Word devNum) {
Handle responseData;
RPCConnection rpcConn;
uint32_t assocGroupID;
SHARE_ENUM_STRUCT *infoPtr;
SHARE_INFO_1_CONTAINER *si1ContainerPtr;
uint32_t entryCount;
NDR_CONFORMANT_ARRAY(SHARE_INFO_1) *si1ArrayPtr;
SHARE_INFO_1 *si1Array;
NDR_CONFORMANT_VARYING_STRING(char16_t) *str;
uint32_t i;
static char path[15];
snprintf(path, sizeof(path), ".d%u:srvsvc", devNum);
if (!ConnectRPC(&rpcConn, path))
return NULL;
assocGroupID = RPCBind(&rpcConn, &srvsvcSyntax);
if (assocGroupID == 0) {
DisconnectRPC(&rpcConn);
return NULL;
}
static unsigned char msgBuf[32];
NDRBufInfo ndr;
static const SHARE_ENUM_STRUCT infoStruct = {
.Level = LEVEL_1,
.ShareInfo.tag = LEVEL_1,
.ShareInfo.data.Level1 = NDR_ARBITRARY
};
static const SHARE_INFO_1_CONTAINER si1Container = {
.EntriesRead = 0,
.Buffer = NDR_NULL
};
InitNDRBuf(&ndr, msgBuf, sizeof(msgBuf));
NDRWritePtr(&ndr, NDR_NULL); // ServerName
NDRWrite(&ndr, &infoStruct, sizeof(infoStruct)); // InfoStruct
NDRWrite(&ndr, &si1Container, sizeof(si1Container));
/*
* macOS won't accept any other value for PreferedMaximumLength
*/
NDRWriteI32(&ndr, 0xFFFFFFFF); // PreferedMaximumLength
NDRWritePtr(&ndr, NDR_NULL); // ResumeHandle
responseData =
RPCRequest(&rpcConn, NetrShareEnum_opnum, msgBuf, NDRDataSize(&ndr));
DisconnectRPC(&rpcConn);
if (responseData == NULL)
return NULL;
InitNDRBuf(&ndr, *responseData, GetHandleSize(responseData));
infoPtr = NDRRead(&ndr, sizeof(SHARE_ENUM_STRUCT));
if (!infoPtr)
goto error;
if (infoPtr->Level != LEVEL_1)
goto error;
if (infoPtr->ShareInfo.tag != LEVEL_1)
goto error;
si1ContainerPtr = NDRRead(&ndr, sizeof(SHARE_INFO_1_CONTAINER));
if (!si1ContainerPtr)
goto error;
entryCount = si1ContainerPtr->EntriesRead;
si1ArrayPtr = NDRRead(&ndr, sizeof(NDR_CONFORMANT_ARRAY(SHARE_INFO_1)));
if (!si1ArrayPtr)
goto error;
if (si1ArrayPtr->maxCount != entryCount)
goto error;
if (entryCount > UINT32_MAX / sizeof(SHARE_INFO_1))
goto error;
si1Array = NDRRead(&ndr, entryCount * sizeof(SHARE_INFO_1));
for (i = 0; i < entryCount; i++) {
if (!NDRAlign(&ndr, 4))
goto error;
str = NDRRead(&ndr, sizeof(NDR_CONFORMANT_VARYING_STRING(char16_t)));
if (str->maxCount != str->actualCount || str->maxCount == 0)
goto error;
if (str->offset != 0)
goto error;
if (str->actualCount > UINT32_MAX/sizeof(char16_t))
goto error;
NDRRead(&ndr, str->actualCount * sizeof(char16_t));
si1Array[i].shi1_netname = (uint32_t)&str->actualCount;
if (!NDRAlign(&ndr, 4))
goto error;
str = NDRRead(&ndr, sizeof(NDR_CONFORMANT_VARYING_STRING(char16_t)));
if (str->maxCount != str->actualCount || str->maxCount == 0)
goto error;
if (str->offset != 0)
goto error;
if (str->actualCount > UINT32_MAX/sizeof(char16_t))
goto error;
NDRRead(&ndr, str->actualCount * sizeof(char16_t));
si1Array[i].shi1_remark = (uint32_t)&str->actualCount;
}
return responseData;
error:
DisposeHandle(responseData);
return NULL;
}