1
mirror of https://github.com/rapid7/metasploit-payloads synced 2025-04-24 10:09:49 +02:00
Brent Cook 0d59fc7447 support building on newer Linux systems and Makefile cleanups
- try to share some bits between different makefiles, make modifying
   global compiler flags not such a huge pain.
 - directly specify we should be using the gold rather than bpf linker
 - make compiler output largely quiet except where we care - allow
   warnings to actually be visible
 - don't delete downloaded tarballs with --really-clean
 - add missing dependencies between libraries
   (--no-add-needed/--no-copy-dt-needed-entries causes lots of trouble)
 - update readme to show what to install to build

I made minimal changes to the loader makefile - it breaks easily.
 -Os prevents if from being able to load libc, for instance
2015-01-13 16:33:56 -06:00

189 lines
4.7 KiB
C

/*!
* @file unix_socket_server.c
* @brief Definitions for functions which provide an unix domain socket server.
* @details An implementation of an unix domain socket for local communications.
* Useful to communicate data between processes. It is used while in
* meterpreter migration to share the socket between the old and new
* host process.
*/
#include "unix_socket_server.h"
/*!
* @brief Creates an unix local domain socket and listens on it.
* @param s Pointer to the \c server_un to start.
* @param sock_path File path for the local domain socket.
* @returns Indication of success or failure.
* @retval 0 Indicates success.
*/
LONG
start_server(server_un *s, LPSTR sock_path) {
LONG flags;
if ((sock_path == NULL) || (s == NULL))
return ERROR_INVALID_PARAMETER;
s->timeout.tv_sec = DEFAULT_TIMEOUT; // Default timeout
s->timeout.tv_usec = 0;
dprintf("[UNIX SOCKET SERVER] Setting up the server");
if ((s->socket = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
dprintf("[UNIX SOCKET SERVER] socket failed");
return errno;
}
// Set up non blocking mode
// http://stackoverflow.com/questions/3444729/using-accept-and-select-at-the-same-time
FD_ZERO(&(s->set));
FD_SET(s->socket, &(s->set));
flags = fcntl(s->socket, F_GETFL, 0);
fcntl(s->socket, F_SETFL, flags | O_NONBLOCK);
s->local.sun_family = AF_UNIX;
memset(s->local.sun_path, 0, UNIX_PATH_MAX);
strncpy(s->local.sun_path, sock_path, UNIX_PATH_MAX - 1);
unlink(s->local.sun_path);
if (bind(s->socket, (struct sockaddr *)&(s->local), sizeof(struct sockaddr_un)) == -1) {
dprintf("[UNIX SOCKET SERVER] bind failed");
return errno;
}
if (listen(s->socket, 1) == -1) {
dprintf("[UNIX SOCKET SERVER] listen failed");
return errno;
}
return 0;
}
/*!
* @brief Accepts a new connection.
* @param s Pointer to the \c server_un listening.
* @param timeout Time, in seconds, to wait for a new connection (default = 5).
* @returns Indication of success or failure.
* @retval 0 Indicates success.
*/
LONG
accept_connection(server_un *s, DWORD timeout) {
connection_un *c;
LONG rv;
int len;
if (s == NULL) {
dprintf("[UNIX SOCKET SERVER] NULL server");
return ERROR_INVALID_PARAMETER;
}
c = &(s->client);
if (c == NULL) {
dprintf("[UNIX SOCKET SERVER] NULL server");
return ERROR_INVALID_PARAMETER;
}
if (timeout != -1) {
s->timeout.tv_sec = timeout;
}
dprintf("[UNIX SOCKET SERVER] Waiting for a new connection");
rv = select(s->socket + 1, &(s->set), NULL, NULL, &(s->timeout));
if(rv == -1) {
dprintf("[UNIX SOCKET SERVER] select failed");
return errno;
} else if (rv == 0) {
dprintf("[UNIX SOCKET SERVER] timeout");
return ETIME;
}
len = sizeof(struct sockaddr_un);
if ((c->socket = accept(s->socket, (struct sockaddr *)&(c->remote), &len)) == -1) {
dprintf("[UNIX SOCKET SERVER] accept failed");
return errno;
}
return 0;
}
/*!
* @brief Close an existent connection.
* @param c Pointer to the \c connection_un to close.
* @returns Indication of success or failure.
* @retval 0 Indicates success.
*/
LONG
close_connection(connection_un *c) {
if (c == NULL) {
dprintf("[UNIX SOCKET SERVER] NULL connection");
return ERROR_INVALID_PARAMETER;
}
if (close(c->socket) == -1){
dprintf("[UNIX SOCKET SERVER] Close connection failed");
return errno;
}
return 0;
}
/*!
* @brief Stops a listening server.
* @param c Pointer to the \c server_un to stop.
* @returns Indication of success or failure.
* @retval 0 Indicates success.
*/
LONG
stop_server(server_un *s) {
if (s == NULL) {
dprintf("[UNIX SOCKET SERVER] NULL server");
return ERROR_INVALID_PARAMETER;
}
close_connection(&(s->client));
close(s->socket);
unlink(s->local.sun_path);
return 0;
}
/*!
* @brief Sends a files descriptor over an existing connection.
* @param c Pointer to the \c connection_un to send the socket.
* @param fd file descriptor to send.
* @returns Indication of success or failure.
* @retval 0 Indicates success.
*/
LONG
send_socket(connection_un *c, HANDLE fd) {
struct iovec vector;
struct msghdr msg;
struct cmsghdr * cmsg;
dprintf("[UNIX SOCKET SERVER] Building message for socket sharing...");
vector.iov_base = "METERPRETER";
vector.iov_len = strlen("METERPRETER") + 1;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &vector;
msg.msg_iovlen = 1;
cmsg = alloca(sizeof(struct cmsghdr) + sizeof(fd));
cmsg->cmsg_len = sizeof(struct cmsghdr) + sizeof(fd);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd));
msg.msg_control = cmsg;
msg.msg_controllen = cmsg->cmsg_len;
if (sendmsg(c->socket, &msg, 0) != vector.iov_len) {
dprintf("[UNIX SOCKET SERVER] sendmsg failed");
return errno;
}
return 0;
}