diff options
author | Andreas Schneider <asn@cynapses.org> | 2010-09-06 14:28:38 +0200 |
---|---|---|
committer | Andreas Schneider <asn@cynapses.org> | 2010-09-06 14:28:38 +0200 |
commit | f7842e3a4b9acea2126ff725f993c299aef0e6db (patch) | |
tree | 18239f819a5edbcfc7f2961c48f3f9297314ef22 /libssh/server.c | |
parent | 38421403d2dc45636e597f2a909daa6ae31976de (diff) | |
download | libssh-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.c | 1174 |
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: */ |