aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormilo <milo@r0ot.me>2010-09-29 23:33:25 +0200
committerAris Adamantiadis <aris@0xbadc0de.be>2010-10-02 22:51:49 +0200
commit26170241363b6b1911b5515f23fc38ff081296cf (patch)
tree15c88554da41a13e975784ecc07cc91500a9c9c1
parent26d40b5354d6760472127f2c16045fbbb2f12fee (diff)
downloadlibssh-26170241363b6b1911b5515f23fc38ff081296cf.tar.gz
libssh-26170241363b6b1911b5515f23fc38ff081296cf.tar.xz
libssh-26170241363b6b1911b5515f23fc38ff081296cf.zip
Added channel features on the server
- ssh_channel_request_send_exit_status() - ssh_channel_request_send_exit_signal() - enhanced these features client-side
-rw-r--r--include/libssh/server.h8
-rw-r--r--src/channels.c211
2 files changed, 213 insertions, 6 deletions
diff --git a/include/libssh/server.h b/include/libssh/server.h
index b4116dc2..1a7fd4e6 100644
--- a/include/libssh/server.h
+++ b/include/libssh/server.h
@@ -192,6 +192,14 @@ LIBSSH_API int ssh_message_global_request_port(ssh_message msg);
LIBSSH_API int ssh_channel_open_reverse_forward(ssh_channel channel, const char *remotehost,
int remoteport, const char *sourcehost, int localport);
+LIBSSH_API int ssh_channel_request_send_exit_status(ssh_channel channel,
+ int exit_status);
+LIBSSH_API int ssh_channel_request_send_exit_signal(ssh_channel channel,
+ const char *signum,
+ int core,
+ const char *errmsg,
+ const char *lang);
+
/* deprecated functions */
SSH_DEPRECATED LIBSSH_API int ssh_accept(ssh_session session);
diff --git a/src/channels.c b/src/channels.c
index b91db723..2463bb0d 100644
--- a/src/channels.c
+++ b/src/channels.c
@@ -635,9 +635,51 @@ SSH_PACKET_CALLBACK(channel_rcv_request) {
if (strcmp(request,"exit-status") == 0) {
SAFE_FREE(request);
- ssh_log(session, SSH_LOG_PACKET, "received exit-status");
buffer_get_u32(packet, &status);
channel->exit_status = ntohl(status);
+ ssh_log(session, SSH_LOG_PACKET, "received exit-status %d", channel->exit_status);
+
+ if(ssh_callbacks_exists(channel->callbacks, channel_exit_status_function)) {
+ channel->callbacks->channel_exit_status_function(channel->session,
+ channel,
+ channel->exit_status,
+ channel->callbacks->userdata);
+ }
+
+ leave_function();
+ return SSH_PACKET_USED;
+ }
+
+ if (strcmp(request,"signal") == 0) {
+ ssh_string signal;
+ char *sig;
+
+ SAFE_FREE(request);
+ ssh_log(session, SSH_LOG_PACKET, "received signal");
+
+ signal = buffer_get_ssh_string(packet);
+ if (signal == NULL) {
+ ssh_log(session, SSH_LOG_PACKET, "Invalid MSG_CHANNEL_REQUEST");
+ leave_function();
+ return SSH_PACKET_USED;
+ }
+
+ sig = ssh_string_to_char(signal);
+ ssh_string_free(signal);
+ if (sig == NULL) {
+ leave_function();
+ return SSH_PACKET_USED;
+ }
+
+
+ ssh_log(session, SSH_LOG_PACKET,
+ "Remote connection sent a signal SIG %s", sig);
+ if(ssh_callbacks_exists(channel->callbacks, channel_signal_function)) {
+ channel->callbacks->channel_signal_function(channel->session,
+ channel,
+ sig,
+ channel->callbacks->userdata);
+ }
leave_function();
return SSH_PACKET_USED;
@@ -645,21 +687,23 @@ SSH_PACKET_CALLBACK(channel_rcv_request) {
if (strcmp(request, "exit-signal") == 0) {
const char *core = "(core dumped)";
- ssh_string signal_s;
+ ssh_string tmp;
char *sig;
+ char *errmsg = NULL;
+ char *lang = NULL;
uint8_t i;
SAFE_FREE(request);
- signal_s = buffer_get_ssh_string(packet);
- if (signal_s == NULL) {
+ tmp = buffer_get_ssh_string(packet);
+ if (tmp == NULL) {
ssh_log(session, SSH_LOG_PACKET, "Invalid MSG_CHANNEL_REQUEST");
leave_function();
return SSH_PACKET_USED;
}
- sig = ssh_string_to_char(signal_s);
- ssh_string_free(signal_s);
+ sig = ssh_string_to_char(tmp);
+ ssh_string_free(tmp);
if (sig == NULL) {
leave_function();
return SSH_PACKET_USED;
@@ -670,8 +714,51 @@ SSH_PACKET_CALLBACK(channel_rcv_request) {
core = "";
}
+ tmp = buffer_get_ssh_string(packet);
+ if (tmp == NULL) {
+ ssh_log(session, SSH_LOG_PACKET, "Invalid MSG_CHANNEL_REQUEST");
+ SAFE_FREE(sig);
+ leave_function();
+ return SSH_PACKET_USED;
+ }
+
+ errmsg = ssh_string_to_char(tmp);
+ ssh_string_free(tmp);
+ if (errmsg == NULL) {
+ SAFE_FREE(sig);
+ leave_function();
+ return SSH_PACKET_USED;
+ }
+
+ tmp = buffer_get_ssh_string(packet);
+ if (tmp == NULL) {
+ ssh_log(session, SSH_LOG_PACKET, "Invalid MSG_CHANNEL_REQUEST");
+ SAFE_FREE(errmsg);
+ SAFE_FREE(sig);
+ leave_function();
+ return SSH_PACKET_USED;
+ }
+
+ lang = ssh_string_to_char(tmp);
+ ssh_string_free(tmp);
+ if (lang == NULL) {
+ SAFE_FREE(errmsg);
+ SAFE_FREE(sig);
+ leave_function();
+ return SSH_PACKET_USED;
+ }
+
ssh_log(session, SSH_LOG_PACKET,
"Remote connection closed by signal SIG %s %s", sig, core);
+ if(ssh_callbacks_exists(channel->callbacks, channel_exit_signal_function)) {
+ channel->callbacks->channel_exit_signal_function(channel->session,
+ channel,
+ sig, i, errmsg, lang,
+ channel->callbacks->userdata);
+ }
+
+ SAFE_FREE(lang);
+ SAFE_FREE(errmsg);
SAFE_FREE(sig);
leave_function();
@@ -833,6 +920,7 @@ error:
return rc;
}
+
/**
* @brief Close and free a channel.
*
@@ -2572,6 +2660,117 @@ error:
return rc;
}
+/**
+ * @brief Send the exit status to the remote process (as described in RFC 4254, section 6.10).
+ *
+ * Sends the exit status to the remote process.
+ * Only SSH-v2 is supported (I'm not sure about SSH-v1).
+ *
+ * @param[in] channel The channel to send exit status.
+ *
+ * @param[in] sig The exit status to send
+ *
+ * @return SSH_OK on success, SSH_ERROR if an error occured
+ * (including attempts to send exit status via SSH-v1 session).
+ */
+int ssh_channel_request_send_exit_status(ssh_channel channel, int exit_status) {
+ ssh_buffer buffer = NULL;
+ int rc = SSH_ERROR;
+
+#ifdef WITH_SSH1
+ if (channel->version == 1) {
+ return SSH_ERROR; // TODO: Add support for SSH-v1 if possible.
+ }
+#endif
+
+ buffer = ssh_buffer_new();
+ if (buffer == NULL) {
+ goto error;
+ }
+
+ if (buffer_add_u32(buffer, ntohl(exit_status)) < 0) {
+ goto error;
+ }
+
+ rc = channel_request(channel, "exit-status", buffer, 0);
+error:
+ ssh_buffer_free(buffer);
+ return rc;
+}
+
+/**
+ * @brief Send an exit signal to remote process (as described in RFC 4254, section 6.10).
+ *
+ * Sends a signal 'sig' to the remote process.
+ * Note, that remote system may not support signals concept.
+ * In such a case this request will be silently ignored.
+ * Only SSH-v2 is supported (I'm not sure about SSH-v1).
+ *
+ * @param[in] channel The channel to send signal.
+ *
+ * @param[in] sig The signal to send (without SIG prefix)
+ * (e.g. "TERM" or "KILL").
+ * @param[in] core A boolean to tell if a core was dumped
+ * @param[in] errmsg A CRLF explanation text about the error condition
+ * @param[in] lang The language used in the message (format: RFC 3066)
+ *
+ * @return SSH_OK on success, SSH_ERROR if an error occured
+ * (including attempts to send signal via SSH-v1 session).
+ */
+int ssh_channel_request_send_exit_signal(ssh_channel channel, const char *sig, int core, const char *errmsg, const char *lang) {
+ ssh_buffer buffer = NULL;
+ ssh_string tmp = NULL;
+ int rc = SSH_ERROR;
+
+#ifdef WITH_SSH1
+ if (channel->version == 1) {
+ return SSH_ERROR; // TODO: Add support for SSH-v1 if possible.
+ }
+#endif
+
+ buffer = ssh_buffer_new();
+ if (buffer == NULL) {
+ goto error;
+ }
+
+ tmp = ssh_string_from_char(sig);
+ if (tmp == NULL) {
+ goto error;
+ }
+ if (buffer_add_ssh_string(buffer, tmp) < 0) {
+ goto error;
+ }
+
+ if (buffer_add_u8(buffer, core?1:0) < 0) {
+ goto error;
+ }
+
+ ssh_string_free(tmp);
+ tmp = ssh_string_from_char(errmsg);
+ if (tmp == NULL) {
+ goto error;
+ }
+ if (buffer_add_ssh_string(buffer, tmp) < 0) {
+ goto error;
+ }
+
+ ssh_string_free(tmp);
+ tmp = ssh_string_from_char(lang);
+ if (tmp == NULL) {
+ goto error;
+ }
+ if (buffer_add_ssh_string(buffer, tmp) < 0) {
+ goto error;
+ }
+
+ rc = channel_request(channel, "signal", buffer, 0);
+error:
+ ssh_buffer_free(buffer);
+ if(tmp)
+ ssh_string_free(tmp);
+ return rc;
+}
+
#endif
/* @} */