1
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:
OJ 2015-03-20 11:59:28 +10:00
commit b7d6eba46b
16 changed files with 951 additions and 777 deletions

@ -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); 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_add_tlv_uint(response, TLV_TYPE_RESULT, result);
return packet_transmit(remote, response, NULL);
packet_transmit(remote, response, NULL);
if (directory)
free(directory);
return ERROR_SUCCESS;
} }
/* /*
* 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,8 +139,6 @@ DWORD request_fs_file_channel_open(Remote *remote, Packet *packet)
FileContext *ctx; FileContext *ctx;
LPSTR expandedFilePath = NULL; LPSTR expandedFilePath = NULL;
do
{
// Allocate a response // Allocate a response
response = packet_create_response(packet); response = packet_create_response(packet);
@ -145,38 +146,22 @@ DWORD request_fs_file_channel_open(Remote *remote, Packet *packet)
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;
break; goto out;
} }
// 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)
{
res = ERROR_INVALID_PARAMETER;
break;
}
// Expand the file path
if (!(expandedFilePath = fs_expand_path(filePath)))
{
res = ERROR_NOT_ENOUGH_MEMORY;
break;
}
if (!mode)
mode = "rb"; mode = "rb";
}
// Invalid file? res = fs_fopen(filePath, mode, &ctx->fd);
if (!(ctx->fd = fopen(expandedFilePath, mode))) if (res != ERROR_SUCCESS) {
{ goto out;
res = GetLastError();
break;
} }
memset(&chops, 0, sizeof(chops)); memset(&chops, 0, sizeof(chops));
@ -192,34 +177,26 @@ DWORD request_fs_file_channel_open(Remote *remote, Packet *packet)
// Check the response allocation & allocate a un-connected // Check the response allocation & allocate a un-connected
// channel // channel
if ((!response) || (!(newChannel = channel_create_pool(0, flags, &chops)))) if ((!response) || (!(newChannel = channel_create_pool(0, flags, &chops)))) {
{
res = ERROR_NOT_ENOUGH_MEMORY; res = ERROR_NOT_ENOUGH_MEMORY;
break; goto out;
} }
// Add the channel identifier to the response // Add the channel identifier to the response
packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, channel_get_id(newChannel));
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);
packet_add_tlv_uint(response, TLV_TYPE_RESULT, result); if (expanded == NULL) {
result = ERROR_NOT_ENOUGH_MEMORY;
goto out;
}
packet_transmit(remote, response, NULL); result = fs_stat(expanded, &buf);
if (0 == result) {
packet_add_tlv_raw(response, TLV_TYPE_STAT_BUF, &buf, sizeof(buf));
}
if (expanded)
free(expanded); free(expanded);
return result; out:
packet_add_tlv_uint(response, TLV_TYPE_RESULT, result);
return packet_transmit(remote, response, NULL);
} }
/* /*
* 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,138 +286,92 @@ 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) {
do
{
// No regular path?
if (!regular)
{
result = ERROR_INVALID_PARAMETER; result = ERROR_INVALID_PARAMETER;
break; goto out;
} }
// Allocate storage for the expanded path // Allocate storage for the expanded path
if (!(expanded = fs_expand_path(regular))) expanded = fs_expand_path(regular);
{ if (expanded == NULL) {
result = ERROR_NOT_ENOUGH_MEMORY; result = ERROR_NOT_ENOUGH_MEMORY;
break; goto out;
} }
packet_add_tlv_string(response, TLV_TYPE_FILE_PATH, expanded); 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); free(expanded);
out:
return ERROR_SUCCESS; packet_add_tlv_uint(response, TLV_TYPE_RESULT, result);
return packet_transmit(remote, response, NULL);
} }
/* /*
* 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); MD5_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 ) {
MD5_Update(&context, buff, ret); MD5_Update(&context, buff, ret);
} }
fclose(fd);
MD5_Final(hash, &context); MD5_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, 17);
} while(0); 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;
else if (!(expanded = fs_expand_path(filePath)))
result = ERROR_NOT_ENOUGH_MEMORY;
else
{
do {
SHA1_Init(&context); 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);
@ -468,24 +380,13 @@ DWORD request_fs_sha1(Remote *remote, Packet *packet)
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 packet_add_tlv_uint(response, TLV_TYPE_RESULT, result);
result = GetLastError(); return packet_transmit(remote, response, NULL);
packet_add_tlv_uint(response, TLV_TYPE_RESULT, result);
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

@ -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

@ -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
}
}

@ -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;
} }
if (extension->deinit)
{
extension->deinit(remote); 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>