Ejemplo n.º 1
0
/* Run the given command line as if with exec. What we actually do is fork the
   command line as a subprocess, then loop, relaying data between the socket and
   the subprocess. This allows Ncat to handle SSL from the socket and give plain
   text to the subprocess, and also allows things like logging and line delays.
   Never returns. */
void netexec(struct fdinfo *info, char *cmdexec)
{
    int child_stdin[2];
    int child_stdout[2];
    int pid;
    int crlf_state;

    char buf[DEFAULT_TCP_BUF_LEN];
    int maxfd;

    if (o.debug) {
        switch (o.execmode) {
        case EXEC_SHELL:
            logdebug("Executing with shell: %s\n", cmdexec);
            break;
#ifdef HAVE_LUA
        case EXEC_LUA:
            logdebug("Executing as lua script: %s\n", cmdexec);
            break;
#endif
        default:
            logdebug("Executing: %s\n", cmdexec);
            break;
        }
    }

    if (pipe(child_stdin) == -1 || pipe(child_stdout) == -1)
        bye("Can't create child pipes: %s", strerror(errno));

    pid = fork();
    if (pid == -1)
        bye("Error in fork: %s", strerror(errno));
    if (pid == 0) {
        /* This is the child process. Exec the command. */
        close(child_stdin[1]);
        close(child_stdout[0]);

        /* We might have turned off SIGPIPE handling in ncat_listen.c. Since
           the child process SIGPIPE might mean that the connection got broken,
           ignoring it could result in an infinite loop if the code here
           ignores the error codes of read()/write() calls. So, just in case,
           let's restore SIGPIPE so that writing to a broken pipe results in
           killing the child process. */
        Signal(SIGPIPE, SIG_DFL);

        /* rearrange stdin and stdout */
        Dup2(child_stdin[0], STDIN_FILENO);
        Dup2(child_stdout[1], STDOUT_FILENO);

        switch (o.execmode) {
        char **cmdargs;

        case EXEC_SHELL:
            execl("/bin/sh", "sh", "-c", cmdexec, (void *) NULL);
            break;
#ifdef HAVE_LUA
        case EXEC_LUA:
            lua_run();
            break;
#endif
        default:
            cmdargs = cmdline_split(cmdexec);
            execv(cmdargs[0], cmdargs);
            break;
        }

        /* exec failed. */
        die("exec");
    }

    close(child_stdin[0]);
    close(child_stdout[1]);

    maxfd = child_stdout[0];
    if (info->fd > maxfd)
        maxfd = info->fd;

    /* This is the parent process. Enter a "caretaker" loop that reads from the
       socket and writes to the suprocess, and reads from the subprocess and
       writes to the socket. We exit the loop on any read error (or EOF). On a
       write error we just close the opposite side of the conversation. */
    crlf_state = 0;
    for (;;) {
        fd_set fds;
        int r, n_r;

        FD_ZERO(&fds);
        FD_SET(info->fd, &fds);
        FD_SET(child_stdout[0], &fds);

        r = fselect(maxfd + 1, &fds, NULL, NULL, NULL);
        if (r == -1) {
            if (errno == EINTR)
                continue;
            else
                break;
        }
        if (FD_ISSET(info->fd, &fds)) {
            int pending;

            do {
                n_r = ncat_recv(info, buf, sizeof(buf), &pending);
                if (n_r <= 0)
                    goto loop_end;
                write_loop(child_stdin[1], buf, n_r);
            } while (pending);
        }
        if (FD_ISSET(child_stdout[0], &fds)) {
            char *crlf = NULL, *wbuf;
            n_r = read(child_stdout[0], buf, sizeof(buf));
            if (n_r <= 0)
                break;
            wbuf = buf;
            if (o.crlf) {
                if (fix_line_endings((char *) buf, &n_r, &crlf, &crlf_state))
                    wbuf = crlf;
            }
            ncat_send(info, wbuf, n_r);
            if (crlf != NULL)
                free(crlf);
        }
    }
loop_end:

#ifdef HAVE_OPENSSL
    if (info->ssl != NULL) {
        SSL_shutdown(info->ssl);
        SSL_free(info->ssl);
    }
#endif
    close(info->fd);

    exit(0);
}
Ejemplo n.º 2
0
/* Run the given command line as if with exec. What we actually do is fork the
   command line as a subprocess, then loop, relaying data between the socket and
   the subprocess. This allows Ncat to handle SSL from the socket and give plain
   text to the subprocess, and also allows things like logging and line delays.
   Never returns. */
void netexec(struct fdinfo *info, char *cmdexec)
{
    int child_stdin[2];
    int child_stdout[2];
    int pid;
    int crlf_state;

    char buf[DEFAULT_TCP_BUF_LEN];
    int maxfd;

    if (o.debug) {
        if (o.shellexec)
            logdebug("Executing with shell: %s\n", cmdexec);
        else
            logdebug("Executing: %s\n", cmdexec);
    }

    if (pipe(child_stdin) == -1 || pipe(child_stdout) == -1)
        bye("Can't create child pipes: %s", strerror(errno));

    pid = fork();
    if (pid == -1)
        bye("Error in fork: %s", strerror(errno));
    if (pid == 0) {
        /* This is the child process. Exec the command. */
        close(child_stdin[1]);
        close(child_stdout[0]);

        /* rearrange stdin and stdout */
        Dup2(child_stdin[0], STDIN_FILENO);
        Dup2(child_stdout[1], STDOUT_FILENO);

        if (o.shellexec) {
            execl("/bin/sh", "sh", "-c", cmdexec, (void *) NULL);
        } else {
            char **cmdargs;

            cmdargs = cmdline_split(cmdexec);
            execv(cmdargs[0], cmdargs);
        }

        /* exec failed.*/
        die("exec");
    }

    close(child_stdin[0]);
    close(child_stdout[1]);

    maxfd = child_stdout[0];
    if (info->fd > maxfd)
        maxfd = info->fd;

    /* This is the parent process. Enter a "caretaker" loop that reads from the
       socket and writes to the suprocess, and reads from the subprocess and
       writes to the socket. We exit the loop on any read error (or EOF). On a
       write error we just close the opposite side of the conversation. */
    crlf_state = 0;
    for (;;) {
        fd_set fds;
        int r, n_r, n_w;

        FD_ZERO(&fds);
        FD_SET(info->fd, &fds);
        FD_SET(child_stdout[0], &fds);

        r = fselect(maxfd + 1, &fds, NULL, NULL, NULL);
        if (r == -1) {
            if (errno == EINTR)
                continue;
            else
                break;
        }
        if (FD_ISSET(info->fd, &fds)) {
            int pending;

            do {
                n_r = ncat_recv(info, buf, sizeof(buf), &pending);
                if (n_r <= 0)
                    goto loop_end;
                n_w = write_loop(child_stdin[1], buf, n_r);
            } while (pending);
        }
        if (FD_ISSET(child_stdout[0], &fds)) {
            char *crlf = NULL, *wbuf;
            n_r = read(child_stdout[0], buf, sizeof(buf));
            if (n_r <= 0)
                break;
            wbuf = buf;
            if (o.crlf) {
                if (fix_line_endings((char *) buf, &n_r, &crlf, &crlf_state))
                    wbuf = crlf;
            }
            n_w = ncat_send(info, wbuf, n_r);
            if (crlf != NULL)
                free(crlf);
        }
    }
loop_end:

#ifdef HAVE_OPENSSL
    if (info->ssl != NULL) {
        SSL_shutdown(info->ssl);
        SSL_free(info->ssl);
    }
#endif
    close(info->fd);

    exit(0);
}