Compare commits
2 commits
4c6087fe9d
...
53cc2a08ce
Author | SHA1 | Date | |
---|---|---|---|
53cc2a08ce | |||
9d71f33432 |
4 changed files with 141 additions and 133 deletions
|
@ -12,7 +12,7 @@ endif()
|
|||
project ("shell-server")
|
||||
|
||||
# Добавьте источник в исполняемый файл этого проекта.
|
||||
add_executable (shell-server "main.c" "server.c" "server.h")
|
||||
add_executable (shell-server "main.c" "server.c" "server.h" "client.c" "client.h")
|
||||
|
||||
if (CMAKE_VERSION VERSION_GREATER 3.12)
|
||||
set_property(TARGET shell-server PROPERTY CXX_STANDARD 20)
|
||||
|
|
35
main.c
35
main.c
|
@ -3,31 +3,38 @@
|
|||
|
||||
#include "server.h"
|
||||
|
||||
void PrintHelpMessage() {
|
||||
printf("Usage error: I know 3 arguments \n\t\"install\"\n\t\"delete\"\n\t\"app\"\n");
|
||||
}
|
||||
|
||||
int _tmain(int argc, TCHAR *argv[]) {
|
||||
printf("\n->Start of parent execution.\n");
|
||||
int _tmain(int argc, char *argv[]) {
|
||||
if (argc == 2) {
|
||||
if (lstrcmpi(argv[1], TEXT("-c")) == 0) {
|
||||
return 0;
|
||||
}
|
||||
else if (lstrcmpi(argv[1], TEXT("-s")) == 0) {
|
||||
if (lstrcmpi(argv[1], TEXT("-s")) == 0) {
|
||||
StartShellServer();
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
PrintHelpMessage();
|
||||
return -1;
|
||||
goto help_message;
|
||||
}
|
||||
|
||||
}
|
||||
else if (argc == 3) {
|
||||
if (lstrcmpi(argv[1], TEXT("-c")) == 0) {
|
||||
StartShellClient(argv[2]);
|
||||
return 0;
|
||||
}
|
||||
// TODO: implement service
|
||||
else if (lstrcmpi(argv[1], TEXT("-s")) == 0 && lstrcmpi(argv[2], TEXT("-service")) == 0) {
|
||||
// CreateService
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
goto help_message;
|
||||
}
|
||||
}
|
||||
else {
|
||||
PrintHelpMessage();
|
||||
return -1;
|
||||
goto help_message;
|
||||
}
|
||||
|
||||
return 0;
|
||||
help_message:
|
||||
printf("Wrong usage\nUsage: %s [-c {remote ip} | -s [-service]]\n", argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
227
server.c
227
server.c
|
@ -1,77 +1,32 @@
|
|||
#include "server.h"
|
||||
|
||||
#define BUFSIZE 4096
|
||||
#define DEFAULT_PORT "50113"
|
||||
#define DEFAULT_BUFLEN 512
|
||||
|
||||
// Handles for child process STDIN and STDOUT
|
||||
HANDLE g_hChildStd_IN_Rd = NULL;
|
||||
HANDLE g_hChildStd_IN_Wr = NULL;
|
||||
HANDLE g_hChildStd_OUT_Rd = NULL;
|
||||
HANDLE g_hChildStd_OUT_Wr = NULL;
|
||||
typedef struct PipeThreadInfo_t {
|
||||
HANDLE Pipe;
|
||||
SOCKET ClientSocket;
|
||||
} PipeThreadInfo;
|
||||
|
||||
SOCKET ClientSocket = INVALID_SOCKET;
|
||||
|
||||
//HANDLE g_hInputFile = NULL;
|
||||
void CreateChildProcess(HANDLE g_hChildStd_IN_Rd, HANDLE g_hChildStd_OUT_Wr);
|
||||
DWORD WINAPI WorkWithClient(LPVOID lpParam);
|
||||
DWORD WINAPI WriteToPipe(LPVOID lpParam);
|
||||
DWORD WINAPI ReadFromPipe(LPVOID lpParam);
|
||||
void ErrorExit(PCTSTR);
|
||||
|
||||
void StartShellServer() {
|
||||
printf("\n->Start of shell server execution.\n");
|
||||
|
||||
CreatePipes();
|
||||
CreateSocket();
|
||||
|
||||
// Create the child process.
|
||||
CreateChildProcess();
|
||||
|
||||
// TODO: split into threads
|
||||
WriteToPipe();
|
||||
// Read from pipe that is the standard output for child process.
|
||||
ReadFromPipe();
|
||||
|
||||
printf("\n->End of shell server execution.\n");
|
||||
|
||||
// The remaining open handles are cleaned up when this process terminates.
|
||||
// To avoid resource leaks in a larger application, close handles explicitly.
|
||||
|
||||
}
|
||||
|
||||
void CreatePipes() {
|
||||
SECURITY_ATTRIBUTES saAttr;
|
||||
|
||||
// Set the bInheritHandle flag so pipe handles are inherited.
|
||||
|
||||
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
saAttr.bInheritHandle = TRUE;
|
||||
saAttr.lpSecurityDescriptor = NULL;
|
||||
|
||||
// Create a pipe for the child process's STDOUT.
|
||||
|
||||
if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0))
|
||||
ErrorExit(TEXT("StdoutRd CreatePipe"));
|
||||
|
||||
// Ensure the read handle to the pipe for STDOUT is not inherited.
|
||||
|
||||
if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0))
|
||||
ErrorExit(TEXT("Stdout SetHandleInformation"));
|
||||
|
||||
// Create a pipe for the child process's STDIN.
|
||||
|
||||
if (!CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0))
|
||||
ErrorExit(TEXT("Stdin CreatePipe"));
|
||||
|
||||
// Ensure the write handle to the pipe for STDIN is not inherited.
|
||||
|
||||
if (!SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0))
|
||||
ErrorExit(TEXT("Stdin SetHandleInformation"));
|
||||
}
|
||||
|
||||
// TODO: to review
|
||||
void CreateSocket() {
|
||||
WSADATA wsaData;
|
||||
struct addrinfo* result = NULL, * ptr = NULL, hints;
|
||||
int iResult;
|
||||
|
||||
SOCKET ClientSocket = INVALID_SOCKET;
|
||||
SOCKET ListenSocket = INVALID_SOCKET;
|
||||
|
||||
int iResult;
|
||||
/*
|
||||
* Initialize listening socket
|
||||
*/
|
||||
|
||||
// Initialize Winsock
|
||||
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
|
||||
|
@ -125,22 +80,87 @@ void CreateSocket() {
|
|||
return 1;
|
||||
}
|
||||
|
||||
// Accepting a connection
|
||||
ClientSocket = INVALID_SOCKET;
|
||||
/*
|
||||
* Process client connection
|
||||
*/
|
||||
for (;;) {
|
||||
// Accepting a client connection
|
||||
ClientSocket = INVALID_SOCKET;
|
||||
|
||||
// Accept a client socket
|
||||
ClientSocket = accept(ListenSocket, NULL, NULL);
|
||||
if (ClientSocket == INVALID_SOCKET) {
|
||||
printf("accept failed: %d\n", WSAGetLastError());
|
||||
closesocket(ListenSocket);
|
||||
WSACleanup();
|
||||
return 1;
|
||||
ClientSocket = accept(ListenSocket, NULL, NULL);
|
||||
if (ClientSocket == INVALID_SOCKET) {
|
||||
printf("accept failed: %d\n", WSAGetLastError());
|
||||
break;
|
||||
}
|
||||
printf("Client connected\n");
|
||||
// Create separate thread to process client connection
|
||||
CreateThread(NULL, 0, WorkWithClient, ClientSocket, 0, NULL);
|
||||
}
|
||||
// No longer needed
|
||||
|
||||
/*
|
||||
* Finalization
|
||||
*/
|
||||
// TODO: properly close all handles
|
||||
closesocket(ListenSocket);
|
||||
WSACleanup();
|
||||
}
|
||||
|
||||
void CreateChildProcess()
|
||||
DWORD WINAPI WorkWithClient(LPVOID lpParam) {
|
||||
/*
|
||||
* Client variables
|
||||
*/
|
||||
// Pipe handles for child STDIN/STDOUT
|
||||
HANDLE g_hChildStd_IN_Rd = NULL;
|
||||
HANDLE g_hChildStd_IN_Wr = NULL;
|
||||
HANDLE g_hChildStd_OUT_Rd = NULL;
|
||||
HANDLE g_hChildStd_OUT_Wr = NULL;
|
||||
|
||||
SECURITY_ATTRIBUTES saAttr;
|
||||
HANDLE PipeThreads[2];
|
||||
|
||||
SOCKET ClientSocket = (SOCKET)lpParam;
|
||||
|
||||
/*
|
||||
* Initialize pipes
|
||||
*/
|
||||
// Set the bInheritHandle flag so pipe handles are inherited.
|
||||
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
saAttr.bInheritHandle = TRUE;
|
||||
saAttr.lpSecurityDescriptor = NULL;
|
||||
|
||||
// Create a pipe for the child process's STDOUT.
|
||||
if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0))
|
||||
ErrorExit(TEXT("StdoutRd CreatePipe"));
|
||||
|
||||
// Ensure the read handle to the pipe for STDOUT is not inherited.
|
||||
if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0))
|
||||
ErrorExit(TEXT("Stdout SetHandleInformation"));
|
||||
|
||||
// Create a pipe for the child process's STDIN.
|
||||
if (!CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0))
|
||||
ErrorExit(TEXT("Stdin CreatePipe"));
|
||||
|
||||
// Ensure the write handle to the pipe for STDIN is not inherited.
|
||||
if (!SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0))
|
||||
ErrorExit(TEXT("Stdin SetHandleInformation"));
|
||||
|
||||
/*
|
||||
* Create child process cmd.exe
|
||||
*/
|
||||
CreateChildProcess(g_hChildStd_IN_Rd, g_hChildStd_OUT_Wr);
|
||||
|
||||
// Create threads for STDIN/STDOUT
|
||||
PipeThreadInfo WriteThreadInfo = { g_hChildStd_IN_Wr, ClientSocket };
|
||||
PipeThreadInfo ReadThreadInfo = { g_hChildStd_OUT_Rd, ClientSocket };
|
||||
PipeThreads[0] = CreateThread(NULL, 0, WriteToPipe, &WriteThreadInfo, 0, NULL);
|
||||
PipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &ReadThreadInfo, 0, NULL);
|
||||
|
||||
WaitForMultipleObjects(2, PipeThreads, TRUE, INFINITE);
|
||||
|
||||
printf("\n->Client disconnected.\n");
|
||||
}
|
||||
|
||||
void CreateChildProcess(HANDLE g_hChildStd_IN_Rd, HANDLE g_hChildStd_OUT_Wr)
|
||||
// Create a child process that uses the previously created pipes for STDIN and STDOUT.
|
||||
{
|
||||
TCHAR szCmdline[] = TEXT("C:\\Windows\\System32\\cmd.exe");
|
||||
|
@ -195,36 +215,31 @@ void CreateChildProcess()
|
|||
}
|
||||
}
|
||||
|
||||
void WriteToPipe(void)
|
||||
|
||||
// Read from a file and write its contents to the pipe for the child's STDIN.
|
||||
// Stop when there is no more data.
|
||||
DWORD WINAPI WriteToPipe(LPVOID lpParam)
|
||||
{
|
||||
DWORD dwRead, dwWritten;
|
||||
//CHAR chBuf[BUFSIZE] = "dir\r\n";
|
||||
BOOL bSuccess = FALSE;
|
||||
int i = 0;
|
||||
|
||||
SOCKET ClientSocket = ((PipeThreadInfo*)lpParam)->ClientSocket;
|
||||
HANDLE g_hChildStd_IN_Wr = ((PipeThreadInfo*)lpParam)->Pipe;
|
||||
|
||||
char recvbuf[DEFAULT_BUFLEN];
|
||||
int iResult, iSendResult;
|
||||
int recvbuflen = DEFAULT_BUFLEN;
|
||||
|
||||
|
||||
// Change codepage to UTF-8
|
||||
//CHAR chcpCommand[] = "chcp 65001\n";
|
||||
//bSuccess = WriteFile(g_hChildStd_IN_Wr, chcpCommand, strlen(chcpCommand), &dwWritten, NULL);
|
||||
//if (!bSuccess) goto WriteToPipe_end;
|
||||
|
||||
do
|
||||
{
|
||||
iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
|
||||
if (iResult > 0) {
|
||||
printf("Bytes received: %d\n", iResult);
|
||||
|
||||
// Echo the buffer back to the sender
|
||||
iSendResult = send(ClientSocket, recvbuf, iResult, 0);
|
||||
if (iSendResult == SOCKET_ERROR) {
|
||||
printf("send failed: %d\n", WSAGetLastError());
|
||||
closesocket(ClientSocket);
|
||||
WSACleanup();
|
||||
return 1;
|
||||
}
|
||||
printf("Bytes sent: %d\n", iSendResult);
|
||||
bSuccess = WriteFile(g_hChildStd_IN_Wr, recvbuf, iResult, &dwWritten, NULL);
|
||||
if (!bSuccess) break;
|
||||
printf("Received command: %s\n");
|
||||
}
|
||||
else if (iResult == 0)
|
||||
printf("Connection closing...\n");
|
||||
|
@ -234,40 +249,34 @@ void WriteToPipe(void)
|
|||
WSACleanup();
|
||||
return 1;
|
||||
}
|
||||
|
||||
//dwRead = strlen(chBuf) + 1;
|
||||
bSuccess = WriteFile(g_hChildStd_IN_Wr, recvbuf, iResult, &dwWritten, NULL);
|
||||
if (!bSuccess) break;
|
||||
//break;
|
||||
//dwRead = strlen(chBuf) + 1;
|
||||
//bSuccess = WriteFile(g_hChildStd_IN_Wr, chBuf, dwRead, &dwWritten, NULL);
|
||||
//if (!bSuccess) break;
|
||||
ReadFromPipe();
|
||||
} while (iResult > 0);
|
||||
|
||||
// Close the pipe handle so the child process stops reading.
|
||||
|
||||
WriteToPipe_end:
|
||||
// Closing STDIN => cmd.exe exit
|
||||
if (!CloseHandle(g_hChildStd_IN_Wr))
|
||||
ErrorExit(TEXT("StdInWr CloseHandle"));
|
||||
}
|
||||
|
||||
void ReadFromPipe(void)
|
||||
|
||||
// Read output from the child process's pipe for STDOUT
|
||||
// and write to the parent process's pipe for STDOUT.
|
||||
// Stop when there is no more data.
|
||||
DWORD WINAPI ReadFromPipe(LPVOID lpParam)
|
||||
{
|
||||
DWORD dwRead, dwWritten;
|
||||
CHAR chBuf[BUFSIZE];
|
||||
DWORD dwRead;
|
||||
CHAR chBuf[BUFSIZE + 1];
|
||||
|
||||
BOOL bSuccess = FALSE;
|
||||
HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
//HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
SOCKET ClientSocket = ((PipeThreadInfo*)lpParam)->ClientSocket;
|
||||
HANDLE g_hChildStd_OUT_Rd = ((PipeThreadInfo*)lpParam)->Pipe;
|
||||
|
||||
int iSendResult;
|
||||
|
||||
|
||||
for (;;)
|
||||
{
|
||||
bSuccess = ReadFile(g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL);
|
||||
if (!bSuccess || dwRead == 0) break;
|
||||
printf("STDOUT: %s\n", chBuf);
|
||||
|
||||
chBuf[dwRead] = '\0';
|
||||
|
||||
iSendResult = send(ClientSocket, chBuf, dwRead, 0);
|
||||
if (iSendResult == SOCKET_ERROR) {
|
||||
|
@ -276,11 +285,7 @@ void ReadFromPipe(void)
|
|||
WSACleanup();
|
||||
return 1;
|
||||
}
|
||||
// Write to console
|
||||
bSuccess = WriteFile(hParentStdOut, chBuf,
|
||||
dwRead, &dwWritten, NULL);
|
||||
if (!bSuccess) break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
10
server.h
10
server.h
|
@ -12,11 +12,7 @@
|
|||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
|
||||
#define DEFAULT_PORT "50113"
|
||||
|
||||
// Defined functions
|
||||
void StartShellServer();
|
||||
void CreatePipes();
|
||||
void CreateChildProcess(void);
|
||||
void WriteToPipe(void);
|
||||
void ReadFromPipe(void);
|
||||
void ErrorExit(PCTSTR);
|
||||
void CreateSocket();
|
||||
void StartShellServer();
|
Loading…
Reference in a new issue