8000 Honeyd/command.c at dhcpWork · newdominic/Honeyd · GitHub
[go: up one dir, main page]

Skip to content

Latest commit

 

History

History
824 lines (677 loc) · 19.8 KB

command.c

File metadata and controls

824 lines (677 loc) · 19.8 KB
setpriority(PRIO_PROCESS, 0, 10);
if (tmpl->uid)
uid = tmpl->uid;
if (tmpl->gid)
gid = tmpl->gid;
if (tmpl->max_nofiles)
nofiles = tmpl->max_nofiles;
cmd_droppriv(uid, gid);
/* Raising file descriptor limits */
rl.rlim_cur = rl.rlim_max = nofiles;
if (setrlimit(RLIMIT_NOFILE, &rl) == -1)
{
syslog(LOG_ERR, "setrlimit: %d, failed to set resource limit", nofiles);
exit(EXIT_FAILURE);
}
return (0);
}
int
cmd_fork(struct tuple *hdr, struct command *cmd, struct template *tmpl,
char *execcmd, char **argv, void *con)
{
extern int honeyd_nchildren;
int pair[2], perr[2];
struct callback *cb;
sigset_t sigmask;
if (socketpair(AF_UNIX, hdr->type, 0, pair) == -1)
return (-1);
if (socketpair(AF_UNIX, SOCK_STREAM, 0, perr) == -1) {
TRACE_RESET(pair[0], close(pair[0]));
TRACE_RESET(pair[1], close(pair[1]));
return (-1);
}
/* Block SIGCHLD */
sigemptyset(&sigmask);
sigaddset(&sigmask, SIGCHLD);
if (sigprocmask(SIG_BLOCK, &sigmask, NULL) == -1) {
warn("sigprocmask");
goto fork_err;
}
cmd->pid = fork();
if (cmd->pid == -1) {
warn("fork");
goto unmask_err;
}
if (cmd->pid == 0) {
/* Child privileges */
cmd_setpriv(tmpl);
/* Child */
TRACE_RESET(pair[0], close(pair[0]));
if (dup2(pair[1], fileno(stdout)) == -1)
{
syslog(LOG_ERR, "%s: dup2 failed to copy descriptor",__func__);
exit(EXIT_FAILURE);
}
if (dup2(pair[1], fileno(stdin)) == -1)
{
syslog(LOG_ERR, "%s: dup2", __func__);
exit(EXIT_FAILURE);
}
TRACE_RESET(pair[0], close(perr[0]));
if (dup2(perr[1], fileno(stderr)) == -1)
{
syslog(LOG_ERR, "%s: dup2", __func__);
exit(EXIT_FAILURE);
}
TRACE_RESET(pair[1], close(pair[1]));
TRACE_RESET(perr[1], close(perr[1]));
cmd_environment(tmpl, hdr);
if (execvp(execcmd, argv) == -1)
{
syslog(LOG_ERR, "%s: execv(%s): %s", __func__, execcmd, strerror(errno));
exit(EXIT_FAILURE);
}
/* NOT REACHED */
}
TRACE_RESET(pair[1], close(pair[1]));
TRACE(pair[0], cmd->pfd = pair[0]);
if (fcntl(cmd->pfd, F_SETFD, 1) == -1)
warn("fcntl(F_SETFD)");
if (fcntl(cmd->pfd, F_SETFL, O_NONBLOCK) == -1)
warn("fcntl(F_SETFL)");
TRACE_RESET(perr[1], close(perr[1]));
cmd->perrfd = perr[0];
if (fcntl(cmd->perrfd, F_SETFD, 1) == -1)
warn("fcntl(F_SETFD)");
if (fcntl(cmd->perrfd, F_SETFL, O_NONBLOCK) == -1)
warn("fcntl(F_SETFL)");
if (hdr->type == SOCK_STREAM)
cb = &cb_tcp;
else
cb = &cb_udp;
cmd_ready_fd(cmd, cb, con);
TRACE(event_get_fd(cmd->pread), event_add(cmd->pread, NULL));
TRACE(event_get_fd(cmd->peread), event_add(cmd->peread, NULL));
honeyd_nchildren++;
/* Install old signal handler */
if (sigprocmask(SIG_UNBLOCK, &sigmask, NULL) == -1) {
warn("sigprocmask");
goto fork_err;
}
return (0);
/* Error cleanup */
unmask_err:
/* Install old signal handler */
if (sigprocmask(SIG_UNBLOCK, &sigmask, NULL) == -1)
warn("sigprocmask");
fork_err:
TRACE_RESET(perr[0], close(perr[0]));
TRACE_RESET(perr[1], clos 8BD0 e(perr[1]));
TRACE_RESET(pair[0], close(pair[0]));
TRACE_RESET(pair[1], close(pair[1]));
cmd->pfd = -1;
return (-1);
}
int
cmd_python(struct tuple *hdr, struct command *cmd, void *con)
{
int pair[2];
struct callback *cb;
if (socketpair(AF_UNIX, hdr->type, 0, pair) == -1)
return (-1);
TRACE(pair[0], cmd->pfd = pair[0]);
if (fcntl(cmd->pfd, F_SETFD, 1) == -1)
warn("fcntl(F_SETFD)");
if (fcntl(cmd->pfd, F_SETFL, O_NONBLOCK) == -1)
warn("fcntl(F_SETFL)");
/* Python descriptors should not go across exec */
if (fcntl(pair[1], F_SETFD, 1) == -1)
warn("fcntl(F_SETFD)");
if (fcntl(pair[1], F_SETFL, O_NONBLOCK) == -1)
warn("fcntl(F_SETFL)");
if (hdr->type == SOCK_STREAM)
cb = &cb_tcp;
else
cb = &cb_udp;
cmd_ready_fd(cmd, cb, con);
TRACE(event_get_fd(cmd->pread), event_add(cmd->pread, NULL));
return (pair[1]);
}
int
cmd_subsystem(struct template *tmpl, struct subsystem *sub,
char *execcmd, char **argv)
{
extern int honeyd_nchildren;
struct command *cmd = &sub->cmd;
extern struct callback subsystem_cb;
int pair[2];
sigset_t sigmask;
if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1)
return (-1);
/* Block SIGCHLD */
sigemptyset(&sigmask);
sigaddset(&sigmask, SIGCHLD);
if (sigprocmask(SIG_BLOCK, &sigmask, NULL) == -1) {
warn("sigprocmask");
goto fork_err;
}
cmd->pid = fork();
if (cmd->pid == -1) {
warn("fork");
goto unmask_err;
}
if (cmd->pid == 0) {
char magic_buf[12];
int magic_fd;
/* Set privileges */
cmd_setpriv(tmpl);
/* Child */
TRACE_RESET(pair[0], close(pair[0]));
/* Set the communication fd */
if ((magic_fd = dup(pair[1])) == -1)
{
syslog(LOG_ERR, "%s: dup(%d): no magic failed to duplicate the pair", __func__, pair[1]);
exit(EXIT_FAILURE);
}
snprintf(magic_buf, sizeof(magic_buf), "%d", magic_fd);
setenv(SUBSYSTEM_MAGICFD, magic_buf, 1);
if (dup2(fileno(stderr), fileno(stdout)) == -1)
{
syslog(LOG_ERR, "%s: dup2", __func__);
exit(EXIT_FAILURE);
}
if (dup2(fileno(stderr), fileno(stdin)) == -1)
{
syslog(LOG_ERR, "%s: dup2", __func__);
exit(EXIT_FAILURE);
}
TRACE_RESET(pair[1], close(pair[1]));
cmd_environment(tmpl, NULL);
/* Setup the wrapper library */
if (setenv("LD_PRELOAD", PATH_HONEYDLIB"/libhoneyd.so", 1) == -1)
{
syslog(LOG_ERR, "%s: setenv", __func__);
exit(EXIT_FAILURE);
}
if (execv(execcmd, argv) == -1)
{
syslog(LOG_ERR, "%s: execv(%s)", __func__, execcmd);
exit(EXIT_FAILURE);
}
/* NOT REACHED */
}
TRACE_RESET(pair[1], close(pair[1]));
TRACE(pair[0], cmd->pfd = pair[0]);
if (fcntl(cmd->pfd, F_SETFD, 1) == -1)
warn("fcntl(F_SETFD)");
cmd->perrfd = -1;
cmd_ready_fd(cmd, &subsystem_cb, sub);
TRACE(event_get_fd(cmd->pread), event_add(cmd->pread, NULL));
honeyd_nchildren++;
/* Install old signal handler */
if (sigprocmask(SIG_UNBLOCK, &sigmask, NULL) == -1) {
warn("sigprocmask");
goto fork_err;
}
return (0);
/* Error cleanup */
unmask_err:
/* Install old signal handler */
if (sigprocmask(SIG_UNBLOCK, &sigmask, NULL) == -1)
warn("sigprocmask");
fork_err:
TRACE_RESET(pair[0], close(pair[0]));
TRACE_RESET(pair[1], close(pair[1]));
cmd->pfd = -1;
return (-1);
}
static void
cmd_subsystem_connect_cb(int fd, short what, void *arg)
{
struct port_encapsulate *tmp = arg;
struct port *port = tmp->port;
TAILQ_REMOVE(&port->pending, tmp, next);
if (what != EV_WRITE) {
/* We encountered some error with this */
if (tmp->hdr->type == SOCK_STREAM)
tcp_connectfail(tmp->con);
goto out;
}
cmd_subsystem_connect(tmp->hdr, tmp->cmd, port, tmp->con);
out:
port_encapsulation_free(tmp);
}
int
cmd_subsystem_schedule_connect(struct tuple *hdr, struct command *cmd,
struct port *port, void *con)
{
struct port_encapsulate *tmp = calloc(1, sizeof(*tmp));
struct subsystem *sub = port->sub;
if (tmp == NULL)
return (-1);
tmp->hdr = hdr;
tmp->cmd = cmd;
tmp->port = port;
tmp->con = con;
/* Tell the connection that it has a pending connection */
tmp->hdr->pending = tmp;
TAILQ_INSERT_TAIL(&port->pending, tmp, next);
TRACE(port->sub_fd,
event_new(libevent_base, port->sub_fd, EV_WRITE, cmd_subsystem_connect_cb, tmp));
TRACE(event_get_fd(tmp->ev),
event_add(tmp->ev, NULL));
syslog(LOG_DEBUG,
"Scheduling connection establishment: %s -> subsystem \"%s\"",
honeyd_contoa(hdr), sub->cmdstring);
return (0);
}
int
cmd_subsystem_connect(struct tuple *hdr, struct command *cmd,
struct port *port, void *con)
{
struct callback *cb;
struct subsystem *sub = port->sub;
struct bundle bundle;
struct addr src, dst;
int pair[2];
if (hdr->type == SOCK_STREAM)
cb = &cb_tcp;
else
cb = &cb_udp;
if (socketpair(AF_LOCAL, hdr->type, 0, pair) == -1) {
warn("%s: socketpair: %s", __func__, sub->cmdstring);
return (-1);
}
if (fcntl(pair[0], F_SETFL, O_NONBLOCK) == -1)
warn("fcntl(O_NONBLOCK)");
if (fcntl(pair[0], F_SETFD, 1) == -1)
warn("fcntl(F_SETFD)");
TRACE(pair[0], cmd->pfd = pair[0]);
/* Prepare sockaddr for both src and destination */
addr_pack(&src, ADDR_TYPE_IP, IP_ADDR_BITS, &hdr->ip_src,IP_ADDR_LEN);
addr_ntos(&src, (struct sockaddr *)&bundle.src);
bundle.src.sin_port = htons(hdr->sport);
addr_pack(&dst, ADDR_TYPE_IP, IP_ADDR_BITS, &hdr->ip_dst,IP_ADDR_LEN);
addr_ntos(&dst, (struct sockaddr *)&bundle.dst);
bundle.dst.sin_port = htons(hdr->dport);
if (send_fd(port->sub_fd, pair[1], &bundle, sizeof(bundle)) == -1) {
TRACE_RESET(pair[0], close(pair[0]));
TRACE_RESET(pair[1], close(pair[1]));
cmd->pfd = -1;
return (-1);
}
/* After transfering the file descriptor, we may close it */
TRACE_RESET(pair[1], close(pair[1]));
/* We are connected now */
(*cb->cb_connect)(pair[0], EV_WRITE, con);
syslog(LOG_INFO, "Connection established: %s -> subsystem \"%s\"",
honeyd_contoa(hdr), sub->cmdstring);
return (0);
}
/*
* Called when the 3-way handshake for a connection initiated by a
* subsystem completed successfully.
*/
int
cmd_subsystem_localconnect(struct tuple *hdr, struct command *cmd,
struct port *port, void *con)
{
struct callback *cb;
struct subsystem *sub = port->sub;
struct sockaddr_in si;
struct addr src;
int fd;
if (hdr->type == SOCK_STREAM)
cb = &cb_tcp;
else
cb = &cb_udp;
/*
* If we do not have a control file descriptor for this connection,
* then get it now. The control file descriptor will give us the
* fd that is used for the real communication.
*/
if (port->sub_fd == -1) {
char res;
while ((fd = receive_fd(sub->cmd.pfd, NULL, NULL)) == -1) {
if (errno != EAGAIN) {
warnx("%s: receive_fd", __func__);
}
}
/* Confirm success of failure */
res = fd == -1 ? -1 : 0;
TRACE(sub->cmd.pfd,
atomicio(write, sub->cmd.pfd, &res, 1));
if (fd == -1)
return (-1);
TRACE(fd, port->sub_fd = fdshare_dup(fd));
}
/* Get another fd on this special thingy */
while ((fd = receive_fd(port->sub_fd, NULL, NULL)) == -1) {
if (errno != EAGAIN) {
TRACE(port->sub_fd, fdshare_close(port->sub_fd));
warnx("%s: receive_fd", __func__);
return (-1);
}
}
if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1)
warn("%s: fcntl(O_NONBLOCK)", __func__);
if (fcntl(fd, F_SETFD, 1) == -1)
warn("%s: fcntl(F_SETFD)", __func__);
TRACE(fd, cmd->pfd = fd);
/* Prepare sockaddr */
addr_pack(&src, ADDR_TYPE_IP, IP_ADDR_BITS, &hdr->ip_dst, IP_ADDR_LEN);
addr_ntos(&src, (struct sockaddr *)&si);
si.sin_port = htons(hdr->dport);
/* Write the bound socket address to the other side */
if (atomicio(write, port->sub_fd, &si, sizeof(si)) != sizeof(si)) {
TRACE(port->sub_fd, fdshare_close(port->sub_fd));
port->sub_fd = -1;
TRACE_RESET(cmd->pfd, close(cmd->pfd));
cmd->pfd = -1;
return (-1);
}
/* Now we may close the special thingy */
TRACE(port->sub_fd, fdshare_close(port->sub_fd));
port->sub_fd = -1;
/* We are connected now */
(*cb->cb_connect)(fd, EV_WRITE, con);
syslog(LOG_INFO, "Connection established: subsystem \"%s\" -> %s",
sub->cmdstring, honeyd_contoa(hdr));
return (0);
}
0