mirror of
https://github.com/rapid7/metasploit-payloads
synced 2025-04-18 07:11:12 +02:00
Merge branch 'master' into winhttp
This commit is contained in:
commit
b7d6eba46b
c/meterpreter
source
extensions
networkpug
sniffer
stdapi
server
workspace/ext_server_stdapi
@ -438,7 +438,11 @@ Command customCommands[] =
|
|||||||
/*
|
/*
|
||||||
* Initialize the server extension
|
* Initialize the server extension
|
||||||
*/
|
*/
|
||||||
|
#ifdef _WIN32
|
||||||
DWORD __declspec(dllexport) InitServerExtension(Remote *remote)
|
DWORD __declspec(dllexport) InitServerExtension(Remote *remote)
|
||||||
|
#else
|
||||||
|
DWORD InitServerExtension(Remote *remote)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
int peername_len;
|
int peername_len;
|
||||||
struct sockaddr peername;
|
struct sockaddr peername;
|
||||||
@ -497,7 +501,11 @@ DWORD __declspec(dllexport) InitServerExtension(Remote *remote)
|
|||||||
/*
|
/*
|
||||||
* Deinitialize the server extension
|
* Deinitialize the server extension
|
||||||
*/
|
*/
|
||||||
|
#ifdef _WIN32
|
||||||
DWORD __declspec(dllexport) DeinitServerExtension(Remote *remote)
|
DWORD __declspec(dllexport) DeinitServerExtension(Remote *remote)
|
||||||
|
#else
|
||||||
|
DWORD DeinitServerExtension(Remote *remote)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
command_deregister_all(customCommands);
|
command_deregister_all(customCommands);
|
||||||
|
|
||||||
@ -507,3 +515,23 @@ DWORD __declspec(dllexport) DeinitServerExtension(Remote *remote)
|
|||||||
|
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief Get the name of the extension.
|
||||||
|
* @param buffer Pointer to the buffer to write the name to.
|
||||||
|
* @param bufferSize Size of the \c buffer parameter.
|
||||||
|
* @return Indication of success or failure.
|
||||||
|
*/
|
||||||
|
#ifdef _WIN32
|
||||||
|
DWORD __declspec(dllexport) GetExtensionName(char* buffer, int bufferSize)
|
||||||
|
#else
|
||||||
|
DWORD GetExtensionName(char* buffer, int bufferSize)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
strncpy_s(buffer, bufferSize, "networkpug", bufferSize - 1);
|
||||||
|
#else
|
||||||
|
strncpy(buffer, "networkpug", bufferSize - 1);
|
||||||
|
#endif
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
@ -1197,7 +1197,11 @@ DWORD request_sniffer_capture_dump(Remote *remote, Packet *packet)
|
|||||||
* @param remote Pointer to the remote instance.
|
* @param remote Pointer to the remote instance.
|
||||||
* @return Indication of success or failure.
|
* @return Indication of success or failure.
|
||||||
*/
|
*/
|
||||||
|
#ifdef _WIN32
|
||||||
DWORD __declspec(dllexport) InitServerExtension(Remote *remote)
|
DWORD __declspec(dllexport) InitServerExtension(Remote *remote)
|
||||||
|
#else
|
||||||
|
DWORD InitServerExtension(Remote *remote)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
// This handle has to be set before calls to command_register
|
// This handle has to be set before calls to command_register
|
||||||
@ -1271,7 +1275,11 @@ DWORD __declspec(dllexport) InitServerExtension(Remote *remote)
|
|||||||
* @param remote Pointer to the remote instance.
|
* @param remote Pointer to the remote instance.
|
||||||
* @return Indication of success or failure.
|
* @return Indication of success or failure.
|
||||||
*/
|
*/
|
||||||
|
#ifdef _WIN32
|
||||||
DWORD __declspec(dllexport) DeinitServerExtension(Remote *remote)
|
DWORD __declspec(dllexport) DeinitServerExtension(Remote *remote)
|
||||||
|
#else
|
||||||
|
DWORD DeinitServerExtension(Remote *remote)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
command_register_all( customCommands );
|
command_register_all( customCommands );
|
||||||
|
|
||||||
@ -1294,8 +1302,16 @@ DWORD __declspec(dllexport) DeinitServerExtension(Remote *remote)
|
|||||||
* @param bufferSize Size of the \c buffer parameter.
|
* @param bufferSize Size of the \c buffer parameter.
|
||||||
* @return Indication of success or failure.
|
* @return Indication of success or failure.
|
||||||
*/
|
*/
|
||||||
|
#ifdef _WIN32
|
||||||
DWORD __declspec(dllexport) GetExtensionName(char* buffer, int bufferSize)
|
DWORD __declspec(dllexport) GetExtensionName(char* buffer, int bufferSize)
|
||||||
|
#else
|
||||||
|
DWORD GetExtensionName(char* buffer, int bufferSize)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
strncpy_s(buffer, bufferSize, "sniffer", bufferSize - 1);
|
strncpy_s(buffer, bufferSize, "sniffer", bufferSize - 1);
|
||||||
|
#else
|
||||||
|
strncpy(buffer, "sniffer", bufferSize - 1);
|
||||||
|
#endif
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
@ -1,370 +1,132 @@
|
|||||||
#include "precomp.h"
|
#include "precomp.h"
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
#ifndef _WIN32
|
#include "fs_local.h"
|
||||||
#include <dirent.h>
|
|
||||||
#endif
|
void request_fs_ls_cb(void *arg, char *name, char *short_name, char *path)
|
||||||
|
{
|
||||||
|
Packet *response = arg;
|
||||||
|
struct meterp_stat s;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the file name, full path and stat information
|
||||||
|
*/
|
||||||
|
packet_add_tlv_string(response, TLV_TYPE_FILE_NAME, name);
|
||||||
|
packet_add_tlv_string(response, TLV_TYPE_FILE_PATH, path);
|
||||||
|
if (short_name) {
|
||||||
|
packet_add_tlv_string(response, TLV_TYPE_FILE_SHORT_NAME, short_name);
|
||||||
|
}
|
||||||
|
if (fs_stat(path, &s) >= 0) {
|
||||||
|
packet_add_tlv_raw(response, TLV_TYPE_STAT_BUF, &s, sizeof(s));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Gets the contents of a given directory path and returns the list of file
|
* Gets the contents of a given directory path and returns the list of file
|
||||||
* names to the requestor.
|
* names to the requestor.
|
||||||
*
|
*
|
||||||
* TLVs:
|
|
||||||
*
|
|
||||||
* req: TLV_TYPE_DIRECTORY_PATH - The directory that should be listed
|
* req: TLV_TYPE_DIRECTORY_PATH - The directory that should be listed
|
||||||
*/
|
*/
|
||||||
DWORD request_fs_ls(Remote *remote, Packet *packet)
|
DWORD request_fs_ls(Remote * remote, Packet * packet)
|
||||||
{
|
{
|
||||||
Packet *response = packet_create_response(packet);
|
Packet *response = packet_create_response(packet);
|
||||||
LPCSTR directory;
|
LPCSTR directory = packet_get_tlv_value_string(packet, TLV_TYPE_DIRECTORY_PATH);
|
||||||
DWORD result = ERROR_SUCCESS;
|
DWORD result;
|
||||||
LPSTR expanded = NULL, tempFile = NULL;
|
|
||||||
size_t tempFileSize = 0;
|
|
||||||
LPSTR baseDirectory = NULL;
|
|
||||||
struct meterp_stat buf;
|
|
||||||
|
|
||||||
directory = packet_get_tlv_value_string(packet, TLV_TYPE_DIRECTORY_PATH);
|
if (!directory) {
|
||||||
|
|
||||||
// Enumerate the directory if one was provided
|
|
||||||
if (!directory)
|
|
||||||
result = ERROR_INVALID_PARAMETER;
|
result = ERROR_INVALID_PARAMETER;
|
||||||
else
|
} else {
|
||||||
{
|
result = fs_ls(directory, request_fs_ls_cb, response);
|
||||||
#ifdef _WIN32
|
|
||||||
WIN32_FIND_DATA data;
|
|
||||||
HANDLE ctx = NULL;
|
|
||||||
#else
|
|
||||||
DIR *ctx;
|
|
||||||
struct dirent *data;
|
|
||||||
#endif
|
|
||||||
BOOLEAN freeDirectory = FALSE;
|
|
||||||
LPSTR tempDirectory = (LPSTR)directory;
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
// If there is not wildcard mask on the directory, create a version of the
|
|
||||||
// directory with a mask appended
|
|
||||||
if (!strrchr(directory, '*'))
|
|
||||||
{
|
|
||||||
if (!(tempDirectory = (LPSTR)malloc(strlen(directory) + 3)))
|
|
||||||
{
|
|
||||||
result = ERROR_NOT_ENOUGH_MEMORY;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
sprintf(tempDirectory, "%s\\*", directory);
|
|
||||||
|
|
||||||
// Dupe!
|
|
||||||
if (!(baseDirectory = _strdup(directory)))
|
|
||||||
{
|
|
||||||
result = ERROR_NOT_ENOUGH_MEMORY;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Otherwise, if it does have an asterisk, we need to scan back and find
|
|
||||||
// the base directory. If there is no slash, it means we're listing the
|
|
||||||
// cwd.
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PCHAR slash = strrchr(directory, '\\');
|
|
||||||
|
|
||||||
if (slash)
|
|
||||||
{
|
|
||||||
*slash = 0;
|
|
||||||
|
|
||||||
if (!(baseDirectory = _strdup(directory)))
|
|
||||||
{
|
|
||||||
result = ERROR_NOT_ENOUGH_MEMORY;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
*slash = '\\';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Expand the path
|
|
||||||
if (!(expanded = fs_expand_path(tempDirectory)))
|
|
||||||
{
|
|
||||||
result = ERROR_NOT_ENOUGH_MEMORY;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start the find operation
|
|
||||||
ctx = FindFirstFile(expanded, &data);
|
|
||||||
|
|
||||||
#define DF_NAME data.cFileName
|
|
||||||
#else
|
|
||||||
expanded = 0;
|
|
||||||
ctx = opendir(tempDirectory);
|
|
||||||
if(ctx == NULL)
|
|
||||||
{
|
|
||||||
result = errno;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
data = readdir(ctx);
|
|
||||||
if (!(baseDirectory = _strdup(directory)))
|
|
||||||
{
|
|
||||||
result = ERROR_NOT_ENOUGH_MEMORY;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define DF_NAME data->d_name
|
|
||||||
#endif
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
size_t fullSize = (baseDirectory ? strlen(baseDirectory) : 0) + strlen(DF_NAME) + 2;
|
|
||||||
|
|
||||||
// No context? Sucktastic
|
|
||||||
if (ctx == INVALID_HANDLE_VALUE)
|
|
||||||
{
|
|
||||||
result = GetLastError();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allocate temporary storage to stat the file
|
|
||||||
if ((!tempFile) || (tempFileSize < fullSize))
|
|
||||||
{
|
|
||||||
if (tempFile)
|
|
||||||
{
|
|
||||||
free(tempFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
// No memory means we suck a lot like spoon's mom
|
|
||||||
if (!(tempFile = (LPSTR)malloc(fullSize)))
|
|
||||||
{
|
|
||||||
result = ERROR_NOT_ENOUGH_MEMORY;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the tempFileSize so that we don't allocate if we don't
|
|
||||||
// need to like a true efficient ninja
|
|
||||||
tempFileSize = fullSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build the full path
|
|
||||||
if (baseDirectory)
|
|
||||||
{
|
|
||||||
#ifdef _WIN32
|
|
||||||
sprintf(tempFile, "%s\\%s", baseDirectory, DF_NAME);
|
|
||||||
#else
|
|
||||||
sprintf(tempFile, "%s/%s", baseDirectory, DF_NAME);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sprintf(tempFile, "%s", DF_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the file name to the response
|
|
||||||
packet_add_tlv_string(response, TLV_TYPE_FILE_NAME, DF_NAME);
|
|
||||||
// Add the full path
|
|
||||||
packet_add_tlv_string(response, TLV_TYPE_FILE_PATH, tempFile);
|
|
||||||
|
|
||||||
// Stat the file to get more information about it.
|
|
||||||
if (fs_stat(tempFile, &buf) >= 0)
|
|
||||||
{
|
|
||||||
packet_add_tlv_raw(response, TLV_TYPE_STAT_BUF, &buf, sizeof(buf));
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
} while (FindNextFile(ctx, &data));
|
|
||||||
#else
|
|
||||||
} while (data = readdir(ctx));
|
|
||||||
#endif
|
|
||||||
#undef DF_NAME
|
|
||||||
|
|
||||||
// Clean up resources
|
|
||||||
if (freeDirectory)
|
|
||||||
{
|
|
||||||
free(tempDirectory);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ctx)
|
|
||||||
{
|
|
||||||
#ifdef _WIN32
|
|
||||||
FindClose(ctx);
|
|
||||||
#else
|
|
||||||
closedir(ctx);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (expanded)
|
|
||||||
{
|
|
||||||
free(expanded);
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
if (baseDirectory)
|
|
||||||
{
|
|
||||||
free(baseDirectory);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the result and transmit the response
|
|
||||||
packet_add_tlv_uint(response, TLV_TYPE_RESULT, result);
|
packet_add_tlv_uint(response, TLV_TYPE_RESULT, result);
|
||||||
|
return packet_transmit(remote, response, NULL);
|
||||||
packet_transmit(remote, response, NULL);
|
|
||||||
|
|
||||||
return ERROR_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Gets the current working directory
|
* Gets the current working directory
|
||||||
|
*
|
||||||
|
* req: TLV_TYPE_DIRECTORY_PATH - The directory path to change the working
|
||||||
|
* directory to.
|
||||||
*/
|
*/
|
||||||
DWORD request_fs_getwd(Remote *remote, Packet *packet)
|
DWORD request_fs_getwd(Remote * remote, Packet * packet)
|
||||||
{
|
{
|
||||||
Packet *response = packet_create_response(packet);
|
Packet *response = packet_create_response(packet);
|
||||||
DWORD directorySize = 4096, realSize;
|
char *directory = NULL;
|
||||||
LPSTR directory = NULL;
|
DWORD result;
|
||||||
DWORD result = ERROR_SUCCESS;
|
|
||||||
|
|
||||||
do
|
result = fs_getwd(&directory);
|
||||||
{
|
if (directory != NULL) {
|
||||||
again:
|
packet_add_tlv_string(response, TLV_TYPE_DIRECTORY_PATH, directory);
|
||||||
// Allocate storage for the directory path
|
|
||||||
if (!(directory = (LPSTR)malloc(directorySize)))
|
|
||||||
{
|
|
||||||
result = ERROR_NOT_ENOUGH_MEMORY;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(directory, 0, directorySize);
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
if (!(realSize = GetCurrentDirectory(directorySize, directory)))
|
|
||||||
{
|
|
||||||
result = ERROR_NOT_ENOUGH_MEMORY;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (realSize > directorySize)
|
|
||||||
{
|
|
||||||
free(directory);
|
|
||||||
directorySize = realSize;
|
|
||||||
goto again;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (!getcwd(directory, directorySize))
|
|
||||||
{
|
|
||||||
if (errno == ERANGE && directorySize > 0)
|
|
||||||
{
|
|
||||||
// Then we didn't allocate enough to hold the whole path,
|
|
||||||
// increase the size and try again.
|
|
||||||
free(directory);
|
|
||||||
directorySize = directorySize * 2;
|
|
||||||
goto again;
|
|
||||||
} else {
|
|
||||||
dprintf("getcwd failed with errno %d", errno);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
packet_add_tlv_string(response, TLV_TYPE_DIRECTORY_PATH,
|
|
||||||
directory);
|
|
||||||
|
|
||||||
} while (0);
|
|
||||||
|
|
||||||
// Set the result and transmit the response
|
|
||||||
packet_add_tlv_uint(response, TLV_TYPE_RESULT, result);
|
|
||||||
|
|
||||||
packet_transmit(remote, response, NULL);
|
|
||||||
|
|
||||||
if (directory)
|
|
||||||
free(directory);
|
free(directory);
|
||||||
|
}
|
||||||
|
|
||||||
return ERROR_SUCCESS;
|
packet_add_tlv_uint(response, TLV_TYPE_RESULT, result);
|
||||||
|
return packet_transmit(remote, response, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Changes the working directory of the process
|
* Changes the working directory of the process
|
||||||
*
|
*
|
||||||
* TLVs:
|
|
||||||
*
|
|
||||||
* req: TLV_TYPE_DIRECTORY_PATH - The directory path to change the working
|
* req: TLV_TYPE_DIRECTORY_PATH - The directory path to change the working
|
||||||
* directory to.
|
* directory to.
|
||||||
*/
|
*/
|
||||||
DWORD request_fs_chdir(Remote *remote, Packet *packet)
|
DWORD request_fs_chdir(Remote * remote, Packet * packet)
|
||||||
{
|
{
|
||||||
Packet *response = packet_create_response(packet);
|
Packet *response = packet_create_response(packet);
|
||||||
LPCSTR directory;
|
char *directory;
|
||||||
DWORD result = ERROR_SUCCESS;
|
DWORD result;
|
||||||
|
|
||||||
directory = packet_get_tlv_value_string(packet, TLV_TYPE_DIRECTORY_PATH);
|
directory = packet_get_tlv_value_string(packet, TLV_TYPE_DIRECTORY_PATH);
|
||||||
|
|
||||||
if (!directory)
|
if (directory == NULL) {
|
||||||
result = ERROR_INVALID_PARAMETER;
|
result = ERROR_INVALID_PARAMETER;
|
||||||
#ifdef _WIN32
|
} else {
|
||||||
else if (!SetCurrentDirectory(directory))
|
result = fs_chdir(directory);
|
||||||
#else
|
}
|
||||||
else if (chdir(directory))
|
|
||||||
#endif
|
|
||||||
result = GetLastError();
|
|
||||||
|
|
||||||
packet_add_tlv_uint(response, TLV_TYPE_RESULT, result);
|
packet_add_tlv_uint(response, TLV_TYPE_RESULT, result);
|
||||||
|
return packet_transmit(remote, response, NULL);
|
||||||
packet_transmit(remote, response, NULL);
|
|
||||||
|
|
||||||
return ERROR_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Creates a new directory
|
* Creates a new directory
|
||||||
*
|
*
|
||||||
* TLVs:
|
|
||||||
*
|
|
||||||
* req: TLV_TYPE_DIRECTORY_PATH - The directory path to create.
|
* req: TLV_TYPE_DIRECTORY_PATH - The directory path to create.
|
||||||
*/
|
*/
|
||||||
DWORD request_fs_mkdir(Remote *remote, Packet *packet)
|
DWORD request_fs_mkdir(Remote * remote, Packet * packet)
|
||||||
{
|
{
|
||||||
Packet *response = packet_create_response(packet);
|
Packet *response = packet_create_response(packet);
|
||||||
LPCSTR directory;
|
char *directory;
|
||||||
DWORD result = ERROR_SUCCESS;
|
DWORD result;
|
||||||
|
|
||||||
directory = packet_get_tlv_value_string(packet, TLV_TYPE_DIRECTORY_PATH);
|
directory = packet_get_tlv_value_string(packet, TLV_TYPE_DIRECTORY_PATH);
|
||||||
|
|
||||||
if (!directory)
|
if (directory == NULL) {
|
||||||
result = ERROR_INVALID_PARAMETER;
|
result = ERROR_INVALID_PARAMETER;
|
||||||
#ifdef _WIN32
|
} else {
|
||||||
else if (!CreateDirectory(directory, NULL))
|
result = fs_mkdir(directory);
|
||||||
#else
|
}
|
||||||
else if (mkdir(directory, 0777))
|
|
||||||
#endif
|
|
||||||
result = GetLastError();
|
|
||||||
|
|
||||||
packet_add_tlv_uint(response, TLV_TYPE_RESULT, result);
|
packet_add_tlv_uint(response, TLV_TYPE_RESULT, result);
|
||||||
|
return packet_transmit(remote, response, NULL);
|
||||||
packet_transmit(remote, response, NULL);
|
|
||||||
|
|
||||||
return ERROR_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Removes the supplied directory from disk if it's empty
|
* Removes the supplied directory from disk if it's empty
|
||||||
*
|
*
|
||||||
* TLVs:
|
|
||||||
*
|
|
||||||
* req: TLV_TYPE_DIRECTORY_PATH - The directory that is to be removed.
|
* req: TLV_TYPE_DIRECTORY_PATH - The directory that is to be removed.
|
||||||
*/
|
*/
|
||||||
DWORD request_fs_delete_dir(Remote *remote, Packet *packet)
|
DWORD request_fs_delete_dir(Remote * remote, Packet * packet)
|
||||||
{
|
{
|
||||||
Packet *response = packet_create_response(packet);
|
Packet *response = packet_create_response(packet);
|
||||||
LPCSTR directory;
|
char *directory;
|
||||||
DWORD result = ERROR_SUCCESS;
|
DWORD result;
|
||||||
|
|
||||||
directory = packet_get_tlv_value_string(packet, TLV_TYPE_DIRECTORY_PATH);
|
directory = packet_get_tlv_value_string(packet, TLV_TYPE_DIRECTORY_PATH);
|
||||||
|
|
||||||
if (!directory)
|
if (directory == NULL) {
|
||||||
result = ERROR_INVALID_PARAMETER;
|
result = ERROR_INVALID_PARAMETER;
|
||||||
#ifdef _WIN32
|
} else {
|
||||||
else if (!RemoveDirectory(directory))
|
result = fs_delete_dir(directory);
|
||||||
#else
|
}
|
||||||
else if (rmdir(directory))
|
|
||||||
#endif
|
|
||||||
result = GetLastError();
|
|
||||||
|
|
||||||
packet_add_tlv_uint(response, TLV_TYPE_RESULT, result);
|
packet_add_tlv_uint(response, TLV_TYPE_RESULT, result);
|
||||||
|
return packet_transmit(remote, response, NULL);
|
||||||
packet_transmit(remote, response, NULL);
|
|
||||||
|
|
||||||
return ERROR_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
#include "precomp.h"
|
#include "precomp.h"
|
||||||
|
#include "fs_local.h"
|
||||||
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include <openssl/md5.h>
|
#include <openssl/md5.h>
|
||||||
@ -23,19 +25,18 @@ static DWORD file_channel_write(Channel *channel, Packet *request,
|
|||||||
{
|
{
|
||||||
FileContext *ctx = (FileContext *)context;
|
FileContext *ctx = (FileContext *)context;
|
||||||
DWORD result= ERROR_SUCCESS;
|
DWORD result= ERROR_SUCCESS;
|
||||||
DWORD written = 0;
|
size_t written = 0;
|
||||||
|
|
||||||
// Write a chunk
|
// Write a chunk
|
||||||
if (bufferSize && (written = (DWORD)fwrite(buffer, 1, bufferSize, ctx->fd)) <= 0)
|
if (bufferSize) {
|
||||||
{
|
written = fwrite(buffer, 1, bufferSize, ctx->fd);
|
||||||
written = 0;
|
if (written < bufferSize) {
|
||||||
result = GetLastError();
|
result = GetLastError();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set bytesWritten
|
if (bytesWritten) {
|
||||||
if (bytesWritten)
|
*bytesWritten = (DWORD)written;
|
||||||
{
|
|
||||||
*bytesWritten = written;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -64,18 +65,19 @@ static DWORD file_channel_read(Channel *channel, Packet *request,
|
|||||||
{
|
{
|
||||||
FileContext *ctx = (FileContext *)context;
|
FileContext *ctx = (FileContext *)context;
|
||||||
DWORD result = ERROR_SUCCESS;
|
DWORD result = ERROR_SUCCESS;
|
||||||
DWORD bytes = 0;
|
size_t bytes = 0;
|
||||||
|
|
||||||
// Read a chunk
|
// Read a chunk
|
||||||
if (bufferSize && (bytes= (DWORD)fread(buffer, 1, bufferSize, ctx->fd)) <= 0)
|
if (bufferSize) {
|
||||||
{
|
bytes = fread(buffer, 1, bufferSize, ctx->fd);
|
||||||
bytes = 0;
|
if (bytes < bufferSize) {
|
||||||
result = GetLastError();
|
result = GetLastError();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set bytesRead
|
if (bytesRead) {
|
||||||
if (bytesRead)
|
*bytesRead = (DWORD)bytes;
|
||||||
*bytesRead = bytes;
|
}
|
||||||
|
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -112,8 +114,9 @@ static DWORD file_channel_tell(Channel *channel, Packet *request,
|
|||||||
DWORD result = ERROR_SUCCESS;
|
DWORD result = ERROR_SUCCESS;
|
||||||
LONG pos = 0;
|
LONG pos = 0;
|
||||||
|
|
||||||
if ((pos = ftell(ctx->fd)) < 0)
|
if ((pos = ftell(ctx->fd)) < 0) {
|
||||||
result = GetLastError();
|
result = GetLastError();
|
||||||
|
}
|
||||||
|
|
||||||
if (offset)
|
if (offset)
|
||||||
*offset = pos;
|
*offset = pos;
|
||||||
@ -136,90 +139,64 @@ DWORD request_fs_file_channel_open(Remote *remote, Packet *packet)
|
|||||||
FileContext *ctx;
|
FileContext *ctx;
|
||||||
LPSTR expandedFilePath = NULL;
|
LPSTR expandedFilePath = NULL;
|
||||||
|
|
||||||
do
|
// Allocate a response
|
||||||
{
|
response = packet_create_response(packet);
|
||||||
// Allocate a response
|
|
||||||
response = packet_create_response(packet);
|
|
||||||
|
|
||||||
// Get the channel flags
|
// Get the channel flags
|
||||||
flags = packet_get_tlv_value_uint(packet, TLV_TYPE_FLAGS);
|
flags = packet_get_tlv_value_uint(packet, TLV_TYPE_FLAGS);
|
||||||
|
|
||||||
// Allocate storage for the file context
|
// Allocate storage for the file context
|
||||||
if (!(ctx = (FileContext *)malloc(sizeof(FileContext))))
|
if (!(ctx = calloc(1, sizeof(FileContext)))) {
|
||||||
{
|
res = ERROR_NOT_ENOUGH_MEMORY;
|
||||||
res = ERROR_NOT_ENOUGH_MEMORY;
|
goto out;
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Get the file path and the mode
|
// Get the file path and the mode
|
||||||
filePath = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_PATH);
|
filePath = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_PATH);
|
||||||
mode = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_MODE);
|
mode = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_MODE);
|
||||||
|
|
||||||
// No file path? bogus.
|
if (mode == NULL) {
|
||||||
if (!filePath)
|
mode = "rb";
|
||||||
{
|
}
|
||||||
res = ERROR_INVALID_PARAMETER;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Expand the file path
|
res = fs_fopen(filePath, mode, &ctx->fd);
|
||||||
if (!(expandedFilePath = fs_expand_path(filePath)))
|
if (res != ERROR_SUCCESS) {
|
||||||
{
|
goto out;
|
||||||
res = ERROR_NOT_ENOUGH_MEMORY;
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mode)
|
memset(&chops, 0, sizeof(chops));
|
||||||
mode = "rb";
|
|
||||||
|
|
||||||
// Invalid file?
|
// Initialize the pool operation handlers
|
||||||
if (!(ctx->fd = fopen(expandedFilePath, mode)))
|
chops.native.context = ctx;
|
||||||
{
|
chops.native.write = file_channel_write;
|
||||||
res = GetLastError();
|
chops.native.close = file_channel_close;
|
||||||
break;
|
chops.read = file_channel_read;
|
||||||
}
|
chops.eof = file_channel_eof;
|
||||||
|
chops.seek = file_channel_seek;
|
||||||
|
chops.tell = file_channel_tell;
|
||||||
|
|
||||||
memset(&chops, 0, sizeof(chops));
|
// Check the response allocation & allocate a un-connected
|
||||||
|
// channel
|
||||||
|
if ((!response) || (!(newChannel = channel_create_pool(0, flags, &chops)))) {
|
||||||
|
res = ERROR_NOT_ENOUGH_MEMORY;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize the pool operation handlers
|
// Add the channel identifier to the response
|
||||||
chops.native.context = ctx;
|
packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, channel_get_id(newChannel));
|
||||||
chops.native.write = file_channel_write;
|
|
||||||
chops.native.close = file_channel_close;
|
|
||||||
chops.read = file_channel_read;
|
|
||||||
chops.eof = file_channel_eof;
|
|
||||||
chops.seek = file_channel_seek;
|
|
||||||
chops.tell = file_channel_tell;
|
|
||||||
|
|
||||||
// Check the response allocation & allocate a un-connected
|
|
||||||
// channel
|
|
||||||
if ((!response) || (!(newChannel = channel_create_pool(0, flags, &chops))))
|
|
||||||
{
|
|
||||||
res = ERROR_NOT_ENOUGH_MEMORY;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the channel identifier to the response
|
|
||||||
packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID,
|
|
||||||
channel_get_id(newChannel));
|
|
||||||
|
|
||||||
} while (0);
|
|
||||||
|
|
||||||
|
out:
|
||||||
// Transmit the packet if it's valid
|
// Transmit the packet if it's valid
|
||||||
packet_transmit_response(res, remote, response);
|
packet_transmit_response(res, remote, response);
|
||||||
|
|
||||||
// Clean up on failure
|
// Clean up on failure
|
||||||
if (res != ERROR_SUCCESS)
|
if (res != ERROR_SUCCESS) {
|
||||||
{
|
if (newChannel) {
|
||||||
if (newChannel)
|
|
||||||
channel_destroy(newChannel, NULL);
|
channel_destroy(newChannel, NULL);
|
||||||
if (ctx)
|
}
|
||||||
free(ctx);
|
free(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free the expanded file path if it was allocated
|
|
||||||
if (expandedFilePath)
|
|
||||||
free(expandedFilePath);
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,20 +206,12 @@ DWORD request_fs_file_channel_open(Remote *remote, Packet *packet)
|
|||||||
DWORD request_fs_separator(Remote *remote, Packet *packet)
|
DWORD request_fs_separator(Remote *remote, Packet *packet)
|
||||||
{
|
{
|
||||||
Packet *response = packet_create_response(packet);
|
Packet *response = packet_create_response(packet);
|
||||||
#ifdef _WIN32
|
|
||||||
LPCSTR separator = "\\";
|
|
||||||
#else
|
|
||||||
LPCSTR separator = "/";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
packet_add_tlv_string(response, TLV_TYPE_STRING, separator);
|
packet_add_tlv_string(response, TLV_TYPE_STRING, FS_SEPARATOR);
|
||||||
|
|
||||||
// Set the result and transmit the response
|
|
||||||
packet_add_tlv_uint(response, TLV_TYPE_RESULT, ERROR_SUCCESS);
|
packet_add_tlv_uint(response, TLV_TYPE_RESULT, ERROR_SUCCESS);
|
||||||
|
|
||||||
packet_transmit(remote, response, NULL);
|
return packet_transmit(remote, response, NULL);
|
||||||
|
|
||||||
return ERROR_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -250,73 +219,62 @@ DWORD request_fs_separator(Remote *remote, Packet *packet)
|
|||||||
* Gets information about the file path that is supplied and returns it to the
|
* Gets information about the file path that is supplied and returns it to the
|
||||||
* requestor
|
* requestor
|
||||||
*
|
*
|
||||||
* TLVs:
|
|
||||||
*
|
|
||||||
* req: TLV_TYPE_FILE_PATH - The file path that is to be stat'd
|
* req: TLV_TYPE_FILE_PATH - The file path that is to be stat'd
|
||||||
*/
|
*/
|
||||||
DWORD request_fs_stat(Remote *remote, Packet *packet)
|
DWORD request_fs_stat(Remote *remote, Packet *packet)
|
||||||
{
|
{
|
||||||
Packet *response = packet_create_response(packet);
|
Packet *response = packet_create_response(packet);
|
||||||
struct meterp_stat buf;
|
struct meterp_stat buf;
|
||||||
LPCSTR filePath;
|
char *filePath;
|
||||||
LPSTR expanded = NULL;
|
char *expanded = NULL;
|
||||||
DWORD result = ERROR_SUCCESS;
|
DWORD result = ERROR_SUCCESS;
|
||||||
|
|
||||||
filePath = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_PATH);
|
filePath = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_PATH);
|
||||||
|
|
||||||
// Validate parameters
|
if (!filePath) {
|
||||||
if (!filePath)
|
|
||||||
result = ERROR_INVALID_PARAMETER;
|
result = ERROR_INVALID_PARAMETER;
|
||||||
else if (!(expanded = fs_expand_path(filePath)))
|
goto out;
|
||||||
result = ERROR_NOT_ENOUGH_MEMORY;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result = fs_stat(expanded, &buf);
|
|
||||||
if (0 == result)
|
|
||||||
packet_add_tlv_raw(response, TLV_TYPE_STAT_BUF, &buf,
|
|
||||||
sizeof(buf));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the result and transmit the response
|
expanded = fs_expand_path(filePath);
|
||||||
|
if (expanded == NULL) {
|
||||||
|
result = ERROR_NOT_ENOUGH_MEMORY;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = fs_stat(expanded, &buf);
|
||||||
|
if (0 == result) {
|
||||||
|
packet_add_tlv_raw(response, TLV_TYPE_STAT_BUF, &buf, sizeof(buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
free(expanded);
|
||||||
|
|
||||||
|
out:
|
||||||
packet_add_tlv_uint(response, TLV_TYPE_RESULT, result);
|
packet_add_tlv_uint(response, TLV_TYPE_RESULT, result);
|
||||||
|
return packet_transmit(remote, response, NULL);
|
||||||
packet_transmit(remote, response, NULL);
|
|
||||||
|
|
||||||
if (expanded)
|
|
||||||
free(expanded);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Removes the supplied file from disk
|
* Removes the supplied file from disk
|
||||||
*
|
*
|
||||||
* TLVs:
|
|
||||||
*
|
|
||||||
* req: TLV_TYPE_FILE_PATH - The file that is to be removed.
|
* req: TLV_TYPE_FILE_PATH - The file that is to be removed.
|
||||||
*/
|
*/
|
||||||
DWORD request_fs_delete_file(Remote *remote, Packet *packet)
|
DWORD request_fs_delete_file(Remote *remote, Packet *packet)
|
||||||
{
|
{
|
||||||
Packet *response = packet_create_response(packet);
|
Packet *response = packet_create_response(packet);
|
||||||
LPCSTR path;
|
char *path;
|
||||||
DWORD result = ERROR_SUCCESS;
|
DWORD result = ERROR_SUCCESS;
|
||||||
|
|
||||||
path = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_PATH);
|
path = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_PATH);
|
||||||
|
|
||||||
if (!path)
|
if (!path) {
|
||||||
result = ERROR_INVALID_PARAMETER;
|
result = ERROR_INVALID_PARAMETER;
|
||||||
#ifdef _WIN32
|
} else {
|
||||||
else if (!DeleteFile(path))
|
result = fs_delete_file(path);
|
||||||
#else
|
}
|
||||||
else if (unlink(path))
|
|
||||||
#endif
|
|
||||||
result = GetLastError();
|
|
||||||
|
|
||||||
packet_add_tlv_uint(response, TLV_TYPE_RESULT, result);
|
packet_add_tlv_uint(response, TLV_TYPE_RESULT, result);
|
||||||
|
return packet_transmit(remote, response, NULL);
|
||||||
packet_transmit(remote, response, NULL);
|
|
||||||
|
|
||||||
return ERROR_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -328,164 +286,107 @@ DWORD request_fs_file_expand_path(Remote *remote, Packet *packet)
|
|||||||
{
|
{
|
||||||
Packet *response = packet_create_response(packet);
|
Packet *response = packet_create_response(packet);
|
||||||
DWORD result = ERROR_SUCCESS;
|
DWORD result = ERROR_SUCCESS;
|
||||||
LPSTR expanded = NULL;
|
char *expanded = NULL;
|
||||||
LPSTR regular;
|
char *regular;
|
||||||
|
|
||||||
regular = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_PATH);
|
regular = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_PATH);
|
||||||
|
if (regular == NULL) {
|
||||||
|
result = ERROR_INVALID_PARAMETER;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
do
|
// Allocate storage for the expanded path
|
||||||
{
|
expanded = fs_expand_path(regular);
|
||||||
// No regular path?
|
if (expanded == NULL) {
|
||||||
if (!regular)
|
result = ERROR_NOT_ENOUGH_MEMORY;
|
||||||
{
|
goto out;
|
||||||
result = ERROR_INVALID_PARAMETER;
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allocate storage for the expanded path
|
packet_add_tlv_string(response, TLV_TYPE_FILE_PATH, expanded);
|
||||||
if (!(expanded = fs_expand_path(regular)))
|
free(expanded);
|
||||||
{
|
out:
|
||||||
result = ERROR_NOT_ENOUGH_MEMORY;
|
packet_add_tlv_uint(response, TLV_TYPE_RESULT, result);
|
||||||
break;
|
return packet_transmit(remote, response, NULL);
|
||||||
}
|
|
||||||
|
|
||||||
packet_add_tlv_string(response, TLV_TYPE_FILE_PATH, expanded);
|
|
||||||
|
|
||||||
} while (0);
|
|
||||||
|
|
||||||
// Transmit the response to the mofo
|
|
||||||
packet_transmit_response(result, remote, response);
|
|
||||||
|
|
||||||
if (expanded)
|
|
||||||
free(expanded);
|
|
||||||
|
|
||||||
return ERROR_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns the MD5 hash for a specified file path
|
* Returns the MD5 hash for a specified file path
|
||||||
*
|
*
|
||||||
* TLVs:
|
|
||||||
*
|
|
||||||
* req: TLV_TYPE_FILE_PATH - The file path that is to be stat'd
|
* req: TLV_TYPE_FILE_PATH - The file path that is to be stat'd
|
||||||
*/
|
*/
|
||||||
DWORD request_fs_md5(Remote *remote, Packet *packet)
|
DWORD request_fs_md5(Remote *remote, Packet *packet)
|
||||||
{
|
{
|
||||||
Packet *response = packet_create_response(packet);
|
Packet *response = packet_create_response(packet);
|
||||||
LPCSTR filePath;
|
char *filePath;
|
||||||
LPSTR expanded = NULL;
|
|
||||||
DWORD result = ERROR_SUCCESS;
|
DWORD result = ERROR_SUCCESS;
|
||||||
MD5_CTX context;
|
MD5_CTX context;
|
||||||
|
|
||||||
FILE *fd;
|
FILE *fd;
|
||||||
size_t ret;
|
size_t ret;
|
||||||
unsigned char buff[16384];
|
unsigned char buff[16384];
|
||||||
unsigned char hash[128];
|
unsigned char hash[MD5_DIGEST_LENGTH + 1] = {0};
|
||||||
|
|
||||||
filePath = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_PATH);
|
filePath = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_PATH);
|
||||||
|
|
||||||
// Validate parameters
|
result = fs_fopen(filePath, "rb", &fd);
|
||||||
if (!filePath)
|
if (result == ERROR_SUCCESS) {
|
||||||
result = ERROR_INVALID_PARAMETER;
|
|
||||||
else if (!(expanded = fs_expand_path(filePath)))
|
|
||||||
result = ERROR_NOT_ENOUGH_MEMORY;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
do {
|
|
||||||
MD5_Init(&context);
|
|
||||||
fd = fopen(expanded, "rb");
|
|
||||||
if (! fd) {
|
|
||||||
result = GetLastError();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
while((ret = fread(buff, 1, sizeof(buff), fd)) > 0 ) {
|
MD5_Init(&context);
|
||||||
MD5_Update(&context, buff, ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(fd);
|
while ((ret = fread(buff, 1, sizeof(buff), fd)) > 0 ) {
|
||||||
MD5_Final(hash, &context);
|
MD5_Update(&context, buff, ret);
|
||||||
|
}
|
||||||
|
|
||||||
// One byte extra for the NULL
|
MD5_Final(hash, &context);
|
||||||
packet_add_tlv_raw(response, TLV_TYPE_FILE_NAME, hash, 17);
|
|
||||||
} while(0);
|
packet_add_tlv_raw(response, TLV_TYPE_FILE_NAME, hash, sizeof(hash));
|
||||||
|
|
||||||
|
fclose(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the result and transmit the response
|
|
||||||
packet_add_tlv_uint(response, TLV_TYPE_RESULT, result);
|
packet_add_tlv_uint(response, TLV_TYPE_RESULT, result);
|
||||||
|
return packet_transmit(remote, response, NULL);
|
||||||
packet_transmit(remote, response, NULL);
|
|
||||||
|
|
||||||
if (expanded)
|
|
||||||
free(expanded);
|
|
||||||
|
|
||||||
return ERROR_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns the SHA1 hash for a specified file path
|
* Returns the SHA1 hash for a specified file path
|
||||||
*
|
*
|
||||||
* TLVs:
|
|
||||||
*
|
|
||||||
* req: TLV_TYPE_FILE_PATH - The file path that is to be stat'd
|
* req: TLV_TYPE_FILE_PATH - The file path that is to be stat'd
|
||||||
*/
|
*/
|
||||||
DWORD request_fs_sha1(Remote *remote, Packet *packet)
|
DWORD request_fs_sha1(Remote *remote, Packet *packet)
|
||||||
{
|
{
|
||||||
Packet *response = packet_create_response(packet);
|
Packet *response = packet_create_response(packet);
|
||||||
LPCSTR filePath;
|
char *filePath;
|
||||||
LPSTR expanded = NULL;
|
|
||||||
DWORD result = ERROR_SUCCESS;
|
DWORD result = ERROR_SUCCESS;
|
||||||
SHA_CTX context;
|
SHA_CTX context;
|
||||||
|
|
||||||
FILE *fd;
|
FILE *fd;
|
||||||
size_t ret;
|
size_t ret;
|
||||||
unsigned char buff[16384];
|
unsigned char buff[16384];
|
||||||
unsigned char hash[128];
|
unsigned char hash[SHA_DIGEST_LENGTH + 1] = {0};
|
||||||
|
|
||||||
filePath = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_PATH);
|
filePath = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_PATH);
|
||||||
|
|
||||||
// Validate parameters
|
result = fs_fopen(filePath, "rb", &fd);
|
||||||
if (!filePath)
|
if (result == ERROR_SUCCESS) {
|
||||||
result = ERROR_INVALID_PARAMETER;
|
SHA1_Init(&context);
|
||||||
else if (!(expanded = fs_expand_path(filePath)))
|
|
||||||
result = ERROR_NOT_ENOUGH_MEMORY;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
do {
|
|
||||||
SHA1_Init(&context);
|
|
||||||
fd = fopen(expanded, "rb");
|
|
||||||
if (! fd) {
|
|
||||||
result = GetLastError();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
while((ret = fread(buff, 1, sizeof(buff), fd)) > 0 ) {
|
while ((ret = fread(buff, 1, sizeof(buff), fd)) > 0 ) {
|
||||||
SHA1_Update(&context, buff, ret);
|
SHA1_Update(&context, buff, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(fd);
|
fclose(fd);
|
||||||
SHA1_Final(hash, &context);
|
SHA1_Final(hash, &context);
|
||||||
|
|
||||||
// One byte extra for the NULL
|
packet_add_tlv_raw(response, TLV_TYPE_FILE_NAME, hash, sizeof(hash));
|
||||||
packet_add_tlv_raw(response, TLV_TYPE_FILE_NAME, hash, 21);
|
|
||||||
} while(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the result and transmit the response
|
|
||||||
packet_add_tlv_uint(response, TLV_TYPE_RESULT, result);
|
packet_add_tlv_uint(response, TLV_TYPE_RESULT, result);
|
||||||
|
return packet_transmit(remote, response, NULL);
|
||||||
packet_transmit(remote, response, NULL);
|
|
||||||
|
|
||||||
if (expanded)
|
|
||||||
free(expanded);
|
|
||||||
|
|
||||||
return ERROR_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copies source file path to destination
|
* Copies source file path to destination
|
||||||
*
|
*
|
||||||
@ -495,25 +396,19 @@ DWORD request_fs_file_move(Remote *remote, Packet *packet)
|
|||||||
{
|
{
|
||||||
Packet *response = packet_create_response(packet);
|
Packet *response = packet_create_response(packet);
|
||||||
DWORD result = ERROR_SUCCESS;
|
DWORD result = ERROR_SUCCESS;
|
||||||
LPCSTR oldpath;
|
char *oldpath;
|
||||||
LPCSTR newpath;
|
char *newpath;
|
||||||
|
|
||||||
oldpath = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_NAME);
|
oldpath = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_NAME);
|
||||||
newpath = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_PATH);
|
newpath = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_PATH);
|
||||||
|
|
||||||
if (!oldpath)
|
if (!oldpath) {
|
||||||
result = ERROR_INVALID_PARAMETER;
|
result = ERROR_INVALID_PARAMETER;
|
||||||
#ifdef _WIN32
|
} else {
|
||||||
else if (!MoveFile(oldpath,newpath))
|
result = fs_move(oldpath, newpath);
|
||||||
#else
|
}
|
||||||
else if (rename(oldpath,newpath))
|
|
||||||
#endif
|
|
||||||
result = GetLastError();
|
|
||||||
|
|
||||||
packet_add_tlv_uint(response, TLV_TYPE_RESULT, result);
|
packet_add_tlv_uint(response, TLV_TYPE_RESULT, result);
|
||||||
|
return packet_transmit(remote, response, NULL);
|
||||||
packet_transmit(remote, response, NULL);
|
|
||||||
|
|
||||||
return ERROR_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#ifndef _METERPRETER_SOURCE_EXTENSION_STDAPI_STDAPI_SERVER_FS_FS_H
|
#ifndef _METERPRETER_SOURCE_EXTENSION_STDAPI_STDAPI_SERVER_FS_FS_H
|
||||||
#define _METERPRETER_SOURCE_EXTENSION_STDAPI_STDAPI_SERVER_FS_FS_H
|
#define _METERPRETER_SOURCE_EXTENSION_STDAPI_STDAPI_SERVER_FS_FS_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
LPSTR fs_expand_path(LPCSTR regular);
|
LPSTR fs_expand_path(LPCSTR regular);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -25,33 +27,4 @@ DWORD request_fs_file_move(Remote *remote, Packet *packet);
|
|||||||
*/
|
*/
|
||||||
DWORD request_fs_file_channel_open(Remote *remote, Packet *packet);
|
DWORD request_fs_file_channel_open(Remote *remote, Packet *packet);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Stat structures on Windows and various Unixes are all slightly different.
|
|
||||||
* Use this as a means of standardization so the client has some hope of
|
|
||||||
* understanding what the stat'd file really is.
|
|
||||||
*/
|
|
||||||
struct meterp_stat {
|
|
||||||
unsigned int st_dev;
|
|
||||||
unsigned short st_ino;
|
|
||||||
unsigned short st_mode;
|
|
||||||
unsigned short st_nlink;
|
|
||||||
unsigned short st_uid;
|
|
||||||
unsigned short st_gid;
|
|
||||||
unsigned short pad;
|
|
||||||
unsigned int st_rdev;
|
|
||||||
unsigned int st_size;
|
|
||||||
/*
|
|
||||||
* These are always 64-bits on Windows and usually 32-bits on Linux. Force
|
|
||||||
* them to be the same size everywhere.
|
|
||||||
*/
|
|
||||||
unsigned long long st_atime;
|
|
||||||
unsigned long long st_mtime;
|
|
||||||
unsigned long long st_ctime;
|
|
||||||
};
|
|
||||||
|
|
||||||
int fs_stat(LPCSTR filename, struct meterp_stat *buf);
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
68
c/meterpreter/source/extensions/stdapi/server/fs/fs_local.h
Normal file
68
c/meterpreter/source/extensions/stdapi/server/fs/fs_local.h
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
#ifndef _FS_LOCAL_H
|
||||||
|
#define _FS_LOCAL_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define FS_SEPARATOR "\\"
|
||||||
|
#define FS_MAX_PATH 32768
|
||||||
|
#else
|
||||||
|
#define FS_SEPARATOR "/"
|
||||||
|
#define FS_MAX_PATH PATH_MAX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stat structures on Windows and various Unixes are all slightly different.
|
||||||
|
* Use this as a means of standardization so the client has some hope of
|
||||||
|
* understanding what the stat'd file really is.
|
||||||
|
*/
|
||||||
|
struct meterp_stat {
|
||||||
|
uint32_t st_dev;
|
||||||
|
uint16_t st_ino;
|
||||||
|
uint16_t st_mode;
|
||||||
|
uint16_t st_nlink;
|
||||||
|
uint16_t st_uid;
|
||||||
|
uint16_t st_gid;
|
||||||
|
uint16_t pad;
|
||||||
|
uint32_t st_rdev;
|
||||||
|
uint32_t st_size;
|
||||||
|
/*
|
||||||
|
* These are always 64-bits on Windows and usually 32-bits on Linux. Force
|
||||||
|
* them to be the same size everywhere.
|
||||||
|
*/
|
||||||
|
uint64_t st_atime;
|
||||||
|
uint64_t st_mtime;
|
||||||
|
uint64_t st_ctime;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void (*fs_ls_cb_t)(void *arg, char *name, char *short_name, char *path);
|
||||||
|
|
||||||
|
int fs_chdir(const char *directory);
|
||||||
|
|
||||||
|
int fs_delete_dir(const char *directory);
|
||||||
|
|
||||||
|
int fs_delete_file(const char *path);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns an expanded file path that must be freed
|
||||||
|
*/
|
||||||
|
char * fs_expand_path(const char *regular);
|
||||||
|
|
||||||
|
int fs_fopen(const char *path, const char *mode, FILE **f);
|
||||||
|
|
||||||
|
int fs_ls(const char *directory, fs_ls_cb_t cb, void *arg);
|
||||||
|
|
||||||
|
int fs_getwd(char **directory);
|
||||||
|
|
||||||
|
int fs_mkdir(const char *directory);
|
||||||
|
|
||||||
|
int fs_move(const char *oldpath, const char *newpath);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fills the platform-independent meterp_stat buf with data from the
|
||||||
|
* platform-dependent stat()
|
||||||
|
*/
|
||||||
|
int fs_stat(char *filename, struct meterp_stat *buf);
|
||||||
|
|
||||||
|
#endif
|
126
c/meterpreter/source/extensions/stdapi/server/fs/fs_posix.c
Normal file
126
c/meterpreter/source/extensions/stdapi/server/fs/fs_posix.c
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "precomp.h"
|
||||||
|
#include "fs_local.h"
|
||||||
|
|
||||||
|
int fs_ls(const char *directory, fs_ls_cb_t cb, void *arg)
|
||||||
|
{
|
||||||
|
struct meterp_stat s;
|
||||||
|
struct dirent *data;
|
||||||
|
char path[FS_MAX_PATH];
|
||||||
|
|
||||||
|
DIR *ctx = opendir(directory);
|
||||||
|
if (ctx == NULL) {
|
||||||
|
return errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((data = readdir(ctx))) {
|
||||||
|
|
||||||
|
snprintf(path, sizeof(path), "%s/%s", directory, data->d_name);
|
||||||
|
|
||||||
|
cb(arg, data->d_name, NULL, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(ctx);
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fs_chdir(const char *directory)
|
||||||
|
{
|
||||||
|
if (chdir(directory) == -1) {
|
||||||
|
return errno;
|
||||||
|
}
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fs_delete_file(const char *path)
|
||||||
|
{
|
||||||
|
if (unlink(path) == -1) {
|
||||||
|
return errno;
|
||||||
|
}
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fs_delete_dir(const char *directory)
|
||||||
|
{
|
||||||
|
if (rmdir(directory) == -1) {
|
||||||
|
return errno;
|
||||||
|
}
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
char * fs_expand_path(const char *regular)
|
||||||
|
{
|
||||||
|
return strdup(regular);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fs_getwd(char **directory)
|
||||||
|
{
|
||||||
|
char dir[FS_MAX_PATH];
|
||||||
|
if (getcwd(dir, sizeof(dir)) == NULL) {
|
||||||
|
return errno;
|
||||||
|
}
|
||||||
|
*directory = strdup(dir);
|
||||||
|
return *directory == NULL ? ERROR_NOT_ENOUGH_MEMORY : ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fs_mkdir(const char *directory)
|
||||||
|
{
|
||||||
|
if (mkdir(directory, 0777) == -1) {
|
||||||
|
return errno;
|
||||||
|
}
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fs_fopen(const char *path, const char *mode, FILE **f)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
if (path == NULL || f == NULL) {
|
||||||
|
return ERROR_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
*f = fopen(path, mode);
|
||||||
|
if (*f == NULL) {
|
||||||
|
rc = errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fs_move(const char *oldpath, const char *newpath)
|
||||||
|
{
|
||||||
|
if (rename(oldpath, newpath) == -1) {
|
||||||
|
return errno;
|
||||||
|
}
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fs_stat(char *filename, struct meterp_stat *buf)
|
||||||
|
{
|
||||||
|
struct stat sbuf;
|
||||||
|
|
||||||
|
if (stat(filename, &sbuf) == -1) {
|
||||||
|
return errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf->st_dev = sbuf.st_dev;
|
||||||
|
buf->st_ino = sbuf.st_ino;
|
||||||
|
buf->st_mode = sbuf.st_mode;
|
||||||
|
buf->st_nlink = sbuf.st_nlink;
|
||||||
|
buf->st_uid = sbuf.st_uid;
|
||||||
|
buf->st_gid = sbuf.st_gid;
|
||||||
|
buf->st_rdev = sbuf.st_rdev;
|
||||||
|
buf->st_size = sbuf.st_size;
|
||||||
|
buf->st_atime = sbuf.st_atime;
|
||||||
|
buf->st_mtime = sbuf.st_mtime;
|
||||||
|
buf->st_ctime = sbuf.st_ctime;
|
||||||
|
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
@ -1,75 +0,0 @@
|
|||||||
#include "precomp.h"
|
|
||||||
#include "fs.h"
|
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns an expanded file path that must be freed
|
|
||||||
*/
|
|
||||||
LPSTR fs_expand_path(LPCSTR regular)
|
|
||||||
{
|
|
||||||
#ifdef _WIN32
|
|
||||||
DWORD expandedFilePathSize = 32768;
|
|
||||||
LPSTR expandedFilePath = NULL;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
// Expand the file path
|
|
||||||
if (!(expandedFilePath = (LPSTR)malloc(expandedFilePathSize)))
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Expand the file path being accessed
|
|
||||||
if (!ExpandEnvironmentStrings(regular, expandedFilePath,
|
|
||||||
expandedFilePathSize - 1))
|
|
||||||
{
|
|
||||||
free(expandedFilePath);
|
|
||||||
|
|
||||||
expandedFilePath = 0;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
expandedFilePath[expandedFilePathSize - 1] = 0;
|
|
||||||
|
|
||||||
} while (0);
|
|
||||||
|
|
||||||
return expandedFilePath;
|
|
||||||
#else /* Hack to make it work with existing code under *nix */
|
|
||||||
char *expandedFilePath;
|
|
||||||
DWORD expandedFilePathSize = strlen(regular)+1;
|
|
||||||
expandedFilePath = malloc(expandedFilePathSize);
|
|
||||||
strncpy(expandedFilePath, regular, expandedFilePathSize);
|
|
||||||
expandedFilePath[expandedFilePathSize - 1] = '\0';
|
|
||||||
return expandedFilePath;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Fills the platform-independent meterp_stat buf with data from the platform-dependent stat()
|
|
||||||
*/
|
|
||||||
int fs_stat(LPCSTR filename, struct meterp_stat *buf) {
|
|
||||||
struct stat sbuf;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = stat(filename, &sbuf);
|
|
||||||
|
|
||||||
if (ret == 0) {
|
|
||||||
buf->st_dev = sbuf.st_dev;
|
|
||||||
buf->st_ino = sbuf.st_ino;
|
|
||||||
buf->st_mode = sbuf.st_mode;
|
|
||||||
buf->st_nlink = sbuf.st_nlink;
|
|
||||||
buf->st_uid = sbuf.st_uid;
|
|
||||||
buf->st_gid = sbuf.st_gid;
|
|
||||||
buf->st_rdev = sbuf.st_rdev;
|
|
||||||
buf->st_size = sbuf.st_size;
|
|
||||||
buf->st_atime = (unsigned long long)sbuf.st_atime;
|
|
||||||
buf->st_mtime = (unsigned long long)sbuf.st_mtime;
|
|
||||||
buf->st_ctime = (unsigned long long)sbuf.st_ctime;
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
#ifdef _WIN32
|
|
||||||
return GetLastError();
|
|
||||||
#else
|
|
||||||
return errno;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
339
c/meterpreter/source/extensions/stdapi/server/fs/fs_win.c
Normal file
339
c/meterpreter/source/extensions/stdapi/server/fs/fs_win.c
Normal file
@ -0,0 +1,339 @@
|
|||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include "fs_local.h"
|
||||||
|
#include "precomp.h"
|
||||||
|
|
||||||
|
static wchar_t *utf8_to_wchar(const char *in)
|
||||||
|
{
|
||||||
|
wchar_t *out;
|
||||||
|
int len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, in, -1, NULL, 0);
|
||||||
|
if (len <= 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
out = calloc(len, sizeof(wchar_t));
|
||||||
|
if (out == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MultiByteToWideChar(CP_UTF8, 0, in, -1, out, len) == 0) {
|
||||||
|
free(out);
|
||||||
|
out = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *wchar_to_utf8(const wchar_t *in)
|
||||||
|
{
|
||||||
|
char *out;
|
||||||
|
int len = WideCharToMultiByte(CP_UTF8, 0, in, -1, NULL, 0, NULL, NULL);
|
||||||
|
if (len <= 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
out = calloc(len, sizeof(char));
|
||||||
|
if (out == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WideCharToMultiByte(CP_UTF8, 0, in, -1, out, len, NULL, FALSE) == 0) {
|
||||||
|
free(out);
|
||||||
|
out = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
char * fs_expand_path(const char *regular)
|
||||||
|
{
|
||||||
|
wchar_t expanded_path[FS_MAX_PATH];
|
||||||
|
wchar_t *regular_w;
|
||||||
|
|
||||||
|
regular_w = utf8_to_wchar(regular);
|
||||||
|
if (regular_w == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ExpandEnvironmentStringsW(regular_w, expanded_path, FS_MAX_PATH) == 0) {
|
||||||
|
free(regular_w);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(regular_w);
|
||||||
|
|
||||||
|
return wchar_to_utf8(expanded_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fs_ls(const char *directory, fs_ls_cb_t cb, void *arg)
|
||||||
|
{
|
||||||
|
DWORD result = 0;
|
||||||
|
LPSTR expanded = NULL;
|
||||||
|
LPSTR baseDirectory = NULL;
|
||||||
|
char tempDirectory[FS_MAX_PATH];
|
||||||
|
|
||||||
|
_snprintf(tempDirectory, sizeof(tempDirectory), "%s", directory);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If there is not wildcard mask on the directory, create a version of the
|
||||||
|
* directory with a mask appended
|
||||||
|
*/
|
||||||
|
if (strrchr(directory, '*') == NULL) {
|
||||||
|
_snprintf(tempDirectory, sizeof(tempDirectory), "%s\\*",
|
||||||
|
directory);
|
||||||
|
|
||||||
|
baseDirectory = _strdup(directory);
|
||||||
|
if (baseDirectory == NULL) {
|
||||||
|
result = ERROR_NOT_ENOUGH_MEMORY;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Otherwise, if it does have an asterisk, we need to scan back
|
||||||
|
* and find the base directory. If there is no slash, it means
|
||||||
|
* we're listing the cwd.
|
||||||
|
*/
|
||||||
|
PCHAR slash = strrchr(directory, '\\');
|
||||||
|
if (slash) {
|
||||||
|
*slash = 0;
|
||||||
|
baseDirectory = _strdup(directory);
|
||||||
|
if (baseDirectory == NULL) {
|
||||||
|
result = ERROR_NOT_ENOUGH_MEMORY;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
*slash = '\\';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expanded = fs_expand_path(tempDirectory);
|
||||||
|
if (expanded == NULL) {
|
||||||
|
result = ERROR_NOT_ENOUGH_MEMORY;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
WIN32_FIND_DATAW data;
|
||||||
|
wchar_t *path_w = utf8_to_wchar(expanded);
|
||||||
|
if (path_w == NULL) {
|
||||||
|
result = GetLastError();
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE ctx = FindFirstFileW(path_w, &data);
|
||||||
|
if (ctx == NULL) {
|
||||||
|
result = GetLastError();
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (ctx == INVALID_HANDLE_VALUE) {
|
||||||
|
result = GetLastError();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *filename = wchar_to_utf8(data.cFileName);
|
||||||
|
char *short_filename = wchar_to_utf8(data.cAlternateFileName);
|
||||||
|
char path[FS_MAX_PATH];
|
||||||
|
|
||||||
|
if (baseDirectory) {
|
||||||
|
_snprintf(path, sizeof(path), "%s\\%s", baseDirectory, filename);
|
||||||
|
} else {
|
||||||
|
_snprintf(path, sizeof(path), "%s", filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
cb(arg, filename, short_filename, path);
|
||||||
|
|
||||||
|
free(filename);
|
||||||
|
free(short_filename);
|
||||||
|
|
||||||
|
} while (FindNextFileW(ctx, &data));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clean up resources
|
||||||
|
*/
|
||||||
|
FindClose(ctx);
|
||||||
|
free(expanded);
|
||||||
|
out:
|
||||||
|
free(baseDirectory);
|
||||||
|
free(path_w);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fs_chdir(const char *directory)
|
||||||
|
{
|
||||||
|
int rc = ERROR_SUCCESS;
|
||||||
|
wchar_t *dir_w = utf8_to_wchar(directory);
|
||||||
|
|
||||||
|
if (dir_w == NULL) {
|
||||||
|
rc = GetLastError();
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SetCurrentDirectoryW(dir_w) == 0) {
|
||||||
|
rc = GetLastError();
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
free(dir_w);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fs_delete_dir(const char *directory)
|
||||||
|
{
|
||||||
|
int rc = ERROR_SUCCESS;
|
||||||
|
wchar_t *dir_w = utf8_to_wchar(directory);
|
||||||
|
|
||||||
|
if (dir_w == NULL) {
|
||||||
|
rc = GetLastError();
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RemoveDirectoryW(dir_w) == 0) {
|
||||||
|
rc = GetLastError();
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
free(dir_w);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fs_delete_file(const char *path)
|
||||||
|
{
|
||||||
|
int rc = ERROR_SUCCESS;
|
||||||
|
wchar_t *path_w = utf8_to_wchar(path);
|
||||||
|
|
||||||
|
if (path_w == NULL) {
|
||||||
|
rc = GetLastError();
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DeleteFileW(path_w) == 0) {
|
||||||
|
rc = GetLastError();
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
free(path_w);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fs_getwd(char **dir)
|
||||||
|
{
|
||||||
|
int rc = ERROR_SUCCESS;
|
||||||
|
wchar_t dir_w[FS_MAX_PATH];
|
||||||
|
|
||||||
|
if (GetCurrentDirectoryW(FS_MAX_PATH, dir_w) == 0) {
|
||||||
|
rc = GetLastError();
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
*dir = wchar_to_utf8(dir_w);
|
||||||
|
if (*dir == NULL) {
|
||||||
|
rc = GetLastError();
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fs_move(const char *oldpath, const char *newpath)
|
||||||
|
{
|
||||||
|
int rc = ERROR_SUCCESS;
|
||||||
|
wchar_t *old_w = utf8_to_wchar(oldpath);
|
||||||
|
wchar_t *new_w = utf8_to_wchar(newpath);
|
||||||
|
|
||||||
|
if ((old_w == NULL) || (new_w == NULL)) {
|
||||||
|
rc = GetLastError();
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MoveFileW(old_w, new_w) == 0) {
|
||||||
|
rc = GetLastError();
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
free(old_w);
|
||||||
|
free(new_w);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fs_mkdir(const char *directory)
|
||||||
|
{
|
||||||
|
int rc = ERROR_SUCCESS;
|
||||||
|
wchar_t *dir_w = utf8_to_wchar(directory);
|
||||||
|
|
||||||
|
if (dir_w == NULL) {
|
||||||
|
rc = GetLastError();
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CreateDirectoryW(dir_w, NULL) == 0) {
|
||||||
|
rc = GetLastError();
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
free(dir_w);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fs_fopen(const char *path, const char *mode, FILE **f)
|
||||||
|
{
|
||||||
|
char *expanded = NULL;
|
||||||
|
int rc = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
if (path == NULL || f == NULL) {
|
||||||
|
return ERROR_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((expanded = fs_expand_path(path)) == NULL) {
|
||||||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
wchar_t *path_w = utf8_to_wchar(expanded);
|
||||||
|
wchar_t *mode_w = utf8_to_wchar(mode);
|
||||||
|
|
||||||
|
if ((path_w == NULL) || (mode_w == NULL)) {
|
||||||
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
*f = _wfopen(path_w, mode_w);
|
||||||
|
if (*f == NULL) {
|
||||||
|
rc = GetLastError();
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
free(expanded);
|
||||||
|
free(path_w);
|
||||||
|
free(mode_w);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fs_stat(char *filename, struct meterp_stat *buf)
|
||||||
|
{
|
||||||
|
struct _stat64i32 sbuf;
|
||||||
|
|
||||||
|
wchar_t *filename_w = utf8_to_wchar(filename);
|
||||||
|
if (filename_w == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_wstat(filename_w, &sbuf) == -1) {
|
||||||
|
return GetLastError();
|
||||||
|
}
|
||||||
|
|
||||||
|
free(filename_w);
|
||||||
|
|
||||||
|
buf->st_dev = sbuf.st_dev;
|
||||||
|
buf->st_ino = sbuf.st_ino;
|
||||||
|
buf->st_mode = sbuf.st_mode;
|
||||||
|
buf->st_nlink = sbuf.st_nlink;
|
||||||
|
buf->st_uid = sbuf.st_uid;
|
||||||
|
buf->st_gid = sbuf.st_gid;
|
||||||
|
buf->st_rdev = sbuf.st_rdev;
|
||||||
|
buf->st_size = sbuf.st_size;
|
||||||
|
buf->st_atime = sbuf.st_atime;
|
||||||
|
buf->st_mtime = sbuf.st_mtime;
|
||||||
|
buf->st_ctime = sbuf.st_ctime;
|
||||||
|
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
@ -216,8 +216,16 @@ DWORD DeinitServerExtension(Remote *remote)
|
|||||||
* @param bufferSize Size of the \c buffer parameter.
|
* @param bufferSize Size of the \c buffer parameter.
|
||||||
* @return Indication of success or failure.
|
* @return Indication of success or failure.
|
||||||
*/
|
*/
|
||||||
|
#ifdef _WIN32
|
||||||
DWORD __declspec(dllexport) GetExtensionName(char* buffer, int bufferSize)
|
DWORD __declspec(dllexport) GetExtensionName(char* buffer, int bufferSize)
|
||||||
|
#else
|
||||||
|
DWORD GetExtensionName(char* buffer, int bufferSize)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
strncpy_s(buffer, bufferSize, "stdapi", bufferSize - 1);
|
strncpy_s(buffer, bufferSize, "stdapi", bufferSize - 1);
|
||||||
|
#else
|
||||||
|
strncpy(buffer, "stdapi", bufferSize - 1);
|
||||||
|
#endif
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#define TLV_TYPE_FILE_PATH MAKE_CUSTOM_TLV( TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_STDAPI, 1202 )
|
#define TLV_TYPE_FILE_PATH MAKE_CUSTOM_TLV( TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_STDAPI, 1202 )
|
||||||
#define TLV_TYPE_FILE_MODE MAKE_CUSTOM_TLV( TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_STDAPI, 1203 )
|
#define TLV_TYPE_FILE_MODE MAKE_CUSTOM_TLV( TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_STDAPI, 1203 )
|
||||||
#define TLV_TYPE_FILE_SIZE MAKE_CUSTOM_TLV( TLV_META_TYPE_UINT, TLV_TYPE_EXTENSION_STDAPI, 1204 )
|
#define TLV_TYPE_FILE_SIZE MAKE_CUSTOM_TLV( TLV_META_TYPE_UINT, TLV_TYPE_EXTENSION_STDAPI, 1204 )
|
||||||
|
#define TLV_TYPE_FILE_SHORT_NAME MAKE_CUSTOM_TLV( TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_STDAPI, 1205 )
|
||||||
|
|
||||||
#define TLV_TYPE_STAT_BUF MAKE_CUSTOM_TLV( TLV_META_TYPE_COMPLEX, TLV_TYPE_EXTENSION_STDAPI, 1220 )
|
#define TLV_TYPE_STAT_BUF MAKE_CUSTOM_TLV( TLV_META_TYPE_COMPLEX, TLV_TYPE_EXTENSION_STDAPI, 1220 )
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#include "metsrv.h"
|
#include "metsrv.h"
|
||||||
|
|
||||||
extern Command *extensionCommands;
|
extern Command *extensionCommands;
|
||||||
|
extern PLIST gExtensionList;
|
||||||
|
|
||||||
DWORD request_core_loadlib(Remote *remote, Packet *packet)
|
DWORD request_core_loadlib(Remote *remote, Packet *packet)
|
||||||
{
|
{
|
||||||
@ -61,15 +62,37 @@ DWORD request_core_loadlib(Remote *remote, Packet *packet)
|
|||||||
// call its Init routine
|
// call its Init routine
|
||||||
if (flags & LOAD_LIBRARY_FLAG_EXTENSION)
|
if (flags & LOAD_LIBRARY_FLAG_EXTENSION)
|
||||||
{
|
{
|
||||||
DWORD(*init)(Remote *remote);
|
PEXTENSION pExtension = (PEXTENSION)malloc(sizeof(EXTENSION));
|
||||||
|
if (!pExtension)
|
||||||
|
{
|
||||||
|
res = ERROR_NOT_ENOUGH_MEMORY;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//DWORD(*init)(Remote *remote);
|
||||||
|
|
||||||
|
pExtension->init = dlsym(library, "InitServerExtension");
|
||||||
|
|
||||||
init = dlsym(library, "InitServerExtension");
|
|
||||||
// Call the init routine in the library
|
// Call the init routine in the library
|
||||||
if (init)
|
if (pExtension->init)
|
||||||
{
|
{
|
||||||
dprintf("calling InitServerExtension");
|
dprintf("calling InitServerExtension");
|
||||||
res = init(remote);
|
res = pExtension->init(remote);
|
||||||
|
pExtension->getname = dlsym(library, "GetExtensionName");
|
||||||
|
|
||||||
|
|
||||||
|
pExtension->deinit = dlsym(library, "DeinitServerExtension");
|
||||||
|
|
||||||
|
if (pExtension->getname)
|
||||||
|
{
|
||||||
|
pExtension->getname(pExtension->name, sizeof(pExtension->name));
|
||||||
|
}
|
||||||
|
list_push(gExtensionList, pExtension);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
free(pExtension);
|
||||||
|
}
|
||||||
|
|
||||||
if (response)
|
if (response)
|
||||||
{
|
{
|
||||||
for (command = extensionCommands; command != first; command = command->next)
|
for (command = extensionCommands; command != first; command = command->next)
|
||||||
|
@ -7,6 +7,8 @@ extern HINSTANCE hAppInstance;
|
|||||||
|
|
||||||
PLIST gExtensionList = NULL;
|
PLIST gExtensionList = NULL;
|
||||||
|
|
||||||
|
DWORD request_core_enumextcmd(Remote* pRemote, Packet* pPacket);
|
||||||
|
|
||||||
// Dispatch table
|
// Dispatch table
|
||||||
Command customCommands[] =
|
Command customCommands[] =
|
||||||
{
|
{
|
||||||
@ -15,6 +17,56 @@ Command customCommands[] =
|
|||||||
COMMAND_TERMINATOR
|
COMMAND_TERMINATOR
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct _EnumExtensions
|
||||||
|
{
|
||||||
|
Packet* pResponse;
|
||||||
|
char* lpExtensionName;
|
||||||
|
} EnumExtensions, * PEnumExtensions;
|
||||||
|
|
||||||
|
BOOL ext_cmd_callback(LPVOID pState, LPVOID pData)
|
||||||
|
{
|
||||||
|
PEnumExtensions pEnum = (PEnumExtensions)pState;
|
||||||
|
Command* command = NULL;
|
||||||
|
|
||||||
|
if (pEnum != NULL && pEnum->pResponse != NULL && pData != NULL)
|
||||||
|
{
|
||||||
|
PEXTENSION pExt = (PEXTENSION)pData;
|
||||||
|
if (pExt->name[0] != '\0' && pEnum->lpExtensionName != NULL && strcmp(pExt->name, pEnum->lpExtensionName) == 0)
|
||||||
|
{
|
||||||
|
dprintf("[LISTEXT] Found extension: %s", pExt->name);
|
||||||
|
for (command = pExt->start; command != pExt->end; command = command->next)
|
||||||
|
{
|
||||||
|
packet_add_tlv_string(pEnum->pResponse, TLV_TYPE_STRING, command->method);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD request_core_enumextcmd(Remote* pRemote, Packet* pPacket)
|
||||||
|
{
|
||||||
|
BOOL bResult = FALSE;
|
||||||
|
Packet* pResponse = packet_create_response(pPacket);
|
||||||
|
|
||||||
|
if (pResponse != NULL)
|
||||||
|
{
|
||||||
|
EnumExtensions enumExt;
|
||||||
|
enumExt.pResponse = pResponse;
|
||||||
|
enumExt.lpExtensionName = packet_get_tlv_value_string(pPacket, TLV_TYPE_STRING);
|
||||||
|
|
||||||
|
dprintf("[LISTEXTCMD] Listing extension commands for %s ...", enumExt.lpExtensionName);
|
||||||
|
// Start by enumerating the names of the extensions
|
||||||
|
bResult = list_enumerate(gExtensionList, ext_cmd_callback, &enumExt);
|
||||||
|
|
||||||
|
packet_add_tlv_uint(pResponse, TLV_TYPE_RESULT, ERROR_SUCCESS);
|
||||||
|
packet_transmit(pRemote, pResponse, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Registers custom command handlers
|
* Registers custom command handlers
|
||||||
*/
|
*/
|
||||||
@ -38,7 +90,10 @@ VOID deregister_dispatch_routines(Remote * remote)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
extension->deinit(remote);
|
if (extension->deinit)
|
||||||
|
{
|
||||||
|
extension->deinit(remote);
|
||||||
|
}
|
||||||
|
|
||||||
free(extension);
|
free(extension);
|
||||||
}
|
}
|
||||||
|
@ -8,54 +8,6 @@ extern PLIST gExtensionList;
|
|||||||
// see common/base.c
|
// see common/base.c
|
||||||
extern Command *extensionCommands;
|
extern Command *extensionCommands;
|
||||||
|
|
||||||
typedef struct _EnumExtensions
|
|
||||||
{
|
|
||||||
Packet* pResponse;
|
|
||||||
char* lpExtensionName;
|
|
||||||
} EnumExtensions, * PEnumExtensions;
|
|
||||||
|
|
||||||
BOOL ext_cmd_callback(LPVOID pState, LPVOID pData)
|
|
||||||
{
|
|
||||||
PEnumExtensions pEnum = (PEnumExtensions)pState;
|
|
||||||
|
|
||||||
if (pEnum != NULL && pEnum->pResponse != NULL && pData != NULL)
|
|
||||||
{
|
|
||||||
PEXTENSION pExt = (PEXTENSION)pData;
|
|
||||||
if (pExt->name[0] != '\0' && pEnum->lpExtensionName != NULL && strcmp(pExt->name, pEnum->lpExtensionName) == 0)
|
|
||||||
{
|
|
||||||
dprintf("[LISTEXT] Found extension: %s", pExt->name);
|
|
||||||
for (Command* command = pExt->start; command != pExt->end; command = command->next)
|
|
||||||
{
|
|
||||||
packet_add_tlv_string(pEnum->pResponse, TLV_TYPE_STRING, command->method);
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
DWORD request_core_enumextcmd(Remote* pRemote, Packet* pPacket)
|
|
||||||
{
|
|
||||||
Packet* pResponse = packet_create_response(pPacket);
|
|
||||||
|
|
||||||
if (pResponse != NULL)
|
|
||||||
{
|
|
||||||
EnumExtensions enumExt;
|
|
||||||
enumExt.pResponse = pResponse;
|
|
||||||
enumExt.lpExtensionName = packet_get_tlv_value_string(pPacket, TLV_TYPE_STRING);
|
|
||||||
|
|
||||||
dprintf("[LISTEXTCMD] Listing extension commands for %s ...", enumExt.lpExtensionName);
|
|
||||||
// Start by enumerating the names of the extensions
|
|
||||||
BOOL bResult = list_enumerate(gExtensionList, ext_cmd_callback, &enumExt);
|
|
||||||
|
|
||||||
packet_add_tlv_uint(pResponse, TLV_TYPE_RESULT, ERROR_SUCCESS);
|
|
||||||
packet_transmit(pRemote, pResponse, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
DWORD initialise_extension(HMODULE hLibrary, BOOL bLibLoadedReflectivly, Remote* pRemote, Packet* pResponse, Command* pFirstCommand)
|
DWORD initialise_extension(HMODULE hLibrary, BOOL bLibLoadedReflectivly, Remote* pRemote, Packet* pResponse, Command* pFirstCommand)
|
||||||
{
|
{
|
||||||
DWORD dwResult = ERROR_OUTOFMEMORY;
|
DWORD dwResult = ERROR_OUTOFMEMORY;
|
||||||
@ -129,6 +81,8 @@ DWORD initialise_extension(HMODULE hLibrary, BOOL bLibLoadedReflectivly, Remote*
|
|||||||
return dwResult;
|
return dwResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* core_loadlib
|
* core_loadlib
|
||||||
* ------------
|
* ------------
|
||||||
|
@ -9,7 +9,7 @@ CFLAGS+= -I../../source/extensions/stdapi/server
|
|||||||
objects = \
|
objects = \
|
||||||
server/fs/dir.o \
|
server/fs/dir.o \
|
||||||
server/fs/file.o \
|
server/fs/file.o \
|
||||||
server/fs/fs_util.o \
|
server/fs/fs_posix.o \
|
||||||
server/general.o \
|
server/general.o \
|
||||||
server/net/config/interface.o \
|
server/net/config/interface.o \
|
||||||
server/net/config/route.o \
|
server/net/config/route.o \
|
||||||
|
@ -633,7 +633,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho
|
|||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\source\extensions\stdapi\server\fs\dir.c" />
|
<ClCompile Include="..\..\source\extensions\stdapi\server\fs\dir.c" />
|
||||||
<ClCompile Include="..\..\source\extensions\stdapi\server\fs\file.c" />
|
<ClCompile Include="..\..\source\extensions\stdapi\server\fs\file.c" />
|
||||||
<ClCompile Include="..\..\source\extensions\stdapi\server\fs\fs_util.c" />
|
<ClCompile Include="..\..\source\extensions\stdapi\server\fs\fs_win.c" />
|
||||||
<ClCompile Include="..\..\source\extensions\stdapi\server\fs\search.c" />
|
<ClCompile Include="..\..\source\extensions\stdapi\server\fs\search.c" />
|
||||||
<ClCompile Include="..\..\source\extensions\stdapi\server\net\net.c" />
|
<ClCompile Include="..\..\source\extensions\stdapi\server\net\net.c" />
|
||||||
<ClCompile Include="..\..\source\extensions\stdapi\server\net\config\interface.c" />
|
<ClCompile Include="..\..\source\extensions\stdapi\server\net\config\interface.c" />
|
||||||
@ -687,6 +687,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho
|
|||||||
<ClInclude Include="..\..\source\extensions\stdapi\server\webcam\bmp2jpeg.h" />
|
<ClInclude Include="..\..\source\extensions\stdapi\server\webcam\bmp2jpeg.h" />
|
||||||
<ClInclude Include="..\..\source\extensions\stdapi\server\webcam\webcam.h" />
|
<ClInclude Include="..\..\source\extensions\stdapi\server\webcam\webcam.h" />
|
||||||
<ClInclude Include="..\..\source\extensions\stdapi\server\fs\fs.h" />
|
<ClInclude Include="..\..\source\extensions\stdapi\server\fs\fs.h" />
|
||||||
|
<ClInclude Include="..\..\source\extensions\stdapi\server\fs\fs_local.h" />
|
||||||
<ClInclude Include="..\..\source\extensions\stdapi\server\fs\search.h" />
|
<ClInclude Include="..\..\source\extensions\stdapi\server\fs\search.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user