SshStream ssh_stream_fd_file(const char *filename, Boolean readable,
                             Boolean writable)
{
  SshIOHandle fd;
  int mode;
  SshStream stream;

  SSH_ASSERT(readable || writable);
  if (readable && writable)
    mode = O_RDWR;
  else if (readable)
    mode = O_RDONLY;
  else
    mode = O_WRONLY;

  fd = open(filename, mode, 0);
  if (fd < 0)
    return NULL;

  /* Create the stream. */
  stream = ssh_stream_fd_wrap(fd, TRUE);
  if (stream == NULL)
    close(fd);

  /* Return the stream or NULL if the wrap operation failed. */
  return stream;
}
Example #2
0
void ssh_local_listen_callback(unsigned int events, void *context)
{
    SshLocalListener listener = (SshLocalListener)context;
    int sock, addrlen;
    struct sockaddr_un sunaddr;

    if (events & SSH_IO_READ)
    {
        addrlen = sizeof(sunaddr);
        sock = accept(listener->sock, (struct sockaddr *)&sunaddr, &addrlen);
        if (sock < 0)
        {
            ssh_debug("ssh_local_listen_callback: accept failed");
            return;
        }

        /* Re-enable requests on the listener. */
        ssh_io_set_fd_request(listener->sock, SSH_IO_READ);

        /* Inform user callback of the new socket.  Note that this might
           destroy the listener. */
        (*listener->callback)(ssh_stream_fd_wrap(sock, TRUE), listener->context);
    }
}
Example #3
0
void ssh_local_connect_try(unsigned int events, void *context)
{
    SshLocalConnect c = (SshLocalConnect)context;
    int ret;
    struct sockaddr_un sunaddr;

    /* Initialize the address to connect to. */
    memset(&sunaddr, 0, sizeof(sunaddr));
    sunaddr.sun_family = AF_UNIX;
    strncpy(sunaddr.sun_path, c->path, sizeof(sunaddr.sun_path));

    /* Make a non-blocking connect attempt. */
    ret = connect(c->sock, (struct sockaddr *)&sunaddr, AF_UNIX_SIZE(sunaddr));
    if (ret >= 0 || errno == EISCONN) /* Connection is ready. */
    {
        /* Successful connection. */
        ssh_io_unregister_fd(c->sock, FALSE);
        (*c->callback)(ssh_stream_fd_wrap(c->sock, TRUE), c->context);
        ssh_xfree(c->path);
        ssh_xfree(c);
        return;
    }
    if (errno == EINPROGRESS || errno == EWOULDBLOCK || errno == EALREADY)
    {
        /* Connection still in progress.  */
        ssh_io_set_fd_request(c->sock, SSH_IO_WRITE);
        return;
    }

    /* Connection failed. */
    ssh_io_unregister_fd(c->sock, FALSE);
    close(c->sock);
    (*c->callback)(NULL, c->context);
    ssh_xfree(c->path);
    ssh_xfree(c);
}
Example #4
0
SshPipeStatus ssh_pipe_create_and_fork(SshStream *stdio_return,
                                       SshStream *stderr_return)
{
    int pin[2], pout[2], perr[2];
    pid_t pid;
    SshPipeStream pipes;

    if (pipe(pin) < 0)
        return SSH_PIPE_ERROR;
    if (pipe(pout) < 0)
    {
        close(pin[0]);
        close(pin[1]);
        return SSH_PIPE_ERROR;
    }
    if (stderr_return != NULL && pipe(perr) < 0)
    {
        close(pin[0]);
        close(pin[1]);
        close(pout[0]);
        close(pout[1]);
        return SSH_PIPE_ERROR;
    }

    /* Initialize SIGCHLD handling.  This will ensure the SIGCHLD won't get
       delivered until we register the handler for the new process below. */
    ssh_sigchld_initialize();

    /* Fork a child process. */
    pid = fork();
    if (pid < 0)
    {
        ssh_warning("Fork failed: %s", strerror(errno));
        close(pin[0]);
        close(pin[1]);
        close(pout[0]);
        close(pout[1]);
        if (stderr_return != NULL)
        {
            close(perr[0]);
            close(perr[1]);
        }
        return SSH_PIPE_ERROR;
    }

    /* The remaining processing depends on whether we are the parent or
       the child. */
    if (pid == 0)
    {
        /* Redirect stdin. */
        close(pin[1]);
        if (dup2(pin[0], 0) < 0)
            perror("dup2 stdin");
        close(pin[0]);

        /* Redirect stdout. */
        close(pout[0]);
        if (dup2(pout[1], 1) < 0)
            perror("dup2 stdout");
        close(pout[1]);

        if (stderr_return != NULL)
        {
            /* Redirect stderr. */
            close(perr[0]);
            if (dup2(perr[1], 2) < 0)
                perror("dup2 stderr");
            close(perr[1]);
        }

        *stdio_return = NULL;
        if (stderr_return != NULL)
            *stderr_return = NULL;
        return SSH_PIPE_CHILD_OK;
    }

    /* Parent */
    pipes = ssh_xcalloc(sizeof(*pipes), 1);
    pipes->pid = pid;
    pipes->callback = NULL;
    pipes->callback_context = NULL;

    pipes->status_returned = FALSE;
    pipes->exit_status = -1;

    /* Close the child-side file descriptors. */
    close(pin[0]);
    close(pout[1]);
    if (stderr_return != NULL)
        close(perr[1]);

    /* Register a handler for SIGCHLD for our new child. */
    ssh_sigchld_register(pid, ssh_pipe_sigchld_handler, (void *)pipes);

    /* Wrap the master fd into a stream. */
    pipes->stdio_stream = ssh_stream_fd_wrap2(pout[0], pin[1], TRUE);
    *stdio_return = ssh_stream_create(&ssh_pipe_methods, (void *) pipes);

    /* Create the stderr stream if requested. */
    /* XXX should another context (errpipes?) be allocated for this, so that
       this, too, could be created as above?*/
    if (stderr_return != NULL)
        *stderr_return = ssh_stream_fd_wrap(perr[0], TRUE);

    return SSH_PIPE_PARENT_OK;
}