Last active
November 22, 2021 03:21
-
-
Save phr34k/7539329 to your computer and use it in GitHub Desktop.
Ssh connection with file-serving via lib-ssh and NFSv2. Can be used connect to linux-based target machine from windows, on the same network though, and execute file-served files. Example usage: -t 192.168.0.1 -u user -p 22 -cwd "myworkingdirectoy" -cmd "./window". Intended for serving and executing cross compiled binaries.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <libssh/libssh.h> | |
#include <stdlib.h> | |
#include <stdio.h> | |
#include <errno.h> | |
#include <string.h> | |
#include <string> | |
#include <windows.h> | |
#include <map> | |
#include <vector> | |
#include <assert.h> | |
#include <windows.h> | |
#include <stdio.h> | |
#pragma comment(lib, "ws2_32.lib"); | |
//Command parameters | |
std::string arg_target = "192.168.0.1"; | |
std::string arg_user = "user"; | |
std::string arg_port = ""; | |
std::string arg_cwd = "."; | |
std::string arg_cmd = "echo no command was given \n ./main"; | |
//NFSv2 RPC Helper structures | |
enum RpcMountdProc | |
{ | |
Null = 0, | |
Mount = 1, | |
Dump = 2, | |
UMount = 3, | |
UMountAll = 4, | |
Export = 5 | |
}; | |
enum RpcNfsv2Proc | |
{ | |
GetAttribs = 1, | |
SetAttribs = 2, | |
Root = 3, | |
Lookup = 4, | |
ReadLink = 5, | |
Read = 6, | |
Write = 8, | |
Create = 9, | |
Remove = 10, | |
Rename = 11, | |
SymLink = 13, | |
MkDir = 14, | |
RmDir = 15, | |
ReadDir = 16, | |
StatFS = 17, | |
}; | |
enum RpcNfsv2Status | |
{ | |
NFS_OK = 0, | |
NFSERR_PERM = 1, | |
NFSERR_NOENT = 2, | |
NFSERR_IO = 5, | |
NFSERR_NXIO = 6, | |
NFSERR_ACCES = 13, | |
NFSERR_EXIST = 17, | |
NFSERR_NODEV = 19, | |
NFSERR_NOTDIR = 20, | |
NFSERR_ISDIR = 21, | |
NFSERR_FBIG = 27, | |
NFSERR_NOSPC = 28, | |
NFSERR_ROFS = 30, | |
NFSERR_NAMETOOLONG = 63, | |
NFSERR_NOTEMPTY = 66, | |
NFSERR_DQUOT = 69, | |
NFSERR_STALE = 70, | |
NFSERR_WFLUSG = 99 | |
}; | |
struct RpcFileHandle | |
{ | |
unsigned int index; | |
RpcFileHandle(unsigned int handle) | |
{ | |
index = handle; | |
} | |
bool operator<(const RpcFileHandle& r) const { return index < r.index; } | |
}; | |
struct RpcFileInfo | |
{ | |
std::string path; | |
RpcFileInfo() {} | |
RpcFileInfo(const std::string& Path) | |
{ | |
path = Path; | |
} | |
RpcFileInfo(const RpcFileInfo& f ) | |
{ | |
path = f.path; | |
} | |
}; | |
struct RpcFileTime | |
{ | |
unsigned int sec; | |
unsigned int usec; | |
RpcFileTime() : sec(0), usec(0) {} | |
RpcFileTime(const FILETIME& f) | |
{ | |
LARGE_INTEGER date, adjust; | |
date.LowPart = f.dwLowDateTime; | |
date.HighPart = f.dwHighDateTime; | |
adjust.QuadPart = 11644473600000 * 10000; | |
date.QuadPart -= adjust.QuadPart; | |
sec = (unsigned int)(date.QuadPart / 10000000); | |
usec = 0; | |
} | |
}; | |
struct RpcFileAttributes | |
{ | |
enum ftype | |
{ | |
NFNON = 0, | |
NFREG = 1, | |
NFDIR = 2, | |
NFBLK = 3, | |
NFCHR = 4, | |
NFLNK = 5 | |
}; | |
enum modes | |
{ | |
DIR = 16384, | |
CHR = 8192, | |
BLK = 24576, | |
REG = 32768, | |
LNK = 40960, | |
NON = 49152, | |
SUID = 2048, | |
SGID = 1024, | |
SWAP = 512, | |
ROWN = 256, | |
WOWN = 128, | |
XOWN = 64, | |
RGRP = 32, | |
WGRP = 16, | |
XGRP = 8, | |
ROTH = 4, | |
WOTH = 2, | |
XOTH = 1 | |
}; | |
ftype type; | |
unsigned int mode; | |
unsigned int nlink; | |
unsigned int uid; | |
unsigned int gid; | |
unsigned int size; | |
unsigned int blocksize; | |
unsigned int rdev; | |
unsigned int blocks; | |
unsigned int fsid; | |
unsigned int fileid; | |
RpcFileTime atime; | |
RpcFileTime mtime; | |
RpcFileAttributes() | |
{ | |
type = NFNON; | |
mode = XOWN | XGRP | XOTH | ROWN | RGRP | ROTH; | |
nlink = 1; | |
uid = 0; | |
gid = 0; | |
size = 0; | |
blocksize = 0; | |
rdev = 0; | |
blocks = 0; | |
fsid = 1; | |
fileid = 0; | |
} | |
}; | |
struct RpcDirectoryEntry | |
{ | |
unsigned int fileid; | |
const char* filename; | |
unsigned int cookie; | |
RpcDirectoryEntry( const RpcFileHandle& handle, const char* filename, | |
unsigned int cookie) | |
{ | |
this->fileid = handle.index; | |
this->filename = filename; | |
this->cookie = cookie; | |
} | |
}; | |
class RpcReader | |
{ | |
unsigned char* _data; | |
unsigned int _offset; | |
unsigned int _size; | |
public: | |
RpcReader(unsigned char* data, int size) | |
{ | |
_data = data; | |
_offset = 0; | |
_size = size; | |
} | |
unsigned int read_uint32() | |
{ | |
unsigned int v = 0; | |
v |= static_cast<unsigned int>(_data[_offset + 0]) << 24; | |
v |= static_cast<unsigned int>(_data[_offset + 1]) << 16; | |
v |= static_cast<unsigned int>(_data[_offset + 2]) << 8; | |
v |= static_cast<unsigned int>(_data[_offset + 3]) << 0; | |
_offset += 4; | |
return v; | |
} | |
RpcFileHandle read_rcphandle() | |
{ | |
unsigned int index = read_uint32(); | |
read_uint32(); | |
read_uint32(); | |
read_uint32(); | |
read_uint32(); | |
read_uint32(); | |
read_uint32(); | |
read_uint32(); | |
RpcFileHandle d( index ); | |
return d; | |
} | |
std::string read_string() | |
{ | |
unsigned int length = read_uint32(); | |
std::string dirPath = ""; | |
for (unsigned int i = 0; i < length; ++i) | |
dirPath.push_back(read_char()); | |
return dirPath; | |
} | |
char read_char() | |
{ | |
char s = static_cast<char>( _data[_offset + 0] ); | |
_offset += 1; | |
return s; | |
} | |
char* data() | |
{ | |
return (char*)&_data[0]; | |
} | |
int size() | |
{ | |
return _size; | |
} | |
void skip( int size ) | |
{ | |
_offset += size; | |
} | |
}; | |
class RpcWriter | |
{ | |
std::vector<unsigned char> _data; | |
unsigned int _offset; | |
unsigned int _size; | |
public: | |
RpcWriter() | |
{ | |
_data.reserve(2048 * 4); | |
_data.resize(2048 * 4); | |
_offset = 0; | |
_size = 0; | |
} | |
void write_uint32( unsigned int a ) | |
{ | |
_data.resize( _size + 4 ); | |
_data[_offset + 0] = (unsigned char)( (a >> 24) & 0xFF); | |
_data[_offset + 1] = (unsigned char)( (a >> 16) & 0xFF); | |
_data[_offset + 2] = (unsigned char)( (a >> 8) & 0xFF); | |
_data[_offset + 3] = (unsigned char)( (a >> 0) & 0xFF); | |
_offset += 4; | |
_size += 4; | |
assert( (_offset % 4) == 0 ); | |
} | |
void write_rcphandle( const RpcFileHandle& handle ) | |
{ | |
write_uint32(handle.index); | |
write_uint32(0); | |
write_uint32(0); | |
write_uint32(0); | |
write_uint32(0); | |
write_uint32(0); | |
write_uint32(0); | |
write_uint32(0); | |
} | |
void write_rcptime( const RpcFileTime& time ) | |
{ | |
write_uint32(time.sec); | |
write_uint32(time.usec); | |
} | |
void write_rcpattributes( const RpcFileAttributes& attr ) | |
{ | |
write_uint32(attr.type); | |
write_uint32(attr.mode); | |
write_uint32(attr.nlink); | |
write_uint32(attr.uid); | |
write_uint32(attr.gid); | |
write_uint32(attr.size); | |
write_uint32(attr.blocksize); | |
write_uint32(attr.rdev); | |
write_uint32(attr.blocks); | |
write_uint32(attr.fsid); | |
write_uint32(attr.fileid); | |
write_rcptime(attr.atime); | |
write_rcptime(attr.mtime); | |
write_rcptime(attr.mtime); | |
} | |
void write_entry( const RpcDirectoryEntry& e ) | |
{ | |
write_uint32( e.fileid ); | |
write_string( e.filename ); | |
write_uint32( e.cookie ); | |
} | |
void write_string(const char* s ) | |
{ | |
int length = strlen(s); | |
_data.resize( _size + (4 + length + 3) ); | |
//resize( _size); | |
int offset = _offset; | |
_offset += 4; | |
_size += 4; | |
const char* c = s; | |
while( *c != 0 ) | |
{ | |
_data[_offset++] = *c; | |
_size++; | |
c = c + 1; | |
} | |
if( (length % 4) != 0 ) | |
{ | |
for (int pad = 4 - (length % 4); pad != 0; --pad) | |
{ | |
_data[_offset++] = 0; | |
_size++; | |
} | |
} | |
_data[offset + 0] = (unsigned char)( (length >> 24) & 0xFF); | |
_data[offset + 1] = (unsigned char)( (length >> 16) & 0xFF); | |
_data[offset + 2] = (unsigned char)( (length >> 8) & 0xFF); | |
_data[offset + 3] = (unsigned char)( (length >> 0) & 0xFF); | |
assert( (_offset % 4) == 0 ); | |
} | |
unsigned char* write_unmanaged(unsigned int size) | |
{ | |
_data.resize( _size + 4 + 3); | |
_data[_offset + 0] = (unsigned char)( (size >> 24) & 0xFF); | |
_data[_offset + 1] = (unsigned char)( (size >> 16) & 0xFF); | |
_data[_offset + 2] = (unsigned char)( (size >> 8) & 0xFF); | |
_data[_offset + 3] = (unsigned char)( (size >> 0) & 0xFF); | |
_offset += 4; _size += 4; | |
_data.resize( _size + size + 3 ); | |
unsigned char* d = &_data[_offset]; | |
_size = _size + size; | |
_offset = _offset + size; | |
if( (size % 4) != 0 ) | |
{ | |
for (int pad = 4 - (size % 4); pad != 0; --pad) | |
{ | |
_data[_offset++] = 0; | |
_size++; | |
} | |
} | |
assert( (_offset % 4) == 0 ); | |
return d; | |
} | |
char* data() | |
{ | |
return (char*)&_data.front(); | |
} | |
int size() | |
{ | |
return _size; | |
} | |
void reset(int size) | |
{ | |
_size = size; | |
_offset = size; | |
} | |
}; | |
struct RpcCredentialsSkip | |
{ | |
RpcCredentialsSkip(RpcReader& rdr) | |
{ | |
unsigned flavor = rdr.read_uint32(); | |
unsigned length = rdr.read_uint32(); | |
rdr.skip(length); | |
} | |
}; | |
struct RpcVerificationSkip | |
{ | |
RpcVerificationSkip(RpcReader& rdr) | |
{ | |
unsigned flavor = rdr.read_uint32(); | |
unsigned length = rdr.read_uint32(); | |
rdr.skip(length); | |
} | |
}; | |
struct RpcAccept | |
{ | |
RpcAccept( RpcWriter& w, unsigned int xid, unsigned int acceptStatus) | |
{ | |
w.write_uint32(xid); | |
w.write_uint32(1); | |
w.write_uint32(0); | |
w.write_uint32(0); | |
w.write_uint32(0); | |
w.write_uint32(acceptStatus); | |
} | |
}; | |
struct RpcMismatch | |
{ | |
RpcMismatch( RpcWriter& w, unsigned int xid) | |
{ | |
w.write_uint32(xid); | |
w.write_uint32(1); | |
w.write_uint32(1); | |
w.write_uint32(0); | |
w.write_uint32(2); | |
w.write_uint32(2); | |
} | |
}; | |
//Global state | |
std::map<RpcFileHandle, RpcFileInfo> m_ReferenceTable; | |
unsigned int m_ReferenceKey = 2; | |
bool m_IsRunning = true; | |
HANDLE m_Event = 0; | |
//Working reverse tunnel example, make portmap compatible with ssh reverse tunnel. | |
int web_server(ssh_session session) | |
{ | |
int rc; | |
ssh_channel channel; | |
char buffer[256]; | |
int nbytes, nwritten; | |
char *helloworld = "" | |
"HTTP/1.1 200 OK\n" | |
"Content-Type: text/html\n" | |
"Content-Length: 113\n" | |
"\n" | |
"<html>\n" | |
" <head>\n" | |
" <title>Hello, World!</title>\n" | |
" </head>\n" | |
" <body>\n" | |
" <h1>Hello, World!</h1>\n" | |
" </body>\n" | |
"</html>\n"; | |
rc = ssh_forward_listen(session, NULL, 8080, NULL); | |
if (rc != SSH_OK) | |
{ | |
fprintf(stderr, "Error opening remote port: %s\n", | |
ssh_get_error(session)); | |
return rc; | |
} | |
channel = ssh_forward_accept(session, 60000); | |
if (channel == NULL) | |
{ | |
fprintf(stderr, "Error waiting for incoming connection: %s\n", | |
ssh_get_error(session)); | |
return SSH_ERROR; | |
} | |
while (1) | |
{ | |
nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0); | |
if (nbytes < 0) | |
{ | |
fprintf(stderr, "Error reading incoming data: %s\n", | |
ssh_get_error(session)); | |
ssh_channel_send_eof(channel); | |
ssh_channel_free(channel); | |
return SSH_ERROR; | |
} | |
if (strncmp(buffer, "GET /", 5)) continue; | |
nbytes = strlen(helloworld); | |
nwritten = ssh_channel_write(channel, helloworld, nbytes); | |
if (nwritten != nbytes) | |
{ | |
fprintf(stderr, "Error sending answer: %s\n", | |
ssh_get_error(session)); | |
ssh_channel_send_eof(channel); | |
ssh_channel_free(channel); | |
return SSH_ERROR; | |
} | |
ssh_blocking_flush(session, -1); | |
printf("Sent answer\n"); | |
break; | |
} | |
ssh_channel_send_eof(channel); | |
ssh_channel_free(channel); | |
return SSH_OK; | |
} | |
//Ssh utillity function to verify the host. | |
int verify_knownhost(ssh_session session) | |
{ | |
int state, hlen; | |
unsigned char *hash = NULL; | |
char *hexa; | |
char buf[10]; | |
state = ssh_is_server_known(session); | |
hlen = ssh_get_pubkey_hash(session, &hash); | |
if (hlen < 0) | |
return -1; | |
switch (state) | |
{ | |
case SSH_SERVER_KNOWN_OK: | |
break; /* ok */ | |
case SSH_SERVER_KNOWN_CHANGED: | |
fprintf(stderr, "Host key for server changed: it is now:\n"); | |
ssh_print_hexa("Public key hash", hash, hlen); | |
fprintf(stderr, "For security reasons, connection will be stopped\n"); | |
free(hash); | |
return -1; | |
case SSH_SERVER_FOUND_OTHER: | |
fprintf(stderr, "The host key for this server was not found but an other" | |
"type of key exists.\n"); | |
fprintf(stderr, "An attacker might change the default server key to" | |
"confuse your client into thinking the key does not exist\n"); | |
free(hash); | |
return -1; | |
case SSH_SERVER_FILE_NOT_FOUND: | |
fprintf(stderr, "Could not find known host file.\n"); | |
fprintf(stderr, "If you accept the host key here, the file will be" | |
"automatically created.\n"); | |
/* fallback to SSH_SERVER_NOT_KNOWN behavior */ | |
case SSH_SERVER_NOT_KNOWN: | |
hexa = ssh_get_hexa(hash, hlen); | |
fprintf(stderr,"The server is unknown. Do you trust the host key?\n"); | |
fprintf(stderr, "Public key hash: %s\n", hexa); | |
ssh_string_free_char(hexa); | |
if (fgets(buf, sizeof(buf), stdin) == NULL) | |
{ | |
ssh_string_free_char((char*)hash); | |
return -1; | |
} | |
if (strcmpi(buf, "yes\n") != 0) | |
{ | |
ssh_string_free_char((char*)hash); | |
return -1; | |
} | |
if (ssh_write_knownhost(session) < 0) | |
{ | |
fprintf(stderr, "Error %s\n", strerror(errno)); | |
ssh_string_free_char((char*)hash); | |
return -1; | |
} | |
break; | |
case SSH_SERVER_ERROR: | |
fprintf(stderr, "Error %s", ssh_get_error(session)); | |
ssh_string_free_char((char*)hash); | |
return -1; | |
} | |
ssh_string_free_char((char*)hash); | |
return 0; | |
} | |
//Ssh execute command statement, kill processes created by the previous process id, these are assumed | |
//to be working on from the NFS filesystem, and prevent unmounting the filesystem for a replacement. Remount | |
//the NFS directory (~/Desktop/home) to the connecting client (using remote ip of the ssh client). | |
int show_remote_dir(ssh_session session, ssh_channel channel) | |
{ | |
char buffer[256]; | |
unsigned int nbytes; | |
int rc; | |
std::string cmd; | |
cmd.append("pkill -TERM -P $(cat ~/.pid) \n kill -9 $(cat ~/.pid) \n echo $$ > ~/.pid \n DISPLAY=:0 \n export DISPLAY \n echo password | sudo -S umount -f ~/Desktop/home \n export DISPLAY \n echo password | sudo -S mount -t nfs -o vers=2 $(echo $SSH_CONNECTION | grep -oP \"^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\"): ~/Desktop/home \n cd Desktop/home \n"); | |
cmd.append( arg_cmd ); | |
cmd.append( "\n cd / \n echo password | sudo -S umount -f ~/Desktop/home " ); | |
rc = ssh_channel_request_exec(channel, cmd.c_str()); | |
if (rc != SSH_OK) | |
{ | |
return rc; | |
} | |
nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0); | |
while (nbytes > 0) | |
{ | |
if (fwrite(buffer, 1, nbytes, stdout) != nbytes) | |
{ | |
return SSH_ERROR; | |
} | |
nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0); | |
} | |
if (nbytes < 0) | |
{ | |
return SSH_ERROR; | |
} | |
nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 1); | |
while (nbytes > 0) | |
{ | |
if (fwrite(buffer, 1, nbytes, stdout) != nbytes) | |
{ | |
return SSH_ERROR; | |
} | |
nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 1); | |
} | |
if (nbytes < 0) | |
{ | |
return SSH_ERROR; | |
} | |
} | |
//Ssh utillity function to start a channel for show_remote_dir. | |
int show_remote_processes(ssh_session session) | |
{ | |
ssh_channel channel; | |
int rc; | |
channel = ssh_channel_new(session); | |
if (channel == NULL) | |
return SSH_ERROR; | |
rc = ssh_channel_open_session(channel); | |
if (rc != SSH_OK) | |
{ | |
ssh_channel_free(channel); | |
return rc; | |
} | |
//show_remote_processs_channel(session, channel); | |
rc = show_remote_dir(session, channel); | |
if (rc == SSH_OK) | |
{ | |
/* | |
rc = show_test(session, channel); | |
if (rc == SSH_OK) | |
{ | |
} | |
*/ | |
} | |
ssh_channel_close(channel); | |
ssh_channel_free(channel); | |
return SSH_OK; | |
} | |
//Portmap thread, we should probably setup a reverse tunnel so it's only exposed the target, rather than | |
//being globally available for every application, however this works. And ideally we should also setup | |
//udp hole punching, so the target machine can reach the host machine. Currently it's presumed they | |
//reside on the same network. | |
DWORD WINAPI portmap_thread( LPVOID lpParam ) | |
{ | |
int sockfd,n; | |
struct sockaddr_in servaddr,cliaddr; | |
int len; | |
char mesg[1000]; | |
sockfd=socket(AF_INET,SOCK_DGRAM,0); | |
memset(&servaddr,0, sizeof(servaddr)); | |
servaddr.sin_family = AF_INET; | |
servaddr.sin_addr.s_addr=htonl(INADDR_ANY); | |
servaddr.sin_port=htons(111); | |
bind(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr)); | |
for (;m_IsRunning;) | |
{ | |
const int progId = 100000; | |
len = sizeof(cliaddr); | |
n = recvfrom(sockfd,mesg,1000,0,(struct sockaddr *)&cliaddr,&len); | |
RpcReader rdr((unsigned char*)mesg, n); | |
unsigned int xid = rdr.read_uint32(); | |
unsigned int msg_type = rdr.read_uint32(); | |
unsigned int rpcvers = rdr.read_uint32(); | |
unsigned int prog = rdr.read_uint32(); | |
unsigned int vers = rdr.read_uint32(); | |
unsigned int proc = rdr.read_uint32(); | |
//printf("xid %08X msg_type %08X rpcvers %08X\r\n", xid, msg_type, rpcvers); | |
//printf("prog %08X vers %08X proc %08X\r\n", prog, vers, proc); | |
if( msg_type != 0 ) | |
{ | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 4); | |
sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
} | |
else if( rpcvers != 2 ) | |
{ | |
RpcWriter reply; | |
RpcMismatch type(reply, xid); | |
sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
} | |
else if( prog != progId ) | |
{ | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 2); | |
reply.write_uint32(100000); | |
reply.write_uint32(100000); | |
sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
} | |
else | |
{ | |
RpcCredentialsSkip cred(rdr); | |
RpcVerificationSkip verif(rdr); | |
if( proc == 3 ) | |
{ | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 0); | |
unsigned int portmap_prog = rdr.read_uint32(); | |
unsigned int portmap_vers = rdr.read_uint32(); | |
unsigned int portmap_prot = rdr.read_uint32(); | |
unsigned int portmap_port = rdr.read_uint32(); | |
/* | |
printf("prog:%08X, vers:%08X prot:%08X, port:%08X\r\n", | |
portmap_prog, portmap_vers, | |
portmap_prot, portmap_port); | |
*/ | |
unsigned int registeredPort = 0; | |
if( portmap_prot == 17 ) | |
{ | |
//mountd | |
if (portmap_prog == 100005 && portmap_vers == 1) | |
{ | |
registeredPort = 635; | |
} | |
//ntfsd | |
else if (portmap_prog == 100003 && portmap_vers == 2) | |
{ | |
registeredPort = 2049; | |
} | |
} | |
reply.write_uint32(registeredPort); | |
sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
} | |
else | |
{ | |
//Reply with proc unavailable | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 3); | |
sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
} | |
} | |
} | |
return 0; | |
} | |
//NFSv2 - nfsd UDP used to setup mounted access points and read data from the host machine. Currently we | |
//don't garbage collect, we presume this utillity is used for short lived sessions. | |
DWORD WINAPI nfs_thread( LPVOID lpParam ) | |
{ | |
int sockfd,n; | |
struct sockaddr_in servaddr,cliaddr; | |
int len; | |
char mesg[1000]; | |
sockfd=socket(AF_INET,SOCK_DGRAM,0); | |
memset(&servaddr,0, sizeof(servaddr)); | |
servaddr.sin_family = AF_INET; | |
servaddr.sin_addr.s_addr=htonl(INADDR_ANY); | |
servaddr.sin_port=htons(2049); | |
bind(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr)); | |
for (;m_IsRunning;) | |
{ | |
const int progId = 100003; | |
len = sizeof(cliaddr); | |
SetEvent(m_Event); | |
n = recvfrom(sockfd,mesg,1000,0,(struct sockaddr *)&cliaddr,&len); | |
if( m_IsRunning == false ) | |
continue; | |
ResetEvent(m_Event); | |
RpcReader rdr((unsigned char*)mesg, n); | |
unsigned int xid = rdr.read_uint32(); | |
unsigned int msg_type = rdr.read_uint32(); | |
unsigned int rpcvers = rdr.read_uint32(); | |
unsigned int prog = rdr.read_uint32(); | |
unsigned int vers = rdr.read_uint32(); | |
unsigned int proc = rdr.read_uint32(); | |
//printf("xid %08X msg_type %08X rpcvers %08X\r\n", xid, msg_type, rpcvers); | |
//printf("prog %08X vers %08X proc %08X\r\n", prog, vers, proc); | |
if( msg_type != 0 ) | |
{ | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 4); | |
sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
} | |
else if( rpcvers != 2 ) | |
{ | |
RpcWriter reply; | |
RpcMismatch type(reply, xid); | |
sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
} | |
else if( prog != progId ) | |
{ | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 2); | |
reply.write_uint32(progId); | |
reply.write_uint32(progId); | |
sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
} | |
else | |
{ | |
RpcCredentialsSkip cred(rdr); | |
RpcVerificationSkip verif(rdr); | |
if( proc == RpcMountdProc::Null ) | |
{ | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 0); | |
sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
} | |
else if( proc == RpcNfsv2Proc::GetAttribs ) | |
{ | |
RpcFileHandle fhandle = rdr.read_rcphandle(); | |
std::map<RpcFileHandle, RpcFileInfo>::iterator itt = m_ReferenceTable.find(fhandle); | |
if( itt == m_ReferenceTable.end() ) | |
{ | |
printf("GetAttribs: Illegal entry\r\n"); | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 0); | |
reply.write_uint32(RpcNfsv2Status::NFSERR_STALE); | |
int bytesSent = sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
if( bytesSent != reply.size() ) { | |
printf("error sending data %d %d\r\n", bytesSent, reply.size()); | |
} | |
} | |
else | |
{ | |
WIN32_FILE_ATTRIBUTE_DATA attributes; | |
BOOL succeeded = GetFileAttributesExA( itt->second.path.c_str(), GetFileExInfoStandard, &attributes); | |
ULARGE_INTEGER fileSize; | |
fileSize.LowPart = attributes.nFileSizeLow; | |
fileSize.HighPart = attributes.nFileSizeHigh; | |
if( succeeded == false || attributes.dwFileAttributes == INVALID_FILE_ATTRIBUTES ) | |
{ | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 0); | |
reply.write_uint32(RpcNfsv2Status::NFSERR_NOENT); | |
int bytesSent = sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
if( bytesSent != reply.size() ) { | |
printf("error sending data %d %d\r\n", bytesSent, reply.size()); | |
} | |
} | |
else | |
{ | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 0); | |
reply.write_uint32(RpcNfsv2Status::NFS_OK); | |
if( (attributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY ) | |
{ | |
RpcFileAttributes attribs; | |
attribs.type = RpcFileAttributes::NFDIR; | |
attribs.mode |= RpcFileAttributes::DIR; | |
attribs.size = 4096; | |
attribs.blocksize = 4096; | |
attribs.blocks = 8; | |
attribs.atime = RpcFileTime(attributes.ftLastAccessTime); | |
attribs.mtime = RpcFileTime(attributes.ftLastWriteTime); | |
attribs.fileid = fhandle.index; | |
reply.write_rcpattributes(attribs); | |
} | |
//TODO: symbolic links | |
else | |
{ | |
RpcFileAttributes attribs; | |
attribs.type = RpcFileAttributes::NFREG; | |
attribs.mode |= RpcFileAttributes::REG; | |
attribs.size = (unsigned int)fileSize.QuadPart; | |
attribs.blocksize = 4096; | |
attribs.blocks = (fileSize.QuadPart / 4096) + (4096 - (fileSize.QuadPart % 4096)); | |
attribs.atime = RpcFileTime(attributes.ftLastAccessTime); | |
attribs.mtime = RpcFileTime(attributes.ftLastWriteTime); | |
attribs.fileid = fhandle.index; | |
reply.write_rcpattributes(attribs); | |
} | |
int bytesSent = sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
if( bytesSent != reply.size() ) { | |
printf("error sending data %d %d\r\n", bytesSent, reply.size()); | |
} | |
} | |
} | |
} | |
else if( proc == RpcNfsv2Proc::SetAttribs ) | |
{ | |
printf("SetAttribs\r\n"); | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 0); | |
sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
} | |
else if( proc == RpcNfsv2Proc::Root ) | |
{ | |
printf("Root\r\n"); | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 0); | |
sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
} | |
else if( proc == RpcNfsv2Proc::Lookup ) | |
{ | |
RpcFileHandle fhandle = rdr.read_rcphandle(); | |
std::string entry = rdr.read_string(); | |
std::map<RpcFileHandle, RpcFileInfo>::iterator itt = m_ReferenceTable.find(fhandle); | |
if( itt == m_ReferenceTable.end() ) | |
{ | |
printf("Lookup: Illegal entry\r\n"); | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 0); | |
reply.write_uint32(RpcNfsv2Status::NFSERR_NOENT); | |
int bytesSent = sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
if( bytesSent != reply.size() ) { | |
printf("error sending data %d %d\r\n", bytesSent, reply.size()); | |
} | |
} | |
else | |
{ | |
std::string v = itt->second.path; | |
v.append( "\\" ); | |
v.append( entry.c_str() ); | |
/* | |
RpcFileHandle handle(1); | |
RpcFileInfo info(dirPath); | |
reply.write_uint32(0); | |
reply.write_rcphandle(handle); | |
*/ | |
bool found = false; | |
std::map<RpcFileHandle, RpcFileInfo>::iterator itt = m_ReferenceTable.begin(); | |
for( ; itt != m_ReferenceTable.end(); ++itt ) | |
{ | |
if( itt->second.path == v ) | |
{ | |
found = true; | |
break; | |
} | |
} | |
if( found ) | |
{ | |
WIN32_FILE_ATTRIBUTE_DATA attributes; | |
BOOL succeeded = GetFileAttributesExA( itt->second.path.c_str(), GetFileExInfoStandard, &attributes); | |
ULARGE_INTEGER fileSize; | |
fileSize.LowPart = attributes.nFileSizeLow; | |
fileSize.HighPart = attributes.nFileSizeHigh; | |
if( succeeded == false || attributes.dwFileAttributes == INVALID_FILE_ATTRIBUTES ) | |
{ | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 0); | |
reply.write_uint32(RpcNfsv2Status::NFSERR_NOENT); | |
int bytesSent = sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
if( bytesSent != reply.size() ) { | |
printf("error sending data %d %d\r\n", bytesSent, reply.size()); | |
} | |
} | |
else | |
{ | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 0); | |
reply.write_uint32(RpcNfsv2Status::NFS_OK); | |
if( (attributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY ) | |
{ | |
RpcFileAttributes attribs; | |
attribs.type = RpcFileAttributes::NFDIR; | |
attribs.mode |= RpcFileAttributes::DIR; | |
attribs.size = 4096; | |
attribs.blocksize = 4096; | |
attribs.blocks = 8; | |
attribs.atime = RpcFileTime(attributes.ftLastAccessTime); | |
attribs.mtime = RpcFileTime(attributes.ftLastWriteTime); | |
attribs.fileid = itt->first.index; | |
reply.write_rcphandle( itt->first ); | |
reply.write_rcpattributes(attribs); | |
} | |
//TODO: symbolic links | |
else | |
{ | |
RpcFileAttributes attribs; | |
attribs.type = RpcFileAttributes::NFREG; | |
attribs.mode |= RpcFileAttributes::REG; | |
attribs.size = (unsigned int)fileSize.QuadPart; | |
attribs.blocksize = 4096; | |
attribs.blocks = (fileSize.QuadPart / 4096) + (4096 - (fileSize.QuadPart % 4096)); | |
attribs.atime = RpcFileTime(attributes.ftLastAccessTime); | |
attribs.mtime = RpcFileTime(attributes.ftLastWriteTime); | |
attribs.fileid = itt->first.index; | |
reply.write_rcphandle( itt->first ); | |
reply.write_rcpattributes(attribs); | |
} | |
int bytesSent = sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
if( bytesSent != reply.size() ) { | |
printf("error sending data %d %d\r\n", bytesSent, reply.size()); | |
} | |
} | |
} | |
else | |
{ | |
for( int i =0; i < v.size(); ++i ) | |
if( v[i] == '/' ) | |
v[i] = '\\'; | |
WIN32_FILE_ATTRIBUTE_DATA attributes; | |
BOOL succeeded = GetFileAttributesExA( v.c_str(), GetFileExInfoStandard, &attributes); | |
ULARGE_INTEGER fileSize; | |
fileSize.LowPart = attributes.nFileSizeLow; | |
fileSize.HighPart = attributes.nFileSizeHigh; | |
if( succeeded == false || attributes.dwFileAttributes == INVALID_FILE_ATTRIBUTES ) | |
{ | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 0); | |
reply.write_uint32(RpcNfsv2Status::NFSERR_NOENT); | |
int bytesSent = sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
if( bytesSent != reply.size() ) { | |
printf("error sending data %d %d\r\n", bytesSent, reply.size()); | |
} | |
} | |
else | |
{ | |
unsigned int newId = m_ReferenceKey++; | |
RpcFileHandle handle = RpcFileHandle(newId); | |
m_ReferenceTable[handle] = RpcFileInfo(v.c_str()); | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 0); | |
reply.write_uint32(RpcNfsv2Status::NFS_OK); | |
if( (attributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY ) | |
{ | |
RpcFileAttributes attribs; | |
attribs.type = RpcFileAttributes::NFDIR; | |
attribs.mode |= RpcFileAttributes::DIR; | |
attribs.size = 4096; | |
attribs.blocksize = 4096; | |
attribs.blocks = 8; | |
attribs.atime = RpcFileTime(attributes.ftLastAccessTime); | |
attribs.mtime = RpcFileTime(attributes.ftLastWriteTime); | |
attribs.fileid = handle.index; | |
reply.write_rcphandle( handle ); | |
reply.write_rcpattributes(attribs); | |
} | |
//TODO: symbolic links | |
else | |
{ | |
RpcFileAttributes attribs; | |
attribs.type = RpcFileAttributes::NFREG; | |
attribs.mode |= RpcFileAttributes::REG; | |
attribs.size = (unsigned int)fileSize.QuadPart; | |
attribs.blocksize = 4096; | |
attribs.blocks = (fileSize.QuadPart / 4096) + (4096 - (fileSize.QuadPart % 4096)); | |
attribs.atime = RpcFileTime(attributes.ftLastAccessTime); | |
attribs.mtime = RpcFileTime(attributes.ftLastWriteTime); | |
attribs.fileid = handle.index; | |
reply.write_rcphandle( handle ); | |
reply.write_rcpattributes(attribs); | |
} | |
int bytesSent = sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
if( bytesSent != reply.size() ) { | |
printf("error sending data %d %d\r\n", bytesSent, reply.size()); | |
} | |
} | |
} | |
} | |
} | |
else if( proc == RpcNfsv2Proc::ReadLink ) | |
{ | |
printf("ReadLink\r\n"); | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 0); | |
sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
} | |
else if( proc == RpcNfsv2Proc::Read ) | |
{ | |
RpcFileHandle fhandle = rdr.read_rcphandle(); | |
unsigned int offset = rdr.read_uint32(); | |
unsigned int count = rdr.read_uint32(); | |
unsigned int totalcount = rdr.read_uint32(); | |
std::map<RpcFileHandle, RpcFileInfo>::iterator itt = m_ReferenceTable.find(fhandle); | |
if( itt == m_ReferenceTable.end() ) | |
{ | |
printf("Read: Illegal entry\r\n"); | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 0); | |
reply.write_uint32(RpcNfsv2Status::NFSERR_NOENT); | |
int bytesSent = sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
if( bytesSent != reply.size() ) { | |
printf("error sending data %d %d\r\n", bytesSent, reply.size()); | |
} | |
} | |
else | |
{ | |
char buffer[4096]; DWORD bytesRead; | |
HANDLE hFile = CreateFileA(itt->second.path.c_str(), GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); | |
if( hFile == INVALID_HANDLE_VALUE ) | |
{ | |
printf("Read: failed to retieve disk-space\r\n"); | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 0); | |
reply.write_uint32(RpcNfsv2Status::NFSERR_IO); | |
int bytesSent = sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
if( bytesSent != reply.size() ) { | |
printf("error sending data %d %d\r\n", bytesSent, reply.size()); | |
} | |
} | |
else | |
{ | |
BY_HANDLE_FILE_INFORMATION info; | |
if( GetFileInformationByHandle(hFile, &info ) == false ) | |
{ | |
printf("Read: failed to information\r\n"); | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 0); | |
reply.write_uint32(RpcNfsv2Status::NFSERR_IO); | |
int bytesSent = sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
if( bytesSent != reply.size() ) { | |
printf("error sending data %d %d\r\n", bytesSent, reply.size()); | |
} | |
CloseHandle(hFile); | |
} | |
else | |
{ | |
ULARGE_INTEGER fileSize; | |
fileSize.HighPart = info.nFileSizeHigh; | |
fileSize.LowPart = info.nFileSizeLow; | |
RpcFileAttributes attribs; | |
attribs.type = RpcFileAttributes::NFREG; | |
attribs.mode |= RpcFileAttributes::REG; | |
attribs.size = (unsigned int)fileSize.QuadPart; | |
attribs.blocksize = 4096; | |
attribs.blocks = (fileSize.QuadPart / 4096) + (4096 - (fileSize.QuadPart % 4096)); | |
attribs.atime = RpcFileTime(info.ftLastAccessTime); | |
attribs.mtime = RpcFileTime(info.ftLastWriteTime); | |
attribs.fileid = fhandle.index; | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 0); | |
reply.write_uint32(RpcNfsv2Status::NFS_OK); | |
reply.write_rcpattributes(attribs); | |
unsigned char* d = reply.write_unmanaged(count); | |
SetFilePointer(hFile, offset, 0, FILE_BEGIN ); | |
ReadFile(hFile, d, count, &bytesRead, 0 ); | |
CloseHandle(hFile); | |
if( bytesRead == count ) | |
{ | |
int bytesSent = sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
if( bytesSent != reply.size() ) { | |
printf("error sending data %d %d\r\n", bytesSent, reply.size()); | |
} | |
} | |
else | |
{ | |
printf("Read: failed to retieve disk-space\r\n"); | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 0); | |
reply.write_uint32(RpcNfsv2Status::NFSERR_IO); | |
int bytesSent = sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
if( bytesSent != reply.size() ) { | |
printf("error sending data %d %d\r\n", bytesSent, reply.size()); | |
} | |
} | |
} | |
} | |
} | |
} | |
else if( proc == RpcNfsv2Proc::Write ) | |
{ | |
printf("Write\r\n"); | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 0); | |
sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
} | |
else if( proc == RpcNfsv2Proc::Create ) | |
{ | |
printf("Create\r\n"); | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 0); | |
sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
} | |
else if( proc == RpcNfsv2Proc::Remove ) | |
{ | |
printf("Remove\r\n"); | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 0); | |
sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
} | |
else if( proc == RpcNfsv2Proc::Rename ) | |
{ | |
printf("Rename\r\n"); | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 0); | |
sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
} | |
else if( proc == RpcNfsv2Proc::SymLink ) | |
{ | |
printf("SymLink\r\n"); | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 0); | |
sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
} | |
else if( proc == RpcNfsv2Proc::MkDir ) | |
{ | |
printf("MkDir\r\n"); | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 0); | |
sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
} | |
else if( proc == RpcNfsv2Proc::RmDir ) | |
{ | |
printf("RmDir\r\n"); | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 0); | |
sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
} | |
else if( proc == RpcNfsv2Proc::ReadDir ) | |
{ | |
RpcFileHandle fhandle = rdr.read_rcphandle(); | |
unsigned int cookie = rdr.read_uint32(); | |
unsigned int count = rdr.read_uint32(); | |
std::map<RpcFileHandle, RpcFileInfo>::iterator itt = m_ReferenceTable.find(fhandle); | |
if( itt == m_ReferenceTable.end() ) | |
{ | |
printf("ReadDir: Illegal entry\r\n"); | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 0); | |
reply.write_uint32(RpcNfsv2Status::NFSERR_NOENT); | |
int bytesSent = sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
if( bytesSent != reply.size() ) { | |
printf("error sending data %d %d\r\n", bytesSent, reply.size()); | |
} | |
} | |
else | |
{ | |
std::string v = itt->second.path; | |
v.append("\\*"); | |
WIN32_FIND_DATAA ffd; | |
HANDLE hFind = INVALID_HANDLE_VALUE; | |
hFind = FindFirstFileA(v.c_str(), &ffd); | |
if (hFind == INVALID_HANDLE_VALUE) | |
{ | |
DWORD v = ::GetFileAttributesA( itt->second.path.c_str() ); | |
if( v == INVALID_FILE_ATTRIBUTES ) | |
{ | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 0); | |
reply.write_uint32(RpcNfsv2Status::NFSERR_STALE); | |
int bytesSent = sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
if( bytesSent != reply.size() ) { | |
printf("error sending data %d %d\r\n", bytesSent, reply.size()); | |
} | |
continue; | |
} | |
else if( (v & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY) | |
{ | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 0); | |
reply.write_uint32(RpcNfsv2Status::NFSERR_NOTDIR); | |
int bytesSent = sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
if( bytesSent != reply.size() ) { | |
printf("error sending data %d %d\r\n", bytesSent, reply.size()); | |
} | |
continue; | |
} | |
else | |
{ | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 0); | |
reply.write_uint32(RpcNfsv2Status::NFSERR_ACCES); | |
int bytesSent = sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
if( bytesSent != reply.size() ) { | |
printf("error sending data %d %d\r\n", bytesSent, reply.size()); | |
} | |
continue; | |
} | |
} | |
else | |
{ | |
std::string realPath; | |
realPath.reserve(2048); | |
std::vector<RpcFileInfo*> entries; | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 0); | |
reply.write_uint32(RpcNfsv2Status::NFS_OK); | |
bool wasReset = false; | |
int file_count = 0; | |
int numberOfBytes = reply.size(); | |
do | |
{ | |
if( file_count >= cookie && file_count < (cookie + count) ) | |
{ | |
realPath = itt->second.path; | |
realPath.append("\\"); | |
realPath.append(ffd.cFileName); | |
RpcFileHandle handle(0); | |
bool requiredNewEntry = true; | |
std::map<RpcFileHandle, RpcFileInfo>::iterator itt = m_ReferenceTable.begin(); | |
for( ; itt != m_ReferenceTable.end(); ++itt ) | |
{ | |
if( itt->second.path == realPath ) | |
{ | |
handle = itt->first; | |
entries.push_back( & ((RpcFileInfo)itt->second)); | |
requiredNewEntry = false; | |
break; | |
} | |
} | |
if( requiredNewEntry == true ) | |
{ | |
unsigned int newId = m_ReferenceKey++; | |
handle = RpcFileHandle(newId); | |
m_ReferenceTable[handle] = RpcFileInfo( | |
realPath); | |
} | |
reply.write_uint32(1); | |
//reply.write_rcphandle(handle); | |
int reset = reply.size(); | |
RpcDirectoryEntry e(handle, ffd.cFileName, | |
file_count ); | |
reply.write_entry( e); | |
if( reply.size() > count ) | |
{ | |
wasReset = true; | |
reply.reset( reset); | |
break; | |
} | |
} | |
file_count = file_count + 1; | |
} | |
while (FindNextFileA(hFind, &ffd) != 0); | |
reply.write_uint32(0); | |
DWORD dwError = GetLastError(); | |
if (dwError == ERROR_NO_MORE_FILES && wasReset == false) | |
{ | |
reply.write_uint32(1); | |
} | |
else | |
{ | |
reply.write_uint32(0); | |
} | |
FindClose(hFind); | |
int bytesSent = sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
if( bytesSent != reply.size() ) { | |
printf("error sending data %d %d\r\n", bytesSent, reply.size()); | |
} | |
} | |
} | |
} | |
else if( proc == RpcNfsv2Proc::StatFS ) | |
{ | |
RpcFileHandle fhandle = rdr.read_rcphandle(); | |
std::map<RpcFileHandle, RpcFileInfo>::iterator itt = m_ReferenceTable.find(fhandle); | |
if( itt == m_ReferenceTable.end() ) | |
{ | |
printf("StatFS: Illegal entry\r\n"); | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 0); | |
reply.write_uint32(RpcNfsv2Status::NFSERR_NOENT); | |
int bytesSent = sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
if( bytesSent != reply.size() ) { | |
printf("error sending data %d %d\r\n", bytesSent, reply.size()); | |
} | |
} | |
else | |
{ | |
const unsigned int BLOCK_SIZE = 4096; | |
ULARGE_INTEGER FreeBytesAvailableToCaller, TotalNumberOfBytes, TotalNumberOfFreeBytes; | |
if( GetDiskFreeSpaceExA(itt->second.path.c_str(), &FreeBytesAvailableToCaller, | |
&TotalNumberOfBytes, &TotalNumberOfFreeBytes ) == false ) | |
{ | |
printf("StatFS: failed to retieve disk-space\r\n"); | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 0); | |
reply.write_uint32(RpcNfsv2Status::NFSERR_NOENT); | |
sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
} | |
else | |
{ | |
FreeBytesAvailableToCaller.QuadPart /= BLOCK_SIZE; | |
TotalNumberOfBytes.QuadPart /= BLOCK_SIZE; | |
TotalNumberOfFreeBytes.QuadPart /= BLOCK_SIZE; | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 0); | |
reply.write_uint32(RpcNfsv2Status::NFS_OK); | |
reply.write_uint32(BLOCK_SIZE); // tsize: optimum transfer size | |
reply.write_uint32(BLOCK_SIZE); // Block size of FS | |
reply.write_uint32(TotalNumberOfBytes.QuadPart); // Total # of blocks (of the above size) | |
reply.write_uint32(TotalNumberOfFreeBytes.QuadPart); // Free blocks | |
reply.write_uint32(FreeBytesAvailableToCaller.QuadPart); // Free blocks available to non-priv. users | |
int bytesSent = sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
if( bytesSent != reply.size() ) { | |
printf("error sending data %d %d\r\n", bytesSent, reply.size()); | |
} | |
} | |
} | |
} | |
else | |
{ | |
//Reply with proc unavailable | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 3); | |
sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
} | |
} | |
} | |
return 0; | |
} | |
//NFSv2 - mountd UDP used to resolved the mount access point. | |
DWORD WINAPI mountd_thread( LPVOID lpParam ) | |
{ | |
int sockfd,n; | |
struct sockaddr_in servaddr,cliaddr; | |
int len; | |
char mesg[1000]; | |
sockfd=socket(AF_INET,SOCK_DGRAM,0); | |
memset(&servaddr,0, sizeof(servaddr)); | |
servaddr.sin_family = AF_INET; | |
servaddr.sin_addr.s_addr=htonl(INADDR_ANY); | |
servaddr.sin_port=htons(635); | |
bind(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr)); | |
for (;m_IsRunning;) | |
{ | |
const int progId = 100005; | |
len = sizeof(cliaddr); | |
n = recvfrom(sockfd,mesg,1000,0,(struct sockaddr *)&cliaddr,&len); | |
RpcReader rdr((unsigned char*)mesg, n); | |
unsigned int xid = rdr.read_uint32(); | |
unsigned int msg_type = rdr.read_uint32(); | |
unsigned int rpcvers = rdr.read_uint32(); | |
unsigned int prog = rdr.read_uint32(); | |
unsigned int vers = rdr.read_uint32(); | |
unsigned int proc = rdr.read_uint32(); | |
//printf("xid %08X msg_type %08X rpcvers %08X\r\n", xid, msg_type, rpcvers); | |
//printf("prog %08X vers %08X proc %08X\r\n", prog, vers, proc); | |
if( msg_type != 0 ) | |
{ | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 4); | |
sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
} | |
else if( rpcvers != 2 ) | |
{ | |
RpcWriter reply; | |
RpcMismatch type(reply, xid); | |
sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
} | |
else if( prog != progId ) | |
{ | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 2); | |
reply.write_uint32(progId); | |
reply.write_uint32(progId); | |
sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
} | |
else | |
{ | |
RpcCredentialsSkip cred(rdr); | |
RpcVerificationSkip verif(rdr); | |
if( proc == RpcMountdProc::Null ) | |
{ | |
//Reply with proc unavailable | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 0); | |
sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
} | |
else if( proc == RpcMountdProc::Mount ) | |
{ | |
unsigned int length = rdr.read_uint32(); | |
std::string dirPath = ""; | |
for (unsigned int i = 0; i < length; ++i) | |
{ | |
char s = rdr.read_char(); | |
if( s == '/' ) s = '\\'; | |
dirPath.push_back(s); | |
} | |
if( dirPath.size() >= 2 && dirPath[1] == ':' ) | |
{ | |
} | |
else | |
{ | |
std::string t; | |
dirPath.swap(t); | |
dirPath = arg_cwd; | |
dirPath.append(t); | |
} | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 0); | |
DWORD dwAttrib = GetFileAttributesA(dirPath.c_str()); | |
if( dwAttrib == INVALID_FILE_ATTRIBUTES ) | |
{ | |
reply.write_uint32(2); | |
reply.write_uint32(0); | |
} | |
else | |
{ | |
RpcFileHandle handle(1); | |
RpcFileInfo info(dirPath); | |
m_ReferenceTable[handle] = info; | |
reply.write_uint32(0); | |
reply.write_rcphandle(handle); | |
} | |
sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
} | |
else if( proc == RpcMountdProc::Dump ) | |
{ | |
printf("Dump\r\n"); | |
//Reply with proc unavailable | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 3); | |
sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
} | |
else if( proc == RpcMountdProc::UMount ) | |
{ | |
unsigned int length = rdr.read_uint32(); | |
std::string dirPath = ""; | |
for (unsigned int i = 0; i < length; ++i) | |
dirPath.push_back(rdr.read_char()); | |
printf("Unmount %d:%s\r\n", length, dirPath.c_str()); | |
//Reply with proc unavailable | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 3); | |
sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
} | |
else if( proc == RpcMountdProc::UMountAll ) | |
{ | |
printf("UMountAll\r\n"); | |
//Reply with proc unavailable | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 3); | |
sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
} | |
else | |
{ | |
//Reply with proc unavailable | |
RpcWriter reply; | |
RpcAccept type(reply, xid, 3); | |
sendto(sockfd,reply.data(),reply.size(),0, | |
(struct sockaddr *)&cliaddr,sizeof(cliaddr)); | |
} | |
} | |
} | |
return 0; | |
} | |
int main() | |
{ | |
for( int i = 0; i < __argc; ++i ) | |
{ | |
if( stricmp( __argv[i], "-t") == 0 ) | |
{ | |
if( i + 1 < __argc ) | |
{ | |
arg_target = __argv[i + 1]; | |
i += 1; | |
} | |
else | |
{ | |
printf("missing argument"); | |
} | |
} | |
else if( stricmp( __argv[i], "-u") == 0 ) | |
{ | |
if( i + 1 < __argc ) | |
{ | |
arg_user = __argv[i + 1]; | |
i += 1; | |
} | |
else | |
{ | |
printf("missing argument"); | |
} | |
} | |
else if( stricmp( __argv[i], "-p") == 0 ) | |
{ | |
if( i + 1 < __argc ) | |
{ | |
arg_port = __argv[i + 1]; | |
i += 1; | |
} | |
else | |
{ | |
printf("missing argument"); | |
} | |
} | |
else if( stricmp( __argv[i], "-cwd") == 0 ) | |
{ | |
if( i + 1 < __argc ) | |
{ | |
arg_cwd = __argv[i + 1]; | |
i += 1; | |
} | |
else | |
{ | |
printf("missing argument"); | |
} | |
} | |
else if( stricmp( __argv[i], "-cmd") == 0 ) | |
{ | |
if( i + 1 < __argc ) | |
{ | |
arg_cmd = __argv[i + 1]; | |
i += 1; | |
} | |
else | |
{ | |
printf("missing argument"); | |
} | |
} | |
} | |
ssh_session my_ssh_session; | |
int rc; | |
my_ssh_session = ssh_new(); | |
if (my_ssh_session == NULL) | |
exit(-1); | |
rc = ssh_options_set(my_ssh_session, SSH_OPTIONS_HOST, arg_target.c_str()); | |
if (rc != SSH_OK) | |
{ | |
fprintf(stderr, "Error setting option host: %s\n", | |
ssh_get_error(my_ssh_session)); | |
exit(-1); | |
} | |
rc = ssh_options_set(my_ssh_session, SSH_OPTIONS_USER, arg_user.c_str()); | |
if (rc != SSH_OK) | |
{ | |
fprintf(stderr, "Error setting option user: %s\n", | |
ssh_get_error(my_ssh_session)); | |
exit(-1); | |
} | |
if( arg_port.empty() == false ) | |
{ | |
rc = ssh_options_set(my_ssh_session, SSH_OPTIONS_PORT, arg_port.c_str()); | |
if (rc != SSH_OK) | |
{ | |
fprintf(stderr, "Error setting option port: %s\n", | |
ssh_get_error(my_ssh_session)); | |
exit(-1); | |
} | |
} | |
if( arg_port.empty() == true ) | |
printf("Connecting to %s as user %s\r\n", arg_target.c_str(), arg_user.c_str() ); | |
else | |
printf("Connecting to %s:%s as user %s\r\n", arg_target.c_str(), arg_port.c_str(), arg_user.c_str() ); | |
rc = ssh_connect(my_ssh_session); | |
if (rc != SSH_OK) | |
{ | |
fprintf(stderr, "Error connecting to localhost: %s\n", | |
ssh_get_error(my_ssh_session)); | |
exit(-1); | |
} | |
printf("Connected to target\r\n"); | |
if (verify_knownhost(my_ssh_session) < 0) | |
{ | |
ssh_disconnect(my_ssh_session); | |
ssh_free(my_ssh_session); | |
exit(-1); | |
} | |
char path[2048]; | |
GetModuleFileNameA(0, path, 2048); | |
char* ds = strrchr(path, '\\') + 1; | |
int type; | |
strcpy(ds, "min.pub" ); ssh_string publickey = publickey_from_file(my_ssh_session, path, &type); | |
strcpy(ds, "min" ); ssh_private_key privatkey = privatekey_from_file(my_ssh_session,path, type,""); | |
rc = ssh_userauth_pubkey(my_ssh_session, NULL, publickey, privatkey ); | |
if (rc != SSH_OK) | |
{ | |
fprintf(stderr, "Authentication failed: %s\n", | |
ssh_get_error(my_ssh_session)); | |
} | |
//Prepare the NFS service before starting the script | |
DWORD threadId; | |
m_Event = CreateEvent(0, true, false, 0 ); | |
HANDLE webserver = CreateThread(0,0, &portmap_thread, 0, 0, &threadId); | |
HANDLE nfsserver = CreateThread(0,0, &nfs_thread, 0, 0, &threadId); | |
HANDLE mountdserver = CreateThread(0,0, &mountd_thread, 0, 0, &threadId); | |
//Execute the script | |
show_remote_processes(my_ssh_session); | |
//Close client (fire & forget style) | |
ssh_disconnect(my_ssh_session); | |
ssh_free(my_ssh_session); | |
Sleep(100); | |
//Wait for all server threads to close down. | |
m_IsRunning = false; | |
//WaitForSingleObject(webserver, INFINITE); | |
//WaitForSingleObject(mountdserver, INFINITE); | |
WaitForSingleObject(m_Event, INFINITE); | |
TerminateThread(webserver, 0 ); | |
TerminateThread(nfsserver, 0 ); | |
TerminateThread(mountdserver, 0 ); | |
CloseHandle(webserver); | |
CloseHandle(nfsserver); | |
CloseHandle(mountdserver); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment