aboutsummaryrefslogtreecommitdiff
path: root/libssh/server.c
diff options
context:
space:
mode:
authorAndreas Schneider <asn@cynapses.org>2010-09-06 14:28:38 +0200
committerAndreas Schneider <asn@cynapses.org>2010-09-06 14:28:38 +0200
commitf7842e3a4b9acea2126ff725f993c299aef0e6db (patch)
tree18239f819a5edbcfc7f2961c48f3f9297314ef22 /libssh/server.c
parent38421403d2dc45636e597f2a909daa6ae31976de (diff)
downloadlibssh-f7842e3a4b9acea2126ff725f993c299aef0e6db.tar.gz
libssh-f7842e3a4b9acea2126ff725f993c299aef0e6db.tar.xz
libssh-f7842e3a4b9acea2126ff725f993c299aef0e6db.zip
misc: Rename libssh/ to src/
Diffstat (limited to 'libssh/server.c')
-rw-r--r--libssh/server.c1174
1 files changed, 0 insertions, 1174 deletions
diff --git a/libssh/server.c b/libssh/server.c
deleted file mode 100644
index e2367675..00000000
--- a/libssh/server.c
+++ /dev/null
@@ -1,1174 +0,0 @@
-/*
- * server.c - functions for creating a SSH server
- *
- * This file is part of the SSH Library
- *
- * Copyright (c) 2004-2005 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 "config.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include "libssh/priv.h"
-#include "libssh/libssh.h"
-#include "libssh/server.h"
-#include "libssh/ssh2.h"
-#include "libssh/keyfiles.h"
-#include "libssh/buffer.h"
-#include "libssh/packet.h"
-#include "libssh/socket.h"
-#include "libssh/channels.h"
-#include "libssh/session.h"
-#include "libssh/misc.h"
-#include "libssh/keys.h"
-#include "libssh/dh.h"
-#include "libssh/messages.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)
-
-static int dh_handshake_server(ssh_session session);
-
-
-/**
- * @addtogroup libssh_server
- *
- * @{
- */
-
-#ifdef _WIN32
-
-#include <winsock2.h>
-#define SOCKOPT_TYPE_ARG4 char
-
-/* We need to provide hstrerror. Not we can't call the parameter h_errno because it's #defined */
-static char *hstrerror(int h_errno_val) {
- static char text[50] = {0};
-
- snprintf(text, sizeof(text), "gethostbyname error %d\n", h_errno_val);
-
- return text;
-}
-#else /* _WIN32 */
-
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#define SOCKOPT_TYPE_ARG4 int
-
-#endif /* _WIN32 */
-
-/* TODO FIXME: must use getaddrinfo */
-static socket_t bind_socket(ssh_bind sshbind, const char *hostname,
- int port) {
- struct sockaddr_in myaddr;
- struct hostent *hp=NULL;
- socket_t s;
- int opt = 1;
-
- s = socket(PF_INET, SOCK_STREAM, 0);
- if (s < 0) {
- ssh_set_error(sshbind, SSH_FATAL, "%s", strerror(errno));
- return -1;
- }
-
-#ifdef HAVE_GETHOSTBYNAME
- hp = gethostbyname(hostname);
-#endif
-
- if (hp == NULL) {
- ssh_set_error(sshbind, SSH_FATAL,
- "Resolving %s: %s", hostname, hstrerror(h_errno));
- close(s);
- return -1;
- }
-
- memset(&myaddr, 0, sizeof(myaddr));
- memcpy(&myaddr.sin_addr, hp->h_addr, hp->h_length);
- myaddr.sin_family = hp->h_addrtype;
- myaddr.sin_port = htons(port);
-
- if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) < 0) {
- ssh_set_error(sshbind, SSH_FATAL,
- "Setting socket options failed: %s", hstrerror(h_errno));
- close(s);
- return -1;
- }
-
- if (bind(s, (struct sockaddr *) &myaddr, sizeof(myaddr)) < 0) {
- ssh_set_error(sshbind, SSH_FATAL, "Binding to %s:%d: %s",
- hostname,
- port,
- strerror(errno));
- close(s);
- return -1;
- }
-
- return s;
-}
-
-ssh_bind ssh_bind_new(void) {
- ssh_bind ptr;
-
- ptr = malloc(sizeof(struct ssh_bind_struct));
- if (ptr == NULL) {
- return NULL;
- }
- ZERO_STRUCTP(ptr);
- ptr->bindfd = SSH_INVALID_SOCKET;
- ptr->bindport= 22;
- ptr->log_verbosity = 0;
-
- return ptr;
-}
-
-int ssh_bind_listen(ssh_bind sshbind) {
- const char *host;
- socket_t fd;
-
- if (ssh_init() < 0) {
- return -1;
- }
-
- host = sshbind->bindaddr;
- if (host == NULL) {
- host = "0.0.0.0";
- }
-
- fd = bind_socket(sshbind, host, sshbind->bindport);
- if (fd == SSH_INVALID_SOCKET) {
- return -1;
- }
- sshbind->bindfd = fd;
-
- if (listen(fd, 10) < 0) {
- ssh_set_error(sshbind, SSH_FATAL,
- "Listening to socket %d: %s",
- fd, strerror(errno));
- close(fd);
- return -1;
- }
-
- return 0;
-}
-
-void ssh_bind_set_blocking(ssh_bind sshbind, int blocking) {
- sshbind->blocking = blocking ? 1 : 0;
-}
-
-socket_t ssh_bind_get_fd(ssh_bind sshbind) {
- return sshbind->bindfd;
-}
-
-void ssh_bind_set_fd(ssh_bind sshbind, socket_t fd) {
- sshbind->bindfd = fd;
-}
-
-void ssh_bind_fd_toaccept(ssh_bind sshbind) {
- sshbind->toaccept = 1;
-}
-
-void ssh_bind_free(ssh_bind sshbind){
- int i;
-
- if (sshbind == NULL) {
- return;
- }
-
- if (sshbind->bindfd >= 0) {
-#ifdef _WIN32
- closesocket(sshbind->bindfd);
-#else
- close(sshbind->bindfd);
-#endif
- }
- sshbind->bindfd = SSH_INVALID_SOCKET;
-
- /* options */
- SAFE_FREE(sshbind->banner);
- SAFE_FREE(sshbind->dsakey);
- SAFE_FREE(sshbind->rsakey);
- SAFE_FREE(sshbind->bindaddr);
-
- for (i = 0; i < 10; i++) {
- if (sshbind->wanted_methods[i]) {
- SAFE_FREE(sshbind->wanted_methods[i]);
- }
- }
-
- SAFE_FREE(sshbind);
-}
-
-extern char *supported_methods[];
-/** @internal
- * This functions sets the Key Exchange protocols to be accepted
- * by the server. They depend on
- * -What the user asked (via options)
- * -What is available (keys)
- * It should then accept the intersection of what the user asked
- * and what is available, and return an error if nothing matches
- */
-
-static int server_set_kex(ssh_session session) {
- KEX *server = &session->server_kex;
- int i, j;
- char *wanted;
-
- ZERO_STRUCTP(server);
- ssh_get_random(server->cookie, 16, 0);
- if (session->dsa_key != NULL && session->rsa_key != NULL) {
- if (ssh_options_set_algo(session, SSH_HOSTKEYS,
- "ssh-dss,ssh-rsa") < 0) {
- return -1;
- }
- } else if (session->dsa_key != NULL) {
- if (ssh_options_set_algo(session, SSH_HOSTKEYS, "ssh-dss") < 0) {
- return -1;
- }
- } else {
- if (ssh_options_set_algo(session, SSH_HOSTKEYS, "ssh-rsa") < 0) {
- return -1;
- }
- }
-
- server->methods = malloc(10 * sizeof(char **));
- if (server->methods == NULL) {
- return -1;
- }
-
- for (i = 0; i < 10; i++) {
- if ((wanted = session->wanted_methods[i]) == NULL) {
- wanted = supported_methods[i];
- }
- server->methods[i] = strdup(wanted);
- if (server->methods[i] == NULL) {
- for (j = i - 1; j <= 0; j--) {
- SAFE_FREE(server->methods[j]);
- }
- SAFE_FREE(server->methods);
- return -1;
- }
- }
-
- return 0;
-}
-
-SSH_PACKET_CALLBACK(ssh_packet_kexdh_init){
- ssh_string e;
- (void)type;
- (void)user;enter_function();
- ssh_log(session,SSH_LOG_PACKET,"Received SSH_MSG_KEXDH_INIT");
- if(session->dh_handshake_state != DH_STATE_INIT){
- ssh_log(session,SSH_LOG_RARE,"Invalid state for SSH_MSG_KEXDH_INIT");
- goto error;
- }
- e = buffer_get_ssh_string(packet);
- if (e == NULL) {
- ssh_set_error(session, SSH_FATAL, "No e number in client request");
- return -1;
- }
- if (dh_import_e(session, e) < 0) {
- ssh_set_error(session, SSH_FATAL, "Cannot import e number");
- session->session_state=SSH_SESSION_STATE_ERROR;
- } else {
- session->dh_handshake_state=DH_STATE_INIT_SENT;
- dh_handshake_server(session);
- }
- ssh_string_free(e);
-
- error:
- leave_function();
- return SSH_PACKET_USED;
-}
-
-static int dh_handshake_server(ssh_session session) {
- ssh_string f;
- ssh_string pubkey;
- ssh_string sign;
- ssh_public_key pub;
- ssh_private_key prv;
-
- if (dh_generate_y(session) < 0) {
- ssh_set_error(session, SSH_FATAL, "Could not create y number");
- return -1;
- }
- if (dh_generate_f(session) < 0) {
- ssh_set_error(session, SSH_FATAL, "Could not create f number");
- return -1;
- }
-
- f = dh_get_f(session);
- if (f == NULL) {
- ssh_set_error(session, SSH_FATAL, "Could not get the f number");
- return -1;
- }
-
- switch(session->hostkeys){
- case SSH_KEYTYPE_DSS:
- prv = session->dsa_key;
- break;
- case SSH_KEYTYPE_RSA:
- prv = session->rsa_key;
- break;
- default:
- prv = NULL;
- }
-
- pub = publickey_from_privatekey(prv);
- if (pub == NULL) {
- ssh_set_error(session, SSH_FATAL,
- "Could not get the public key from the private key");
- ssh_string_free(f);
- return -1;
- }
- pubkey = publickey_to_string(pub);
- publickey_free(pub);
- if (pubkey == NULL) {
- ssh_set_error(session, SSH_FATAL, "Not enough space");
- ssh_string_free(f);
- return -1;
- }
-
- dh_import_pubkey(session, pubkey);
- if (dh_build_k(session) < 0) {
- ssh_set_error(session, SSH_FATAL, "Could not import the public key");
- ssh_string_free(f);
- return -1;
- }
-
- if (make_sessionid(session) != SSH_OK) {
- ssh_set_error(session, SSH_FATAL, "Could not create a session id");
- ssh_string_free(f);
- return -1;
- }
-
- sign = ssh_sign_session_id(session, prv);
- if (sign == NULL) {
- ssh_set_error(session, SSH_FATAL, "Could not sign the session id");
- ssh_string_free(f);
- return -1;
- }
-
- /* Free private keys as they should not be readable after this point */
- if (session->rsa_key) {
- privatekey_free(session->rsa_key);
- session->rsa_key = NULL;
- }
- if (session->dsa_key) {
- privatekey_free(session->dsa_key);
- session->dsa_key = NULL;
- }
-
- if (buffer_add_u8(session->out_buffer, SSH2_MSG_KEXDH_REPLY) < 0 ||
- buffer_add_ssh_string(session->out_buffer, pubkey) < 0 ||
- buffer_add_ssh_string(session->out_buffer, f) < 0 ||
- buffer_add_ssh_string(session->out_buffer, sign) < 0) {
- ssh_set_error(session, SSH_FATAL, "Not enough space");
- buffer_reinit(session->out_buffer);
- ssh_string_free(f);
- ssh_string_free(sign);
- return -1;
- }
- ssh_string_free(f);
- ssh_string_free(sign);
- if (packet_send(session) == SSH_ERROR) {
- return -1;
- }
-
- if (buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
- buffer_reinit(session->out_buffer);
- return -1;
- }
-
- if (packet_send(session) == SSH_ERROR) {
- return -1;
- }
- ssh_log(session, SSH_LOG_PACKET, "SSH_MSG_NEWKEYS sent");
- session->dh_handshake_state=DH_STATE_NEWKEYS_SENT;
-
- return 0;
-}
-
-/**
- * @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->clientbanner;
- 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 client version: %d.%d (%x)",
- major, minor, session->openssh);
- }
-
- return 0;
-}
-
-/**
- * @internal
- *
- * @brief A function to be called each time a step has been done in the
- * connection.
- */
-static void ssh_server_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->clientbanner == NULL) {
- goto error;
- }
- set_status(session, 0.4f);
- ssh_log(session, SSH_LOG_RARE,
- "SSH client banner: %s", session->clientbanner);
-
- /* 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->clientbanner);
- 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);
- set_status(session, 0.5f);
- session->session_state=SSH_SESSION_STATE_INITIAL_KEX;
- if (ssh_send_kex(session, 1) < 0) {
- goto error;
- }
- 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->client_kex); // log client kex
- crypt_set_algorithms_server(session);
- if (set_kex(session) < 0) {
- goto error;
- }
- set_status(session,0.8f);
- session->session_state=SSH_SESSION_STATE_DH;
- break;
- case SSH_SESSION_STATE_DH:
- if(session->dh_handshake_state==DH_STATE_FINISHED){
- if (generate_session_keys(session) < 0) {
- goto error;
- }
-
- /*
- * Once we got SSH2_MSG_NEWKEYS we can switch next_crypto and
- * current_crypto
- */
- if (session->current_crypto) {
- crypto_free(session->current_crypto);
- }
-
- /* FIXME TODO later, include a function to change keys */
- session->current_crypto = session->next_crypto;
- session->next_crypto = crypto_new();
- if (session->next_crypto == NULL) {
- goto error;
- }
- 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();
-}
-
-/**
- * @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->clientbanner = 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;
-}
-
-int ssh_bind_accept(ssh_bind sshbind, ssh_session session) {
- ssh_private_key dsa = NULL;
- ssh_private_key rsa = NULL;
- socket_t fd = SSH_INVALID_SOCKET;
- int i;
-
- if (sshbind->bindfd == SSH_INVALID_SOCKET) {
- ssh_set_error(sshbind, SSH_FATAL,
- "Can't accept new clients on a not bound socket.");
- return SSH_ERROR;
- }
- if(session == NULL){
- ssh_set_error(sshbind, SSH_FATAL,"session is null");
- return SSH_ERROR;
- }
- if (sshbind->dsakey == NULL && sshbind->rsakey == NULL) {
- ssh_set_error(sshbind, SSH_FATAL,
- "DSA or RSA host key file must be set before accept()");
- return SSH_ERROR;
- }
-
- if (sshbind->dsakey) {
- dsa = _privatekey_from_file(sshbind, sshbind->dsakey, SSH_KEYTYPE_DSS);
- if (dsa == NULL) {
- return SSH_ERROR;
- }
- }
-
- if (sshbind->rsakey) {
- rsa = _privatekey_from_file(sshbind, sshbind->rsakey, SSH_KEYTYPE_RSA);
- if (rsa == NULL) {
- privatekey_free(dsa);
- return SSH_ERROR;
- }
- }
-
- fd = accept(sshbind->bindfd, NULL, NULL);
- if (fd == SSH_INVALID_SOCKET) {
- ssh_set_error(sshbind, SSH_FATAL,
- "Accepting a new connection: %s",
- strerror(errno));
- privatekey_free(dsa);
- privatekey_free(rsa);
- return SSH_ERROR;
- }
-
- session->server = 1;
- session->version = 2;
-
- /* copy options */
- for (i = 0; i < 10; ++i) {
- if (sshbind->wanted_methods[i]) {
- session->wanted_methods[i] = strdup(sshbind->wanted_methods[i]);
- if (session->wanted_methods[i] == NULL) {
- privatekey_free(dsa);
- privatekey_free(rsa);
- return SSH_ERROR;
- }
- }
- }
-
- if (sshbind->bindaddr == NULL)
- session->bindaddr = NULL;
- else {
- session->bindaddr = strdup(sshbind->bindaddr);
- if (session->bindaddr == NULL) {
- privatekey_free(dsa);
- privatekey_free(rsa);
- return SSH_ERROR;
- }
- }
-
- session->log_verbosity = sshbind->log_verbosity;
-
- ssh_socket_free(session->socket);
- session->socket = ssh_socket_new(session);
- if (session->socket == NULL) {
- privatekey_free(dsa);
- privatekey_free(rsa);
- return SSH_ERROR;
- }
- ssh_socket_set_fd(session->socket, fd);
- session->dsa_key = dsa;
- session->rsa_key = rsa;
-
-return SSH_OK;
-}
-
-/* Do the banner and key exchange */
-int ssh_handle_key_exchange(ssh_session session) {
- int rc;
-
- rc = ssh_send_banner(session, 1);
- if (rc < 0) {
- return SSH_ERROR;
- }
-
- session->alive = 1;
-
- session->ssh_connection_callback = ssh_server_connection_callback;
- session->session_state = SSH_SESSION_STATE_SOCKET_CONNECTED;
- ssh_socket_set_callbacks(session->socket,&session->socket_callbacks);
- session->socket_callbacks.data=callback_receive_banner;
- session->socket_callbacks.exception=ssh_socket_exception_callback;
- session->socket_callbacks.userdata=session;
-
- rc = server_set_kex(session);
- if (rc < 0) {
- return SSH_ERROR;
- }
-
- 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_accept: Actual state : %d",
- session->session_state);
- }
-
- if (session->session_state == SSH_SESSION_STATE_ERROR ||
- session->session_state == SSH_SESSION_STATE_DISCONNECTED) {
- return SSH_ERROR;
- }
-
- return SSH_OK;
-}
-
-/**
- * @brief Blocking write on channel for stderr.
- *
- * @param channel The channel to write to.
- *
- * @param data A pointer to the data to write.
- *
- * @param len The length of the buffer to write to.
- *
- * @return The number of bytes written, SSH_ERROR on error.
- *
- * @see channel_read()
- */
-int channel_write_stderr(ssh_channel channel, const void *data, uint32_t len) {
- return channel_write_common(channel, data, len, 1);
-}
-
-/* messages */
-
-static int ssh_message_auth_reply_default(ssh_message msg,int partial) {
- ssh_session session = msg->session;
- char methods_c[128] = {0};
- ssh_string methods = NULL;
- int rc = SSH_ERROR;
-
- enter_function();
-
- if (buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_FAILURE) < 0) {
- return rc;
- }
-
- if (session->auth_methods == 0) {
- session->auth_methods = SSH_AUTH_METHOD_PUBLICKEY | SSH_AUTH_METHOD_PASSWORD;
- }
- if (session->auth_methods & SSH_AUTH_METHOD_PUBLICKEY) {
- strcat(methods_c, "publickey,");
- }
- if (session->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) {
- strcat(methods_c, "keyboard-interactive,");
- }
- if (session->auth_methods & SSH_AUTH_METHOD_PASSWORD) {
- strcat(methods_c, "password,");
- }
- if (session->auth_methods & SSH_AUTH_METHOD_HOSTBASED) {
- strcat(methods_c, "hostbased,");
- }
-
- /* Strip the comma. */
- methods_c[strlen(methods_c) - 1] = '\0'; // strip the comma. We are sure there is at
-
- ssh_log(session, SSH_LOG_PACKET,
- "Sending a auth failure. methods that can continue: %s", methods_c);
-
- methods = ssh_string_from_char(methods_c);
- if (methods == NULL) {
- goto error;
- }
-
- if (buffer_add_ssh_string(msg->session->out_buffer, methods) < 0) {
- goto error;
- }
-
- if (partial) {
- if (buffer_add_u8(session->out_buffer, 1) < 0) {
- goto error;
- }
- } else {
- if (buffer_add_u8(session->out_buffer, 0) < 0) {
- goto error;
- }
- }
-
- rc = packet_send(msg->session);
-error:
- ssh_string_free(methods);
-
- leave_function();
- return rc;
-}
-
-static int ssh_message_channel_request_open_reply_default(ssh_message msg) {
- ssh_log(msg->session, SSH_LOG_FUNCTIONS, "Refusing a channel");
-
- if (buffer_add_u8(msg->session->out_buffer
- , SSH2_MSG_CHANNEL_OPEN_FAILURE) < 0) {
- goto error;
- }
- if (buffer_add_u32(msg->session->out_buffer,
- htonl(msg->channel_request_open.sender)) < 0) {
- goto error;
- }
- if (buffer_add_u32(msg->session->out_buffer,
- htonl(SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED)) < 0) {
- goto error;
- }
- /* reason is an empty string */
- if (buffer_add_u32(msg->session->out_buffer, 0) < 0) {
- goto error;
- }
- /* language too */
- if (buffer_add_u32(msg->session->out_buffer, 0) < 0) {
- goto error;
- }
-
- return packet_send(msg->session);
-error:
- return SSH_ERROR;
-}
-
-static int ssh_message_channel_request_reply_default(ssh_message msg) {
- uint32_t channel;
-
- if (msg->channel_request.want_reply) {
- channel = msg->channel_request.channel->remote_channel;
-
- ssh_log(msg->session, SSH_LOG_PACKET,
- "Sending a default channel_request denied to channel %d", channel);
-
- if (buffer_add_u8(msg->session->out_buffer, SSH2_MSG_CHANNEL_FAILURE) < 0) {
- return SSH_ERROR;
- }
- if (buffer_add_u32(msg->session->out_buffer, htonl(channel)) < 0) {
- return SSH_ERROR;
- }
-
- return packet_send(msg->session);
- }
-
- ssh_log(msg->session, SSH_LOG_PACKET,
- "The client doesn't want to know the request failed!");
-
- return SSH_OK;
-}
-
-static int ssh_message_service_request_reply_default(ssh_message msg) {
- /* The only return code accepted by specifications are success or disconnect */
- return ssh_message_service_reply_success(msg);
-}
-
-int ssh_message_service_reply_success(ssh_message msg) {
- struct ssh_string_struct *service;
- ssh_session session=msg->session;
- if (msg == NULL) {
- return SSH_ERROR;
- }
- ssh_log(session, SSH_LOG_PACKET,
- "Sending a SERVICE_ACCEPT for service %s", msg->service_request.service);
- if (buffer_add_u8(session->out_buffer, SSH2_MSG_SERVICE_ACCEPT) < 0) {
- return -1;
- }
- service=ssh_string_from_char(msg->service_request.service);
- if (buffer_add_ssh_string(session->out_buffer, service) < 0) {
- ssh_string_free(service);
- return -1;
- }
- ssh_string_free(service);
- return packet_send(msg->session);
-}
-
-int ssh_message_reply_default(ssh_message msg) {
- if (msg == NULL) {
- return -1;
- }
-
- switch(msg->type) {
- case SSH_REQUEST_AUTH:
- return ssh_message_auth_reply_default(msg, 0);
- case SSH_REQUEST_CHANNEL_OPEN:
- return ssh_message_channel_request_open_reply_default(msg);
- case SSH_REQUEST_CHANNEL:
- return ssh_message_channel_request_reply_default(msg);
- case SSH_REQUEST_SERVICE:
- return ssh_message_service_request_reply_default(msg);
- default:
- ssh_log(msg->session, SSH_LOG_PACKET,
- "Don't know what to default reply to %d type",
- msg->type);
- break;
- }
-
- return -1;
-}
-
-char *ssh_message_service_service(ssh_message msg){
- if (msg == NULL) {
- return NULL;
- }
- return msg->service_request.service;
-}
-
-char *ssh_message_auth_user(ssh_message msg) {
- if (msg == NULL) {
- return NULL;
- }
-
- return msg->auth_request.username;
-}
-
-char *ssh_message_auth_password(ssh_message msg){
- if (msg == NULL) {
- return NULL;
- }
-
- return msg->auth_request.password;
-}
-
-/* Get the publickey of an auth request */
-ssh_public_key ssh_message_auth_publickey(ssh_message msg){
- if (msg == NULL) {
- return NULL;
- }
-
- return msg->auth_request.public_key;
-}
-
-enum ssh_publickey_state_e ssh_message_auth_publickey_state(ssh_message msg){
- if (msg == NULL) {
- return -1;
- }
- return msg->auth_request.signature_state;
-}
-
-int ssh_message_auth_set_methods(ssh_message msg, int methods) {
- if (msg == NULL || msg->session == NULL) {
- return -1;
- }
-
- msg->session->auth_methods = methods;
-
- return 0;
-}
-
-int ssh_message_auth_reply_success(ssh_message msg, int partial) {
- if (msg == NULL) {
- return SSH_ERROR;
- }
-
- if (partial) {
- return ssh_message_auth_reply_default(msg, partial);
- }
-
- if (buffer_add_u8(msg->session->out_buffer,SSH2_MSG_USERAUTH_SUCCESS) < 0) {
- return SSH_ERROR;
- }
-
- return packet_send(msg->session);
-}
-
-/* Answer OK to a pubkey auth request */
-int ssh_message_auth_reply_pk_ok(ssh_message msg, ssh_string algo, ssh_string pubkey) {
- if (msg == NULL) {
- return SSH_ERROR;
- }
-
- if (buffer_add_u8(msg->session->out_buffer, SSH2_MSG_USERAUTH_PK_OK) < 0 ||
- buffer_add_ssh_string(msg->session->out_buffer, algo) < 0 ||
- buffer_add_ssh_string(msg->session->out_buffer, pubkey) < 0) {
- return SSH_ERROR;
- }
-
- return packet_send(msg->session);
-}
-
-int ssh_message_auth_reply_pk_ok_simple(ssh_message msg) {
- ssh_string algo;
- ssh_string pubkey;
- int ret;
- algo=ssh_string_from_char(msg->auth_request.public_key->type_c);
- pubkey=publickey_to_string(msg->auth_request.public_key);
- ret=ssh_message_auth_reply_pk_ok(msg,algo,pubkey);
- ssh_string_free(algo);
- ssh_string_free(pubkey);
- return ret;
-}
-
-
-char *ssh_message_channel_request_open_originator(ssh_message msg){
- return msg->channel_request_open.originator;
-}
-
-int ssh_message_channel_request_open_originator_port(ssh_message msg){
- return msg->channel_request_open.originator_port;
-}
-
-char *ssh_message_channel_request_open_destination(ssh_message msg){
- return msg->channel_request_open.destination;
-}
-
-int ssh_message_channel_request_open_destination_port(ssh_message msg){
- return msg->channel_request_open.destination_port;
-}
-
-ssh_channel ssh_message_channel_request_channel(ssh_message msg){
- return msg->channel_request.channel;
-}
-
-char *ssh_message_channel_request_pty_term(ssh_message msg){
- return msg->channel_request.TERM;
-}
-
-int ssh_message_channel_request_pty_width(ssh_message msg){
- return msg->channel_request.width;
-}
-
-int ssh_message_channel_request_pty_height(ssh_message msg){
- return msg->channel_request.height;
-}
-
-int ssh_message_channel_request_pty_pxwidth(ssh_message msg){
- return msg->channel_request.pxwidth;
-}
-
-int ssh_message_channel_request_pty_pxheight(ssh_message msg){
- return msg->channel_request.pxheight;
-}
-
-char *ssh_message_channel_request_env_name(ssh_message msg){
- return msg->channel_request.var_name;
-}
-
-char *ssh_message_channel_request_env_value(ssh_message msg){
- return msg->channel_request.var_value;
-}
-
-char *ssh_message_channel_request_command(ssh_message msg){
- return msg->channel_request.command;
-}
-
-char *ssh_message_channel_request_subsystem(ssh_message msg){
- return msg->channel_request.subsystem;
-}
-
-/** @brief defines the SSH_MESSAGE callback
- * @param session the current ssh session
- * @param[in] ssh_message_callback_ a function pointer to a callback taking the
- * current ssh session and received message as parameters. the function returns
- * 0 if the message has been parsed and treated sucessfuly, 1 otherwise (libssh
- * must take care of the response).
- * @param[in] data void pointer to be passed to callback functions
- */
-void ssh_set_message_callback(ssh_session session,
- int(*ssh_bind_message_callback)(ssh_session session, ssh_message msg, void *data),
- void *data) {
- session->ssh_message_callback = ssh_bind_message_callback;
- session->ssh_message_callback_data = data;
-}
-
-int ssh_execute_message_callbacks(ssh_session session){
- ssh_message msg=NULL;
- int ret;
- ssh_handle_packets(session, 0);
- if(!session->ssh_message_list)
- return SSH_OK;
- if(session->ssh_message_callback){
- while((msg=ssh_message_pop_head(session)) != NULL) {
- ret=session->ssh_message_callback(session,msg,
- session->ssh_message_callback_data);
- if(ret==1){
- ret = ssh_message_reply_default(msg);
- ssh_message_free(msg);
- if(ret != SSH_OK)
- return ret;
- } else {
- ssh_message_free(msg);
- }
- }
- } else {
- while((msg=ssh_message_pop_head(session)) != NULL) {
- ret = ssh_message_reply_default(msg);
- ssh_message_free(msg);
- if(ret != SSH_OK)
- return ret;
- }
- }
- return SSH_OK;
-}
-
-/** @} */
-
-/* vim: set ts=4 sw=4 et cindent: */