aboutsummaryrefslogtreecommitdiff
path: root/libssh/client.c
diff options
context:
space:
mode:
Diffstat (limited to 'libssh/client.c')
-rw-r--r--libssh/client.c814
1 files changed, 0 insertions, 814 deletions
diff --git a/libssh/client.c b/libssh/client.c
deleted file mode 100644
index d12aa117..00000000
--- a/libssh/client.c
+++ /dev/null
@@ -1,814 +0,0 @@
-/*
- * client.c - SSH client functions
- *
- * This file is part of the SSH Library
- *
- * Copyright (c) 2003-2008 by Aris Adamantiadis
- *
- * The SSH Library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or (at your
- * option) any later version.
- *
- * The SSH Library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
- * License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with the SSH Library; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- * MA 02111-1307, USA.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifndef _WIN32
-#include <arpa/inet.h>
-#endif
-
-#include "libssh/priv.h"
-#include "libssh/ssh2.h"
-#include "libssh/buffer.h"
-#include "libssh/packet.h"
-#include "libssh/socket.h"
-#include "libssh/session.h"
-#include "libssh/dh.h"
-
-#define set_status(session, status) do {\
- if (session->callbacks && session->callbacks->connect_status_function) \
- session->callbacks->connect_status_function(session->callbacks->userdata, status); \
- } while (0)
-
-/**
- * @internal
- * @brief Callback to be called when the socket is connected or had a
- * connection error. Changes the state of the session and updates the error
- * message.
- * @param code one of SSH_SOCKET_CONNECTED_OK or SSH_SOCKET_CONNECTED_ERROR
- * @param user is a pointer to session
- */
-static void socket_callback_connected(int code, int errno_code, void *user){
- ssh_session session=(ssh_session)user;
- enter_function();
- ssh_log(session,SSH_LOG_RARE,"Socket connection callback: %d (%d)",code, errno_code);
- if(code == SSH_SOCKET_CONNECTED_OK)
- session->session_state=SSH_SESSION_STATE_SOCKET_CONNECTED;
- else {
- session->session_state=SSH_SESSION_STATE_ERROR;
- ssh_set_error(session,SSH_FATAL,"%s",strerror(errno_code));
- }
- session->ssh_connection_callback(session);
- leave_function();
-}
-
-/**
- * @internal
- *
- * @brief Gets the banner from socket and saves it in session.
- * Updates the session state
- *
- * @param data pointer to the beginning of header
- * @param len size of the banner
- * @param user is a pointer to session
- * @returns Number of bytes processed, or zero if the banner is not complete.
- */
-static int callback_receive_banner(const void *data, size_t len, void *user) {
- char *buffer = (char *)data;
- ssh_session session=(ssh_session) user;
- char *str = NULL;
- size_t i;
- int ret=0;
- enter_function();
- for(i=0;i<len;++i){
-#ifdef WITH_PCAP
- if(session->pcap_ctx && buffer[i] == '\n'){
- ssh_pcap_context_write(session->pcap_ctx,SSH_PCAP_DIR_IN,buffer,i+1,i+1);
- }
-#endif
- if(buffer[i]=='\r')
- buffer[i]='\0';
- if(buffer[i]=='\n'){
- buffer[i]='\0';
- str=strdup(buffer);
- /* number of bytes read */
- ret=i+1;
- session->serverbanner=str;
- session->session_state=SSH_SESSION_STATE_BANNER_RECEIVED;
- ssh_log(session,SSH_LOG_PACKET,"Received banner: %s",str);
- session->ssh_connection_callback(session);
- leave_function();
- return ret;
- }
- if(i>127){
- /* Too big banner */
- session->session_state=SSH_SESSION_STATE_ERROR;
- ssh_set_error(session,SSH_FATAL,"Receiving banner: too large banner");
- leave_function();
- return 0;
- }
- }
- leave_function();
- return ret;
-}
-
-/**
- * @internal
- *
- * @brief Analyze the SSH banner to find out if we have a SSHv1 or SSHv2
- * server.
- *
- * @param session The session to analyze the banner from.
- * @param ssh1 The variable which is set if it is a SSHv1 server.
- * @param ssh2 The variable which is set if it is a SSHv2 server.
- *
- * @return 0 on success, < 0 on error.
- *
- * @see ssh_get_banner()
- */
-static int ssh_analyze_banner(ssh_session session, int *ssh1, int *ssh2) {
- const char *banner = session->serverbanner;
- const char *openssh;
-
- ssh_log(session, SSH_LOG_RARE, "Analyzing banner: %s", banner);
-
- if (strncmp(banner, "SSH-", 4) != 0) {
- ssh_set_error(session, SSH_FATAL, "Protocol mismatch: %s", banner);
- return -1;
- }
-
- /*
- * Typical banners e.g. are:
- * SSH-1.5-blah
- * SSH-1.99-blah
- * SSH-2.0-blah
- */
- switch(banner[4]) {
- case '1':
- *ssh1 = 1;
- if (banner[6] == '9') {
- *ssh2 = 1;
- } else {
- *ssh2 = 0;
- }
- break;
- case '2':
- *ssh1 = 0;
- *ssh2 = 1;
- break;
- default:
- ssh_set_error(session, SSH_FATAL, "Protocol mismatch: %s", banner);
- return -1;
- }
-
- openssh = strstr(banner, "OpenSSH");
- if (openssh != NULL) {
- int major, minor;
- major = strtol(openssh + 8, (char **) NULL, 10);
- minor = strtol(openssh + 10, (char **) NULL, 10);
- session->openssh = SSH_VERSION_INT(major, minor, 0);
- ssh_log(session, SSH_LOG_RARE,
- "We are talking to an OpenSSH server version: %d.%d (%x)",
- major, minor, session->openssh);
- }
-
- return 0;
-}
-
-/** @internal
- * @brief Sends a SSH banner to the server.
- *
- * @param session The SSH session to use.
- *
- * @param server Send client or server banner.
- *
- * @return 0 on success, < 0 on error.
- */
-int ssh_send_banner(ssh_session session, int server) {
- const char *banner = NULL;
- char buffer[128] = {0};
- int err=SSH_ERROR;
-
- enter_function();
-
- banner = session->version == 1 ? CLIENTBANNER1 : CLIENTBANNER2;
-
- if (session->xbanner) {
- banner = session->xbanner;
- }
-
- if (server) {
- session->serverbanner = strdup(banner);
- if (session->serverbanner == NULL) {
- goto end;
- }
- } else {
- session->clientbanner = strdup(banner);
- if (session->clientbanner == NULL) {
- goto end;
- }
- }
-
- snprintf(buffer, 128, "%s\n", banner);
-
- if (ssh_socket_write(session->socket, buffer, strlen(buffer)) == SSH_ERROR) {
- goto end;
- }
- if (ssh_socket_nonblocking_flush(session->socket) == SSH_ERROR){
- goto end;
- }
-#ifdef WITH_PCAP
- if(session->pcap_ctx)
- ssh_pcap_context_write(session->pcap_ctx,SSH_PCAP_DIR_OUT,buffer,strlen(buffer),strlen(buffer));
-#endif
- err=SSH_OK;
-end:
- leave_function();
- return err;
-}
-
-
-
-SSH_PACKET_CALLBACK(ssh_packet_dh_reply){
- ssh_string f = NULL;
- ssh_string pubkey = NULL;
- ssh_string signature = NULL;
- (void)type;
- (void)user;
- ssh_log(session,SSH_LOG_PROTOCOL,"Received SSH_KEXDH_REPLY");
- if(session->session_state!= SSH_SESSION_STATE_DH &&
- session->dh_handshake_state != DH_STATE_INIT_SENT){
- ssh_set_error(session,SSH_FATAL,"ssh_packet_dh_reply called in wrong state : %d:%d",
- session->session_state,session->dh_handshake_state);
- goto error;
- }
-
- pubkey = buffer_get_ssh_string(packet);
- if (pubkey == NULL){
- ssh_set_error(session,SSH_FATAL, "No public key in packet");
- goto error;
- }
- dh_import_pubkey(session, pubkey);
-
- f = buffer_get_ssh_string(packet);
- if (f == NULL) {
- ssh_set_error(session,SSH_FATAL, "No F number in packet");
- goto error;
- }
- if (dh_import_f(session, f) < 0) {
- ssh_set_error(session, SSH_FATAL, "Cannot import f number");
- goto error;
- }
- ssh_string_burn(f);
- ssh_string_free(f);
- f=NULL;
- signature = buffer_get_ssh_string(packet);
- if (signature == NULL) {
- ssh_set_error(session, SSH_FATAL, "No signature in packet");
- goto error;
- }
- session->dh_server_signature = signature;
- signature=NULL; /* ownership changed */
- if (dh_build_k(session) < 0) {
- ssh_set_error(session, SSH_FATAL, "Cannot build k number");
- goto error;
- }
-
- /* Send the MSG_NEWKEYS */
- if (buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
- goto error;
- }
-
- packet_send(session);
- ssh_log(session, SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
-
- session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
- return SSH_PACKET_USED;
-error:
- session->session_state=SSH_SESSION_STATE_ERROR;
- return SSH_PACKET_USED;
-}
-
-SSH_PACKET_CALLBACK(ssh_packet_newkeys){
- ssh_string signature = NULL;
- int rc;
- (void)packet;
- (void)user;
- (void)type;
- ssh_log(session, SSH_LOG_PROTOCOL, "Received SSH_MSG_NEWKEYS");
- if(session->session_state!= SSH_SESSION_STATE_DH &&
- session->dh_handshake_state != DH_STATE_NEWKEYS_SENT){
- ssh_set_error(session,SSH_FATAL,"ssh_packet_newkeys called in wrong state : %d:%d",
- session->session_state,session->dh_handshake_state);
- goto error;
- }
- if(session->server){
- /* server things are done in server.c */
- session->dh_handshake_state=DH_STATE_FINISHED;
- } else {
- /* client */
- rc = make_sessionid(session);
- if (rc != SSH_OK) {
- goto error;
- }
-
- /*
- * Set the cryptographic functions for the next crypto
- * (it is needed for generate_session_keys for key lengths)
- */
- if (crypt_set_algorithms(session)) {
- goto error;
- }
-
- if (generate_session_keys(session) < 0) {
- goto error;
- }
-
- /* Verify the host's signature. FIXME do it sooner */
- signature = session->dh_server_signature;
- session->dh_server_signature = NULL;
- if (signature_verify(session, signature)) {
- goto error;
- }
-
- /* forget it for now ... */
- ssh_string_burn(signature);
- ssh_string_free(signature);
- signature=NULL;
- /*
- * Once we got SSH2_MSG_NEWKEYS we can switch next_crypto and
- * current_crypto
- */
- if (session->current_crypto) {
- crypto_free(session->current_crypto);
- session->current_crypto=NULL;
- }
-
- /* FIXME later, include a function to change keys */
- session->current_crypto = session->next_crypto;
-
- session->next_crypto = crypto_new();
- if (session->next_crypto == NULL) {
- ssh_set_error_oom(session);
- goto error;
- }
- }
- session->dh_handshake_state = DH_STATE_FINISHED;
- session->ssh_connection_callback(session);
- return SSH_PACKET_USED;
-error:
- session->session_state=SSH_SESSION_STATE_ERROR;
- return SSH_PACKET_USED;
-}
-
-/** @internal
- * @brief launches the DH handshake state machine
- * @param session session handle
- * @returns SSH_OK or SSH_ERROR
- * @warning this function returning is no proof that DH handshake is
- * completed
- */
-static int dh_handshake(ssh_session session) {
- ssh_string e = NULL;
- ssh_string f = NULL;
- ssh_string signature = NULL;
- int rc = SSH_ERROR;
-
- enter_function();
-
- switch (session->dh_handshake_state) {
- case DH_STATE_INIT:
- if (buffer_add_u8(session->out_buffer, SSH2_MSG_KEXDH_INIT) < 0) {
- goto error;
- }
-
- if (dh_generate_x(session) < 0) {
- goto error;
- }
- if (dh_generate_e(session) < 0) {
- goto error;
- }
-
- e = dh_get_e(session);
- if (e == NULL) {
- goto error;
- }
-
- if (buffer_add_ssh_string(session->out_buffer, e) < 0) {
- goto error;
- }
- ssh_string_burn(e);
- ssh_string_free(e);
- e=NULL;
-
- rc = packet_send(session);
- if (rc == SSH_ERROR) {
- goto error;
- }
-
- session->dh_handshake_state = DH_STATE_INIT_SENT;
- case DH_STATE_INIT_SENT:
- /* wait until ssh_packet_dh_reply is called */
- break;
- case DH_STATE_NEWKEYS_SENT:
- /* wait until ssh_packet_newkeys is called */
- break;
- case DH_STATE_FINISHED:
- leave_function();
- return SSH_OK;
- default:
- ssh_set_error(session, SSH_FATAL, "Invalid state in dh_handshake(): %d",
- session->dh_handshake_state);
- leave_function();
- return SSH_ERROR;
- }
-
- leave_function();
- return SSH_AGAIN;
-error:
- if(e != NULL){
- ssh_string_burn(e);
- ssh_string_free(e);
- }
- if(f != NULL){
- ssh_string_burn(f);
- ssh_string_free(f);
- }
- if(signature != NULL){
- ssh_string_burn(signature);
- ssh_string_free(signature);
- }
-
- leave_function();
- return rc;
-}
-
-/**
- * @internal
- * @brief handles a SSH_SERVICE_ACCEPT packet
- *
- */
-SSH_PACKET_CALLBACK(ssh_packet_service_accept){
- (void)packet;
- (void)type;
- (void)user;
- enter_function();
- session->auth_service_state=SSH_AUTH_SERVICE_ACCEPTED;
- ssh_log(session, SSH_LOG_PACKET,
- "Received SSH_MSG_SERVICE_ACCEPT");
- leave_function();
- return SSH_PACKET_USED;
-}
-
-/**
- * @internal
- *
- * @brief Request a service from the SSH server.
- *
- * Service requests are for example: ssh-userauth, ssh-connection, etc.
- *
- * @param session The session to use to ask for a service request.
- * @param service The service request.
- *
- * @return SSH_OK on success
- * @return SSH_ERROR on error
- * @return SSH_AGAIN No response received yet
- * @bug actually only works with ssh-userauth
- */
-int ssh_service_request(ssh_session session, const char *service) {
- ssh_string service_s = NULL;
- int rc=SSH_ERROR;
- enter_function();
- switch(session->auth_service_state){
- case SSH_AUTH_SERVICE_NONE:
- if (buffer_add_u8(session->out_buffer, SSH2_MSG_SERVICE_REQUEST) < 0) {
- break;
- }
- service_s = ssh_string_from_char(service);
- if (service_s == NULL) {
- break;
- }
-
- if (buffer_add_ssh_string(session->out_buffer,service_s) < 0) {
- ssh_string_free(service_s);
- break;
- }
- ssh_string_free(service_s);
-
- if (packet_send(session) == SSH_ERROR) {
- ssh_set_error(session, SSH_FATAL,
- "Sending SSH2_MSG_SERVICE_REQUEST failed.");
- break;
- }
-
- ssh_log(session, SSH_LOG_PACKET,
- "Sent SSH_MSG_SERVICE_REQUEST (service %s)", service);
- session->auth_service_state=SSH_AUTH_SERVICE_SENT;
- rc=SSH_AGAIN;
- break;
- case SSH_AUTH_SERVICE_DENIED:
- ssh_set_error(session,SSH_FATAL,"ssh_auth_service request denied");
- break;
- case SSH_AUTH_SERVICE_ACCEPTED:
- rc=SSH_OK;
- break;
- case SSH_AUTH_SERVICE_SENT:
- rc=SSH_AGAIN;
- break;
- case SSH_AUTH_SERVICE_USER_SENT:
- /* Invalid state, SSH1 specific */
- rc=SSH_ERROR;
- break;
- }
-
- leave_function();
- return rc;
-}
-
-/**
- * @addtogroup libssh_session
- *
- * @{
- */
-
-/**
- * @internal
- *
- * @brief A function to be called each time a step has been done in the
- * connection.
- */
-static void ssh_client_connection_callback(ssh_session session){
- int ssh1,ssh2;
- enter_function();
- switch(session->session_state){
- case SSH_SESSION_STATE_NONE:
- case SSH_SESSION_STATE_CONNECTING:
- case SSH_SESSION_STATE_SOCKET_CONNECTED:
- break;
- case SSH_SESSION_STATE_BANNER_RECEIVED:
- if (session->serverbanner == NULL) {
- goto error;
- }
- set_status(session, 0.4f);
- ssh_log(session, SSH_LOG_RARE,
- "SSH server banner: %s", session->serverbanner);
-
- /* Here we analyze the different protocols the server allows. */
- if (ssh_analyze_banner(session, &ssh1, &ssh2) < 0) {
- goto error;
- }
- /* Here we decide which version of the protocol to use. */
- if (ssh2 && session->ssh2) {
- session->version = 2;
- } else if(ssh1 && session->ssh1) {
- session->version = 1;
- } else if(ssh1 && !session->ssh1){
-#ifdef WITH_SSH1
- ssh_set_error(session, SSH_FATAL,
- "SSH-1 protocol not available (configure session to allow SSH-1)");
- goto error;
-#else
- ssh_set_error(session, SSH_FATAL,
- "SSH-1 protocol not available (libssh compiled without SSH-1 support)");
- goto error;
-#endif
- } else {
- ssh_set_error(session, SSH_FATAL,
- "No version of SSH protocol usable (banner: %s)",
- session->serverbanner);
- goto error;
- }
- /* from now, the packet layer is handling incoming packets */
- if(session->version==2)
- session->socket_callbacks.data=ssh_packet_socket_callback;
-#ifdef WITH_SSH1
- else
- session->socket_callbacks.data=ssh_packet_socket_callback1;
-#endif
- ssh_packet_set_default_callbacks(session);
- ssh_send_banner(session, 0);
- set_status(session, 0.5f);
- session->session_state=SSH_SESSION_STATE_INITIAL_KEX;
- break;
- case SSH_SESSION_STATE_INITIAL_KEX:
- /* TODO: This state should disappear in favor of get_key handle */
-#ifdef WITH_SSH1
- if(session->version==1){
- if (ssh_get_kex1(session) < 0)
- goto error;
- set_status(session,0.6f);
- session->connected = 1;
- break;
- }
-#endif
- break;
- case SSH_SESSION_STATE_KEXINIT_RECEIVED:
- set_status(session,0.6f);
- ssh_list_kex(session, &session->server_kex);
- if (set_kex(session) < 0) {
- goto error;
- }
- if (ssh_send_kex(session, 0) < 0) {
- goto error;
- }
- set_status(session,0.8f);
- session->session_state=SSH_SESSION_STATE_DH;
- if (dh_handshake(session) == SSH_ERROR) {
- goto error;
- }
- case SSH_SESSION_STATE_DH:
- if(session->dh_handshake_state==DH_STATE_FINISHED){
- set_status(session,1.0f);
- session->connected = 1;
- session->session_state=SSH_SESSION_STATE_AUTHENTICATING;
- }
- break;
- case SSH_SESSION_STATE_AUTHENTICATING:
- break;
- case SSH_SESSION_STATE_ERROR:
- goto error;
- default:
- ssh_set_error(session,SSH_FATAL,"Invalid state %d",session->session_state);
- }
- leave_function();
- return;
- error:
- ssh_socket_close(session->socket);
- session->alive = 0;
- session->session_state=SSH_SESSION_STATE_ERROR;
- leave_function();
-}
-
-/**
- * @brief Connect to the ssh server.
- *
- * @param[in] session The ssh session to connect.
- *
- * @returns SSH_OK on success, SSH_ERROR on error.
- *
- * @see ssh_new()
- * @see ssh_disconnect()
- */
-int ssh_connect(ssh_session session) {
- int ret;
-
- if (session == NULL) {
- ssh_set_error(session, SSH_FATAL, "Invalid session pointer");
- return SSH_ERROR;
- }
-
- enter_function();
-
- session->alive = 0;
- session->client = 1;
-
- if (ssh_init() < 0) {
- leave_function();
- return SSH_ERROR;
- }
- if (session->fd == SSH_INVALID_SOCKET && session->host == NULL && session->ProxyCommand == NULL) {
- ssh_set_error(session, SSH_FATAL, "Hostname required");
- leave_function();
- return SSH_ERROR;
- }
-
- ret = ssh_options_apply(session);
- if (ret < 0) {
- ssh_set_error(session, SSH_FATAL, "Couldn't apply options");
- leave_function();
- return SSH_ERROR;
- }
-
- session->ssh_connection_callback = ssh_client_connection_callback;
- session->session_state=SSH_SESSION_STATE_CONNECTING;
- ssh_socket_set_callbacks(session->socket,&session->socket_callbacks);
- session->socket_callbacks.connected=socket_callback_connected;
- session->socket_callbacks.data=callback_receive_banner;
- session->socket_callbacks.exception=ssh_socket_exception_callback;
- session->socket_callbacks.userdata=session;
- if (session->fd != SSH_INVALID_SOCKET) {
- ssh_socket_set_fd(session->socket, session->fd);
- ret=SSH_OK;
-#ifndef _WIN32
- } else if (session->ProxyCommand != NULL){
- ret=ssh_socket_connect_proxycommand(session->socket, session->ProxyCommand);
-#endif
- } else {
- ret=ssh_socket_connect(session->socket, session->host, session->port,
- session->bindaddr);
-
- /*, session->timeout * 1000 + session->timeout_usec); */
- }
- if (ret == SSH_ERROR) {
- leave_function();
- return SSH_ERROR;
- }
-
- set_status(session, 0.2f);
-
- session->alive = 1;
- ssh_log(session,SSH_LOG_PROTOCOL,"Socket connecting, now waiting for the callbacks to work");
- while(session->session_state != SSH_SESSION_STATE_ERROR &&
- session->session_state != SSH_SESSION_STATE_AUTHENTICATING &&
- session->session_state != SSH_SESSION_STATE_DISCONNECTED){
- /* loop until SSH_SESSION_STATE_BANNER_RECEIVED or
- * SSH_SESSION_STATE_ERROR */
- ssh_handle_packets(session,-1);
- ssh_log(session,SSH_LOG_PACKET,"ssh_connect: Actual state : %d",session->session_state);
- }
- leave_function();
- if(session->session_state == SSH_SESSION_STATE_ERROR || session->session_state == SSH_SESSION_STATE_DISCONNECTED)
- return SSH_ERROR;
- return SSH_OK;
-}
-
-/**
- * @brief Get the issue banner from the server.
- *
- * This is the banner showing a disclaimer to users who log in,
- * typically their right or the fact that they will be monitored.
- *
- * @param[in] session The SSH session to use.
- *
- * @return A newly allocated string with the banner, NULL on error.
- */
-char *ssh_get_issue_banner(ssh_session session) {
- if (session == NULL || session->banner == NULL) {
- return NULL;
- }
-
- return ssh_string_to_char(session->banner);
-}
-
-/**
- * @brief Get the version of the OpenSSH server, if it is not an OpenSSH server
- * then 0 will be returned.
- *
- * You can use the SSH_VERSION_INT macro to compare version numbers.
- *
- * @param[in] session The SSH session to use.
- *
- * @return The version number if available, 0 otherwise.
- */
-int ssh_get_openssh_version(ssh_session session) {
- if (session == NULL) {
- return 0;
- }
-
- return session->openssh;
-}
-
-/**
- * @brief Disconnect from a session (client or server).
- * The session can then be reused to open a new session.
- *
- * @param[in] session The SSH session to use.
- */
-void ssh_disconnect(ssh_session session) {
- ssh_string str = NULL;
-
- if (session == NULL) {
- return;
- }
-
- enter_function();
-
- if (ssh_socket_is_open(session->socket)) {
- if (buffer_add_u8(session->out_buffer, SSH2_MSG_DISCONNECT) < 0) {
- goto error;
- }
- if (buffer_add_u32(session->out_buffer,
- htonl(SSH2_DISCONNECT_BY_APPLICATION)) < 0) {
- goto error;
- }
-
- str = ssh_string_from_char("Bye Bye");
- if (str == NULL) {
- goto error;
- }
-
- if (buffer_add_ssh_string(session->out_buffer,str) < 0) {
- ssh_string_free(str);
- goto error;
- }
- ssh_string_free(str);
-
- packet_send(session);
- ssh_socket_close(session->socket);
- }
- session->alive = 0;
-
-error:
- leave_function();
-}
-
-const char *ssh_copyright(void) {
- return SSH_STRINGIFY(LIBSSH_VERSION) " (c) 2003-2010 Aris Adamantiadis "
- "(aris@0xbadc0de.be) Distributed under the LGPL, please refer to COPYING"
- "file for information about your rights";
-}
-/** @} */
-
-/* vim: set ts=4 sw=4 et cindent: */