int ssh_mkdir_verb(const char *path, verbose_t verb) { Attrib a; u_int status, id; char *abspath; attrib_clear(&a); a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; a.perm = 0777; id = ftp->ssh_id++; abspath = ftp_path_absolute(path); stripslash(abspath); ssh_send_string_attrs_request(id, SSH2_FXP_MKDIR, abspath, strlen(abspath), &a); status = ssh_get_status(id); if(status != SSH2_FX_OK) { ftp_err("Couldn't create directory: %s\n", fx2txt(status)); free(abspath); return -1; } ftp_cache_flush_mark_for(abspath); free(abspath); return 0; }
static void on_channel_exit_status (ssh_session session, ssh_channel channel, int exit_status, void *userdata) { CockpitSshTransport *self = userdata; const gchar *problem = NULL; self->received_exit = TRUE; if (exit_status == 127) { g_debug ("%s: received exit status %d", self->logname, exit_status); problem = "no-cockpit"; /* cockpit-bridge not installed */ } else if (exit_status) { g_warning ("%s: session program exited with %d status", self->logname, exit_status); problem = "internal-error"; } if (!self->problem) self->problem = problem; close_maybe (self, ssh_get_status (session)); }
/** * Disconnect of the SSH server * @return bool true if it's ok, false else */ bool Kssh::disconnect() { if (ssh_get_status(this->m_session) != SSH_CLOSED) { ssh_disconnect(this->m_session); } return true; }
int ssh_unlink(const char *path) { u_int status, id; id = ftp->ssh_id++; ssh_send_string_request(id, SSH2_FXP_REMOVE, path, strlen(path)); status = ssh_get_status(id); if(status != SSH2_FX_OK) { /* ftp_err("Couldn't delete file: %s\n", fx2txt(status));*/ ftp->code = ctError; ftp->fullcode = 500; return -1; } else ftp_cache_flush_mark_for(path); return 0; }
int ssh_rmdir(const char *path) { char *p; u_int status, id; p = ftp_path_absolute(path); stripslash(p); id = ftp->ssh_id++; ssh_send_string_request(id, SSH2_FXP_RMDIR, p, strlen(p)); status = ssh_get_status(id); if(status != SSH2_FX_OK) { ftp_err("Couldn't remove directory: %s\n", fx2txt(status)); free(p); return -1; } ftp_cache_flush_mark(p); ftp_cache_flush_mark_for(p); free(p); return 0; }
int ssh_rename(const char *oldname, const char *newname) { Buffer msg; u_int status, id; char *on, *nn; buffer_init(&msg); on = ftp_path_absolute(oldname); nn = ftp_path_absolute(newname); stripslash(on); stripslash(nn); /* Send rename request */ id = ftp->ssh_id++; buffer_put_char(&msg, SSH2_FXP_RENAME); buffer_put_int(&msg, id); buffer_put_cstring(&msg, on); buffer_put_cstring(&msg, nn); ssh_cmd( &msg); buffer_free(&msg); status = ssh_get_status(id); if(status != SSH2_FX_OK) { ftp_err("Couldn't rename file \"%s\" to \"%s\": %s\n", on, nn, fx2txt(status)); free(on); free(nn); return -1; } ftp_cache_flush_mark_for(on); ftp_cache_flush_mark_for(nn); free(on); free(nn); return 0; }
static void on_channel_exit_signal (ssh_session session, ssh_channel channel, const char *signal, int core, const char *errmsg, const char *lang, void *userdata) { CockpitSshTransport *self = userdata; const gchar *problem = NULL; g_return_if_fail (signal != NULL); self->received_exit = TRUE; if (g_ascii_strcasecmp (signal, "TERM") == 0 || g_ascii_strcasecmp (signal, "Terminated") == 0) { g_debug ("%s: received TERM signal", self->logname); problem = "terminated"; } else { if (errmsg) g_warning ("%s: session program killed: %s", self->logname, errmsg); else g_warning ("%s: session program killed by %s signal", self->logname, signal); problem = "internal-error"; } if (!self->problem) self->problem = problem; close_maybe (self, ssh_get_status (session)); }
static gboolean cockpit_ssh_source_prepare (GSource *source, gint *timeout) { CockpitSshSource *cs = (CockpitSshSource *)source; CockpitSshTransport *self = cs->transport; GThread *thread; gint status; *timeout = 1; /* Connecting, check if done */ if (G_UNLIKELY (!self->data)) { if (g_atomic_int_get (&self->connecting)) return FALSE; g_object_ref (self); /* Get the result from connecting thread */ thread = self->connect_thread; self->connect_fd = -1; self->connect_thread = NULL; self->data = g_thread_join (thread); g_assert (self->data != NULL); if (!self->result_emitted) { self->result_emitted = TRUE; g_signal_emit_by_name (self, "result", self->data->problem); } if (self->data->problem) { close_immediately (self, self->data->problem); g_object_unref (self); return FALSE; } g_object_unref (self); ssh_event_add_session (self->event, self->data->session); ssh_set_channel_callbacks (self->data->channel, &self->channel_cbs); /* Start watching the fd */ ssh_set_blocking (self->data->session, 0); cs->pfd.fd = ssh_get_fd (self->data->session); g_source_add_poll (source, &cs->pfd); g_debug ("%s: starting io", self->logname); } status = ssh_get_status (self->data->session); /* Short cut this ... we're ready now */ if (self->drain_buffer) return TRUE; /* * Channel completely closed, and output buffers * are empty. We're in a good place to close the * SSH session and thus the transport. */ if (close_maybe (self, status)) return FALSE; cs->pfd.revents = 0; cs->pfd.events = G_IO_IN | G_IO_ERR | G_IO_NVAL | G_IO_HUP; /* libssh has something in its buffer: want to write */ if (status & SSH_WRITE_PENDING) cs->pfd.events |= G_IO_OUT; /* We have something in our queue: want to write */ else if (!g_queue_is_empty (self->queue)) cs->pfd.events |= G_IO_OUT; /* We are closing and need to send eof: want to write */ else if (self->closing && !self->sent_eof) cs->pfd.events |= G_IO_OUT; /* Need to reply to an EOF or close */ if ((self->received_eof && self->sent_eof && !self->sent_close) || (self->received_close && !self->sent_close)) cs->pfd.events |= G_IO_OUT; return cockpit_ssh_source_check (source); }
static void handle_session(ssh_event event, ssh_session session) { int n; int rc = 0; /* Structure for storing the pty size. */ struct winsize wsize = { .ws_row = 0, .ws_col = 0, .ws_xpixel = 0, .ws_ypixel = 0 }; /* Our struct holding information about the channel. */ struct channel_data_struct cdata = { .pid = 0, .pty_master = -1, .pty_slave = -1, .child_stdin = -1, .child_stdout = -1, .child_stderr = -1, .event = NULL, .winsize = &wsize }; /* Our struct holding information about the session. */ struct session_data_struct sdata = { .channel = NULL, .auth_attempts = 0, .authenticated = 0 }; struct ssh_channel_callbacks_struct channel_cb = { .userdata = &cdata, .channel_pty_request_function = pty_request, .channel_pty_window_change_function = pty_resize, .channel_shell_request_function = shell_request, .channel_exec_request_function = exec_request, .channel_data_function = data_function, .channel_subsystem_request_function = subsystem_request }; struct ssh_server_callbacks_struct server_cb = { .userdata = &sdata, .auth_password_function = auth_password, .channel_open_request_session_function = channel_open, }; if (authorizedkeys[0]) { server_cb.auth_pubkey_function = auth_publickey; ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD | SSH_AUTH_METHOD_PUBLICKEY); } else ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD); ssh_callbacks_init(&server_cb); ssh_callbacks_init(&channel_cb); ssh_set_server_callbacks(session, &server_cb); if (ssh_handle_key_exchange(session) != SSH_OK) { fprintf(stderr, "%s\n", ssh_get_error(session)); return; } ssh_event_add_session(event, session); n = 0; while (sdata.authenticated == 0 || sdata.channel == NULL) { /* If the user has used up all attempts, or if he hasn't been able to * authenticate in 10 seconds (n * 100ms), disconnect. */ if (sdata.auth_attempts >= 3 || n >= 100) { return; } if (ssh_event_dopoll(event, 100) == SSH_ERROR) { fprintf(stderr, "%s\n", ssh_get_error(session)); return; } n++; } ssh_set_channel_callbacks(sdata.channel, &channel_cb); do { /* Poll the main event which takes care of the session, the channel and * even our child process's stdout/stderr (once it's started). */ if (ssh_event_dopoll(event, -1) == SSH_ERROR) { ssh_channel_close(sdata.channel); } /* If child process's stdout/stderr has been registered with the event, * or the child process hasn't started yet, continue. */ if (cdata.event != NULL || cdata.pid == 0) { continue; } /* Executed only once, once the child process starts. */ cdata.event = event; /* If stdout valid, add stdout to be monitored by the poll event. */ if (cdata.child_stdout != -1) { if (ssh_event_add_fd(event, cdata.child_stdout, POLLIN, process_stdout, sdata.channel) != SSH_OK) { fprintf(stderr, "Failed to register stdout to poll context\n"); ssh_channel_close(sdata.channel); } } /* If stderr valid, add stderr to be monitored by the poll event. */ if (cdata.child_stderr != -1){ if (ssh_event_add_fd(event, cdata.child_stderr, POLLIN, process_stderr, sdata.channel) != SSH_OK) { fprintf(stderr, "Failed to register stderr to poll context\n"); ssh_channel_close(sdata.channel); } } } while(ssh_channel_is_open(sdata.channel) && (cdata.pid == 0 || waitpid(cdata.pid, &rc, WNOHANG) == 0)); close(cdata.pty_master); close(cdata.child_stdin); close(cdata.child_stdout); close(cdata.child_stderr); /* Remove the descriptors from the polling context, since they are now * closed, they will always trigger during the poll calls. */ ssh_event_remove_fd(event, cdata.child_stdout); ssh_event_remove_fd(event, cdata.child_stderr); /* If the child process exited. */ if (kill(cdata.pid, 0) < 0 && WIFEXITED(rc)) { rc = WEXITSTATUS(rc); ssh_channel_request_send_exit_status(sdata.channel, rc); /* If client terminated the channel or the process did not exit nicely, * but only if something has been forked. */ } else if (cdata.pid > 0) { kill(cdata.pid, SIGKILL); } ssh_channel_send_eof(sdata.channel); ssh_channel_close(sdata.channel); /* Wait up to 5 seconds for the client to terminate the session. */ for (n = 0; n < 50 && (ssh_get_status(session) & SESSION_END) == 0; n++) { ssh_event_dopoll(event, 100); } } /* SIGCHLD handler for cleaning up dead children. */ static void sigchld_handler(int signo) { (void) signo; while (waitpid(-1, NULL, WNOHANG) > 0); } int main(int argc, char **argv) { ssh_bind sshbind; ssh_session session; ssh_event event; struct sigaction sa; int rc; /* Set up SIGCHLD handler. */ sa.sa_handler = sigchld_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART | SA_NOCLDSTOP; if (sigaction(SIGCHLD, &sa, NULL) != 0) { fprintf(stderr, "Failed to register SIGCHLD handler\n"); return 1; } rc = ssh_init(); if (rc < 0) { fprintf(stderr, "ssh_init failed\n"); return 1; } sshbind = ssh_bind_new(); if (sshbind == NULL) { fprintf(stderr, "ssh_bind_new failed\n"); return 1; } #ifdef HAVE_ARGP_H argp_parse(&argp, argc, argv, 0, 0, sshbind); #else (void) argc; (void) argv; set_default_keys(sshbind, 0, 0, 0); #endif /* HAVE_ARGP_H */ if(ssh_bind_listen(sshbind) < 0) { fprintf(stderr, "%s\n", ssh_get_error(sshbind)); return 1; } while (1) { session = ssh_new(); if (session == NULL) { fprintf(stderr, "Failed to allocate session\n"); continue; } /* Blocks until there is a new incoming connection. */ if(ssh_bind_accept(sshbind, session) != SSH_ERROR) { switch(fork()) { case 0: /* Remove the SIGCHLD handler inherited from parent. */ sa.sa_handler = SIG_DFL; sigaction(SIGCHLD, &sa, NULL); /* Remove socket binding, which allows us to restart the * parent process, without terminating existing sessions. */ ssh_bind_free(sshbind); event = ssh_event_new(); if (event != NULL) { /* Blocks until the SSH session ends by either * child process exiting, or client disconnecting. */ handle_session(event, session); ssh_event_free(event); } else { fprintf(stderr, "Could not create polling context\n"); } ssh_disconnect(session); ssh_free(session); exit(0); case -1: fprintf(stderr, "Failed to fork\n"); } } else { fprintf(stderr, "%s\n", ssh_get_error(sshbind)); } /* Since the session has been passed to a child fork, do some cleaning * up at the parent process. */ ssh_disconnect(session); ssh_free(session); } ssh_bind_free(sshbind); ssh_finalize(); return 0; }