aboutsummaryrefslogtreecommitdiff
path: root/libssh
diff options
context:
space:
mode:
Diffstat (limited to 'libssh')
-rw-r--r--libssh/CMakeLists.txt204
-rw-r--r--libssh/agent.c502
-rw-r--r--libssh/auth.c1682
-rw-r--r--libssh/auth1.c206
-rw-r--r--libssh/base64.c287
-rw-r--r--libssh/buffer.c578
-rw-r--r--libssh/callbacks.c43
-rw-r--r--libssh/channels.c2495
-rw-r--r--libssh/channels1.c298
-rw-r--r--libssh/client.c814
-rw-r--r--libssh/config.c347
-rw-r--r--libssh/connect.c600
-rw-r--r--libssh/crc32.c92
-rw-r--r--libssh/crypt.c216
-rw-r--r--libssh/dh.c1049
-rw-r--r--libssh/error.c123
-rw-r--r--libssh/gcrypt_missing.c99
-rw-r--r--libssh/gzip.c222
-rw-r--r--libssh/init.c94
-rw-r--r--libssh/kex.c835
-rw-r--r--libssh/keyfiles.c1902
-rw-r--r--libssh/keys.c1497
-rw-r--r--libssh/legacy.c237
-rw-r--r--libssh/libcrypto.c443
-rw-r--r--libssh/libgcrypt.c423
-rw-r--r--libssh/log.c82
-rw-r--r--libssh/match.c185
-rw-r--r--libssh/messages.c848
-rw-r--r--libssh/misc.c685
-rw-r--r--libssh/options.c1138
-rw-r--r--libssh/packet.c529
-rw-r--r--libssh/packet1.c362
-rw-r--r--libssh/pcap.c434
-rw-r--r--libssh/pki.c113
-rw-r--r--libssh/poll.c692
-rw-r--r--libssh/scp.c752
-rw-r--r--libssh/server.c1174
-rw-r--r--libssh/session.c520
-rw-r--r--libssh/sftp.c3207
-rw-r--r--libssh/sftpserver.c490
-rw-r--r--libssh/socket.c719
-rw-r--r--libssh/string.c212
-rw-r--r--libssh/threads.c159
-rw-r--r--libssh/wrapper.c325
44 files changed, 0 insertions, 27914 deletions
diff --git a/libssh/CMakeLists.txt b/libssh/CMakeLists.txt
deleted file mode 100644
index b158ae6c..00000000
--- a/libssh/CMakeLists.txt
+++ /dev/null
@@ -1,204 +0,0 @@
-project(libssh-library C)
-
-set(LIBSSH_PUBLIC_INCLUDE_DIRS
- ${CMAKE_SOURCE_DIR}/include
- ${CMAKE_CURRENT_SOURCE_DIR}
- ${CMAKE_SOURCE_DIR}
- CACHE INTERNAL "libssh public include directories"
-)
-
-set(LIBSSH_PRIVATE_INCLUDE_DIRS
- ${CMAKE_BINARY_DIR}
- ${ZLIB_INCLUDE_DIRS}
-)
-
-set(LIBSSH_SHARED_LIBRARY
- ssh_shared
- CACHE INTERNAL "libssh shared library"
-)
-
-if (WITH_STATIC_LIB)
- set(LIBSSH_STATIC_LIBRARY
- ssh_static
- CACHE INTERNAL "libssh static library"
- )
-endif (WITH_STATIC_LIB)
-
-set(LIBSSH_LINK_LIBRARIES
- ${LIBSSH_REQUIRED_LIBRARIES}
- ${ZLIB_LIBRARIES}
-)
-
-if (WIN32)
- set(LIBSSH_LINK_LIBRARIES
- ${LIBSSH_LINK_LIBRARIES}
- ws2_32
- )
-endif (WIN32)
-
-if (HAVE_LIBSOCKET)
- set(LIBSSH_LINK_LIBRARIES
- ${LIBSSH_LINK_LIBRARIES}
- socket
- )
-endif (HAVE_LIBSOCKET)
-
-if (OPENSSL_LIBRARIES)
- set(LIBSSH_PRIVATE_INCLUDE_DIRS
- ${LIBSSH_PRIVATE_INCLUDE_DIRS}
- ${OPENSSL_INCLUDE_DIRS}
- )
-
- set(LIBSSH_LINK_LIBRARIES
- ${LIBSSH_LINK_LIBRARIES}
- ${OPENSSL_LIBRARIES}
- )
-endif (OPENSSL_LIBRARIES)
-
-if (GCRYPT_LIBRARY)
- set(LIBSSH_PRIVATE_INCLUDE_DIRS
- ${LIBSSH_PRIVATE_INCLUDE_DIRS}
- ${GCRYPT_INCLUDE_DIRS}
- )
-
- set(LIBSSH_LINK_LIBRARIES
- ${LIBSSH_LINK_LIBRARIES}
- ${GCRYPT_LIBRARY}
- )
-endif (GCRYPT_LIBRARY)
-
-set(LIBSSH_LINK_LIBRARIES
- ${LIBSSH_LINK_LIBRARIES}
- CACHE INTERNAL "libssh link libraries"
-)
-
-set(libssh_SRCS
- agent.c
- auth.c
- base64.c
- buffer.c
- callbacks.c
- channels.c
- client.c
- config.c
- connect.c
- crc32.c
- crypt.c
- dh.c
- error.c
- gcrypt_missing.c
- gzip.c
- init.c
- kex.c
- keyfiles.c
- keys.c
- legacy.c
- libcrypto.c
- libgcrypt.c
- log.c
- match.c
- messages.c
- misc.c
- options.c
- packet.c
- pcap.c
- pki.c
- poll.c
- session.c
- scp.c
- socket.c
- string.c
- threads.c
- wrapper.c
-)
-
-if (WITH_SFTP)
- set(libssh_SRCS
- ${libssh_SRCS}
- sftp.c
- )
-
- if (WITH_SERVER)
- set(libssh_SRCS
- ${libssh_SRCS}
- sftpserver.c
- )
- endif (WITH_SERVER)
-endif (WITH_SFTP)
-
-if (WITH_SSH1)
- set(libssh_SRCS
- ${libssh_SRCS}
- auth1.c
- channels1.c
- packet1.c
- )
-endif (WITH_SSH1)
-
-if (WITH_SERVER)
- set(libssh_SRCS
- ${libssh_SRCS}
- server.c
- )
-endif (WITH_SERVER)
-
-include_directories(
- ${LIBSSH_PUBLIC_INCLUDE_DIRS}
- ${LIBSSH_PRIVATE_INCLUDE_DIRS}
-)
-
-add_library(${LIBSSH_SHARED_LIBRARY} SHARED ${libssh_SRCS})
-
-target_link_libraries(${LIBSSH_SHARED_LIBRARY} ${LIBSSH_LINK_LIBRARIES})
-
-set_target_properties(
- ${LIBSSH_SHARED_LIBRARY}
- PROPERTIES
- VERSION
- ${LIBRARY_VERSION}
- SOVERSION
- ${LIBRARY_SOVERSION}
- OUTPUT_NAME
- ssh
- DEFINE_SYMBOL
- LIBSSH_EXPORTS
-)
-
-if (WITH_VISIBILITY_HIDDEN)
- set_target_properties(${LIBSSH_SHARED_LIBRARY} PROPERTIES COMPILE_FLAGS "-fvisibility=hidden")
-endif (WITH_VISIBILITY_HIDDEN)
-
-
-install(
- TARGETS
- ${LIBSSH_SHARED_LIBRARY}
- RUNTIME DESTINATION ${BIN_INSTALL_DIR}
- LIBRARY DESTINATION ${LIB_INSTALL_DIR}
- ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
- COMPONENT libraries
-)
-
-if (WITH_STATIC_LIB)
- add_library(${LIBSSH_STATIC_LIBRARY} STATIC ${libssh_SRCS})
-
- set_target_properties(
- ${LIBSSH_STATIC_LIBRARY}
- PROPERTIES
- VERSION
- ${LIBRARY_VERSION}
- SOVERSION
- ${LIBRARY_SOVERSION}
- COMPILE_FLAGS
- "-DLIBSSH_STATIC"
- )
-
- install(
- TARGETS
- ${LIBSSH_STATIC_LIBRARY}
- DESTINATION
- ${LIB_INSTALL_DIR}
- COMPONENT
- libraries
- )
-endif (WITH_STATIC_LIB)
-
diff --git a/libssh/agent.c b/libssh/agent.c
deleted file mode 100644
index 16b38b8c..00000000
--- a/libssh/agent.c
+++ /dev/null
@@ -1,502 +0,0 @@
-/*
- * agent.c - ssh agent functions
- *
- * This file is part of the SSH Library
- *
- * Copyright (c) 2008-2009 by Andreas Schneider <mail@cynapses.org>
- *
- * 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.
- */
-
-/* This file is based on authfd.c from OpenSSH */
-
-/*
- * How does the ssh-agent work?
- *
- * a) client sends a request to get a list of all keys
- * the agent returns the count and all public keys
- * b) iterate over them to check if the server likes one
- * c) the client sends a sign request to the agent
- * type, pubkey as blob, data to sign, flags
- * the agent returns the signed data
- */
-
-#ifndef _WIN32
-
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-#include <stdio.h>
-
-#include <unistd.h>
-
-#ifndef _WIN32
-#include <arpa/inet.h>
-#endif
-
-#include "libssh/agent.h"
-#include "libssh/priv.h"
-#include "libssh/socket.h"
-#include "libssh/buffer.h"
-#include "libssh/session.h"
-#include "libssh/keys.h"
-#include "libssh/poll.h"
-
-/* macro to check for "agent failure" message */
-#define agent_failed(x) \
- (((x) == SSH_AGENT_FAILURE) || ((x) == SSH_COM_AGENT2_FAILURE) || \
- ((x) == SSH2_AGENT_FAILURE))
-
-static uint32_t agent_get_u32(const void *vp) {
- const uint8_t *p = (const uint8_t *)vp;
- uint32_t v;
-
- v = (uint32_t)p[0] << 24;
- v |= (uint32_t)p[1] << 16;
- v |= (uint32_t)p[2] << 8;
- v |= (uint32_t)p[3];
-
- return v;
-}
-
-static void agent_put_u32(void *vp, uint32_t v) {
- uint8_t *p = (uint8_t *)vp;
-
- p[0] = (uint8_t)(v >> 24) & 0xff;
- p[1] = (uint8_t)(v >> 16) & 0xff;
- p[2] = (uint8_t)(v >> 8) & 0xff;
- p[3] = (uint8_t)v & 0xff;
-}
-
-static size_t atomicio(ssh_socket s, void *buf, size_t n, int do_read) {
- char *b = buf;
- size_t pos = 0;
- ssize_t res;
- ssh_pollfd_t pfd;
- socket_t fd = ssh_socket_get_fd_in(s);
-
- pfd.fd = fd;
- pfd.events = do_read ? POLLIN : POLLOUT;
-
- while (n > pos) {
- if (do_read) {
- res = read(fd, b + pos, n - pos);
- } else {
- res = write(fd, b + pos, n - pos);
- }
- switch (res) {
- case -1:
- if (errno == EINTR) {
- continue;
- }
-#ifdef EWOULDBLOCK
- if (errno == EAGAIN || errno == EWOULDBLOCK) {
-#else
- if (errno == EAGAIN) {
-#endif
- (void) ssh_poll(&pfd, 1, -1);
- continue;
- }
- return 0;
- case 0:
- errno = EPIPE;
- return pos;
- default:
- pos += (size_t) res;
- }
- }
-
- return pos;
-}
-
-ssh_agent agent_new(struct ssh_session_struct *session) {
- ssh_agent agent = NULL;
-
- agent = malloc(sizeof(struct ssh_agent_struct));
- if (agent == NULL) {
- return NULL;
- }
- ZERO_STRUCTP(agent);
-
- agent->count = 0;
- agent->sock = ssh_socket_new(session);
- if (agent->sock == NULL) {
- SAFE_FREE(agent);
- return NULL;
- }
-
- return agent;
-}
-
-void agent_close(struct ssh_agent_struct *agent) {
- if (agent == NULL) {
- return;
- }
-
- if (getenv("SSH_AUTH_SOCK")) {
- ssh_socket_close(agent->sock);
- }
-}
-
-void agent_free(ssh_agent agent) {
- if (agent) {
- if (agent->ident) {
- ssh_buffer_free(agent->ident);
- }
- if (agent->sock) {
- agent_close(agent);
- ssh_socket_free(agent->sock);
- }
- SAFE_FREE(agent);
- }
-}
-
-static int agent_connect(ssh_session session) {
- const char *auth_sock = NULL;
-
- if (session == NULL || session->agent == NULL) {
- return -1;
- }
-
- auth_sock = getenv("SSH_AUTH_SOCK");
-
- if (auth_sock && *auth_sock) {
- if (ssh_socket_unix(session->agent->sock, auth_sock) < 0) {
- return -1;
- }
- return 0;
- }
-
- return -1;
-}
-
-#if 0
-static int agent_decode_reply(struct ssh_session_struct *session, int type) {
- switch (type) {
- case SSH_AGENT_FAILURE:
- case SSH2_AGENT_FAILURE:
- case SSH_COM_AGENT2_FAILURE:
- ssh_log(session, SSH_LOG_RARE, "SSH_AGENT_FAILURE");
- return 0;
- case SSH_AGENT_SUCCESS:
- return 1;
- default:
- ssh_set_error(session, SSH_FATAL,
- "Bad response from authentication agent: %d", type);
- break;
- }
-
- return -1;
-}
-#endif
-
-static int agent_talk(struct ssh_session_struct *session,
- struct ssh_buffer_struct *request, struct ssh_buffer_struct *reply) {
- uint32_t len = 0;
- uint8_t payload[1024] = {0};
-
- len = ssh_buffer_get_len(request);
- ssh_log(session, SSH_LOG_PACKET, "agent_talk - len of request: %u", len);
- agent_put_u32(payload, len);
-
- /* send length and then the request packet */
- if (atomicio(session->agent->sock, payload, 4, 0) == 4) {
- if (atomicio(session->agent->sock, buffer_get_rest(request), len, 0)
- != len) {
- ssh_log(session, SSH_LOG_PACKET, "atomicio sending request failed: %s",
- strerror(errno));
- return -1;
- }
- } else {
- ssh_log(session, SSH_LOG_PACKET,
- "atomicio sending request length failed: %s",
- strerror(errno));
- return -1;
- }
-
- /* wait for response, read the length of the response packet */
- if (atomicio(session->agent->sock, payload, 4, 1) != 4) {
- ssh_log(session, SSH_LOG_PACKET, "atomicio read response length failed: %s",
- strerror(errno));
- return -1;
- }
-
- len = agent_get_u32(payload);
- if (len > 256 * 1024) {
- ssh_set_error(session, SSH_FATAL,
- "Authentication response too long: %u", len);
- return -1;
- }
- ssh_log(session, SSH_LOG_PACKET, "agent_talk - response length: %u", len);
-
- while (len > 0) {
- size_t n = len;
- if (n > sizeof(payload)) {
- n = sizeof(payload);
- }
- if (atomicio(session->agent->sock, payload, n, 1) != n) {
- ssh_log(session, SSH_LOG_RARE,
- "Error reading response from authentication socket.");
- return -1;
- }
- if (buffer_add_data(reply, payload, n) < 0) {
- ssh_log(session, SSH_LOG_FUNCTIONS,
- "Not enough space");
- return -1;
- }
- len -= n;
- }
-
- return 0;
-}
-
-int agent_get_ident_count(struct ssh_session_struct *session) {
- ssh_buffer request = NULL;
- ssh_buffer reply = NULL;
- unsigned int type = 0;
- unsigned int c1 = 0, c2 = 0;
- uint8_t buf[4] = {0};
-
- switch (session->version) {
- case 1:
- c1 = SSH_AGENTC_REQUEST_RSA_IDENTITIES;
- c2 = SSH_AGENT_RSA_IDENTITIES_ANSWER;
- break;
- case 2:
- c1 = SSH2_AGENTC_REQUEST_IDENTITIES;
- c2 = SSH2_AGENT_IDENTITIES_ANSWER;
- break;
- default:
- return 0;
- }
-
- /* send message to the agent requesting the list of identities */
- request = ssh_buffer_new();
- if (buffer_add_u8(request, c1) < 0) {
- ssh_set_error(session, SSH_FATAL, "Not enough space");
- return -1;
- }
-
- reply = ssh_buffer_new();
- if (reply == NULL) {
- ssh_set_error(session, SSH_FATAL, "Not enough space");
- return -1;
- }
-
- if (agent_talk(session, request, reply) < 0) {
- ssh_buffer_free(request);
- return 0;
- }
- ssh_buffer_free(request);
-
- /* get message type and verify the answer */
- buffer_get_u8(reply, (uint8_t *) &type);
- ssh_log(session, SSH_LOG_PACKET,
- "agent_ident_count - answer type: %d, expected answer: %d",
- type, c2);
- if (agent_failed(type)) {
- return 0;
- } else if (type != c2) {
- ssh_set_error(session, SSH_FATAL,
- "Bad authentication reply message type: %d", type);
- return -1;
- }
-
- buffer_get_u32(reply, (uint32_t *) buf);
- session->agent->count = agent_get_u32(buf);
- ssh_log(session, SSH_LOG_PACKET, "agent_ident_count - count: %d",
- session->agent->count);
- if (session->agent->count > 1024) {
- ssh_set_error(session, SSH_FATAL,
- "Too many identities in authentication reply: %d",
- session->agent->count);
- ssh_buffer_free(reply);
- return -1;
- }
-
- if (session->agent->ident) {
- buffer_reinit(session->agent->ident);
- }
- session->agent->ident = reply;
-
- return session->agent->count;
-}
-
-/* caller has to free commment */
-struct ssh_public_key_struct *agent_get_first_ident(struct ssh_session_struct *session,
- char **comment) {
- if (agent_get_ident_count(session) > 0) {
- return agent_get_next_ident(session, comment);
- }
-
- return NULL;
-}
-
-/* caller has to free commment */
-struct ssh_public_key_struct *agent_get_next_ident(struct ssh_session_struct *session,
- char **comment) {
- struct ssh_public_key_struct *pubkey = NULL;
- struct ssh_string_struct *blob = NULL;
- struct ssh_string_struct *tmp = NULL;
-
- if (session->agent->count == 0) {
- return NULL;
- }
-
- switch(session->version) {
- case 1:
- return NULL;
- case 2:
- /* get the blob */
- blob = buffer_get_ssh_string(session->agent->ident);
- if (blob == NULL) {
- return NULL;
- }
-
- /* get the comment */
- tmp = buffer_get_ssh_string(session->agent->ident);
- if (tmp == NULL) {
- ssh_string_free(blob);
-
- return NULL;
- }
-
- if (comment) {
- *comment = ssh_string_to_char(tmp);
- } else {
- ssh_string_free(blob);
- ssh_string_free(tmp);
-
- return NULL;
- }
- ssh_string_free(tmp);
-
- /* get key from blob */
- pubkey = publickey_from_string(session, blob);
- ssh_string_free(blob);
- break;
- default:
- return NULL;
- }
-
- return pubkey;
-}
-
-ssh_string agent_sign_data(struct ssh_session_struct *session,
- struct ssh_buffer_struct *data,
- struct ssh_public_key_struct *pubkey) {
- struct ssh_string_struct *blob = NULL;
- struct ssh_string_struct *sig = NULL;
- struct ssh_buffer_struct *request = NULL;
- struct ssh_buffer_struct *reply = NULL;
- int type = SSH2_AGENT_FAILURE;
- int flags = 0;
- uint32_t dlen = 0;
-
- /* create blob from the pubkey */
- blob = publickey_to_string(pubkey);
-
- request = ssh_buffer_new();
- if (request == NULL) {
- goto error;
- }
-
- /* create request */
- if (buffer_add_u8(request, SSH2_AGENTC_SIGN_REQUEST) < 0) {
- goto error;
- }
-
- /* adds len + blob */
- if (buffer_add_ssh_string(request, blob) < 0) {
- goto error;
- }
-
- /* Add data */
- dlen = ssh_buffer_get_len(data);
- if (buffer_add_u32(request, htonl(dlen)) < 0) {
- goto error;
- }
- if (buffer_add_data(request, ssh_buffer_get_begin(data), dlen) < 0) {
- goto error;
- }
-
- if (buffer_add_u32(request, htonl(flags)) < 0) {
- goto error;
- }
-
- ssh_string_free(blob);
-
- reply = ssh_buffer_new();
- if (reply == NULL) {
- goto error;
- }
-
- /* send the request */
- if (agent_talk(session, request, reply) < 0) {
- ssh_buffer_free(request);
- return NULL;
- }
- ssh_buffer_free(request);
-
- /* check if reply is valid */
- if (buffer_get_u8(reply, (uint8_t *) &type) != sizeof(uint8_t)) {
- goto error;
- }
- if (agent_failed(type)) {
- ssh_log(session, SSH_LOG_RARE, "Agent reports failure in signing the key");
- ssh_buffer_free(reply);
- return NULL;
- } else if (type != SSH2_AGENT_SIGN_RESPONSE) {
- ssh_set_error(session, SSH_FATAL, "Bad authentication response: %d", type);
- ssh_buffer_free(reply);
- return NULL;
- }
-
- sig = buffer_get_ssh_string(reply);
-
- ssh_buffer_free(reply);
-
- return sig;
-error:
- ssh_set_error(session, SSH_FATAL, "Not enough memory");
- ssh_string_free(blob);
- ssh_buffer_free(request);
- ssh_buffer_free(reply);
-
- return NULL;
-}
-
-int agent_is_running(ssh_session session) {
- if (session == NULL || session->agent == NULL) {
- return 0;
- }
-
- if (ssh_socket_is_open(session->agent->sock)) {
- return 1;
- } else {
- if (agent_connect(session) < 0) {
- return 0;
- } else {
- return 1;
- }
- }
-
- return 0;
-}
-
-#endif /* _WIN32 */
-
-/* vim: set ts=2 sw=2 et cindent: */
diff --git a/libssh/auth.c b/libssh/auth.c
deleted file mode 100644
index f0443db0..00000000
--- a/libssh/auth.c
+++ /dev/null
@@ -1,1682 +0,0 @@
-/*
- * auth1.c - authentication with SSH protocols
- *
- * This file is part of the SSH Library
- *
- * Copyright (c) 2003-2008 by Aris Adamantiadis
- * Copyright (c) 2008-2009 Andreas Schneider <mail@cynapses.org>
- *
- * 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 <stdlib.h>
-#include <stdio.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/agent.h"
-#include "libssh/keyfiles.h"
-#include "libssh/misc.h"
-#include "libssh/packet.h"
-#include "libssh/session.h"
-#include "libssh/keys.h"
-#include "libssh/auth.h"
-
-/**
- * @defgroup libssh_auth The SSH authentication functions.
- * @ingroup libssh
- *
- * Functions to authenticate with a server.
- *
- * @{
- */
-
-/**
- * @internal
- *
- * @brief Ask access to the ssh-userauth service.
- *
- * @param[in] session The SSH session handle.
- *
- * @returns SSH_OK on success, SSH_ERROR on error.
- *
- * @bug current implementation is blocking
- */
-static int ask_userauth(ssh_session session) {
- int rc = 0;
-
- enter_function();
- do {
- rc=ssh_service_request(session,"ssh-userauth");
- if(rc==SSH_AGAIN)
- ssh_handle_packets(session,-1);
- } while(rc==SSH_AGAIN);
- leave_function();
- return rc;
-}
-
-/**
- * @internal
- *
- * @brief Handles a SSH_USERAUTH_BANNER packet.
- *
- * This banner should be shown to user prior to authentication
- */
-SSH_PACKET_CALLBACK(ssh_packet_userauth_banner){
- ssh_string banner;
- (void)type;
- (void)user;
- enter_function();
- banner = buffer_get_ssh_string(packet);
- if (banner == NULL) {
- ssh_log(session, SSH_LOG_RARE,
- "Invalid SSH_USERAUTH_BANNER packet");
- } else {
- ssh_log(session, SSH_LOG_PACKET,
- "Received SSH_USERAUTH_BANNER packet");
- if(session->banner != NULL)
- ssh_string_free(session->banner);
- session->banner = banner;
- }
- leave_function();
- return SSH_PACKET_USED;
-}
-
-/**
- * @internal
- *
- * @brief Handles a SSH_USERAUTH_FAILURE packet.
- *
- * This handles the complete or partial authentication failure.
- */
-SSH_PACKET_CALLBACK(ssh_packet_userauth_failure){
- char *auth_methods = NULL;
- ssh_string auth;
- uint8_t partial = 0;
- (void) type;
- (void) user;
- enter_function();
-
- auth = buffer_get_ssh_string(packet);
- if (auth == NULL || buffer_get_u8(packet, &partial) != 1) {
- ssh_set_error(session, SSH_FATAL,
- "Invalid SSH_MSG_USERAUTH_FAILURE message");
- session->auth_state=SSH_AUTH_STATE_ERROR;
- goto end;
- }
-
- auth_methods = ssh_string_to_char(auth);
- if (auth_methods == NULL) {
- ssh_set_error_oom(session);
- goto end;
- }
-
- if (partial) {
- session->auth_state=SSH_AUTH_STATE_PARTIAL;
- ssh_log(session,SSH_LOG_PROTOCOL,
- "Partial success. Authentication that can continue: %s",
- auth_methods);
- } else {
- session->auth_state=SSH_AUTH_STATE_FAILED;
- ssh_log(session, SSH_LOG_PROTOCOL,
- "Access denied. Authentication that can continue: %s",
- auth_methods);
- ssh_set_error(session, SSH_REQUEST_DENIED,
- "Access denied. Authentication that can continue: %s",
- auth_methods);
-
- session->auth_methods = 0;
- }
- if (strstr(auth_methods, "password") != NULL) {
- session->auth_methods |= SSH_AUTH_METHOD_PASSWORD;
- }
- if (strstr(auth_methods, "keyboard-interactive") != NULL) {
- session->auth_methods |= SSH_AUTH_METHOD_INTERACTIVE;
- }
- if (strstr(auth_methods, "publickey") != NULL) {
- session->auth_methods |= SSH_AUTH_METHOD_PUBLICKEY;
- }
- if (strstr(auth_methods, "hostbased") != NULL) {
- session->auth_methods |= SSH_AUTH_METHOD_HOSTBASED;
- }
-
-end:
- ssh_string_free(auth);
- SAFE_FREE(auth_methods);
- leave_function();
- return SSH_PACKET_USED;
-}
-
-/**
- * @internal
- *
- * @brief Handles a SSH_USERAUTH_SUCCESS packet.
- *
- * It is also used to communicate the new to the upper levels.
- */
-SSH_PACKET_CALLBACK(ssh_packet_userauth_success){
- enter_function();
- (void)packet;
- (void)type;
- (void)user;
- ssh_log(session,SSH_LOG_PACKET,"Received SSH_USERAUTH_SUCCESS");
- ssh_log(session,SSH_LOG_PROTOCOL,"Authentication successful");
- session->auth_state=SSH_AUTH_STATE_SUCCESS;
- session->session_state=SSH_SESSION_STATE_AUTHENTICATED;
- leave_function();
- return SSH_PACKET_USED;
-}
-
-/**
- * @internal
- *
- * @brief Handles a SSH_USERAUTH_PK_OK or SSH_USERAUTH_INFO_REQUEST packet.
- *
- * Since the two types of packets share the same code, additional work is done
- * to understand if we are in a public key or keyboard-interactive context.
- */
-SSH_PACKET_CALLBACK(ssh_packet_userauth_pk_ok){
- int rc;
- enter_function();
- ssh_log(session,SSH_LOG_PACKET,"Received SSH_USERAUTH_PK_OK/INFO_REQUEST");
- if(session->auth_state==SSH_AUTH_STATE_KBDINT_SENT){
- /* Assuming we are in keyboard-interactive context */
- ssh_log(session,SSH_LOG_PACKET,"keyboard-interactive context, assuming SSH_USERAUTH_INFO_REQUEST");
- rc=ssh_packet_userauth_info_request(session,type,packet,user);
- } else {
- session->auth_state=SSH_AUTH_STATE_PK_OK;
- ssh_log(session,SSH_LOG_PACKET,"assuming SSH_USERAUTH_PK_OK");
- rc=SSH_PACKET_USED;
- }
- leave_function();
- return rc;
-}
-
-static int wait_auth_status(ssh_session session) {
- int rc = SSH_AUTH_ERROR;
-
- enter_function();
-
- while (session->auth_state == SSH_AUTH_STATE_NONE ||
- session->auth_state == SSH_AUTH_STATE_KBDINT_SENT) {
- if (ssh_handle_packets(session,-1) != SSH_OK)
- break;
- }
- switch(session->auth_state){
- case SSH_AUTH_STATE_ERROR:
- rc=SSH_AUTH_ERROR;
- break;
- case SSH_AUTH_STATE_FAILED:
- rc=SSH_AUTH_DENIED;
- break;
- case SSH_AUTH_STATE_INFO:
- rc=SSH_AUTH_INFO;
- break;
- case SSH_AUTH_STATE_PARTIAL:
- rc=SSH_AUTH_PARTIAL;
- break;
- case SSH_AUTH_STATE_PK_OK:
- case SSH_AUTH_STATE_SUCCESS:
- rc=SSH_AUTH_SUCCESS;
- break;
- case SSH_AUTH_STATE_KBDINT_SENT:
- case SSH_AUTH_STATE_NONE:
- /* not reached */
- rc=SSH_AUTH_ERROR;
- break;
- }
- leave_function();
- return rc;
-}
-
-/**
- * @brief retrieves available authentication methods for this session
- * @deprecated
- * @see ssh_userauth_list
- */
-int ssh_auth_list(ssh_session session) {
- return ssh_userauth_list(session, NULL);
-}
-
-/**
- * @brief retrieves available authentication methods for this session
- * @param[in] session the SSH session
- * @param[in] username set to NULL
- * @returns A bitfield of values SSH_AUTH_METHOD_NONE, SSH_AUTH_METHOD_PASSWORD,
- SSH_AUTH_METHOD_PUBLICKEY, SSH_AUTH_METHOD_HOSTBASED,
- SSH_AUTH_METHOD_INTERACTIVE.
- @warning Other reserved flags may appear in future versions.
- */
-int ssh_userauth_list(ssh_session session, const char *username) {
- if (session == NULL) {
- return SSH_AUTH_ERROR;
- }
-
-#ifdef WITH_SSH1
- if(session->version==1){
- return SSH_AUTH_METHOD_PASSWORD;
- }
-#endif
- if (session->auth_methods == 0) {
- ssh_userauth_none(session, username);
- }
- return session->auth_methods;
-}
-
-/* use the "none" authentication question */
-
-/**
- * @brief Try to authenticate through the "none" method.
- *
- * @param[in] session The ssh session to use.
- *
- * @param[in] username Deprecated, set to NULL.
- *
- * @returns SSH_AUTH_ERROR: A serious error happened.\n
- * SSH_AUTH_DENIED: Authentication failed: use another method\n
- * SSH_AUTH_PARTIAL: You've been partially authenticated, you still
- * have to use another method\n
- * SSH_AUTH_SUCCESS: Authentication success
- */
-int ssh_userauth_none(ssh_session session, const char *username) {
- ssh_string user = NULL;
- ssh_string service = NULL;
- ssh_string method = NULL;
- int rc = SSH_AUTH_ERROR;
-
- enter_function();
-
-#ifdef WITH_SSH1
- if (session->version == 1) {
- rc = ssh_userauth1_none(session, username);
- leave_function();
- return rc;
- }
-#endif
- if(session->auth_methods != 0){
- /* userauth_none or other method was already tried before */
- ssh_set_error(session,SSH_REQUEST_DENIED,"None method rejected by server");
- leave_function();
- return SSH_AUTH_DENIED;
- }
- if (username == NULL) {
- if (session->username == NULL) {
- if (ssh_options_apply(session) < 0) {
- leave_function();
- return rc;
- }
- }
- user = ssh_string_from_char(session->username);
- } else {
- user = ssh_string_from_char(username);
- }
-
- if (user == NULL) {
- leave_function();
- return rc;
- }
-
- if (ask_userauth(session) < 0) {
- ssh_string_free(user);
- leave_function();
- return rc;
- }
-
- method = ssh_string_from_char("none");
- if (method == NULL) {
- goto error;
- }
- service = ssh_string_from_char("ssh-connection");
- if (service == NULL) {
- goto error;
- }
-
- if (buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_REQUEST) < 0 ||
- buffer_add_ssh_string(session->out_buffer, user) < 0 ||
- buffer_add_ssh_string(session->out_buffer, service) < 0 ||
- buffer_add_ssh_string(session->out_buffer, method) < 0) {
- goto error;
- }
-
- ssh_string_free(service);
- ssh_string_free(method);
- ssh_string_free(user);
- session->auth_state=SSH_AUTH_STATE_NONE;
- if (packet_send(session) == SSH_ERROR) {
- leave_function();
- return rc;
- }
- rc = wait_auth_status(session);
-
- leave_function();
- return rc;
-error:
- buffer_reinit(session->out_buffer);
- ssh_string_free(service);
- ssh_string_free(method);
- ssh_string_free(user);
-
- leave_function();
- return rc;
-}
-
-/**
- * @brief Try to authenticate through public key.
- *
- * @param[in] session The ssh session to use.
- *
- * @param[in] username The username to authenticate. You can specify NULL if
- * ssh_option_set_username() has been used. You cannot try
- * two different logins in a row.
- *
- * @param[in] type The type of the public key. This value is given by
- * publickey_from_file() or ssh_privatekey_type().
- *
- * @param[in] publickey A public key returned by publickey_from_file().
- *
- * @returns SSH_AUTH_ERROR: A serious error happened.\n
- * SSH_AUTH_DENIED: The server doesn't accept that public key as an
- * authentication token. Try another key or another
- * method.\n
- * SSH_AUTH_PARTIAL: You've been partially authenticated, you still
- * have to use another method.\n
- * SSH_AUTH_SUCCESS: The public key is accepted, you want now to use
- * ssh_userauth_pubkey().
- *
- * @see publickey_from_file()
- * @see privatekey_from_file()
- * @see ssh_privatekey_type()
- * @see ssh_userauth_pubkey()
- */
-int ssh_userauth_offer_pubkey(ssh_session session, const char *username,
- int type, ssh_string publickey) {
- ssh_string user = NULL;
- ssh_string service = NULL;
- ssh_string method = NULL;
- ssh_string algo = NULL;
- int rc = SSH_AUTH_ERROR;
-
- enter_function();
-
-#ifdef WITH_SSH1
- if (session->version == 1) {
- ssh_userauth1_offer_pubkey(session, username, type, publickey);
- leave_function();
- return rc;
- }
-#endif
-
- if (username == NULL) {
- if (session->username == NULL) {
- if (ssh_options_apply(session) < 0) {
- leave_function();
- return rc;
- }
- }
- user = ssh_string_from_char(session->username);
- } else {
- user = ssh_string_from_char(username);
- }
-
- if (user == NULL) {
- leave_function();
- return rc;
- }
-
- if (ask_userauth(session) < 0) {
- ssh_string_free(user);
- leave_function();
- return rc;
- }
-
- service = ssh_string_from_char("ssh-connection");
- if (service == NULL) {
- goto error;
- }
- method = ssh_string_from_char("publickey");
- if (method == NULL) {
- goto error;
- }
- algo = ssh_string_from_char(ssh_type_to_char(type));
- if (algo == NULL) {
- goto error;
- }
-
- if (buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_REQUEST) < 0 ||
- buffer_add_ssh_string(session->out_buffer, user) < 0 ||
- buffer_add_ssh_string(session->out_buffer, service) < 0 ||
- buffer_add_ssh_string(session->out_buffer, method) < 0 ||
- buffer_add_u8(session->out_buffer, 0) < 0 ||
- buffer_add_ssh_string(session->out_buffer, algo) < 0 ||
- buffer_add_ssh_string(session->out_buffer, publickey) < 0) {
- goto error;
- }
-
- ssh_string_free(user);
- ssh_string_free(method);
- ssh_string_free(service);
- ssh_string_free(algo);
- session->auth_state=SSH_AUTH_STATE_NONE;
- if (packet_send(session) == SSH_ERROR) {
- leave_function();
- return rc;
- }
- rc = wait_auth_status(session);
-
- leave_function();
- return rc;
-error:
- buffer_reinit(session->out_buffer);
- ssh_string_free(user);
- ssh_string_free(method);
- ssh_string_free(service);
- ssh_string_free(algo);
-
- leave_function();
- return rc;
-}
-
-
-/**
- * @brief Try to authenticate through public key.
- *
- * @param[in] session The ssh session to use.
- *
- * @param[in] username The username to authenticate. You can specify NULL if
- * ssh_option_set_username() has been used. You cannot try
- * two different logins in a row.
- *
- * @param[in] publickey A public key returned by publickey_from_file(), or NULL
- * to generate automatically from privatekey.
- *
- * @param[in] privatekey A private key returned by privatekey_from_file().
- *
- * @returns SSH_AUTH_ERROR: A serious error happened.\n
- * SSH_AUTH_DENIED: Authentication failed: use another method.\n
- * SSH_AUTH_PARTIAL: You've been partially authenticated, you still
- * have to use another method.\n
- * SSH_AUTH_SUCCESS: Authentication successful.
- *
- * @see publickey_from_file()
- * @see privatekey_from_file()
- * @see privatekey_free()
- * @see ssh_userauth_offer_pubkey()
- */
-int ssh_userauth_pubkey(ssh_session session, const char *username,
- ssh_string publickey, ssh_private_key privatekey) {
- ssh_string user = NULL;
- ssh_string service = NULL;
- ssh_string method = NULL;
- ssh_string algo = NULL;
- ssh_string sign = NULL;
- ssh_public_key pk = NULL;
- ssh_string pkstr = NULL;
- int rc = SSH_AUTH_ERROR;
-
- enter_function();
-
-#if 0
- if (session->version == 1) {
- return ssh_userauth1_pubkey(session, username, publickey, privatekey);
- }
-#endif
-
- if (username == NULL) {
- if (session->username == NULL) {
- if (ssh_options_apply(session) < 0) {
- leave_function();
- return rc;
- }
- }
- user = ssh_string_from_char(session->username);
- } else {
- user = ssh_string_from_char(username);
- }
-
- if (user == NULL) {
- leave_function();
- return rc;
- }
-
- if (ask_userauth(session) < 0) {
- ssh_string_free(user);
- leave_function();
- return rc;
- }
-
- service = ssh_string_from_char("ssh-connection");
- if (service == NULL) {
- goto error;
- }
- method = ssh_string_from_char("publickey");
- if (method == NULL) {
- goto error;
- }
- algo = ssh_string_from_char(ssh_type_to_char(privatekey->type));
- if (algo == NULL) {
- goto error;
- }
- if (publickey == NULL) {
- pk = publickey_from_privatekey(privatekey);
- if (pk == NULL) {
- goto error;
- }
- pkstr = publickey_to_string(pk);
- publickey_free(pk);
- if (pkstr == NULL) {
- goto error;
- }
- }
-
- /* we said previously the public key was accepted */
- if (buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_REQUEST) < 0 ||
- buffer_add_ssh_string(session->out_buffer, user) < 0 ||
- buffer_add_ssh_string(session->out_buffer, service) < 0 ||
- buffer_add_ssh_string(session->out_buffer, method) < 0 ||
- buffer_add_u8(session->out_buffer, 1) < 0 ||
- buffer_add_ssh_string(session->out_buffer, algo) < 0 ||
- buffer_add_ssh_string(session->out_buffer, (publickey == NULL ? pkstr : publickey)) < 0) {
- goto error;
- }
-
- ssh_string_free(user);
- ssh_string_free(service);
- ssh_string_free(method);
- ssh_string_free(algo);
- ssh_string_free(pkstr);
-
- sign = ssh_do_sign(session,session->out_buffer, privatekey);
- if (sign) {
- if (buffer_add_ssh_string(session->out_buffer,sign) < 0) {
- goto error;
- }
- ssh_string_free(sign);
- session->auth_state=SSH_AUTH_STATE_NONE;
- if (packet_send(session) == SSH_ERROR) {
- leave_function();
- return rc;
- }
- rc = wait_auth_status(session);
- }
-
- leave_function();
- return rc;
-error:
- buffer_reinit(session->out_buffer);
- ssh_string_free(user);
- ssh_string_free(service);
- ssh_string_free(method);
- ssh_string_free(algo);
- ssh_string_free(pkstr);
-
- leave_function();
- return rc;
-}
-
-/**
- * @brief Try to authenticate through a private key file.
- *
- * @param[in] session The ssh session to use.
- *
- * @param[in] username The username to authenticate. You can specify NULL if
- * ssh_option_set_username() has been used. You cannot try
- * two different logins in a row.
- *
- * @param[in] filename Filename containing the private key.
- *
- * @param[in] passphrase Passphrase to decrypt the private key. Set to null if
- * none is needed or it is unknown.
- *
- * @returns SSH_AUTH_ERROR: A serious error happened.\n
- * SSH_AUTH_DENIED: Authentication failed: use another method.\n
- * SSH_AUTH_PARTIAL: You've been partially authenticated, you still
- * have to use another method.\n
- * SSH_AUTH_SUCCESS: Authentication successful.
- *
- * @see publickey_from_file()
- * @see privatekey_from_file()
- * @see privatekey_free()
- * @see ssh_userauth_pubkey()
- */
-int ssh_userauth_privatekey_file(ssh_session session, const char *username,
- const char *filename, const char *passphrase) {
- char *pubkeyfile = NULL;
- ssh_string pubkey = NULL;
- ssh_private_key privkey = NULL;
- int type = 0;
- int rc = SSH_AUTH_ERROR;
-
- enter_function();
-
- pubkeyfile = malloc(strlen(filename) + 1 + 4);
- if (pubkeyfile == NULL) {
- leave_function();
- return SSH_AUTH_ERROR;
- }
- sprintf(pubkeyfile, "%s.pub", filename);
-
- pubkey = publickey_from_file(session, pubkeyfile, &type);
- if (pubkey == NULL) {
- ssh_log(session, SSH_LOG_RARE, "Public key file %s not found. Trying to generate it.", pubkeyfile);
- /* auto-detect the key type with type=0 */
- privkey = privatekey_from_file(session, filename, 0, passphrase);
- } else {
- ssh_log(session, SSH_LOG_RARE, "Public key file %s loaded.", pubkeyfile);
- privkey = privatekey_from_file(session, filename, type, passphrase);
- }
- if (privkey == NULL) {
- goto error;
- }
- /* ssh_userauth_pubkey is responsible for taking care of null-pubkey */
- rc = ssh_userauth_pubkey(session, username, pubkey, privkey);
- privatekey_free(privkey);
-
-error:
- SAFE_FREE(pubkeyfile);
- ssh_string_free(pubkey);
-
- leave_function();
- return rc;
-}
-
-#ifndef _WIN32
-/**
- * @brief Try to authenticate through public key with an ssh agent.
- *
- * @param[in] session The ssh session to use.
- *
- * @param[in] username The username to authenticate. You can specify NULL if
- * ssh_option_set_username() has been used. You cannot try
- * two different logins in a row.
- *
- * @param[in] publickey The public key provided by the agent.
- *
- * @returns SSH_AUTH_ERROR: A serious error happened.\n
- * SSH_AUTH_DENIED: Authentication failed: use another method.\n
- * SSH_AUTH_PARTIAL: You've been partially authenticated, you still
- * have to use another method.\n
- * SSH_AUTH_SUCCESS: Authentication successful.
- *
- * @see publickey_from_file()
- * @see privatekey_from_file()
- * @see privatekey_free()
- * @see ssh_userauth_offer_pubkey()
- */
-int ssh_userauth_agent_pubkey(ssh_session session, const char *username,
- ssh_public_key publickey) {
- ssh_string user = NULL;
- ssh_string service = NULL;
- ssh_string method = NULL;
- ssh_string algo = NULL;
- ssh_string key = NULL;
- ssh_string sign = NULL;
- int rc = SSH_AUTH_ERROR;
-
- enter_function();
-
- if (! agent_is_running(session)) {
- return rc;
- }
-
- if (username == NULL) {
- if (session->username == NULL) {
- if (ssh_options_apply(session) < 0) {
- leave_function();
- return rc;
- }
- }
- user = ssh_string_from_char(session->username);
- } else {
- user = ssh_string_from_char(username);
- }
-
- if (user == NULL) {
- leave_function();
- return rc;
- }
-
- if (ask_userauth(session) < 0) {
- ssh_string_free(user);
- leave_function();
- return rc;
- }
-
- service = ssh_string_from_char("ssh-connection");
- if (service == NULL) {
- goto error;
- }
- method = ssh_string_from_char("publickey");
- if (method == NULL) {
- goto error;
- }
- algo = ssh_string_from_char(ssh_type_to_char(publickey->type));
- if (algo == NULL) {
- goto error;
- }
- key = publickey_to_string(publickey);
- if (key == NULL) {
- goto error;
- }
-
- /* we said previously the public key was accepted */
- if (buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_REQUEST) < 0 ||
- buffer_add_ssh_string(session->out_buffer, user) < 0 ||
- buffer_add_ssh_string(session->out_buffer, service) < 0 ||
- buffer_add_ssh_string(session->out_buffer, method) < 0 ||
- buffer_add_u8(session->out_buffer, 1) < 0 ||
- buffer_add_ssh_string(session->out_buffer, algo) < 0 ||
- buffer_add_ssh_string(session->out_buffer, key) < 0) {
- goto error;
- }
-
- sign = ssh_do_sign_with_agent(session, session->out_buffer, publickey);
-
- if (sign) {
- if (buffer_add_ssh_string(session->out_buffer, sign) < 0) {
- goto error;
- }
- ssh_string_free(sign);
- session->auth_state=SSH_AUTH_STATE_NONE;
- if (packet_send(session) == SSH_ERROR) {
- leave_function();
- return rc;
- }
- rc = wait_auth_status(session);
- }
-
- ssh_string_free(user);
- ssh_string_free(service);
- ssh_string_free(method);
- ssh_string_free(algo);
- ssh_string_free(key);
-
- leave_function();
-
- return rc;
-error:
- buffer_reinit(session->out_buffer);
- ssh_string_free(sign);
- ssh_string_free(user);
- ssh_string_free(service);
- ssh_string_free(method);
- ssh_string_free(algo);
- ssh_string_free(key);
-
- leave_function();
- return rc;
-}
-#endif /* _WIN32 */
-
-/**
- * @brief Try to authenticate by password.
- *
- * @param[in] session The ssh session to use.
- *
- * @param[in] username The username to authenticate. You can specify NULL if
- * ssh_option_set_username() has been used. You cannot try
- * two different logins in a row.
- *
- * @param[in] password The password to use. Take care to clean it after
- * the authentication.
- *
- * @returns SSH_AUTH_ERROR: A serious error happened.\n
- * SSH_AUTH_DENIED: Authentication failed: use another method.\n
- * SSH_AUTH_PARTIAL: You've been partially authenticated, you still
- * have to use another method.\n
- * SSH_AUTH_SUCCESS: Authentication successful.
- *
- * @see ssh_userauth_kbdint()
- * @see BURN_STRING
- */
-int ssh_userauth_password(ssh_session session, const char *username,
- const char *password) {
- ssh_string user = NULL;
- ssh_string service = NULL;
- ssh_string method = NULL;
- ssh_string pwd = NULL;
- int rc = SSH_AUTH_ERROR;
-
- enter_function();
-
-#ifdef WITH_SSH1
- if (session->version == 1) {
- rc = ssh_userauth1_password(session, username, password);
- leave_function();
- return rc;
- }
-#endif
-
- if (username == NULL) {
- if (session->username == NULL) {
- if (ssh_options_apply(session) < 0) {
- leave_function();
- return rc;
- }
- }
- user = ssh_string_from_char(session->username);
- } else {
- user = ssh_string_from_char(username);
- }
-
- if (user == NULL) {
- leave_function();
- return rc;
- }
-
- if (ask_userauth(session) < 0) {
- ssh_string_free(user);
- leave_function();
- return rc;
- }
-
- service = ssh_string_from_char("ssh-connection");
- if (service == NULL) {
- goto error;
- }
- method = ssh_string_from_char("password");
- if (method == NULL) {
- goto error;
- }
- pwd = ssh_string_from_char(password);
- if (pwd == NULL) {
- goto error;
- }
-
- if (buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_REQUEST) < 0 ||
- buffer_add_ssh_string(session->out_buffer, user) < 0 ||
- buffer_add_ssh_string(session->out_buffer, service) < 0 ||
- buffer_add_ssh_string(session->out_buffer, method) < 0 ||
- buffer_add_u8(session->out_buffer, 0) < 0 ||
- buffer_add_ssh_string(session->out_buffer, pwd) < 0) {
- goto error;
- }
-
- ssh_string_free(user);
- ssh_string_free(service);
- ssh_string_free(method);
- ssh_string_burn(pwd);
- ssh_string_free(pwd);
- session->auth_state=SSH_AUTH_STATE_NONE;
- if (packet_send(session) == SSH_ERROR) {
- leave_function();
- return rc;
- }
- rc = wait_auth_status(session);
-
- leave_function();
- return rc;
-error:
- buffer_reinit(session->out_buffer);
- ssh_string_free(user);
- ssh_string_free(service);
- ssh_string_free(method);
- ssh_string_burn(pwd);
- ssh_string_free(pwd);
-
- leave_function();
- return rc;
-}
-
-/**
- * @brief Tries to automatically authenticate with public key and "none"
- *
- * It may fail, for instance it doesn't ask for a password and uses a default
- * asker for passphrases (in case the private key is encrypted).
- *
- * @param[in] session The ssh session to authenticate with.
- *
- * @param[in] passphrase Use this passphrase to unlock the privatekey. Use NULL
- * if you don't want to use a passphrase or the user
- * should be asked.
- *
- * @returns SSH_AUTH_ERROR: A serious error happened\n
- * SSH_AUTH_DENIED: Authentication failed: use another method\n
- * SSH_AUTH_PARTIAL: You've been partially authenticated, you still
- * have to use another method\n
- * SSH_AUTH_SUCCESS: Authentication success
- *
- * @see ssh_userauth_kbdint()
- * @see ssh_userauth_password()
- */
-int ssh_userauth_autopubkey(ssh_session session, const char *passphrase) {
- struct ssh_iterator *it;
- ssh_private_key privkey;
- ssh_public_key pubkey;
- ssh_string pubkey_string;
- int type = 0;
- int rc;
-
- enter_function();
-
- /* Always test none authentication */
- rc = ssh_userauth_none(session, NULL);
- if (rc == SSH_AUTH_ERROR || rc == SSH_AUTH_SUCCESS) {
- leave_function();
- return rc;
- }
-
- /* Try authentication with ssh-agent first */
-#ifndef _WIN32
- if (agent_is_running(session)) {
- char *privkey_file = NULL;
-
- ssh_log(session, SSH_LOG_RARE,
- "Trying to authenticate with SSH agent keys as user: %s",
- session->username);
-
- for (pubkey = agent_get_first_ident(session, &privkey_file);
- pubkey != NULL;
- pubkey = agent_get_next_ident(session, &privkey_file)) {
-
- ssh_log(session, SSH_LOG_RARE, "Trying identity %s", privkey_file);
-
- pubkey_string = publickey_to_string(pubkey);
- if (pubkey_string) {
- rc = ssh_userauth_offer_pubkey(session, NULL, pubkey->type, pubkey_string);
- ssh_string_free(pubkey_string);
- if (rc == SSH_AUTH_ERROR) {
- SAFE_FREE(privkey_file);
- publickey_free(pubkey);
- leave_function();
-
- return rc;
- } else if (rc != SSH_AUTH_SUCCESS) {
- ssh_log(session, SSH_LOG_PROTOCOL, "Public key refused by server");
- SAFE_FREE(privkey_file);
- publickey_free(pubkey);
- continue;
- }
- ssh_log(session, SSH_LOG_PROTOCOL, "Public key accepted");
- /* pubkey accepted by server ! */
- rc = ssh_userauth_agent_pubkey(session, NULL, pubkey);
- if (rc == SSH_AUTH_ERROR) {
- SAFE_FREE(privkey_file);
- publickey_free(pubkey);
- leave_function();
-
- return rc;
- } else if (rc != SSH_AUTH_SUCCESS) {
- ssh_log(session, SSH_LOG_RARE,
- "Server accepted public key but refused the signature ;"
- " It might be a bug of libssh");
- SAFE_FREE(privkey_file);
- publickey_free(pubkey);
- continue;
- }
- /* auth success */
- ssh_log(session, SSH_LOG_PROTOCOL, "Authentication using %s success",
- privkey_file);
- SAFE_FREE(privkey_file);
- publickey_free(pubkey);
-
- leave_function();
-
- return SSH_AUTH_SUCCESS;
- } /* if pubkey */
- SAFE_FREE(privkey_file);
- publickey_free(pubkey);
- } /* for each privkey */
- } /* if agent is running */
-#endif
-
-
- for (it = ssh_list_get_iterator(session->identity);
- it != NULL;
- it = it->next) {
- const char *privkey_file = it->data;
- int privkey_open = 0;
-
- privkey = NULL;
-
- ssh_log(session, SSH_LOG_PROTOCOL, "Trying to read privatekey %s", privkey_file);
-
- rc = ssh_try_publickey_from_file(session, privkey_file, &pubkey_string, &type);
- if (rc == 1) {
- char *publickey_file;
- size_t len;
-
- privkey = privatekey_from_file(session, privkey_file, type, passphrase);
- if (privkey == NULL) {
- ssh_log(session, SSH_LOG_RARE,
- "Reading private key %s failed (bad passphrase ?)",
- privkey_file);
- leave_function();
- return SSH_AUTH_ERROR;
- }
- privkey_open = 1;
-
- pubkey = publickey_from_privatekey(privkey);
- if (pubkey == NULL) {
- privatekey_free(privkey);
- ssh_set_error_oom(session);
- leave_function();
- return SSH_AUTH_ERROR;
- }
-
- pubkey_string = publickey_to_string(pubkey);
- type = pubkey->type;
- publickey_free(pubkey);
- if (pubkey_string == NULL) {
- ssh_set_error_oom(session);
- leave_function();
- return SSH_AUTH_ERROR;
- }
-
- len = strlen(privkey_file) + 5;
- publickey_file = malloc(len);
- if (publickey_file == NULL) {
- ssh_set_error_oom(session);
- leave_function();
- return SSH_AUTH_ERROR;
- }
- snprintf(publickey_file, len, "%s.pub", privkey_file);
- rc = ssh_publickey_to_file(session, publickey_file, pubkey_string, type);
- if (rc < 0) {
- ssh_log(session, SSH_LOG_PACKET,
- "Could not write public key to file: %s", publickey_file);
- }
- SAFE_FREE(publickey_file);
- } else if (rc < 0) {
- continue;
- }
-
- rc = ssh_userauth_offer_pubkey(session, NULL, type, pubkey_string);
- if (rc == SSH_AUTH_ERROR){
- ssh_string_free(pubkey_string);
- ssh_log(session, SSH_LOG_RARE, "Publickey authentication error");
- leave_function();
- return rc;
- } else {
- if (rc != SSH_AUTH_SUCCESS){
- ssh_log(session, SSH_LOG_PROTOCOL, "Publickey refused by server");
- ssh_string_free(pubkey_string);
- continue;
- }
- }
-
- /* Public key accepted by server! */
- if (!privkey_open) {
- ssh_log(session, SSH_LOG_PROTOCOL, "Trying to read privatekey %s",
- privkey_file);
- privkey = privatekey_from_file(session, privkey_file, type, passphrase);
- if (privkey == NULL) {
- ssh_log(session, SSH_LOG_RARE,
- "Reading private key %s failed (bad passphrase ?)",
- privkey_file);
- ssh_string_free(pubkey_string);
- continue; /* continue the loop with other pubkey */
- }
- }
-
- rc = ssh_userauth_pubkey(session, NULL, pubkey_string, privkey);
- if (rc == SSH_AUTH_ERROR) {
- ssh_string_free(pubkey_string);
- privatekey_free(privkey);
- leave_function();
- return rc;
- } else {
- if (rc != SSH_AUTH_SUCCESS){
- ssh_log(session, SSH_LOG_RARE,
- "The server accepted the public key but refused the signature");
- ssh_string_free(pubkey_string);
- privatekey_free(privkey);
- continue;
- }
- }
-
- /* auth success */
- ssh_log(session, SSH_LOG_PROTOCOL,
- "Successfully authenticated using %s", privkey_file);
- ssh_string_free(pubkey_string);
- privatekey_free(privkey);
-
- leave_function();
- return SSH_AUTH_SUCCESS;
- }
-
- /* at this point, pubkey is NULL and so is privkeyfile */
- ssh_log(session, SSH_LOG_PROTOCOL,
- "Tried every public key, none matched");
- ssh_set_error(session,SSH_NO_ERROR,"No public key matched");
-
- leave_function();
- return SSH_AUTH_DENIED;
-}
-
-struct ssh_kbdint_struct {
- uint32_t nprompts;
- char *name;
- char *instruction;
- char **prompts;
- unsigned char *echo; /* bool array */
- char **answers;
-};
-
-static ssh_kbdint kbdint_new(void) {
- ssh_kbdint kbd;
-
- kbd = malloc(sizeof (struct ssh_kbdint_struct));
- if (kbd == NULL) {
- return NULL;
- }
- ZERO_STRUCTP(kbd);
-
- return kbd;
-}
-
-
-static void kbdint_free(ssh_kbdint kbd) {
- int i, n;
-
- if (kbd == NULL) {
- return;
- }
-
- n = kbd->nprompts;
-
- SAFE_FREE(kbd->name);
- SAFE_FREE(kbd->instruction);
- SAFE_FREE(kbd->echo);
-
- if (kbd->prompts) {
- for (i = 0; i < n; i++) {
- BURN_STRING(kbd->prompts[i]);
- SAFE_FREE(kbd->prompts[i]);
- }
- SAFE_FREE(kbd->prompts);
- }
- if (kbd->answers) {
- for (i = 0; i < n; i++) {
- BURN_STRING(kbd->answers[i]);
- SAFE_FREE(kbd->answers[i]);
- }
- SAFE_FREE(kbd->answers);
- }
-
- SAFE_FREE(kbd);
-}
-
-static void kbdint_clean(ssh_kbdint kbd) {
- int i, n;
-
- if (kbd == NULL) {
- return;
- }
-
- n = kbd->nprompts;
-
- SAFE_FREE(kbd->name);
- SAFE_FREE(kbd->instruction);
- SAFE_FREE(kbd->echo);
-
- if (kbd->prompts) {
- for (i = 0; i < n; i++) {
- BURN_STRING(kbd->prompts[i]);
- SAFE_FREE(kbd->prompts[i]);
- }
- SAFE_FREE(kbd->prompts);
- }
-
- if (kbd->answers) {
- for (i = 0; i < n; i++) {
- BURN_STRING(kbd->answers[i]);
- SAFE_FREE(kbd->answers[i]);
- }
- SAFE_FREE(kbd->answers);
- }
-
- kbd->nprompts = 0;
-}
-
-/* this function sends the first packet as explained in section 3.1
- * of the draft */
-static int kbdauth_init(ssh_session session, const char *user,
- const char *submethods) {
- ssh_string usr = NULL;
- ssh_string sub = NULL;
- ssh_string service = NULL;
- ssh_string method = NULL;
- int rc = SSH_AUTH_ERROR;
-
- enter_function();
-
- usr = ssh_string_from_char(user);
- if (usr == NULL) {
- goto error;
- }
- sub = (submethods ? ssh_string_from_char(submethods) : ssh_string_from_char(""));
- if (sub == NULL) {
- goto error;
- }
- service = ssh_string_from_char("ssh-connection");
- if (service == NULL) {
- goto error;
- }
- method = ssh_string_from_char("keyboard-interactive");
- if (method == NULL) {
- goto error;
- }
-
- if (buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_REQUEST) < 0 ||
- buffer_add_ssh_string(session->out_buffer, usr) < 0 ||
- buffer_add_ssh_string(session->out_buffer, service) < 0 ||
- buffer_add_ssh_string(session->out_buffer, method) < 0 ||
- buffer_add_u32(session->out_buffer, 0) < 0 ||
- buffer_add_ssh_string(session->out_buffer, sub) < 0) {
- goto error;
- }
-
- ssh_string_free(usr);
- ssh_string_free(service);
- ssh_string_free(method);
- ssh_string_free(sub);
- session->auth_state=SSH_AUTH_STATE_KBDINT_SENT;
- if (packet_send(session) == SSH_ERROR) {
- leave_function();
- return rc;
- }
- rc = wait_auth_status(session);
-
- leave_function();
- return rc;
-error:
- buffer_reinit(session->out_buffer);
- ssh_string_free(usr);
- ssh_string_free(service);
- ssh_string_free(method);
- ssh_string_free(sub);
-
- leave_function();
- return rc;
-}
-
-/**
- * @internal
- * @brief handles a SSH_USERAUTH_INFO_REQUEST packet, as used in
- * keyboard-interactive authentication, and changes the
- * authentication state.
- */
-SSH_PACKET_CALLBACK(ssh_packet_userauth_info_request) {
- ssh_string name; /* name of the "asking" window showed to client */
- ssh_string instruction;
- ssh_string tmp;
- uint32_t nprompts;
- uint32_t i;
- (void)user;
- (void)type;
- enter_function();
-
- name = buffer_get_ssh_string(packet);
- instruction = buffer_get_ssh_string(packet);
- tmp = buffer_get_ssh_string(packet);
- buffer_get_u32(packet, &nprompts);
-
- if (name == NULL || instruction == NULL || tmp == NULL) {
- ssh_string_free(name);
- ssh_string_free(instruction);
- /* tmp if empty if we got here */
- ssh_set_error(session, SSH_FATAL, "Invalid USERAUTH_INFO_REQUEST msg");
- leave_function();
- return SSH_PACKET_USED;
- }
- ssh_string_free(tmp);
-
- if (session->kbdint == NULL) {
- session->kbdint = kbdint_new();
- if (session->kbdint == NULL) {
- ssh_set_error_oom(session);
- ssh_string_free(name);
- ssh_string_free(instruction);
-
- leave_function();
- return SSH_PACKET_USED;
- }
- } else {
- kbdint_clean(session->kbdint);
- }
-
- session->kbdint->name = ssh_string_to_char(name);
- ssh_string_free(name);
- if (session->kbdint->name == NULL) {
- ssh_set_error_oom(session);
- kbdint_free(session->kbdint);
- leave_function();
- return SSH_PACKET_USED;
- }
-
- session->kbdint->instruction = ssh_string_to_char(instruction);
- ssh_string_free(instruction);
- if (session->kbdint->instruction == NULL) {
- ssh_set_error_oom(session);
- kbdint_free(session->kbdint);
- session->kbdint = NULL;
- leave_function();
- return SSH_PACKET_USED;
- }
-
- nprompts = ntohl(nprompts);
- ssh_log(session,SSH_LOG_PACKET,"kbdint: %d prompts",nprompts);
- if (nprompts > KBDINT_MAX_PROMPT) {
- ssh_set_error(session, SSH_FATAL,
- "Too much prompt asked from server: %u (0x%.4x)",
- nprompts, nprompts);
- kbdint_free(session->kbdint);
- session->kbdint = NULL;
- leave_function();
- return SSH_PACKET_USED;
- }
-
- session->kbdint->nprompts = nprompts;
- session->kbdint->prompts = malloc(nprompts * sizeof(char *));
- if (session->kbdint->prompts == NULL) {
- session->kbdint->nprompts = 0;
- ssh_set_error_oom(session);
- kbdint_free(session->kbdint);
- session->kbdint = NULL;
- leave_function();
- return SSH_PACKET_USED;
- }
- memset(session->kbdint->prompts, 0, nprompts * sizeof(char *));
-
- session->kbdint->echo = malloc(nprompts);
- if (session->kbdint->echo == NULL) {
- session->kbdint->nprompts = 0;
- ssh_set_error_oom(session);
- kbdint_free(session->kbdint);
- session->kbdint = NULL;
- leave_function();
- return SSH_PACKET_USED;
- }
- memset(session->kbdint->echo, 0, nprompts);
-
- for (i = 0; i < nprompts; i++) {
- tmp = buffer_get_ssh_string(packet);
- buffer_get_u8(packet, &session->kbdint->echo[i]);
- if (tmp == NULL) {
- ssh_set_error(session, SSH_FATAL, "Short INFO_REQUEST packet");
- kbdint_free(session->kbdint);
- session->kbdint = NULL;
- leave_function();
- return SSH_PACKET_USED;
- }
- session->kbdint->prompts[i] = ssh_string_to_char(tmp);
- ssh_string_free(tmp);
- if (session->kbdint->prompts[i] == NULL) {
- ssh_set_error_oom(session);
- kbdint_free(session->kbdint);
- session->kbdint = NULL;
- leave_function();
- return SSH_PACKET_USED;
- }
- }
- session->auth_state=SSH_AUTH_STATE_INFO;
- leave_function();
- return SSH_PACKET_USED;
-}
-
-/**
- * @internal
- * @brief Sends the current challenge response and wait for a
- * reply from the server
- * @returns SSH_AUTH_INFO if more info is needed
- * @returns SSH_AUTH_SUCCESS
- * @returns SSH_AUTH_FAILURE
- * @returns SSH_AUTH_PARTIAL
- */
-static int kbdauth_send(ssh_session session) {
- ssh_string answer = NULL;
- int rc = SSH_AUTH_ERROR;
- uint32_t i;
-
- enter_function();
-
- if (buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_INFO_RESPONSE) < 0 ||
- buffer_add_u32(session->out_buffer,
- htonl(session->kbdint->nprompts)) < 0) {
- goto error;
- }
-
- for (i = 0; i < session->kbdint->nprompts; i++) {
- if (session->kbdint->answers[i]) {
- answer = ssh_string_from_char(session->kbdint->answers[i]);
- } else {
- answer = ssh_string_from_char("");
- }
- if (answer == NULL) {
- goto error;
- }
-
- if (buffer_add_ssh_string(session->out_buffer, answer) < 0) {
- goto error;
- }
-
- ssh_string_burn(answer);
- ssh_string_free(answer);
- }
- session->auth_state=SSH_AUTH_STATE_KBDINT_SENT;
- kbdint_free(session->kbdint);
- session->kbdint = NULL;
- if (packet_send(session) == SSH_ERROR) {
- leave_function();
- return rc;
- }
- rc = wait_auth_status(session);
-
- leave_function();
- return rc;
-error:
- buffer_reinit(session->out_buffer);
- ssh_string_burn(answer);
- ssh_string_free(answer);
-
- leave_function();
- return rc;
-}
-
-/**
- * @brief Try to authenticate through the "keyboard-interactive" method.
- *
- * @param[in] session The ssh session to use.
- *
- * @param[in] user The username to authenticate. You can specify NULL if
- * ssh_option_set_username() has been used. You cannot try
- * two different logins in a row.
- *
- * @param[in] submethods Undocumented. Set it to NULL.
- *
- * @returns SSH_AUTH_ERROR: A serious error happened\n
- * SSH_AUTH_DENIED: Authentication failed : use another method\n
- * SSH_AUTH_PARTIAL: You've been partially authenticated, you still
- * have to use another method\n
- * SSH_AUTH_SUCCESS: Authentication success\n
- * SSH_AUTH_INFO: The server asked some questions. Use
- * ssh_userauth_kbdint_getnprompts() and such.
- *
- * @see ssh_userauth_kbdint_getnprompts()
- * @see ssh_userauth_kbdint_getname()
- * @see ssh_userauth_kbdint_getinstruction()
- * @see ssh_userauth_kbdint_getprompt()
- * @see ssh_userauth_kbdint_setanswer()
- */
-int ssh_userauth_kbdint(ssh_session session, const char *user,
- const char *submethods) {
- int rc = SSH_AUTH_ERROR;
-
- if (session->version == 1) {
- /* No keyb-interactive for ssh1 */
- return SSH_AUTH_DENIED;
- }
-
- enter_function();
-
- if (session->kbdint == NULL) {
- /* first time we call. we must ask for a challenge */
- if (user == NULL) {
- if ((user = session->username) == NULL) {
- if (ssh_options_apply(session) < 0) {
- leave_function();
- return SSH_AUTH_ERROR;
- } else {
- user = session->username;
- }
- }
- }
-
- if (ask_userauth(session)) {
- leave_function();
- return SSH_AUTH_ERROR;
- }
-
- rc = kbdauth_init(session, user, submethods);
-
- leave_function();
- return rc;
- }
-
- /*
- * If we are at this point, it is because session->kbdint exists.
- * It means the user has set some information there we need to send
- * the server and then we need to ack the status (new questions or ok
- * pass in).
- */
- rc = kbdauth_send(session);
-
- leave_function();
- return rc;
-}
-
-/**
- * @brief Get the number of prompts (questions) the server has given.
- *
- * You have called ssh_userauth_kbdint() and got SSH_AUTH_INFO. This
- * function returns the questions from the server.
- *
- * @param[in] session The ssh session to use.
- *
- * @returns The number of prompts.
- */
-int ssh_userauth_kbdint_getnprompts(ssh_session session) {
- return session->kbdint->nprompts;
-}
-
-/**
- * @brief Get the "name" of the message block.
- *
- * You have called ssh_userauth_kbdint() and got SSH_AUTH_INFO. This
- * function returns the questions from the server.
- *
- * @param[in] session The ssh session to use.
- *
- * @returns The name of the message block. Do not free it.
- */
-const char *ssh_userauth_kbdint_getname(ssh_session session) {
- return session->kbdint->name;
-}
-
-/**
- * @brief Get the "instruction" of the message block.
- *
- * You have called ssh_userauth_kbdint() and got SSH_AUTH_INFO. This
- * function returns the questions from the server.
- *
- * @param[in] session The ssh session to use.
- *
- * @returns The instruction of the message block.
- */
-
-const char *ssh_userauth_kbdint_getinstruction(ssh_session session) {
- return session->kbdint->instruction;
-}
-
-/**
- * @brief Get a prompt from a message block.
- *
- * You have called ssh_userauth_kbdint() and got SSH_AUTH_INFO. This
- * function returns the questions from the server.
- *
- * @param[in] session The ssh session to use.
- *
- * @param[in] i The index number of the i'th prompt.
- *
- * @param[in] echo When different of NULL, it will obtain a boolean meaning
- * that the resulting user input should be echoed or not
- * (like passwords).
- *
- * @returns A pointer to the prompt. Do not free it.
- */
-const char *ssh_userauth_kbdint_getprompt(ssh_session session, unsigned int i,
- char *echo) {
- if (i > session->kbdint->nprompts) {
- return NULL;
- }
-
- if (echo) {
- *echo = session->kbdint->echo[i];
- }
-
- return session->kbdint->prompts[i];
-}
-
-/**
- * @brief Set the answer for a question from a message block.
- *
- * If you have called ssh_userauth_kbdint() and got SSH_AUTH_INFO, this
- * function returns the questions from the server.
- *
- * @param[in] session The ssh session to use.
- *
- * @param[in] i index The number of the ith prompt.
- *
- * @param[in] answer The answer to give to the server.
- *
- * @return 0 on success, < 0 on error.
- */
-int ssh_userauth_kbdint_setanswer(ssh_session session, unsigned int i,
- const char *answer) {
- if (session == NULL || answer == NULL || i > session->kbdint->nprompts) {
- return -1;
- }
-
- if (session->kbdint->answers == NULL) {
- session->kbdint->answers = malloc(sizeof(char*) * session->kbdint->nprompts);
- if (session->kbdint->answers == NULL) {
- return -1;
- }
- memset(session->kbdint->answers, 0, sizeof(char *) * session->kbdint->nprompts);
- }
-
- if (session->kbdint->answers[i]) {
- BURN_STRING(session->kbdint->answers[i]);
- SAFE_FREE(session->kbdint->answers[i]);
- }
-
- session->kbdint->answers[i] = strdup(answer);
- if (session->kbdint->answers[i] == NULL) {
- return -1;
- }
-
- return 0;
-}
-
-/** @} */
-
-/* vim: set ts=4 sw=4 et cindent: */
diff --git a/libssh/auth1.c b/libssh/auth1.c
deleted file mode 100644
index 06f05497..00000000
--- a/libssh/auth1.c
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * auth1.c - authentication with SSH-1 protocol
- *
- * This file is part of the SSH Library
- *
- * Copyright (c) 2005-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 "config.h"
-
-#include <string.h>
-#include <stdlib.h>
-
-#include "libssh/priv.h"
-#include "libssh/ssh1.h"
-#include "libssh/buffer.h"
-#include "libssh/packet.h"
-#include "libssh/session.h"
-#include "libssh/string.h"
-
-#ifdef WITH_SSH1
-static int wait_auth1_status(ssh_session session) {
- enter_function();
- /* wait for a packet */
- while(session->auth_state == SSH_AUTH_STATE_NONE)
- if (ssh_handle_packets(session,-1) != SSH_OK)
- break;
- ssh_log(session,SSH_LOG_PROTOCOL,"Auth state : %d",session->auth_state);
- leave_function();
- switch(session->auth_state) {
- case SSH_AUTH_STATE_SUCCESS:
- return SSH_AUTH_SUCCESS;
- case SSH_AUTH_STATE_FAILED:
- return SSH_AUTH_DENIED;
- default:
- return SSH_AUTH_ERROR;
- }
- return SSH_AUTH_ERROR;
-}
-
-void ssh_auth1_handler(ssh_session session, uint8_t type){
- if(session->session_state != SSH_SESSION_STATE_AUTHENTICATING){
- ssh_set_error(session,SSH_FATAL,"SSH_SMSG_SUCCESS or FAILED received in wrong state");
- return;
- }
- if(type==SSH_SMSG_SUCCESS){
- session->auth_state=SSH_AUTH_STATE_SUCCESS;
- session->session_state=SSH_SESSION_STATE_AUTHENTICATED;
- } else if(type==SSH_SMSG_FAILURE)
- session->auth_state=SSH_AUTH_STATE_FAILED;
-}
-
-static int send_username(ssh_session session, const char *username) {
- ssh_string user = NULL;
- /* returns SSH_AUTH_SUCCESS or SSH_AUTH_DENIED */
- if(session->auth_service_state == SSH_AUTH_SERVICE_USER_SENT) {
- if(session->auth_state == SSH_AUTH_STATE_FAILED)
- return SSH_AUTH_DENIED;
- if(session->auth_state == SSH_AUTH_STATE_SUCCESS)
- return SSH_AUTH_SUCCESS;
- return SSH_AUTH_ERROR;
- }
-
- if (!username) {
- if(!(username = session->username)) {
- if (ssh_options_set(session, SSH_OPTIONS_USER, NULL) < 0) {
- session->auth_service_state = SSH_AUTH_SERVICE_DENIED;
- return SSH_ERROR;
- } else {
- username = session->username;
- }
- }
- }
- user = ssh_string_from_char(username);
- if (user == NULL) {
- return SSH_AUTH_ERROR;
- }
-
- if (buffer_add_u8(session->out_buffer, SSH_CMSG_USER) < 0) {
- ssh_string_free(user);
- return SSH_AUTH_ERROR;
- }
- if (buffer_add_ssh_string(session->out_buffer, user) < 0) {
- ssh_string_free(user);
- return SSH_AUTH_ERROR;
- }
- ssh_string_free(user);
- session->auth_state=SSH_AUTH_STATE_NONE;
- if (packet_send(session) == SSH_ERROR) {
- return SSH_AUTH_ERROR;
- }
-
- if(wait_auth1_status(session) == SSH_AUTH_SUCCESS){
- session->auth_service_state=SSH_AUTH_SERVICE_USER_SENT;
- session->auth_state=SSH_AUTH_STATE_SUCCESS;
- return SSH_AUTH_SUCCESS;
- } else {
- session->auth_service_state=SSH_AUTH_SERVICE_USER_SENT;
- ssh_set_error(session,SSH_REQUEST_DENIED,"Password authentication necessary for user %s",username);
- return SSH_AUTH_DENIED;
- }
-
-}
-
-/* use the "none" authentication question */
-int ssh_userauth1_none(ssh_session session, const char *username){
- return send_username(session, username);
-}
-
-/** \internal
- * \todo implement ssh1 public key
- */
-int ssh_userauth1_offer_pubkey(ssh_session session, const char *username,
- int type, ssh_string pubkey) {
- (void) session;
- (void) username;
- (void) type;
- (void) pubkey;
- enter_function();
- leave_function();
- return SSH_AUTH_DENIED;
-}
-
-int ssh_userauth1_password(ssh_session session, const char *username,
- const char *password) {
- ssh_string pwd = NULL;
- int rc;
- enter_function();
- rc = send_username(session, username);
- if (rc != SSH_AUTH_DENIED) {
- leave_function();
- return rc;
- }
-
- /* we trick a bit here. A known flaw in SSH1 protocol is that it's
- * easy to guess password sizes.
- * not that sure ...
- */
-
- /* XXX fix me here ! */
- /* cisco IOS doesn't like when a password is followed by zeroes and random pad. */
- if(1 || strlen(password) >= 128) {
- /* not risky to disclose the size of such a big password .. */
- pwd = ssh_string_from_char(password);
- if (pwd == NULL) {
- leave_function();
- return SSH_AUTH_ERROR;
- }
- } else {
- /* fill the password string from random things. the strcpy
- * ensure there is at least a nul byte after the password.
- * most implementation won't see the garbage at end.
- * why garbage ? because nul bytes will be compressed by
- * gzip and disclose password len.
- */
- pwd = ssh_string_new(128);
- if (pwd == NULL) {
- leave_function();
- return SSH_AUTH_ERROR;
- }
- ssh_get_random( pwd->string, 128, 0);
- strcpy((char *) pwd->string, password);
- }
-
- if (buffer_add_u8(session->out_buffer, SSH_CMSG_AUTH_PASSWORD) < 0) {
- ssh_string_burn(pwd);
- ssh_string_free(pwd);
- leave_function();
- return SSH_AUTH_ERROR;
- }
- if (buffer_add_ssh_string(session->out_buffer, pwd) < 0) {
- ssh_string_burn(pwd);
- ssh_string_free(pwd);
- leave_function();
- return SSH_AUTH_ERROR;
- }
-
- ssh_string_burn(pwd);
- ssh_string_free(pwd);
- session->auth_state=SSH_AUTH_STATE_NONE;
- if (packet_send(session) == SSH_ERROR) {
- leave_function();
- return SSH_AUTH_ERROR;
- }
- rc = wait_auth1_status(session);
- leave_function();
- return rc;
-}
-
-#endif /* WITH_SSH1 */
-/* vim: set ts=2 sw=2 et cindent: */
diff --git a/libssh/base64.c b/libssh/base64.c
deleted file mode 100644
index 262c97ca..00000000
--- a/libssh/base64.c
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * base64.c - support for base64 alphabet system, described in RFC1521
- *
- * This file is part of the SSH Library
- *
- * Copyright (c) 2005-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.
- */
-
-/* just the dirtiest part of code i ever made */
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "libssh/priv.h"
-#include "libssh/buffer.h"
-
-static char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "abcdefghijklmnopqrstuvwxyz"
- "0123456789+/";
-
-/* Transformations */
-#define SET_A(n, i) do { (n) |= ((i) & 63) <<18; } while (0)
-#define SET_B(n, i) do { (n) |= ((i) & 63) <<12; } while (0)
-#define SET_C(n, i) do { (n) |= ((i) & 63) << 6; } while (0)
-#define SET_D(n, i) do { (n) |= ((i) & 63); } while (0)
-
-#define GET_A(n) (((n) & 0xff0000) >> 16)
-#define GET_B(n) (((n) & 0xff00) >> 8)
-#define GET_C(n) ((n) & 0xff)
-
-static int _base64_to_bin(unsigned char dest[3], const char *source, int num);
-static int get_equals(char *string);
-
-/* First part: base64 to binary */
-
-/**
- * @internal
- *
- * @brief Translates a base64 string into a binary one.
- *
- * @returns A buffer containing the decoded string, NULL if something went
- * wrong (e.g. incorrect char).
- */
-ssh_buffer base64_to_bin(const char *source) {
- ssh_buffer buffer = NULL;
- unsigned char block[3];
- char *base64;
- char *ptr;
- size_t len;
- int equals;
-
- base64 = strdup(source);
- if (base64 == NULL) {
- return NULL;
- }
- ptr = base64;
-
- /* Get the number of equals signs, which mirrors the padding */
- equals = get_equals(ptr);
- if (equals > 2) {
- SAFE_FREE(base64);
- return NULL;
- }
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- SAFE_FREE(base64);
- return NULL;
- }
-
- len = strlen(ptr);
- while (len > 4) {
- if (_base64_to_bin(block, ptr, 3) < 0) {
- goto error;
- }
- if (buffer_add_data(buffer, block, 3) < 0) {
- goto error;
- }
- len -= 4;
- ptr += 4;
- }
-
- /*
- * Depending on the number of bytes resting, there are 3 possibilities
- * from the RFC.
- */
- switch (len) {
- /*
- * (1) The final quantum of encoding input is an integral multiple of
- * 24 bits. Here, the final unit of encoded output will be an integral
- * multiple of 4 characters with no "=" padding
- */
- case 4:
- if (equals != 0) {
- goto error;
- }
- if (_base64_to_bin(block, ptr, 3) < 0) {
- goto error;
- }
- if (buffer_add_data(buffer, block, 3) < 0) {
- goto error;
- }
- SAFE_FREE(base64);
-
- return buffer;
- /*
- * (2) The final quantum of encoding input is exactly 8 bits; here, the
- * final unit of encoded output will be two characters followed by
- * two "=" padding characters.
- */
- case 2:
- if (equals != 2){
- goto error;
- }
-
- if (_base64_to_bin(block, ptr, 1) < 0) {
- goto error;
- }
- if (buffer_add_data(buffer, block, 1) < 0) {
- goto error;
- }
- SAFE_FREE(base64);
-
- return buffer;
- /*
- * The final quantum of encoding input is exactly 16 bits. Here, the final
- * unit of encoded output will be three characters followed by one "="
- * padding character.
- */
- case 3:
- if (equals != 1) {
- goto error;
- }
- if (_base64_to_bin(block, ptr, 2) < 0) {
- goto error;
- }
- if (buffer_add_data(buffer,block,2) < 0) {
- goto error;
- }
- SAFE_FREE(base64);
-
- return buffer;
- default:
- /* 4,3,2 are the only padding size allowed */
- goto error;
- }
-
-error:
- SAFE_FREE(base64);
- ssh_buffer_free(buffer);
- return NULL;
-}
-
-#define BLOCK(letter, n) do {ptr = strchr(alphabet, source[n]); \
- if(!ptr) return -1; \
- i = ptr - alphabet; \
- SET_##letter(*block, i); \
- } while(0)
-
-/* Returns 0 if ok, -1 if not (ie invalid char into the stuff) */
-static int to_block4(unsigned long *block, const char *source, int num) {
- char *ptr;
- unsigned int i;
-
- *block = 0;
- if (num < 1) {
- return 0;
- }
-
- BLOCK(A, 0); /* 6 bit */
- BLOCK(B,1); /* 12 bit */
-
- if (num < 2) {
- return 0;
- }
-
- BLOCK(C, 2); /* 18 bit */
-
- if (num < 3) {
- return 0;
- }
-
- BLOCK(D, 3); /* 24 bit */
-
- return 0;
-}
-
-/* num = numbers of final bytes to be decoded */
-static int _base64_to_bin(unsigned char dest[3], const char *source, int num) {
- unsigned long block;
-
- if (to_block4(&block, source, num) < 0) {
- return -1;
- }
- dest[0] = GET_A(block);
- dest[1] = GET_B(block);
- dest[2] = GET_C(block);
-
- return 0;
-}
-
-/* Count the number of "=" signs and replace them by zeroes */
-static int get_equals(char *string) {
- char *ptr = string;
- int num = 0;
-
- while ((ptr=strchr(ptr,'=')) != NULL) {
- num++;
- *ptr = '\0';
- ptr++;
- }
-
- return num;
-}
-
-/* thanks sysk for debugging my mess :) */
-#define BITS(n) ((1 << (n)) - 1)
-static void _bin_to_base64(unsigned char *dest, const unsigned char source[3],
- int len) {
- switch (len) {
- case 1:
- dest[0] = alphabet[(source[0] >> 2)];
- dest[1] = alphabet[((source[0] & BITS(2)) << 4)];
- dest[2] = '=';
- dest[3] = '=';
- break;
- case 2:
- dest[0] = alphabet[source[0] >> 2];
- dest[1] = alphabet[(source[1] >> 4) | ((source[0] & BITS(2)) << 4)];
- dest[2] = alphabet[(source[1] & BITS(4)) << 2];
- dest[3] = '=';
- break;
- case 3:
- dest[0] = alphabet[(source[0] >> 2)];
- dest[1] = alphabet[(source[1] >> 4) | ((source[0] & BITS(2)) << 4)];
- dest[2] = alphabet[ (source[2] >> 6) | (source[1] & BITS(4)) << 2];
- dest[3] = alphabet[source[2] & BITS(6)];
- break;
- }
-}
-
-/**
- * @internal
- *
- * @brief Converts binary data to a base64 string.
- *
- * @returns the converted string
- */
-unsigned char *bin_to_base64(const unsigned char *source, int len) {
- unsigned char *base64;
- unsigned char *ptr;
- int flen = len + (3 - (len % 3)); /* round to upper 3 multiple */
- flen = (4 * flen) / 3 + 1;
-
- base64 = malloc(flen);
- if (base64 == NULL) {
- return NULL;
- }
- ptr = base64;
-
- while(len > 0){
- _bin_to_base64(ptr, source, len > 3 ? 3 : len);
- ptr += 4;
- source += 3;
- len -= 3;
- }
- ptr[0] = '\0';
-
- return base64;
-}
-
-/* vim: set ts=2 sw=2 et cindent: */
diff --git a/libssh/buffer.c b/libssh/buffer.c
deleted file mode 100644
index 80c99560..00000000
--- a/libssh/buffer.c
+++ /dev/null
@@ -1,578 +0,0 @@
-/*
- * buffer.c - buffer functions
- *
- * This file is part of the SSH Library
- *
- * Copyright (c) 2003-2009 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 <stdlib.h>
-#include <string.h>
-
-#ifndef _WIN32
-#include <arpa/inet.h>
-#endif
-
-#include "libssh/priv.h"
-#include "libssh/buffer.h"
-
-/**
- * @defgroup libssh_buffer The SSH buffer functions.
- * @ingroup libssh
- *
- * Functions to handle SSH buffers.
- *
- * @{
- */
-
-
-#ifdef DEBUG_BUFFER
-/**
- * @internal
- *
- * @brief Check that preconditions and postconditions are valid.
- *
- * @param[in] buf The buffer to check.
- */
-static void buffer_verify(struct buffer_struct *buf){
- int doabort=0;
- if(buf->data == NULL)
- return;
- if(buf->used > buf->allocated){
- fprintf(stderr,"Buffer error : allocated %u, used %u\n",buf->allocated, buf->used);
- doabort=1;
- }
- if(buf->pos > buf->used){
- fprintf(stderr,"Buffer error : position %u, used %u\n",buf->pos, buf->used);
- doabort=1;
- }
- if(buf->pos > buf->allocated){
- fprintf(stderr,"Buffer error : position %u, allocated %u\n",buf->pos, buf->allocated);
- doabort=1;
- }
- if(doabort)
- abort();
-}
-
-#else
-#define buffer_verify(x)
-#endif
-
-/**
- * @brief Create a new SSH buffer.
- *
- * @return A newly initialized SSH buffer, NULL on error.
- */
-struct ssh_buffer_struct *ssh_buffer_new(void) {
- struct ssh_buffer_struct *buf = malloc(sizeof(struct ssh_buffer_struct));
-
- if (buf == NULL) {
- return NULL;
- }
- memset(buf, 0, sizeof(struct ssh_buffer_struct));
- buffer_verify(buf);
- return buf;
-}
-
-/**
- * @brief Deallocate a SSH buffer.
- *
- * \param[in] buffer The buffer to free.
- */
-void ssh_buffer_free(struct ssh_buffer_struct *buffer) {
- if (buffer == NULL) {
- return;
- }
- buffer_verify(buffer);
-
- if (buffer->data) {
- /* burn the data */
- memset(buffer->data, 0, buffer->allocated);
- SAFE_FREE(buffer->data);
- }
- memset(buffer, 'X', sizeof(*buffer));
- SAFE_FREE(buffer);
-}
-
-static int realloc_buffer(struct ssh_buffer_struct *buffer, int needed) {
- int smallest = 1;
- char *new = NULL;
- buffer_verify(buffer);
- /* Find the smallest power of two which is greater or equal to needed */
- while(smallest < needed) {
- smallest <<= 1;
- }
- needed = smallest;
- new = realloc(buffer->data, needed);
- if (new == NULL) {
- return -1;
- }
- buffer->data = new;
- buffer->allocated = needed;
- buffer_verify(buffer);
- return 0;
-}
-
-/**
- * @internal
- *
- * @brief Reinitialize a SSH buffer.
- *
- * @param[in] buffer The buffer to reinitialize.
- *
- * @return 0 on success, < 0 on error.
- */
-int buffer_reinit(struct ssh_buffer_struct *buffer) {
- buffer_verify(buffer);
- memset(buffer->data, 0, buffer->used);
- buffer->used = 0;
- buffer->pos = 0;
- if(buffer->allocated > 127) {
- if (realloc_buffer(buffer, 127) < 0) {
- return -1;
- }
- }
- buffer_verify(buffer);
- return 0;
-}
-
-/**
- * @internal
- *
- * @brief Add data at the tail of a buffer.
- *
- * @param[in] buffer The buffer to add the data.
- *
- * @param[in] data A pointer to the data to add.
- *
- * @param[in] len The length of the data to add.
- *
- * @return 0 on success, < 0 on error.
- */
-int buffer_add_data(struct ssh_buffer_struct *buffer, const void *data, uint32_t len) {
- buffer_verify(buffer);
- if (buffer->allocated < (buffer->used + len)) {
- if (realloc_buffer(buffer, buffer->used + len) < 0) {
- return -1;
- }
- }
-
- memcpy(buffer->data+buffer->used, data, len);
- buffer->used+=len;
- buffer_verify(buffer);
- return 0;
-}
-
-/**
- * @internal
- *
- * @brief Add a SSH string to the tail of a buffer.
- *
- * @param[in] buffer The buffer to add the string.
- *
- * @param[in] string The SSH String to add.
- *
- * @return 0 on success, < 0 on error.
- */
-int buffer_add_ssh_string(struct ssh_buffer_struct *buffer,
- struct ssh_string_struct *string) {
- uint32_t len = 0;
-
- len = ssh_string_len(string);
- if (buffer_add_data(buffer, string, len + sizeof(uint32_t)) < 0) {
- return -1;
- }
-
- return 0;
-}
-
-/**
- * @internal
- *
- * @brief Add a 32 bits unsigned integer to the tail of a buffer.
- *
- * @param[in] buffer The buffer to add the integer.
- *
- * @param[in] data The 32 bits integer to add.
- *
- * @return 0 on success, -1 on error.
- */
-int buffer_add_u32(struct ssh_buffer_struct *buffer,uint32_t data){
- if (buffer_add_data(buffer, &data, sizeof(data)) < 0) {
- return -1;
- }
-
- return 0;
-}
-
-/**
- * @internal
- *
- * @brief Add a 16 bits unsigned integer to the tail of a buffer.
- *
- * @param[in] buffer The buffer to add the integer.
- *
- * @param[in] data The 16 bits integer to add.
- *
- * @return 0 on success, -1 on error.
- */
-int buffer_add_u16(struct ssh_buffer_struct *buffer,uint16_t data){
- if (buffer_add_data(buffer, &data, sizeof(data)) < 0) {
- return -1;
- }
-
- return 0;
-}
-
-/**
- * @internal
- *
- * @brief Add a 64 bits unsigned integer to the tail of a buffer.
- *
- * @param[in] buffer The buffer to add the integer.
- *
- * @param[in] data The 64 bits integer to add.
- *
- * @return 0 on success, -1 on error.
- */
-int buffer_add_u64(struct ssh_buffer_struct *buffer, uint64_t data){
- if (buffer_add_data(buffer, &data, sizeof(data)) < 0) {
- return -1;
- }
-
- return 0;
-}
-
-/**
- * @internal
- *
- * @brief Add a 8 bits unsigned integer to the tail of a buffer.
- *
- * @param[in] buffer The buffer to add the integer.
- *
- * @param[in] data The 8 bits integer to add.
- *
- * @return 0 on success, -1 on error.
- */
-int buffer_add_u8(struct ssh_buffer_struct *buffer,uint8_t data){
- if (buffer_add_data(buffer, &data, sizeof(uint8_t)) < 0) {
- return -1;
- }
-
- return 0;
-}
-
-/**
- * @internal
- *
- * @brief Add data at the head of a buffer.
- *
- * @param[in] buffer The buffer to add the data.
- *
- * @param[in] data The data to prepend.
- *
- * @param[in] len The length of data to prepend.
- *
- * @return 0 on success, -1 on error.
- */
-int buffer_prepend_data(struct ssh_buffer_struct *buffer, const void *data,
- uint32_t len) {
- buffer_verify(buffer);
- if (buffer->allocated < (buffer->used + len)) {
- if (realloc_buffer(buffer, buffer->used + len) < 0) {
- return -1;
- }
- }
- memmove(buffer->data + len, buffer->data, buffer->used);
- memcpy(buffer->data, data, len);
- buffer->used += len;
- buffer_verify(buffer);
- return 0;
-}
-
-/**
- * @internal
- *
- * @brief Append data from a buffer to the tail of another buffer.
- *
- * @param[in] buffer The destination buffer.
- *
- * @param[in] source The source buffer to append. It doesn't take the
- * position of the buffer into account.
- *
- * @return 0 on success, -1 on error.
- */
-int buffer_add_buffer(struct ssh_buffer_struct *buffer,
- struct ssh_buffer_struct *source) {
- if (buffer_add_data(buffer, ssh_buffer_get_begin(source), ssh_buffer_get_len(source)) < 0) {
- return -1;
- }
-
- return 0;
-}
-
-/**
- * @brief Get a pointer on the head of a buffer.
- *
- * @param[in] buffer The buffer to get the head pointer.
- *
- * @return A data pointer on the head. It doesn't take the position
- * into account.
- *
- * @warning Don't expect data to be nul-terminated.
- *
- * @see buffer_get_rest()
- * @see buffer_get_len()
- */
-void *ssh_buffer_get_begin(struct ssh_buffer_struct *buffer){
- return buffer->data;
-}
-
-/**
- * @internal
- *
- * @brief Get a pointer to the head of a buffer at the current position.
- *
- * @param[in] buffer The buffer to get the head pointer.
- *
- * @return A pointer to the data from current position.
- *
- * @see buffer_get_rest_len()
- * @see buffer_get()
- */
-void *buffer_get_rest(struct ssh_buffer_struct *buffer){
- return buffer->data + buffer->pos;
-}
-
-/**
- * @brief Get the length of the buffer, not counting position.
- *
- * @param[in] buffer The buffer to get the length from.
- *
- * @return The length of the buffer.
- *
- * @see buffer_get()
- */
-uint32_t ssh_buffer_get_len(struct ssh_buffer_struct *buffer){
- return buffer->used;
-}
-
-/**
- * @internal
- *
- * @brief Get the length of the buffer from the current position.
- *
- * @param[in] buffer The buffer to get the length from.
- *
- * @return The length of the buffer.
- *
- * @see buffer_get_rest()
- */
-uint32_t buffer_get_rest_len(struct ssh_buffer_struct *buffer){
- buffer_verify(buffer);
- return buffer->used - buffer->pos;
-}
-
-/**
- * @internal
- *
- * @brief Advance the position in the buffer.
- *
- * This has effect to "eat" bytes at head of the buffer.
- *
- * @param[in] buffer The buffer to advance the position.
- *
- * @param[in] len The number of bytes to eat.
- *
- * @return The new size of the buffer.
- */
-uint32_t buffer_pass_bytes(struct ssh_buffer_struct *buffer, uint32_t len){
- buffer_verify(buffer);
- if(buffer->used < buffer->pos+len)
- return 0;
- buffer->pos+=len;
- /* if the buffer is empty after having passed the whole bytes into it, we can clean it */
- if(buffer->pos==buffer->used){
- buffer->pos=0;
- buffer->used=0;
- }
- buffer_verify(buffer);
- return len;
-}
-
-/**
- * @internal
- *
- * @brief Cut the end of the buffer.
- *
- * @param[in] buffer The buffer to cut.
- *
- * @param[in] len The number of bytes to remove from the tail.
- *
- * @return The new size of the buffer.
- */
-uint32_t buffer_pass_bytes_end(struct ssh_buffer_struct *buffer, uint32_t len){
- buffer_verify(buffer);
- if(buffer->used < buffer->pos + len)
- return 0;
- buffer->used-=len;
- buffer_verify(buffer);
- return len;
-}
-
-/**
- * @internal
- *
- * @brief Get the remaining data out of the buffer and adjust the read pointer.
- *
- * @param[in] buffer The buffer to read.
- *
- * @param[in] data The data buffer where to store the data.
- *
- * @param[in] len The length to read from the buffer.
- *
- * @returns 0 if there is not enough data in buffer, len otherwise.
- */
-uint32_t buffer_get_data(struct ssh_buffer_struct *buffer, void *data, uint32_t len){
- /*
- * Check for a integer overflow first, then check if not enough data is in
- * the buffer.
- */
- if (buffer->pos + len < len || buffer->pos + len > buffer->used) {
- return 0;
- }
- memcpy(data,buffer->data+buffer->pos,len);
- buffer->pos+=len;
- return len; /* no yet support for partial reads (is it really needed ?? ) */
-}
-
-/**
- * @internal
- *
- * @brief Get a 8 bits unsigned int out of the buffer and adjusts the read
- * pointer.
- *
- * @param[in] buffer The buffer to read.
- *
- * @param[in] data A pointer to a uint8_t where to store the data.
- *
- * @returns 0 if there is not enough data in buffer, 1 otherwise.
- */
-int buffer_get_u8(struct ssh_buffer_struct *buffer, uint8_t *data){
- return buffer_get_data(buffer,data,sizeof(uint8_t));
-}
-
-/** \internal
- * \brief gets a 32 bits unsigned int out of the buffer. Adjusts the read pointer.
- * \param buffer Buffer to read
- * \param data pointer to a uint32_t where to store the data
- * \returns 0 if there is not enough data in buffer
- * \returns 4 otherwise.
- */
-int buffer_get_u32(struct ssh_buffer_struct *buffer, uint32_t *data){
- return buffer_get_data(buffer,data,sizeof(uint32_t));
-}
-/**
- * @internal
- *
- * @brief Get a 64 bits unsigned int out of the buffer and adjusts the read
- * pointer.
- *
- * @param[in] buffer The buffer to read.
- *
- * @param[in] data A pointer to a uint64_t where to store the data.
- *
- * @returns 0 if there is not enough data in buffer, 8 otherwise.
- */
-int buffer_get_u64(struct ssh_buffer_struct *buffer, uint64_t *data){
- return buffer_get_data(buffer,data,sizeof(uint64_t));
-}
-
-/**
- * @internal
- *
- * @brief Get a SSH String out of the buffer and adjusts the read pointer.
- *
- * @param[in] buffer The buffer to read.
- *
- * @returns The SSH String, NULL on error.
- */
-struct ssh_string_struct *buffer_get_ssh_string(struct ssh_buffer_struct *buffer) {
- uint32_t stringlen;
- uint32_t hostlen;
- struct ssh_string_struct *str = NULL;
-
- if (buffer_get_u32(buffer, &stringlen) == 0) {
- return NULL;
- }
- hostlen = ntohl(stringlen);
- /* verify if there is enough space in buffer to get it */
- if ((buffer->pos + hostlen) > buffer->used) {
- return NULL; /* it is indeed */
- }
- str = ssh_string_new(hostlen);
- if (str == NULL) {
- return NULL;
- }
- if (buffer_get_data(buffer, ssh_string_data(str), hostlen) != hostlen) {
- /* should never happen */
- SAFE_FREE(str);
- return NULL;
- }
-
- return str;
-}
-
-/**
- * @internal
- *
- * @brief Get a mpint out of the buffer and adjusts the read pointer.
- *
- * @note This function is SSH-1 only.
- *
- * @param[in] buffer The buffer to read.
- *
- * @returns The SSH String containing the mpint, NULL on error.
- */
-struct ssh_string_struct *buffer_get_mpint(struct ssh_buffer_struct *buffer) {
- uint16_t bits;
- uint32_t len;
- struct ssh_string_struct *str = NULL;
-
- if (buffer_get_data(buffer, &bits, sizeof(uint16_t)) != sizeof(uint16_t)) {
- return NULL;
- }
- bits = ntohs(bits);
- len = (bits + 7) / 8;
- if ((buffer->pos + len) > buffer->used) {
- return NULL;
- }
- str = ssh_string_new(len);
- if (str == NULL) {
- return NULL;
- }
- if (buffer_get_data(buffer, ssh_string_data(str), len) != len) {
- SAFE_FREE(str);
- return NULL;
- }
- return str;
-}
-
-/** @} */
-
-/* vim: set ts=4 sw=4 et cindent: */
diff --git a/libssh/callbacks.c b/libssh/callbacks.c
deleted file mode 100644
index 1568d516..00000000
--- a/libssh/callbacks.c
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * callbacks.c - callback functions
- *
- * This file is part of the SSH Library
- *
- * Copyright (c) 2009 by Andreas Schneider <mail@cynapses.org>
- *
- * 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 "libssh/callbacks.h"
-#include "libssh/session.h"
-
-int ssh_set_callbacks(ssh_session session, ssh_callbacks cb) {
- if (session == NULL || cb == NULL) {
- return SSH_ERROR;
- }
- enter_function();
- if(cb->size <= 0 || cb->size > 1024 * sizeof(void *)){
- ssh_set_error(session,SSH_FATAL,
- "Invalid callback passed in (badly initialized)");
- leave_function();
- return SSH_ERROR;
- }
- session->callbacks = cb;
- leave_function();
- return 0;
-}
diff --git a/libssh/channels.c b/libssh/channels.c
deleted file mode 100644
index 6900beea..00000000
--- a/libssh/channels.c
+++ /dev/null
@@ -1,2495 +0,0 @@
-/*
- * channels.c - SSH channel functions
- *
- * This file is part of the SSH Library
- *
- * Copyright (c) 2003-2008 by Aris Adamantiadis
- * Copyright (c) 2009 by Andreas Schneider <mail@cynapses.org>
- *
- * 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 <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-#include <time.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/channels.h"
-#include "libssh/session.h"
-#include "libssh/misc.h"
-#include "libssh/messages.h"
-
-#define WINDOWBASE 128000
-#define WINDOWLIMIT (WINDOWBASE/2)
-
-/**
- * @defgroup libssh_channel The SSH channel functions
- * @ingroup libssh
- *
- * Functions that manage a SSH channel.
- *
- * @{
- */
-
-static ssh_channel channel_from_msg(ssh_session session, ssh_buffer packet);
-
-/**
- * @brief Allocate a new channel.
- *
- * @param[in] session The ssh session to use.
- *
- * @return A pointer to a newly allocated channel, NULL on error.
- */
-ssh_channel ssh_channel_new(ssh_session session) {
- ssh_channel channel = NULL;
-
- channel = malloc(sizeof(struct ssh_channel_struct));
- if (channel == NULL) {
- return NULL;
- }
- memset(channel,0,sizeof(struct ssh_channel_struct));
-
- channel->stdout_buffer = ssh_buffer_new();
- if (channel->stdout_buffer == NULL) {
- SAFE_FREE(channel);
- return NULL;
- }
-
- channel->stderr_buffer = ssh_buffer_new();
- if (channel->stderr_buffer == NULL) {
- ssh_buffer_free(channel->stdout_buffer);
- SAFE_FREE(channel);
- return NULL;
- }
-
- channel->session = session;
- channel->version = session->version;
- channel->exit_status = -1;
-
- if(session->channels == NULL) {
- session->channels = channel;
- channel->next = channel->prev = channel;
- return channel;
- }
- channel->next = session->channels;
- channel->prev = session->channels->prev;
- channel->next->prev = channel;
- channel->prev->next = channel;
-
- return channel;
-}
-
-/**
- * @internal
- *
- * @brief Create a new channel identifier.
- *
- * @param[in] session The SSH session to use.
- *
- * @return The new channel identifier.
- */
-uint32_t ssh_channel_new_id(ssh_session session) {
- return ++(session->maxchannel);
-}
-
-/**
- * @internal
- *
- * @brief Handle a SSH_PACKET_CHANNEL_OPEN_CONFIRMATION packet.
- *
- * Constructs the channel object.
- */
-SSH_PACKET_CALLBACK(ssh_packet_channel_open_conf){
- uint32_t channelid=0;
- uint32_t tmp;
- ssh_channel channel;
- (void)type;
- (void)user;
- enter_function();
- ssh_log(session,SSH_LOG_PACKET,"Received SSH2_MSG_CHANNEL_OPEN_CONFIRMATION");
-
- buffer_get_u32(packet, &channelid);
- channelid=ntohl(channelid);
- channel=ssh_channel_from_local(session,channelid);
- if(channel==NULL){
- ssh_set_error(session, SSH_FATAL,
- "Unknown channel id %lu",
- (long unsigned int) channelid);
- /* TODO: Set error marking in channel object */
- leave_function();
- return SSH_PACKET_USED;
- }
-
- buffer_get_u32(packet, &tmp);
- channel->remote_channel = ntohl(tmp);
-
- buffer_get_u32(packet, &tmp);
- channel->remote_window = ntohl(tmp);
-
- buffer_get_u32(packet,&tmp);
- channel->remote_maxpacket=ntohl(tmp);
-
- ssh_log(session, SSH_LOG_PROTOCOL,
- "Received a CHANNEL_OPEN_CONFIRMATION for channel %d:%d",
- channel->local_channel,
- channel->remote_channel);
- ssh_log(session, SSH_LOG_PROTOCOL,
- "Remote window : %lu, maxpacket : %lu",
- (long unsigned int) channel->remote_window,
- (long unsigned int) channel->remote_maxpacket);
-
- channel->state = SSH_CHANNEL_STATE_OPEN;
- leave_function();
- return SSH_PACKET_USED;
-}
-
-/**
- * @internal
- *
- * @brief Handle a SSH_CHANNEL_OPEN_FAILURE and set the state of the channel.
- */
-SSH_PACKET_CALLBACK(ssh_packet_channel_open_fail){
-
- ssh_channel channel;
- ssh_string error_s;
- char *error = NULL;
- uint32_t code;
- (void)user;
- (void)type;
- channel=channel_from_msg(session,packet);
- if(channel==NULL){
- ssh_log(session,SSH_LOG_RARE,"Invalid channel in packet");
- return SSH_PACKET_USED;
- }
- buffer_get_u32(packet, &code);
-
- error_s = buffer_get_ssh_string(packet);
- if(error_s != NULL)
- error = ssh_string_to_char(error_s);
- ssh_string_free(error_s);
- if (error == NULL) {
- ssh_set_error_oom(session);
- return SSH_PACKET_USED;
- }
-
- ssh_set_error(session, SSH_REQUEST_DENIED,
- "Channel opening failure: channel %u error (%lu) %s",
- channel->local_channel,
- (long unsigned int) ntohl(code),
- error);
- SAFE_FREE(error);
- channel->state=SSH_CHANNEL_STATE_OPEN_DENIED;
- return SSH_PACKET_USED;
-}
-
-/**
- * @internal
- *
- * @brief Open a channel by sending a SSH_OPEN_CHANNEL message and
- * wait for the reply.
- *
- * @param[in] channel The current channel.
- *
- * @param[in] type_c A C string describing the kind of channel (e.g. "exec").
- *
- * @param[in] window The receiving window of the channel. The window is the
- * maximum size of data that can stay in buffers and
- * network.
- *
- * @param[in] maxpacket The maximum packet size allowed (like MTU).
- *
- * @param[in] payload The buffer containing additional payload for the query.
- */
-static int channel_open(ssh_channel channel, const char *type_c, int window,
- int maxpacket, ssh_buffer payload) {
- ssh_session session = channel->session;
- ssh_string type = NULL;
- int err=SSH_ERROR;
-
- enter_function();
- channel->local_channel = ssh_channel_new_id(session);
- channel->local_maxpacket = maxpacket;
- channel->local_window = window;
-
- ssh_log(session, SSH_LOG_PROTOCOL,
- "Creating a channel %d with %d window and %d max packet",
- channel->local_channel, window, maxpacket);
-
- type = ssh_string_from_char(type_c);
- if (type == NULL) {
- leave_function();
- return err;
- }
-
- if (buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_OPEN) < 0 ||
- buffer_add_ssh_string(session->out_buffer,type) < 0 ||
- buffer_add_u32(session->out_buffer, htonl(channel->local_channel)) < 0 ||
- buffer_add_u32(session->out_buffer, htonl(channel->local_window)) < 0 ||
- buffer_add_u32(session->out_buffer, htonl(channel->local_maxpacket)) < 0) {
- ssh_string_free(type);
- leave_function();
- return err;
- }
-
- ssh_string_free(type);
-
- if (payload != NULL) {
- if (buffer_add_buffer(session->out_buffer, payload) < 0) {
- leave_function();
- return err;
- }
- }
-
- if (packet_send(session) == SSH_ERROR) {
- leave_function();
- return err;
- }
-
- ssh_log(session, SSH_LOG_PACKET,
- "Sent a SSH_MSG_CHANNEL_OPEN type %s for channel %d",
- type_c, channel->local_channel);
-
- /* Todo: fix this into a correct loop */
- /* wait until channel is opened by server */
- while(channel->state == SSH_CHANNEL_STATE_NOT_OPEN){
- ssh_handle_packets(session,-1);
- }
- if(channel->state == SSH_CHANNEL_STATE_OPEN)
- err=SSH_OK;
- leave_function();
- return err;
-}
-
-/* get ssh channel from local session? */
-ssh_channel ssh_channel_from_local(ssh_session session, uint32_t id) {
- ssh_channel initchan = session->channels;
- ssh_channel channel;
-
- /* We assume we are always the local */
- if (initchan == NULL) {
- return NULL;
- }
-
- for (channel = initchan; channel->local_channel != id;
- channel=channel->next) {
- if (channel->next == initchan) {
- return NULL;
- }
- }
-
- return channel;
-}
-
-static int grow_window(ssh_session session, ssh_channel channel, int minimumsize) {
- uint32_t new_window = minimumsize > WINDOWBASE ? minimumsize : WINDOWBASE;
-
- enter_function();
-
- if (buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_WINDOW_ADJUST) < 0 ||
- buffer_add_u32(session->out_buffer, htonl(channel->remote_channel)) < 0 ||
- buffer_add_u32(session->out_buffer, htonl(new_window)) < 0) {
- goto error;
- }
-
- if (packet_send(session) == SSH_ERROR) {
- /* FIXME should we fail here or not? */
- leave_function();
- return 1;
- }
-
- ssh_log(session, SSH_LOG_PROTOCOL,
- "growing window (channel %d:%d) to %d bytes",
- channel->local_channel,
- channel->remote_channel,
- channel->local_window + new_window);
-
- channel->local_window += new_window;
-
- leave_function();
- return 0;
-error:
- buffer_reinit(session->out_buffer);
-
- leave_function();
- return -1;
-}
-
-/**
- * @internal
- *
- * @brief Parse a channel-related packet to resolve it to a ssh_channel.
- *
- * This works on SSH1 sessions too.
- *
- * @param[in] session The current SSH session.
- *
- * @param[in] packet The buffer to parse packet from. The read pointer will
- * be moved after the call.
- *
- * @returns The related ssh_channel, or NULL if the channel is
- * unknown or the packet is invalid.
- */
-static ssh_channel channel_from_msg(ssh_session session, ssh_buffer packet) {
- ssh_channel channel;
- uint32_t chan;
-#ifdef WITH_SSH1
- /* With SSH1, the channel is always the first one */
- if(session->version==1)
- return session->channels;
-#endif
- if (buffer_get_u32(packet, &chan) != sizeof(uint32_t)) {
- ssh_set_error(session, SSH_FATAL,
- "Getting channel from message: short read");
- return NULL;
- }
-
- channel = ssh_channel_from_local(session, ntohl(chan));
- if (channel == NULL) {
- ssh_set_error(session, SSH_FATAL,
- "Server specified invalid channel %lu",
- (long unsigned int) ntohl(chan));
- }
-
- return channel;
-}
-
-SSH_PACKET_CALLBACK(channel_rcv_change_window) {
- ssh_channel channel;
- uint32_t bytes;
- int rc;
- (void)user;
- (void)type;
- enter_function();
-
- channel = channel_from_msg(session,packet);
- if (channel == NULL) {
- ssh_log(session, SSH_LOG_FUNCTIONS, "%s", ssh_get_error(session));
- }
-
- rc = buffer_get_u32(packet, &bytes);
- if (channel == NULL || rc != sizeof(uint32_t)) {
- ssh_log(session, SSH_LOG_PACKET,
- "Error getting a window adjust message: invalid packet");
- leave_function();
- return SSH_PACKET_USED;
- }
-
- bytes = ntohl(bytes);
- ssh_log(session, SSH_LOG_PROTOCOL,
- "Adding %d bytes to channel (%d:%d) (from %d bytes)",
- bytes,
- channel->local_channel,
- channel->remote_channel,
- channel->remote_window);
-
- channel->remote_window += bytes;
-
- leave_function();
- return SSH_PACKET_USED;
-}
-
-/* is_stderr is set to 1 if the data are extended, ie stderr */
-SSH_PACKET_CALLBACK(channel_rcv_data){
- ssh_channel channel;
- ssh_string str;
- size_t len;
- int is_stderr;
- (void)user;
- enter_function();
- if(type==SSH2_MSG_CHANNEL_DATA)
- is_stderr=0;
- else
- is_stderr=1;
-
- channel = channel_from_msg(session,packet);
- if (channel == NULL) {
- ssh_log(session, SSH_LOG_FUNCTIONS,
- "%s", ssh_get_error(session));
- leave_function();
- return SSH_PACKET_USED;
- }
-
- if (is_stderr) {
- uint32_t ignore;
- /* uint32 data type code. we can ignore it */
- buffer_get_u32(packet, &ignore);
- }
-
- str = buffer_get_ssh_string(packet);
- if (str == NULL) {
- ssh_log(session, SSH_LOG_PACKET, "Invalid data packet!");
- leave_function();
- return SSH_PACKET_USED;
- }
- len = ssh_string_len(str);
-
- ssh_log(session, SSH_LOG_PROTOCOL,
- "Channel receiving %zu bytes data in %d (local win=%d remote win=%d)",
- len,
- is_stderr,
- channel->local_window,
- channel->remote_window);
-
- /* What shall we do in this case? Let's accept it anyway */
- if (len > channel->local_window) {
- ssh_log(session, SSH_LOG_RARE,
- "Data packet too big for our window(%zu vs %d)",
- len,
- channel->local_window);
- }
-
- if (channel_default_bufferize(channel, ssh_string_data(str), len,
- is_stderr) < 0) {
- ssh_string_free(str);
- leave_function();
- return SSH_PACKET_USED;
- }
-
- if (len <= channel->local_window) {
- channel->local_window -= len;
- } else {
- channel->local_window = 0; /* buggy remote */
- }
-
- ssh_log(session, SSH_LOG_PROTOCOL,
- "Channel windows are now (local win=%d remote win=%d)",
- channel->local_window,
- channel->remote_window);
-
- ssh_string_free(str);
- leave_function();
- return SSH_PACKET_USED;
-}
-
-SSH_PACKET_CALLBACK(channel_rcv_eof) {
- ssh_channel channel;
- (void)user;
- (void)type;
- enter_function();
-
- channel = channel_from_msg(session,packet);
- if (channel == NULL) {
- ssh_log(session, SSH_LOG_FUNCTIONS, "%s", ssh_get_error(session));
- leave_function();
- return SSH_PACKET_USED;
- }
-
- ssh_log(session, SSH_LOG_PACKET,
- "Received eof on channel (%d:%d)",
- channel->local_channel,
- channel->remote_channel);
- /* channel->remote_window = 0; */
- channel->remote_eof = 1;
-
- leave_function();
- return SSH_PACKET_USED;
-}
-
-SSH_PACKET_CALLBACK(channel_rcv_close) {
- ssh_channel channel;
- (void)user;
- (void)type;
- enter_function();
-
- channel = channel_from_msg(session,packet);
- if (channel == NULL) {
- ssh_log(session, SSH_LOG_FUNCTIONS, "%s", ssh_get_error(session));
- leave_function();
- return SSH_PACKET_USED;
- }
-
- ssh_log(session, SSH_LOG_PACKET,
- "Received close on channel (%d:%d)",
- channel->local_channel,
- channel->remote_channel);
-
- if ((channel->stdout_buffer &&
- buffer_get_rest_len(channel->stdout_buffer) > 0) ||
- (channel->stderr_buffer &&
- buffer_get_rest_len(channel->stderr_buffer) > 0)) {
- channel->delayed_close = 1;
- } else {
- channel->state = SSH_CHANNEL_STATE_CLOSED;
- }
-
- if (channel->remote_eof == 0) {
- ssh_log(session, SSH_LOG_PACKET,
- "Remote host not polite enough to send an eof before close");
- }
- channel->remote_eof = 1;
- /*
- * The remote eof doesn't break things if there was still data into read
- * buffer because the eof is ignored until the buffer is empty.
- */
-
- leave_function();
- return SSH_PACKET_USED;
-}
-
-SSH_PACKET_CALLBACK(channel_rcv_request) {
- ssh_channel channel;
- ssh_string request_s;
- char *request;
- uint32_t status;
- (void)user;
- (void)type;
-
- enter_function();
-
- channel = channel_from_msg(session,packet);
- if (channel == NULL) {
- ssh_log(session, SSH_LOG_FUNCTIONS,"%s", ssh_get_error(session));
- leave_function();
- return SSH_PACKET_USED;
- }
-
- request_s = buffer_get_ssh_string(packet);
- if (request_s == NULL) {
- ssh_log(session, SSH_LOG_PACKET, "Invalid MSG_CHANNEL_REQUEST");
- leave_function();
- return SSH_PACKET_USED;
- }
-
- request = ssh_string_to_char(request_s);
- ssh_string_free(request_s);
- if (request == NULL) {
- leave_function();
- return SSH_PACKET_USED;
- }
-
- buffer_get_u8(packet, (uint8_t *) &status);
-
- 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);
-
- leave_function();
- return SSH_PACKET_USED;
- }
-
- if (strcmp(request, "exit-signal") == 0) {
- const char *core = "(core dumped)";
- ssh_string signal_s;
- char *sig;
- uint8_t i;
-
- SAFE_FREE(request);
-
- signal_s = buffer_get_ssh_string(packet);
- if (signal_s == 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);
- if (sig == NULL) {
- leave_function();
- return SSH_PACKET_USED;
- }
-
- buffer_get_u8(packet, &i);
- if (i == 0) {
- core = "";
- }
-
- ssh_log(session, SSH_LOG_PACKET,
- "Remote connection closed by signal SIG %s %s", sig, core);
- SAFE_FREE(sig);
-
- leave_function();
- return SSH_PACKET_USED;
- }
- if(strcmp(request,"keepalive@openssh.com")==0){
- SAFE_FREE(request);
- ssh_log(session, SSH_LOG_PROTOCOL,"Responding to Openssh's keepalive");
- buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_FAILURE);
- buffer_add_u32(session->out_buffer, htonl(channel->remote_channel));
- packet_send(session);
- leave_function();
- return SSH_PACKET_USED;
- }
-
- /* If we are here, that means we have a request that is not in the understood
- * client requests. That means we need to create a ssh message to be passed
- * to the user code handling ssh messages
- */
- ssh_message_handle_channel_request(session,channel,packet,request,status);
-
- SAFE_FREE(request);
-
- leave_function();
- return SSH_PACKET_USED;
-}
-
-/*
- * When data has been received from the ssh server, it can be applied to the
- * known user function, with help of the callback, or inserted here
- *
- * FIXME is the window changed?
- */
-int channel_default_bufferize(ssh_channel channel, void *data, int len,
- int is_stderr) {
- ssh_session session = channel->session;
-
- ssh_log(session, SSH_LOG_RARE,
- "placing %d bytes into channel buffer (stderr=%d)", len, is_stderr);
- if (is_stderr == 0) {
- /* stdout */
- if (channel->stdout_buffer == NULL) {
- channel->stdout_buffer = ssh_buffer_new();
- if (channel->stdout_buffer == NULL) {
- ssh_set_error_oom(session);
- return -1;
- }
- }
-
- if (buffer_add_data(channel->stdout_buffer, data, len) < 0) {
- ssh_buffer_free(channel->stdout_buffer);
- channel->stdout_buffer = NULL;
- return -1;
- }
- } else {
- /* stderr */
- if (channel->stderr_buffer == NULL) {
- channel->stderr_buffer = ssh_buffer_new();
- if (channel->stderr_buffer == NULL) {
- ssh_set_error_oom(session);
- return -1;
- }
- }
-
- if (buffer_add_data(channel->stderr_buffer, data, len) < 0) {
- ssh_buffer_free(channel->stderr_buffer);
- channel->stderr_buffer = NULL;
- return -1;
- }
- }
-
- return 0;
-}
-
-/**
- * @brief Open a session channel (suited for a shell, not TCP forwarding).
- *
- * @param[in] channel An allocated channel.
- *
- * @return SSH_OK on success, SSH_ERROR if an error occured.
- *
- * @see channel_open_forward()
- * @see channel_request_env()
- * @see channel_request_shell()
- * @see channel_request_exec()
- */
-int ssh_channel_open_session(ssh_channel channel) {
-#ifdef WITH_SSH1
- if (channel->session->version == 1) {
- return channel_open_session1(channel);
- }
-#endif
-
- return channel_open(channel,"session",64000,32000,NULL);
-}
-
-/**
- * @brief Open a TCP/IP forwarding channel.
- *
- * @param[in] channel An allocated channel.
- *
- * @param[in] remotehost The remote host to connected (host name or IP).
- *
- * @param[in] remoteport The remote port.
- *
- * @param[in] sourcehost The source host (your local computer). It's optional
- * and for logging purpose.
- *
- * @param[in] localport The source port (your local computer). It's optional
- * and for logging purpose.
- *
- * @return SSH_OK on success, SSH_ERROR if an error occured.
- *
- * @warning This function does not bind the local port and does not automatically
- * forward the content of a socket to the channel. You still have to
- * use channel_read and channel_write for this.
- */
-int ssh_channel_open_forward(ssh_channel channel, const char *remotehost,
- int remoteport, const char *sourcehost, int localport) {
- ssh_session session = channel->session;
- ssh_buffer payload = NULL;
- ssh_string str = NULL;
- int rc = SSH_ERROR;
-
- enter_function();
-
- payload = ssh_buffer_new();
- if (payload == NULL) {
- goto error;
- }
- str = ssh_string_from_char(remotehost);
- if (str == NULL) {
- goto error;
- }
-
- if (buffer_add_ssh_string(payload, str) < 0 ||
- buffer_add_u32(payload,htonl(remoteport)) < 0) {
- goto error;
- }
-
- ssh_string_free(str);
- str = ssh_string_from_char(sourcehost);
- if (str == NULL) {
- goto error;
- }
-
- if (buffer_add_ssh_string(payload, str) < 0 ||
- buffer_add_u32(payload,htonl(localport)) < 0) {
- goto error;
- }
-
- rc = channel_open(channel, "direct-tcpip", 64000, 32000, payload);
-
-error:
- ssh_buffer_free(payload);
- ssh_string_free(str);
-
- leave_function();
- return rc;
-}
-
-/**
- * @brief Close and free a channel.
- *
- * @param[in] channel The channel to free.
- *
- * @warning Any data unread on this channel will be lost.
- */
-void ssh_channel_free(ssh_channel channel) {
- ssh_session session = channel->session;
- enter_function();
-
- if (channel == NULL) {
- leave_function();
- return;
- }
-
- if (session->alive && channel->state == SSH_CHANNEL_STATE_OPEN) {
- ssh_channel_close(channel);
- }
-
- /* handle the "my channel is first on session list" case */
- if (session->channels == channel) {
- session->channels = channel->next;
- }
-
- /* handle the "my channel is the only on session list" case */
- if (channel->next == channel) {
- session->channels = NULL;
- } else {
- channel->prev->next = channel->next;
- channel->next->prev = channel->prev;
- }
-
- ssh_buffer_free(channel->stdout_buffer);
- ssh_buffer_free(channel->stderr_buffer);
-
- /* debug trick to catch use after frees */
- memset(channel, 'X', sizeof(struct ssh_channel_struct));
- SAFE_FREE(channel);
-
- leave_function();
-}
-
-/**
- * @brief Send an end of file on the channel.
- *
- * This doesn't close the channel. You may still read from it but not write.
- *
- * @param[in] channel The channel to send the eof to.
- *
- * @return SSH_OK on success, SSH_ERROR if an error occured.
- *
- * @see channel_close()
- * @see channel_free()
- */
-int ssh_channel_send_eof(ssh_channel channel){
- ssh_session session = channel->session;
- int rc = SSH_ERROR;
-
- enter_function();
-
- if (buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_EOF) < 0) {
- goto error;
- }
- if (buffer_add_u32(session->out_buffer,htonl(channel->remote_channel)) < 0) {
- goto error;
- }
- rc = packet_send(session);
- ssh_log(session, SSH_LOG_PACKET,
- "Sent a EOF on client channel (%d:%d)",
- channel->local_channel,
- channel->remote_channel);
-
- channel->local_eof = 1;
-
- leave_function();
- return rc;
-error:
- buffer_reinit(session->out_buffer);
-
- leave_function();
- return rc;
-}
-
-/**
- * @brief Close a channel.
- *
- * This sends an end of file and then closes the channel. You won't be able
- * to recover any data the server was going to send or was in buffers.
- *
- * @param[in] channel The channel to close.
- *
- * @return SSH_OK on success, SSH_ERROR if an error occured.
- *
- * @see channel_free()
- * @see channel_eof()
- */
-int ssh_channel_close(ssh_channel channel){
- ssh_session session = channel->session;
- int rc = 0;
-
- enter_function();
-
- if (channel->local_eof == 0) {
- rc = ssh_channel_send_eof(channel);
- }
-
- if (rc != SSH_OK) {
- leave_function();
- return rc;
- }
-
- if (buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_CLOSE) < 0 ||
- buffer_add_u32(session->out_buffer, htonl(channel->remote_channel)) < 0) {
- goto error;
- }
-
- rc = packet_send(session);
- ssh_log(session, SSH_LOG_PACKET,
- "Sent a close on client channel (%d:%d)",
- channel->local_channel,
- channel->remote_channel);
-
- if(rc == SSH_OK) {
- channel->state=SSH_CHANNEL_STATE_CLOSED;
- }
-
- leave_function();
- return rc;
-error:
- buffer_reinit(session->out_buffer);
-
- leave_function();
- return rc;
-}
-
-int channel_write_common(ssh_channel channel, const void *data,
- uint32_t len, int is_stderr) {
- ssh_session session = channel->session;
- int origlen = len;
- size_t effectivelen;
- /* handle the max packet len from remote side, be nice */
- /* 10 bytes for the headers */
- size_t maxpacketlen = channel->remote_maxpacket - 10;
-
- enter_function();
-
- if (channel->local_eof) {
- ssh_set_error(session, SSH_REQUEST_DENIED,
- "Can't write to channel %d:%d after EOF was sent",
- channel->local_channel,
- channel->remote_channel);
- leave_function();
- return -1;
- }
-
- if (channel->state != SSH_CHANNEL_STATE_OPEN || channel->delayed_close != 0) {
- ssh_set_error(session, SSH_REQUEST_DENIED, "Remote channel is closed");
- leave_function();
- return -1;
- }
-
-#ifdef WITH_SSH1
- if (channel->version == 1) {
- int rc = channel_write1(channel, data, len);
- leave_function();
- return rc;
- }
-#endif
-
- while (len > 0) {
- if (channel->remote_window < len) {
- ssh_log(session, SSH_LOG_PROTOCOL,
- "Remote window is %d bytes. going to write %d bytes",
- channel->remote_window,
- len);
- ssh_log(session, SSH_LOG_PROTOCOL,
- "Waiting for a growing window message...");
- /* What happens when the channel window is zero? */
- while(channel->remote_window == 0) {
- /* parse every incoming packet */
- if (ssh_handle_packets(session,-1) == SSH_ERROR) {
- leave_function();
- return SSH_ERROR;
- }
- }
- effectivelen = len > channel->remote_window ? channel->remote_window : len;
- } else {
- effectivelen = len;
- }
- effectivelen = effectivelen > maxpacketlen ? maxpacketlen : effectivelen;
- if (buffer_add_u8(session->out_buffer, is_stderr ?
- SSH2_MSG_CHANNEL_EXTENDED_DATA : SSH2_MSG_CHANNEL_DATA) < 0 ||
- buffer_add_u32(session->out_buffer,
- htonl(channel->remote_channel)) < 0 ||
- buffer_add_u32(session->out_buffer, htonl(effectivelen)) < 0 ||
- buffer_add_data(session->out_buffer, data, effectivelen) < 0) {
- goto error;
- }
-
- if (packet_send(session) == SSH_ERROR) {
- leave_function();
- return SSH_ERROR;
- }
-
- ssh_log(session, SSH_LOG_RARE,
- "channel_write wrote %ld bytes", effectivelen);
-
- channel->remote_window -= effectivelen;
- len -= effectivelen;
- data = ((uint8_t*)data + effectivelen);
- }
-
- leave_function();
- return origlen;
-error:
- buffer_reinit(session->out_buffer);
-
- leave_function();
- return SSH_ERROR;
-}
-
-/**
- * @brief Blocking write on a channel.
- *
- * @param[in] channel The channel to write to.
- *
- * @param[in] data A pointer to the data to write.
- *
- * @param[in] len The length of the buffer to write to.
- *
- * @return The number of bytes written, SSH_ERROR on error.
- *
- * @see channel_read()
- */
-int ssh_channel_write(ssh_channel channel, const void *data, uint32_t len) {
- return channel_write_common(channel, data, len, 0);
-}
-
-/**
- * @brief Check if the channel is open or not.
- *
- * @param[in] channel The channel to check.
- *
- * @return 0 if channel is closed, nonzero otherwise.
- *
- * @see channel_is_closed()
- */
-int ssh_channel_is_open(ssh_channel channel) {
- return (channel->state == SSH_CHANNEL_STATE_OPEN && channel->session->alive != 0);
-}
-
-/**
- * @brief Check if the channel is closed or not.
- *
- * @param[in] channel The channel to check.
- *
- * @return 0 if channel is opened, nonzero otherwise.
- *
- * @see channel_is_open()
- */
-int ssh_channel_is_closed(ssh_channel channel) {
- return (channel->state != SSH_CHANNEL_STATE_OPEN || channel->session->alive == 0);
-}
-
-/**
- * @brief Check if remote has sent an EOF.
- *
- * @param[in] channel The channel to check.
- *
- * @return 0 if there is no EOF, nonzero otherwise.
- */
-int ssh_channel_is_eof(ssh_channel channel) {
- if ((channel->stdout_buffer &&
- buffer_get_rest_len(channel->stdout_buffer) > 0) ||
- (channel->stderr_buffer &&
- buffer_get_rest_len(channel->stderr_buffer) > 0)) {
- return 0;
- }
-
- return (channel->remote_eof != 0);
-}
-
-/**
- * @brief Put the channel into blocking or nonblocking mode.
- *
- * @param[in] channel The channel to use.
- *
- * @param[in] blocking A boolean for blocking or nonblocking.
- *
- * @bug This functionality is still under development and
- * doesn't work correctly.
- */
-void ssh_channel_set_blocking(ssh_channel channel, int blocking) {
- channel->blocking = (blocking == 0 ? 0 : 1);
-}
-
-/**
- * @internal
- *
- * @brief handle a SSH_CHANNEL_SUCCESS packet and set the channel state.
- *
- * This works on SSH1 sessions too.
- */
-SSH_PACKET_CALLBACK(ssh_packet_channel_success){
- ssh_channel channel;
- (void)type;
- (void)user;
- enter_function();
- channel=channel_from_msg(session,packet);
- if (channel == NULL) {
- ssh_log(session, SSH_LOG_FUNCTIONS, "%s", ssh_get_error(session));
- leave_function();
- return SSH_PACKET_USED;
- }
-
- ssh_log(session, SSH_LOG_PACKET,
- "Received SSH_CHANNEL_SUCCESS on channel (%d:%d)",
- channel->local_channel,
- channel->remote_channel);
- if(channel->request_state != SSH_CHANNEL_REQ_STATE_PENDING){
- ssh_log(session, SSH_LOG_RARE, "SSH_CHANNEL_SUCCESS received in incorrect state %d",
- channel->request_state);
- } else {
- channel->request_state=SSH_CHANNEL_REQ_STATE_ACCEPTED;
- }
-
- leave_function();
- return SSH_PACKET_USED;
-}
-
-/**
- * @internal
- *
- * @brief Handle a SSH_CHANNEL_FAILURE packet and set the channel state.
- *
- * This works on SSH1 sessions too.
- */
-SSH_PACKET_CALLBACK(ssh_packet_channel_failure){
- ssh_channel channel;
- (void)type;
- (void)user;
- enter_function();
- channel=channel_from_msg(session,packet);
- if (channel == NULL) {
- ssh_log(session, SSH_LOG_FUNCTIONS, "%s", ssh_get_error(session));
- leave_function();
- return SSH_PACKET_USED;
- }
-
- ssh_log(session, SSH_LOG_PACKET,
- "Received SSH_CHANNEL_FAILURE on channel (%d:%d)",
- channel->local_channel,
- channel->remote_channel);
- if(channel->request_state != SSH_CHANNEL_REQ_STATE_PENDING){
- ssh_log(session, SSH_LOG_RARE, "SSH_CHANNEL_FAILURE received in incorrect state %d",
- channel->request_state);
- } else {
- channel->request_state=SSH_CHANNEL_REQ_STATE_DENIED;
- }
- leave_function();
- return SSH_PACKET_USED;
-}
-
-static int channel_request(ssh_channel channel, const char *request,
- ssh_buffer buffer, int reply) {
- ssh_session session = channel->session;
- ssh_string req = NULL;
- int rc = SSH_ERROR;
-
- enter_function();
- if(channel->request_state != SSH_CHANNEL_REQ_STATE_NONE){
- ssh_set_error(session,SSH_REQUEST_DENIED,"channel_request_* used in incorrect state");
- leave_function();
- return SSH_ERROR;
- }
-
- req = ssh_string_from_char(request);
- if (req == NULL) {
- goto error;
- }
-
- if (buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_REQUEST) < 0 ||
- buffer_add_u32(session->out_buffer, htonl(channel->remote_channel)) < 0 ||
- buffer_add_ssh_string(session->out_buffer, req) < 0 ||
- buffer_add_u8(session->out_buffer, reply == 0 ? 0 : 1) < 0) {
- goto error;
- }
- ssh_string_free(req);
-
- if (buffer != NULL) {
- if (buffer_add_data(session->out_buffer, ssh_buffer_get_begin(buffer),
- ssh_buffer_get_len(buffer)) < 0) {
- goto error;
- }
- }
- channel->request_state = SSH_CHANNEL_REQ_STATE_PENDING;
- if (packet_send(session) == SSH_ERROR) {
- leave_function();
- return rc;
- }
-
- ssh_log(session, SSH_LOG_PACKET,
- "Sent a SSH_MSG_CHANNEL_REQUEST %s", request);
- if (reply == 0) {
- channel->request_state = SSH_CHANNEL_REQ_STATE_NONE;
- leave_function();
- return SSH_OK;
- }
- while(channel->request_state == SSH_CHANNEL_REQ_STATE_PENDING){
- ssh_handle_packets(session,-1);
- }
- /* we received something */
- switch (channel->request_state){
- case SSH_CHANNEL_REQ_STATE_ERROR:
- rc=SSH_ERROR;
- break;
- case SSH_CHANNEL_REQ_STATE_DENIED:
- ssh_set_error(session, SSH_REQUEST_DENIED,
- "Channel request %s failed", request);
- rc=SSH_ERROR;
- break;
- case SSH_CHANNEL_REQ_STATE_ACCEPTED:
- ssh_log(session, SSH_LOG_PROTOCOL,
- "Channel request %s success",request);
- rc=SSH_OK;
- break;
- case SSH_CHANNEL_REQ_STATE_NONE:
- case SSH_CHANNEL_REQ_STATE_PENDING:
- /* Never reached */
- ssh_set_error(session, SSH_FATAL, "Invalid state in channel_request()");
- rc=SSH_ERROR;
- break;
- }
- channel->request_state=SSH_CHANNEL_REQ_STATE_NONE;
- leave_function();
- return rc;
-error:
- buffer_reinit(session->out_buffer);
- ssh_string_free(req);
-
- leave_function();
- return rc;
-}
-
-/**
- * @brief Request a pty with a specific type and size.
- *
- * @param[in] channel The channel to sent the request.
- *
- * @param[in] terminal The terminal type ("vt100, xterm,...").
- *
- * @param[in] col The number of columns.
- *
- * @param[in] row The number of rows.
- *
- * @return SSH_OK on success, SSH_ERROR if an error occured.
- */
-int ssh_channel_request_pty_size(ssh_channel channel, const char *terminal,
- int col, int row) {
- ssh_session session = channel->session;
- ssh_string term = NULL;
- ssh_buffer buffer = NULL;
- int rc = SSH_ERROR;
-
- enter_function();
-#ifdef WITH_SSH1
- if (channel->version==1) {
- channel_request_pty_size1(channel,terminal, col, row);
- leave_function();
- return rc;
- }
-#endif
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- goto error;
- }
-
- term = ssh_string_from_char(terminal);
- if (term == NULL) {
- goto error;
- }
-
- if (buffer_add_ssh_string(buffer, term) < 0 ||
- buffer_add_u32(buffer, htonl(col)) < 0 ||
- buffer_add_u32(buffer, htonl(row)) < 0 ||
- buffer_add_u32(buffer, 0) < 0 ||
- buffer_add_u32(buffer, 0) < 0 ||
- buffer_add_u32(buffer, htonl(1)) < 0 || /* Add a 0byte string */
- buffer_add_u8(buffer, 0) < 0) {
- goto error;
- }
-
- rc = channel_request(channel, "pty-req", buffer, 1);
-error:
- ssh_buffer_free(buffer);
- ssh_string_free(term);
-
- leave_function();
- return rc;
-}
-
-/**
- * @brief Request a PTY.
- *
- * @param[in] channel The channel to send the request.
- *
- * @return SSH_OK on success, SSH_ERROR if an error occured.
- *
- * @see channel_request_pty_size()
- */
-int ssh_channel_request_pty(ssh_channel channel) {
- return ssh_channel_request_pty_size(channel, "xterm", 80, 24);
-}
-
-/**
- * @brief Change the size of the terminal associated to a channel.
- *
- * @param[in] channel The channel to change the size.
- *
- * @param[in] cols The new number of columns.
- *
- * @param[in] rows The new number of rows.
- *
- * @return SSH_OK on success, SSH_ERROR if an error occured.
- *
- * @warning Do not call it from a signal handler if you are not sure any other
- * libssh function using the same channel/session is running at same
- * time (not 100% threadsafe).
- */
-int ssh_channel_change_pty_size(ssh_channel channel, int cols, int rows) {
- ssh_session session = channel->session;
- ssh_buffer buffer = NULL;
- int rc = SSH_ERROR;
-
- enter_function();
-
-#ifdef WITH_SSH1
- if (channel->version == 1) {
- rc = channel_change_pty_size1(channel,cols,rows);
- leave_function();
- return rc;
- }
-#endif
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- goto error;
- }
-
- if (buffer_add_u32(buffer, htonl(cols)) < 0 ||
- buffer_add_u32(buffer, htonl(rows)) < 0 ||
- buffer_add_u32(buffer, 0) < 0 ||
- buffer_add_u32(buffer, 0) < 0) {
- goto error;
- }
-
- rc = channel_request(channel, "window-change", buffer, 0);
-error:
- ssh_buffer_free(buffer);
-
- leave_function();
- return rc;
-}
-
-/**
- * @brief Request a shell.
- *
- * @param[in] channel The channel to send the request.
- *
- * @return SSH_OK on success, SSH_ERROR if an error occured.
- */
-int ssh_channel_request_shell(ssh_channel channel) {
-#ifdef WITH_SSH1
- if (channel->version == 1) {
- return channel_request_shell1(channel);
- }
-#endif
- return channel_request(channel, "shell", NULL, 1);
-}
-
-/**
- * @brief Request a subsystem (for example "sftp").
- *
- * @param[in] channel The channel to send the request.
- *
- * @param[in] subsys The subsystem to request (for example "sftp").
- *
- * @return SSH_OK on success, SSH_ERROR if an error occured.
- *
- * @warning You normally don't have to call it for sftp, see sftp_new().
- */
-int ssh_channel_request_subsystem(ssh_channel channel, const char *subsys) {
- ssh_buffer buffer = NULL;
- ssh_string subsystem = NULL;
- int rc = SSH_ERROR;
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- goto error;
- }
-
- subsystem = ssh_string_from_char(subsys);
- if (subsystem == NULL) {
- goto error;
- }
-
- if (buffer_add_ssh_string(buffer, subsystem) < 0) {
- goto error;
- }
-
- rc = channel_request(channel, "subsystem", buffer, 1);
-error:
- ssh_buffer_free(buffer);
- ssh_string_free(subsystem);
-
- return rc;
-}
-
-int ssh_channel_request_sftp( ssh_channel channel){
- return ssh_channel_request_subsystem(channel, "sftp");
-}
-
-static ssh_string generate_cookie(void) {
- static const char *hex = "0123456789abcdef";
- char s[36];
- int i;
-
- srand ((unsigned int)time(NULL));
- for (i = 0; i < 32; i++) {
- s[i] = hex[rand() % 16];
- }
- s[32] = '\0';
- return ssh_string_from_char(s);
-}
-
-/**
- * @brief Sends the "x11-req" channel request over an existing session channel.
- *
- * This will enable redirecting the display of the remote X11 applications to
- * local X server over an secure tunnel.
- *
- * @param[in] channel An existing session channel where the remote X11
- * applications are going to be executed.
- *
- * @param[in] single_connection A boolean to mark only one X11 app will be
- * redirected.
- *
- * @param[in] protocol A x11 authentication protocol. Pass NULL to use the
- * default value MIT-MAGIC-COOKIE-1.
- *
- * @param[in] cookie A x11 authentication cookie. Pass NULL to generate
- * a random cookie.
- *
- * @param[in] screen_number The screen number.
- *
- * @return SSH_OK on success, SSH_ERROR if an error occured.
- */
-int ssh_channel_request_x11(ssh_channel channel, int single_connection, const char *protocol,
- const char *cookie, int screen_number) {
- ssh_buffer buffer = NULL;
- ssh_string p = NULL;
- ssh_string c = NULL;
- int rc = SSH_ERROR;
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- goto error;
- }
-
- p = ssh_string_from_char(protocol ? protocol : "MIT-MAGIC-COOKIE-1");
- if (p == NULL) {
- goto error;
- }
-
- if (cookie) {
- c = ssh_string_from_char(cookie);
- } else {
- c = generate_cookie();
- }
- if (c == NULL) {
- goto error;
- }
-
- if (buffer_add_u8(buffer, single_connection == 0 ? 0 : 1) < 0 ||
- buffer_add_ssh_string(buffer, p) < 0 ||
- buffer_add_ssh_string(buffer, c) < 0 ||
- buffer_add_u32(buffer, htonl(screen_number)) < 0) {
- goto error;
- }
-
- rc = channel_request(channel, "x11-req", buffer, 1);
-
-error:
- ssh_buffer_free(buffer);
- ssh_string_free(p);
- ssh_string_free(c);
- return rc;
-}
-
-static ssh_channel ssh_channel_accept(ssh_session session, int channeltype,
- int timeout_ms) {
-#ifndef _WIN32
- static const struct timespec ts = {
- .tv_sec = 0,
- .tv_nsec = 50000000 /* 50ms */
- };
-#endif
- ssh_message msg = NULL;
- ssh_channel channel = NULL;
- struct ssh_iterator *iterator;
- int t;
-
- for (t = timeout_ms; t >= 0; t -= 50)
- {
- ssh_handle_packets(session,50);
-
- if (session->ssh_message_list) {
- iterator = ssh_list_get_iterator(session->ssh_message_list);
- while (iterator) {
- msg = (ssh_message)iterator->data;
- if (ssh_message_type(msg) == SSH_REQUEST_CHANNEL_OPEN &&
- ssh_message_subtype(msg) == channeltype) {
- ssh_list_remove(session->ssh_message_list, iterator);
- channel = ssh_message_channel_request_open_reply_accept(msg);
- ssh_message_free(msg);
- return channel;
- }
- iterator = iterator->next;
- }
- }
-#ifdef _WIN32
- Sleep(50); /* 50ms */
-#else
- nanosleep(&ts, NULL);
-#endif
- }
-
- return NULL;
-}
-
-/**
- * @brief Accept an X11 forwarding channel.
- *
- * @param[in] channel An x11-enabled session channel.
- *
- * @param[in] timeout_ms Timeout in milliseconds.
- *
- * @return A newly created channel, or NULL if no X11 request from
- * the server.
- */
-ssh_channel ssh_channel_accept_x11(ssh_channel channel, int timeout_ms) {
- return ssh_channel_accept(channel->session, SSH_CHANNEL_X11, timeout_ms);
-}
-
-/**
- * @internal
- *
- * @brief Handle a SSH_REQUEST_SUCCESS packet normally sent after a global
- * request.
- */
-SSH_PACKET_CALLBACK(ssh_request_success){
- (void)type;
- (void)user;
- (void)packet;
- enter_function();
-
- ssh_log(session, SSH_LOG_PACKET,
- "Received SSH_REQUEST_SUCCESS");
- if(session->global_req_state != SSH_CHANNEL_REQ_STATE_PENDING){
- ssh_log(session, SSH_LOG_RARE, "SSH_REQUEST_SUCCESS received in incorrect state %d",
- session->global_req_state);
- } else {
- session->global_req_state=SSH_CHANNEL_REQ_STATE_ACCEPTED;
- }
-
- leave_function();
- return SSH_PACKET_USED;
-}
-
-/**
- * @internal
- *
- * @brief Handle a SSH_REQUEST_DENIED packet normally sent after a global
- * request.
- */
-SSH_PACKET_CALLBACK(ssh_request_denied){
- (void)type;
- (void)user;
- (void)packet;
- enter_function();
-
- ssh_log(session, SSH_LOG_PACKET,
- "Received SSH_REQUEST_FAILURE");
- if(session->global_req_state != SSH_CHANNEL_REQ_STATE_PENDING){
- ssh_log(session, SSH_LOG_RARE, "SSH_REQUEST_DENIED received in incorrect state %d",
- session->global_req_state);
- } else {
- session->global_req_state=SSH_CHANNEL_REQ_STATE_DENIED;
- }
-
- leave_function();
- return SSH_PACKET_USED;
-
-}
-
-/**
- * @internal
- *
- * @brief Send a global request (needed for forward listening) and wait for the
- * result.
- *
- * @param[in] session The SSH session handle.
- *
- * @param[in] request The type of request (defined in RFC).
- *
- * @param[in] buffer Additional data to put in packet.
- *
- * @param[in] reply Set if you expect a reply from server.
- *
- * @return SSH_OK on success, SSH_ERROR if an error occured.
- */
-static int global_request(ssh_session session, const char *request,
- ssh_buffer buffer, int reply) {
- ssh_string req = NULL;
- int rc = SSH_ERROR;
-
- enter_function();
- if(session->global_req_state != SSH_CHANNEL_REQ_STATE_NONE){
- ssh_set_error(session,SSH_FATAL,"Invalid state in start of global_request()");
- leave_function();
- return rc;
- }
- req = ssh_string_from_char(request);
- if (req == NULL) {
- goto error;
- }
-
- if (buffer_add_u8(session->out_buffer, SSH2_MSG_GLOBAL_REQUEST) < 0 ||
- buffer_add_ssh_string(session->out_buffer, req) < 0 ||
- buffer_add_u8(session->out_buffer, reply == 0 ? 0 : 1) < 0) {
- goto error;
- }
- ssh_string_free(req);
- req=NULL;
-
- if (buffer != NULL) {
- if (buffer_add_data(session->out_buffer, ssh_buffer_get_begin(buffer),
- ssh_buffer_get_len(buffer)) < 0) {
- goto error;
- }
- }
- session->global_req_state = SSH_CHANNEL_REQ_STATE_PENDING;
- if (packet_send(session) == SSH_ERROR) {
- leave_function();
- return rc;
- }
-
- ssh_log(session, SSH_LOG_PACKET,
- "Sent a SSH_MSG_GLOBAL_REQUEST %s", request);
- if (reply == 0) {
- session->global_req_state=SSH_CHANNEL_REQ_STATE_NONE;
- leave_function();
- return SSH_OK;
- }
- while(session->global_req_state == SSH_CHANNEL_REQ_STATE_PENDING){
- rc=ssh_handle_packets(session,-1);
- if(rc==SSH_ERROR){
- session->global_req_state = SSH_CHANNEL_REQ_STATE_ERROR;
- break;
- }
- }
- switch(session->global_req_state){
- case SSH_CHANNEL_REQ_STATE_ACCEPTED:
- ssh_log(session, SSH_LOG_PROTOCOL, "Global request %s success",request);
- rc=SSH_OK;
- break;
- case SSH_CHANNEL_REQ_STATE_DENIED:
- ssh_log(session, SSH_LOG_PACKET,
- "Global request %s failed", request);
- ssh_set_error(session, SSH_REQUEST_DENIED,
- "Global request %s failed", request);
- rc=SSH_ERROR;
- break;
- case SSH_CHANNEL_REQ_STATE_ERROR:
- case SSH_CHANNEL_REQ_STATE_NONE:
- case SSH_CHANNEL_REQ_STATE_PENDING:
- rc=SSH_ERROR;
- break;
-
- }
-
- leave_function();
- return rc;
-error:
- ssh_string_free(req);
- leave_function();
- return rc;
-}
-
-/**
- * @brief Sends the "tcpip-forward" global request to ask the server to begin
- * listening for inbound connections.
- *
- * @param[in] session The ssh session to send the request.
- *
- * @param[in] address The address to bind to on the server. Pass NULL to bind
- * to all available addresses on all protocol families
- * supported by the server.
- *
- * @param[in] port The port to bind to on the server. Pass 0 to ask the
- * server to allocate the next available unprivileged port
- * number
- *
- * @param[in] bound_port The pointer to get actual bound port. Pass NULL to
- * ignore.
- *
- * @return SSH_OK on success, SSH_ERROR if an error occured.
- */
-int ssh_forward_listen(ssh_session session, const char *address, int port, int *bound_port) {
- ssh_buffer buffer = NULL;
- ssh_string addr = NULL;
- int rc = SSH_ERROR;
- uint32_t tmp;
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- goto error;
- }
-
- addr = ssh_string_from_char(address ? address : "");
- if (addr == NULL) {
- goto error;
- }
-
- if (buffer_add_ssh_string(buffer, addr) < 0 ||
- buffer_add_u32(buffer, htonl(port)) < 0) {
- goto error;
- }
-
- rc = global_request(session, "tcpip-forward", buffer, 1);
-
- if (rc == SSH_OK && port == 0 && bound_port) {
- buffer_get_u32(session->in_buffer, &tmp);
- *bound_port = ntohl(tmp);
- }
-
-error:
- ssh_buffer_free(buffer);
- ssh_string_free(addr);
- return rc;
-}
-
-/**
- * @brief Accept an incoming TCP/IP forwarding channel.
- *
- * @param[in] session The ssh session to use.
- *
- * @param[in] timeout_ms A timeout in milliseconds.
- *
- * @return Newly created channel, or NULL if no incoming channel request from
- * the server
- */
-ssh_channel ssh_forward_accept(ssh_session session, int timeout_ms) {
- return ssh_channel_accept(session, SSH_CHANNEL_FORWARDED_TCPIP, timeout_ms);
-}
-
-/**
- * @brief Sends the "cancel-tcpip-forward" global request to ask the server to
- * cancel the tcpip-forward request.
- *
- * @param[in] session The ssh session to send the request.
- *
- * @param[in] address The bound address on the server.
- *
- * @param[in] port The bound port on the server.
- *
- * @return SSH_OK on success, SSH_ERROR if an error occured.
- */
-int ssh_forward_cancel(ssh_session session, const char *address, int port) {
- ssh_buffer buffer = NULL;
- ssh_string addr = NULL;
- int rc = SSH_ERROR;
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- goto error;
- }
-
- addr = ssh_string_from_char(address ? address : "");
- if (addr == NULL) {
- goto error;
- }
-
- if (buffer_add_ssh_string(buffer, addr) < 0 ||
- buffer_add_u32(buffer, htonl(port)) < 0) {
- goto error;
- }
-
- rc = global_request(session, "cancel-tcpip-forward", buffer, 1);
-
-error:
- ssh_buffer_free(buffer);
- ssh_string_free(addr);
- return rc;
-}
-
-/**
- * @brief Set environment variables.
- *
- * @param[in] channel The channel to set the environment variables.
- *
- * @param[in] name The name of the variable.
- *
- * @param[in] value The value to set.
- *
- * @return SSH_OK on success, SSH_ERROR if an error occured.
- *
- * @warning Some environment variables may be refused by security reasons.
- */
-int ssh_channel_request_env(ssh_channel channel, const char *name, const char *value) {
- ssh_buffer buffer = NULL;
- ssh_string str = NULL;
- int rc = SSH_ERROR;
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- goto error;
- }
-
- str = ssh_string_from_char(name);
- if (str == NULL) {
- goto error;
- }
-
- if (buffer_add_ssh_string(buffer, str) < 0) {
- goto error;
- }
-
- ssh_string_free(str);
- str = ssh_string_from_char(value);
- if (str == NULL) {
- goto error;
- }
-
- if (buffer_add_ssh_string(buffer, str) < 0) {
- goto error;
- }
-
- rc = channel_request(channel, "env", buffer,1);
-error:
- ssh_buffer_free(buffer);
- ssh_string_free(str);
-
- return rc;
-}
-
-/**
- * @brief Run a shell command without an interactive shell.
- *
- * This is similar to 'sh -c command'.
- *
- * @param[in] channel The channel to execute the command.
- *
- * @param[in] cmd The command to execute
- * (e.g. "ls ~/ -al | grep -i reports").
- *
- * @return SSH_OK on success, SSH_ERROR if an error occured.
- *
- * @code
- * rc = channel_request_exec(channel, "ps aux");
- * if (rc > 0) {
- * return -1;
- * }
- *
- * while ((rc = channel_read(channel, buffer, sizeof(buffer), 0)) > 0) {
- * if (fwrite(buffer, 1, rc, stdout) != (unsigned int) rc) {
- * return -1;
- * }
- * }
- * @endcode
- *
- * @see channel_request_shell()
- */
-int ssh_channel_request_exec(ssh_channel channel, const char *cmd) {
- ssh_buffer buffer = NULL;
- ssh_string command = NULL;
- int rc = SSH_ERROR;
-
-#ifdef WITH_SSH1
- if (channel->version == 1) {
- return channel_request_exec1(channel, cmd);
- }
-#endif
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- goto error;
- }
-
- command = ssh_string_from_char(cmd);
- if (command == NULL) {
- goto error;
- }
-
- if (buffer_add_ssh_string(buffer, command) < 0) {
- goto error;
- }
-
- rc = channel_request(channel, "exec", buffer, 1);
-error:
- ssh_buffer_free(buffer);
- ssh_string_free(command);
- return rc;
-}
-
-
-/**
- * @brief Send a signal to remote process (as described in RFC 4254, section 6.9).
- *
- * 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").
- *
- * @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_signal(ssh_channel channel, const char *sig) {
- ssh_buffer buffer = NULL;
- ssh_string encoded_signal = 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;
- }
-
- encoded_signal = ssh_string_from_char(sig);
- if (encoded_signal == NULL) {
- goto error;
- }
-
- if (buffer_add_ssh_string(buffer, encoded_signal) < 0) {
- goto error;
- }
-
- rc = channel_request(channel, "signal", buffer, 0);
-error:
- ssh_buffer_free(buffer);
- ssh_string_free(encoded_signal);
- return rc;
-}
-
-
-/**
- * @brief Read data from a channel into a buffer.
- *
- * @param[in] channel The channel to read from.
- *
- * @param[in] buffer The buffer which will get the data.
- *
- * @param[in] count The count of bytes to be read. If it is bigger than 0,
- * the exact size will be read, else (bytes=0) it will
- * return once anything is available.
- *
- * @param is_stderr A boolean value to mark reading from the stderr stream.
- *
- * @return The number of bytes read, 0 on end of file or SSH_ERROR
- * on error.
- * @deprecated Please use ssh_channel_read instead
- * @see ssh_channel_read
- */
-int channel_read_buffer(ssh_channel channel, ssh_buffer buffer, uint32_t count,
- int is_stderr) {
- ssh_session session=channel->session;
- ssh_buffer stdbuf = channel->stdout_buffer;
- uint32_t maxread = count;
- uint32_t len;
-
- buffer_reinit(buffer);
-
- enter_function();
-
- if (count == 0) {
- maxread = MAX_PACKET_LEN;
- }
-
- if (is_stderr) {
- stdbuf = channel->stderr_buffer;
- }
-
- /*
- * We may have problem if the window is too small to accept as much data
- * as asked
- */
- ssh_log(session, SSH_LOG_PROTOCOL,
- "Read (%d) buffered: %d bytes. Window: %d",
- count,
- buffer_get_rest_len(stdbuf),
- channel->local_window);
-
- if (count > buffer_get_rest_len(stdbuf) + channel->local_window) {
- if (grow_window(session, channel,
- count - buffer_get_rest_len(stdbuf)) < 0) {
- leave_function();
- return -1;
- }
- }
- /* block reading if asked bytes=0 */
- while (buffer_get_rest_len(stdbuf) == 0 ||
- buffer_get_rest_len(stdbuf) < count) {
- if (channel->remote_eof && buffer_get_rest_len(stdbuf) == 0) {
- leave_function();
- return 0;
- }
- if (channel->remote_eof) {
- /* Return the resting bytes in buffer */
- break;
- }
- if (buffer_get_rest_len(stdbuf) >= maxread) {
- /* Stop reading when buffer is full enough */
- break;
- }
- ssh_handle_packets(session,-1);
- }
-
- if(channel->local_window < WINDOWLIMIT) {
- if (grow_window(session, channel, 0) < 0) {
- leave_function();
- return -1;
- }
- }
-
- if (count == 0) {
- /* write the ful buffer information */
- if (buffer_add_data(buffer, buffer_get_rest(stdbuf),
- buffer_get_rest_len(stdbuf)) < 0) {
- leave_function();
- return -1;
- }
- buffer_reinit(stdbuf);
- } else {
- /* Read bytes bytes if len is greater, everything otherwise */
- len = buffer_get_rest_len(stdbuf);
- len = (len > count ? count : len);
- if (buffer_add_data(buffer, buffer_get_rest(stdbuf), len) < 0) {
- leave_function();
- return -1;
- }
- buffer_pass_bytes(stdbuf,len);
- }
-
- leave_function();
- return ssh_buffer_get_len(buffer);
-}
-
-/* TODO FIXME Fix the delayed close thing */
-/* TODO FIXME Fix the blocking behaviours */
-
-/**
- * @brief Reads data from a channel.
- *
- * @param[in] channel The channel to read from.
- *
- * @param[in] dest The destination buffer which will get the data.
- *
- * @param[in] count The count of bytes to be read.
- *
- * @param[in] is_stderr A boolean value to mark reading from the stderr flow.
- *
- * @return The number of bytes read, 0 on end of file or SSH_ERROR
- * on error.
- *
- * @warning This function may return less than count bytes of data, and won't
- * block until count bytes have been read.
- * @warning The read function using a buffer has been renamed to
- * channel_read_buffer().
- */
-int ssh_channel_read(ssh_channel channel, void *dest, uint32_t count, int is_stderr) {
- ssh_session session = channel->session;
- ssh_buffer stdbuf = channel->stdout_buffer;
- uint32_t len;
-
- enter_function();
-
- if (count == 0) {
- leave_function();
- return 0;
- }
-
- if (is_stderr) {
- stdbuf=channel->stderr_buffer;
- }
-
- /*
- * We may have problem if the window is too small to accept as much data
- * as asked
- */
- ssh_log(session, SSH_LOG_PROTOCOL,
- "Read (%d) buffered : %d bytes. Window: %d",
- count,
- buffer_get_rest_len(stdbuf),
- channel->local_window);
-
- if (count > buffer_get_rest_len(stdbuf) + channel->local_window) {
- if (grow_window(session, channel,
- count - buffer_get_rest_len(stdbuf)) < 0) {
- leave_function();
- return -1;
- }
- }
-
- /* block reading until at least one byte is read
- * and ignore the trivial case count=0
- */
- while (buffer_get_rest_len(stdbuf) == 0 && count > 0) {
- if (channel->remote_eof && buffer_get_rest_len(stdbuf) == 0) {
- leave_function();
- return 0;
- }
-
- if (channel->remote_eof) {
- /* Return the resting bytes in buffer */
- break;
- }
-
- if (buffer_get_rest_len(stdbuf) >= count) {
- /* Stop reading when buffer is full enough */
- break;
- }
-
- ssh_handle_packets(session,-1);
- }
-
- if (channel->local_window < WINDOWLIMIT) {
- if (grow_window(session, channel, 0) < 0) {
- leave_function();
- return -1;
- }
- }
-
- len = buffer_get_rest_len(stdbuf);
- /* Read count bytes if len is greater, everything otherwise */
- len = (len > count ? count : len);
- memcpy(dest, buffer_get_rest(stdbuf), len);
- buffer_pass_bytes(stdbuf,len);
-
- leave_function();
- return len;
-}
-
-/**
- * @brief Do a nonblocking read on the channel.
- *
- * A nonblocking read on the specified channel. it will return <= count bytes of
- * data read atomically.
- *
- * @param[in] channel The channel to read from.
- *
- * @param[in] dest A pointer to a destination buffer.
- *
- * @param[in] count The count of bytes of data to be read.
- *
- * @param[in] is_stderr A boolean to select the stderr stream.
- *
- * @return The number of bytes read, 0 if nothing is available or
- * SSH_ERROR on error.
- *
- * @warning Don't forget to check for EOF as it would return 0 here.
- *
- * @see channel_is_eof()
- */
-int ssh_channel_read_nonblocking(ssh_channel channel, void *dest, uint32_t count,
- int is_stderr) {
- ssh_session session = channel->session;
- uint32_t to_read;
- int rc;
-
- enter_function();
-
- to_read = ssh_channel_poll(channel, is_stderr);
-
- if (to_read <= 0) {
- leave_function();
- return to_read; /* may be an error code */
- }
-
- if (to_read > count) {
- to_read = count;
- }
- rc = ssh_channel_read(channel, dest, to_read, is_stderr);
-
- leave_function();
- return rc;
-}
-
-/**
- * @brief Polls a channel for data to read.
- *
- * @param[in] channel The channel to poll.
- *
- * @param[in] is_stderr A boolean to select the stderr stream.
- *
- * @return The number of bytes available for reading, 0 if nothing
- * is available or SSH_ERROR on error.
- *
- * @warning When the channel is in EOF state, the function returns SSH_EOF.
- *
- * @see channel_is_eof()
- */
-int ssh_channel_poll(ssh_channel channel, int is_stderr){
- ssh_session session = channel->session;
- ssh_buffer stdbuf = channel->stdout_buffer;
-
- enter_function();
-
- if (is_stderr) {
- stdbuf = channel->stderr_buffer;
- }
-
- if (buffer_get_rest_len(stdbuf) == 0 && channel->remote_eof == 0) {
- if (ssh_handle_packets(channel->session,0)==SSH_ERROR) {
- leave_function();
- return SSH_ERROR;
- }
- }
-
- if (buffer_get_rest_len(stdbuf) > 0){
- leave_function();
- return buffer_get_rest_len(stdbuf);
- }
-
- if (channel->remote_eof) {
- leave_function();
- return SSH_EOF;
- }
-
- leave_function();
- return buffer_get_rest_len(stdbuf);
-}
-
-/**
- * @brief Recover the session in which belongs a channel.
- *
- * @param[in] channel The channel to recover the session from.
- *
- * @return The session pointer.
- */
-ssh_session ssh_channel_get_session(ssh_channel channel) {
- return channel->session;
-}
-
-/**
- * @brief Get the exit status of the channel (error code from the executed
- * instruction).
- *
- * @param[in] channel The channel to get the status from.
- *
- * @returns The exit status, -1 if no exit status has been returned
- * or eof not sent.
- */
-int ssh_channel_get_exit_status(ssh_channel channel) {
- if (channel->local_eof == 0) {
- return -1;
- }
-
- while (channel->remote_eof == 0 || channel->exit_status == -1) {
- /* Parse every incoming packet */
- if (ssh_handle_packets(channel->session,-1) != SSH_OK) {
- return -1;
- }
- /* XXX We should actually wait for a close packet and not a close
- * we issued ourselves
- */
- if (channel->state != SSH_CHANNEL_STATE_OPEN) {
- /* When a channel is closed, no exit status message can
- * come anymore */
- break;
- }
- }
-
- return channel->exit_status;
-}
-
-/*
- * This function acts as a meta select.
- *
- * First, channels are analyzed to seek potential can-write or can-read ones,
- * then if no channel has been elected, it goes in a loop with the posix
- * select(2).
- * This is made in two parts: protocol select and network select. The protocol
- * select does not use the network functions at all
- */
-static int channel_protocol_select(ssh_channel *rchans, ssh_channel *wchans,
- ssh_channel *echans, ssh_channel *rout, ssh_channel *wout, ssh_channel *eout) {
- ssh_channel chan;
- int i;
- int j = 0;
-
- for (i = 0; rchans[i] != NULL; i++) {
- chan = rchans[i];
-
- while (ssh_channel_is_open(chan) && ssh_socket_data_available(chan->session->socket)) {
- ssh_handle_packets(chan->session,-1);
- }
-
- if ((chan->stdout_buffer && ssh_buffer_get_len(chan->stdout_buffer) > 0) ||
- (chan->stderr_buffer && ssh_buffer_get_len(chan->stderr_buffer) > 0) ||
- chan->remote_eof) {
- rout[j] = chan;
- j++;
- }
- }
- rout[j] = NULL;
-
- j = 0;
- for(i = 0; wchans[i] != NULL; i++) {
- chan = wchans[i];
- /* It's not our business to seek if the file descriptor is writable */
- if (ssh_socket_data_writable(chan->session->socket) &&
- ssh_channel_is_open(chan) && (chan->remote_window > 0)) {
- wout[j] = chan;
- j++;
- }
- }
- wout[j] = NULL;
-
- j = 0;
- for (i = 0; echans[i] != NULL; i++) {
- chan = echans[i];
-
- if (!ssh_socket_is_open(chan->session->socket) || ssh_channel_is_closed(chan)) {
- eout[j] = chan;
- j++;
- }
- }
- eout[j] = NULL;
-
- return 0;
-}
-
-/* Just count number of pointers in the array */
-static int count_ptrs(ssh_channel *ptrs) {
- int c;
- for (c = 0; ptrs[c] != NULL; c++)
- ;
-
- return c;
-}
-
-/**
- * @brief Act like the standard select(2) on channels.
- *
- * The list of pointers are then actualized and will only contain pointers to
- * channels that are respectively readable, writable or have an exception to
- * trap.
- *
- * @param[in] readchans A NULL pointer or an array of channel pointers,
- * terminated by a NULL.
- *
- * @param[in] writechans A NULL pointer or an array of channel pointers,
- * terminated by a NULL.
- *
- * @param[in] exceptchans A NULL pointer or an array of channel pointers,
- * terminated by a NULL.
- *
- * @param[in] timeout Timeout as defined by select(2).
- *
- * @return SSH_OK on a successful operation, SSH_EINTR if the
- * select(2) syscall was interrupted, then relaunch the
- * function.
- */
-int ssh_channel_select(ssh_channel *readchans, ssh_channel *writechans,
- ssh_channel *exceptchans, struct timeval * timeout) {
- ssh_channel *rchans, *wchans, *echans;
- ssh_channel dummy = NULL;
- fd_set rset;
- fd_set wset;
- fd_set eset;
- socket_t max_fd = SSH_INVALID_SOCKET;
- int rc;
- int i;
-
- /* don't allow NULL pointers */
- if (readchans == NULL) {
- readchans = &dummy;
- }
-
- if (writechans == NULL) {
- writechans = &dummy;
- }
-
- if (exceptchans == NULL) {
- exceptchans = &dummy;
- }
-
- if (readchans[0] == NULL && writechans[0] == NULL && exceptchans[0] == NULL) {
- /* No channel to poll?? Go away! */
- return 0;
- }
-
- /* Prepare the outgoing temporary arrays */
- rchans = malloc(sizeof(ssh_channel ) * (count_ptrs(readchans) + 1));
- if (rchans == NULL) {
- return SSH_ERROR;
- }
-
- wchans = malloc(sizeof(ssh_channel ) * (count_ptrs(writechans) + 1));
- if (wchans == NULL) {
- SAFE_FREE(rchans);
- return SSH_ERROR;
- }
-
- echans = malloc(sizeof(ssh_channel ) * (count_ptrs(exceptchans) + 1));
- if (echans == NULL) {
- SAFE_FREE(rchans);
- SAFE_FREE(wchans);
- return SSH_ERROR;
- }
-
- /*
- * First, try without doing network stuff then, select and redo the
- * networkless stuff
- */
- do {
- channel_protocol_select(readchans, writechans, exceptchans,
- rchans, wchans, echans);
- if (rchans[0] != NULL || wchans[0] != NULL || echans[0] != NULL) {
- /* We've got one without doing any select overwrite the beginning arrays */
- memcpy(readchans, rchans, (count_ptrs(rchans) + 1) * sizeof(ssh_channel ));
- memcpy(writechans, wchans, (count_ptrs(wchans) + 1) * sizeof(ssh_channel ));
- memcpy(exceptchans, echans, (count_ptrs(echans) + 1) * sizeof(ssh_channel ));
- SAFE_FREE(rchans);
- SAFE_FREE(wchans);
- SAFE_FREE(echans);
- return 0;
- }
- /*
- * Since we verified the invalid fd cases into the networkless select,
- * we can be sure all fd are valid ones
- */
- FD_ZERO(&rset);
- FD_ZERO(&wset);
- FD_ZERO(&eset);
-
- for (i = 0; readchans[i] != NULL; i++) {
- if (!ssh_socket_fd_isset(readchans[i]->session->socket, &rset)) {
- ssh_socket_fd_set(readchans[i]->session->socket, &rset, &max_fd);
- }
- }
-
- for (i = 0; writechans[i] != NULL; i++) {
- if (!ssh_socket_fd_isset(writechans[i]->session->socket, &wset)) {
- ssh_socket_fd_set(writechans[i]->session->socket, &wset, &max_fd);
- }
- }
-
- for (i = 0; exceptchans[i] != NULL; i++) {
- if (!ssh_socket_fd_isset(exceptchans[i]->session->socket, &eset)) {
- ssh_socket_fd_set(exceptchans[i]->session->socket, &eset, &max_fd);
- }
- }
-
- /* Here we go */
- rc = select(max_fd, &rset, &wset, &eset, timeout);
- /* Leave if select was interrupted */
- if (rc == EINTR) {
- SAFE_FREE(rchans);
- SAFE_FREE(wchans);
- SAFE_FREE(echans);
- return SSH_EINTR;
- }
-
- for (i = 0; readchans[i] != NULL; i++) {
- if (ssh_socket_fd_isset(readchans[i]->session->socket, &rset)) {
- ssh_socket_set_toread(readchans[i]->session->socket);
- }
- }
-
- for (i = 0; writechans[i] != NULL; i++) {
- if (ssh_socket_fd_isset(writechans[i]->session->socket, &wset)) {
- ssh_socket_set_towrite(writechans[i]->session->socket);
- }
- }
-
- for (i = 0; exceptchans[i] != NULL; i++) {
- if (ssh_socket_fd_isset(exceptchans[i]->session->socket, &eset)) {
- ssh_socket_set_except(exceptchans[i]->session->socket);
- }
- }
- } while(1); /* Return to do loop */
-
- /* not reached */
- return 0;
-}
-
-/** @} */
-
-/* vim: set ts=4 sw=4 et cindent: */
diff --git a/libssh/channels1.c b/libssh/channels1.c
deleted file mode 100644
index 4cf7e778..00000000
--- a/libssh/channels1.c
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * channels1.c - Support for SSH-1 type channels
- *
- * This file is part of the SSH Library
- *
- * Copyright (c) 2003-2008 by Aris Adamantiadis
- * Copyright (c) 2009 by Andreas Schneider <mail@cynapses.org>
- *
- * 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 <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <stdio.h>
-#ifndef _WIN32
-#include <arpa/inet.h>
-#endif
-#include "libssh/priv.h"
-#include "libssh/ssh1.h"
-#include "libssh/buffer.h"
-#include "libssh/packet.h"
-#include "libssh/channels.h"
-#include "libssh/session.h"
-
-#ifdef WITH_SSH1
-
-/*
- * This is a big hack. In fact, SSH1 doesn't make a clever use of channels.
- * The whole packets concerning shells are sent outside of a channel.
- * Thus, an inside limitation of this behavior is that you can't only
- * request one shell.
- * The question is still how they managed to embed two "channel" into one
- * protocol.
- */
-
-int channel_open_session1(ssh_channel chan) {
- /*
- * We guess we are requesting an *exec* channel. It can only have one exec
- * channel. So we abort with an error if we need more than one.
- */
- ssh_session session = chan->session;
- if (session->exec_channel_opened) {
- ssh_set_error(session, SSH_REQUEST_DENIED,
- "SSH1 supports only one execution channel. "
- "One has already been opened");
- return -1;
- }
- session->exec_channel_opened = 1;
- chan->state = SSH_CHANNEL_STATE_OPEN;
- chan->local_maxpacket = 32000;
- chan->local_window = 64000;
- ssh_log(session, SSH_LOG_PACKET, "Opened a SSH1 channel session");
-
- return 0;
-}
-
-/* 10 SSH_CMSG_REQUEST_PTY
- *
- * string TERM environment variable value (e.g. vt100)
- * 32-bit int terminal height, rows (e.g., 24)
- * 32-bit int terminal width, columns (e.g., 80)
- * 32-bit int terminal width, pixels (0 if no graphics) (e.g., 480)
- * 32-bit int terminal height, pixels (0 if no graphics) (e.g., 640)
- * n bytes tty modes encoded in binary
- * Some day, someone should have a look at that nasty tty encoded. It's
- * much simplier under ssh2. I just hope the defaults values are ok ...
- */
-
-int channel_request_pty_size1(ssh_channel channel, const char *terminal, int col,
- int row) {
- ssh_session session = channel->session;
- ssh_string str = NULL;
- if(channel->request_state != SSH_CHANNEL_REQ_STATE_NONE){
- ssh_set_error(session,SSH_REQUEST_DENIED,"Wrong request state");
- return SSH_ERROR;
- }
- str = ssh_string_from_char(terminal);
- if (str == NULL) {
- ssh_set_error_oom(session);
- return -1;
- }
-
- if (buffer_add_u8(session->out_buffer, SSH_CMSG_REQUEST_PTY) < 0 ||
- buffer_add_ssh_string(session->out_buffer, str) < 0) {
- ssh_string_free(str);
- return -1;
- }
- ssh_string_free(str);
-
- if (buffer_add_u32(session->out_buffer, ntohl(row)) < 0 ||
- buffer_add_u32(session->out_buffer, ntohl(col)) < 0 ||
- buffer_add_u32(session->out_buffer, 0) < 0 || /* x */
- buffer_add_u32(session->out_buffer, 0) < 0 || /* y */
- buffer_add_u8(session->out_buffer, 0) < 0) { /* tty things */
- return -1;
- }
-
- ssh_log(session, SSH_LOG_FUNCTIONS, "Opening a ssh1 pty");
-
- if (packet_send(session) == SSH_ERROR) {
- return -1;
- }
- switch(channel->request_state){
- case SSH_CHANNEL_REQ_STATE_ERROR:
- case SSH_CHANNEL_REQ_STATE_PENDING:
- case SSH_CHANNEL_REQ_STATE_NONE:
- channel->request_state=SSH_CHANNEL_REQ_STATE_NONE;
- return SSH_ERROR;
- case SSH_CHANNEL_REQ_STATE_ACCEPTED:
- channel->request_state=SSH_CHANNEL_REQ_STATE_NONE;
- ssh_log(session, SSH_LOG_RARE, "PTY: Success");
- return SSH_OK;
- case SSH_CHANNEL_REQ_STATE_DENIED:
- channel->request_state=SSH_CHANNEL_REQ_STATE_NONE;
- ssh_set_error(session, SSH_REQUEST_DENIED,
- "Server denied PTY allocation");
- ssh_log(session, SSH_LOG_RARE, "PTY: denied\n");
- return SSH_ERROR;
- }
- // Not reached
- return SSH_ERROR;
-}
-
-int channel_change_pty_size1(ssh_channel channel, int cols, int rows) {
- ssh_session session = channel->session;
- if(channel->request_state != SSH_CHANNEL_REQ_STATE_NONE){
- ssh_set_error(session,SSH_REQUEST_DENIED,"Wrong request state");
- return SSH_ERROR;
- }
- if (buffer_add_u8(session->out_buffer, SSH_CMSG_WINDOW_SIZE) < 0 ||
- buffer_add_u32(session->out_buffer, ntohl(rows)) < 0 ||
- buffer_add_u32(session->out_buffer, ntohl(cols)) < 0 ||
- buffer_add_u32(session->out_buffer, 0) < 0 ||
- buffer_add_u32(session->out_buffer, 0) < 0) {
- return SSH_ERROR;
- }
- channel->request_state=SSH_CHANNEL_REQ_STATE_PENDING;
- if (packet_send(session) == SSH_ERROR) {
- return SSH_ERROR;
- }
-
- ssh_log(session, SSH_LOG_PROTOCOL, "Change pty size send");
- while(channel->request_state==SSH_CHANNEL_REQ_STATE_PENDING){
- ssh_handle_packets(session,-1);
- }
- switch(channel->request_state){
- case SSH_CHANNEL_REQ_STATE_ERROR:
- case SSH_CHANNEL_REQ_STATE_PENDING:
- case SSH_CHANNEL_REQ_STATE_NONE:
- channel->request_state=SSH_CHANNEL_REQ_STATE_NONE;
- return SSH_ERROR;
- case SSH_CHANNEL_REQ_STATE_ACCEPTED:
- channel->request_state=SSH_CHANNEL_REQ_STATE_NONE;
- ssh_log(session, SSH_LOG_PROTOCOL, "pty size changed");
- return SSH_OK;
- case SSH_CHANNEL_REQ_STATE_DENIED:
- channel->request_state=SSH_CHANNEL_REQ_STATE_NONE;
- ssh_log(session, SSH_LOG_RARE, "pty size change denied");
- ssh_set_error(session, SSH_REQUEST_DENIED, "pty size change denied");
- return SSH_ERROR;
- }
- // Not reached
- return SSH_ERROR;
-
-}
-
-int channel_request_shell1(ssh_channel channel) {
- ssh_session session = channel->session;
-
- if (buffer_add_u8(session->out_buffer,SSH_CMSG_EXEC_SHELL) < 0) {
- return -1;
- }
-
- if (packet_send(session) == SSH_ERROR) {
- return -1;
- }
-
- ssh_log(session, SSH_LOG_RARE, "Launched a shell");
-
- return 0;
-}
-
-int channel_request_exec1(ssh_channel channel, const char *cmd) {
- ssh_session session = channel->session;
- ssh_string command = NULL;
-
- command = ssh_string_from_char(cmd);
- if (command == NULL) {
- return -1;
- }
-
- if (buffer_add_u8(session->out_buffer, SSH_CMSG_EXEC_CMD) < 0 ||
- buffer_add_ssh_string(session->out_buffer, command) < 0) {
- ssh_string_free(command);
- return -1;
- }
- ssh_string_free(command);
-
- if(packet_send(session) == SSH_ERROR) {
- return -1;
- }
-
- ssh_log(session, SSH_LOG_RARE, "Executing %s ...", cmd);
-
- return 0;
-}
-
-SSH_PACKET_CALLBACK(ssh_packet_data1){
- ssh_channel channel = session->channels;
- ssh_string str = NULL;
- int is_stderr=(type==SSH_SMSG_STDOUT_DATA ? 0 : 1);
- (void)user;
- str = buffer_get_ssh_string(packet);
- if (str == NULL) {
- ssh_log(session, SSH_LOG_FUNCTIONS, "Invalid data packet !\n");
- return SSH_PACKET_USED;
- }
-
- ssh_log(session, SSH_LOG_PROTOCOL,
- "Adding %zu bytes data in %d",
- ssh_string_len(str), is_stderr);
-
- if (channel_default_bufferize(channel, ssh_string_data(str), ssh_string_len(str),
- is_stderr) < 0) {
- ssh_string_free(str);
- return SSH_PACKET_USED;
- }
- ssh_string_free(str);
-
- return SSH_PACKET_USED;
-}
-
-SSH_PACKET_CALLBACK(ssh_packet_close1){
- ssh_channel channel = session->channels;
- uint32_t status;
- (void)type;
- (void)user;
- buffer_get_u32(packet, &status);
- /*
- * It's much more than a channel closing. spec says it's the last
- * message sent by server (strange)
- */
-
- /* actually status is lost somewhere */
- channel->state = SSH_CHANNEL_STATE_CLOSED;
- channel->remote_eof = 1;
-
- buffer_add_u8(session->out_buffer, SSH_CMSG_EXIT_CONFIRMATION);
- packet_send(session);
-
- return SSH_PACKET_USED;
-}
-
-
-int channel_write1(ssh_channel channel, const void *data, int len) {
- ssh_session session = channel->session;
- int origlen = len;
- int effectivelen;
- const unsigned char *ptr=data;
- while (len > 0) {
- if (buffer_add_u8(session->out_buffer, SSH_CMSG_STDIN_DATA) < 0) {
- return -1;
- }
-
- effectivelen = len > 32000 ? 32000 : len;
-
- if (buffer_add_u32(session->out_buffer, htonl(effectivelen)) < 0 ||
- buffer_add_data(session->out_buffer, ptr, effectivelen) < 0) {
- return -1;
- }
-
- ptr += effectivelen;
- len -= effectivelen;
-
- if (packet_send(session) == SSH_ERROR) {
- return -1;
- }
- }
-
- return origlen;
-}
-
-#endif /* WITH_SSH1 */
-/* vim: set ts=2 sw=2 et cindent: */
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: */
diff --git a/libssh/config.c b/libssh/config.c
deleted file mode 100644
index cfe2cc5f..00000000
--- a/libssh/config.c
+++ /dev/null
@@ -1,347 +0,0 @@
-/*
- * config.c - parse the ssh config file
- *
- * This file is part of the SSH Library
- *
- * Copyright (c) 2009 by Andreas Schneider <mail@cynapses.org>
- *
- * 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 <ctype.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "libssh/priv.h"
-#include "libssh/session.h"
-#include "libssh/misc.h"
-
-enum ssh_config_opcode_e {
- SOC_UNSUPPORTED = -1,
- SOC_HOST,
- SOC_HOSTNAME,
- SOC_PORT,
- SOC_USERNAME,
- SOC_IDENTITY,
- SOC_CIPHERS,
- SOC_COMPRESSION,
- SOC_TIMEOUT,
- SOC_PROTOCOL,
- SOC_HOSTKEYCHECK,
- SOC_KNOWNHOSTS,
- SOC_PROXYCOMMAND
-};
-
-struct ssh_config_keyword_table_s {
- const char *name;
- enum ssh_config_opcode_e opcode;
-};
-
-static struct ssh_config_keyword_table_s ssh_config_keyword_table[] = {
- { "host", SOC_HOST },
- { "hostname", SOC_HOSTNAME },
- { "port", SOC_PORT },
- { "user", SOC_USERNAME },
- { "identityfile", SOC_IDENTITY },
- { "ciphers", SOC_CIPHERS },
- { "compression", SOC_COMPRESSION },
- { "connecttimeout", SOC_TIMEOUT },
- { "protocol", SOC_PROTOCOL },
- { "stricthostkeychecking", SOC_HOSTKEYCHECK },
- { "userknownhostsfile", SOC_KNOWNHOSTS },
- { "proxycommand", SOC_PROXYCOMMAND },
- { NULL, SOC_UNSUPPORTED }
-};
-
-static enum ssh_config_opcode_e ssh_config_get_opcode(char *keyword) {
- int i;
-
- for (i = 0; ssh_config_keyword_table[i].name != NULL; i++) {
- if (strcasecmp(keyword, ssh_config_keyword_table[i].name) == 0) {
- return ssh_config_keyword_table[i].opcode;
- }
- }
-
- return SOC_UNSUPPORTED;
-}
-
-static char *ssh_config_get_token(char **str) {
- register char *c;
- char *r;
-
- /* Ignore leading spaces */
- for (c = *str; *c; c++) {
- if (! isblank(*c)) {
- break;
- }
- }
-
- if (*c == '\"') {
- for (r = ++c; *c; c++) {
- if (*c == '\"') {
- *c = '\0';
- goto out;
- }
- }
- }
-
- for (r = c; *c; c++) {
- if (isblank(*c)) {
- *c = '\0';
- goto out;
- }
- }
-
-out:
- *str = c + 1;
-
- return r;
-}
-
-static int ssh_config_get_int(char **str, int notfound) {
- char *p, *endp;
- int i;
-
- p = ssh_config_get_token(str);
- if (p && *p) {
- i = strtol(p, &endp, 10);
- if (p == endp) {
- return notfound;
- }
- return i;
- }
-
- return notfound;
-}
-
-static const char *ssh_config_get_str(char **str, const char *def) {
- char *p;
-
- p = ssh_config_get_token(str);
- if (p && *p) {
- return p;
- }
-
- return def;
-}
-
-static int ssh_config_get_yesno(char **str, int notfound) {
- const char *p;
-
- p = ssh_config_get_str(str, NULL);
- if (p == NULL) {
- return notfound;
- }
-
- if (strncasecmp(p, "yes", 3) == 0) {
- return 1;
- } else if (strncasecmp(p, "no", 2) == 0) {
- return 0;
- }
-
- return notfound;
-}
-
-static int ssh_config_parse_line(ssh_session session, const char *line,
- unsigned int count, int *parsing) {
- enum ssh_config_opcode_e opcode;
- const char *p;
- char *s, *x;
- char *keyword;
- char *lowerhost;
- size_t len;
- int i;
-
- x = s = strdup(line);
- if (s == NULL) {
- ssh_set_error_oom(session);
- return -1;
- }
-
- /* Remove trailing spaces */
- for (len = strlen(s) - 1; len > 0; len--) {
- if (! isspace(s[len])) {
- break;
- }
- s[len] = '\0';
- }
-
- keyword = ssh_config_get_token(&s);
- if (keyword == NULL || *keyword == '#' ||
- *keyword == '\0' || *keyword == '\n') {
- SAFE_FREE(x);
- return 0;
- }
-
- opcode = ssh_config_get_opcode(keyword);
-
- switch (opcode) {
- case SOC_HOST:
- *parsing = 0;
- lowerhost = (session->host) ? ssh_lowercase(session->host) : NULL;
- for (p = ssh_config_get_str(&s, NULL); p && *p;
- p = ssh_config_get_str(&s, NULL)) {
- if (match_hostname(lowerhost, p, strlen(p))) {
- *parsing = 1;
- }
- }
- SAFE_FREE(lowerhost);
- break;
- case SOC_HOSTNAME:
- p = ssh_config_get_str(&s, NULL);
- if (p && *parsing) {
- ssh_options_set(session, SSH_OPTIONS_HOST, p);
- }
- break;
- case SOC_PORT:
- if (session->port == 22) {
- p = ssh_config_get_str(&s, NULL);
- if (p && *parsing) {
- ssh_options_set(session, SSH_OPTIONS_PORT_STR, p);
- }
- }
- break;
- case SOC_USERNAME:
- if (session->username == NULL) {
- p = ssh_config_get_str(&s, NULL);
- if (p && *parsing) {
- ssh_options_set(session, SSH_OPTIONS_USER, p);
- }
- }
- break;
- case SOC_IDENTITY:
- p = ssh_config_get_str(&s, NULL);
- if (p && *parsing) {
- ssh_options_set(session, SSH_OPTIONS_ADD_IDENTITY, p);
- }
- break;
- case SOC_CIPHERS:
- p = ssh_config_get_str(&s, NULL);
- if (p && *parsing) {
- ssh_options_set(session, SSH_OPTIONS_CIPHERS_C_S, p);
- ssh_options_set(session, SSH_OPTIONS_CIPHERS_S_C, p);
- }
- break;
- case SOC_COMPRESSION:
- i = ssh_config_get_yesno(&s, -1);
- if (i >= 0 && *parsing) {
- if (i) {
- ssh_options_set(session, SSH_OPTIONS_COMPRESSION_C_S, "zlib,none");
- ssh_options_set(session, SSH_OPTIONS_COMPRESSION_S_C, "zlib,none");
- } else {
- ssh_options_set(session, SSH_OPTIONS_COMPRESSION_C_S, "none");
- ssh_options_set(session, SSH_OPTIONS_COMPRESSION_S_C, "none");
- }
- }
- break;
- case SOC_PROTOCOL:
- p = ssh_config_get_str(&s, NULL);
- if (p && *parsing) {
- char *a, *b;
- b = strdup(p);
- if (b == NULL) {
- SAFE_FREE(x);
- ssh_set_error_oom(session);
- return -1;
- }
- i = 0;
- ssh_options_set(session, SSH_OPTIONS_SSH1, &i);
- ssh_options_set(session, SSH_OPTIONS_SSH2, &i);
-
- for (a = strtok(b, ","); a; a = strtok(NULL, ",")) {
- switch (atoi(a)) {
- case 1:
- i = 1;
- ssh_options_set(session, SSH_OPTIONS_SSH1, &i);
- break;
- case 2:
- i = 1;
- ssh_options_set(session, SSH_OPTIONS_SSH2, &i);
- break;
- default:
- break;
- }
- }
- SAFE_FREE(b);
- }
- break;
- case SOC_TIMEOUT:
- i = ssh_config_get_int(&s, -1);
- if (i >= 0 && *parsing) {
- ssh_options_set(session, SSH_OPTIONS_TIMEOUT, &i);
- }
- break;
- case SOC_HOSTKEYCHECK:
- i = ssh_config_get_yesno(&s, -1);
- if (i >= 0 && *parsing) {
- ssh_options_set(session, SSH_OPTIONS_HOSTKEYCHECK, &i);
- }
- break;
- case SOC_KNOWNHOSTS:
- p = ssh_config_get_str(&s, NULL);
- if (p && *parsing) {
- ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, p);
- }
- break;
- case SOC_PROXYCOMMAND:
- p = ssh_config_get_str(&s, NULL);
- if (p && *parsing) {
- ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, p);
- }
- break;
- case SOC_UNSUPPORTED:
- ssh_log(session, SSH_LOG_RARE, "Unsupported option: %s, line: %d\n",
- keyword, count);
- break;
- default:
- ssh_set_error(session, SSH_FATAL, "ERROR - unimplemented opcode: %d\n",
- opcode);
- SAFE_FREE(x);
- return -1;
- break;
- }
-
- SAFE_FREE(x);
- return 0;
-}
-
-/* ssh_config_parse_file */
-int ssh_config_parse_file(ssh_session session, const char *filename) {
- char line[1024] = {0};
- unsigned int count = 0;
- FILE *f;
- int parsing;
-
- if ((f = fopen(filename, "r")) == NULL) {
- return 0;
- }
-
- if (session->log_verbosity) {
- fprintf(stderr, "Reading configuration data from %s\n", filename);
- }
-
- parsing = 1;
- while (fgets(line, sizeof(line), f)) {
- count++;
- if (ssh_config_parse_line(session, line, count, &parsing) < 0) {
- fclose(f);
- return -1;
- }
- }
-
- fclose(f);
- return 0;
-}
diff --git a/libssh/connect.c b/libssh/connect.c
deleted file mode 100644
index d877982c..00000000
--- a/libssh/connect.c
+++ /dev/null
@@ -1,600 +0,0 @@
-/*
- * connect.c - handles connections to ssh servers
- *
- * This file is part of the SSH Library
- *
- * Copyright (c) 2003-2009 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 <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifdef _WIN32
-/*
- * Only use Windows API functions available on Windows 2000 SP4 or later.
- * The available constants are in <sdkddkver.h>.
- * http://msdn.microsoft.com/en-us/library/aa383745.aspx
- * http://blogs.msdn.com/oldnewthing/archive/2007/04/11/2079137.aspx
- */
-#undef _WIN32_WINNT
-#ifdef HAVE_WSPIAPI_H
-#define _WIN32_WINNT 0x0500 /* _WIN32_WINNT_WIN2K */
-#undef NTDDI_VERSION
-#define NTDDI_VERSION 0x05000400 /* NTDDI_WIN2KSP4 */
-#else
-#define _WIN32_WINNT 0x0501 /* _WIN32_WINNT_WINXP */
-#undef NTDDI_VERSION
-#define NTDDI_VERSION 0x05010000 /* NTDDI_WINXP */
-#endif
-
-#if _MSC_VER >= 1400
-#include <io.h>
-#undef close
-#define close _close
-#endif /* _MSC_VER */
-#include <winsock2.h>
-#include <ws2tcpip.h>
-
-/* <wspiapi.h> is necessary for getaddrinfo before Windows XP, but it isn't
- * available on some platforms like MinGW. */
-#ifdef HAVE_WSPIAPI_H
-#include <wspiapi.h>
-#endif
-
-#else /* _WIN32 */
-
-#include <netdb.h>
-#include <sys/socket.h>
-#include <sys/select.h>
-#include <netinet/in.h>
-
-#endif /* _WIN32 */
-
-#include "libssh/priv.h"
-#include "libssh/socket.h"
-#include "libssh/channels.h"
-#include "libssh/session.h"
-
-#ifndef HAVE_SELECT
-#error "Your system must have select()"
-#endif
-
-#ifndef HAVE_GETADDRINFO
-#error "Your system must have getaddrinfo()"
-#endif
-
-#ifdef HAVE_REGCOMP
-/* don't declare gnu extended regexp's */
-#ifndef _POSIX_C_SOURCE
-#define _POSIX_C_SOURCE
-#endif
-#include <regex.h>
-#endif /* HAVE_REGCOMP */
-
-#ifdef _WIN32
-void ssh_sock_set_nonblocking(socket_t sock) {
- u_long nonblocking = 1;
- ioctlsocket(sock, FIONBIO, &nonblocking);
-}
-
-void ssh_sock_set_blocking(socket_t sock) {
- u_long nonblocking = 0;
- ioctlsocket(sock, FIONBIO, &nonblocking);
-}
-
-#ifndef gai_strerror
-char WSAAPI *gai_strerrorA(int code) {
- static char buf[256];
-
- snprintf(buf, sizeof(buf), "Undetermined error code (%d)", code);
-
- return buf;
-}
-#endif /* gai_strerror */
-
-#else /* _WIN32 */
-void ssh_sock_set_nonblocking(socket_t sock) {
- fcntl(sock, F_SETFL, O_NONBLOCK);
-}
-
-void ssh_sock_set_blocking(socket_t sock) {
- fcntl(sock, F_SETFL, 0);
-}
-
-#endif /* _WIN32 */
-
-#ifdef HAVE_REGCOMP
-static regex_t *ip_regex = NULL;
-
-/** @internal
- * @brief initializes and compile the regexp to be used for IP matching
- * @returns -1 on error (and error message is set)
- * @returns 0 on success
- */
-int ssh_regex_init(){
- if(ip_regex==NULL){
- int err;
- regex_t *regex=malloc(sizeof (regex_t));
- ZERO_STRUCTP(regex);
- err=regcomp(regex,"^[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+$",REG_EXTENDED | REG_NOSUB);
- if(err != 0){
- char buffer[128];
- regerror(err,regex,buffer,sizeof(buffer));
- fprintf(stderr,"Error while compiling regular expression : %s\n",buffer);
- SAFE_FREE(regex);
- return -1;
- }
- ip_regex=regex;
- }
- return 0;
-}
-
-/** @internal
- * @brief clean up the IP regexp
- */
-void ssh_regex_finalize(){
- if(ip_regex){
- regfree(ip_regex);
- SAFE_FREE(ip_regex);
- }
-}
-
-#else /* HAVE_REGCOMP */
-int ssh_regex_init(){
- return 0;
-}
-void ssh_regex_finalize(){
-}
-#endif
-
-
-static int ssh_connect_socket_close(socket_t s){
-#ifdef _WIN32
- return closesocket(s);
-#else
- return close(s);
-#endif
-}
-
-
-static int getai(ssh_session session, const char *host, int port, struct addrinfo **ai) {
- const char *service = NULL;
- struct addrinfo hints;
- char s_port[10];
-
- ZERO_STRUCT(hints);
-
- hints.ai_protocol = IPPROTO_TCP;
- hints.ai_family = PF_UNSPEC;
- hints.ai_socktype = SOCK_STREAM;
-
- if (port == 0) {
- hints.ai_flags = AI_PASSIVE;
- } else {
- snprintf(s_port, sizeof(s_port), "%hu", (unsigned short)port);
- service = s_port;
-#ifdef AI_NUMERICSERV
- hints.ai_flags=AI_NUMERICSERV;
-#endif
- }
-#ifdef HAVE_REGCOMP
- if(regexec(ip_regex,host,0,NULL,0) == 0){
- /* this is an IP address */
- ssh_log(session,SSH_LOG_PACKET,"host %s matches an IP address",host);
- hints.ai_flags |= AI_NUMERICHOST;
- }
-#endif
- return getaddrinfo(host, service, &hints, ai);
-}
-
-static int ssh_connect_ai_timeout(ssh_session session, const char *host,
- int port, struct addrinfo *ai, long timeout, long usec, socket_t s) {
- struct timeval to;
- fd_set set;
- int rc = 0;
- unsigned int len = sizeof(rc);
-
- enter_function();
-
- to.tv_sec = timeout;
- to.tv_usec = usec;
-
- ssh_sock_set_nonblocking(s);
-
- ssh_log(session, SSH_LOG_RARE, "Trying to connect to host: %s:%d with "
- "timeout %ld.%ld", host, port, timeout, usec);
-
- /* The return value is checked later */
- connect(s, ai->ai_addr, ai->ai_addrlen);
- freeaddrinfo(ai);
-
- FD_ZERO(&set);
- FD_SET(s, &set);
-
- rc = select(s + 1, NULL, &set, NULL, &to);
- if (rc == 0) {
- /* timeout */
- ssh_set_error(session, SSH_FATAL,
- "Timeout while connecting to %s:%d", host, port);
- ssh_connect_socket_close(s);
- leave_function();
- return -1;
- }
-
- if (rc < 0) {
- ssh_set_error(session, SSH_FATAL,
- "Select error: %s", strerror(errno));
- ssh_connect_socket_close(s);
- leave_function();
- return -1;
- }
- rc = 0;
-
- /* Get connect(2) return code. Zero means no error */
- getsockopt(s, SOL_SOCKET, SO_ERROR,(char *) &rc, &len);
- if (rc != 0) {
- ssh_set_error(session, SSH_FATAL,
- "Connect to %s:%d failed: %s", host, port, strerror(rc));
- ssh_connect_socket_close(s);
- leave_function();
- return -1;
- }
-
- /* s is connected ? */
- ssh_log(session, SSH_LOG_PACKET, "Socket connected with timeout\n");
- ssh_sock_set_blocking(s);
-
- leave_function();
- return s;
-}
-
-/**
- * @internal
- *
- * @brief Connect to an IPv4 or IPv6 host specified by its IP address or
- * hostname.
- *
- * @returns A file descriptor, < 0 on error.
- */
-socket_t ssh_connect_host(ssh_session session, const char *host,
- const char *bind_addr, int port, long timeout, long usec) {
- socket_t s = -1;
- int rc;
- struct addrinfo *ai;
- struct addrinfo *itr;
-
- enter_function();
-
- rc = getai(session,host, port, &ai);
- if (rc != 0) {
- ssh_set_error(session, SSH_FATAL,
- "Failed to resolve hostname %s (%s)", host, gai_strerror(rc));
- leave_function();
- return -1;
- }
-
- for (itr = ai; itr != NULL; itr = itr->ai_next){
- /* create socket */
- s = socket(itr->ai_family, itr->ai_socktype, itr->ai_protocol);
- if (s < 0) {
- ssh_set_error(session, SSH_FATAL,
- "Socket create failed: %s", strerror(errno));
- continue;
- }
-
- if (bind_addr) {
- struct addrinfo *bind_ai;
- struct addrinfo *bind_itr;
-
- ssh_log(session, SSH_LOG_PACKET, "Resolving %s\n", bind_addr);
-
- rc = getai(session,bind_addr, 0, &bind_ai);
- if (rc != 0) {
- ssh_set_error(session, SSH_FATAL,
- "Failed to resolve bind address %s (%s)",
- bind_addr,
- gai_strerror(rc));
- leave_function();
- return -1;
- }
-
- for (bind_itr = bind_ai; bind_itr != NULL; bind_itr = bind_itr->ai_next) {
- if (bind(s, bind_itr->ai_addr, bind_itr->ai_addrlen) < 0) {
- ssh_set_error(session, SSH_FATAL,
- "Binding local address: %s", strerror(errno));
- continue;
- } else {
- break;
- }
- }
- freeaddrinfo(bind_ai);
-
- /* Cannot bind to any local addresses */
- if (bind_itr == NULL) {
- ssh_connect_socket_close(s);
- s = -1;
- continue;
- }
- }
-
- if (timeout || usec) {
- socket_t ret = ssh_connect_ai_timeout(session, host, port, itr,
- timeout, usec, s);
- leave_function();
- return ret;
- }
-
- if (connect(s, itr->ai_addr, itr->ai_addrlen) < 0) {
- ssh_set_error(session, SSH_FATAL, "Connect failed: %s", strerror(errno));
- ssh_connect_socket_close(s);
- s = -1;
- leave_function();
- continue;
- } else {
- /* We are connected */
- break;
- }
- }
-
- freeaddrinfo(ai);
- leave_function();
-
- return s;
-}
-
-/**
- * @internal
- *
- * @brief Launches a nonblocking connect to an IPv4 or IPv6 host
- * specified by its IP address or hostname.
- *
- * @returns A file descriptor, < 0 on error.
- * @warning very ugly !!!
- */
-socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
- const char *bind_addr, int port) {
- socket_t s = -1;
- int rc;
- struct addrinfo *ai;
- struct addrinfo *itr;
-
- enter_function();
-
- rc = getai(session,host, port, &ai);
- if (rc != 0) {
- ssh_set_error(session, SSH_FATAL,
- "Failed to resolve hostname %s (%s)", host, gai_strerror(rc));
- leave_function();
- return -1;
- }
-
- for (itr = ai; itr != NULL; itr = itr->ai_next){
- /* create socket */
- s = socket(itr->ai_family, itr->ai_socktype, itr->ai_protocol);
- if (s < 0) {
- ssh_set_error(session, SSH_FATAL,
- "Socket create failed: %s", strerror(errno));
- continue;
- }
-
- if (bind_addr) {
- struct addrinfo *bind_ai;
- struct addrinfo *bind_itr;
-
- ssh_log(session, SSH_LOG_PACKET, "Resolving %s\n", bind_addr);
-
- rc = getai(session,bind_addr, 0, &bind_ai);
- if (rc != 0) {
- ssh_set_error(session, SSH_FATAL,
- "Failed to resolve bind address %s (%s)",
- bind_addr,
- gai_strerror(rc));
- close(s);
- s=-1;
- break;
- }
-
- for (bind_itr = bind_ai; bind_itr != NULL; bind_itr = bind_itr->ai_next) {
- if (bind(s, bind_itr->ai_addr, bind_itr->ai_addrlen) < 0) {
- ssh_set_error(session, SSH_FATAL,
- "Binding local address: %s", strerror(errno));
- continue;
- } else {
- break;
- }
- }
- freeaddrinfo(bind_ai);
-
- /* Cannot bind to any local addresses */
- if (bind_itr == NULL) {
- ssh_connect_socket_close(s);
- s = -1;
- continue;
- }
- }
- ssh_sock_set_nonblocking(s);
-
- connect(s, itr->ai_addr, itr->ai_addrlen);
- break;
- }
-
- freeaddrinfo(ai);
- leave_function();
-
- return s;
-}
-
-/**
- * @addtogroup libssh_session
- *
- * @{
- */
-
-/**
- * @brief A wrapper for the select syscall
- *
- * This functions acts more or less like the select(2) syscall.\n
- * There is no support for writing or exceptions.\n
- *
- * @param[in] channels Arrays of channels pointers terminated by a NULL.
- * It is never rewritten.
- *
- * @param[out] outchannels Arrays of same size that "channels", there is no need
- * to initialize it.
- *
- * @param[in] maxfd Maximum +1 file descriptor from readfds.
- *
- * @param[in] readfds A fd_set of file descriptors to be select'ed for
- * reading.
- *
- * @param[in] timeout A timeout for the select.
- *
- * @return -1 if an error occured. E_INTR if it was interrupted, in
- * that case, just restart it.
- *
- * @warning libssh is not threadsafe here. That means that if a signal is caught
- * during the processing of this function, you cannot call ssh
- * functions on sessions that are busy with ssh_select().
- *
- * @see select(2)
- */
-int ssh_select(ssh_channel *channels, ssh_channel *outchannels, socket_t maxfd,
- fd_set *readfds, struct timeval *timeout) {
- struct timeval zerotime;
- fd_set localset, localset2;
- socket_t f;
- int rep;
- int set;
- int i;
- int j;
-
- zerotime.tv_sec = 0;
- zerotime.tv_usec = 0;
-
- /*
- * First, poll the maxfd file descriptors from the user with a zero-second
- * timeout. They have the bigger priority.
- */
- if (maxfd > 0) {
- memcpy(&localset, readfds, sizeof(fd_set));
- rep = select(maxfd, &localset, NULL, NULL, &zerotime);
- /* catch the eventual errors */
- if (rep==-1) {
- return -1;
- }
- }
-
- /* Poll every channel */
- j = 0;
- for (i = 0; channels[i]; i++) {
- if (channels[i]->session->alive) {
- if(ssh_channel_poll(channels[i], 0) > 0) {
- outchannels[j] = channels[i];
- j++;
- } else {
- if(ssh_channel_poll(channels[i], 1) > 0) {
- outchannels[j] = channels[i];
- j++;
- }
- }
- }
- }
- outchannels[j] = NULL;
-
- /* Look into the localset for active fd */
- set = 0;
- for (f = 0; (f < maxfd) && !set; f++) {
- if (FD_ISSET(f, &localset)) {
- set = 1;
- }
- }
-
- /* j != 0 means a channel has data */
- if( (j != 0) || (set != 0)) {
- if(maxfd > 0) {
- memcpy(readfds, &localset, sizeof(fd_set));
- }
- return 0;
- }
-
- /*
- * At this point, not any channel had any data ready for reading, nor any fd
- * had data for reading.
- */
- memcpy(&localset, readfds, sizeof(fd_set));
- for (i = 0; channels[i]; i++) {
- if (channels[i]->session->alive) {
- ssh_socket_fd_set(channels[i]->session->socket, &localset, &maxfd);
- }
- }
-
- rep = select(maxfd, &localset, NULL, NULL, timeout);
- if (rep == -1 && errno == EINTR) {
- /* Interrupted by a signal */
- return SSH_EINTR;
- }
-
- if (rep == -1) {
- /*
- * Was the error due to a libssh's channel or from a closed descriptor from
- * the user? User closed descriptors have been caught in the first select
- * and not closed since that moment. That case shouldn't occur at all
- */
- return -1;
- }
-
- /* Set the data_to_read flag on each session */
- for (i = 0; channels[i]; i++) {
- if (channels[i]->session->alive &&
- ssh_socket_fd_isset(channels[i]->session->socket,&localset)) {
- ssh_socket_set_toread(channels[i]->session->socket);
- }
- }
-
- /* Now, test each channel */
- j = 0;
- for (i = 0; channels[i]; i++) {
- if (channels[i]->session->alive &&
- ssh_socket_fd_isset(channels[i]->session->socket,&localset)) {
- if ((ssh_channel_poll(channels[i],0) > 0) ||
- (ssh_channel_poll(channels[i], 1) > 0)) {
- outchannels[j] = channels[i];
- j++;
- }
- }
- }
- outchannels[j] = NULL;
-
- FD_ZERO(&localset2);
- for (f = 0; f < maxfd; f++) {
- if (FD_ISSET(f, readfds) && FD_ISSET(f, &localset)) {
- FD_SET(f, &localset2);
- }
- }
-
- memcpy(readfds, &localset2, sizeof(fd_set));
-
- return 0;
-}
-
-/** @} */
-
-/* vim: set ts=4 sw=4 et cindent: */
diff --git a/libssh/crc32.c b/libssh/crc32.c
deleted file mode 100644
index 94d3020c..00000000
--- a/libssh/crc32.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * crc32.c - simple CRC32 code
- *
- * This file is part of the SSH Library
- *
- * Copyright (c) 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 "libssh/priv.h"
-
-static uint32_t crc_table[] = {
- 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
- 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,
- 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,
- 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,
- 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL,
- 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,
- 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,
- 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,
- 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL,
- 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL,
- 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL,
- 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,
- 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,
- 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL,
- 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL,
- 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,
- 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL,
- 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,
- 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,
- 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,
- 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL,
- 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL,
- 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL,
- 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
- 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,
- 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL,
- 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL,
- 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,
- 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL,
- 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,
- 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,
- 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,
- 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL,
- 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL,
- 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL,
- 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,
- 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,
- 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL,
- 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL,
- 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,
- 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL,
- 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,
- 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,
- 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,
- 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL,
- 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL,
- 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL,
- 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
- 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,
- 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,
- 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,
- 0x2d02ef8dUL
-};
-
-uint32_t ssh_crc32(const char *buf, uint32_t len) {
- uint32_t ret = 0;
- while(len > 0) {
- ret = crc_table[(ret ^ *buf) & 0xff] ^ (ret >> 8);
- --len;
- ++buf;
- }
-
- return ret;
-}
-
-/* vim: set ts=2 sw=2 et cindent: */
diff --git a/libssh/crypt.c b/libssh/crypt.c
deleted file mode 100644
index 1085c4aa..00000000
--- a/libssh/crypt.c
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * crypt.c - blowfish-cbc code
- *
- * This file is part of the SSH Library
- *
- * Copyright (c) 2003 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 <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#ifndef _WIN32
-#include <arpa/inet.h>
-#endif
-
-#ifdef OPENSSL_CRYPTO
-#include <openssl/blowfish.h>
-#include <openssl/evp.h>
-#include <openssl/hmac.h>
-#endif
-
-#include "libssh/priv.h"
-#include "libssh/session.h"
-#include "libssh/wrapper.h"
-#include "libssh/crypto.h"
-#include "libssh/buffer.h"
-
-uint32_t packet_decrypt_len(ssh_session session, char *crypted){
- uint32_t decrypted;
-
- if (session->current_crypto) {
- if (packet_decrypt(session, crypted,
- session->current_crypto->in_cipher->blocksize) < 0) {
- return 0;
- }
- }
-
- memcpy(&decrypted,crypted,sizeof(decrypted));
- ssh_log(session, SSH_LOG_PACKET,
- "Packet size decrypted: %lu (0x%lx)",
- (long unsigned int) ntohl(decrypted),
- (long unsigned int) ntohl(decrypted));
- return ntohl(decrypted);
-}
-
-int packet_decrypt(ssh_session session, void *data,uint32_t len) {
- struct crypto_struct *crypto = session->current_crypto->in_cipher;
- char *out = NULL;
- if(len % session->current_crypto->in_cipher->blocksize != 0){
- ssh_set_error(session, SSH_FATAL, "Cryptographic functions must be set on at least one blocksize (received %d)",len);
- return SSH_ERROR;
- }
- out = malloc(len);
- if (out == NULL) {
- return -1;
- }
-
- ssh_log(session,SSH_LOG_PACKET, "Decrypting %d bytes", len);
-
-#ifdef HAVE_LIBGCRYPT
- if (crypto->set_decrypt_key(crypto, session->current_crypto->decryptkey,
- session->current_crypto->decryptIV) < 0) {
- SAFE_FREE(out);
- return -1;
- }
- crypto->cbc_decrypt(crypto,data,out,len);
-#elif defined HAVE_LIBCRYPTO
- if (crypto->set_decrypt_key(crypto, session->current_crypto->decryptkey) < 0) {
- SAFE_FREE(out);
- return -1;
- }
- crypto->cbc_decrypt(crypto,data,out,len,session->current_crypto->decryptIV);
-#endif
-
- memcpy(data,out,len);
- memset(out,0,len);
-
- SAFE_FREE(out);
- return 0;
-}
-
-unsigned char *packet_encrypt(ssh_session session, void *data, uint32_t len) {
- struct crypto_struct *crypto = NULL;
- HMACCTX ctx = NULL;
- char *out = NULL;
- unsigned int finallen;
- uint32_t seq;
-
- if (!session->current_crypto) {
- return NULL; /* nothing to do here */
- }
- if(len % session->current_crypto->in_cipher->blocksize != 0){
- ssh_set_error(session, SSH_FATAL, "Cryptographic functions must be set on at least one blocksize (received %d)",len);
- return NULL;
- }
- out = malloc(len);
- if (out == NULL) {
- return NULL;
- }
-
- seq = ntohl(session->send_seq);
- crypto = session->current_crypto->out_cipher;
-
- ssh_log(session, SSH_LOG_PACKET,
- "Encrypting packet with seq num: %d, len: %d",
- session->send_seq,len);
-
-#ifdef HAVE_LIBGCRYPT
- if (crypto->set_encrypt_key(crypto, session->current_crypto->encryptkey,
- session->current_crypto->encryptIV) < 0) {
- SAFE_FREE(out);
- return NULL;
- }
-#elif defined HAVE_LIBCRYPTO
- if (crypto->set_encrypt_key(crypto, session->current_crypto->encryptkey) < 0) {
- SAFE_FREE(out);
- return NULL;
- }
-#endif
-
- if (session->version == 2) {
- ctx = hmac_init(session->current_crypto->encryptMAC,20,HMAC_SHA1);
- if (ctx == NULL) {
- SAFE_FREE(out);
- return NULL;
- }
- hmac_update(ctx,(unsigned char *)&seq,sizeof(uint32_t));
- hmac_update(ctx,data,len);
- hmac_final(ctx,session->current_crypto->hmacbuf,&finallen);
-#ifdef DEBUG_CRYPTO
- ssh_print_hexa("mac: ",data,len);
- if (finallen != 20) {
- printf("Final len is %d\n",finallen);
- }
- ssh_print_hexa("Packet hmac", session->current_crypto->hmacbuf, 20);
-#endif
- }
-
-#ifdef HAVE_LIBGCRYPT
- crypto->cbc_encrypt(crypto, data, out, len);
-#elif defined HAVE_LIBCRYPTO
- crypto->cbc_encrypt(crypto, data, out, len,
- session->current_crypto->encryptIV);
-#endif
-
- memcpy(data, out, len);
- memset(out, 0, len);
- SAFE_FREE(out);
-
- if (session->version == 2) {
- return session->current_crypto->hmacbuf;
- }
-
- return NULL;
-}
-
-/**
- * @internal
- *
- * @brief Verify the hmac of a packet
- *
- * @param session The session to use.
- * @param buffer The buffer to verify the hmac from.
- * @param mac The mac to compare with the hmac.
- *
- * @return 0 if hmac and mac are equal, < 0 if not or an error
- * occurred.
- */
-int packet_hmac_verify(ssh_session session, ssh_buffer buffer,
- unsigned char *mac) {
- unsigned char hmacbuf[EVP_MAX_MD_SIZE] = {0};
- HMACCTX ctx;
- unsigned int len;
- uint32_t seq;
-
- ctx = hmac_init(session->current_crypto->decryptMAC, 20, HMAC_SHA1);
- if (ctx == NULL) {
- return -1;
- }
-
- seq = htonl(session->recv_seq);
-
- hmac_update(ctx, (unsigned char *) &seq, sizeof(uint32_t));
- hmac_update(ctx, ssh_buffer_get_begin(buffer), ssh_buffer_get_len(buffer));
- hmac_final(ctx, hmacbuf, &len);
-
-#ifdef DEBUG_CRYPTO
- ssh_print_hexa("received mac",mac,len);
- ssh_print_hexa("Computed mac",hmacbuf,len);
- ssh_print_hexa("seq",(unsigned char *)&seq,sizeof(uint32_t));
-#endif
- if (memcmp(mac, hmacbuf, len) == 0) {
- return 0;
- }
-
- return -1;
-}
-
-/* vim: set ts=2 sw=2 et cindent: */
diff --git a/libssh/dh.c b/libssh/dh.c
deleted file mode 100644
index 74d799e6..00000000
--- a/libssh/dh.c
+++ /dev/null
@@ -1,1049 +0,0 @@
-/*
- * dh.c - Diffie-Helman algorithm code against SSH 2
- *
- * This file is part of the SSH Library
- *
- * Copyright (c) 2003-2008 by Aris Adamantiadis
- * Copyright (c) 2009 by Andreas Schneider <mail@cynapses.org>
- *
- * 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.
- */
-
-/*
- * Let us resume the dh protocol.
- * Each side computes a private prime number, x at client side, y at server
- * side.
- * g and n are two numbers common to every ssh software.
- * client's public key (e) is calculated by doing:
- * e = g^x mod p
- * client sends e to the server.
- * the server computes his own public key, f
- * f = g^y mod p
- * it sends it to the client
- * the common key K is calculated by the client by doing
- * k = f^x mod p
- * the server does the same with the client public key e
- * k' = e^y mod p
- * if everything went correctly, k and k' are equal
- */
-
-#include "config.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifndef _WIN32
-#include <arpa/inet.h>
-#endif
-
-#include "libssh/priv.h"
-#include "libssh/crypto.h"
-#include "libssh/buffer.h"
-#include "libssh/session.h"
-#include "libssh/keys.h"
-#include "libssh/dh.h"
-
-/* todo: remove it */
-#include "libssh/string.h"
-#ifdef HAVE_LIBCRYPTO
-#include <openssl/rand.h>
-#include <openssl/evp.h>
-#include <openssl/err.h>
-#endif
-
-static unsigned char p_value[] = {
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
- 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
- 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
- 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
- 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
- 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
- 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
- 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
- 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11,
- 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
-#define P_LEN 128 /* Size in bytes of the p number */
-
-static unsigned long g_int = 2 ; /* G is defined as 2 by the ssh2 standards */
-static bignum g;
-static bignum p;
-static int ssh_crypto_initialized;
-
-int ssh_get_random(void *where, int len, int strong){
-
-#ifdef HAVE_LIBGCRYPT
- /* variable not used in gcrypt */
- (void) strong;
- /* not using GCRY_VERY_STRONG_RANDOM which is a bit overkill */
- gcry_randomize(where,len,GCRY_STRONG_RANDOM);
-
- return 1;
-#elif defined HAVE_LIBCRYPTO
- if (strong) {
- return RAND_bytes(where,len);
- } else {
- return RAND_pseudo_bytes(where,len);
- }
-#endif
-
- /* never reached */
- return 1;
-}
-
-/*
- * This inits the values g and p which are used for DH key agreement
- * FIXME: Make the function thread safe by adding a semaphore or mutex.
- */
-int ssh_crypto_init(void) {
- if (ssh_crypto_initialized == 0) {
-#ifdef HAVE_LIBGCRYPT
- gcry_check_version(NULL);
- if (!gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P,0)) {
- gcry_control(GCRYCTL_INIT_SECMEM, 4096);
- gcry_control(GCRYCTL_INITIALIZATION_FINISHED,0);
- }
-#endif
-
- g = bignum_new();
- if (g == NULL) {
- return -1;
- }
- bignum_set_word(g,g_int);
-
-#ifdef HAVE_LIBGCRYPT
- bignum_bin2bn(p_value, P_LEN, &p);
- if (p == NULL) {
- bignum_free(g);
- g = NULL;
- return -1;
- }
-#elif defined HAVE_LIBCRYPTO
- p = bignum_new();
- if (p == NULL) {
- bignum_free(g);
- g = NULL;
- return -1;
- }
- bignum_bin2bn(p_value, P_LEN, p);
- OpenSSL_add_all_algorithms();
-#endif
-
- ssh_crypto_initialized = 1;
- }
-
- return 0;
-}
-
-void ssh_crypto_finalize(void) {
- if (ssh_crypto_initialized) {
- bignum_free(g);
- g = NULL;
- bignum_free(p);
- p = NULL;
- ssh_crypto_initialized=0;
-
- }
-}
-
-/* prints the bignum on stderr */
-void ssh_print_bignum(const char *which, bignum num) {
-#ifdef HAVE_LIBGCRYPT
- unsigned char *hex = NULL;
- bignum_bn2hex(num, &hex);
-#elif defined HAVE_LIBCRYPTO
- char *hex = NULL;
- hex = bignum_bn2hex(num);
-#endif
- fprintf(stderr, "%s value: ", which);
- fprintf(stderr, "%s\n", (hex == NULL) ? "(null)" : (char *) hex);
- SAFE_FREE(hex);
-}
-
-/**
- * @brief Convert a buffer into a colon separated hex string.
- * The caller has to free the memory.
- *
- * @param what What should be converted to a hex string.
- *
- * @param len Length of the buffer to convert.
- *
- * @return The hex string or NULL on error.
- */
-char *ssh_get_hexa(const unsigned char *what, size_t len) {
- char *hexa = NULL;
- size_t i;
-
- hexa = malloc(len * 3 + 1);
- if (hexa == NULL) {
- return NULL;
- }
-
- ZERO_STRUCTP(hexa);
-
- for (i = 0; i < len; i++) {
- char hex[4];
- snprintf(hex, sizeof(hex), "%02x:", what[i]);
- strcat(hexa, hex);
- }
-
- hexa[(len * 3) - 1] = '\0';
-
- return hexa;
-}
-
-/**
- * @brief Print a buffer as colon separated hex string.
- *
- * @param descr Description printed in front of the hex string.
- *
- * @param what What should be converted to a hex string.
- *
- * @param len Length of the buffer to convert.
- */
-void ssh_print_hexa(const char *descr, const unsigned char *what, size_t len) {
- char *hexa = ssh_get_hexa(what, len);
-
- if (hexa == NULL) {
- return;
- }
- printf("%s: %s\n", descr, hexa);
-}
-
-int dh_generate_x(ssh_session session) {
- session->next_crypto->x = bignum_new();
- if (session->next_crypto->x == NULL) {
- return -1;
- }
-
-#ifdef HAVE_LIBGCRYPT
- bignum_rand(session->next_crypto->x, 128);
-#elif defined HAVE_LIBCRYPTO
- bignum_rand(session->next_crypto->x, 128, 0, -1);
-#endif
-
- /* not harder than this */
-#ifdef DEBUG_CRYPTO
- ssh_print_bignum("x", session->next_crypto->x);
-#endif
-
- return 0;
-}
-
-/* used by server */
-int dh_generate_y(ssh_session session) {
- session->next_crypto->y = bignum_new();
- if (session->next_crypto->y == NULL) {
- return -1;
- }
-
-#ifdef HAVE_LIBGCRYPT
- bignum_rand(session->next_crypto->y, 128);
-#elif defined HAVE_LIBCRYPTO
- bignum_rand(session->next_crypto->y, 128, 0, -1);
-#endif
-
- /* not harder than this */
-#ifdef DEBUG_CRYPTO
- ssh_print_bignum("y", session->next_crypto->y);
-#endif
-
- return 0;
-}
-
-/* used by server */
-int dh_generate_e(ssh_session session) {
-#ifdef HAVE_LIBCRYPTO
- bignum_CTX ctx = bignum_ctx_new();
- if (ctx == NULL) {
- return -1;
- }
-#endif
-
- session->next_crypto->e = bignum_new();
- if (session->next_crypto->e == NULL) {
-#ifdef HAVE_LIBCRYPTO
- bignum_ctx_free(ctx);
-#endif
- return -1;
- }
-
-#ifdef HAVE_LIBGCRYPT
- bignum_mod_exp(session->next_crypto->e, g, session->next_crypto->x, p);
-#elif defined HAVE_LIBCRYPTO
- bignum_mod_exp(session->next_crypto->e, g, session->next_crypto->x, p, ctx);
-#endif
-
-#ifdef DEBUG_CRYPTO
- ssh_print_bignum("e", session->next_crypto->e);
-#endif
-
-#ifdef HAVE_LIBCRYPTO
- bignum_ctx_free(ctx);
-#endif
-
- return 0;
-}
-
-int dh_generate_f(ssh_session session) {
-#ifdef HAVE_LIBCRYPTO
- bignum_CTX ctx = bignum_ctx_new();
- if (ctx == NULL) {
- return -1;
- }
-#endif
-
- session->next_crypto->f = bignum_new();
- if (session->next_crypto->f == NULL) {
-#ifdef HAVE_LIBCRYPTO
- bignum_ctx_free(ctx);
-#endif
- return -1;
- }
-
-#ifdef HAVE_LIBGCRYPT
- bignum_mod_exp(session->next_crypto->f, g, session->next_crypto->y, p);
-#elif defined HAVE_LIBCRYPTO
- bignum_mod_exp(session->next_crypto->f, g, session->next_crypto->y, p, ctx);
-#endif
-
-#ifdef DEBUG_CRYPTO
- ssh_print_bignum("f", session->next_crypto->f);
-#endif
-
-#ifdef HAVE_LIBCRYPTO
- bignum_ctx_free(ctx);
-#endif
-
- return 0;
-}
-
-ssh_string make_bignum_string(bignum num) {
- ssh_string ptr = NULL;
- int pad = 0;
- unsigned int len = bignum_num_bytes(num);
- unsigned int bits = bignum_num_bits(num);
-
- /* Remember if the fist bit is set, it is considered as a
- * negative number. So 0's must be appended */
- if (!(bits % 8) && bignum_is_bit_set(num, bits - 1)) {
- pad++;
- }
-
-#ifdef DEBUG_CRYPTO
- fprintf(stderr, "%d bits, %d bytes, %d padding\n", bits, len, pad);
-#endif /* DEBUG_CRYPTO */
-/* TODO: fix that crap !! */
- ptr = malloc(4 + len + pad);
- if (ptr == NULL) {
- return NULL;
- }
- ptr->size = htonl(len + pad);
- if (pad) {
- ptr->string[0] = 0;
- }
-
-#ifdef HAVE_LIBGCRYPT
- bignum_bn2bin(num, len, ptr->string + pad);
-#elif HAVE_LIBCRYPTO
- bignum_bn2bin(num, ptr->string + pad);
-#endif
-
- return ptr;
-}
-
-bignum make_string_bn(ssh_string string){
- bignum bn = NULL;
- unsigned int len = ssh_string_len(string);
-
-#ifdef DEBUG_CRYPTO
- fprintf(stderr, "Importing a %d bits, %d bytes object ...\n",
- len * 8, len);
-#endif /* DEBUG_CRYPTO */
-
-#ifdef HAVE_LIBGCRYPT
- bignum_bin2bn(string->string, len, &bn);
-#elif defined HAVE_LIBCRYPTO
- bn = bignum_bin2bn(string->string, len, NULL);
-#endif
-
- return bn;
-}
-
-ssh_string dh_get_e(ssh_session session) {
- return make_bignum_string(session->next_crypto->e);
-}
-
-/* used by server */
-ssh_string dh_get_f(ssh_session session) {
- return make_bignum_string(session->next_crypto->f);
-}
-
-void dh_import_pubkey(ssh_session session, ssh_string pubkey_string) {
- session->next_crypto->server_pubkey = pubkey_string;
-}
-
-int dh_import_f(ssh_session session, ssh_string f_string) {
- session->next_crypto->f = make_string_bn(f_string);
- if (session->next_crypto->f == NULL) {
- return -1;
- }
-
-#ifdef DEBUG_CRYPTO
- ssh_print_bignum("f",session->next_crypto->f);
-#endif
-
- return 0;
-}
-
-/* used by the server implementation */
-int dh_import_e(ssh_session session, ssh_string e_string) {
- session->next_crypto->e = make_string_bn(e_string);
- if (session->next_crypto->e == NULL) {
- return -1;
- }
-
-#ifdef DEBUG_CRYPTO
- ssh_print_bignum("e",session->next_crypto->e);
-#endif
-
- return 0;
-}
-
-int dh_build_k(ssh_session session) {
-#ifdef HAVE_LIBCRYPTO
- bignum_CTX ctx = bignum_ctx_new();
- if (ctx == NULL) {
- return -1;
- }
-#endif
-
- session->next_crypto->k = bignum_new();
- if (session->next_crypto->k == NULL) {
-#ifdef HAVE_LIBCRYPTO
- bignum_ctx_free(ctx);
-#endif
- return -1;
- }
-
- /* the server and clients don't use the same numbers */
-#ifdef HAVE_LIBGCRYPT
- if(session->client) {
- bignum_mod_exp(session->next_crypto->k, session->next_crypto->f,
- session->next_crypto->x, p);
- } else {
- bignum_mod_exp(session->next_crypto->k, session->next_crypto->e,
- session->next_crypto->y, p);
- }
-#elif defined HAVE_LIBCRYPTO
- if (session->client) {
- bignum_mod_exp(session->next_crypto->k, session->next_crypto->f,
- session->next_crypto->x, p, ctx);
- } else {
- bignum_mod_exp(session->next_crypto->k, session->next_crypto->e,
- session->next_crypto->y, p, ctx);
- }
-#endif
-
-#ifdef DEBUG_CRYPTO
- ssh_print_hexa("Session server cookie", session->server_kex.cookie, 16);
- ssh_print_hexa("Session client cookie", session->client_kex.cookie, 16);
- ssh_print_bignum("Shared secret key", session->next_crypto->k);
-#endif
-
-#ifdef HAVE_LIBCRYPTO
- bignum_ctx_free(ctx);
-#endif
-
- return 0;
-}
-
-/*
-static void sha_add(ssh_string str,SHACTX ctx){
- sha1_update(ctx,str,string_len(str)+4);
-#ifdef DEBUG_CRYPTO
- ssh_print_hexa("partial hashed sessionid",str,string_len(str)+4);
-#endif
-}
-*/
-
-int make_sessionid(ssh_session session) {
- SHACTX ctx;
- ssh_string num = NULL;
- ssh_string str = NULL;
- ssh_buffer server_hash = NULL;
- ssh_buffer client_hash = NULL;
- ssh_buffer buf = NULL;
- uint32_t len;
- int rc = SSH_ERROR;
-
- enter_function();
-
- ctx = sha1_init();
- if (ctx == NULL) {
- return rc;
- }
-
- buf = ssh_buffer_new();
- if (buf == NULL) {
- return rc;
- }
-
- str = ssh_string_from_char(session->clientbanner);
- if (str == NULL) {
- goto error;
- }
-
- if (buffer_add_ssh_string(buf, str) < 0) {
- goto error;
- }
- ssh_string_free(str);
-
- str = ssh_string_from_char(session->serverbanner);
- if (str == NULL) {
- goto error;
- }
-
- if (buffer_add_ssh_string(buf, str) < 0) {
- goto error;
- }
-
- if (session->client) {
- server_hash = session->in_hashbuf;
- client_hash = session->out_hashbuf;
- } else {
- server_hash = session->out_hashbuf;
- client_hash = session->in_hashbuf;
- }
-
- if (buffer_add_u32(server_hash, 0) < 0) {
- goto error;
- }
- if (buffer_add_u8(server_hash, 0) < 0) {
- goto error;
- }
- if (buffer_add_u32(client_hash, 0) < 0) {
- goto error;
- }
- if (buffer_add_u8(client_hash, 0) < 0) {
- goto error;
- }
-
- len = ntohl(ssh_buffer_get_len(client_hash));
- if (buffer_add_u32(buf,len) < 0) {
- goto error;
- }
- if (buffer_add_data(buf, ssh_buffer_get_begin(client_hash),
- ssh_buffer_get_len(client_hash)) < 0) {
- goto error;
- }
-
- len = ntohl(ssh_buffer_get_len(server_hash));
- if (buffer_add_u32(buf, len) < 0) {
- goto error;
- }
- if (buffer_add_data(buf, ssh_buffer_get_begin(server_hash),
- ssh_buffer_get_len(server_hash)) < 0) {
- goto error;
- }
-
- len = ssh_string_len(session->next_crypto->server_pubkey) + 4;
- if (buffer_add_data(buf, session->next_crypto->server_pubkey, len) < 0) {
- goto error;
- }
-
- num = make_bignum_string(session->next_crypto->e);
- if (num == NULL) {
- goto error;
- }
-
- len = ssh_string_len(num) + 4;
- if (buffer_add_data(buf, num, len) < 0) {
- goto error;
- }
-
- ssh_string_free(num);
- num = make_bignum_string(session->next_crypto->f);
- if (num == NULL) {
- goto error;
- }
-
- len = ssh_string_len(num) + 4;
- if (buffer_add_data(buf, num, len) < 0) {
- goto error;
- }
-
- ssh_string_free(num);
- num = make_bignum_string(session->next_crypto->k);
- if (num == NULL) {
- goto error;
- }
-
- len = ssh_string_len(num) + 4;
- if (buffer_add_data(buf, num, len) < 0) {
- goto error;
- }
-
-#ifdef DEBUG_CRYPTO
- ssh_print_hexa("hash buffer", ssh_buffer_get_begin(buf), ssh_buffer_get_len(buf));
-#endif
-
- sha1_update(ctx, ssh_buffer_get_begin(buf), ssh_buffer_get_len(buf));
- sha1_final(session->next_crypto->session_id, ctx);
-
-#ifdef DEBUG_CRYPTO
- printf("Session hash: ");
- ssh_print_hexa("session id", session->next_crypto->session_id, SHA_DIGEST_LEN);
-#endif
-
- rc = SSH_OK;
-error:
- ssh_buffer_free(buf);
- ssh_buffer_free(client_hash);
- ssh_buffer_free(server_hash);
-
- session->in_hashbuf = NULL;
- session->out_hashbuf = NULL;
-
- ssh_string_free(str);
- ssh_string_free(num);
-
- leave_function();
-
- return rc;
-}
-
-int hashbufout_add_cookie(ssh_session session) {
- session->out_hashbuf = ssh_buffer_new();
- if (session->out_hashbuf == NULL) {
- return -1;
- }
-
- if (buffer_add_u8(session->out_hashbuf, 20) < 0) {
- buffer_reinit(session->out_hashbuf);
- return -1;
- }
-
- if (session->server) {
- if (buffer_add_data(session->out_hashbuf,
- session->server_kex.cookie, 16) < 0) {
- buffer_reinit(session->out_hashbuf);
- return -1;
- }
- } else {
- if (buffer_add_data(session->out_hashbuf,
- session->client_kex.cookie, 16) < 0) {
- buffer_reinit(session->out_hashbuf);
- return -1;
- }
- }
-
- return 0;
-}
-
-int hashbufin_add_cookie(ssh_session session, unsigned char *cookie) {
- session->in_hashbuf = ssh_buffer_new();
- if (session->in_hashbuf == NULL) {
- return -1;
- }
-
- if (buffer_add_u8(session->in_hashbuf, 20) < 0) {
- buffer_reinit(session->in_hashbuf);
- return -1;
- }
- if (buffer_add_data(session->in_hashbuf,cookie, 16) < 0) {
- buffer_reinit(session->in_hashbuf);
- return -1;
- }
-
- return 0;
-}
-
-static int generate_one_key(ssh_string k,
- unsigned char session_id[SHA_DIGEST_LEN],
- unsigned char output[SHA_DIGEST_LEN],
- char letter) {
- SHACTX ctx = NULL;
-
- ctx = sha1_init();
- if (ctx == NULL) {
- return -1;
- }
-
- sha1_update(ctx, k, ssh_string_len(k) + 4);
- sha1_update(ctx, session_id, SHA_DIGEST_LEN);
- sha1_update(ctx, &letter, 1);
- sha1_update(ctx, session_id, SHA_DIGEST_LEN);
- sha1_final(output, ctx);
-
- return 0;
-}
-
-int generate_session_keys(ssh_session session) {
- ssh_string k_string = NULL;
- SHACTX ctx = NULL;
- int rc = -1;
-
- enter_function();
-
- k_string = make_bignum_string(session->next_crypto->k);
- if (k_string == NULL) {
- goto error;
- }
-
- /* IV */
- if (session->client) {
- if (generate_one_key(k_string, session->next_crypto->session_id,
- session->next_crypto->encryptIV, 'A') < 0) {
- goto error;
- }
- if (generate_one_key(k_string, session->next_crypto->session_id,
- session->next_crypto->decryptIV, 'B') < 0) {
- goto error;
- }
- } else {
- if (generate_one_key(k_string, session->next_crypto->session_id,
- session->next_crypto->decryptIV, 'A') < 0) {
- goto error;
- }
- if (generate_one_key(k_string, session->next_crypto->session_id,
- session->next_crypto->encryptIV, 'B') < 0) {
- goto error;
- }
- }
- if (session->client) {
- if (generate_one_key(k_string, session->next_crypto->session_id,
- session->next_crypto->encryptkey, 'C') < 0) {
- goto error;
- }
- if (generate_one_key(k_string, session->next_crypto->session_id,
- session->next_crypto->decryptkey, 'D') < 0) {
- goto error;
- }
- } else {
- if (generate_one_key(k_string, session->next_crypto->session_id,
- session->next_crypto->decryptkey, 'C') < 0) {
- goto error;
- }
- if (generate_one_key(k_string, session->next_crypto->session_id,
- session->next_crypto->encryptkey, 'D') < 0) {
- goto error;
- }
- }
-
- /* some ciphers need more than 20 bytes of input key */
- /* XXX verify it's ok for server implementation */
- if (session->next_crypto->out_cipher->keysize > SHA_DIGEST_LEN * 8) {
- ctx = sha1_init();
- if (ctx == NULL) {
- goto error;
- }
- sha1_update(ctx, k_string, ssh_string_len(k_string) + 4);
- sha1_update(ctx, session->next_crypto->session_id, SHA_DIGEST_LEN);
- sha1_update(ctx, session->next_crypto->encryptkey, SHA_DIGEST_LEN);
- sha1_final(session->next_crypto->encryptkey + SHA_DIGEST_LEN, ctx);
- }
-
- if (session->next_crypto->in_cipher->keysize > SHA_DIGEST_LEN * 8) {
- ctx = sha1_init();
- sha1_update(ctx, k_string, ssh_string_len(k_string) + 4);
- sha1_update(ctx, session->next_crypto->session_id, SHA_DIGEST_LEN);
- sha1_update(ctx, session->next_crypto->decryptkey, SHA_DIGEST_LEN);
- sha1_final(session->next_crypto->decryptkey + SHA_DIGEST_LEN, ctx);
- }
- if(session->client) {
- if (generate_one_key(k_string, session->next_crypto->session_id,
- session->next_crypto->encryptMAC, 'E') < 0) {
- goto error;
- }
- if (generate_one_key(k_string, session->next_crypto->session_id,
- session->next_crypto->decryptMAC, 'F') < 0) {
- goto error;
- }
- } else {
- if (generate_one_key(k_string, session->next_crypto->session_id,
- session->next_crypto->decryptMAC, 'E') < 0) {
- goto error;
- }
- if (generate_one_key(k_string, session->next_crypto->session_id,
- session->next_crypto->encryptMAC, 'F') < 0) {
- goto error;
- }
- }
-
-#ifdef DEBUG_CRYPTO
- ssh_print_hexa("Encrypt IV", session->next_crypto->encryptIV, SHA_DIGEST_LEN);
- ssh_print_hexa("Decrypt IV", session->next_crypto->decryptIV, SHA_DIGEST_LEN);
- ssh_print_hexa("Encryption key", session->next_crypto->encryptkey,
- session->next_crypto->out_cipher->keysize);
- ssh_print_hexa("Decryption key", session->next_crypto->decryptkey,
- session->next_crypto->in_cipher->keysize);
- ssh_print_hexa("Encryption MAC", session->next_crypto->encryptMAC, SHA_DIGEST_LEN);
- ssh_print_hexa("Decryption MAC", session->next_crypto->decryptMAC, 20);
-#endif
-
- rc = 0;
-error:
- ssh_string_free(k_string);
- leave_function();
-
- return rc;
-}
-
-/**
- * @addtogroup libssh_session
- *
- * @{
- */
-
-/**
- * @brief Allocates a buffer with the MD5 hash of the server public key.
- *
- * @param[in] session The SSH session to use.
- *
- * @param[in] hash The buffer to allocate.
- *
- * @return The bytes allocated or < 0 on error.
- *
- * @warning It is very important that you verify at some moment that the hash
- * matches a known server. If you don't do it, cryptography wont help
- * you at making things secure
- *
- * @see ssh_is_server_known()
- * @see ssh_get_hexa()
- * @see ssh_print_hexa()
- */
-int ssh_get_pubkey_hash(ssh_session session, unsigned char **hash) {
- ssh_string pubkey;
- MD5CTX ctx;
- unsigned char *h;
-
- if (session == NULL || hash == NULL) {
- return -1;
- }
- *hash = NULL;
- if (session->current_crypto == NULL ||
- session->current_crypto->server_pubkey == NULL){
- ssh_set_error(session,SSH_FATAL,"No current cryptographic context");
- }
-
- h = malloc(sizeof(unsigned char *) * MD5_DIGEST_LEN);
- if (h == NULL) {
- return -1;
- }
-
- ctx = md5_init();
- if (ctx == NULL) {
- SAFE_FREE(h);
- return -1;
- }
-
- pubkey = session->current_crypto->server_pubkey;
-
- md5_update(ctx, pubkey->string, ssh_string_len(pubkey));
- md5_final(h, ctx);
-
- *hash = h;
-
- return MD5_DIGEST_LEN;
-}
-
-/**
- * @brief Deallocate the hash obtained by ssh_get_pubkey_hash.
- *
- * This is required under Microsoft platform as this library might use a
- * different C library than your software, hence a different heap.
- *
- * @param[in] hash The buffer to deallocate.
- *
- * @see ssh_get_pubkey_hash()
- */
-void ssh_clean_pubkey_hash(unsigned char **hash) {
- SAFE_FREE(*hash);
- *hash = NULL;
-}
-
-ssh_string ssh_get_pubkey(ssh_session session){
- return ssh_string_copy(session->current_crypto->server_pubkey);
-}
-
-static int match(const char *group, const char *object){
- const char *a;
- const char *z;
-
- z = group;
- do {
- a = strchr(z, ',');
- if (a == NULL) {
- if (strcmp(z, object) == 0) {
- return 1;
- }
- return 0;
- } else {
- if (strncmp(z, object, a - z) == 0) {
- return 1;
- }
- }
- z = a + 1;
- } while(1);
-
- /* not reached */
- return 0;
-}
-
-int sig_verify(ssh_session session, ssh_public_key pubkey,
- SIGNATURE *signature, unsigned char *digest, int size) {
-#ifdef HAVE_LIBGCRYPT
- gcry_error_t valid = 0;
- gcry_sexp_t gcryhash;
-#elif defined HAVE_LIBCRYPTO
- int valid = 0;
-#endif
- unsigned char hash[SHA_DIGEST_LEN + 1] = {0};
-
- sha1(digest, size, hash + 1);
-
-#ifdef DEBUG_CRYPTO
- ssh_print_hexa("Hash to be verified with dsa", hash + 1, SHA_DIGEST_LEN);
-#endif
-
- switch(pubkey->type) {
- case SSH_KEYTYPE_DSS:
-#ifdef HAVE_LIBGCRYPT
- valid = gcry_sexp_build(&gcryhash, NULL, "%b", SHA_DIGEST_LEN + 1, hash);
- if (valid != 0) {
- ssh_set_error(session, SSH_FATAL,
- "RSA error: %s", gcry_strerror(valid));
- return -1;
- }
- valid = gcry_pk_verify(signature->dsa_sign, gcryhash, pubkey->dsa_pub);
- gcry_sexp_release(gcryhash);
- if (valid == 0) {
- return 0;
- }
-
- if (gcry_err_code(valid) != GPG_ERR_BAD_SIGNATURE) {
- ssh_set_error(session, SSH_FATAL,
- "DSA error: %s", gcry_strerror(valid));
- return -1;
- }
-#elif defined HAVE_LIBCRYPTO
- valid = DSA_do_verify(hash + 1, SHA_DIGEST_LEN, signature->dsa_sign,
- pubkey->dsa_pub);
- if (valid == 1) {
- return 0;
- }
-
- if (valid == -1) {
- ssh_set_error(session, SSH_FATAL,
- "DSA error: %s", ERR_error_string(ERR_get_error(), NULL));
- return -1;
- }
-#endif
- ssh_set_error(session, SSH_FATAL, "Invalid DSA signature");
- return -1;
-
- case SSH_KEYTYPE_RSA:
- case SSH_KEYTYPE_RSA1:
-#ifdef HAVE_LIBGCRYPT
- valid = gcry_sexp_build(&gcryhash, NULL,
- "(data(flags pkcs1)(hash sha1 %b))", SHA_DIGEST_LEN, hash + 1);
- if (valid != 0) {
- ssh_set_error(session, SSH_FATAL,
- "RSA error: %s", gcry_strerror(valid));
- return -1;
- }
- valid = gcry_pk_verify(signature->rsa_sign,gcryhash,pubkey->rsa_pub);
- gcry_sexp_release(gcryhash);
- if (valid == 0) {
- return 0;
- }
- if (gcry_err_code(valid) != GPG_ERR_BAD_SIGNATURE) {
- ssh_set_error(session, SSH_FATAL,
- "RSA error: %s", gcry_strerror(valid));
- return -1;
- }
-#elif defined HAVE_LIBCRYPTO
- valid = RSA_verify(NID_sha1, hash + 1, SHA_DIGEST_LEN,
- signature->rsa_sign->string, ssh_string_len(signature->rsa_sign),
- pubkey->rsa_pub);
- if (valid == 1) {
- return 0;
- }
- if (valid == -1) {
- ssh_set_error(session, SSH_FATAL,
- "RSA error: %s", ERR_error_string(ERR_get_error(), NULL));
- return -1;
- }
-#endif
- ssh_set_error(session, SSH_FATAL, "Invalid RSA signature");
- return -1;
- default:
- ssh_set_error(session, SSH_FATAL, "Unknown public key type");
- return -1;
- }
-
- return -1;
-}
-
-int signature_verify(ssh_session session, ssh_string signature) {
- ssh_public_key pubkey = NULL;
- SIGNATURE *sign = NULL;
- int err;
-
- enter_function();
-
- pubkey = publickey_from_string(session,session->next_crypto->server_pubkey);
- if(pubkey == NULL) {
- leave_function();
- return -1;
- }
-
- if (session->wanted_methods[SSH_HOSTKEYS]) {
- if(!match(session->wanted_methods[SSH_HOSTKEYS],pubkey->type_c)) {
- ssh_set_error(session, SSH_FATAL,
- "Public key from server (%s) doesn't match user preference (%s)",
- pubkey->type_c, session->wanted_methods[SSH_HOSTKEYS]);
- publickey_free(pubkey);
- leave_function();
- return -1;
- }
- }
-
- sign = signature_from_string(session, signature, pubkey, pubkey->type);
- if (sign == NULL) {
- ssh_set_error(session, SSH_FATAL, "Invalid signature blob");
- publickey_free(pubkey);
- leave_function();
- return -1;
- }
-
- ssh_log(session, SSH_LOG_FUNCTIONS,
- "Going to verify a %s type signature", pubkey->type_c);
-
- err = sig_verify(session,pubkey,sign,
- session->next_crypto->session_id,SHA_DIGEST_LEN);
- signature_free(sign);
- session->next_crypto->server_pubkey_type = pubkey->type_c;
- publickey_free(pubkey);
-
- leave_function();
- return err;
-}
-
-/** @} */
-
-/* vim: set ts=4 sw=4 et cindent: */
diff --git a/libssh/error.c b/libssh/error.c
deleted file mode 100644
index f5bb1190..00000000
--- a/libssh/error.c
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * error.c - functions for ssh error handling
- *
- * 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 <stdarg.h>
-#include "libssh/priv.h"
-
-/**
- * @defgroup libssh_error The SSH error functions.
- * @ingroup libssh
- *
- * Functions for error handling.
- *
- * @{
- */
-
-/**
- * @internal
- *
- * @brief Registers an error with a description.
- *
- * @param error The place to store the error.
- *
- * @param code The class of error.
- *
- * @param descr The description, which can be a format string.
- *
- * @param ... The arguments for the format string.
- */
-void ssh_set_error(void *error, int code, const char *descr, ...) {
- struct error_struct *err = error;
- va_list va;
- va_start(va, descr);
- vsnprintf(err->error_buffer, ERROR_BUFFERLEN, descr, va);
- va_end(va);
- err->error_code = code;
-}
-
-/**
- * @internal
- *
- * @brief Registers an out of memory error
- *
- * @param error The place to store the error.
- *
- */
-void ssh_set_error_oom(void *error) {
- struct error_struct *err = error;
-
- strcpy(err->error_buffer, "Out of memory");
- err->error_code = SSH_FATAL;
-}
-
-/**
- * @internal
- *
- * @brief Registers an invalid argument error
- *
- * @param error The place to store the error.
- *
- * @param function The function the error happened in.
- *
- */
-void ssh_set_error_invalid(void *error, const char *function) {
- ssh_set_error(error, SSH_FATAL, "Invalid argument in %s", function);
-}
-
-/**
- * @brief Retrieve the error text message from the last error.
- *
- * @param error The SSH session pointer.
- *
- * @return A static string describing the error.
- */
-const char *ssh_get_error(void *error) {
- struct error_struct *err = error;
-
- return err->error_buffer;
-}
-
-/**
- * @brief Retrieve the error code from the last error.
- *
- * @param error The SSH session pointer.
- *
- * \return SSH_NO_ERROR No error occurred\n
- * SSH_REQUEST_DENIED The last request was denied but situation is
- * recoverable\n
- * SSH_FATAL A fatal error occurred. This could be an unexpected
- * disconnection\n
- *
- * Other error codes are internal but can be considered same than
- * SSH_FATAL.
- */
-int ssh_get_error_code(void *error) {
- struct error_struct *err = error;
-
- return err->error_code;
-}
-
-/** @} */
-
-/* vim: set ts=4 sw=4 et cindent: */
diff --git a/libssh/gcrypt_missing.c b/libssh/gcrypt_missing.c
deleted file mode 100644
index 7a456a6a..00000000
--- a/libssh/gcrypt_missing.c
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * gcrypt_missing.c - routines that are in OpenSSL but not in libgcrypt.
- *
- * This file is part of the SSH Library
- *
- * Copyright (c) 2003-2006 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 <stdlib.h>
-#include "libssh/priv.h"
-
-#ifdef HAVE_LIBGCRYPT
-int my_gcry_dec2bn(bignum *bn, const char *data) {
- int count;
-
- *bn = bignum_new();
- if (*bn == NULL) {
- return 0;
- }
- gcry_mpi_set_ui(*bn, 0);
- for (count = 0; data[count]; count++) {
- gcry_mpi_mul_ui(*bn, *bn, 10);
- gcry_mpi_add_ui(*bn, *bn, data[count] - '0');
- }
-
- return count;
-}
-
-char *my_gcry_bn2dec(bignum bn) {
- bignum bndup, num, ten;
- char *ret;
- int count, count2;
- int size, rsize;
- char decnum;
-
- size = gcry_mpi_get_nbits(bn) * 3;
- rsize = size / 10 + size / 1000 + 2;
-
- ret = malloc(rsize + 1);
- if (ret == NULL) {
- return NULL;
- }
-
- if (!gcry_mpi_cmp_ui(bn, 0)) {
- strcpy(ret, "0");
- } else {
- ten = bignum_new();
- if (ten == NULL) {
- SAFE_FREE(ret);
- return NULL;
- }
-
- num = bignum_new();
- if (num == NULL) {
- SAFE_FREE(ret);
- bignum_free(ten);
- return NULL;
- }
-
- for (bndup = gcry_mpi_copy(bn), bignum_set_word(ten, 10), count = rsize;
- count; count--) {
- gcry_mpi_div(bndup, num, bndup, ten, 0);
- for (decnum = 0, count2 = gcry_mpi_get_nbits(num); count2;
- decnum *= 2, decnum += (gcry_mpi_test_bit(num, count2 - 1) ? 1 : 0),
- count2--)
- ;
- ret[count - 1] = decnum + '0';
- }
- for (count = 0; count < rsize && ret[count] == '0'; count++)
- ;
- for (count2 = 0; count2 < rsize - count; ++count2) {
- ret[count2] = ret[count2 + count];
- }
- ret[count2] = 0;
- bignum_free(num);
- bignum_free(bndup);
- bignum_free(ten);
- }
-
- return ret;
-}
-
-#endif
-/* vim: set ts=2 sw=2 et cindent: */
diff --git a/libssh/gzip.c b/libssh/gzip.c
deleted file mode 100644
index 1e892dc7..00000000
--- a/libssh/gzip.c
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * gzip.c - hooks for compression of packets
- *
- * This file is part of the SSH Library
- *
- * Copyright (c) 2003 by Aris Adamantiadis
- * Copyright (c) 2009 by Andreas Schneider <mail@cynapses.org>
- *
- * 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 "libssh/priv.h"
-#include "libssh/buffer.h"
-#include "libssh/session.h"
-
-#if defined(HAVE_LIBZ) && defined(WITH_LIBZ)
-
-#include <zlib.h>
-#include <string.h>
-#include <stdlib.h>
-
-#define BLOCKSIZE 4092
-
-static z_stream *initcompress(ssh_session session, int level) {
- z_stream *stream = NULL;
- int status;
-
- stream = malloc(sizeof(z_stream));
- if (stream == NULL) {
- return NULL;
- }
- memset(stream, 0, sizeof(z_stream));
-
- status = deflateInit(stream, level);
- if (status != Z_OK) {
- SAFE_FREE(stream);
- ssh_set_error(session, SSH_FATAL,
- "status %d inititalising zlib deflate", status);
- return NULL;
- }
-
- return stream;
-}
-
-static ssh_buffer gzip_compress(ssh_session session,ssh_buffer source,int level){
- z_stream *zout = session->current_crypto->compress_out_ctx;
- void *in_ptr = ssh_buffer_get_begin(source);
- unsigned long in_size = ssh_buffer_get_len(source);
- ssh_buffer dest = NULL;
- unsigned char out_buf[BLOCKSIZE] = {0};
- unsigned long len;
- int status;
-
- if(zout == NULL) {
- zout = session->current_crypto->compress_out_ctx = initcompress(session, level);
- if (zout == NULL) {
- return NULL;
- }
- }
-
- dest = ssh_buffer_new();
- if (dest == NULL) {
- return NULL;
- }
-
- zout->next_out = out_buf;
- zout->next_in = in_ptr;
- zout->avail_in = in_size;
- do {
- zout->avail_out = BLOCKSIZE;
- status = deflate(zout, Z_PARTIAL_FLUSH);
- if (status != Z_OK) {
- ssh_buffer_free(dest);
- ssh_set_error(session, SSH_FATAL,
- "status %d deflating zlib packet", status);
- return NULL;
- }
- len = BLOCKSIZE - zout->avail_out;
- if (buffer_add_data(dest, out_buf, len) < 0) {
- ssh_buffer_free(dest);
- return NULL;
- }
- zout->next_out = out_buf;
- } while (zout->avail_out == 0);
-
- return dest;
-}
-
-int compress_buffer(ssh_session session, ssh_buffer buf) {
- ssh_buffer dest = NULL;
-
- dest = gzip_compress(session, buf, 9);
- if (dest == NULL) {
- return -1;
- }
-
- if (buffer_reinit(buf) < 0) {
- ssh_buffer_free(dest);
- return -1;
- }
-
- if (buffer_add_data(buf, ssh_buffer_get_begin(dest), ssh_buffer_get_len(dest)) < 0) {
- ssh_buffer_free(dest);
- return -1;
- }
-
- ssh_buffer_free(dest);
- return 0;
-}
-
-/* decompression */
-
-static z_stream *initdecompress(ssh_session session) {
- z_stream *stream = NULL;
- int status;
-
- stream = malloc(sizeof(z_stream));
- if (stream == NULL) {
- return NULL;
- }
- memset(stream,0,sizeof(z_stream));
-
- status = inflateInit(stream);
- if (status != Z_OK) {
- SAFE_FREE(stream);
- ssh_set_error(session, SSH_FATAL,
- "Status = %d initiating inflate context!", status);
- return NULL;
- }
-
- return stream;
-}
-
-static ssh_buffer gzip_decompress(ssh_session session, ssh_buffer source, size_t maxlen) {
- z_stream *zin = session->current_crypto->compress_in_ctx;
- void *in_ptr = buffer_get_rest(source);
- unsigned long in_size = buffer_get_rest_len(source);
- unsigned char out_buf[BLOCKSIZE] = {0};
- ssh_buffer dest = NULL;
- unsigned long len;
- int status;
-
- if (zin == NULL) {
- zin = session->current_crypto->compress_in_ctx = initdecompress(session);
- if (zin == NULL) {
- return NULL;
- }
- }
-
- dest = ssh_buffer_new();
- if (dest == NULL) {
- return NULL;
- }
-
- zin->next_out = out_buf;
- zin->next_in = in_ptr;
- zin->avail_in = in_size;
-
- do {
- zin->avail_out = BLOCKSIZE;
- status = inflate(zin, Z_PARTIAL_FLUSH);
- if (status != Z_OK) {
- ssh_set_error(session, SSH_FATAL,
- "status %d inflating zlib packet", status);
- ssh_buffer_free(dest);
- return NULL;
- }
-
- len = BLOCKSIZE - zin->avail_out;
- if (buffer_add_data(dest,out_buf,len) < 0) {
- ssh_buffer_free(dest);
- return NULL;
- }
- if (ssh_buffer_get_len(dest) > maxlen){
- /* Size of packet exceded, avoid a denial of service attack */
- ssh_buffer_free(dest);
- return NULL;
- }
- zin->next_out = out_buf;
- } while (zin->avail_out == 0);
-
- return dest;
-}
-
-int decompress_buffer(ssh_session session,ssh_buffer buf, size_t maxlen){
- ssh_buffer dest = NULL;
-
- dest = gzip_decompress(session,buf, maxlen);
- if (dest == NULL) {
- return -1;
- }
-
- if (buffer_reinit(buf) < 0) {
- ssh_buffer_free(dest);
- return -1;
- }
-
- if (buffer_add_data(buf, ssh_buffer_get_begin(dest), ssh_buffer_get_len(dest)) < 0) {
- ssh_buffer_free(dest);
- return -1;
- }
-
- ssh_buffer_free(dest);
- return 0;
-}
-
-#endif /* HAVE_LIBZ && WITH_LIBZ */
-/* vim: set ts=2 sw=2 et cindent: */
diff --git a/libssh/init.c b/libssh/init.c
deleted file mode 100644
index 5952e272..00000000
--- a/libssh/init.c
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * init.c - initialization and finalization of the library
- *
- * This file is part of the SSH Library
- *
- * Copyright (c) 2003-2009 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 "libssh/priv.h"
-#include "libssh/socket.h"
-#include "libssh/dh.h"
-#include "libssh/poll.h"
-#include "libssh/threads.h"
-
-#ifdef _WIN32
-#include <winsock2.h>
-#endif
-
-/**
- * @defgroup libssh The libssh API
- *
- * The libssh library is implementing the SSH protocols and some of its
- * extensions. This group of functions is mostly used to implment a SSH client.
- * Some function are needed to implement a SSH server too.
- *
- * @{
- */
-
-/**
- * @brief Initialize global cryptographic data structures.
- *
- * This function should only be called once, at the beginning of the program, in
- * the main thread. It may be omitted if your program is not multithreaded.
- *
- * @returns 0 on success, -1 if an error occured.
- */
-int ssh_init(void) {
- if(ssh_threads_init())
- return -1;
- if(ssh_crypto_init())
- return -1;
- if(ssh_socket_init())
- return -1;
- if(ssh_regex_init())
- return -1;
- return 0;
-}
-
-
-/**
- * @brief Finalize and cleanup all libssh and cryptographic data structures.
- *
- * This function should only be called once, at the end of the program!
- *
- * @returns 0 on succes, -1 if an error occured.
- *
- @returns 0 otherwise
- */
-int ssh_finalize(void) {
- ssh_threads_finalize();
- ssh_free_global_poll_ctx();
- ssh_regex_finalize();
- ssh_crypto_finalize();
- ssh_socket_cleanup();
-#ifdef HAVE_LIBGCRYPT
- gcry_control(GCRYCTL_TERM_SECMEM);
-#elif defined HAVE_LIBCRYPTO
- EVP_cleanup();
-#endif
-#ifdef _WIN32
- WSACleanup();
-#endif
- return 0;
-}
-
-/** @} */
-
-/* vim: set ts=4 sw=4 et cindent: */
diff --git a/libssh/kex.c b/libssh/kex.c
deleted file mode 100644
index d57273ec..00000000
--- a/libssh/kex.c
+++ /dev/null
@@ -1,835 +0,0 @@
-/*
- * kex.c - key exchange
- *
- * 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 "config.h"
-
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#ifndef _WIN32
-#include <arpa/inet.h>
-#endif
-
-#include "libssh/priv.h"
-#include "libssh/ssh2.h"
-#include "libssh/ssh1.h"
-#include "libssh/buffer.h"
-#include "libssh/packet.h"
-#include "libssh/session.h"
-#include "libssh/wrapper.h"
-#include "libssh/keys.h"
-#include "libssh/dh.h"
-#include "libssh/kex.h"
-#include "libssh/string.h"
-
-#ifdef HAVE_LIBGCRYPT
-#define BLOWFISH "blowfish-cbc,"
-#define AES "aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc,aes192-cbc,aes128-cbc,"
-#define DES "3des-cbc"
-#elif defined HAVE_LIBCRYPTO
-#ifdef HAVE_OPENSSL_BLOWFISH_H
-#define BLOWFISH "blowfish-cbc,"
-#else
-#define BLOWFISH ""
-#endif
-#ifdef HAVE_OPENSSL_AES_H
-#ifdef BROKEN_AES_CTR
-#define AES "aes256-cbc,aes192-cbc,aes128-cbc,"
-#else
-#define AES "aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc,aes192-cbc,aes128-cbc,"
-#endif /* BROKEN_AES_CTR */
-#else
-#define AES ""
-#endif
-
-#define DES "3des-cbc"
-#endif
-
-#if defined(HAVE_LIBZ) && defined(WITH_LIBZ)
-#define ZLIB "none,zlib,zlib@openssh.org"
-#else
-#define ZLIB "none"
-#endif
-
-const char *default_methods[] = {
- "diffie-hellman-group1-sha1",
- "ssh-rsa,ssh-dss",
- AES BLOWFISH DES,
- AES BLOWFISH DES,
- "hmac-sha1",
- "hmac-sha1",
- "none",
- "none",
- "",
- "",
- NULL
-};
-
-const char *supported_methods[] = {
- "diffie-hellman-group1-sha1",
- "ssh-rsa,ssh-dss",
- AES BLOWFISH DES,
- AES BLOWFISH DES,
- "hmac-sha1",
- "hmac-sha1",
- ZLIB,
- ZLIB,
- "",
- "",
- NULL
-};
-
-/* descriptions of the key exchange packet */
-const char *ssh_kex_nums[] = {
- "kex algos",
- "server host key algo",
- "encryption client->server",
- "encryption server->client",
- "mac algo client->server",
- "mac algo server->client",
- "compression algo client->server",
- "compression algo server->client",
- "languages client->server",
- "languages server->client",
- NULL
-};
-
-/* tokenize will return a token of strings delimited by ",". the first element has to be freed */
-static char **tokenize(const char *chain){
- char **tokens;
- int n=1;
- int i=0;
- char *tmp;
- char *ptr;
-
- tmp = strdup(chain);
- if (tmp == NULL) {
- return NULL;
- }
- ptr = tmp;
- while(*ptr){
- if(*ptr==','){
- n++;
- *ptr=0;
- }
- ptr++;
- }
- /* now n contains the number of tokens, the first possibly empty if the list was empty too e.g. "" */
- tokens=malloc(sizeof(char *) * (n+1) ); /* +1 for the null */
- if (tokens == NULL) {
- SAFE_FREE(tmp);
- return NULL;
- }
- ptr=tmp;
- for(i=0;i<n;i++){
- tokens[i]=ptr;
- while(*ptr)
- ptr++; // find a zero
- ptr++; // then go one step further
- }
- tokens[i]=NULL;
- return tokens;
-}
-
-/* same as tokenize(), but with spaces instead of ',' */
-/* TODO FIXME rewrite me! */
-char **space_tokenize(const char *chain){
- char **tokens;
- int n=1;
- int i=0;
- char *tmp;
- char *ptr;
-
- tmp = strdup(chain);
- if (tmp == NULL) {
- return NULL;
- }
- ptr = tmp;
-
- while(*ptr==' ')
- ++ptr; /* skip initial spaces */
- while(*ptr){
- if(*ptr==' '){
- n++; /* count one token per word */
- *ptr=0;
- while(*(ptr+1)==' '){ /* don't count if the tokens have more than 2 spaces */
- *(ptr++)=0;
- }
- }
- ptr++;
- }
- /* now n contains the number of tokens, the first possibly empty if the list was empty too e.g. "" */
- tokens = malloc(sizeof(char *) * (n + 1)); /* +1 for the null */
- if (tokens == NULL) {
- SAFE_FREE(tmp);
- return NULL;
- }
- ptr=tmp; /* we don't pass the initial spaces because the "tmp" pointer is needed by the caller */
- /* function to free the tokens. */
- for(i=0;i<n;i++){
- tokens[i]=ptr;
- if(i!=n-1){
- while(*ptr)
- ptr++; // find a zero
- while(!*(ptr+1))
- ++ptr; /* if the zero is followed by other zeros, go through them */
- ptr++; // then go one step further
- }
- }
- tokens[i]=NULL;
- return tokens;
-}
-
-/* find_matching gets 2 parameters : a list of available objects (available_d), separated by colons,*/
-/* and a list of preferred objects (preferred_d) */
-/* it will return a strduped pointer on the first preferred object found in the available objects list */
-
-char *ssh_find_matching(const char *available_d, const char *preferred_d){
- char ** tok_available, **tok_preferred;
- int i_avail, i_pref;
- char *ret;
-
- if ((available_d == NULL) || (preferred_d == NULL)) {
- return NULL; /* don't deal with null args */
- }
-
- tok_available = tokenize(available_d);
- if (tok_available == NULL) {
- return NULL;
- }
-
- tok_preferred = tokenize(preferred_d);
- if (tok_preferred == NULL) {
- SAFE_FREE(tok_available[0]);
- SAFE_FREE(tok_available);
- return NULL;
- }
-
- for(i_pref=0; tok_preferred[i_pref] ; ++i_pref){
- for(i_avail=0; tok_available[i_avail]; ++i_avail){
- if(!strcmp(tok_available[i_avail],tok_preferred[i_pref])){
- /* match */
- ret=strdup(tok_available[i_avail]);
- /* free the tokens */
- SAFE_FREE(tok_available[0]);
- SAFE_FREE(tok_preferred[0]);
- SAFE_FREE(tok_available);
- SAFE_FREE(tok_preferred);
- return ret;
- }
- }
- }
- SAFE_FREE(tok_available[0]);
- SAFE_FREE(tok_preferred[0]);
- SAFE_FREE(tok_available);
- SAFE_FREE(tok_preferred);
- return NULL;
-}
-
-SSH_PACKET_CALLBACK(ssh_packet_kexinit){
- int server_kex=session->server;
- ssh_string str = NULL;
- char *strings[10];
- int i;
-
- enter_function();
- (void)type;
- (void)user;
- if(session->session_state != SSH_SESSION_STATE_INITIAL_KEX){
- ssh_set_error(session,SSH_FATAL,"SSH_KEXINIT received in wrong state");
- goto error;
- }
- if (server_kex) {
- if (buffer_get_data(packet,session->client_kex.cookie,16) != 16) {
- ssh_set_error(session, SSH_FATAL, "ssh_packet_kexinit: no cookie in packet");
- goto error;
- }
-
- if (hashbufin_add_cookie(session, session->client_kex.cookie) < 0) {
- ssh_set_error(session, SSH_FATAL, "ssh_packet_kexinit: adding cookie failed");
- goto error;
- }
- } else {
- if (buffer_get_data(packet,session->server_kex.cookie,16) != 16) {
- ssh_set_error(session, SSH_FATAL, "ssh_packet_kexinit: no cookie in packet");
- goto error;
- }
-
- if (hashbufin_add_cookie(session, session->server_kex.cookie) < 0) {
- ssh_set_error(session, SSH_FATAL, "ssh_packet_kexinit: adding cookie failed");
- goto error;
- }
- }
-
- memset(strings, 0, sizeof(char *) * 10);
-
- for (i = 0; i < 10; i++) {
- str = buffer_get_ssh_string(packet);
- if (str == NULL) {
- break;
- }
-
- if (buffer_add_ssh_string(session->in_hashbuf, str) < 0) {
- goto error;
- }
-
- strings[i] = ssh_string_to_char(str);
- if (strings[i] == NULL) {
- goto error;
- }
- ssh_string_free(str);
- str = NULL;
- }
-
- /* copy the server kex info into an array of strings */
- if (server_kex) {
- session->client_kex.methods = malloc(10 * sizeof(char **));
- if (session->client_kex.methods == NULL) {
- leave_function();
- return -1;
- }
-
- for (i = 0; i < 10; i++) {
- session->client_kex.methods[i] = strings[i];
- }
- } else { /* client */
- session->server_kex.methods = malloc(10 * sizeof(char **));
- if (session->server_kex.methods == NULL) {
- leave_function();
- return -1;
- }
-
- for (i = 0; i < 10; i++) {
- session->server_kex.methods[i] = strings[i];
- }
- }
-
- leave_function();
- session->session_state=SSH_SESSION_STATE_KEXINIT_RECEIVED;
- session->ssh_connection_callback(session);
- return SSH_PACKET_USED;
-error:
- ssh_string_free(str);
- for (i = 0; i < 10; i++) {
- SAFE_FREE(strings[i]);
- }
-
- session->session_state = SSH_SESSION_STATE_ERROR;
- leave_function();
- return SSH_PACKET_USED;
-}
-
-void ssh_list_kex(ssh_session session, KEX *kex) {
- int i = 0;
-
-#ifdef DEBUG_CRYPTO
- ssh_print_hexa("session cookie", kex->cookie, 16);
-#endif
- if(kex->methods==NULL){
- ssh_log(session, SSH_LOG_RARE,"kex->methods is NULL");
- return;
- }
- for(i = 0; i < 10; i++) {
- ssh_log(session, SSH_LOG_FUNCTIONS, "%s: %s",
- ssh_kex_nums[i], kex->methods[i]);
- }
-}
-
-/* set_kex basicaly look at the option structure of the session and set the output kex message */
-/* it must be aware of the server kex message */
-/* it can fail if option is null, not any user specified kex method matches the server one, if not any default kex matches */
-
-int set_kex(ssh_session session){
- KEX *server = &session->server_kex;
- KEX *client=&session->client_kex;
- int i;
- const char *wanted;
- enter_function();
- ssh_get_random(client->cookie,16,0);
- client->methods=malloc(10 * sizeof(char **));
- if (client->methods == NULL) {
- ssh_set_error(session, SSH_FATAL, "No space left");
- leave_function();
- return -1;
- }
- memset(client->methods,0,10*sizeof(char **));
- for (i=0;i<10;i++){
- if(!(wanted=session->wanted_methods[i]))
- wanted=default_methods[i];
- client->methods[i]=ssh_find_matching(server->methods[i],wanted);
- if(!client->methods[i] && i < SSH_LANG_C_S){
- ssh_set_error(session,SSH_FATAL,"kex error : did not find one of algos %s in list %s for %s",
- wanted,server->methods[i],ssh_kex_nums[i]);
- leave_function();
- return -1;
- } else {
- if ((i >= SSH_LANG_C_S) && (client->methods[i] == NULL)) {
- /* we can safely do that for languages */
- client->methods[i] = strdup("");
- if (client->methods[i] == NULL) {
- return -1;
- }
- }
- }
- }
- leave_function();
- return 0;
-}
-
-/* this function only sends the predefined set of kex methods */
-int ssh_send_kex(ssh_session session, int server_kex) {
- KEX *kex = (server_kex ? &session->server_kex : &session->client_kex);
- ssh_string str = NULL;
- int i;
-
- enter_function();
-
- if (buffer_add_u8(session->out_buffer, SSH2_MSG_KEXINIT) < 0) {
- goto error;
- }
- if (buffer_add_data(session->out_buffer, kex->cookie, 16) < 0) {
- goto error;
- }
-
- if (hashbufout_add_cookie(session) < 0) {
- goto error;
- }
-
- ssh_list_kex(session, kex);
-
- for (i = 0; i < 10; i++) {
- str = ssh_string_from_char(kex->methods[i]);
- if (str == NULL) {
- goto error;
- }
-
- if (buffer_add_ssh_string(session->out_hashbuf, str) < 0) {
- goto error;
- }
- if (buffer_add_ssh_string(session->out_buffer, str) < 0) {
- goto error;
- }
- ssh_string_free(str);
- }
-
- if (buffer_add_u8(session->out_buffer, 0) < 0) {
- goto error;
- }
- if (buffer_add_u32(session->out_buffer, 0) < 0) {
- goto error;
- }
-
- if (packet_send(session) == SSH_ERROR) {
- leave_function();
- return -1;
- }
-
- leave_function();
- return 0;
-error:
- buffer_reinit(session->out_buffer);
- buffer_reinit(session->out_hashbuf);
- ssh_string_free(str);
-
- leave_function();
- return -1;
-}
-
-/* returns 1 if at least one of the name algos is in the default algorithms table */
-int verify_existing_algo(int algo, const char *name){
- char *ptr;
- if(algo>9 || algo <0)
- return -1;
- ptr=ssh_find_matching(supported_methods[algo],name);
- if(ptr){
- free(ptr);
- return 1;
- }
- return 0;
-}
-
-#ifdef WITH_SSH1
-
-/* makes a STRING contating 3 strings : ssh-rsa1,e and n */
-/* this is a public key in openssh's format */
-static ssh_string make_rsa1_string(ssh_string e, ssh_string n){
- ssh_buffer buffer = NULL;
- ssh_string rsa = NULL;
- ssh_string ret = NULL;
-
- buffer = ssh_buffer_new();
- rsa = ssh_string_from_char("ssh-rsa1");
-
- if (buffer_add_ssh_string(buffer, rsa) < 0) {
- goto error;
- }
- if (buffer_add_ssh_string(buffer, e) < 0) {
- goto error;
- }
- if (buffer_add_ssh_string(buffer, n) < 0) {
- goto error;
- }
-
- ret = ssh_string_new(ssh_buffer_get_len(buffer));
- if (ret == NULL) {
- goto error;
- }
-
- ssh_string_fill(ret, ssh_buffer_get_begin(buffer), ssh_buffer_get_len(buffer));
-error:
- ssh_buffer_free(buffer);
- ssh_string_free(rsa);
-
- return ret;
-}
-
-static int build_session_id1(ssh_session session, ssh_string servern,
- ssh_string hostn) {
- MD5CTX md5 = NULL;
-
- md5 = md5_init();
- if (md5 == NULL) {
- return -1;
- }
-
-#ifdef DEBUG_CRYPTO
- ssh_print_hexa("host modulus",ssh_string_data(hostn),ssh_string_len(hostn));
- ssh_print_hexa("server modulus",ssh_string_data(servern),ssh_string_len(servern));
-#endif
- md5_update(md5,ssh_string_data(hostn),ssh_string_len(hostn));
- md5_update(md5,ssh_string_data(servern),ssh_string_len(servern));
- md5_update(md5,session->server_kex.cookie,8);
- md5_final(session->next_crypto->session_id,md5);
-#ifdef DEBUG_CRYPTO
- ssh_print_hexa("session_id",session->next_crypto->session_id,MD5_DIGEST_LEN);
-#endif
-
- return 0;
-}
-
-/* returns 1 if the modulus of k1 is < than the one of k2 */
-static int modulus_smaller(ssh_public_key k1, ssh_public_key k2){
- bignum n1;
- bignum n2;
- int res;
-#ifdef HAVE_LIBGCRYPT
- gcry_sexp_t sexp;
- sexp=gcry_sexp_find_token(k1->rsa_pub,"n",0);
- n1=gcry_sexp_nth_mpi(sexp,1,GCRYMPI_FMT_USG);
- gcry_sexp_release(sexp);
- sexp=gcry_sexp_find_token(k2->rsa_pub,"n",0);
- n2=gcry_sexp_nth_mpi(sexp,1,GCRYMPI_FMT_USG);
- gcry_sexp_release(sexp);
-#elif defined HAVE_LIBCRYPTO
- n1=k1->rsa_pub->n;
- n2=k2->rsa_pub->n;
-#endif
- if(bignum_cmp(n1,n2)<0)
- res=1;
- else
- res=0;
-#ifdef HAVE_LIBGCRYPT
- bignum_free(n1);
- bignum_free(n2);
-#endif
- return res;
-
-}
-
-#define ABS(A) ( (A)<0 ? -(A):(A) )
-static ssh_string encrypt_session_key(ssh_session session, ssh_public_key srvkey,
- ssh_public_key hostkey, int slen, int hlen) {
- unsigned char buffer[32] = {0};
- int i;
- ssh_string data1 = NULL;
- ssh_string data2 = NULL;
-
- /* first, generate a session key */
- ssh_get_random(session->next_crypto->encryptkey, 32, 1);
- memcpy(buffer, session->next_crypto->encryptkey, 32);
- memcpy(session->next_crypto->decryptkey, session->next_crypto->encryptkey, 32);
-
-#ifdef DEBUG_CRYPTO
- ssh_print_hexa("session key",buffer,32);
-#endif
-
- /* xor session key with session_id */
- for (i = 0; i < 16; i++) {
- buffer[i] ^= session->next_crypto->session_id[i];
- }
- data1 = ssh_string_new(32);
- if (data1 == NULL) {
- return NULL;
- }
- ssh_string_fill(data1, buffer, 32);
- if (ABS(hlen - slen) < 128){
- ssh_log(session, SSH_LOG_FUNCTIONS,
- "Difference between server modulus and host modulus is only %d. "
- "It's illegal and may not work",
- ABS(hlen - slen));
- }
-
- if (modulus_smaller(srvkey, hostkey)) {
- data2 = ssh_encrypt_rsa1(session, data1, srvkey);
- ssh_string_free(data1);
- data1 = NULL;
- if (data2 == NULL) {
- return NULL;
- }
- data1 = ssh_encrypt_rsa1(session, data2, hostkey);
- ssh_string_free(data2);
- if (data1 == NULL) {
- return NULL;
- }
- } else {
- data2 = ssh_encrypt_rsa1(session, data1, hostkey);
- ssh_string_free(data1);
- data1 = NULL;
- if (data2 == NULL) {
- return NULL;
- }
- data1 = ssh_encrypt_rsa1(session, data2, srvkey);
- ssh_string_free(data2);
- if (data1 == NULL) {
- return NULL;
- }
- }
-
- return data1;
-}
-
-/* SSH-1 functions */
-/* 2 SSH_SMSG_PUBLIC_KEY
- *
- * 8 bytes anti_spoofing_cookie
- * 32-bit int server_key_bits
- * mp-int server_key_public_exponent
- * mp-int server_key_public_modulus
- * 32-bit int host_key_bits
- * mp-int host_key_public_exponent
- * mp-int host_key_public_modulus
- * 32-bit int protocol_flags
- * 32-bit int supported_ciphers_mask
- * 32-bit int supported_authentications_mask
- */
-/**
- * @brief Wait for a SSH_SMSG_PUBLIC_KEY and does the key exchange
- */
-SSH_PACKET_CALLBACK(ssh_packet_publickey1){
- ssh_string server_exp = NULL;
- ssh_string server_mod = NULL;
- ssh_string host_exp = NULL;
- ssh_string host_mod = NULL;
- ssh_string serverkey = NULL;
- ssh_string hostkey = NULL;
- ssh_public_key srv = NULL;
- ssh_public_key host = NULL;
- uint32_t server_bits;
- uint32_t host_bits;
- uint32_t protocol_flags;
- uint32_t supported_ciphers_mask;
- uint32_t supported_authentications_mask;
- ssh_string enc_session = NULL;
- uint16_t bits;
- int ko;
- enter_function();
- (void)type;
- (void)user;
- ssh_log(session, SSH_LOG_PROTOCOL, "Got a SSH_SMSG_PUBLIC_KEY");
- if(session->session_state != SSH_SESSION_STATE_INITIAL_KEX){
- ssh_set_error(session,SSH_FATAL,"SSH_KEXINIT received in wrong state");
- goto error;
- }
- if (buffer_get_data(packet, session->server_kex.cookie, 8) != 8) {
- ssh_set_error(session, SSH_FATAL, "Can't get cookie in buffer");
- goto error;
- }
-
- buffer_get_u32(packet, &server_bits);
- server_exp = buffer_get_mpint(packet);
- if (server_exp == NULL) {
- goto error;
- }
- server_mod = buffer_get_mpint(packet);
- if (server_mod == NULL) {
- goto error;
- }
- buffer_get_u32(packet, &host_bits);
- host_exp = buffer_get_mpint(packet);
- if (host_exp == NULL) {
- goto error;
- }
- host_mod = buffer_get_mpint(packet);
- if (host_mod == NULL) {
- goto error;
- }
- buffer_get_u32(packet, &protocol_flags);
- buffer_get_u32(packet, &supported_ciphers_mask);
- ko = buffer_get_u32(packet, &supported_authentications_mask);
-
- if ((ko != sizeof(uint32_t)) || !host_mod || !host_exp
- || !server_mod || !server_exp) {
- ssh_log(session, SSH_LOG_RARE, "Invalid SSH_SMSG_PUBLIC_KEY packet");
- ssh_set_error(session, SSH_FATAL, "Invalid SSH_SMSG_PUBLIC_KEY packet");
- goto error;
- }
-
- server_bits = ntohl(server_bits);
- host_bits = ntohl(host_bits);
- protocol_flags = ntohl(protocol_flags);
- supported_ciphers_mask = ntohl(supported_ciphers_mask);
- supported_authentications_mask = ntohl(supported_authentications_mask);
- ssh_log(session, SSH_LOG_PROTOCOL,
- "Server bits: %d; Host bits: %d; Protocol flags: %.8lx; "
- "Cipher mask: %.8lx; Auth mask: %.8lx",
- server_bits,
- host_bits,
- (unsigned long int) protocol_flags,
- (unsigned long int) supported_ciphers_mask,
- (unsigned long int) supported_authentications_mask);
-
- serverkey = make_rsa1_string(server_exp, server_mod);
- if (serverkey == NULL) {
- goto error;
- }
- hostkey = make_rsa1_string(host_exp,host_mod);
- if (serverkey == NULL) {
- goto error;
- }
- if (build_session_id1(session, server_mod, host_mod) < 0) {
- goto error;
- }
-
- srv = publickey_from_string(session, serverkey);
- if (srv == NULL) {
- goto error;
- }
- host = publickey_from_string(session, hostkey);
- if (host == NULL) {
- goto error;
- }
-
- session->next_crypto->server_pubkey = ssh_string_copy(hostkey);
- if (session->next_crypto->server_pubkey == NULL) {
- goto error;
- }
- session->next_crypto->server_pubkey_type = "ssh-rsa1";
-
- /* now, we must choose an encryption algo */
- /* hardcode 3des */
- if (!(supported_ciphers_mask & (1 << SSH_CIPHER_3DES))) {
- ssh_set_error(session, SSH_FATAL, "Remote server doesn't accept 3DES");
- goto error;
- }
- ssh_log(session, SSH_LOG_PROTOCOL, "Sending SSH_CMSG_SESSION_KEY");
-
- if (buffer_add_u8(session->out_buffer, SSH_CMSG_SESSION_KEY) < 0) {
- goto error;
- }
- if (buffer_add_u8(session->out_buffer, SSH_CIPHER_3DES) < 0) {
- goto error;
- }
- if (buffer_add_data(session->out_buffer, session->server_kex.cookie, 8) < 0) {
- goto error;
- }
-
- enc_session = encrypt_session_key(session, srv, host, server_bits, host_bits);
- if (enc_session == NULL) {
- goto error;
- }
-
- bits = ssh_string_len(enc_session) * 8 - 7;
- ssh_log(session, SSH_LOG_PROTOCOL, "%d bits, %zu bytes encrypted session",
- bits, ssh_string_len(enc_session));
- bits = htons(bits);
- /* the encrypted mpint */
- if (buffer_add_data(session->out_buffer, &bits, sizeof(uint16_t)) < 0) {
- goto error;
- }
- if (buffer_add_data(session->out_buffer, ssh_string_data(enc_session),
- ssh_string_len(enc_session)) < 0) {
- goto error;
- }
- /* the protocol flags */
- if (buffer_add_u32(session->out_buffer, 0) < 0) {
- goto error;
- }
- session->session_state=SSH_SESSION_STATE_KEXINIT_RECEIVED;
- if (packet_send(session) == SSH_ERROR) {
- goto error;
- }
-
- /* we can set encryption */
- if (crypt_set_algorithms(session)) {
- goto error;
- }
-
- session->current_crypto = session->next_crypto;
- session->next_crypto = NULL;
- goto end;
-error:
- session->session_state=SSH_SESSION_STATE_ERROR;
-end:
-
- ssh_string_free(host_mod);
- ssh_string_free(host_exp);
- ssh_string_free(server_mod);
- ssh_string_free(server_exp);
- ssh_string_free(serverkey);
- ssh_string_free(hostkey);
- ssh_string_free(enc_session);
-
- publickey_free(srv);
- publickey_free(host);
-
- leave_function();
- return SSH_PACKET_USED;
-}
-
-int ssh_get_kex1(ssh_session session) {
- int ret=SSH_ERROR;
- enter_function();
- ssh_log(session, SSH_LOG_PROTOCOL, "Waiting for a SSH_SMSG_PUBLIC_KEY");
- /* Here the callback is called */
- while(session->session_state==SSH_SESSION_STATE_INITIAL_KEX){
- ssh_handle_packets(session,-1);
- }
- if(session->session_state==SSH_SESSION_STATE_ERROR)
- goto error;
- ssh_log(session, SSH_LOG_PROTOCOL, "Waiting for a SSH_SMSG_SUCCESS");
- /* Waiting for SSH_SMSG_SUCCESS */
- while(session->session_state==SSH_SESSION_STATE_KEXINIT_RECEIVED){
- ssh_handle_packets(session,-1);
- }
- if(session->session_state==SSH_SESSION_STATE_ERROR)
- goto error;
- ssh_log(session, SSH_LOG_PROTOCOL, "received SSH_SMSG_SUCCESS\n");
- ret=SSH_OK;
-error:
- leave_function();
- return ret;
-}
-
-#endif /* WITH_SSH1 */
-/* vim: set ts=2 sw=2 et cindent: */
diff --git a/libssh/keyfiles.c b/libssh/keyfiles.c
deleted file mode 100644
index 9512de0a..00000000
--- a/libssh/keyfiles.c
+++ /dev/null
@@ -1,1902 +0,0 @@
-/*
- * keyfiles.c - private and public key handling for authentication.
- *
- * This file is part of the SSH Library
- *
- * Copyright (c) 2003-2009 by Aris Adamantiadis
- * Copyright (c) 2009 by Andreas Schneider <mail@cynapses.org>
- *
- * 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 <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-#ifndef _WIN32
-#if _MSC_VER >= 1400
-#include <io.h>
-#undef open
-#define open _open
-#undef close
-#define close _close
-#undef read
-#define read _read
-#endif /* _MSC_VER */
-#include <arpa/inet.h>
-#endif
-
-#include "libssh/priv.h"
-#include "libssh/buffer.h"
-#include "libssh/keyfiles.h"
-#include "libssh/session.h"
-#include "libssh/wrapper.h"
-#include "libssh/misc.h"
-#include "libssh/keys.h"
-
-/*todo: remove this include */
-#include "libssh/string.h"
-
-
-#ifdef HAVE_LIBGCRYPT
-#include <gcrypt.h>
-#elif defined HAVE_LIBCRYPTO
-#include <openssl/pem.h>
-#include <openssl/dsa.h>
-#include <openssl/err.h>
-#include <openssl/rsa.h>
-#endif /* HAVE_LIBCRYPTO */
-
-#define MAXLINESIZE 80
-#define RSA_HEADER_BEGIN "-----BEGIN RSA PRIVATE KEY-----"
-#define RSA_HEADER_END "-----END RSA PRIVATE KEY-----"
-#define DSA_HEADER_BEGIN "-----BEGIN DSA PRIVATE KEY-----"
-#define DSA_HEADER_END "-----END DSA PRIVATE KEY-----"
-
-#ifdef HAVE_LIBGCRYPT
-
-#define MAX_KEY_SIZE 32
-#define MAX_PASSPHRASE_SIZE 1024
-#define ASN1_INTEGER 2
-#define ASN1_SEQUENCE 48
-#define PKCS5_SALT_LEN 8
-
-static int load_iv(char *header, unsigned char *iv, int iv_len) {
- int i;
- int j;
- int k;
-
- memset(iv, 0, iv_len);
- for (i = 0; i < iv_len; i++) {
- if ((header[2*i] >= '0') && (header[2*i] <= '9'))
- j = header[2*i] - '0';
- else if ((header[2*i] >= 'A') && (header[2*i] <= 'F'))
- j = header[2*i] - 'A' + 10;
- else if ((header[2*i] >= 'a') && (header[2*i] <= 'f'))
- j = header[2*i] - 'a' + 10;
- else
- return -1;
- if ((header[2*i+1] >= '0') && (header[2*i+1] <= '9'))
- k = header[2*i+1] - '0';
- else if ((header[2*i+1] >= 'A') && (header[2*i+1] <= 'F'))
- k = header[2*i+1] - 'A' + 10;
- else if ((header[2*i+1] >= 'a') && (header[2*i+1] <= 'f'))
- k = header[2*i+1] - 'a' + 10;
- else
- return -1;
- iv[i] = (j << 4) + k;
- }
- return 0;
-}
-
-static uint32_t char_to_u32(unsigned char *data, uint32_t size) {
- uint32_t ret;
- uint32_t i;
-
- for (i = 0, ret = 0; i < size; ret = ret << 8, ret += data[i++])
- ;
- return ret;
-}
-
-static uint32_t asn1_get_len(ssh_buffer buffer) {
- uint32_t len;
- unsigned char tmp[4];
-
- if (buffer_get_data(buffer,tmp,1) == 0) {
- return 0;
- }
-
- if (tmp[0] > 127) {
- len = tmp[0] & 127;
- if (len > 4) {
- return 0; /* Length doesn't fit in u32. Can this really happen? */
- }
- if (buffer_get_data(buffer,tmp,len) == 0) {
- return 0;
- }
- len = char_to_u32(tmp, len);
- } else {
- len = char_to_u32(tmp, 1);
- }
-
- return len;
-}
-
-static ssh_string asn1_get_int(ssh_buffer buffer) {
- ssh_string str;
- unsigned char type;
- uint32_t size;
-
- if (buffer_get_data(buffer, &type, 1) == 0 || type != ASN1_INTEGER) {
- return NULL;
- }
- size = asn1_get_len(buffer);
- if (size == 0) {
- return NULL;
- }
-
- str = ssh_string_new(size);
- if (str == NULL) {
- return NULL;
- }
-
- if (buffer_get_data(buffer, str->string, size) == 0) {
- ssh_string_free(str);
- return NULL;
- }
-
- return str;
-}
-
-static int asn1_check_sequence(ssh_buffer buffer) {
- unsigned char *j = NULL;
- unsigned char tmp;
- int i;
- uint32_t size;
- uint32_t padding;
-
- if (buffer_get_data(buffer, &tmp, 1) == 0 || tmp != ASN1_SEQUENCE) {
- return 0;
- }
-
- size = asn1_get_len(buffer);
- if ((padding = ssh_buffer_get_len(buffer) - buffer->pos - size) > 0) {
- for (i = ssh_buffer_get_len(buffer) - buffer->pos - size,
- j = (unsigned char*)ssh_buffer_get_begin(buffer) + size + buffer->pos;
- i;
- i--, j++)
- {
- if (*j != padding) { /* padding is allowed */
- return 0; /* but nothing else */
- }
- }
- }
-
- return 1;
-}
-
-static int read_line(char *data, unsigned int len, FILE *fp) {
- char tmp;
- unsigned int i;
-
- for (i = 0; fread(&tmp, 1, 1, fp) && tmp != '\n' && i < len; data[i++] = tmp)
- ;
- if (tmp == '\n') {
- return i;
- }
-
- if (i >= len) {
- return -1;
- }
-
- return 0;
-}
-
-static int passphrase_to_key(char *data, unsigned int datalen,
- unsigned char *salt, unsigned char *key, unsigned int keylen) {
- MD5CTX md;
- unsigned char digest[MD5_DIGEST_LEN] = {0};
- unsigned int i;
- unsigned int j;
- unsigned int md_not_empty;
-
- for (j = 0, md_not_empty = 0; j < keylen; ) {
- md = md5_init();
- if (md == NULL) {
- return -1;
- }
-
- if (md_not_empty) {
- md5_update(md, digest, MD5_DIGEST_LEN);
- } else {
- md_not_empty = 1;
- }
-
- md5_update(md, data, datalen);
- if (salt) {
- md5_update(md, salt, PKCS5_SALT_LEN);
- }
- md5_final(digest, md);
-
- for (i = 0; j < keylen && i < MD5_DIGEST_LEN; j++, i++) {
- if (key) {
- key[j] = digest[i];
- }
- }
- }
-
- return 0;
-}
-
-static int privatekey_decrypt(int algo, int mode, unsigned int key_len,
- unsigned char *iv, unsigned int iv_len,
- ssh_buffer data, ssh_auth_callback cb,
- void *userdata,
- const char *desc)
-{
- char passphrase[MAX_PASSPHRASE_SIZE] = {0};
- unsigned char key[MAX_KEY_SIZE] = {0};
- unsigned char *tmp = NULL;
- gcry_cipher_hd_t cipher;
- int rc = -1;
-
- if (!algo) {
- return -1;
- }
-
- if (cb) {
- rc = (*cb)(desc, passphrase, MAX_PASSPHRASE_SIZE, 0, 0, userdata);
- if (rc < 0) {
- return -1;
- }
- } else if (cb == NULL && userdata != NULL) {
- snprintf(passphrase, MAX_PASSPHRASE_SIZE, "%s", (char *) userdata);
- }
-
- if (passphrase_to_key(passphrase, strlen(passphrase), iv, key, key_len) < 0) {
- return -1;
- }
-
- if (gcry_cipher_open(&cipher, algo, mode, 0)
- || gcry_cipher_setkey(cipher, key, key_len)
- || gcry_cipher_setiv(cipher, iv, iv_len)
- || (tmp = malloc(ssh_buffer_get_len(data) * sizeof (char))) == NULL
- || gcry_cipher_decrypt(cipher, tmp, ssh_buffer_get_len(data),
- ssh_buffer_get_begin(data), ssh_buffer_get_len(data))) {
- gcry_cipher_close(cipher);
- return -1;
- }
-
- memcpy(ssh_buffer_get_begin(data), tmp, ssh_buffer_get_len(data));
-
- SAFE_FREE(tmp);
- gcry_cipher_close(cipher);
-
- return 0;
-}
-
-static int privatekey_dek_header(char *header, unsigned int header_len,
- int *algo, int *mode, unsigned int *key_len, unsigned char **iv,
- unsigned int *iv_len) {
- unsigned int iv_pos;
-
- if (header_len > 13 && !strncmp("DES-EDE3-CBC", header, 12))
- {
- *algo = GCRY_CIPHER_3DES;
- iv_pos = 13;
- *mode = GCRY_CIPHER_MODE_CBC;
- *key_len = 24;
- *iv_len = 8;
- }
- else if (header_len > 8 && !strncmp("DES-CBC", header, 7))
- {
- *algo = GCRY_CIPHER_DES;
- iv_pos = 8;
- *mode = GCRY_CIPHER_MODE_CBC;
- *key_len = 8;
- *iv_len = 8;
- }
- else if (header_len > 12 && !strncmp("AES-128-CBC", header, 11))
- {
- *algo = GCRY_CIPHER_AES128;
- iv_pos = 12;
- *mode = GCRY_CIPHER_MODE_CBC;
- *key_len = 16;
- *iv_len = 16;
- }
- else if (header_len > 12 && !strncmp("AES-192-CBC", header, 11))
- {
- *algo = GCRY_CIPHER_AES192;
- iv_pos = 12;
- *mode = GCRY_CIPHER_MODE_CBC;
- *key_len = 24;
- *iv_len = 16;
- }
- else if (header_len > 12 && !strncmp("AES-256-CBC", header, 11))
- {
- *algo = GCRY_CIPHER_AES256;
- iv_pos = 12;
- *mode = GCRY_CIPHER_MODE_CBC;
- *key_len = 32;
- *iv_len = 16;
- } else {
- return -1;
- }
-
- *iv = malloc(*iv_len);
- if (*iv == NULL) {
- return -1;
- }
-
- return load_iv(header + iv_pos, *iv, *iv_len);
-}
-
-static ssh_buffer privatekey_file_to_buffer(FILE *fp, int type,
- ssh_auth_callback cb, void *userdata, const char *desc) {
- ssh_buffer buffer = NULL;
- ssh_buffer out = NULL;
- char buf[MAXLINESIZE] = {0};
- unsigned char *iv = NULL;
- const char *header_begin;
- const char *header_end;
- unsigned int header_begin_size;
- unsigned int header_end_size;
- unsigned int key_len = 0;
- unsigned int iv_len = 0;
- int algo = 0;
- int mode = 0;
- int len;
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- return NULL;
- }
-
- switch(type) {
- case SSH_KEYTYPE_DSS:
- header_begin = DSA_HEADER_BEGIN;
- header_end = DSA_HEADER_END;
- break;
- case SSH_KEYTYPE_RSA:
- header_begin = RSA_HEADER_BEGIN;
- header_end = RSA_HEADER_END;
- break;
- default:
- ssh_buffer_free(buffer);
- return NULL;
- }
-
- header_begin_size = strlen(header_begin);
- header_end_size = strlen(header_end);
-
- while (read_line(buf, MAXLINESIZE, fp) &&
- strncmp(buf, header_begin, header_begin_size))
- ;
-
- len = read_line(buf, MAXLINESIZE, fp);
- if (len > 11 && strncmp("Proc-Type: 4,ENCRYPTED", buf, 11) == 0) {
- len = read_line(buf, MAXLINESIZE, fp);
- if (len > 10 && strncmp("DEK-Info: ", buf, 10) == 0) {
- if ((privatekey_dek_header(buf + 10, len - 10, &algo, &mode, &key_len,
- &iv, &iv_len) < 0)
- || read_line(buf, MAXLINESIZE, fp)) {
- ssh_buffer_free(buffer);
- SAFE_FREE(iv);
- return NULL;
- }
- } else {
- ssh_buffer_free(buffer);
- SAFE_FREE(iv);
- return NULL;
- }
- } else {
- if (buffer_add_data(buffer, buf, len) < 0) {
- ssh_buffer_free(buffer);
- SAFE_FREE(iv);
- return NULL;
- }
- }
-
- while ((len = read_line(buf,MAXLINESIZE,fp)) &&
- strncmp(buf, header_end, header_end_size) != 0) {
- if (len == -1) {
- ssh_buffer_free(buffer);
- SAFE_FREE(iv);
- return NULL;
- }
- if (buffer_add_data(buffer, buf, len) < 0) {
- ssh_buffer_free(buffer);
- SAFE_FREE(iv);
- return NULL;
- }
- }
-
- if (strncmp(buf,header_end,header_end_size) != 0) {
- ssh_buffer_free(buffer);
- SAFE_FREE(iv);
- return NULL;
- }
-
- if (buffer_add_data(buffer, "\0", 1) < 0) {
- ssh_buffer_free(buffer);
- SAFE_FREE(iv);
- return NULL;
- }
-
- out = base64_to_bin(ssh_buffer_get_begin(buffer));
- ssh_buffer_free(buffer);
- if (out == NULL) {
- SAFE_FREE(iv);
- return NULL;
- }
-
- if (algo) {
- if (privatekey_decrypt(algo, mode, key_len, iv, iv_len, out,
- cb, userdata, desc) < 0) {
- ssh_buffer_free(out);
- SAFE_FREE(iv);
- return NULL;
- }
- }
- SAFE_FREE(iv);
-
- return out;
-}
-
-static int read_rsa_privatekey(FILE *fp, gcry_sexp_t *r,
- ssh_auth_callback cb, void *userdata, const char *desc) {
- ssh_string n = NULL;
- ssh_string e = NULL;
- ssh_string d = NULL;
- ssh_string p = NULL;
- ssh_string q = NULL;
- ssh_string unused1 = NULL;
- ssh_string unused2 = NULL;
- ssh_string u = NULL;
- ssh_string v = NULL;
- ssh_buffer buffer = NULL;
- int rc = 1;
-
- buffer = privatekey_file_to_buffer(fp, SSH_KEYTYPE_RSA, cb, userdata, desc);
- if (buffer == NULL) {
- return 0;
- }
-
- if (!asn1_check_sequence(buffer)) {
- ssh_buffer_free(buffer);
- return 0;
- }
-
- v = asn1_get_int(buffer);
- if (ntohl(v->size) != 1 || v->string[0] != 0) {
- ssh_buffer_free(buffer);
- return 0;
- }
-
- n = asn1_get_int(buffer);
- e = asn1_get_int(buffer);
- d = asn1_get_int(buffer);
- q = asn1_get_int(buffer);
- p = asn1_get_int(buffer);
- unused1 = asn1_get_int(buffer);
- unused2 = asn1_get_int(buffer);
- u = asn1_get_int(buffer);
-
- ssh_buffer_free(buffer);
-
- if (n == NULL || e == NULL || d == NULL || p == NULL || q == NULL ||
- unused1 == NULL || unused2 == NULL|| u == NULL) {
- rc = 0;
- goto error;
- }
-
- if (gcry_sexp_build(r, NULL,
- "(private-key(rsa(n %b)(e %b)(d %b)(p %b)(q %b)(u %b)))",
- ntohl(n->size), n->string,
- ntohl(e->size), e->string,
- ntohl(d->size), d->string,
- ntohl(p->size), p->string,
- ntohl(q->size), q->string,
- ntohl(u->size), u->string)) {
- rc = 0;
- }
-
-error:
- ssh_string_free(n);
- ssh_string_free(e);
- ssh_string_free(d);
- ssh_string_free(p);
- ssh_string_free(q);
- ssh_string_free(unused1);
- ssh_string_free(unused2);
- ssh_string_free(u);
- ssh_string_free(v);
-
- return rc;
-}
-
-static int read_dsa_privatekey(FILE *fp, gcry_sexp_t *r, ssh_auth_callback cb,
- void *userdata, const char *desc) {
- ssh_buffer buffer = NULL;
- ssh_string p = NULL;
- ssh_string q = NULL;
- ssh_string g = NULL;
- ssh_string y = NULL;
- ssh_string x = NULL;
- ssh_string v = NULL;
- int rc = 1;
-
- buffer = privatekey_file_to_buffer(fp, SSH_KEYTYPE_DSS, cb, userdata, desc);
- if (buffer == NULL) {
- return 0;
- }
-
- if (!asn1_check_sequence(buffer)) {
- ssh_buffer_free(buffer);
- return 0;
- }
-
- v = asn1_get_int(buffer);
- if (ntohl(v->size) != 1 || v->string[0] != 0) {
- ssh_buffer_free(buffer);
- return 0;
- }
-
- p = asn1_get_int(buffer);
- q = asn1_get_int(buffer);
- g = asn1_get_int(buffer);
- y = asn1_get_int(buffer);
- x = asn1_get_int(buffer);
- ssh_buffer_free(buffer);
-
- if (p == NULL || q == NULL || g == NULL || y == NULL || x == NULL) {
- rc = 0;
- goto error;
- }
-
- if (gcry_sexp_build(r, NULL,
- "(private-key(dsa(p %b)(q %b)(g %b)(y %b)(x %b)))",
- ntohl(p->size), p->string,
- ntohl(q->size), q->string,
- ntohl(g->size), g->string,
- ntohl(y->size), y->string,
- ntohl(x->size), x->string)) {
- rc = 0;
- }
-
-error:
- ssh_string_free(p);
- ssh_string_free(q);
- ssh_string_free(g);
- ssh_string_free(y);
- ssh_string_free(x);
- ssh_string_free(v);
-
- return rc;
-}
-#endif /* HAVE_LIBGCRYPT */
-
-#ifdef HAVE_LIBCRYPTO
-static int pem_get_password(char *buf, int size, int rwflag, void *userdata) {
- ssh_session session = userdata;
-
- /* unused flag */
- (void) rwflag;
- if(buf==NULL)
- return 0;
- memset(buf,'\0',size);
- ssh_log(session, SSH_LOG_RARE,
- "Trying to call external authentication function");
-
- if (session && session->callbacks && session->callbacks->auth_function) {
- if (session->callbacks->auth_function("Passphrase for private key:", buf, size, 0, 0,
- session->callbacks->userdata) < 0) {
- return 0;
- }
-
- return strlen(buf);
- }
-
- return 0;
-}
-#endif /* HAVE_LIBCRYPTO */
-
-static int privatekey_type_from_file(FILE *fp) {
- char buffer[MAXLINESIZE] = {0};
-
- if (!fgets(buffer, MAXLINESIZE, fp)) {
- return 0;
- }
- fseek(fp, 0, SEEK_SET);
- if (strncmp(buffer, DSA_HEADER_BEGIN, strlen(DSA_HEADER_BEGIN)) == 0) {
- return SSH_KEYTYPE_DSS;
- }
- if (strncmp(buffer, RSA_HEADER_BEGIN, strlen(RSA_HEADER_BEGIN)) == 0) {
- return SSH_KEYTYPE_RSA;
- }
- return 0;
-}
-
-/**
- * @addtogroup libssh_auth
- *
- * @{
- */
-
-/**
- * @brief Reads a SSH private key from a file.
- *
- * @param[in] session The SSH Session to use.
- *
- * @param[in] filename The filename of the the private key.
- *
- * @param[in] type The type of the private key. This could be SSH_KEYTYPE_DSS or
- * SSH_KEYTYPE_RSA. Pass 0 to automatically detect the type.
- *
- * @param[in] passphrase The passphrase to decrypt the private key. Set to null
- * if none is needed or it is unknown.
- *
- * @return A private_key object containing the private key, or
- * NULL on error.
- * @see privatekey_free()
- * @see publickey_from_privatekey()
- */
-ssh_private_key privatekey_from_file(ssh_session session, const char *filename,
- int type, const char *passphrase) {
- ssh_private_key privkey = NULL;
- FILE *file = NULL;
-#ifdef HAVE_LIBGCRYPT
- ssh_auth_callback auth_cb = NULL;
- void *auth_ud = NULL;
-
- gcry_sexp_t dsa = NULL;
- gcry_sexp_t rsa = NULL;
- int valid;
-#elif defined HAVE_LIBCRYPTO
- DSA *dsa = NULL;
- RSA *rsa = NULL;
-#endif
- /* TODO Implement to read both DSA and RSA at once. */
-
- /* needed for openssl initialization */
- ssh_init();
- ssh_log(session, SSH_LOG_RARE, "Trying to open %s", filename);
- file = fopen(filename,"r");
- if (file == NULL) {
- ssh_set_error(session, SSH_REQUEST_DENIED,
- "Error opening %s: %s", filename, strerror(errno));
- return NULL;
- }
-
- ssh_log(session, SSH_LOG_RARE, "Trying to read %s, passphase=%s, authcb=%s",
- filename, passphrase ? "true" : "false",
- session->callbacks && session->callbacks->auth_function ? "true" : "false");
-
- if (type == 0) {
- type = privatekey_type_from_file(file);
- if (type == 0) {
- fclose(file);
- ssh_set_error(session, SSH_FATAL, "Invalid private key file.");
- return NULL;
- }
- }
- switch (type) {
- case SSH_KEYTYPE_DSS:
- if (passphrase == NULL) {
- if (session->callbacks && session->callbacks->auth_function) {
-#ifdef HAVE_LIBGCRYPT
- auth_cb = session->callbacks->auth_function;
- auth_ud = session->callbacks->userdata;
-
- valid = read_dsa_privatekey(file, &dsa, auth_cb, auth_ud,
- "Passphrase for private key:");
- } else { /* authcb */
- valid = read_dsa_privatekey(file, &dsa, NULL, NULL, NULL);
- } /* authcb */
- } else { /* passphrase */
- valid = read_dsa_privatekey(file, &dsa, NULL,
- (void *) passphrase, NULL);
- }
-
- fclose(file);
-
- if (!valid) {
- ssh_set_error(session, SSH_FATAL, "Parsing private key %s", filename);
-#elif defined HAVE_LIBCRYPTO
- dsa = PEM_read_DSAPrivateKey(file, NULL, pem_get_password, session);
- } else { /* authcb */
- /* openssl uses its own callback to get the passphrase here */
- dsa = PEM_read_DSAPrivateKey(file, NULL, NULL, NULL);
- } /* authcb */
- } else { /* passphrase */
- dsa = PEM_read_DSAPrivateKey(file, NULL, NULL, (void *) passphrase);
- }
-
- fclose(file);
- if (dsa == NULL) {
- ssh_set_error(session, SSH_FATAL,
- "Parsing private key %s: %s",
- filename, ERR_error_string(ERR_get_error(), NULL));
-#endif
- return NULL;
- }
- break;
- case SSH_KEYTYPE_RSA:
- if (passphrase == NULL) {
- if (session->callbacks && session->callbacks->auth_function) {
-#ifdef HAVE_LIBGCRYPT
- auth_cb = session->callbacks->auth_function;
- auth_ud = session->callbacks->userdata;
- valid = read_rsa_privatekey(file, &rsa, auth_cb, auth_ud,
- "Passphrase for private key:");
- } else { /* authcb */
- valid = read_rsa_privatekey(file, &rsa, NULL, NULL, NULL);
- } /* authcb */
- } else { /* passphrase */
- valid = read_rsa_privatekey(file, &rsa, NULL,
- (void *) passphrase, NULL);
- }
-
- fclose(file);
-
- if (!valid) {
- ssh_set_error(session,SSH_FATAL, "Parsing private key %s", filename);
-#elif defined HAVE_LIBCRYPTO
- rsa = PEM_read_RSAPrivateKey(file, NULL, pem_get_password, session);
- } else { /* authcb */
- /* openssl uses its own callback to get the passphrase here */
- rsa = PEM_read_RSAPrivateKey(file, NULL, NULL, NULL);
- } /* authcb */
- } else { /* passphrase */
- rsa = PEM_read_RSAPrivateKey(file, NULL, NULL, (void *) passphrase);
- }
-
- fclose(file);
-
- if (rsa == NULL) {
- ssh_set_error(session, SSH_FATAL,
- "Parsing private key %s: %s",
- filename, ERR_error_string(ERR_get_error(),NULL));
-#endif
- return NULL;
- }
- break;
- default:
- fclose(file);
- ssh_set_error(session, SSH_FATAL, "Invalid private key type %d", type);
- return NULL;
- } /* switch */
-
- privkey = malloc(sizeof(struct ssh_private_key_struct));
- if (privkey == NULL) {
-#ifdef HAVE_LIBGCRYPT
- gcry_sexp_release(dsa);
- gcry_sexp_release(rsa);
-#elif defined HAVE_LIBCRYPTO
- DSA_free(dsa);
- RSA_free(rsa);
-#endif
- return NULL;
- }
-
- privkey->type = type;
- privkey->dsa_priv = dsa;
- privkey->rsa_priv = rsa;
-
- return privkey;
-}
-
-/**
- * @brief returns the type of a private key
- * @param[in] privatekey the private key handle
- * @returns one of SSH_KEYTYPE_RSA,SSH_KEYTYPE_DSS,SSH_KEYTYPE_RSA1
- * @returns SSH_KEYTYPE_UNKNOWN if the type is unknown
- * @see privatekey_from_file
- * @see ssh_userauth_offer_pubkey
- */
-enum ssh_keytypes_e ssh_privatekey_type(ssh_private_key privatekey){
- if (privatekey==NULL)
- return SSH_KEYTYPE_UNKNOWN;
- return privatekey->type;
-}
-
-/* same that privatekey_from_file() but without any passphrase things. */
-ssh_private_key _privatekey_from_file(void *session, const char *filename,
- int type) {
- ssh_private_key privkey = NULL;
- FILE *file = NULL;
-#ifdef HAVE_LIBGCRYPT
- gcry_sexp_t dsa = NULL;
- gcry_sexp_t rsa = NULL;
- int valid;
-#elif defined HAVE_LIBCRYPTO
- DSA *dsa = NULL;
- RSA *rsa = NULL;
-#endif
-
- file = fopen(filename,"r");
- if (file == NULL) {
- ssh_set_error(session, SSH_REQUEST_DENIED,
- "Error opening %s: %s", filename, strerror(errno));
- return NULL;
- }
-
- switch (type) {
- case SSH_KEYTYPE_DSS:
-#ifdef HAVE_LIBGCRYPT
- valid = read_dsa_privatekey(file, &dsa, NULL, NULL, NULL);
-
- fclose(file);
-
- if (!valid) {
- ssh_set_error(session, SSH_FATAL, "Parsing private key %s", filename);
-#elif defined HAVE_LIBCRYPTO
- dsa = PEM_read_DSAPrivateKey(file, NULL, NULL, NULL);
-
- fclose(file);
-
- if (dsa == NULL) {
- ssh_set_error(session, SSH_FATAL,
- "Parsing private key %s: %s",
- filename, ERR_error_string(ERR_get_error(), NULL));
-#endif
- return NULL;
- }
- break;
- case SSH_KEYTYPE_RSA:
-#ifdef HAVE_LIBGCRYPT
- valid = read_rsa_privatekey(file, &rsa, NULL, NULL, NULL);
-
- fclose(file);
-
- if (!valid) {
- ssh_set_error(session, SSH_FATAL, "Parsing private key %s", filename);
-#elif defined HAVE_LIBCRYPTO
- rsa = PEM_read_RSAPrivateKey(file, NULL, NULL, NULL);
-
- fclose(file);
-
- if (rsa == NULL) {
- ssh_set_error(session, SSH_FATAL,
- "Parsing private key %s: %s",
- filename, ERR_error_string(ERR_get_error(), NULL));
-#endif
- return NULL;
- }
- break;
- default:
- ssh_set_error(session, SSH_FATAL, "Invalid private key type %d", type);
- return NULL;
- }
-
- privkey = malloc(sizeof(struct ssh_private_key_struct));
- if (privkey == NULL) {
-#ifdef HAVE_LIBGCRYPT
- gcry_sexp_release(dsa);
- gcry_sexp_release(rsa);
-#elif defined HAVE_LIBCRYPTO
- DSA_free(dsa);
- RSA_free(rsa);
-#endif
- return NULL;
- }
-
- privkey->type = type;
- privkey->dsa_priv = dsa;
- privkey->rsa_priv = rsa;
-
- return privkey;
-}
-
-/**
- * @brief Deallocate a private key object.
- *
- * @param[in] prv The private_key object to free.
- */
-void privatekey_free(ssh_private_key prv) {
- if (prv == NULL) {
- return;
- }
-
-#ifdef HAVE_LIBGCRYPT
- gcry_sexp_release(prv->dsa_priv);
- gcry_sexp_release(prv->rsa_priv);
-#elif defined HAVE_LIBCRYPTO
- DSA_free(prv->dsa_priv);
- RSA_free(prv->rsa_priv);
-#endif
- memset(prv, 0, sizeof(struct ssh_private_key_struct));
- SAFE_FREE(prv);
-}
-
-/**
- * @brief Write a public key to a file.
- *
- * @param[in] session The ssh session to use.
- *
- * @param[in] file The filename to write the key into.
- *
- * @param[in] pubkey The public key to write.
- *
- * @param[in] type The type of the public key.
- *
- * @return 0 on success, -1 on error.
- */
-int ssh_publickey_to_file(ssh_session session, const char *file,
- ssh_string pubkey, int type) {
- FILE *fp;
- char *user;
- char buffer[1024];
- char host[256];
- unsigned char *pubkey_64;
- size_t len;
- int rc;
-
- pubkey_64 = bin_to_base64(pubkey->string, ssh_string_len(pubkey));
- if (pubkey_64 == NULL) {
- return -1;
- }
-
- user = ssh_get_local_username(session);
- if (user == NULL) {
- SAFE_FREE(pubkey_64);
- return -1;
- }
-
- rc = gethostname(host, sizeof(host));
- if (rc < 0) {
- SAFE_FREE(user);
- SAFE_FREE(pubkey_64);
- return -1;
- }
-
- snprintf(buffer, sizeof(buffer), "%s %s %s@%s\n",
- ssh_type_to_char(type),
- pubkey_64,
- user,
- host);
-
- SAFE_FREE(pubkey_64);
- SAFE_FREE(user);
-
- ssh_log(session, SSH_LOG_RARE, "Trying to write public key file: %s", file);
- ssh_log(session, SSH_LOG_PACKET, "public key file content: %s", buffer);
-
- fp = fopen(file, "w+");
- if (fp == NULL) {
- ssh_set_error(session, SSH_REQUEST_DENIED,
- "Error opening %s: %s", file, strerror(errno));
- return -1;
- }
-
- len = strlen(buffer);
- if (fwrite(buffer, len, 1, fp) != 1 || ferror(fp)) {
- ssh_set_error(session, SSH_REQUEST_DENIED,
- "Unable to write to %s", file);
- fclose(fp);
- unlink(file);
- return -1;
- }
-
- fclose(fp);
- return 0;
-}
-
-/**
- * @brief Retrieve a public key from a file.
- *
- * @param[in] session The SSH session to use.
- *
- * @param[in] filename The filename of the public key.
- *
- * @param[out] type The Pointer to a integer. If it is not NULL, it will
- * contain the type of the key after execution.
- *
- * @return A SSH String containing the public key, or NULL if it
- * failed.
- *
- * @see string_free()
- * @see publickey_from_privatekey()
- */
-ssh_string publickey_from_file(ssh_session session, const char *filename,
- int *type) {
- ssh_buffer buffer = NULL;
- char buf[4096] = {0};
- ssh_string str = NULL;
- char *ptr = NULL;
- int key_type;
- int fd = -1;
- int r;
-
- fd = open(filename, O_RDONLY);
- if (fd < 0) {
- ssh_set_error(session, SSH_REQUEST_DENIED, "Public key file doesn't exist");
- return NULL;
- }
-
- if (read(fd, buf, 8) != 8) {
- close(fd);
- ssh_set_error(session, SSH_REQUEST_DENIED, "Invalid public key file");
- return NULL;
- }
-
- buf[7] = '\0';
-
- key_type = ssh_type_from_name(buf);
- if (key_type == -1) {
- close(fd);
- ssh_set_error(session, SSH_REQUEST_DENIED, "Invalid public key file");
- return NULL;
- }
-
- r = read(fd, buf, sizeof(buf) - 1);
- close(fd);
- if (r <= 0) {
- ssh_set_error(session, SSH_REQUEST_DENIED, "Invalid public key file");
- return NULL;
- }
-
- buf[r] = 0;
- ptr = strchr(buf, ' ');
-
- /* eliminate the garbage at end of file */
- if (ptr) {
- *ptr = '\0';
- }
-
- buffer = base64_to_bin(buf);
- if (buffer == NULL) {
- ssh_set_error(session, SSH_REQUEST_DENIED, "Invalid public key file");
- return NULL;
- }
-
- str = ssh_string_new(ssh_buffer_get_len(buffer));
- if (str == NULL) {
- ssh_set_error(session, SSH_FATAL, "Not enough space");
- ssh_buffer_free(buffer);
- return NULL;
- }
-
- ssh_string_fill(str, ssh_buffer_get_begin(buffer), ssh_buffer_get_len(buffer));
- ssh_buffer_free(buffer);
-
- if (type) {
- *type = key_type;
- }
-
- return str;
-}
-
-/**
- * @brief Try to read the public key from a given file.
- *
- * @param[in] session The ssh session to use.
- *
- * @param[in] keyfile The name of the private keyfile.
- *
- * @param[out] publickey A ssh_string to store the public key.
- *
- * @param[out] type A pointer to an integer to store the type.
- *
- * @return 0 on success, -1 on error or the private key doesn't
- * exist, 1 if the public key doesn't exist.
- */
-int ssh_try_publickey_from_file(ssh_session session, const char *keyfile,
- ssh_string *publickey, int *type) {
- char *pubkey_file;
- size_t len;
- ssh_string pubkey_string;
- int pubkey_type;
-
- if (session == NULL || keyfile == NULL || publickey == NULL || type == NULL) {
- return -1;
- }
-
- if (session->sshdir == NULL) {
- if (ssh_options_apply(session) < 0) {
- return -1;
- }
- }
-
- ssh_log(session, SSH_LOG_PACKET, "Trying to open privatekey %s", keyfile);
- if (!ssh_file_readaccess_ok(keyfile)) {
- ssh_log(session, SSH_LOG_PACKET, "Failed to open privatekey %s", keyfile);
- return -1;
- }
-
- len = strlen(keyfile) + 5;
- pubkey_file = malloc(len);
- if (pubkey_file == NULL) {
- return -1;
- }
- snprintf(pubkey_file, len, "%s.pub", keyfile);
-
- ssh_log(session, SSH_LOG_PACKET, "Trying to open publickey %s",
- pubkey_file);
- if (!ssh_file_readaccess_ok(pubkey_file)) {
- ssh_log(session, SSH_LOG_PACKET, "Failed to open publickey %s",
- pubkey_file);
- SAFE_FREE(pubkey_file);
- return 1;
- }
-
- ssh_log(session, SSH_LOG_PACKET, "Success opening public and private key");
-
- /*
- * We are sure both the private and public key file is readable. We return
- * the public as a string, and the private filename as an argument
- */
- pubkey_string = publickey_from_file(session, pubkey_file, &pubkey_type);
- if (pubkey_string == NULL) {
- ssh_log(session, SSH_LOG_PACKET,
- "Wasn't able to open public key file %s: %s",
- pubkey_file,
- ssh_get_error(session));
- SAFE_FREE(pubkey_file);
- return -1;
- }
-
- SAFE_FREE(pubkey_file);
-
- *publickey = pubkey_string;
- *type = pubkey_type;
-
- return 0;
-}
-
-ssh_string try_publickey_from_file(ssh_session session, struct ssh_keys_struct keytab,
- char **privkeyfile, int *type) {
- const char *priv;
- const char *pub;
- char *new;
- ssh_string pubkey=NULL;
-
- pub = keytab.publickey;
- if (pub == NULL) {
- return NULL;
- }
- priv = keytab.privatekey;
- if (priv == NULL) {
- return NULL;
- }
-
- if (session->sshdir == NULL) {
- if (ssh_options_apply(session) < 0) {
- return NULL;
- }
- }
-
- ssh_log(session, SSH_LOG_PACKET, "Trying to open publickey %s", pub);
- if (!ssh_file_readaccess_ok(pub)) {
- ssh_log(session, SSH_LOG_PACKET, "Failed to open publickey %s", pub);
- goto error;
- }
-
- ssh_log(session, SSH_LOG_PACKET, "Trying to open privatekey %s", priv);
- if (!ssh_file_readaccess_ok(priv)) {
- ssh_log(session, SSH_LOG_PACKET, "Failed to open privatekey %s", priv);
- goto error;
- }
-
- ssh_log(session, SSH_LOG_PACKET, "Success opening public and private key");
-
- /*
- * We are sure both the private and public key file is readable. We return
- * the public as a string, and the private filename as an argument
- */
- pubkey = publickey_from_file(session, pub, type);
- if (pubkey == NULL) {
- ssh_log(session, SSH_LOG_PACKET,
- "Wasn't able to open public key file %s: %s",
- pub,
- ssh_get_error(session));
- goto error;
- }
-
- new = realloc(*privkeyfile, strlen(priv) + 1);
- if (new == NULL) {
- ssh_string_free(pubkey);
- goto error;
- }
-
- strcpy(new, priv);
- *privkeyfile = new;
-error:
- return pubkey;
-}
-
-static int alldigits(const char *s) {
- while (*s) {
- if (isdigit(*s)) {
- s++;
- } else {
- return 0;
- }
- }
-
- return 1;
-}
-
-/** @} */
-
-
-/**
- * @addtogroup libssh_session
- *
- * @{
- */
-
-/**
- * @internal
- *
- * @brief Free a token array.
- */
-static void tokens_free(char **tokens) {
- if (tokens == NULL) {
- return;
- }
-
- SAFE_FREE(tokens[0]);
- /* It's not needed to free other pointers because tokens generated by
- * space_tokenize fit all in one malloc
- */
- SAFE_FREE(tokens);
-}
-
-/**
- * @internal
- *
- * @brief Return one line of known host file.
- *
- * This will return a token array containing (host|ip), keytype and key.
- *
- * @param[out] file A pointer to the known host file. Could be pointing to
- * NULL at start.
- *
- * @param[in] filename The file name of the known host file.
- *
- * @param[out] found_type A pointer to a string to be set with the found key
- * type.
- *
- * @returns The found_type type of key (ie "dsa","ssh-rsa1"). Don't
- * free that value. NULL if no match was found or the file
- * was not found.
- */
-static char **ssh_get_knownhost_line(ssh_session session, FILE **file,
- const char *filename, const char **found_type) {
- char buffer[4096] = {0};
- char *ptr;
- char **tokens;
-
- enter_function();
-
- if(*file == NULL){
- *file = fopen(filename,"r");
- if (*file == NULL) {
- leave_function();
- return NULL;
- }
- }
-
- while (fgets(buffer, sizeof(buffer), *file)) {
- ptr = strchr(buffer, '\n');
- if (ptr) {
- *ptr = '\0';
- }
-
- ptr = strchr(buffer,'\r');
- if (ptr) {
- *ptr = '\0';
- }
-
- if (!buffer[0] || buffer[0] == '#') {
- continue; /* skip empty lines */
- }
-
- tokens = space_tokenize(buffer);
- if (tokens == NULL) {
- fclose(*file);
- *file = NULL;
- leave_function();
- return NULL;
- }
-
- if(!tokens[0] || !tokens[1] || !tokens[2]) {
- /* it should have at least 3 tokens */
- tokens_free(tokens);
- continue;
- }
-
- *found_type = tokens[1];
- if (tokens[3]) {
- /* openssh rsa1 format has 4 tokens on the line. Recognize it
- by the fact that everything is all digits */
- if (tokens[4]) {
- /* that's never valid */
- tokens_free(tokens);
- continue;
- }
- if (alldigits(tokens[1]) && alldigits(tokens[2]) && alldigits(tokens[3])) {
- *found_type = "ssh-rsa1";
- } else {
- /* 3 tokens only, not four */
- tokens_free(tokens);
- continue;
- }
- }
- leave_function();
- return tokens;
- }
-
- fclose(*file);
- *file = NULL;
-
- /* we did not find anything, end of file*/
- leave_function();
- return NULL;
-}
-
-/**
- * @brief Check the public key in the known host line matches the public key of
- * the currently connected server.
- *
- * @param[in] session The SSH session to use.
- *
- * @param[in] tokens A list of tokens in the known_hosts line.
- *
- * @returns 1 if the key matches, 0 if the key doesn't match and -1
- * on error.
- */
-static int check_public_key(ssh_session session, char **tokens) {
- ssh_string pubkey = session->current_crypto->server_pubkey;
- ssh_buffer pubkey_buffer;
- char *pubkey_64;
-
- /* ok we found some public key in known hosts file. now un-base64it */
- if (alldigits(tokens[1])) {
- /* openssh rsa1 format */
- bignum tmpbn;
- ssh_string tmpstring;
- unsigned int len;
- int i;
-
- pubkey_buffer = ssh_buffer_new();
- if (pubkey_buffer == NULL) {
- return -1;
- }
-
- tmpstring = ssh_string_from_char("ssh-rsa1");
- if (tmpstring == NULL) {
- ssh_buffer_free(pubkey_buffer);
- return -1;
- }
-
- if (buffer_add_ssh_string(pubkey_buffer, tmpstring) < 0) {
- ssh_buffer_free(pubkey_buffer);
- ssh_string_free(tmpstring);
- return -1;
- }
- ssh_string_free(tmpstring);
-
- for (i = 2; i < 4; i++) { /* e, then n */
- tmpbn = NULL;
- bignum_dec2bn(tokens[i], &tmpbn);
- if (tmpbn == NULL) {
- ssh_buffer_free(pubkey_buffer);
- return -1;
- }
- /* for some reason, make_bignum_string does not work
- because of the padding which it does --kv */
- /* tmpstring = make_bignum_string(tmpbn); */
- /* do it manually instead */
- len = bignum_num_bytes(tmpbn);
- tmpstring = malloc(4 + len);
- if (tmpstring == NULL) {
- ssh_buffer_free(pubkey_buffer);
- bignum_free(tmpbn);
- return -1;
- }
- /* TODO: fix the hardcoding */
- tmpstring->size = htonl(len);
-#ifdef HAVE_LIBGCRYPT
- bignum_bn2bin(tmpbn, len, tmpstring->string);
-#elif defined HAVE_LIBCRYPTO
- bignum_bn2bin(tmpbn, tmpstring->string);
-#endif
- bignum_free(tmpbn);
- if (buffer_add_ssh_string(pubkey_buffer, tmpstring) < 0) {
- ssh_buffer_free(pubkey_buffer);
- ssh_string_free(tmpstring);
- bignum_free(tmpbn);
- return -1;
- }
- ssh_string_free(tmpstring);
- }
- } else {
- /* ssh-dss or ssh-rsa */
- pubkey_64 = tokens[2];
- pubkey_buffer = base64_to_bin(pubkey_64);
- }
-
- if (pubkey_buffer == NULL) {
- ssh_set_error(session, SSH_FATAL,
- "Verifying that server is a known host: base64 error");
- return -1;
- }
-
- if (ssh_buffer_get_len(pubkey_buffer) != ssh_string_len(pubkey)) {
- ssh_buffer_free(pubkey_buffer);
- return 0;
- }
-
- /* now test that they are identical */
- if (memcmp(ssh_buffer_get_begin(pubkey_buffer), pubkey->string,
- ssh_buffer_get_len(pubkey_buffer)) != 0) {
- ssh_buffer_free(pubkey_buffer);
- return 0;
- }
-
- ssh_buffer_free(pubkey_buffer);
- return 1;
-}
-
-/**
- * @brief Check if a hostname matches a openssh-style hashed known host.
- *
- * @param[in] host The host to check.
- *
- * @param[in] hashed The hashed value.
- *
- * @returns 1 if it matches, 0 otherwise.
- */
-static int match_hashed_host(ssh_session session, const char *host,
- const char *sourcehash) {
- /* Openssh hash structure :
- * |1|base64 encoded salt|base64 encoded hash
- * hash is produced that way :
- * hash := HMAC_SHA1(key=salt,data=host)
- */
- unsigned char buffer[256] = {0};
- ssh_buffer salt;
- ssh_buffer hash;
- HMACCTX mac;
- char *source;
- char *b64hash;
- int match;
- unsigned int size;
-
- enter_function();
-
- if (strncmp(sourcehash, "|1|", 3) != 0) {
- leave_function();
- return 0;
- }
-
- source = strdup(sourcehash + 3);
- if (source == NULL) {
- leave_function();
- return 0;
- }
-
- b64hash = strchr(source, '|');
- if (b64hash == NULL) {
- /* Invalid hash */
- SAFE_FREE(source);
- leave_function();
- return 0;
- }
-
- *b64hash = '\0';
- b64hash++;
-
- salt = base64_to_bin(source);
- if (salt == NULL) {
- SAFE_FREE(source);
- leave_function();
- return 0;
- }
-
- hash = base64_to_bin(b64hash);
- SAFE_FREE(source);
- if (hash == NULL) {
- ssh_buffer_free(salt);
- leave_function();
- return 0;
- }
-
- mac = hmac_init(ssh_buffer_get_begin(salt), ssh_buffer_get_len(salt), HMAC_SHA1);
- if (mac == NULL) {
- ssh_buffer_free(salt);
- ssh_buffer_free(hash);
- leave_function();
- return 0;
- }
- size = sizeof(buffer);
- hmac_update(mac, host, strlen(host));
- hmac_final(mac, buffer, &size);
-
- if (size == ssh_buffer_get_len(hash) &&
- memcmp(buffer, ssh_buffer_get_begin(hash), size) == 0) {
- match = 1;
- } else {
- match = 0;
- }
-
- ssh_buffer_free(salt);
- ssh_buffer_free(hash);
-
- ssh_log(session, SSH_LOG_PACKET,
- "Matching a hashed host: %s match=%d", host, match);
-
- leave_function();
- return match;
-}
-
-/* How it's working :
- * 1- we open the known host file and bitch if it doesn't exist
- * 2- we need to examine each line of the file, until going on state SSH_SERVER_KNOWN_OK:
- * - there's a match. if the key is good, state is SSH_SERVER_KNOWN_OK,
- * else it's SSH_SERVER_KNOWN_CHANGED (or SSH_SERVER_FOUND_OTHER)
- * - there's no match : no change
- */
-
-/**
- * @brief Check if the server is known.
- *
- * Checks the user's known host file for a previous connection to the
- * current server.
- *
- * @param[in] session The SSH session to use.
- *
- * @returns SSH_SERVER_KNOWN_OK: The server is known and has not changed.\n
- * SSH_SERVER_KNOWN_CHANGED: The server key has changed. Either you
- * are under attack or the administrator
- * changed the key. You HAVE to warn the
- * user about a possible attack.\n
- * SSH_SERVER_FOUND_OTHER: The server gave use a key of a type while
- * we had an other type recorded. It is a
- * possible attack.\n
- * SSH_SERVER_NOT_KNOWN: The server is unknown. User should
- * confirm the MD5 is correct.\n
- * SSH_SERVER_FILE_NOT_FOUND: The known host file does not exist. The
- * host is thus unknown. File will be
- * created if host key is accepted.\n
- * SSH_SERVER_ERROR: Some error happened.
- *
- * @see ssh_get_pubkey_hash()
- *
- * @bug There is no current way to remove or modify an entry into the known
- * host table.
- */
-int ssh_is_server_known(ssh_session session) {
- FILE *file = NULL;
- char **tokens;
- char *host;
- char *hostport;
- const char *type;
- int match;
- int ret = SSH_SERVER_NOT_KNOWN;
-
- enter_function();
-
- if (session->knownhosts == NULL) {
- if (ssh_options_apply(session) < 0) {
- ssh_set_error(session, SSH_REQUEST_DENIED,
- "Can't find a known_hosts file");
- leave_function();
- return SSH_SERVER_FILE_NOT_FOUND;
- }
- }
-
- if (session->host == NULL) {
- ssh_set_error(session, SSH_FATAL,
- "Can't verify host in known hosts if the hostname isn't known");
- leave_function();
- return SSH_SERVER_ERROR;
- }
-
- if (session->current_crypto == NULL){
- ssh_set_error(session, SSH_FATAL,
- "ssh_is_host_known called without cryptographic context");
- leave_function();
- return SSH_SERVER_ERROR;
- }
- host = ssh_lowercase(session->host);
- hostport = ssh_hostport(host,session->port);
- if (host == NULL || hostport == NULL) {
- ssh_set_error_oom(session);
- SAFE_FREE(host);
- SAFE_FREE(hostport);
- leave_function();
- return SSH_SERVER_ERROR;
- }
-
- do {
- tokens = ssh_get_knownhost_line(session, &file,
- session->knownhosts, &type);
-
- /* End of file, return the current state */
- if (tokens == NULL) {
- break;
- }
- match = match_hashed_host(session, host, tokens[0]);
- if (match == 0){
- match = match_hostname(hostport, tokens[0], strlen(tokens[0]));
- }
- if (match == 0) {
- match = match_hostname(host, tokens[0], strlen(tokens[0]));
- }
- if (match == 0) {
- match = match_hashed_host(session, hostport, tokens[0]);
- }
- if (match) {
- /* We got a match. Now check the key type */
- if (strcmp(session->current_crypto->server_pubkey_type, type) != 0) {
- /* Different type. We don't override the known_changed error which is
- * more important */
- if (ret != SSH_SERVER_KNOWN_CHANGED)
- ret = SSH_SERVER_FOUND_OTHER;
- tokens_free(tokens);
- continue;
- }
- /* so we know the key type is good. We may get a good key or a bad key. */
- match = check_public_key(session, tokens);
- tokens_free(tokens);
-
- if (match < 0) {
- ret = SSH_SERVER_ERROR;
- break;
- } else if (match == 1) {
- ret = SSH_SERVER_KNOWN_OK;
- break;
- } else if(match == 0) {
- /* We override the status with the wrong key state */
- ret = SSH_SERVER_KNOWN_CHANGED;
- }
- } else {
- tokens_free(tokens);
- }
- } while (1);
-
- if ( (ret == SSH_SERVER_NOT_KNOWN) && (session->StrictHostKeyChecking == 0) ) {
- ssh_write_knownhost(session);
- ret = SSH_SERVER_KNOWN_OK;
- }
-
- SAFE_FREE(host);
- SAFE_FREE(hostport);
- if (file != NULL) {
- fclose(file);
- }
-
- /* Return the current state at end of file */
- leave_function();
- return ret;
-}
-
-/**
- * @brief Write the current server as known in the known hosts file.
- *
- * This will create the known hosts file if it does not exist. You generaly use
- * it when ssh_is_server_known() answered SSH_SERVER_NOT_KNOWN.
- *
- * @param[in] session The ssh session to use.
- *
- * @return SSH_OK on success, SSH_ERROR on error.
- */
-int ssh_write_knownhost(ssh_session session) {
- ssh_string pubkey;
- unsigned char *pubkey_64;
- char buffer[4096] = {0};
- FILE *file;
- char *dir;
- char *host;
- char *hostport;
- size_t len = 0;
-
- if (session->host == NULL) {
- ssh_set_error(session, SSH_FATAL,
- "Can't write host in known hosts if the hostname isn't known");
- return SSH_ERROR;
- }
-
- host = ssh_lowercase(session->host);
- /* If using a nonstandard port, save the host in the [host]:port format */
- if(session->port != 22){
- hostport = ssh_hostport(host,session->port);
- SAFE_FREE(host);
- host=hostport;
- hostport=NULL;
- }
-
- if (session->knownhosts == NULL) {
- if (ssh_options_apply(session) < 0) {
- ssh_set_error(session, SSH_FATAL, "Can't find a known_hosts file");
- return SSH_ERROR;
- }
- }
-
- if(session->current_crypto==NULL) {
- ssh_set_error(session, SSH_FATAL, "No current crypto context");
- return SSH_ERROR;
- }
-
- pubkey = session->current_crypto->server_pubkey;
- if(pubkey == NULL){
- ssh_set_error(session, SSH_FATAL, "No public key present");
- return SSH_ERROR;
- }
-
- /* Check if ~/.ssh exists and create it if not */
- dir = ssh_dirname(session->knownhosts);
- if (dir == NULL) {
- ssh_set_error(session, SSH_FATAL, "%s", strerror(errno));
- return -1;
- }
- if (! ssh_file_readaccess_ok(dir)) {
- if (ssh_mkdir(dir, 0700) < 0) {
- ssh_set_error(session, SSH_FATAL,
- "Cannot create %s directory.", dir);
- SAFE_FREE(dir);
- return -1;
- }
- }
- SAFE_FREE(dir);
-
- file = fopen(session->knownhosts, "a");
- if (file == NULL) {
- ssh_set_error(session, SSH_FATAL,
- "Couldn't open known_hosts file %s for appending: %s",
- session->knownhosts, strerror(errno));
- SAFE_FREE(host);
- return -1;
- }
-
- if (strcmp(session->current_crypto->server_pubkey_type, "ssh-rsa1") == 0) {
- /* openssh uses a different format for ssh-rsa1 keys.
- Be compatible --kv */
- ssh_public_key key;
- char *e_string = NULL;
- char *n_string = NULL;
- bignum e = NULL;
- bignum n = NULL;
- int rsa_size;
-#ifdef HAVE_LIBGCRYPT
- gcry_sexp_t sexp;
-#endif
-
- key = publickey_from_string(session, pubkey);
- if (key == NULL) {
- fclose(file);
- SAFE_FREE(host);
- return -1;
- }
-
-#ifdef HAVE_LIBGCRYPT
- sexp = gcry_sexp_find_token(key->rsa_pub, "e", 0);
- if (sexp == NULL) {
- publickey_free(key);
- fclose(file);
- SAFE_FREE(host);
- return -1;
- }
- e = gcry_sexp_nth_mpi(sexp, 1, GCRYMPI_FMT_USG);
- gcry_sexp_release(sexp);
- if (e == NULL) {
- publickey_free(key);
- fclose(file);
- SAFE_FREE(host);
- return -1;
- }
-
- sexp = gcry_sexp_find_token(key->rsa_pub, "n", 0);
- if (sexp == NULL) {
- publickey_free(key);
- bignum_free(e);
- fclose(file);
- SAFE_FREE(host);
- return -1;
- }
- n = gcry_sexp_nth_mpi(sexp, 1, GCRYMPI_FMT_USG);
- gcry_sexp_release(sexp);
- if (n == NULL) {
- publickey_free(key);
- bignum_free(e);
- fclose(file);
- SAFE_FREE(host);
- return -1;
- }
-
- rsa_size = (gcry_pk_get_nbits(key->rsa_pub) + 7) / 8;
-#elif defined HAVE_LIBCRYPTO
- e = key->rsa_pub->e;
- n = key->rsa_pub->n;
- rsa_size = RSA_size(key->rsa_pub);
-#endif
-
- e_string = bignum_bn2dec(e);
- n_string = bignum_bn2dec(n);
- if (e_string == NULL || n_string == NULL) {
-#ifdef HAVE_LIBGCRYPT
- bignum_free(e);
- bignum_free(n);
- SAFE_FREE(e_string);
- SAFE_FREE(n_string);
-#elif defined HAVE_LIBCRYPTO
- OPENSSL_free(e_string);
- OPENSSL_free(n_string);
-#endif
- publickey_free(key);
- fclose(file);
- SAFE_FREE(host);
- return -1;
- }
-
- snprintf(buffer, sizeof(buffer),
- "%s %d %s %s\n",
- host,
- rsa_size << 3,
- e_string,
- n_string);
-
-#ifdef HAVE_LIBGCRYPT
- bignum_free(e);
- bignum_free(n);
- SAFE_FREE(e_string);
- SAFE_FREE(n_string);
-#elif defined HAVE_LIBCRYPTO
- OPENSSL_free(e_string);
- OPENSSL_free(n_string);
-#endif
-
- publickey_free(key);
- } else {
- pubkey_64 = bin_to_base64(pubkey->string, ssh_string_len(pubkey));
- if (pubkey_64 == NULL) {
- fclose(file);
- SAFE_FREE(host);
- return -1;
- }
-
- snprintf(buffer, sizeof(buffer),
- "%s %s %s\n",
- host,
- session->current_crypto->server_pubkey_type,
- pubkey_64);
-
- SAFE_FREE(pubkey_64);
- }
- SAFE_FREE(host);
- len = strlen(buffer);
- if (fwrite(buffer, len, 1, file) != 1 || ferror(file)) {
- fclose(file);
- return -1;
- }
-
- fclose(file);
- return 0;
-}
-
-/** @} */
-
-/* vim: set ts=4 sw=4 et cindent: */
diff --git a/libssh/keys.c b/libssh/keys.c
deleted file mode 100644
index f0ebc155..00000000
--- a/libssh/keys.c
+++ /dev/null
@@ -1,1497 +0,0 @@
-/*
- * keys.c - decoding a public key or signature and verifying them
- *
- * This file is part of the SSH Library
- *
- * Copyright (c) 2003-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 <stdlib.h>
-#include <string.h>
-#ifdef HAVE_LIBCRYPTO
-#include <openssl/dsa.h>
-#include <openssl/rsa.h>
-#endif
-#include "libssh/priv.h"
-#include "libssh/ssh2.h"
-#include "libssh/server.h"
-#include "libssh/buffer.h"
-#include "libssh/agent.h"
-#include "libssh/session.h"
-#include "libssh/keys.h"
-#include "libssh/dh.h"
-#include "libssh/messages.h"
-#include "libssh/string.h"
-
-/**
- * @addtogroup libssh_auth
- *
- * @{
- */
-
-/* Public key decoding functions */
-const char *ssh_type_to_char(int type) {
- switch (type) {
- case SSH_KEYTYPE_DSS:
- return "ssh-dss";
- case SSH_KEYTYPE_RSA:
- return "ssh-rsa";
- case SSH_KEYTYPE_RSA1:
- return "ssh-rsa1";
- default:
- return NULL;
- }
-}
-
-int ssh_type_from_name(const char *name) {
- if (strcmp(name, "rsa1") == 0) {
- return SSH_KEYTYPE_RSA1;
- } else if (strcmp(name, "rsa") == 0) {
- return SSH_KEYTYPE_RSA;
- } else if (strcmp(name, "dsa") == 0) {
- return SSH_KEYTYPE_DSS;
- } else if (strcmp(name, "ssh-rsa1") == 0) {
- return SSH_KEYTYPE_RSA1;
- } else if (strcmp(name, "ssh-rsa") == 0) {
- return SSH_KEYTYPE_RSA;
- } else if (strcmp(name, "ssh-dss") == 0) {
- return SSH_KEYTYPE_DSS;
- }
-
- return -1;
-}
-
-ssh_public_key publickey_make_dss(ssh_session session, ssh_buffer buffer) {
- ssh_string p = NULL;
- ssh_string q = NULL;
- ssh_string g = NULL;
- ssh_string pubkey = NULL;
- ssh_public_key key = NULL;
-
- key = malloc(sizeof(struct ssh_public_key_struct));
- if (key == NULL) {
- ssh_buffer_free(buffer);
- return NULL;
- }
-
- key->type = SSH_KEYTYPE_DSS;
- key->type_c = ssh_type_to_char(key->type);
-
- p = buffer_get_ssh_string(buffer);
- q = buffer_get_ssh_string(buffer);
- g = buffer_get_ssh_string(buffer);
- pubkey = buffer_get_ssh_string(buffer);
-
- ssh_buffer_free(buffer); /* we don't need it anymore */
-
- if (p == NULL || q == NULL || g == NULL || pubkey == NULL) {
- ssh_set_error(session, SSH_FATAL, "Invalid DSA public key");
- goto error;
- }
-
-#ifdef HAVE_LIBGCRYPT
- gcry_sexp_build(&key->dsa_pub, NULL,
- "(public-key(dsa(p %b)(q %b)(g %b)(y %b)))",
- ssh_string_len(p), ssh_string_data(p),
- ssh_string_len(q), ssh_string_data(q),
- ssh_string_len(g), ssh_string_data(g),
- ssh_string_len(pubkey), ssh_string_data(pubkey));
- if (key->dsa_pub == NULL) {
- goto error;
- }
-#elif defined HAVE_LIBCRYPTO
-
- key->dsa_pub = DSA_new();
- if (key->dsa_pub == NULL) {
- goto error;
- }
- key->dsa_pub->p = make_string_bn(p);
- key->dsa_pub->q = make_string_bn(q);
- key->dsa_pub->g = make_string_bn(g);
- key->dsa_pub->pub_key = make_string_bn(pubkey);
- if (key->dsa_pub->p == NULL ||
- key->dsa_pub->q == NULL ||
- key->dsa_pub->g == NULL ||
- key->dsa_pub->pub_key == NULL) {
- goto error;
- }
-#endif /* HAVE_LIBCRYPTO */
-
-#ifdef DEBUG_CRYPTO
- ssh_print_hexa("p", ssh_string_data(p), ssh_string_len(p));
- ssh_print_hexa("q", ssh_string_data(q), ssh_string_len(q));
- ssh_print_hexa("g", ssh_string_data(g), ssh_string_len(g));
-#endif
-
- ssh_string_burn(p);
- ssh_string_free(p);
- ssh_string_burn(q);
- ssh_string_free(q);
- ssh_string_burn(g);
- ssh_string_free(g);
- ssh_string_burn(pubkey);
- ssh_string_free(pubkey);
-
- return key;
-error:
- ssh_string_burn(p);
- ssh_string_free(p);
- ssh_string_burn(q);
- ssh_string_free(q);
- ssh_string_burn(g);
- ssh_string_free(g);
- ssh_string_burn(pubkey);
- ssh_string_free(pubkey);
- publickey_free(key);
-
- return NULL;
-}
-
-ssh_public_key publickey_make_rsa(ssh_session session, ssh_buffer buffer,
- int type) {
- ssh_string e = NULL;
- ssh_string n = NULL;
- ssh_public_key key = NULL;
-
- key = malloc(sizeof(struct ssh_public_key_struct));
- if (key == NULL) {
- ssh_buffer_free(buffer);
- return NULL;
- }
-
- key->type = type;
- key->type_c = ssh_type_to_char(key->type);
-
- e = buffer_get_ssh_string(buffer);
- n = buffer_get_ssh_string(buffer);
-
- ssh_buffer_free(buffer); /* we don't need it anymore */
-
- if(e == NULL || n == NULL) {
- ssh_set_error(session, SSH_FATAL, "Invalid RSA public key");
- goto error;
- }
-#ifdef HAVE_LIBGCRYPT
- gcry_sexp_build(&key->rsa_pub, NULL,
- "(public-key(rsa(n %b)(e %b)))",
- ssh_string_len(n), ssh_string_data(n),
- ssh_string_len(e),ssh_string_data(e));
- if (key->rsa_pub == NULL) {
- goto error;
- }
-#elif HAVE_LIBCRYPTO
- key->rsa_pub = RSA_new();
- if (key->rsa_pub == NULL) {
- goto error;
- }
-
- key->rsa_pub->e = make_string_bn(e);
- key->rsa_pub->n = make_string_bn(n);
- if (key->rsa_pub->e == NULL ||
- key->rsa_pub->n == NULL) {
- goto error;
- }
-#endif
-
-#ifdef DEBUG_CRYPTO
- ssh_print_hexa("e", ssh_string_data(e), ssh_string_len(e));
- ssh_print_hexa("n", ssh_string_data(n), ssh_string_len(n));
-#endif
-
- ssh_string_burn(e);
- ssh_string_free(e);
- ssh_string_burn(n);
- ssh_string_free(n);
-
- return key;
-error:
- ssh_string_burn(e);
- ssh_string_free(e);
- ssh_string_burn(n);
- ssh_string_free(n);
- publickey_free(key);
-
- return NULL;
-}
-
-void publickey_free(ssh_public_key key) {
- if (key == NULL) {
- return;
- }
-
- switch(key->type) {
- case SSH_KEYTYPE_DSS:
-#ifdef HAVE_LIBGCRYPT
- gcry_sexp_release(key->dsa_pub);
-#elif HAVE_LIBCRYPTO
- DSA_free(key->dsa_pub);
-#endif
- break;
- case SSH_KEYTYPE_RSA:
- case SSH_KEYTYPE_RSA1:
-#ifdef HAVE_LIBGCRYPT
- gcry_sexp_release(key->rsa_pub);
-#elif defined HAVE_LIBCRYPTO
- RSA_free(key->rsa_pub);
-#endif
- break;
- default:
- break;
- }
- SAFE_FREE(key);
-}
-
-ssh_public_key publickey_from_string(ssh_session session, ssh_string pubkey_s) {
- ssh_buffer tmpbuf = NULL;
- ssh_string type_s = NULL;
- char *type_c = NULL;
- int type;
-
- tmpbuf = ssh_buffer_new();
- if (tmpbuf == NULL) {
- return NULL;
- }
-
- if (buffer_add_data(tmpbuf, ssh_string_data(pubkey_s), ssh_string_len(pubkey_s)) < 0) {
- goto error;
- }
-
- type_s = buffer_get_ssh_string(tmpbuf);
- if (type_s == NULL) {
- ssh_set_error(session,SSH_FATAL,"Invalid public key format");
- goto error;
- }
-
- type_c = ssh_string_to_char(type_s);
- ssh_string_free(type_s);
- if (type_c == NULL) {
- goto error;
- }
-
- type = ssh_type_from_name(type_c);
- SAFE_FREE(type_c);
-
- switch (type) {
- case SSH_KEYTYPE_DSS:
- return publickey_make_dss(session, tmpbuf);
- case SSH_KEYTYPE_RSA:
- case SSH_KEYTYPE_RSA1:
- return publickey_make_rsa(session, tmpbuf, type);
- }
-
- ssh_set_error(session, SSH_FATAL, "Unknown public key protocol %s",
- ssh_type_to_char(type));
-
-error:
- ssh_buffer_free(tmpbuf);
- return NULL;
-}
-
-/**
- * @brief Make a public_key object out of a private_key object.
- *
- * @param[in] prv The private key to generate the public key.
- *
- * @returns The generated public key, NULL on error.
- *
- * @see publickey_to_string()
- */
-ssh_public_key publickey_from_privatekey(ssh_private_key prv) {
- ssh_public_key key = NULL;
-#ifdef HAVE_LIBGCRYPT
- gcry_sexp_t sexp;
- const char *tmp = NULL;
- size_t size;
- ssh_string p = NULL;
- ssh_string q = NULL;
- ssh_string g = NULL;
- ssh_string y = NULL;
- ssh_string e = NULL;
- ssh_string n = NULL;
-#endif /* HAVE_LIBGCRYPT */
-
- key = malloc(sizeof(struct ssh_public_key_struct));
- if (key == NULL) {
- return NULL;
- }
-
- key->type = prv->type;
- switch(key->type) {
- case SSH_KEYTYPE_DSS:
-#ifdef HAVE_LIBGCRYPT
- sexp = gcry_sexp_find_token(prv->dsa_priv, "p", 0);
- if (sexp == NULL) {
- goto error;
- }
- tmp = gcry_sexp_nth_data(sexp, 1, &size);
- p = ssh_string_new(size);
- if (p == NULL) {
- goto error;
- }
- ssh_string_fill(p,(char *) tmp, size);
- gcry_sexp_release(sexp);
-
- sexp = gcry_sexp_find_token(prv->dsa_priv,"q",0);
- if (sexp == NULL) {
- goto error;
- }
- tmp = gcry_sexp_nth_data(sexp,1,&size);
- q = ssh_string_new(size);
- if (q == NULL) {
- goto error;
- }
- ssh_string_fill(q,(char *) tmp,size);
- gcry_sexp_release(sexp);
-
- sexp = gcry_sexp_find_token(prv->dsa_priv, "g", 0);
- if (sexp == NULL) {
- goto error;
- }
- tmp = gcry_sexp_nth_data(sexp,1,&size);
- g = ssh_string_new(size);
- if (g == NULL) {
- goto error;
- }
- ssh_string_fill(g,(char *) tmp,size);
- gcry_sexp_release(sexp);
-
- sexp = gcry_sexp_find_token(prv->dsa_priv,"y",0);
- if (sexp == NULL) {
- goto error;
- }
- tmp = gcry_sexp_nth_data(sexp,1,&size);
- y = ssh_string_new(size);
- if (y == NULL) {
- goto error;
- }
- ssh_string_fill(y,(char *) tmp,size);
- gcry_sexp_release(sexp);
-
- gcry_sexp_build(&key->dsa_pub, NULL,
- "(public-key(dsa(p %b)(q %b)(g %b)(y %b)))",
- ssh_string_len(p), ssh_string_data(p),
- ssh_string_len(q), ssh_string_data(q),
- ssh_string_len(g), ssh_string_data(g),
- ssh_string_len(y), ssh_string_data(y));
-
- ssh_string_burn(p);
- ssh_string_free(p);
- ssh_string_burn(q);
- ssh_string_free(q);
- ssh_string_burn(g);
- ssh_string_free(g);
- ssh_string_burn(y);
- ssh_string_free(y);
-#elif defined HAVE_LIBCRYPTO
- key->dsa_pub = DSA_new();
- if (key->dsa_pub == NULL) {
- goto error;
- }
- key->dsa_pub->p = BN_dup(prv->dsa_priv->p);
- key->dsa_pub->q = BN_dup(prv->dsa_priv->q);
- key->dsa_pub->g = BN_dup(prv->dsa_priv->g);
- key->dsa_pub->pub_key = BN_dup(prv->dsa_priv->pub_key);
- if (key->dsa_pub->p == NULL ||
- key->dsa_pub->q == NULL ||
- key->dsa_pub->g == NULL ||
- key->dsa_pub->pub_key == NULL) {
- goto error;
- }
-#endif /* HAVE_LIBCRYPTO */
- break;
- case SSH_KEYTYPE_RSA:
- case SSH_KEYTYPE_RSA1:
-#ifdef HAVE_LIBGCRYPT
- sexp = gcry_sexp_find_token(prv->rsa_priv, "n", 0);
- if (sexp == NULL) {
- goto error;
- }
- tmp = gcry_sexp_nth_data(sexp, 1, &size);
- n = ssh_string_new(size);
- if (n == NULL) {
- goto error;
- }
- ssh_string_fill(n, (char *) tmp, size);
- gcry_sexp_release(sexp);
-
- sexp = gcry_sexp_find_token(prv->rsa_priv, "e", 0);
- if (sexp == NULL) {
- goto error;
- }
- tmp = gcry_sexp_nth_data(sexp, 1, &size);
- e = ssh_string_new(size);
- if (e == NULL) {
- goto error;
- }
- ssh_string_fill(e, (char *) tmp, size);
- gcry_sexp_release(sexp);
-
- gcry_sexp_build(&key->rsa_pub, NULL,
- "(public-key(rsa(n %b)(e %b)))",
- ssh_string_len(n), ssh_string_data(n),
- ssh_string_len(e), ssh_string_data(e));
- if (key->rsa_pub == NULL) {
- goto error;
- }
-
- ssh_string_burn(e);
- ssh_string_free(e);
- ssh_string_burn(n);
- ssh_string_free(n);
-#elif defined HAVE_LIBCRYPTO
- key->rsa_pub = RSA_new();
- if (key->rsa_pub == NULL) {
- goto error;
- }
- key->rsa_pub->e = BN_dup(prv->rsa_priv->e);
- key->rsa_pub->n = BN_dup(prv->rsa_priv->n);
- if (key->rsa_pub->e == NULL ||
- key->rsa_pub->n == NULL) {
- goto error;
- }
-#endif
- break;
- }
- key->type_c = ssh_type_to_char(prv->type);
-
- return key;
-error:
-#ifdef HAVE_LIBGCRYPT
- gcry_sexp_release(sexp);
- ssh_string_burn(p);
- ssh_string_free(p);
- ssh_string_burn(q);
- ssh_string_free(q);
- ssh_string_burn(g);
- ssh_string_free(g);
- ssh_string_burn(y);
- ssh_string_free(y);
-
- ssh_string_burn(e);
- ssh_string_free(e);
- ssh_string_burn(n);
- ssh_string_free(n);
-#endif
- publickey_free(key);
-
- return NULL;
-}
-
-#ifdef HAVE_LIBGCRYPT
-static int dsa_public_to_string(gcry_sexp_t key, ssh_buffer buffer) {
-#elif defined HAVE_LIBCRYPTO
-static int dsa_public_to_string(DSA *key, ssh_buffer buffer) {
-#endif
- ssh_string p = NULL;
- ssh_string q = NULL;
- ssh_string g = NULL;
- ssh_string n = NULL;
-
- int rc = -1;
-
-#ifdef HAVE_LIBGCRYPT
- const char *tmp = NULL;
- size_t size;
- gcry_sexp_t sexp;
-
- sexp = gcry_sexp_find_token(key, "p", 0);
- if (sexp == NULL) {
- goto error;
- }
- tmp = gcry_sexp_nth_data(sexp, 1, &size);
- p = ssh_string_new(size);
- if (p == NULL) {
- goto error;
- }
- ssh_string_fill(p, (char *) tmp, size);
- gcry_sexp_release(sexp);
-
- sexp = gcry_sexp_find_token(key, "q", 0);
- if (sexp == NULL) {
- goto error;
- }
- tmp = gcry_sexp_nth_data(sexp, 1, &size);
- q = ssh_string_new(size);
- if (q == NULL) {
- goto error;
- }
- ssh_string_fill(q, (char *) tmp, size);
- gcry_sexp_release(sexp);
-
- sexp = gcry_sexp_find_token(key, "g", 0);
- if (sexp == NULL) {
- goto error;
- }
- tmp = gcry_sexp_nth_data(sexp, 1, &size);
- g = ssh_string_new(size);
- if (g == NULL) {
- goto error;
- }
- ssh_string_fill(g, (char *) tmp, size);
- gcry_sexp_release(sexp);
-
- sexp = gcry_sexp_find_token(key, "y", 0);
- if (sexp == NULL) {
- goto error;
- }
- tmp = gcry_sexp_nth_data(sexp, 1, &size);
- n = ssh_string_new(size);
- if (n == NULL) {
- goto error;
- }
- ssh_string_fill(n, (char *) tmp, size);
-
-#elif defined HAVE_LIBCRYPTO
- p = make_bignum_string(key->p);
- q = make_bignum_string(key->q);
- g = make_bignum_string(key->g);
- n = make_bignum_string(key->pub_key);
- if (p == NULL || q == NULL || g == NULL || n == NULL) {
- goto error;
- }
-#endif /* HAVE_LIBCRYPTO */
- if (buffer_add_ssh_string(buffer, p) < 0) {
- goto error;
- }
- if (buffer_add_ssh_string(buffer, q) < 0) {
- goto error;
- }
- if (buffer_add_ssh_string(buffer, g) < 0) {
- goto error;
- }
- if (buffer_add_ssh_string(buffer, n) < 0) {
- goto error;
- }
-
- rc = 0;
-error:
-#ifdef HAVE_LIBGCRYPT
- gcry_sexp_release(sexp);
-#endif
-
- ssh_string_burn(p);
- ssh_string_free(p);
- ssh_string_burn(q);
- ssh_string_free(q);
- ssh_string_burn(g);
- ssh_string_free(g);
- ssh_string_burn(n);
- ssh_string_free(n);
-
- return rc;
-}
-
-#ifdef HAVE_LIBGCRYPT
-static int rsa_public_to_string(gcry_sexp_t key, ssh_buffer buffer) {
-#elif defined HAVE_LIBCRYPTO
-static int rsa_public_to_string(RSA *key, ssh_buffer buffer) {
-#endif
-
- ssh_string e = NULL;
- ssh_string n = NULL;
-
- int rc = -1;
-
-#ifdef HAVE_LIBGCRYPT
- const char *tmp;
- size_t size;
- gcry_sexp_t sexp;
-
- sexp = gcry_sexp_find_token(key, "n", 0);
- if (sexp == NULL) {
- goto error;
- }
- tmp = gcry_sexp_nth_data(sexp, 1, &size);
- n = ssh_string_new(size);
- if (n == NULL) {
- goto error;
- }
- ssh_string_fill(n, (char *) tmp, size);
- gcry_sexp_release(sexp);
-
- sexp = gcry_sexp_find_token(key, "e", 0);
- if (sexp == NULL) {
- goto error;
- }
- tmp = gcry_sexp_nth_data(sexp, 1, &size);
- e = ssh_string_new(size);
- if (e == NULL) {
- goto error;
- }
- ssh_string_fill(e, (char *) tmp, size);
-
-#elif defined HAVE_LIBCRYPTO
- e = make_bignum_string(key->e);
- n = make_bignum_string(key->n);
- if (e == NULL || n == NULL) {
- goto error;
- }
-#endif
-
- if (buffer_add_ssh_string(buffer, e) < 0) {
- goto error;
- }
- if (buffer_add_ssh_string(buffer, n) < 0) {
- goto error;
- }
-
- rc = 0;
-error:
-#ifdef HAVE_LIBGCRYPT
- gcry_sexp_release(sexp);
-#endif
-
- ssh_string_burn(e);
- ssh_string_free(e);
- ssh_string_burn(n);
- ssh_string_free(n);
-
- return rc;
-}
-
-/**
- * @brief Convert a public_key object into a a SSH string.
- *
- * @param[in] key The public key to convert.
- *
- * @returns An allocated SSH String containing the public key, NULL
- * on error.
- *
- * @see string_free()
- */
-ssh_string publickey_to_string(ssh_public_key key) {
- ssh_string type = NULL;
- ssh_string ret = NULL;
- ssh_buffer buf = NULL;
-
- buf = ssh_buffer_new();
- if (buf == NULL) {
- return NULL;
- }
-
- type = ssh_string_from_char(key->type_c);
- if (type == NULL) {
- goto error;
- }
-
- if (buffer_add_ssh_string(buf, type) < 0) {
- goto error;
- }
-
- switch (key->type) {
- case SSH_KEYTYPE_DSS:
- if (dsa_public_to_string(key->dsa_pub, buf) < 0) {
- goto error;
- }
- break;
- case SSH_KEYTYPE_RSA:
- case SSH_KEYTYPE_RSA1:
- if (rsa_public_to_string(key->rsa_pub, buf) < 0) {
- goto error;
- }
- break;
- }
-
- ret = ssh_string_new(ssh_buffer_get_len(buf));
- if (ret == NULL) {
- goto error;
- }
-
- ssh_string_fill(ret, ssh_buffer_get_begin(buf), ssh_buffer_get_len(buf));
-error:
- ssh_buffer_free(buf);
- ssh_string_free(type);
-
- return ret;
-}
-
-/* Signature decoding functions */
-static ssh_string signature_to_string(SIGNATURE *sign) {
- unsigned char buffer[40] = {0};
- ssh_buffer tmpbuf = NULL;
- ssh_string str = NULL;
- ssh_string tmp = NULL;
- ssh_string rs = NULL;
- int rc = -1;
-#ifdef HAVE_LIBGCRYPT
- const char *r = NULL;
- const char *s = NULL;
- gcry_sexp_t sexp;
- size_t size = 0;
-#elif defined HAVE_LIBCRYPTO
- ssh_string r = NULL;
- ssh_string s = NULL;
-#endif
-
- tmpbuf = ssh_buffer_new();
- if (tmpbuf == NULL) {
- return NULL;
- }
-
- tmp = ssh_string_from_char(ssh_type_to_char(sign->type));
- if (tmp == NULL) {
- ssh_buffer_free(tmpbuf);
- return NULL;
- }
- if (buffer_add_ssh_string(tmpbuf, tmp) < 0) {
- ssh_buffer_free(tmpbuf);
- ssh_string_free(tmp);
- return NULL;
- }
- ssh_string_free(tmp);
-
- switch(sign->type) {
- case SSH_KEYTYPE_DSS:
-#ifdef HAVE_LIBGCRYPT
- sexp = gcry_sexp_find_token(sign->dsa_sign, "r", 0);
- if (sexp == NULL) {
- ssh_buffer_free(tmpbuf);
- return NULL;
- }
- r = gcry_sexp_nth_data(sexp, 1, &size);
- if (*r == 0) { /* libgcrypt put 0 when first bit is set */
- size--;
- r++;
- }
- memcpy(buffer, r + size - 20, 20);
- gcry_sexp_release(sexp);
-
- sexp = gcry_sexp_find_token(sign->dsa_sign, "s", 0);
- if (sexp == NULL) {
- ssh_buffer_free(tmpbuf);
- return NULL;
- }
- s = gcry_sexp_nth_data(sexp,1,&size);
- if (*s == 0) {
- size--;
- s++;
- }
- memcpy(buffer+ 20, s + size - 20, 20);
- gcry_sexp_release(sexp);
-#elif defined HAVE_LIBCRYPTO
- r = make_bignum_string(sign->dsa_sign->r);
- if (r == NULL) {
- ssh_buffer_free(tmpbuf);
- return NULL;
- }
- s = make_bignum_string(sign->dsa_sign->s);
- if (s == NULL) {
- ssh_buffer_free(tmpbuf);
- ssh_string_free(r);
- return NULL;
- }
-
- memcpy(buffer, (char *)ssh_string_data(r) + ssh_string_len(r) - 20, 20);
- memcpy(buffer + 20, (char *)ssh_string_data(s) + ssh_string_len(s) - 20, 20);
-
- ssh_string_free(r);
- ssh_string_free(s);
-#endif /* HAVE_LIBCRYPTO */
- rs = ssh_string_new(40);
- if (rs == NULL) {
- ssh_buffer_free(tmpbuf);
- return NULL;
- }
-
- ssh_string_fill(rs, buffer, 40);
- rc = buffer_add_ssh_string(tmpbuf, rs);
- ssh_string_free(rs);
- if (rc < 0) {
- ssh_buffer_free(tmpbuf);
- return NULL;
- }
-
- break;
- case SSH_KEYTYPE_RSA:
- case SSH_KEYTYPE_RSA1:
-#ifdef HAVE_LIBGCRYPT
- sexp = gcry_sexp_find_token(sign->rsa_sign, "s", 0);
- if (sexp == NULL) {
- ssh_buffer_free(tmpbuf);
- return NULL;
- }
- s = gcry_sexp_nth_data(sexp,1,&size);
- if (*s == 0) {
- size--;
- s++;
- }
- rs = ssh_string_new(size);
- if (rs == NULL) {
- ssh_buffer_free(tmpbuf);
- return NULL;
- }
-
- ssh_string_fill(rs, (char *) s, size);
- rc = buffer_add_ssh_string(tmpbuf, rs);
- gcry_sexp_release(sexp);
- ssh_string_free(rs);
- if (rc < 0) {
- ssh_buffer_free(tmpbuf);
- return NULL;
- }
-#elif defined HAVE_LIBCRYPTO
- if (buffer_add_ssh_string(tmpbuf,sign->rsa_sign) < 0) {
- ssh_buffer_free(tmpbuf);
- return NULL;
- }
-#endif
- break;
- }
-
- str = ssh_string_new(ssh_buffer_get_len(tmpbuf));
- if (str == NULL) {
- ssh_buffer_free(tmpbuf);
- return NULL;
- }
- ssh_string_fill(str, ssh_buffer_get_begin(tmpbuf), ssh_buffer_get_len(tmpbuf));
- ssh_buffer_free(tmpbuf);
-
- return str;
-}
-
-/* TODO : split this function in two so it becomes smaller */
-SIGNATURE *signature_from_string(ssh_session session, ssh_string signature,
- ssh_public_key pubkey, int needed_type) {
- SIGNATURE *sign = NULL;
- ssh_buffer tmpbuf = NULL;
- ssh_string rs = NULL;
- ssh_string type_s = NULL;
- ssh_string e = NULL;
- char *type_c = NULL;
- int type;
- int len;
- int rsalen;
-#ifdef HAVE_LIBGCRYPT
- gcry_sexp_t sig;
-#elif defined HAVE_LIBCRYPTO
- DSA_SIG *sig = NULL;
- ssh_string r = NULL;
- ssh_string s = NULL;
-#endif
-
- sign = malloc(sizeof(SIGNATURE));
- if (sign == NULL) {
- ssh_set_error(session, SSH_FATAL, "Not enough space");
- return NULL;
- }
-
- tmpbuf = ssh_buffer_new();
- if (tmpbuf == NULL) {
- ssh_set_error(session, SSH_FATAL, "Not enough space");
- signature_free(sign);
- return NULL;
- }
-
- if (buffer_add_data(tmpbuf, ssh_string_data(signature), ssh_string_len(signature)) < 0) {
- signature_free(sign);
- ssh_buffer_free(tmpbuf);
- return NULL;
- }
-
- type_s = buffer_get_ssh_string(tmpbuf);
- if (type_s == NULL) {
- ssh_set_error(session, SSH_FATAL, "Invalid signature packet");
- signature_free(sign);
- ssh_buffer_free(tmpbuf);
- return NULL;
- }
-
- type_c = ssh_string_to_char(type_s);
- ssh_string_free(type_s);
- if (type_c == NULL) {
- signature_free(sign);
- ssh_buffer_free(tmpbuf);
- return NULL;
- }
- type = ssh_type_from_name(type_c);
- SAFE_FREE(type_c);
-
- if (needed_type != type) {
- ssh_set_error(session, SSH_FATAL, "Invalid signature type: %s",
- ssh_type_to_char(type));
- signature_free(sign);
- ssh_buffer_free(tmpbuf);
- return NULL;
- }
-
- switch(needed_type) {
- case SSH_KEYTYPE_DSS:
- rs = buffer_get_ssh_string(tmpbuf);
- ssh_buffer_free(tmpbuf);
-
- /* 40 is the dual signature blob len. */
- if (rs == NULL || ssh_string_len(rs) != 40) {
- ssh_string_free(rs);
- signature_free(sign);
- return NULL;
- }
-
- /* we make use of strings (because we have all-made functions to convert
- * them to bignums (ou pas ;) */
-#ifdef HAVE_LIBGCRYPT
- if (gcry_sexp_build(&sig, NULL, "(sig-val(dsa(r %b)(s %b)))",
- 20 ,ssh_string_data(rs), 20,(unsigned char *)ssh_string_data(rs) + 20)) {
- ssh_string_free(rs);
- signature_free(sign);
- return NULL;
- }
-#elif defined HAVE_LIBCRYPTO
- r = ssh_string_new(20);
- s = ssh_string_new(20);
- if (r == NULL || s == NULL) {
- ssh_string_free(r);
- ssh_string_free(s);
- ssh_string_free(rs);
- signature_free(sign);
- return NULL;
- }
-
- ssh_string_fill(r, ssh_string_data(rs), 20);
- ssh_string_fill(s, (char *)ssh_string_data(rs) + 20, 20);
-
- sig = DSA_SIG_new();
- if (sig == NULL) {
- ssh_string_free(r);
- ssh_string_free(s);
- ssh_string_free(rs);
- signature_free(sign);
- return NULL;
- }
- sig->r = make_string_bn(r); /* is that really portable ? Openssh's hack isn't better */
- sig->s = make_string_bn(s);
- ssh_string_free(r);
- ssh_string_free(s);
-
- if (sig->r == NULL || sig->s == NULL) {
- ssh_string_free(rs);
- DSA_SIG_free(sig);
- signature_free(sign);
- return NULL;
- }
-#endif
-
-#ifdef DEBUG_CRYPTO
- ssh_print_hexa("r", ssh_string_data(rs), 20);
- ssh_print_hexa("s", (const unsigned char *)ssh_string_data(rs) + 20, 20);
-#endif
- ssh_string_free(rs);
-
- sign->type = SSH_KEYTYPE_DSS;
- sign->dsa_sign = sig;
-
- return sign;
- case SSH_KEYTYPE_RSA:
- e = buffer_get_ssh_string(tmpbuf);
- ssh_buffer_free(tmpbuf);
- if (e == NULL) {
- signature_free(sign);
- return NULL;
- }
- len = ssh_string_len(e);
-#ifdef HAVE_LIBGCRYPT
- rsalen = (gcry_pk_get_nbits(pubkey->rsa_pub) + 7) / 8;
-#elif defined HAVE_LIBCRYPTO
- rsalen = RSA_size(pubkey->rsa_pub);
-#endif
- if (len > rsalen) {
- ssh_string_free(e);
- signature_free(sign);
- ssh_set_error(session, SSH_FATAL, "Signature too big! %d instead of %d",
- len, rsalen);
- return NULL;
- }
-
- if (len < rsalen) {
- ssh_log(session, SSH_LOG_RARE, "RSA signature len %d < %d",
- len, rsalen);
- }
- sign->type = SSH_KEYTYPE_RSA;
-#ifdef HAVE_LIBGCRYPT
- if (gcry_sexp_build(&sig, NULL, "(sig-val(rsa(s %b)))",
- ssh_string_len(e), ssh_string_data(e))) {
- signature_free(sign);
- ssh_string_free(e);
- return NULL;
- }
-
- sign->rsa_sign = sig;
-#elif defined HAVE_LIBCRYPTO
- sign->rsa_sign = e;
-#endif
-
-#ifdef DEBUG_CRYPTO
- ssh_log(session, SSH_LOG_FUNCTIONS, "len e: %d", len);
- ssh_print_hexa("RSA signature", ssh_string_data(e), len);
-#endif
-
-#ifdef HAVE_LIBGCRYPT
- ssh_string_free(e);
-#endif
-
- return sign;
- default:
- return NULL;
- }
-
- return NULL;
-}
-
-void signature_free(SIGNATURE *sign) {
- if (sign == NULL) {
- return;
- }
-
- switch(sign->type) {
- case SSH_KEYTYPE_DSS:
-#ifdef HAVE_LIBGCRYPT
- gcry_sexp_release(sign->dsa_sign);
-#elif defined HAVE_LIBCRYPTO
- DSA_SIG_free(sign->dsa_sign);
-#endif
- break;
- case SSH_KEYTYPE_RSA:
- case SSH_KEYTYPE_RSA1:
-#ifdef HAVE_LIBGCRYPT
- gcry_sexp_release(sign->rsa_sign);
-#elif defined HAVE_LIBCRYPTO
- SAFE_FREE(sign->rsa_sign);
-#endif
- break;
- default:
- /* FIXME Passing NULL segfaults */
-#if 0
- ssh_log(NULL, SSH_LOG_RARE, "Freeing a signature with no type!\n"); */
-#endif
- break;
- }
- SAFE_FREE(sign);
-}
-
-#ifdef HAVE_LIBCRYPTO
-/*
- * Maybe the missing function from libcrypto
- *
- * I think now, maybe it's a bad idea to name it has it should have be
- * named in libcrypto
- */
-static ssh_string RSA_do_sign(const unsigned char *payload, int len, RSA *privkey) {
- ssh_string sign = NULL;
- unsigned char *buffer = NULL;
- unsigned int size;
-
- buffer = malloc(RSA_size(privkey));
- if (buffer == NULL) {
- return NULL;
- }
-
- if (RSA_sign(NID_sha1, payload, len, buffer, &size, privkey) == 0) {
- SAFE_FREE(buffer);
- return NULL;
- }
-
- sign = ssh_string_new(size);
- if (sign == NULL) {
- SAFE_FREE(buffer);
- return NULL;
- }
-
- ssh_string_fill(sign, buffer, size);
- SAFE_FREE(buffer);
-
- return sign;
-}
-#endif
-
-#ifndef _WIN32
-ssh_string ssh_do_sign_with_agent(ssh_session session,
- struct ssh_buffer_struct *buf, struct ssh_public_key_struct *publickey) {
- struct ssh_buffer_struct *sigbuf = NULL;
- struct ssh_string_struct *signature = NULL;
- struct ssh_string_struct *session_id = NULL;
- struct ssh_crypto_struct *crypto = NULL;
-
- if (session->current_crypto) {
- crypto = session->current_crypto;
- } else {
- crypto = session->next_crypto;
- }
-
- /* prepend session identifier */
- session_id = ssh_string_new(SHA_DIGEST_LEN);
- if (session_id == NULL) {
- return NULL;
- }
- ssh_string_fill(session_id, crypto->session_id, SHA_DIGEST_LEN);
-
- sigbuf = ssh_buffer_new();
- if (sigbuf == NULL) {
- ssh_string_free(session_id);
- return NULL;
- }
-
- if (buffer_add_ssh_string(sigbuf, session_id) < 0) {
- ssh_buffer_free(sigbuf);
- ssh_string_free(session_id);
- return NULL;
- }
- ssh_string_free(session_id);
-
- /* append out buffer */
- if (buffer_add_buffer(sigbuf, buf) < 0) {
- ssh_buffer_free(sigbuf);
- return NULL;
- }
-
- /* create signature */
- signature = agent_sign_data(session, sigbuf, publickey);
-
- ssh_buffer_free(sigbuf);
-
- return signature;
-}
-#endif /* _WIN32 */
-
-/*
- * This function concats in a buffer the values needed to do a signature
- * verification. */
-ssh_buffer ssh_userauth_build_digest(ssh_session session, ssh_message msg, char *service) {
-/*
- The value of 'signature' is a signature by the corresponding private
- key over the following data, in the following order:
-
- string session identifier
- byte SSH_MSG_USERAUTH_REQUEST
- string user name
- string service name
- string "publickey"
- boolean TRUE
- string public key algorithm name
- string public key to be used for authentication
-*/
- struct ssh_crypto_struct *crypto = session->current_crypto ? session->current_crypto :
- session->next_crypto;
- ssh_buffer buffer = NULL;
- ssh_string session_id = NULL;
- uint8_t type = SSH2_MSG_USERAUTH_REQUEST;
- ssh_string username = ssh_string_from_char(msg->auth_request.username);
- ssh_string servicename = ssh_string_from_char(service);
- ssh_string method = ssh_string_from_char("publickey");
- uint8_t has_sign = 1;
- ssh_string algo = ssh_string_from_char(msg->auth_request.public_key->type_c);
- ssh_string publickey = publickey_to_string(msg->auth_request.public_key);
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- goto error;
- }
- session_id = ssh_string_new(SHA_DIGEST_LEN);
- if (session_id == NULL) {
- ssh_buffer_free(buffer);
- buffer = NULL;
- goto error;
- }
- ssh_string_fill(session_id, crypto->session_id, SHA_DIGEST_LEN);
-
- if(buffer_add_ssh_string(buffer, session_id) < 0 ||
- buffer_add_u8(buffer, type) < 0 ||
- buffer_add_ssh_string(buffer, username) < 0 ||
- buffer_add_ssh_string(buffer, servicename) < 0 ||
- buffer_add_ssh_string(buffer, method) < 0 ||
- buffer_add_u8(buffer, has_sign) < 0 ||
- buffer_add_ssh_string(buffer, algo) < 0 ||
- buffer_add_ssh_string(buffer, publickey) < 0) {
- ssh_buffer_free(buffer);
- buffer = NULL;
- goto error;
- }
-
-error:
- if(session_id) ssh_string_free(session_id);
- if(username) ssh_string_free(username);
- if(servicename) ssh_string_free(servicename);
- if(method) ssh_string_free(method);
- if(algo) ssh_string_free(algo);
- if(publickey) ssh_string_free(publickey);
- return buffer;
-}
-
-/*
- * This function signs the session id (known as H) as a string then
- * the content of sigbuf */
-ssh_string ssh_do_sign(ssh_session session, ssh_buffer sigbuf,
- ssh_private_key privatekey) {
- struct ssh_crypto_struct *crypto = session->current_crypto ? session->current_crypto :
- session->next_crypto;
- unsigned char hash[SHA_DIGEST_LEN + 1] = {0};
- ssh_string session_str = NULL;
- ssh_string signature = NULL;
- SIGNATURE *sign = NULL;
- SHACTX ctx = NULL;
-#ifdef HAVE_LIBGCRYPT
- gcry_sexp_t gcryhash;
-#endif
-
- session_str = ssh_string_new(SHA_DIGEST_LEN);
- if (session_str == NULL) {
- return NULL;
- }
- ssh_string_fill(session_str, crypto->session_id, SHA_DIGEST_LEN);
-
- ctx = sha1_init();
- if (ctx == NULL) {
- ssh_string_free(session_str);
- return NULL;
- }
-
- sha1_update(ctx, session_str, ssh_string_len(session_str) + 4);
- ssh_string_free(session_str);
- sha1_update(ctx, ssh_buffer_get_begin(sigbuf), ssh_buffer_get_len(sigbuf));
- sha1_final(hash + 1,ctx);
- hash[0] = 0;
-
-#ifdef DEBUG_CRYPTO
- ssh_print_hexa("Hash being signed with dsa", hash + 1, SHA_DIGEST_LEN);
-#endif
-
- sign = malloc(sizeof(SIGNATURE));
- if (sign == NULL) {
- return NULL;
- }
-
- switch(privatekey->type) {
- case SSH_KEYTYPE_DSS:
-#ifdef HAVE_LIBGCRYPT
- if (gcry_sexp_build(&gcryhash, NULL, "%b", SHA_DIGEST_LEN + 1, hash) ||
- gcry_pk_sign(&sign->dsa_sign, gcryhash, privatekey->dsa_priv)) {
- ssh_set_error(session, SSH_FATAL, "Signing: libcrypt error");
- gcry_sexp_release(gcryhash);
- signature_free(sign);
- return NULL;
- }
-#elif defined HAVE_LIBCRYPTO
- sign->dsa_sign = DSA_do_sign(hash + 1, SHA_DIGEST_LEN,
- privatekey->dsa_priv);
- if (sign->dsa_sign == NULL) {
- ssh_set_error(session, SSH_FATAL, "Signing: openssl error");
- signature_free(sign);
- return NULL;
- }
-#ifdef DEBUG_CRYPTO
- ssh_print_bignum("r", sign->dsa_sign->r);
- ssh_print_bignum("s", sign->dsa_sign->s);
-#endif
-#endif /* HAVE_LIBCRYPTO */
- sign->rsa_sign = NULL;
- break;
- case SSH_KEYTYPE_RSA:
-#ifdef HAVE_LIBGCRYPT
- if (gcry_sexp_build(&gcryhash, NULL, "(data(flags pkcs1)(hash sha1 %b))",
- SHA_DIGEST_LEN, hash + 1) ||
- gcry_pk_sign(&sign->rsa_sign, gcryhash, privatekey->rsa_priv)) {
- ssh_set_error(session, SSH_FATAL, "Signing: libcrypt error");
- gcry_sexp_release(gcryhash);
- signature_free(sign);
- return NULL;
- }
-#elif defined HAVE_LIBCRYPTO
- sign->rsa_sign = RSA_do_sign(hash + 1, SHA_DIGEST_LEN,
- privatekey->rsa_priv);
- if (sign->rsa_sign == NULL) {
- ssh_set_error(session, SSH_FATAL, "Signing: openssl error");
- signature_free(sign);
- return NULL;
- }
-#endif
- sign->dsa_sign = NULL;
- break;
- default:
- return NULL;
- }
-#ifdef HAVE_LIBGCRYPT
- gcry_sexp_release(gcryhash);
-#endif
-
- sign->type = privatekey->type;
-
- signature = signature_to_string(sign);
- signature_free(sign);
-
- return signature;
-}
-
-ssh_string ssh_encrypt_rsa1(ssh_session session, ssh_string data, ssh_public_key key) {
- ssh_string str = NULL;
- size_t len = ssh_string_len(data);
- size_t size = 0;
-#ifdef HAVE_LIBGCRYPT
- const char *tmp = NULL;
- gcry_sexp_t ret_sexp;
- gcry_sexp_t data_sexp;
-
- if (gcry_sexp_build(&data_sexp, NULL, "(data(flags pkcs1)(value %b))",
- len, ssh_string_data(data))) {
- ssh_set_error(session, SSH_FATAL, "RSA1 encrypt: libgcrypt error");
- return NULL;
- }
- if (gcry_pk_encrypt(&ret_sexp, data_sexp, key->rsa_pub)) {
- gcry_sexp_release(data_sexp);
- ssh_set_error(session, SSH_FATAL, "RSA1 encrypt: libgcrypt error");
- return NULL;
- }
-
- gcry_sexp_release(data_sexp);
-
- data_sexp = gcry_sexp_find_token(ret_sexp, "a", 0);
- if (data_sexp == NULL) {
- ssh_set_error(session, SSH_FATAL, "RSA1 encrypt: libgcrypt error");
- gcry_sexp_release(ret_sexp);
- return NULL;
- }
- tmp = gcry_sexp_nth_data(data_sexp, 1, &size);
- if (*tmp == 0) {
- size--;
- tmp++;
- }
-
- str = ssh_string_new(size);
- if (str == NULL) {
- ssh_set_error(session, SSH_FATAL, "Not enough space");
- gcry_sexp_release(data_sexp);
- gcry_sexp_release(ret_sexp);
- return NULL;
- }
- ssh_string_fill(str, tmp, size);
-
- gcry_sexp_release(data_sexp);
- gcry_sexp_release(ret_sexp);
-#elif defined HAVE_LIBCRYPTO
- size = RSA_size(key->rsa_pub);
-
- str = ssh_string_new(size);
- if (str == NULL) {
- ssh_set_error(session, SSH_FATAL, "Not enough space");
- return NULL;
- }
-
- if (RSA_public_encrypt(len, ssh_string_data(data), ssh_string_data(str), key->rsa_pub,
- RSA_PKCS1_PADDING) < 0) {
- ssh_string_free(str);
- return NULL;
- }
-#endif
-
- return str;
-}
-
-
-/* this function signs the session id */
-ssh_string ssh_sign_session_id(ssh_session session, ssh_private_key privatekey) {
- struct ssh_crypto_struct *crypto=session->current_crypto ? session->current_crypto :
- session->next_crypto;
- unsigned char hash[SHA_DIGEST_LEN + 1] = {0};
- ssh_string signature = NULL;
- SIGNATURE *sign = NULL;
- SHACTX ctx = NULL;
-#ifdef HAVE_LIBGCRYPT
- gcry_sexp_t data_sexp;
-#endif
-
- ctx = sha1_init();
- if (ctx == NULL) {
- return NULL;
- }
- sha1_update(ctx,crypto->session_id,SHA_DIGEST_LEN);
- sha1_final(hash + 1,ctx);
- hash[0] = 0;
-
-#ifdef DEBUG_CRYPTO
- ssh_print_hexa("Hash being signed with dsa",hash+1,SHA_DIGEST_LEN);
-#endif
-
- sign = malloc(sizeof(SIGNATURE));
- if (sign == NULL) {
- return NULL;
- }
-
- switch(privatekey->type) {
- case SSH_KEYTYPE_DSS:
-#ifdef HAVE_LIBGCRYPT
- if (gcry_sexp_build(&data_sexp, NULL, "%b", SHA_DIGEST_LEN + 1, hash) ||
- gcry_pk_sign(&sign->dsa_sign, data_sexp, privatekey->dsa_priv)) {
- ssh_set_error(session, SSH_FATAL, "Signing: libgcrypt error");
- gcry_sexp_release(data_sexp);
- signature_free(sign);
- return NULL;
- }
-#elif defined HAVE_LIBCRYPTO
- sign->dsa_sign = DSA_do_sign(hash + 1, SHA_DIGEST_LEN,
- privatekey->dsa_priv);
- if (sign->dsa_sign == NULL) {
- ssh_set_error(session, SSH_FATAL, "Signing: openssl error");
- signature_free(sign);
- return NULL;
- }
-
-#ifdef DEBUG_CRYPTO
- ssh_print_bignum("r",sign->dsa_sign->r);
- ssh_print_bignum("s",sign->dsa_sign->s);
-#endif
-
-#endif /* HAVE_LIBCRYPTO */
- sign->rsa_sign = NULL;
- break;
- case SSH_KEYTYPE_RSA:
-#ifdef HAVE_LIBGCRYPT
- if (gcry_sexp_build(&data_sexp, NULL, "(data(flags pkcs1)(hash sha1 %b))",
- SHA_DIGEST_LEN, hash + 1) ||
- gcry_pk_sign(&sign->rsa_sign, data_sexp, privatekey->rsa_priv)) {
- ssh_set_error(session, SSH_FATAL, "Signing: libgcrypt error");
- gcry_sexp_release(data_sexp);
- signature_free(sign);
- return NULL;
- }
-#elif defined HAVE_LIBCRYPTO
- sign->rsa_sign = RSA_do_sign(hash + 1, SHA_DIGEST_LEN,
- privatekey->rsa_priv);
- if (sign->rsa_sign == NULL) {
- ssh_set_error(session, SSH_FATAL, "Signing: openssl error");
- signature_free(sign);
- return NULL;
- }
-#endif
- sign->dsa_sign = NULL;
- break;
- default:
- return NULL;
- }
-
-#ifdef HAVE_LIBGCRYPT
- gcry_sexp_release(data_sexp);
-#endif
-
- sign->type = privatekey->type;
-
- signature = signature_to_string(sign);
- signature_free(sign);
-
- return signature;
-}
-
-/** @} */
-
-/* vim: set ts=4 sw=4 et cindent: */
diff --git a/libssh/legacy.c b/libssh/legacy.c
deleted file mode 100644
index ea97a31f..00000000
--- a/libssh/legacy.c
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * This file is part of the SSH Library
- *
- * Copyright (c) 2010 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.
- */
-
-/** functions in that file are wrappers to the newly named functions. All
- * of them are depreciated, but these wrapper will avoid breaking backward
- * compatibility
- */
-
-#include <libssh/libssh.h>
-#include <libssh/server.h>
-#include <libssh/buffer.h>
-
-void buffer_free(ssh_buffer buffer){
- ssh_buffer_free(buffer);
-}
-void *buffer_get(ssh_buffer buffer){
- return ssh_buffer_get_begin(buffer);
-}
-uint32_t buffer_get_len(ssh_buffer buffer){
- return ssh_buffer_get_len(buffer);
-}
-ssh_buffer buffer_new(void){
- return ssh_buffer_new();
-}
-
-ssh_channel channel_accept_x11(ssh_channel channel, int timeout_ms){
- return ssh_channel_accept_x11(channel, timeout_ms);
-}
-
-int channel_change_pty_size(ssh_channel channel,int cols,int rows){
- return ssh_channel_change_pty_size(channel,cols,rows);
-}
-
-ssh_channel channel_forward_accept(ssh_session session, int timeout_ms){
- return ssh_forward_accept(session,timeout_ms);
-}
-
-int channel_close(ssh_channel channel){
- return ssh_channel_close(channel);
-}
-
-int channel_forward_cancel(ssh_session session, const char *address, int port){
- return ssh_forward_cancel(session, address, port);
-}
-
-int channel_forward_listen(ssh_session session, const char *address,
- int port, int *bound_port){
- return ssh_forward_listen(session, address, port, bound_port);
-}
-
-void channel_free(ssh_channel channel){
- ssh_channel_free(channel);
-}
-
-int channel_get_exit_status(ssh_channel channel){
- return ssh_channel_get_exit_status(channel);
-}
-
-ssh_session channel_get_session(ssh_channel channel){
- return ssh_channel_get_session(channel);
-}
-
-int channel_is_closed(ssh_channel channel){
- return ssh_channel_is_closed(channel);
-}
-
-int channel_is_eof(ssh_channel channel){
- return ssh_channel_is_eof(channel);
-}
-
-int channel_is_open(ssh_channel channel){
- return ssh_channel_is_open(channel);
-}
-
-ssh_channel channel_new(ssh_session session){
- return ssh_channel_new(session);
-}
-
-int channel_open_forward(ssh_channel channel, const char *remotehost,
- int remoteport, const char *sourcehost, int localport){
- return ssh_channel_open_forward(channel, remotehost, remoteport,
- sourcehost,localport);
-}
-
-int channel_open_session(ssh_channel channel){
- return ssh_channel_open_session(channel);
-}
-
-int channel_poll(ssh_channel channel, int is_stderr){
- return ssh_channel_poll(channel, is_stderr);
-}
-
-int channel_read(ssh_channel channel, void *dest, uint32_t count, int is_stderr){
- return ssh_channel_read(channel, dest, count, is_stderr);
-}
-
-/*
- * This function will completely be depreciated. The old implementation was not
- * renamed.
- * int channel_read_buffer(ssh_channel channel, ssh_buffer buffer, uint32_t count,
- * int is_stderr);
- */
-
-int channel_read_nonblocking(ssh_channel channel, void *dest, uint32_t count,
- int is_stderr){
- return ssh_channel_read_nonblocking(channel, dest, count, is_stderr);
-}
-
-int channel_request_env(ssh_channel channel, const char *name, const char *value){
- return ssh_channel_request_env(channel, name, value);
-}
-
-int channel_request_exec(ssh_channel channel, const char *cmd){
- return ssh_channel_request_exec(channel, cmd);
-}
-
-int channel_request_pty(ssh_channel channel){
- return ssh_channel_request_pty(channel);
-}
-
-int channel_request_pty_size(ssh_channel channel, const char *term,
- int cols, int rows){
- return ssh_channel_request_pty_size(channel, term, cols, rows);
-}
-
-int channel_request_shell(ssh_channel channel){
- return ssh_channel_request_shell(channel);
-}
-
-int channel_request_send_signal(ssh_channel channel, const char *signum){
- return ssh_channel_request_send_signal(channel, signum);
-}
-
-int channel_request_sftp(ssh_channel channel){
- return ssh_channel_request_sftp(channel);
-}
-
-int channel_request_subsystem(ssh_channel channel, const char *subsystem){
- return ssh_channel_request_subsystem(channel, subsystem);
-}
-
-int channel_request_x11(ssh_channel channel, int single_connection, const char *protocol,
- const char *cookie, int screen_number){
- return ssh_channel_request_x11(channel, single_connection, protocol, cookie,
- screen_number);
-}
-
-int channel_send_eof(ssh_channel channel){
- return ssh_channel_send_eof(channel);
-}
-
-int channel_select(ssh_channel *readchans, ssh_channel *writechans, ssh_channel *exceptchans, struct
- timeval * timeout){
- return ssh_channel_select(readchans, writechans, exceptchans, timeout);
-}
-
-void channel_set_blocking(ssh_channel channel, int blocking){
- ssh_channel_set_blocking(channel, blocking);
-}
-
-int channel_write(ssh_channel channel, const void *data, uint32_t len){
- return ssh_channel_write(channel, data, len);
-}
-
-/*
- * These functions have to be wrapped around the pki.c functions.
-
-void privatekey_free(ssh_private_key prv);
-ssh_private_key privatekey_from_file(ssh_session session, const char *filename,
- int type, const char *passphrase);
-void publickey_free(ssh_public_key key);
-int ssh_publickey_to_file(ssh_session session, const char *file,
- ssh_string pubkey, int type);
-ssh_string publickey_from_file(ssh_session session, const char *filename,
- int *type);
-ssh_public_key publickey_from_privatekey(ssh_private_key prv);
-ssh_string publickey_to_string(ssh_public_key key);
- *
- */
-
-void string_burn(ssh_string str){
- ssh_string_burn(str);
-}
-
-ssh_string string_copy(ssh_string str){
- return ssh_string_copy(str);
-}
-
-void *string_data(ssh_string str){
- return ssh_string_data(str);
-}
-
-int string_fill(ssh_string str, const void *data, size_t len){
- return ssh_string_fill(str,data,len);
-}
-
-void string_free(ssh_string str){
- ssh_string_free(str);
-}
-
-ssh_string string_from_char(const char *what){
- return ssh_string_from_char(what);
-}
-
-size_t string_len(ssh_string str){
- return ssh_string_len(str);
-}
-
-ssh_string string_new(size_t size){
- return ssh_string_new(size);
-}
-
-char *string_to_char(ssh_string str){
- return ssh_string_to_char(str);
-}
-
-int ssh_accept(ssh_session session) {
- return ssh_handle_key_exchange(session);
-}
diff --git a/libssh/libcrypto.c b/libssh/libcrypto.c
deleted file mode 100644
index f43a91eb..00000000
--- a/libssh/libcrypto.c
+++ /dev/null
@@ -1,443 +0,0 @@
-/*
- * This file is part of the SSH Library
- *
- * Copyright (c) 2009 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 <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "libssh/priv.h"
-#include "libssh/session.h"
-#include "libssh/crypto.h"
-#include "libssh/wrapper.h"
-#include "libssh/libcrypto.h"
-
-#ifdef HAVE_LIBCRYPTO
-
-#include <openssl/sha.h>
-#include <openssl/md5.h>
-#include <openssl/dsa.h>
-#include <openssl/rsa.h>
-#include <openssl/hmac.h>
-#include <openssl/opensslv.h>
-#ifdef HAVE_OPENSSL_AES_H
-#define HAS_AES
-#include <openssl/aes.h>
-#endif
-#ifdef HAVE_OPENSSL_BLOWFISH_H
-#define HAS_BLOWFISH
-#include <openssl/blowfish.h>
-#endif
-#ifdef HAVE_OPENSSL_DES_H
-#define HAS_DES
-#include <openssl/des.h>
-#endif
-
-#if (OPENSSL_VERSION_NUMBER<0x00907000L)
-#define OLD_CRYPTO
-#endif
-
-#include "libssh/crypto.h"
-
-static int alloc_key(struct crypto_struct *cipher) {
- cipher->key = malloc(cipher->keylen);
- if (cipher->key == NULL) {
- return -1;
- }
-
- return 0;
-}
-
-SHACTX sha1_init(void) {
- SHACTX c = malloc(sizeof(*c));
- if (c == NULL) {
- return NULL;
- }
- SHA1_Init(c);
-
- return c;
-}
-
-void sha1_update(SHACTX c, const void *data, unsigned long len) {
- SHA1_Update(c,data,len);
-}
-
-void sha1_final(unsigned char *md, SHACTX c) {
- SHA1_Final(md, c);
- SAFE_FREE(c);
-}
-
-void sha1(unsigned char *digest, int len, unsigned char *hash) {
- SHA1(digest, len, hash);
-}
-
-MD5CTX md5_init(void) {
- MD5CTX c = malloc(sizeof(*c));
- if (c == NULL) {
- return NULL;
- }
-
- MD5_Init(c);
-
- return c;
-}
-
-void md5_update(MD5CTX c, const void *data, unsigned long len) {
- MD5_Update(c, data, len);
-}
-
-void md5_final(unsigned char *md, MD5CTX c) {
- MD5_Final(md,c);
- SAFE_FREE(c);
-}
-
-HMACCTX hmac_init(const void *key, int len, int type) {
- HMACCTX ctx = NULL;
-
- ctx = malloc(sizeof(*ctx));
- if (ctx == NULL) {
- return NULL;
- }
-
-#ifndef OLD_CRYPTO
- HMAC_CTX_init(ctx); // openssl 0.9.7 requires it.
-#endif
-
- switch(type) {
- case HMAC_SHA1:
- HMAC_Init(ctx, key, len, EVP_sha1());
- break;
- case HMAC_MD5:
- HMAC_Init(ctx, key, len, EVP_md5());
- break;
- default:
- SAFE_FREE(ctx);
- ctx = NULL;
- }
-
- return ctx;
-}
-
-void hmac_update(HMACCTX ctx, const void *data, unsigned long len) {
- HMAC_Update(ctx, data, len);
-}
-
-void hmac_final(HMACCTX ctx, unsigned char *hashmacbuf, unsigned int *len) {
- HMAC_Final(ctx,hashmacbuf,len);
-
-#ifndef OLD_CRYPTO
- HMAC_CTX_cleanup(ctx);
-#else
- HMAC_cleanup(ctx);
-#endif
-
- SAFE_FREE(ctx);
-}
-
-#ifdef HAS_BLOWFISH
-/* the wrapper functions for blowfish */
-static int blowfish_set_key(struct crypto_struct *cipher, void *key){
- if (cipher->key == NULL) {
- if (alloc_key(cipher) < 0) {
- return -1;
- }
- BF_set_key(cipher->key, 16, key);
- }
-
- return 0;
-}
-
-static void blowfish_encrypt(struct crypto_struct *cipher, void *in,
- void *out, unsigned long len, void *IV) {
- BF_cbc_encrypt(in, out, len, cipher->key, IV, BF_ENCRYPT);
-}
-
-static void blowfish_decrypt(struct crypto_struct *cipher, void *in,
- void *out, unsigned long len, void *IV) {
- BF_cbc_encrypt(in, out, len, cipher->key, IV, BF_DECRYPT);
-}
-#endif /* HAS_BLOWFISH */
-
-#ifdef HAS_AES
-static int aes_set_encrypt_key(struct crypto_struct *cipher, void *key) {
- if (cipher->key == NULL) {
- if (alloc_key(cipher) < 0) {
- return -1;
- }
- if (AES_set_encrypt_key(key,cipher->keysize,cipher->key) < 0) {
- SAFE_FREE(cipher->key);
- return -1;
- }
- }
-
- return 0;
-}
-static int aes_set_decrypt_key(struct crypto_struct *cipher, void *key) {
- if (cipher->key == NULL) {
- if (alloc_key(cipher) < 0) {
- return -1;
- }
- if (AES_set_decrypt_key(key,cipher->keysize,cipher->key) < 0) {
- SAFE_FREE(cipher->key);
- return -1;
- }
- }
-
- return 0;
-}
-
-static void aes_encrypt(struct crypto_struct *cipher, void *in, void *out,
- unsigned long len, void *IV) {
- AES_cbc_encrypt(in, out, len, cipher->key, IV, AES_ENCRYPT);
-}
-
-static void aes_decrypt(struct crypto_struct *cipher, void *in, void *out,
- unsigned long len, void *IV) {
- AES_cbc_encrypt(in, out, len, cipher->key, IV, AES_DECRYPT);
-}
-
-#ifndef BROKEN_AES_CTR
-/* OpenSSL until 0.9.7c has a broken AES_ctr128_encrypt implementation which
- * increments the counter from 2^64 instead of 1. It's better not to use it
- */
-
-/** @internal
- * @brief encrypts/decrypts data with stream cipher AES_ctr128. 128 bits is actually
- * the size of the CTR counter and incidentally the blocksize, but not the keysize.
- * @param len[in] must be a multiple of AES128 block size.
- */
-static void aes_ctr128_encrypt(struct crypto_struct *cipher, void *in, void *out,
- unsigned long len, void *IV) {
- unsigned char tmp_buffer[128/8];
- unsigned int num=0;
- /* Some things are special with ctr128 :
- * In this case, tmp_buffer is not being used, because it is used to store temporary data
- * when an encryption is made on lengths that are not multiple of blocksize.
- * Same for num, which is being used to store the current offset in blocksize in CTR
- * function.
- */
- AES_ctr128_encrypt(in, out, len, cipher->key, IV, tmp_buffer, &num);
-}
-#endif /* BROKEN_AES_CTR */
-#endif /* HAS_AES */
-
-#ifdef HAS_DES
-static int des3_set_key(struct crypto_struct *cipher, void *key) {
- if (cipher->key == NULL) {
- if (alloc_key(cipher) < 0) {
- return -1;
- }
-
- DES_set_odd_parity(key);
- DES_set_odd_parity((void*)((uint8_t*)key + 8));
- DES_set_odd_parity((void*)((uint8_t*)key + 16));
- DES_set_key_unchecked(key, cipher->key);
- DES_set_key_unchecked((void*)((uint8_t*)key + 8), (void*)((uint8_t*)cipher->key + sizeof(DES_key_schedule)));
- DES_set_key_unchecked((void*)((uint8_t*)key + 16), (void*)((uint8_t*)cipher->key + 2 * sizeof(DES_key_schedule)));
- }
-
- return 0;
-}
-
-static void des3_encrypt(struct crypto_struct *cipher, void *in,
- void *out, unsigned long len, void *IV) {
- DES_ede3_cbc_encrypt(in, out, len, cipher->key,
- (void*)((uint8_t*)cipher->key + sizeof(DES_key_schedule)),
- (void*)((uint8_t*)cipher->key + 2 * sizeof(DES_key_schedule)),
- IV, 1);
-}
-
-static void des3_decrypt(struct crypto_struct *cipher, void *in,
- void *out, unsigned long len, void *IV) {
- DES_ede3_cbc_encrypt(in, out, len, cipher->key,
- (void*)((uint8_t*)cipher->key + sizeof(DES_key_schedule)),
- (void*)((uint8_t*)cipher->key + 2 * sizeof(DES_key_schedule)),
- IV, 0);
-}
-
-static void des3_1_encrypt(struct crypto_struct *cipher, void *in,
- void *out, unsigned long len, void *IV) {
-#ifdef DEBUG_CRYPTO
- ssh_print_hexa("Encrypt IV before", IV, 24);
-#endif
- DES_ncbc_encrypt(in, out, len, cipher->key, IV, 1);
- DES_ncbc_encrypt(out, in, len, (void*)((uint8_t*)cipher->key + sizeof(DES_key_schedule)),
- (void*)((uint8_t*)IV + 8), 0);
- DES_ncbc_encrypt(in, out, len, (void*)((uint8_t*)cipher->key + 2 * sizeof(DES_key_schedule)),
- (void*)((uint8_t*)IV + 16), 1);
-#ifdef DEBUG_CRYPTO
- ssh_print_hexa("Encrypt IV after", IV, 24);
-#endif
-}
-
-static void des3_1_decrypt(struct crypto_struct *cipher, void *in,
- void *out, unsigned long len, void *IV) {
-#ifdef DEBUG_CRYPTO
- ssh_print_hexa("Decrypt IV before", IV, 24);
-#endif
-
- DES_ncbc_encrypt(in, out, len, (void*)((uint8_t*)cipher->key + 2 * sizeof(DES_key_schedule)),
- IV, 0);
- DES_ncbc_encrypt(out, in, len, (void*)((uint8_t*)cipher->key + sizeof(DES_key_schedule)),
- (void*)((uint8_t*)IV + 8), 1);
- DES_ncbc_encrypt(in, out, len, cipher->key, (void*)((uint8_t*)IV + 16), 0);
-
-#ifdef DEBUG_CRYPTO
- ssh_print_hexa("Decrypt IV after", IV, 24);
-#endif
-}
-
-#endif /* HAS_DES */
-
-/*
- * The table of supported ciphers
- *
- * WARNING: If you modify crypto_struct, you must make sure the order is
- * correct!
- */
-static struct crypto_struct ssh_ciphertab[] = {
-#ifdef HAS_BLOWFISH
- {
- "blowfish-cbc",
- 8,
- sizeof (BF_KEY),
- NULL,
- 128,
- blowfish_set_key,
- blowfish_set_key,
- blowfish_encrypt,
- blowfish_decrypt
- },
-#endif /* HAS_BLOWFISH */
-#ifdef HAS_AES
-#ifndef BROKEN_AES_CTR
- {
- "aes128-ctr",
- 16,
- sizeof(AES_KEY),
- NULL,
- 128,
- aes_set_encrypt_key,
- aes_set_encrypt_key,
- aes_ctr128_encrypt,
- aes_ctr128_encrypt
- },
- {
- "aes192-ctr",
- 16,
- sizeof(AES_KEY),
- NULL,
- 192,
- aes_set_encrypt_key,
- aes_set_encrypt_key,
- aes_ctr128_encrypt,
- aes_ctr128_encrypt
- },
- {
- "aes256-ctr",
- 16,
- sizeof(AES_KEY),
- NULL,
- 256,
- aes_set_encrypt_key,
- aes_set_encrypt_key,
- aes_ctr128_encrypt,
- aes_ctr128_encrypt
- },
-#endif /* BROKEN_AES_CTR */
- {
- "aes128-cbc",
- 16,
- sizeof(AES_KEY),
- NULL,
- 128,
- aes_set_encrypt_key,
- aes_set_decrypt_key,
- aes_encrypt,
- aes_decrypt
- },
- {
- "aes192-cbc",
- 16,
- sizeof(AES_KEY),
- NULL,
- 192,
- aes_set_encrypt_key,
- aes_set_decrypt_key,
- aes_encrypt,
- aes_decrypt
- },
- {
- "aes256-cbc",
- 16,
- sizeof(AES_KEY),
- NULL,
- 256,
- aes_set_encrypt_key,
- aes_set_decrypt_key,
- aes_encrypt,
- aes_decrypt
- },
-#endif /* HAS_AES */
-#ifdef HAS_DES
- {
- "3des-cbc",
- 8,
- sizeof(DES_key_schedule) * 3,
- NULL,
- 192,
- des3_set_key,
- des3_set_key,
- des3_encrypt,
- des3_decrypt
- },
- {
- "3des-cbc-ssh1",
- 8,
- sizeof(DES_key_schedule) * 3,
- NULL,
- 192,
- des3_set_key,
- des3_set_key,
- des3_1_encrypt,
- des3_1_decrypt
- },
-#endif /* HAS_DES */
- {
- NULL,
- 0,
- 0,
- NULL,
- 0,
- NULL,
- NULL,
- NULL,
- NULL
- }
-};
-
-
-struct crypto_struct *ssh_get_ciphertab(){
- return ssh_ciphertab;
-}
-
-#endif /* LIBCRYPTO */
-
diff --git a/libssh/libgcrypt.c b/libssh/libgcrypt.c
deleted file mode 100644
index f8fe96f2..00000000
--- a/libssh/libgcrypt.c
+++ /dev/null
@@ -1,423 +0,0 @@
-/*
- * This file is part of the SSH Library
- *
- * Copyright (c) 2009 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 <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "libssh/priv.h"
-#include "libssh/session.h"
-#include "libssh/crypto.h"
-#include "libssh/wrapper.h"
-
-#ifdef HAVE_LIBGCRYPT
-#include <gcrypt.h>
-
-
-static int alloc_key(struct crypto_struct *cipher) {
- cipher->key = malloc(cipher->keylen);
- if (cipher->key == NULL) {
- return -1;
- }
-
- return 0;
-}
-
-SHACTX sha1_init(void) {
- SHACTX ctx = NULL;
- gcry_md_open(&ctx, GCRY_MD_SHA1, 0);
-
- return ctx;
-}
-
-void sha1_update(SHACTX c, const void *data, unsigned long len) {
- gcry_md_write(c, data, len);
-}
-
-void sha1_final(unsigned char *md, SHACTX c) {
- gcry_md_final(c);
- memcpy(md, gcry_md_read(c, 0), SHA_DIGEST_LEN);
- gcry_md_close(c);
-}
-
-void sha1(unsigned char *digest, int len, unsigned char *hash) {
- gcry_md_hash_buffer(GCRY_MD_SHA1, hash, digest, len);
-}
-
-MD5CTX md5_init(void) {
- MD5CTX c = NULL;
- gcry_md_open(&c, GCRY_MD_MD5, 0);
-
- return c;
-}
-
-void md5_update(MD5CTX c, const void *data, unsigned long len) {
- gcry_md_write(c,data,len);
-}
-
-void md5_final(unsigned char *md, MD5CTX c) {
- gcry_md_final(c);
- memcpy(md, gcry_md_read(c, 0), MD5_DIGEST_LEN);
- gcry_md_close(c);
-}
-
-HMACCTX hmac_init(const void *key, int len, int type) {
- HMACCTX c = NULL;
-
- switch(type) {
- case HMAC_SHA1:
- gcry_md_open(&c, GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC);
- break;
- case HMAC_MD5:
- gcry_md_open(&c, GCRY_MD_MD5, GCRY_MD_FLAG_HMAC);
- break;
- default:
- c = NULL;
- }
-
- gcry_md_setkey(c, key, len);
-
- return c;
-}
-
-void hmac_update(HMACCTX c, const void *data, unsigned long len) {
- gcry_md_write(c, data, len);
-}
-
-void hmac_final(HMACCTX c, unsigned char *hashmacbuf, unsigned int *len) {
- *len = gcry_md_get_algo_dlen(gcry_md_get_algo(c));
- memcpy(hashmacbuf, gcry_md_read(c, 0), *len);
- gcry_md_close(c);
-}
-
-/* the wrapper functions for blowfish */
-static int blowfish_set_key(struct crypto_struct *cipher, void *key, void *IV){
- if (cipher->key == NULL) {
- if (alloc_key(cipher) < 0) {
- return -1;
- }
-
- if (gcry_cipher_open(&cipher->key[0], GCRY_CIPHER_BLOWFISH,
- GCRY_CIPHER_MODE_CBC, 0)) {
- SAFE_FREE(cipher->key);
- return -1;
- }
- if (gcry_cipher_setkey(cipher->key[0], key, 16)) {
- SAFE_FREE(cipher->key);
- return -1;
- }
- if (gcry_cipher_setiv(cipher->key[0], IV, 8)) {
- SAFE_FREE(cipher->key);
- return -1;
- }
- }
-
- return 0;
-}
-
-static void blowfish_encrypt(struct crypto_struct *cipher, void *in,
- void *out, unsigned long len) {
- gcry_cipher_encrypt(cipher->key[0], out, len, in, len);
-}
-
-static void blowfish_decrypt(struct crypto_struct *cipher, void *in,
- void *out, unsigned long len) {
- gcry_cipher_decrypt(cipher->key[0], out, len, in, len);
-}
-
-static int aes_set_key(struct crypto_struct *cipher, void *key, void *IV) {
- int mode=GCRY_CIPHER_MODE_CBC;
- if (cipher->key == NULL) {
- if (alloc_key(cipher) < 0) {
- return -1;
- }
- if(strstr(cipher->name,"-ctr"))
- mode=GCRY_CIPHER_MODE_CTR;
- switch (cipher->keysize) {
- case 128:
- if (gcry_cipher_open(&cipher->key[0], GCRY_CIPHER_AES128,
- mode, 0)) {
- SAFE_FREE(cipher->key);
- return -1;
- }
- break;
- case 192:
- if (gcry_cipher_open(&cipher->key[0], GCRY_CIPHER_AES192,
- mode, 0)) {
- SAFE_FREE(cipher->key);
- return -1;
- }
- break;
- case 256:
- if (gcry_cipher_open(&cipher->key[0], GCRY_CIPHER_AES256,
- mode, 0)) {
- SAFE_FREE(cipher->key);
- return -1;
- }
- break;
- }
- if (gcry_cipher_setkey(cipher->key[0], key, cipher->keysize / 8)) {
- SAFE_FREE(cipher->key);
- return -1;
- }
- if(mode == GCRY_CIPHER_MODE_CBC){
- if (gcry_cipher_setiv(cipher->key[0], IV, 16)) {
-
- SAFE_FREE(cipher->key);
- return -1;
- }
- } else {
- if(gcry_cipher_setctr(cipher->key[0],IV,16)){
- SAFE_FREE(cipher->key);
- return -1;
- }
- }
- }
-
- return 0;
-}
-
-static void aes_encrypt(struct crypto_struct *cipher, void *in, void *out,
- unsigned long len) {
- gcry_cipher_encrypt(cipher->key[0], out, len, in, len);
-}
-
-static void aes_decrypt(struct crypto_struct *cipher, void *in, void *out,
- unsigned long len) {
- gcry_cipher_decrypt(cipher->key[0], out, len, in, len);
-}
-
-static int des3_set_key(struct crypto_struct *cipher, void *key, void *IV) {
- if (cipher->key == NULL) {
- if (alloc_key(cipher) < 0) {
- return -1;
- }
- if (gcry_cipher_open(&cipher->key[0], GCRY_CIPHER_3DES,
- GCRY_CIPHER_MODE_CBC, 0)) {
- SAFE_FREE(cipher->key);
- return -1;
- }
- if (gcry_cipher_setkey(cipher->key[0], key, 24)) {
- SAFE_FREE(cipher->key);
- return -1;
- }
- if (gcry_cipher_setiv(cipher->key[0], IV, 8)) {
- SAFE_FREE(cipher->key);
- return -1;
- }
- }
-
- return 0;
-}
-
-static void des3_encrypt(struct crypto_struct *cipher, void *in,
- void *out, unsigned long len) {
- gcry_cipher_encrypt(cipher->key[0], out, len, in, len);
-}
-
-static void des3_decrypt(struct crypto_struct *cipher, void *in,
- void *out, unsigned long len) {
- gcry_cipher_decrypt(cipher->key[0], out, len, in, len);
-}
-
-static int des3_1_set_key(struct crypto_struct *cipher, void *key, void *IV) {
- if (cipher->key == NULL) {
- if (alloc_key(cipher) < 0) {
- return -1;
- }
- if (gcry_cipher_open(&cipher->key[0], GCRY_CIPHER_DES,
- GCRY_CIPHER_MODE_CBC, 0)) {
- SAFE_FREE(cipher->key);
- return -1;
- }
- if (gcry_cipher_setkey(cipher->key[0], key, 8)) {
- SAFE_FREE(cipher->key);
- return -1;
- }
- if (gcry_cipher_setiv(cipher->key[0], IV, 8)) {
- SAFE_FREE(cipher->key);
- return -1;
- }
-
- if (gcry_cipher_open(&cipher->key[1], GCRY_CIPHER_DES,
- GCRY_CIPHER_MODE_CBC, 0)) {
- SAFE_FREE(cipher->key);
- return -1;
- }
- if (gcry_cipher_setkey(cipher->key[1], (unsigned char *)key + 8, 8)) {
- SAFE_FREE(cipher->key);
- return -1;
- }
- if (gcry_cipher_setiv(cipher->key[1], (unsigned char *)IV + 8, 8)) {
- SAFE_FREE(cipher->key);
- return -1;
- }
-
- if (gcry_cipher_open(&cipher->key[2], GCRY_CIPHER_DES,
- GCRY_CIPHER_MODE_CBC, 0)) {
- SAFE_FREE(cipher->key);
- return -1;
- }
- if (gcry_cipher_setkey(cipher->key[2], (unsigned char *)key + 16, 8)) {
- SAFE_FREE(cipher->key);
- return -1;
- }
- if (gcry_cipher_setiv(cipher->key[2], (unsigned char *)IV + 16, 8)) {
- SAFE_FREE(cipher->key);
- return -1;
- }
- }
-
- return 0;
-}
-
-static void des3_1_encrypt(struct crypto_struct *cipher, void *in,
- void *out, unsigned long len) {
- gcry_cipher_encrypt(cipher->key[0], out, len, in, len);
- gcry_cipher_decrypt(cipher->key[1], in, len, out, len);
- gcry_cipher_encrypt(cipher->key[2], out, len, in, len);
-}
-
-static void des3_1_decrypt(struct crypto_struct *cipher, void *in,
- void *out, unsigned long len) {
- gcry_cipher_decrypt(cipher->key[2], out, len, in, len);
- gcry_cipher_encrypt(cipher->key[1], in, len, out, len);
- gcry_cipher_decrypt(cipher->key[0], out, len, in, len);
-}
-
-/* the table of supported ciphers */
-static struct crypto_struct ssh_ciphertab[] = {
- {
- .name = "blowfish-cbc",
- .blocksize = 8,
- .keylen = sizeof(gcry_cipher_hd_t),
- .key = NULL,
- .keysize = 128,
- .set_encrypt_key = blowfish_set_key,
- .set_decrypt_key = blowfish_set_key,
- .cbc_encrypt = blowfish_encrypt,
- .cbc_decrypt = blowfish_decrypt
- },
- {
- .name = "aes128-ctr",
- .blocksize = 16,
- .keylen = sizeof(gcry_cipher_hd_t),
- .key = NULL,
- .keysize = 128,
- .set_encrypt_key = aes_set_key,
- .set_decrypt_key = aes_set_key,
- .cbc_encrypt = aes_encrypt,
- .cbc_decrypt = aes_encrypt
- },
- {
- .name = "aes192-ctr",
- .blocksize = 16,
- .keylen = sizeof(gcry_cipher_hd_t),
- .key = NULL,
- .keysize = 192,
- .set_encrypt_key = aes_set_key,
- .set_decrypt_key = aes_set_key,
- .cbc_encrypt = aes_encrypt,
- .cbc_decrypt = aes_encrypt
- },
- {
- .name = "aes256-ctr",
- .blocksize = 16,
- .keylen = sizeof(gcry_cipher_hd_t),
- .key = NULL,
- .keysize = 256,
- .set_encrypt_key = aes_set_key,
- .set_decrypt_key = aes_set_key,
- .cbc_encrypt = aes_encrypt,
- .cbc_decrypt = aes_encrypt
- },
- {
- .name = "aes128-cbc",
- .blocksize = 16,
- .keylen = sizeof(gcry_cipher_hd_t),
- .key = NULL,
- .keysize = 128,
- .set_encrypt_key = aes_set_key,
- .set_decrypt_key = aes_set_key,
- .cbc_encrypt = aes_encrypt,
- .cbc_decrypt = aes_decrypt
- },
- {
- .name = "aes192-cbc",
- .blocksize = 16,
- .keylen = sizeof(gcry_cipher_hd_t),
- .key = NULL,
- .keysize = 192,
- .set_encrypt_key = aes_set_key,
- .set_decrypt_key = aes_set_key,
- .cbc_encrypt = aes_encrypt,
- .cbc_decrypt = aes_decrypt
- },
- {
- .name = "aes256-cbc",
- .blocksize = 16,
- .keylen = sizeof(gcry_cipher_hd_t),
- .key = NULL,
- .keysize = 256,
- .set_encrypt_key = aes_set_key,
- .set_decrypt_key = aes_set_key,
- .cbc_encrypt = aes_encrypt,
- .cbc_decrypt = aes_decrypt
- },
- {
- .name = "3des-cbc",
- .blocksize = 8,
- .keylen = sizeof(gcry_cipher_hd_t),
- .key = NULL,
- .keysize = 192,
- .set_encrypt_key = des3_set_key,
- .set_decrypt_key = des3_set_key,
- .cbc_encrypt = des3_encrypt,
- .cbc_decrypt = des3_decrypt
- },
- {
- .name = "3des-cbc-ssh1",
- .blocksize = 8,
- .keylen = sizeof(gcry_cipher_hd_t) * 3,
- .key = NULL,
- .keysize = 192,
- .set_encrypt_key = des3_1_set_key,
- .set_decrypt_key = des3_1_set_key,
- .cbc_encrypt = des3_1_encrypt,
- .cbc_decrypt = des3_1_decrypt
- },
- {
- .name = NULL,
- .blocksize = 0,
- .keylen = 0,
- .key = NULL,
- .keysize = 0,
- .set_encrypt_key = NULL,
- .set_decrypt_key = NULL,
- .cbc_encrypt = NULL,
- .cbc_decrypt = NULL
- }
-};
-
-struct crypto_struct *ssh_get_ciphertab(){
- return ssh_ciphertab;
-}
-#endif
diff --git a/libssh/log.c b/libssh/log.c
deleted file mode 100644
index 6ec5a8ea..00000000
--- a/libssh/log.c
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * log.c - logging and debugging functions
- *
- * This file is part of the SSH Library
- *
- * Copyright (c) 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 <stdarg.h>
-#include <string.h>
-
-#include "libssh/priv.h"
-#include "libssh/session.h"
-
-/**
- * @defgroup libssh_log The SSH logging functions.
- * @ingroup libssh
- *
- * Logging functions for debugging and problem resolving.
- *
- * @{
- */
-
-/**
- * @brief Log a SSH event.
- *
- * @param session The SSH session.
- *
- * @param verbosity The verbosity of the event.
- *
- * @param format The format string of the log entry.
- */
-void ssh_log(ssh_session session, int verbosity, const char *format, ...) {
- char buffer[1024];
- char indent[256];
- int min;
- va_list va;
-
- if (verbosity <= session->log_verbosity) {
- va_start(va, format);
- vsnprintf(buffer, sizeof(buffer), format, va);
- va_end(va);
-
- if (session->callbacks && session->callbacks->log_function) {
- session->callbacks->log_function(session, verbosity, buffer,
- session->callbacks->userdata);
- } else if (verbosity == SSH_LOG_FUNCTIONS) {
- if (session->log_indent > 255) {
- min = 255;
- } else {
- min = session->log_indent;
- }
-
- memset(indent, ' ', min);
- indent[min] = '\0';
-
- fprintf(stderr, "[func] %s%s\n", indent, buffer);
- } else {
- fprintf(stderr, "[%d] %s\n", verbosity, buffer);
- }
- }
-}
-
-/** @} */
-
-/* vim: set ts=4 sw=4 et cindent: */
diff --git a/libssh/match.c b/libssh/match.c
deleted file mode 100644
index 98adf67e..00000000
--- a/libssh/match.c
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Author: Tatu Ylonen <ylo@cs.hut.fi>
- * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
- * All rights reserved
- * Simple pattern matching, with '*' and '?' as wildcards.
- *
- * As far as I am concerned, the code I have written for this software
- * can be used freely for any purpose. Any derived versions of this
- * software must be clearly marked as such, and if the derived work is
- * incompatible with the protocol description in the RFC file, it must be
- * called by a name other than "ssh" or "Secure Shell".
- */
-
-/*
- * Copyright (c) 2000 Markus Friedl. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <ctype.h>
-#include <string.h>
-#include <sys/types.h>
-
-#include "libssh/priv.h"
-
-/*
- * Returns true if the given string matches the pattern (which may contain ?
- * and * as wildcards), and zero if it does not match.
- */
-static int match_pattern(const char *s, const char *pattern) {
- for (;;) {
- /* If at end of pattern, accept if also at end of string. */
- if (!*pattern) {
- return !*s;
- }
-
- if (*pattern == '*') {
- /* Skip the asterisk. */
- pattern++;
-
- /* If at end of pattern, accept immediately. */
- if (!*pattern)
- return 1;
-
- /* If next character in pattern is known, optimize. */
- if (*pattern != '?' && *pattern != '*') {
- /*
- * Look instances of the next character in
- * pattern, and try to match starting from
- * those.
- */
- for (; *s; s++)
- if (*s == *pattern && match_pattern(s + 1, pattern + 1)) {
- return 1;
- }
- /* Failed. */
- return 0;
- }
- /*
- * Move ahead one character at a time and try to
- * match at each position.
- */
- for (; *s; s++) {
- if (match_pattern(s, pattern)) {
- return 1;
- }
- }
- /* Failed. */
- return 0;
- }
- /*
- * There must be at least one more character in the string.
- * If we are at the end, fail.
- */
- if (!*s) {
- return 0;
- }
-
- /* Check if the next character of the string is acceptable. */
- if (*pattern != '?' && *pattern != *s) {
- return 0;
- }
-
- /* Move to the next character, both in string and in pattern. */
- s++;
- pattern++;
- }
-
- /* NOTREACHED */
-}
-
-/*
- * Tries to match the string against the comma-separated sequence of subpatterns
- * (each possibly preceded by ! to indicate negation).
- * Returns -1 if negation matches, 1 if there is a positive match, 0 if there is
- * no match at all.
- */
-static int match_pattern_list(const char *string, const char *pattern,
- unsigned int len, int dolower) {
- char sub[1024];
- int negated;
- int got_positive;
- unsigned int i, subi;
-
- got_positive = 0;
- for (i = 0; i < len;) {
- /* Check if the subpattern is negated. */
- if (pattern[i] == '!') {
- negated = 1;
- i++;
- } else {
- negated = 0;
- }
-
- /*
- * Extract the subpattern up to a comma or end. Convert the
- * subpattern to lowercase.
- */
- for (subi = 0;
- i < len && subi < sizeof(sub) - 1 && pattern[i] != ',';
- subi++, i++) {
- sub[subi] = dolower && isupper(pattern[i]) ?
- (char)tolower(pattern[i]) : pattern[i];
- }
-
- /* If subpattern too long, return failure (no match). */
- if (subi >= sizeof(sub) - 1) {
- return 0;
- }
-
- /* If the subpattern was terminated by a comma, skip the comma. */
- if (i < len && pattern[i] == ',') {
- i++;
- }
-
- /* Null-terminate the subpattern. */
- sub[subi] = '\0';
-
- /* Try to match the subpattern against the string. */
- if (match_pattern(string, sub)) {
- if (negated) {
- return -1; /* Negative */
- } else {
- got_positive = 1; /* Positive */
- }
- }
- }
-
- /*
- * Return success if got a positive match. If there was a negative
- * match, we have already returned -1 and never get here.
- */
- return got_positive;
-}
-
-/*
- * Tries to match the host name (which must be in all lowercase) against the
- * comma-separated sequence of subpatterns (each possibly preceded by ! to
- * indicate negation).
- * Returns -1 if negation matches, 1 if there is a positive match, 0 if there
- * is no match at all.
- */
-int match_hostname(const char *host, const char *pattern, unsigned int len) {
- return match_pattern_list(host, pattern, len, 1);
-}
-
-/* vim: set ts=2 sw=2 et cindent: */
diff --git a/libssh/messages.c b/libssh/messages.c
deleted file mode 100644
index 027daf24..00000000
--- a/libssh/messages.c
+++ /dev/null
@@ -1,848 +0,0 @@
-/*
- * messages.c - message parsion for the server
- *
- * This file is part of the SSH Library
- *
- * Copyright (c) 2003-2009 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 <string.h>
-#include <stdlib.h>
-
-#ifndef _WIN32
-#include <arpa/inet.h>
-#endif
-
-#include "libssh/libssh.h"
-#include "libssh/priv.h"
-#include "libssh/ssh2.h"
-#include "libssh/buffer.h"
-#include "libssh/packet.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"
-
-/**
- * @defgroup libssh_messages The SSH message functions
- * @ingroup libssh
- *
- * This file contains the Message parsing utilities for server programs using
- * libssh. The main loop of the program will call ssh_message_get(session) to
- * get messages as they come. they are not 1-1 with the protocol messages.
- * then, the user will know what kind of a message it is and use the appropriate
- * functions to handle it (or use the default handlers if she doesn't know what to
- * do
- *
- * @{
- */
-
-static ssh_message ssh_message_new(ssh_session session){
- ssh_message msg = malloc(sizeof(struct ssh_message_struct));
- if (msg == NULL) {
- return NULL;
- }
- ZERO_STRUCTP(msg);
- msg->session = session;
- return msg;
-}
-
-SSH_PACKET_CALLBACK(ssh_packet_service_request){
- ssh_string service = NULL;
- char *service_c = NULL;
- ssh_message msg=NULL;
-
- enter_function();
- (void)type;
- (void)user;
- service = buffer_get_ssh_string(packet);
- if (service == NULL) {
- ssh_set_error(session, SSH_FATAL, "Invalid SSH_MSG_SERVICE_REQUEST packet");
- goto error;
- }
-
- service_c = ssh_string_to_char(service);
- if (service_c == NULL) {
- goto error;
- }
- ssh_log(session, SSH_LOG_PACKET,
- "Received a SERVICE_REQUEST for service %s", service_c);
- msg=ssh_message_new(session);
- if(!msg){
- SAFE_FREE(service_c);
- goto error;
- }
- msg->type=SSH_REQUEST_SERVICE;
- msg->service_request.service=service_c;
-error:
- ssh_string_free(service);
- if(msg != NULL)
- ssh_message_queue(session,msg);
- leave_function();
- return SSH_PACKET_USED;
-}
-
-/**
- * @internal
- *
- * @brief Handle a SSH_MSG_MSG_USERAUTH_REQUEST packet and queue a
- * SSH Message
- */
-SSH_PACKET_CALLBACK(ssh_packet_userauth_request){
- ssh_string user_s = NULL;
- ssh_string service = NULL;
- ssh_string method = NULL;
- ssh_message msg = NULL;
- char *service_c = NULL;
- char *method_c = NULL;
- uint32_t method_size = 0;
-
- enter_function();
-
- (void)user;
- (void)type;
- msg = ssh_message_new(session);
- if (msg == NULL) {
- ssh_set_error_oom(session);
- goto error;
- }
-
- user_s = buffer_get_ssh_string(packet);
- if (user_s == NULL) {
- goto error;
- }
- service = buffer_get_ssh_string(packet);
- if (service == NULL) {
- goto error;
- }
- method = buffer_get_ssh_string(packet);
- if (method == NULL) {
- goto error;
- }
-
- msg->type = SSH_REQUEST_AUTH;
- msg->auth_request.username = ssh_string_to_char(user_s);
- if (msg->auth_request.username == NULL) {
- goto error;
- }
- ssh_string_free(user_s);
- user_s = NULL;
-
- service_c = ssh_string_to_char(service);
- if (service_c == NULL) {
- goto error;
- }
- method_c = ssh_string_to_char(method);
- if (method_c == NULL) {
- goto error;
- }
- method_size = ssh_string_len(method);
-
- ssh_string_free(service);
- service = NULL;
- ssh_string_free(method);
- method = NULL;
-
- ssh_log(session, SSH_LOG_PACKET,
- "Auth request for service %s, method %s for user '%s'",
- service_c, method_c,
- msg->auth_request.username);
-
-
- if (strncmp(method_c, "none", method_size) == 0) {
- msg->auth_request.method = SSH_AUTH_METHOD_NONE;
- SAFE_FREE(service_c);
- SAFE_FREE(method_c);
- goto end;
- }
-
- if (strncmp(method_c, "password", method_size) == 0) {
- ssh_string pass = NULL;
- uint8_t tmp;
-
- msg->auth_request.method = SSH_AUTH_METHOD_PASSWORD;
- SAFE_FREE(service_c);
- SAFE_FREE(method_c);
- buffer_get_u8(packet, &tmp);
- pass = buffer_get_ssh_string(packet);
- if (pass == NULL) {
- goto error;
- }
- msg->auth_request.password = ssh_string_to_char(pass);
- ssh_string_burn(pass);
- ssh_string_free(pass);
- pass = NULL;
- if (msg->auth_request.password == NULL) {
- goto error;
- }
- goto end;
- }
-
- if (strncmp(method_c, "publickey", method_size) == 0) {
- ssh_string algo = NULL;
- ssh_string publickey = NULL;
- uint8_t has_sign;
-
- msg->auth_request.method = SSH_AUTH_METHOD_PUBLICKEY;
- SAFE_FREE(method_c);
- buffer_get_u8(packet, &has_sign);
- algo = buffer_get_ssh_string(packet);
- if (algo == NULL) {
- goto error;
- }
- publickey = buffer_get_ssh_string(packet);
- if (publickey == NULL) {
- ssh_string_free(algo);
- algo = NULL;
- goto error;
- }
- msg->auth_request.public_key = publickey_from_string(session, publickey);
- ssh_string_free(algo);
- algo = NULL;
- ssh_string_free(publickey);
- publickey = NULL;
- if (msg->auth_request.public_key == NULL) {
- goto error;
- }
- msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_NONE;
- // has a valid signature ?
- if(has_sign) {
- SIGNATURE *signature = NULL;
- ssh_public_key public_key = msg->auth_request.public_key;
- ssh_string sign = NULL;
- ssh_buffer digest = NULL;
-
- sign = buffer_get_ssh_string(packet);
- if(sign == NULL) {
- ssh_log(session, SSH_LOG_PACKET, "Invalid signature packet from peer");
- msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_ERROR;
- goto error;
- }
- signature = signature_from_string(session, sign, public_key,
- public_key->type);
- digest = ssh_userauth_build_digest(session, msg, service_c);
- if ((digest == NULL || signature == NULL) ||
- (digest != NULL && signature != NULL &&
- sig_verify(session, public_key, signature,
- ssh_buffer_get_begin(digest), ssh_buffer_get_len(digest)) < 0)) {
- ssh_log(session, SSH_LOG_PACKET, "Wrong signature from peer");
-
- ssh_string_free(sign);
- sign = NULL;
- ssh_buffer_free(digest);
- digest = NULL;
- signature_free(signature);
- signature = NULL;
-
- msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_WRONG;
- goto error;
- }
- else
- ssh_log(session, SSH_LOG_PACKET, "Valid signature received");
-
- ssh_buffer_free(digest);
- digest = NULL;
- ssh_string_free(sign);
- sign = NULL;
- signature_free(signature);
- signature = NULL;
-
- msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_VALID;
- }
- SAFE_FREE(service_c);
- goto end;
- }
-
- msg->auth_request.method = SSH_AUTH_METHOD_UNKNOWN;
- SAFE_FREE(method_c);
- goto end;
-error:
- ssh_string_free(user_s);
- ssh_string_free(service);
- ssh_string_free(method);
-
- SAFE_FREE(method_c);
- SAFE_FREE(service_c);
-
- ssh_message_free(msg);
-
- leave_function();
- return SSH_PACKET_USED;
-end:
- ssh_message_queue(session,msg);
- leave_function();
- return SSH_PACKET_USED;
-}
-
-SSH_PACKET_CALLBACK(ssh_packet_channel_open){
- ssh_message msg = NULL;
- ssh_string type_s = NULL, originator = NULL, destination = NULL;
- char *type_c = NULL;
- uint32_t sender, window, packet_size, originator_port, destination_port;
-
- enter_function();
- (void)type;
- (void)user;
- msg = ssh_message_new(session);
- if (msg == NULL) {
- ssh_set_error_oom(session);
- goto error;
- }
-
- msg->type = SSH_REQUEST_CHANNEL_OPEN;
-
- type_s = buffer_get_ssh_string(packet);
- if (type_s == NULL) {
- ssh_set_error_oom(session);
- goto error;
- }
- type_c = ssh_string_to_char(type_s);
- if (type_c == NULL) {
- ssh_set_error_oom(session);
- goto error;
- }
-
- ssh_log(session, SSH_LOG_PACKET,
- "Clients wants to open a %s channel", type_c);
- ssh_string_free(type_s);
- type_s=NULL;
-
- buffer_get_u32(packet, &sender);
- buffer_get_u32(packet, &window);
- buffer_get_u32(packet, &packet_size);
-
- msg->channel_request_open.sender = ntohl(sender);
- msg->channel_request_open.window = ntohl(window);
- msg->channel_request_open.packet_size = ntohl(packet_size);
-
- if (strcmp(type_c,"session") == 0) {
- msg->channel_request_open.type = SSH_CHANNEL_SESSION;
- SAFE_FREE(type_c);
- goto end;
- }
-
- if (strcmp(type_c,"direct-tcpip") == 0) {
- destination = buffer_get_ssh_string(packet);
- if (destination == NULL) {
- ssh_set_error_oom(session);
- goto error;
- }
- msg->channel_request_open.destination = ssh_string_to_char(destination);
- if (msg->channel_request_open.destination == NULL) {
- ssh_set_error_oom(session);
- ssh_string_free(destination);
- goto error;
- }
- ssh_string_free(destination);
-
- buffer_get_u32(packet, &destination_port);
- msg->channel_request_open.destination_port = ntohl(destination_port);
-
- originator = buffer_get_ssh_string(packet);
- if (originator == NULL) {
- ssh_set_error_oom(session);
- goto error;
- }
- msg->channel_request_open.originator = ssh_string_to_char(originator);
- if (msg->channel_request_open.originator == NULL) {
- ssh_set_error_oom(session);
- ssh_string_free(originator);
- goto error;
- }
- ssh_string_free(originator);
-
- buffer_get_u32(packet, &originator_port);
- msg->channel_request_open.originator_port = ntohl(originator_port);
-
- msg->channel_request_open.type = SSH_CHANNEL_DIRECT_TCPIP;
- goto end;
- }
-
- if (strcmp(type_c,"forwarded-tcpip") == 0) {
- destination = buffer_get_ssh_string(packet);
- if (destination == NULL) {
- ssh_set_error_oom(session);
- goto error;
- }
- msg->channel_request_open.destination = ssh_string_to_char(destination);
- if (msg->channel_request_open.destination == NULL) {
- ssh_set_error_oom(session);
- ssh_string_free(destination);
- goto error;
- }
- ssh_string_free(destination);
-
- buffer_get_u32(packet, &destination_port);
- msg->channel_request_open.destination_port = ntohl(destination_port);
-
- originator = buffer_get_ssh_string(packet);
- if (originator == NULL) {
- ssh_set_error_oom(session);
- goto error;
- }
- msg->channel_request_open.originator = ssh_string_to_char(originator);
- if (msg->channel_request_open.originator == NULL) {
- ssh_set_error_oom(session);
- ssh_string_free(originator);
- goto error;
- }
- ssh_string_free(originator);
-
- buffer_get_u32(packet, &originator_port);
- msg->channel_request_open.originator_port = ntohl(originator_port);
-
- msg->channel_request_open.type = SSH_CHANNEL_FORWARDED_TCPIP;
- goto end;
- }
-
- if (strcmp(type_c,"x11") == 0) {
- originator = buffer_get_ssh_string(packet);
- if (originator == NULL) {
- ssh_set_error_oom(session);
- goto error;
- }
- msg->channel_request_open.originator = ssh_string_to_char(originator);
- if (msg->channel_request_open.originator == NULL) {
- ssh_set_error_oom(session);
- ssh_string_free(originator);
- goto error;
- }
- ssh_string_free(originator);
-
- buffer_get_u32(packet, &originator_port);
- msg->channel_request_open.originator_port = ntohl(originator_port);
-
- msg->channel_request_open.type = SSH_CHANNEL_X11;
- goto end;
- }
-
- msg->channel_request_open.type = SSH_CHANNEL_UNKNOWN;
- goto end;
-
-error:
- ssh_message_free(msg);
- msg=NULL;
-end:
- if(type_s != NULL)
- ssh_string_free(type_s);
- SAFE_FREE(type_c);
- if(msg != NULL)
- ssh_message_queue(session,msg);
- leave_function();
- return SSH_PACKET_USED;
-}
-
-/* TODO: make this function accept a ssh_channel */
-ssh_channel ssh_message_channel_request_open_reply_accept(ssh_message msg) {
- ssh_session session = msg->session;
- ssh_channel chan = NULL;
-
- enter_function();
-
- if (msg == NULL) {
- leave_function();
- return NULL;
- }
-
- chan = ssh_channel_new(session);
- if (chan == NULL) {
- leave_function();
- return NULL;
- }
-
- chan->local_channel = ssh_channel_new_id(session);
- chan->local_maxpacket = 35000;
- chan->local_window = 32000;
- chan->remote_channel = msg->channel_request_open.sender;
- chan->remote_maxpacket = msg->channel_request_open.packet_size;
- chan->remote_window = msg->channel_request_open.window;
- chan->state = SSH_CHANNEL_STATE_OPEN;
-
- if (buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION) < 0) {
- goto error;
- }
- if (buffer_add_u32(session->out_buffer, htonl(chan->remote_channel)) < 0) {
- goto error;
- }
- if (buffer_add_u32(session->out_buffer, htonl(chan->local_channel)) < 0) {
- goto error;
- }
- if (buffer_add_u32(session->out_buffer, htonl(chan->local_window)) < 0) {
- goto error;
- }
- if (buffer_add_u32(session->out_buffer, htonl(chan->local_maxpacket)) < 0) {
- goto error;
- }
-
- ssh_log(session, SSH_LOG_PACKET,
- "Accepting a channel request_open for chan %d", chan->remote_channel);
-
- if (packet_send(session) == SSH_ERROR) {
- goto error;
- }
-
- leave_function();
- return chan;
-error:
- ssh_channel_free(chan);
-
- leave_function();
- return NULL;
-}
-
-/**
- * @internal
- *
- * @brief This function parses the last end of a channel request packet.
- *
- * This is normally converted to a SSH message and placed in the queue.
- *
- * @param[in] session The SSH session.
- *
- * @param[in] channel The channel the request is made on.
- *
- * @param[in] packet The rest of the packet to be parsed.
- *
- * @param[in] request The type of request.
- *
- * @param[in] want_reply The want_reply field from the request.
- *
- * @returns SSH_OK on success, SSH_ERROR if an error occured.
- */
-int ssh_message_handle_channel_request(ssh_session session, ssh_channel channel, ssh_buffer packet,
- const char *request, uint8_t want_reply) {
- ssh_message msg = NULL;
- enter_function();
- msg = ssh_message_new(session);
- if (msg == NULL) {
- ssh_set_error_oom(session);
- goto error;
- }
-
- ssh_log(session, SSH_LOG_PACKET,
- "Received a %s channel_request for channel (%d:%d) (want_reply=%hhd)",
- request, channel->local_channel, channel->remote_channel, want_reply);
-
- msg->type = SSH_REQUEST_CHANNEL;
- msg->channel_request.channel = channel;
- msg->channel_request.want_reply = want_reply;
-
- if (strcmp(request, "pty-req") == 0) {
- ssh_string term = NULL;
- char *term_c = NULL;
- term = buffer_get_ssh_string(packet);
- if (term == NULL) {
- ssh_set_error_oom(session);
- goto error;
- }
- term_c = ssh_string_to_char(term);
- if (term_c == NULL) {
- ssh_set_error_oom(session);
- ssh_string_free(term);
- goto error;
- }
- ssh_string_free(term);
-
- msg->channel_request.type = SSH_CHANNEL_REQUEST_PTY;
- msg->channel_request.TERM = term_c;
-
- buffer_get_u32(packet, &msg->channel_request.width);
- buffer_get_u32(packet, &msg->channel_request.height);
- buffer_get_u32(packet, &msg->channel_request.pxwidth);
- buffer_get_u32(packet, &msg->channel_request.pxheight);
-
- msg->channel_request.width = ntohl(msg->channel_request.width);
- msg->channel_request.height = ntohl(msg->channel_request.height);
- msg->channel_request.pxwidth = ntohl(msg->channel_request.pxwidth);
- msg->channel_request.pxheight = ntohl(msg->channel_request.pxheight);
- msg->channel_request.modes = buffer_get_ssh_string(packet);
- if (msg->channel_request.modes == NULL) {
- SAFE_FREE(term_c);
- goto error;
- }
- goto end;
- }
-
- if (strcmp(request, "window-change") == 0) {
- msg->channel_request.type = SSH_CHANNEL_REQUEST_WINDOW_CHANGE;
-
- buffer_get_u32(packet, &msg->channel_request.width);
- buffer_get_u32(packet, &msg->channel_request.height);
- buffer_get_u32(packet, &msg->channel_request.pxwidth);
- buffer_get_u32(packet, &msg->channel_request.pxheight);
-
- msg->channel_request.width = ntohl(msg->channel_request.width);
- msg->channel_request.height = ntohl(msg->channel_request.height);
- msg->channel_request.pxwidth = ntohl(msg->channel_request.pxwidth);
- msg->channel_request.pxheight = ntohl(msg->channel_request.pxheight);
-
- goto end;
- }
-
- if (strcmp(request, "subsystem") == 0) {
- ssh_string subsys = NULL;
- char *subsys_c = NULL;
- subsys = buffer_get_ssh_string(packet);
- if (subsys == NULL) {
- ssh_set_error_oom(session);
- goto error;
- }
- subsys_c = ssh_string_to_char(subsys);
- if (subsys_c == NULL) {
- ssh_set_error_oom(session);
- ssh_string_free(subsys);
- goto error;
- }
- ssh_string_free(subsys);
-
- msg->channel_request.type = SSH_CHANNEL_REQUEST_SUBSYSTEM;
- msg->channel_request.subsystem = subsys_c;
-
- goto end;
- }
-
- if (strcmp(request, "shell") == 0) {
- msg->channel_request.type = SSH_CHANNEL_REQUEST_SHELL;
- goto end;
- }
-
- if (strcmp(request, "exec") == 0) {
- ssh_string cmd = NULL;
- cmd = buffer_get_ssh_string(packet);
- if (cmd == NULL) {
- ssh_set_error_oom(session);
- goto error;
- }
- msg->channel_request.type = SSH_CHANNEL_REQUEST_EXEC;
- msg->channel_request.command = ssh_string_to_char(cmd);
- ssh_string_free(cmd);
- if (msg->channel_request.command == NULL) {
- goto error;
- }
- goto end;
- }
-
- if (strcmp(request, "env") == 0) {
- ssh_string name = NULL;
- ssh_string value = NULL;
- name = buffer_get_ssh_string(packet);
- if (name == NULL) {
- ssh_set_error_oom(session);
- goto error;
- }
- value = buffer_get_ssh_string(packet);
- if (value == NULL) {
- ssh_set_error_oom(session);
- ssh_string_free(name);
- goto error;
- }
-
- msg->channel_request.type = SSH_CHANNEL_REQUEST_ENV;
- msg->channel_request.var_name = ssh_string_to_char(name);
- msg->channel_request.var_value = ssh_string_to_char(value);
- if (msg->channel_request.var_name == NULL ||
- msg->channel_request.var_value == NULL) {
- ssh_string_free(name);
- ssh_string_free(value);
- goto error;
- }
- ssh_string_free(name);
- ssh_string_free(value);
-
- goto end;
- }
-
- msg->channel_request.type = SSH_CHANNEL_UNKNOWN;
-end:
- ssh_message_queue(session,msg);
- leave_function();
- return SSH_OK;
-error:
- ssh_message_free(msg);
-
- leave_function();
- return SSH_ERROR;
-}
-
-int ssh_message_channel_request_reply_success(ssh_message msg) {
- uint32_t channel;
-
- if (msg == NULL) {
- return SSH_ERROR;
- }
-
- if (msg->channel_request.want_reply) {
- channel = msg->channel_request.channel->remote_channel;
-
- ssh_log(msg->session, SSH_LOG_PACKET,
- "Sending a channel_request success to channel %d", channel);
-
- if (buffer_add_u8(msg->session->out_buffer, SSH2_MSG_CHANNEL_SUCCESS) < 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 succeeded");
-
- return SSH_OK;
-}
-
-/**
- * @brief Retrieve a SSH message from a SSH session.
- *
- * @param[in] session The SSH session to get the message.
- *
- * @returns The SSH message received, NULL in case of error.
- *
- * @warning This function blocks until a message has been received. Betterset up
- * a callback if this behavior is unwanted.
- */
-ssh_message ssh_message_get(ssh_session session) {
- ssh_message msg = NULL;
- enter_function();
-
- msg=ssh_message_pop_head(session);
- if(msg) {
- leave_function();
- return msg;
- }
- if(session->ssh_message_list == NULL) {
- session->ssh_message_list = ssh_list_new();
- }
- do {
- if (ssh_handle_packets(session,-1) == SSH_ERROR) {
- leave_function();
- return NULL;
- }
- msg=ssh_list_pop_head(ssh_message, session->ssh_message_list);
- } while(msg==NULL);
- leave_function();
- return msg;
-}
-
-int ssh_message_type(ssh_message msg) {
- if (msg == NULL) {
- return -1;
- }
-
- return msg->type;
-}
-
-int ssh_message_subtype(ssh_message msg) {
- if (msg == NULL) {
- return -1;
- }
-
- switch(msg->type) {
- case SSH_REQUEST_AUTH:
- return msg->auth_request.method;
- case SSH_REQUEST_CHANNEL_OPEN:
- return msg->channel_request_open.type;
- case SSH_REQUEST_CHANNEL:
- return msg->channel_request.type;
- }
-
- return -1;
-}
-
-void ssh_message_free(ssh_message msg){
- if (msg == NULL) {
- return;
- }
-
- switch(msg->type) {
- case SSH_REQUEST_AUTH:
- SAFE_FREE(msg->auth_request.username);
- if (msg->auth_request.password) {
- memset(msg->auth_request.password, 0,
- strlen(msg->auth_request.password));
- SAFE_FREE(msg->auth_request.password);
- }
- publickey_free(msg->auth_request.public_key);
- break;
- case SSH_REQUEST_CHANNEL_OPEN:
- SAFE_FREE(msg->channel_request_open.originator);
- SAFE_FREE(msg->channel_request_open.destination);
- break;
- case SSH_REQUEST_CHANNEL:
- SAFE_FREE(msg->channel_request.TERM);
- SAFE_FREE(msg->channel_request.modes);
- SAFE_FREE(msg->channel_request.var_name);
- SAFE_FREE(msg->channel_request.var_value);
- SAFE_FREE(msg->channel_request.command);
- SAFE_FREE(msg->channel_request.subsystem);
- break;
- case SSH_REQUEST_SERVICE:
- SAFE_FREE(msg->service_request.service);
- break;
- }
- ZERO_STRUCTP(msg);
- SAFE_FREE(msg);
-}
-
-/**
- * @internal
- *
- * @brief Add a message to the current queue of messages to be parsed.
- *
- * @param[in] session The SSH session to add the message.
- *
- * @param[in] message The message to add to the queue.
- */
-void ssh_message_queue(ssh_session session, ssh_message message){
- if(message){
- if(session->ssh_message_list == NULL){
- session->ssh_message_list=ssh_list_new();
- }
- ssh_list_append(session->ssh_message_list, message);
- }
-}
-
-/**
- * @internal
- *
- * @brief Pop a message from the message list and dequeue it.
- *
- * @param[in] session The SSH session to pop the message.
- *
- * @returns The head message or NULL if it doesn't exist.
- */
-ssh_message ssh_message_pop_head(ssh_session session){
- ssh_message msg=NULL;
- struct ssh_iterator *i;
- if(session->ssh_message_list == NULL)
- return NULL;
- i=ssh_list_get_iterator(session->ssh_message_list);
- if(i != NULL){
- msg=ssh_iterator_value(ssh_message,i);
- ssh_list_remove(session->ssh_message_list,i);
- }
- return msg;
-}
-
-/** @} */
-
-/* vim: set ts=4 sw=4 et cindent: */
diff --git a/libssh/misc.c b/libssh/misc.c
deleted file mode 100644
index bd903b02..00000000
--- a/libssh/misc.c
+++ /dev/null
@@ -1,685 +0,0 @@
-/*
- * misc.c - useful client functions
- *
- * This file is part of the SSH Library
- *
- * Copyright (c) 2003-2009 by Aris Adamantiadis
- * Copyright (c) 2008-2009 by Andreas Schneider <mail@cynapses.org>
- *
- * 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 <limits.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <ctype.h>
-
-#ifdef _WIN32
-#define _WIN32_IE 0x0501 //SHGetSpecialFolderPath
-#include <winsock2.h> // Must be the first to include
-#include <ws2tcpip.h>
-#include <shlobj.h>
-#include <direct.h>
-#if _MSC_VER >= 1400
-#include <io.h>
-#endif /* _MSC_VER */
-#else /* _WIN32 */
-/* This is needed for a standard getpwuid_r on opensolaris */
-#define _POSIX_PTHREAD_SEMANTICS
-#include <pwd.h>
-#include <arpa/inet.h>
-#endif /* _WIN32 */
-
-#include "libssh/priv.h"
-#include "libssh/misc.h"
-#include "libssh/session.h"
-
-#ifdef HAVE_LIBGCRYPT
-#define GCRYPT_STRING "/gnutls"
-#else
-#define GCRYPT_STRING ""
-#endif
-
-#ifdef HAVE_LIBCRYPTO
-#define CRYPTO_STRING "/openssl"
-#else
-#define CRYPTO_STRING ""
-#endif
-
-#if defined(HAVE_LIBZ) && defined(WITH_LIBZ)
-#define LIBZ_STRING "/zlib"
-#else
-#define LIBZ_STRING ""
-#endif
-
-/**
- * @defgroup libssh_misc The SSH helper functions.
- * @ingroup libssh
- *
- * Different helper functions used in the SSH Library.
- *
- * @{
- */
-
-#ifdef _WIN32
-char *ssh_get_user_home_dir(void) {
- char tmp[MAX_PATH] = {0};
- char *szPath = NULL;
-
- if (SHGetSpecialFolderPathA(NULL, tmp, CSIDL_PROFILE, TRUE)) {
- szPath = malloc(strlen(tmp) + 1);
- if (szPath == NULL) {
- return NULL;
- }
-
- strcpy(szPath, tmp);
- return szPath;
- }
-
- return NULL;
-}
-
-/* we have read access on file */
-int ssh_file_readaccess_ok(const char *file) {
- if (_access(file, 4) < 0) {
- return 0;
- }
-
- return 1;
-}
-
-#define SSH_USEC_IN_SEC 1000000LL
-#define SSH_SECONDS_SINCE_1601 11644473600LL
-
-int gettimeofday(struct timeval *__p, void *__t) {
- union {
- unsigned long long ns100; /* time since 1 Jan 1601 in 100ns units */
- FILETIME ft;
- } now;
-
- GetSystemTimeAsFileTime (&now.ft);
- __p->tv_usec = (long) ((now.ns100 / 10LL) % SSH_USEC_IN_SEC);
- __p->tv_sec = (long)(((now.ns100 / 10LL ) / SSH_USEC_IN_SEC) - SSH_SECONDS_SINCE_1601);
-
- return (0);
-}
-
-char *ssh_get_local_username(ssh_session session) {
- DWORD size = 0;
- char *user;
-
- /* get the size */
- GetUserName(NULL, &size);
-
- user = malloc(size);
- if (user == NULL) {
- ssh_set_error_oom(session);
- return NULL;
- }
-
- if (GetUserName(user, &size)) {
- return user;
- }
-
- return NULL;
-}
-#else /* _WIN32 */
-
-#ifndef NSS_BUFLEN_PASSWD
-#define NSS_BUFLEN_PASSWD 4096
-#endif /* NSS_BUFLEN_PASSWD */
-
-char *ssh_get_user_home_dir(void) {
- char *szPath = NULL;
- struct passwd pwd;
- struct passwd *pwdbuf;
- char buf[NSS_BUFLEN_PASSWD];
- int rc;
-
- rc = getpwuid_r(getuid(), &pwd, buf, NSS_BUFLEN_PASSWD, &pwdbuf);
- if (rc != 0) {
- return NULL;
- }
-
- szPath = strdup(pwd.pw_dir);
-
- return szPath;
-}
-
-/* we have read access on file */
-int ssh_file_readaccess_ok(const char *file) {
- if (access(file, R_OK) < 0) {
- return 0;
- }
-
- return 1;
-}
-
-char *ssh_get_local_username(ssh_session session) {
- struct passwd pwd;
- struct passwd *pwdbuf;
- char buf[NSS_BUFLEN_PASSWD];
- char *name;
- int rc;
-
- rc = getpwuid_r(getuid(), &pwd, buf, NSS_BUFLEN_PASSWD, &pwdbuf);
- if (rc != 0) {
- ssh_set_error(session, SSH_FATAL,
- "Couldn't retrieve information for current user!");
- return NULL;
- }
-
- name = strdup(pwd.pw_name);
-
- if (name == NULL) {
- ssh_set_error_oom(session);
- return NULL;
- }
-
- return name;
-}
-#endif /* _WIN32 */
-
-uint64_t ntohll(uint64_t a) {
-#ifdef WORDS_BIGENDIAN
- return a;
-#else
- uint32_t low = (uint32_t)(a & 0xffffffff);
- uint32_t high = (uint32_t)(a >> 32);
- low = ntohl(low);
- high = ntohl(high);
-
- return ((((uint64_t) low) << 32) | ( high));
-#endif
-}
-
-char *ssh_lowercase(const char* str) {
- char *new, *p;
-
- if (str == NULL) {
- return NULL;
- }
-
- new = strdup(str);
- if (new == NULL) {
- return NULL;
- }
-
- for (p = new; *p; p++) {
- *p = tolower(*p);
- }
-
- return new;
-}
-
-char *ssh_hostport(const char *host, int port){
- char *dest;
- size_t len;
- if(host==NULL)
- return NULL;
- /* 3 for []:, 5 for 65536 and 1 for nul */
- len=strlen(host) + 3 + 5 + 1;
- dest=malloc(len);
- if(dest==NULL)
- return NULL;
- snprintf(dest,len,"[%s]:%d",host,port);
- return dest;
-}
-
-/**
- * @brief Check if libssh is the required version or get the version
- * string.
- *
- * @param[in] req_version The version required.
- *
- * @return If the version of libssh is newer than the version
- * required it will return a version string.
- * NULL if the version is older.
- *
- * Example:
- *
- * @code
- * if (ssh_version(SSH_VERSION_INT(0,2,1)) == NULL) {
- * fprintf(stderr, "libssh version is too old!\n");
- * exit(1);
- * }
- *
- * if (debug) {
- * printf("libssh %s\n", ssh_version(0));
- * }
- * @endcode
- */
-const char *ssh_version(int req_version) {
- if (req_version <= LIBSSH_VERSION_INT) {
- return SSH_STRINGIFY(LIBSSH_VERSION) GCRYPT_STRING CRYPTO_STRING
- LIBZ_STRING;
- }
-
- return NULL;
-}
-
-struct ssh_list *ssh_list_new(){
- struct ssh_list *ret=malloc(sizeof(struct ssh_list));
- if(!ret)
- return NULL;
- ret->root=ret->end=NULL;
- return ret;
-}
-
-void ssh_list_free(struct ssh_list *list){
- struct ssh_iterator *ptr,*next;
- ptr=list->root;
- while(ptr){
- next=ptr->next;
- SAFE_FREE(ptr);
- ptr=next;
- }
- SAFE_FREE(list);
-}
-
-struct ssh_iterator *ssh_list_get_iterator(const struct ssh_list *list){
- return list->root;
-}
-
-static struct ssh_iterator *ssh_iterator_new(const void *data){
- struct ssh_iterator *iterator=malloc(sizeof(struct ssh_iterator));
- if(!iterator)
- return NULL;
- iterator->next=NULL;
- iterator->data=data;
- return iterator;
-}
-
-int ssh_list_append(struct ssh_list *list,const void *data){
- struct ssh_iterator *iterator=ssh_iterator_new(data);
- if(!iterator)
- return SSH_ERROR;
- if(!list->end){
- /* list is empty */
- list->root=list->end=iterator;
- } else {
- /* put it on end of list */
- list->end->next=iterator;
- list->end=iterator;
- }
- return SSH_OK;
-}
-
-int ssh_list_prepend(struct ssh_list *list, const void *data){
- struct ssh_iterator *it = ssh_iterator_new(data);
-
- if (it == NULL) {
- return SSH_ERROR;
- }
-
- if (list->end == NULL) {
- /* list is empty */
- list->root = list->end = it;
- } else {
- /* set as new root */
- it->next = list->root;
- list->root = it;
- }
-
- return SSH_OK;
-}
-
-void ssh_list_remove(struct ssh_list *list, struct ssh_iterator *iterator){
- struct ssh_iterator *ptr,*prev;
- prev=NULL;
- ptr=list->root;
- while(ptr && ptr != iterator){
- prev=ptr;
- ptr=ptr->next;
- }
- if(!ptr){
- /* we did not find the element */
- return;
- }
- /* unlink it */
- if(prev)
- prev->next=ptr->next;
- /* if iterator was the head */
- if(list->root == iterator)
- list->root=iterator->next;
- /* if iterator was the tail */
- if(list->end == iterator)
- list->end = prev;
- SAFE_FREE(iterator);
-}
-
-/**
- * @internal
- *
- * @brief Removes the top element of the list and returns the data value
- * attached to it.
- *
- * @param[in[ list The ssh_list to remove the element.
- *
- * @returns A pointer to the element being stored in head, or NULL
- * if the list is empty.
- */
-const void *_ssh_list_pop_head(struct ssh_list *list){
- struct ssh_iterator *iterator=list->root;
- const void *data;
- if(!list->root)
- return NULL;
- data=iterator->data;
- list->root=iterator->next;
- if(list->end==iterator)
- list->end=NULL;
- SAFE_FREE(iterator);
- return data;
-}
-
-/**
- * @brief Parse directory component.
- *
- * dirname breaks a null-terminated pathname string into a directory component.
- * In the usual case, ssh_dirname() returns the string up to, but not including,
- * the final '/'. Trailing '/' characters are not counted as part of the
- * pathname. The caller must free the memory.
- *
- * @param[in] path The path to parse.
- *
- * @return The dirname of path or NULL if we can't allocate memory.
- * If path does not contain a slash, c_dirname() returns
- * the string ".". If path is the string "/", it returns
- * the string "/". If path is NULL or an empty string,
- * "." is returned.
- */
-char *ssh_dirname (const char *path) {
- char *new = NULL;
- unsigned int len;
-
- if (path == NULL || *path == '\0') {
- return strdup(".");
- }
-
- len = strlen(path);
-
- /* Remove trailing slashes */
- while(len > 0 && path[len - 1] == '/') --len;
-
- /* We have only slashes */
- if (len == 0) {
- return strdup("/");
- }
-
- /* goto next slash */
- while(len > 0 && path[len - 1] != '/') --len;
-
- if (len == 0) {
- return strdup(".");
- } else if (len == 1) {
- return strdup("/");
- }
-
- /* Remove slashes again */
- while(len > 0 && path[len - 1] == '/') --len;
-
- new = malloc(len + 1);
- if (new == NULL) {
- return NULL;
- }
-
- strncpy(new, path, len);
- new[len] = '\0';
-
- return new;
-}
-
-/**
- * @brief basename - parse filename component.
- *
- * basename breaks a null-terminated pathname string into a filename component.
- * ssh_basename() returns the component following the final '/'. Trailing '/'
- * characters are not counted as part of the pathname.
- *
- * @param[in] path The path to parse.
- *
- * @return The filename of path or NULL if we can't allocate
- * memory. If path is a the string "/", basename returns
- * the string "/". If path is NULL or an empty string,
- * "." is returned.
- */
-char *ssh_basename (const char *path) {
- char *new = NULL;
- const char *s;
- unsigned int len;
-
- if (path == NULL || *path == '\0') {
- return strdup(".");
- }
-
- len = strlen(path);
- /* Remove trailing slashes */
- while(len > 0 && path[len - 1] == '/') --len;
-
- /* We have only slashes */
- if (len == 0) {
- return strdup("/");
- }
-
- while(len > 0 && path[len - 1] != '/') --len;
-
- if (len > 0) {
- s = path + len;
- len = strlen(s);
-
- while(len > 0 && s[len - 1] == '/') --len;
- } else {
- return strdup(path);
- }
-
- new = malloc(len + 1);
- if (new == NULL) {
- return NULL;
- }
-
- strncpy(new, s, len);
- new[len] = '\0';
-
- return new;
-}
-
-/**
- * @brief Attempts to create a directory with the given pathname.
- *
- * This is the portable version of mkdir, mode is ignored on Windows systems.
- *
- * @param[in] pathname The path name to create the directory.
- *
- * @param[in] mode The permissions to use.
- *
- * @return 0 on success, < 0 on error with errno set.
- */
-int ssh_mkdir(const char *pathname, mode_t mode) {
- int r;
-
-#ifdef _WIN32
- r = _mkdir(pathname);
-#else
- r = mkdir(pathname, mode);
-#endif
-
- return r;
-}
-
-/**
- * @brief Expand a directory starting with a tilde '~'
- *
- * @param[in] d The directory to expand.
- *
- * @return The expanded directory, NULL on error.
- */
-char *ssh_path_expand_tilde(const char *d) {
- char *h, *r;
- const char *p;
- size_t ld;
- size_t lh = 0;
-
- if (d[0] != '~') {
- return strdup(d);
- }
- d++;
-
- /* handle ~user/path */
- p = strchr(d, '/');
- if (p != NULL && p > d) {
-#ifdef _WIN32
- return strdup(d);
-#else
- struct passwd *pw;
- size_t s = p - d;
- char u[128];
-
- if (s > sizeof(u)) {
- return NULL;
- }
- memcpy(u, d, s);
- u[s] = '\0';
- pw = getpwnam(u);
- if (pw == NULL) {
- return NULL;
- }
- ld = strlen(p);
- h = strdup(pw->pw_dir);
-#endif
- } else {
- ld = strlen(d);
- p = (char *) d;
- h = ssh_get_user_home_dir();
- }
- if (h == NULL) {
- return NULL;
- }
- lh = strlen(h);
-
- r = malloc(ld + lh + 1);
- if (r == NULL) {
- return NULL;
- }
-
- if (lh > 0) {
- memcpy(r, h, lh);
- }
- memcpy(r + lh, p, ld + 1);
-
- return r;
-}
-
-char *ssh_path_expand_escape(ssh_session session, const char *s) {
-#define MAX_BUF_SIZE 4096
- char host[NI_MAXHOST];
- char buf[MAX_BUF_SIZE];
- char *r, *x = NULL;
- const char *p;
- size_t i, l;
-
- r = ssh_path_expand_tilde(s);
- if (r == NULL) {
- ssh_set_error_oom(session);
- return NULL;
- }
-
- if (strlen(r) > MAX_BUF_SIZE) {
- ssh_set_error(session, SSH_FATAL, "string to expand too long");
- free(r);
- return NULL;
- }
-
- p = r;
- buf[0] = '\0';
-
- for (i = 0; *p != '\0'; p++) {
- if (*p != '%') {
- buf[i] = *p;
- i++;
- if (i > MAX_BUF_SIZE) {
- return NULL;
- }
- buf[i] = '\0';
- continue;
- }
-
- p++;
- if (*p == '\0') {
- break;
- }
-
- switch (*p) {
- case 'd':
- x = strdup(session->sshdir);
- break;
- case 'u':
- x = ssh_get_local_username(session);
- break;
- case 'l':
- if (gethostname(host, sizeof(host) == 0)) {
- x = strdup(host);
- }
- break;
- case 'h':
- x = strdup(session->host);
- break;
- case 'r':
- x = strdup(session->username);
- break;
- case 'p':
- if (session->port < 65536) {
- char tmp[6];
-
- snprintf(tmp, sizeof(tmp), "%u", session->port);
- x = strdup(tmp);
- }
- break;
- default:
- ssh_set_error(session, SSH_FATAL,
- "Wrong escape sequence detected");
- return NULL;
- }
-
- if (x == NULL) {
- ssh_set_error_oom(session);
- return NULL;
- }
-
- i += strlen(x);
- if (i > MAX_BUF_SIZE) {
- ssh_set_error(session, SSH_FATAL,
- "String too long");
- return NULL;
- }
- l = strlen(buf);
- strcat(buf + l, x);
- buf[i] = '\0';
- SAFE_FREE(x);
- }
-
- free(r);
- return strdup(buf);
-#undef MAX_BUF_SIZE
-}
-
-/** @} */
-
-/* vim: set ts=4 sw=4 et cindent: */
diff --git a/libssh/options.c b/libssh/options.c
deleted file mode 100644
index 9cbaf6f2..00000000
--- a/libssh/options.c
+++ /dev/null
@@ -1,1138 +0,0 @@
-/*
- * options.c - handle pre-connection options
- *
- * This file is part of the SSH Library
- *
- * Copyright (c) 2003-2008 by Aris Adamantiadis
- * Copyright (c) 2009 by Andreas Schneider <mail@cynapses.org>
- *
- * 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 <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#ifndef _WIN32
-#include <pwd.h>
-#else
-#include <winsock2.h>
-#endif
-#include <sys/types.h>
-#include "libssh/priv.h"
-#include "libssh/session.h"
-#include "libssh/misc.h"
-#ifdef WITH_SERVER
-#include "libssh/server.h"
-#endif
-
-/**
- * @addtogroup libssh_session
- * @{
- */
-
-/**
- * @brief Duplicate the options of a session structure.
- *
- * If you make several sessions with the same options this is useful. You
- * cannot use twice the same option structure in ssh_session_connect.
- *
- * @param src The session to use to copy the options.
- *
- * @param dest The session to copy the options to.
- *
- * @returns 0 on sucess, -1 on error with errno set.
- *
- * @see ssh_session_connect()
- */
-int ssh_options_copy(ssh_session src, ssh_session *dest) {
- ssh_session new;
- int i;
-
- if (src == NULL || dest == NULL || *dest == NULL) {
- return -1;
- }
-
- new = *dest;
-
- if (src->username) {
- new->username = strdup(src->username);
- if (new->username == NULL) {
- return -1;
- }
- }
-
- if (src->host) {
- new->host = strdup(src->host);
- if (new->host == NULL) {
- return -1;
- }
- }
-
- if (src->identity) {
- struct ssh_iterator *it;
-
- new->identity = ssh_list_new();
- if (new->identity == NULL) {
- return -1;
- }
-
- it = ssh_list_get_iterator(src->identity);
- while (it) {
- char *id;
- int rc;
-
- id = strdup((char *) it->data);
- if (id == NULL) {
- return -1;
- }
-
- rc = ssh_list_append(new->identity, id);
- if (rc < 0) {
- return -1;
- }
- it = it->next;
- }
- }
-
- if (src->sshdir) {
- new->sshdir = strdup(src->sshdir);
- if (new->sshdir == NULL) {
- return -1;
- }
- }
-
- if (src->knownhosts) {
- new->knownhosts = strdup(src->knownhosts);
- if (new->knownhosts == NULL) {
- return -1;
- }
- }
-
- for (i = 0; i < 10; ++i) {
- if (src->wanted_methods[i]) {
- new->wanted_methods[i] = strdup(src->wanted_methods[i]);
- if (new->wanted_methods[i] == NULL) {
- return -1;
- }
- }
- }
-
- if(src->ProxyCommand) {
- new->ProxyCommand = strdup(src->ProxyCommand);
- if(new->ProxyCommand == NULL)
- return -1;
- }
- new->fd = src->fd;
- new->port = src->port;
- new->callbacks = src->callbacks;
- new->timeout = src->timeout;
- new->timeout_usec = src->timeout_usec;
- new->ssh2 = src->ssh2;
- new->ssh1 = src->ssh1;
- new->log_verbosity = src->log_verbosity;
-
- return 0;
-}
-
-int ssh_options_set_algo(ssh_session session, int algo,
- const char *list) {
- if (!verify_existing_algo(algo, list)) {
- ssh_set_error(session, SSH_REQUEST_DENIED,
- "Setting method: no algorithm for method \"%s\" (%s)\n",
- ssh_kex_nums[algo], list);
- return -1;
- }
-
- SAFE_FREE(session->wanted_methods[algo]);
- session->wanted_methods[algo] = strdup(list);
- if (session->wanted_methods[algo] == NULL) {
- ssh_set_error_oom(session);
- return -1;
- }
-
- return 0;
-}
-
-/**
- * @brief This function can set all possible ssh options.
- *
- * @param session An allocated ssh option structure.
- *
- * @param type The option type to set. This could be one of the
- * following:
- *
- * - SSH_OPTIONS_HOST:
- * The hostname or ip address to connect to (string).
- *
- * - SSH_OPTIONS_PORT:
- * The port to connect to (integer).
- *
- * - SSH_OPTIONS_PORT_STR:
- * The port to connect to (string).
- *
- * - SSH_OPTIONS_FD:
- * The file descriptor to use (socket_t).\n
- * \n
- * If you wish to open the socket yourself for a reason
- * or another, set the file descriptor. Don't forget to
- * set the hostname as the hostname is used as a key in
- * the known_host mechanism.
- *
- * - SSH_OPTIONS_BINDADDR:
- * The address to bind the client to (string).
- *
- * - SSH_OPTIONS_USER:
- * The username for authentication (string).\n
- * \n
- * If the value is NULL, the username is set to the
- * default username.
- *
- * - SSH_OPTIONS_SSH_DIR:
- * Set the ssh directory (format string).\n
- * \n
- * If the value is NULL, the directory is set to the
- * default ssh directory.\n
- * \n
- * The ssh directory is used for files like known_hosts
- * and identity (private and public key). It may include
- * "%s" which will be replaced by the user home
- * directory.
- *
- * - SSH_OPTIONS_KNOWNHOSTS:
- * Set the known hosts file name (format string).\n
- * \n
- * If the value is NULL, the directory is set to the
- * default known hosts file, normally
- * ~/.ssh/known_hosts.\n
- * \n
- * The known hosts file is used to certify remote hosts
- * are genuine. It may include "%s" which will be
- * replaced by the user home directory.
- *
- * - SSH_OPTIONS_IDENTITY:
- * Set the identity file name (format string).\n
- * \n
- * By default identity, id_dsa and id_rsa are checked.\n
- * \n
- * The identity file used authenticate with public key.
- * It may include "%s" which will be replaced by the
- * user home directory.
- *
- * - SSH_OPTIONS_TIMEOUT:
- * Set a timeout for the connection in seconds (integer).
- *
- * - SSH_OPTIONS_TIMEOUT_USEC:
- * Set a timeout for the connection in micro seconds
- * (integer).
- *
- * - SSH_OPTIONS_SSH1:
- * Allow or deny the connection to SSH1 servers
- * (integer).
- *
- * - SSH_OPTIONS_SSH2:
- * Allow or deny the connection to SSH2 servers
- * (integer).
- *
- * - SSH_OPTIONS_LOG_VERBOSITY:
- * Set the session logging verbosity (integer).\n
- * \n
- * The verbosity of the messages. Every log smaller or
- * equal to verbosity will be shown.
- * - SSH_LOG_NOLOG: No logging
- * - SSH_LOG_RARE: Rare conditions or warnings
- * - SSH_LOG_ENTRY: API-accessible entrypoints
- * - SSH_LOG_PACKET: Packet id and size
- * - SSH_LOG_FUNCTIONS: Function entering and leaving
- *
- * - SSH_OPTIONS_LOG_VERBOSITY_STR:
- * Set the session logging verbosity (string).\n
- * \n
- * The verbosity of the messages. Every log smaller or
- * equal to verbosity will be shown.
- * - SSH_LOG_NOLOG: No logging
- * - SSH_LOG_RARE: Rare conditions or warnings
- * - SSH_LOG_ENTRY: API-accessible entrypoints
- * - SSH_LOG_PACKET: Packet id and size
- * - SSH_LOG_FUNCTIONS: Function entering and leaving
- * \n
- * See the corresponding numbers in libssh.h.
- *
- * - SSH_OPTTIONS_AUTH_CALLBACK:
- * Set a callback to use your own authentication function
- * (function pointer).
- *
- * - SSH_OPTTIONS_AUTH_USERDATA:
- * Set the user data passed to the authentication
- * function (generic pointer).
- *
- * - SSH_OPTTIONS_LOG_CALLBACK:
- * Set a callback to use your own logging function
- * (function pointer).
- *
- * - SSH_OPTTIONS_LOG_USERDATA:
- * Set the user data passed to the logging function
- * (generic pointer).
- *
- * - SSH_OPTTIONS_STATUS_CALLBACK:
- * Set a callback to show connection status in realtime
- * (function pointer).\n
- * \n
- * @code
- * fn(void *arg, float status)
- * @endcode
- * \n
- * During ssh_connect(), libssh will call the callback
- * with status from 0.0 to 1.0.
- *
- * - SSH_OPTTIONS_STATUS_ARG:
- * Set the status argument which should be passed to the
- * status callback (generic pointer).
- *
- * - SSH_OPTIONS_CIPHERS_C_S:
- * Set the symmetric cipher client to server (string,
- * comma-separated list).
- *
- * - SSH_OPTIONS_CIPHERS_S_C:
- * Set the symmetric cipher server to client (string,
- * comma-separated list).
- *
- * - SSH_OPTIONS_COMPRESSION_C_S:
- * Set the compression to use for client to server
- * communication (string, "none" or "zlib").
- *
- * - SSH_OPTIONS_COMPRESSION_S_C:
- * Set the compression to use for server to client
- * communication (string, "none" or "zlib").
- *
- * - SSH_OPTIONS_HOSTKEYCHECK:
- * Set the parameter StrictHostKeyChecking to avoid
- * asking about a fingerprint
- * - SSH_OPTIONS_PROXYCOMMAND:
- * Set the command to be executed in order to connect to
- * server.
- *
- * @param value The value to set. This is a generic pointer and the
- * datatype which is used should be set according to the
- * type set.
- *
- * @return 0 on success, < 0 on error.
- */
-int ssh_options_set(ssh_session session, enum ssh_options_e type,
- const void *value) {
- char *p, *q;
- long int i;
- int rc;
-
- if (session == NULL) {
- return -1;
- }
-
- switch (type) {
- case SSH_OPTIONS_HOST:
- q = strdup(value);
- if (q == NULL) {
- ssh_set_error_oom(session);
- return -1;
- }
- p = strchr(q, '@');
-
- SAFE_FREE(session->host);
-
- if (p) {
- *p = '\0';
- session->host = strdup(p + 1);
- if (session->host == NULL) {
- SAFE_FREE(q);
- ssh_set_error_oom(session);
- return -1;
- }
-
- SAFE_FREE(session->username);
- session->username = strdup(q);
- SAFE_FREE(q);
- if (session->username == NULL) {
- ssh_set_error_oom(session);
- return -1;
- }
- } else {
- session->host = q;
- }
- break;
- case SSH_OPTIONS_PORT:
- if (value == NULL) {
- session->port = 22 & 0xffff;
- } else {
- int *x = (int *) value;
-
- session->port = *x & 0xffff;
- }
- break;
- case SSH_OPTIONS_PORT_STR:
- if (value == NULL) {
- session->port = 22 & 0xffff;
- } else {
- q = strdup(value);
- if (q == NULL) {
- ssh_set_error_oom(session);
- return -1;
- }
- i = strtol(q, &p, 10);
- if (q == p) {
- SAFE_FREE(q);
- }
- SAFE_FREE(q);
-
- session->port = i & 0xffff;
- }
- break;
- case SSH_OPTIONS_FD:
- if (value == NULL) {
- session->fd = SSH_INVALID_SOCKET;
- } else {
- socket_t *x = (socket_t *) value;
-
- session->fd = *x & 0xffff;
- }
- break;
- case SSH_OPTIONS_BINDADDR:
- if (value == NULL) {
- ssh_set_error_invalid(session, __FUNCTION__);
- return -1;
- }
- q = strdup(value);
- if (q == NULL) {
- return -1;
- }
- SAFE_FREE(session->bindaddr);
- session->bindaddr = q;
- break;
- case SSH_OPTIONS_USER:
- SAFE_FREE(session->username);
- if (value == NULL) { /* set default username */
- q = ssh_get_local_username(session);
- if (q == NULL) {
- return -1;
- }
- session->username = q;
- } else { /* username provided */
- session->username = strdup(value);
- if (session->username == NULL) {
- ssh_set_error_oom(session);
- return -1;
- }
- }
- break;
- case SSH_OPTIONS_SSH_DIR:
- if (value == NULL) {
- SAFE_FREE(session->sshdir);
-
- session->sshdir = ssh_path_expand_tilde("~/.ssh");
- if (session->sshdir == NULL) {
- return -1;
- }
- } else {
- SAFE_FREE(session->sshdir);
- session->sshdir = ssh_path_expand_tilde(value);
- if (session->sshdir == NULL) {
- return -1;
- }
- }
- break;
- case SSH_OPTIONS_IDENTITY:
- case SSH_OPTIONS_ADD_IDENTITY:
- if (value == NULL) {
- ssh_set_error_invalid(session, __FUNCTION__);
- return -1;
- }
- q = strdup(value);
- if (q == NULL) {
- return -1;
- }
- rc = ssh_list_prepend(session->identity, q);
- if (rc < 0) {
- return -1;
- }
- break;
- case SSH_OPTIONS_KNOWNHOSTS:
- if (value == NULL) {
- SAFE_FREE(session->knownhosts);
- if (session->sshdir == NULL) {
- return -1;
- }
- session->knownhosts = ssh_path_expand_escape(session, "%d/known_hosts");
- if (session->knownhosts == NULL) {
- return -1;
- }
- } else {
- SAFE_FREE(session->knownhosts);
- session->knownhosts = strdup(value);
- if (session->knownhosts == NULL) {
- return -1;
- }
- }
- break;
- case SSH_OPTIONS_TIMEOUT:
- if (value == NULL) {
- ssh_set_error_invalid(session, __FUNCTION__);
- return -1;
- } else {
- long *x = (long *) value;
-
- session->timeout = *x & 0xffffffff;
- }
- break;
- case SSH_OPTIONS_TIMEOUT_USEC:
- if (value == NULL) {
- ssh_set_error_invalid(session, __FUNCTION__);
- return -1;
- } else {
- long *x = (long *) value;
-
- session->timeout_usec = *x & 0xffffffff;
- }
- break;
- case SSH_OPTIONS_SSH1:
- if (value == NULL) {
- ssh_set_error_invalid(session, __FUNCTION__);
- return -1;
- } else {
- int *x = (int *) value;
- session->ssh1 = *x;
- }
- break;
- case SSH_OPTIONS_SSH2:
- if (value == NULL) {
- ssh_set_error_invalid(session, __FUNCTION__);
- return -1;
- } else {
- int *x = (int *) value;
- session->ssh2 = *x & 0xffff;
- }
- break;
- case SSH_OPTIONS_LOG_VERBOSITY:
- if (value == NULL) {
- ssh_set_error_invalid(session, __FUNCTION__);
- return -1;
- } else {
- int *x = (int *) value;
-
- session->log_verbosity = *x & 0xffff;
- }
- break;
- case SSH_OPTIONS_LOG_VERBOSITY_STR:
- if (value == NULL) {
- session->log_verbosity = 0 & 0xffff;
- } else {
- q = strdup(value);
- if (q == NULL) {
- ssh_set_error_oom(session);
- return -1;
- }
- i = strtol(q, &p, 10);
- if (q == p) {
- SAFE_FREE(q);
- }
- SAFE_FREE(q);
-
- session->log_verbosity = i & 0xffff;
- }
- break;
- case SSH_OPTIONS_CIPHERS_C_S:
- if (value == NULL) {
- ssh_set_error_invalid(session, __FUNCTION__);
- return -1;
- } else {
- if (ssh_options_set_algo(session, SSH_CRYPT_C_S, value) < 0)
- return -1;
- }
- break;
- case SSH_OPTIONS_CIPHERS_S_C:
- if (value == NULL) {
- ssh_set_error_invalid(session, __FUNCTION__);
- return -1;
- } else {
- if (ssh_options_set_algo(session, SSH_CRYPT_S_C, value) < 0)
- return -1;
- }
- break;
- case SSH_OPTIONS_COMPRESSION_C_S:
- if (value == NULL) {
- ssh_set_error_invalid(session, __FUNCTION__);
- return -1;
- } else {
- if (ssh_options_set_algo(session, SSH_COMP_C_S, value) < 0)
- return -1;
- }
- break;
- case SSH_OPTIONS_COMPRESSION_S_C:
- if (value == NULL) {
- ssh_set_error_invalid(session, __FUNCTION__);
- return -1;
- } else {
- if (ssh_options_set_algo(session, SSH_COMP_S_C, value) < 0)
- return -1;
- }
- break;
- case SSH_OPTIONS_HOSTKEYCHECK:
- if (value == NULL) {
- ssh_set_error_invalid(session, __FUNCTION__);
- return -1;
- } else {
- session->StrictHostKeyChecking = *(int*)value;
- }
- break;
- case SSH_OPTIONS_PROXYCOMMAND:
- if (value == NULL) {
- ssh_set_error_invalid(session, __FUNCTION__);
- return -1;
- } else {
- SAFE_FREE(session->ProxyCommand);
- q = strdup(value);
- if (q == NULL) {
- return -1;
- }
- session->ProxyCommand = q;
- }
- break;
- default:
- ssh_set_error(session, SSH_REQUEST_DENIED, "Unknown ssh option %d", type);
- return -1;
- break;
- }
-
- return 0;
-}
-
-
-/**
- * @brief Parse command line arguments.
- *
- * This is a helper for your application to generate the appropriate
- * options from the command line arguments.\n
- * The argv array and argc value are changed so that the parsed
- * arguments wont appear anymore in them.\n
- * The single arguments (without switches) are not parsed. thus,
- * myssh -l user localhost\n
- * The command wont set the hostname value of options to localhost.
- *
- * @param session The session to configure.
- *
- * @param argcptr The pointer to the argument count.
- *
- * @param argv The arguments list pointer.
- *
- * @returns 0 on success, < 0 on error.
- *
- * @see ssh_session_new()
- */
-int ssh_options_getopt(ssh_session session, int *argcptr, char **argv) {
- char *user = NULL;
- char *cipher = NULL;
- char *localaddr = NULL;
- char *identity = NULL;
- char *port = NULL;
- char *bindport = NULL;
- char **save = NULL;
- int i = 0;
- int argc = *argcptr;
- int debuglevel = 0;
- int usersa = 0;
- int usedss = 0;
- int compress = 0;
- int cont = 1;
- int current = 0;
-#ifdef WITH_SSH1
- int ssh1 = 1;
-#else
- int ssh1 = 0;
-#endif
- int ssh2 = 1;
-#ifdef _MSC_VER
- /* Not supported with a Microsoft compiler */
- return -1;
-#else
- int saveoptind = optind; /* need to save 'em */
- int saveopterr = opterr;
-
- save = malloc(argc * sizeof(char *));
- if (save == NULL) {
- ssh_set_error_oom(session);
- return -1;
- }
-
- opterr = 0; /* shut up getopt */
- while(cont && ((i = getopt(argc, argv, "c:i:Cl:p:vb:t:rd12")) != -1)) {
- switch(i) {
- case 'l':
- user = optarg;
- break;
- case 'p':
- port = optarg;
- break;
- case 't':
- bindport = optarg;
- break;
- case 'v':
- debuglevel++;
- break;
- case 'r':
- usersa++;
- break;
- case 'd':
- usedss++;
- break;
- case 'c':
- cipher = optarg;
- break;
- case 'i':
- identity = optarg;
- break;
- case 'b':
- localaddr = optarg;
- break;
- case 'C':
- compress++;
- break;
- case '2':
- ssh2 = 1;
- ssh1 = 0;
- break;
- case '1':
- ssh2 = 0;
- ssh1 = 1;
- break;
- default:
- {
- char opt[3]="- ";
- opt[1] = optopt;
- save[current] = strdup(opt);
- if (save[current] == NULL) {
- SAFE_FREE(save);
- ssh_set_error_oom(session);
- return -1;
- }
- current++;
- if (optarg) {
- save[current++] = argv[optind + 1];
- }
- }
- } /* switch */
- } /* while */
- opterr = saveopterr;
- while (optind < argc) {
- save[current++] = argv[optind++];
- }
-
- if (usersa && usedss) {
- ssh_set_error(session, SSH_FATAL, "Either RSA or DSS must be chosen");
- cont = 0;
- }
-
- ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &debuglevel);
-
- optind = saveoptind;
-
- if(!cont) {
- SAFE_FREE(save);
- return -1;
- }
-
- /* first recopy the save vector into the original's */
- for (i = 0; i < current; i++) {
- /* don't erase argv[0] */
- argv[ i + 1] = save[i];
- }
- argv[current + 1] = NULL;
- *argcptr = current + 1;
- SAFE_FREE(save);
-
- /* set a new option struct */
- if (compress) {
- if (ssh_options_set(session, SSH_OPTIONS_COMPRESSION_C_S, "zlib,none") < 0) {
- cont = 0;
- }
- if (ssh_options_set(session, SSH_OPTIONS_COMPRESSION_S_C, "zlib,none") < 0) {
- cont = 0;
- }
- }
-
- if (cont && cipher) {
- if (ssh_options_set(session, SSH_OPTIONS_CIPHERS_C_S, cipher) < 0) {
- cont = 0;
- }
- if (cont && ssh_options_set(session, SSH_OPTIONS_CIPHERS_S_C, cipher) < 0) {
- cont = 0;
- }
- }
-
- if (cont && user) {
- if (ssh_options_set(session, SSH_OPTIONS_USER, user) < 0) {
- cont = 0;
- }
- }
-
- if (cont && identity) {
- if (ssh_options_set(session, SSH_OPTIONS_IDENTITY, identity) < 0) {
- cont = 0;
- }
- }
-
- ssh_options_set(session, SSH_OPTIONS_PORT_STR, port);
-
- ssh_options_set(session, SSH_OPTIONS_SSH1, &ssh1);
- ssh_options_set(session, SSH_OPTIONS_SSH2, &ssh2);
-
- if (!cont) {
- return SSH_ERROR;
- }
-
- return SSH_OK;
-#endif
-}
-
-/**
- * @brief Parse the ssh config file.
- *
- * This should be the last call of all options, it may overwrite options which
- * are already set. It requires that the host name is already set with
- * ssh_options_set_host().
- *
- * @param session SSH session handle
- *
- * @param filename The options file to use, if NULL the default
- * ~/.ssh/config will be used.
- *
- * @return 0 on success, < 0 on error.
- *
- * @see ssh_options_set_host()
- */
-int ssh_options_parse_config(ssh_session session, const char *filename) {
- char *expanded_filename;
- int r;
-
- if (session == NULL) {
- return -1;
- }
- if (session->host == NULL) {
- ssh_set_error_invalid(session, __FUNCTION__);
- return -1;
- }
-
- if (session->sshdir == NULL) {
- r = ssh_options_set(session, SSH_OPTIONS_SSH_DIR, NULL);
- if (r < 0) {
- ssh_set_error_oom(session);
- return -1;
- }
- }
-
- /* set default filename */
- if (filename == NULL) {
- expanded_filename = ssh_path_expand_escape(session, "%d/config");
- } else {
- expanded_filename = ssh_path_expand_escape(session, filename);
- }
- if (expanded_filename == NULL) {
- return -1;
- }
-
- r = ssh_config_parse_file(session, expanded_filename);
- if (r < 0) {
- goto out;
- }
- if (filename == NULL) {
- r = ssh_config_parse_file(session, "/etc/ssh/ssh_config");
- }
-
-out:
- free(expanded_filename);
- return r;
-}
-
-int ssh_options_apply(ssh_session session) {
- struct ssh_iterator *it;
- char *tmp;
- int rc;
-
- if (session->sshdir == NULL) {
- rc = ssh_options_set(session, SSH_OPTIONS_SSH_DIR, NULL);
- if (rc < 0) {
- return -1;
- }
- }
-
- if (session->username == NULL) {
- rc = ssh_options_set(session, SSH_OPTIONS_USER, NULL);
- if (rc < 0) {
- return -1;
- }
- }
-
- if (session->knownhosts == NULL) {
- tmp = ssh_path_expand_escape(session, "%d/known_hosts");
- } else {
- tmp = ssh_path_expand_escape(session, session->knownhosts);
- }
- if (tmp == NULL) {
- return -1;
- }
- free(session->knownhosts);
- session->knownhosts = tmp;
-
- if (session->ProxyCommand != NULL) {
- tmp = ssh_path_expand_escape(session, session->ProxyCommand);
- if (tmp == NULL) {
- return -1;
- }
- free(session->ProxyCommand);
- session->ProxyCommand = tmp;
- }
-
- for (it = ssh_list_get_iterator(session->identity);
- it != NULL;
- it = it->next) {
- char *id = (char *) it->data;
- tmp = ssh_path_expand_escape(session, id);
- if (tmp == NULL) {
- return -1;
- }
- free(id);
- it->data = tmp;
- }
-
- return 0;
-}
-
-/** @} */
-
-#ifdef WITH_SERVER
-/**
- * @addtogroup libssh_server
- * @{
- */
-static int ssh_bind_options_set_algo(ssh_bind sshbind, int algo,
- const char *list) {
- if (!verify_existing_algo(algo, list)) {
- ssh_set_error(sshbind, SSH_REQUEST_DENIED,
- "Setting method: no algorithm for method \"%s\" (%s)\n",
- ssh_kex_nums[algo], list);
- return -1;
- }
-
- SAFE_FREE(sshbind->wanted_methods[algo]);
- sshbind->wanted_methods[algo] = strdup(list);
- if (sshbind->wanted_methods[algo] == NULL) {
- ssh_set_error_oom(sshbind);
- return -1;
- }
-
- return 0;
-}
-
-/**
- * @brief This function can set all possible ssh bind options.
- *
- * @param session An allocated ssh option structure.
- *
- * @param type The option type to set. This could be one of the
- * following:
- *
- * SSH_BIND_OPTIONS_LOG_VERBOSITY:
- * Set the session logging verbosity (integer).
- *
- * The verbosity of the messages. Every log smaller or
- * equal to verbosity will be shown.
- * SSH_LOG_NOLOG: No logging
- * SSH_LOG_RARE: Rare conditions or warnings
- * SSH_LOG_ENTRY: API-accessible entrypoints
- * SSH_LOG_PACKET: Packet id and size
- * SSH_LOG_FUNCTIONS: Function entering and leaving
- *
- * SSH_BIND_OPTIONS_LOG_VERBOSITY_STR:
- * Set the session logging verbosity (integer).
- *
- * The verbosity of the messages. Every log smaller or
- * equal to verbosity will be shown.
- * SSH_LOG_NOLOG: No logging
- * SSH_LOG_RARE: Rare conditions or warnings
- * SSH_LOG_ENTRY: API-accessible entrypoints
- * SSH_LOG_PACKET: Packet id and size
- * SSH_LOG_FUNCTIONS: Function entering and leaving
- *
- * SSH_BIND_OPTIONS_BINDADDR:
- * Set the bind address.
- *
- * SSH_BIND_OPTIONS_BINDPORT:
- * Set the bind port, default is 22.
- *
- * SSH_BIND_OPTIONS_HOSTKEY:
- * Set the server public key type: ssh-rsa or ssh-dss
- * (string).
- *
- * SSH_BIND_OPTIONS_DSAKEY:
- * Set the path to the dsa ssh host key (string).
- *
- * SSH_BIND_OPTIONS_RSAKEY:
- * Set the path to the ssh host rsa key (string).
- *
- * SSH_BIND_OPTIONS_BANNER:
- * Set the server banner sent to clients (string).
- *
- * @param value The value to set. This is a generic pointer and the
- * datatype which is used should be set according to the
- * type set.
- *
- * @return 0 on success, < 0 on error.
- */
-int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type,
- const void *value) {
- char *p, *q;
- int i;
-
- if (sshbind == NULL) {
- return -1;
- }
-
- switch (type) {
- case SSH_BIND_OPTIONS_HOSTKEY:
- if (value == NULL) {
- ssh_set_error_invalid(sshbind, __FUNCTION__);
- return -1;
- } else {
- if (ssh_bind_options_set_algo(sshbind, SSH_HOSTKEYS, value) < 0)
- return -1;
- }
- break;
- case SSH_BIND_OPTIONS_BINDADDR:
- if (value == NULL) {
- ssh_set_error_invalid(sshbind, __FUNCTION__);
- return -1;
- } else {
- SAFE_FREE(sshbind->bindaddr);
- sshbind->bindaddr = strdup(value);
- if (sshbind->bindaddr == NULL) {
- ssh_set_error_oom(sshbind);
- return -1;
- }
- }
- break;
- case SSH_BIND_OPTIONS_BINDPORT:
- if (value == NULL) {
- ssh_set_error_invalid(sshbind, __FUNCTION__);
- return -1;
- } else {
- int *x = (int *) value;
- sshbind->bindport = *x & 0xffff;
- }
- break;
- case SSH_BIND_OPTIONS_BINDPORT_STR:
- if (value == NULL) {
- sshbind->bindport = 22 & 0xffff;
- } else {
- q = strdup(value);
- if (q == NULL) {
- ssh_set_error_oom(sshbind);
- return -1;
- }
- i = strtol(q, &p, 10);
- if (q == p) {
- SAFE_FREE(q);
- }
- SAFE_FREE(q);
-
- sshbind->bindport = i & 0xffff;
- }
- break;
- case SSH_BIND_OPTIONS_LOG_VERBOSITY:
- if (value == NULL) {
- ssh_set_error_invalid(sshbind, __FUNCTION__);
- return -1;
- } else {
- int *x = (int *) value;
- sshbind->log_verbosity = *x & 0xffff;
- }
- break;
- case SSH_BIND_OPTIONS_LOG_VERBOSITY_STR:
- if (value == NULL) {
- sshbind->log_verbosity = 0;
- } else {
- q = strdup(value);
- if (q == NULL) {
- ssh_set_error_oom(sshbind);
- return -1;
- }
- i = strtol(q, &p, 10);
- if (q == p) {
- SAFE_FREE(q);
- }
- SAFE_FREE(q);
-
- sshbind->log_verbosity = i & 0xffff;
- }
- break;
- case SSH_BIND_OPTIONS_DSAKEY:
- if (value == NULL) {
- ssh_set_error_invalid(sshbind, __FUNCTION__);
- return -1;
- } else {
- SAFE_FREE(sshbind->dsakey);
- sshbind->dsakey = strdup(value);
- if (sshbind->dsakey == NULL) {
- ssh_set_error_oom(sshbind);
- return -1;
- }
- }
- break;
- case SSH_BIND_OPTIONS_RSAKEY:
- if (value == NULL) {
- ssh_set_error_invalid(sshbind, __FUNCTION__);
- return -1;
- } else {
- SAFE_FREE(sshbind->rsakey);
- sshbind->rsakey = strdup(value);
- if (sshbind->rsakey == NULL) {
- ssh_set_error_oom(sshbind);
- return -1;
- }
- }
- break;
- case SSH_BIND_OPTIONS_BANNER:
- if (value == NULL) {
- ssh_set_error_invalid(sshbind, __FUNCTION__);
- return -1;
- } else {
- SAFE_FREE(sshbind->banner);
- sshbind->banner = strdup(value);
- if (sshbind->banner == NULL) {
- ssh_set_error_oom(sshbind);
- return -1;
- }
- }
- break;
- default:
- ssh_set_error(sshbind, SSH_REQUEST_DENIED, "Unknown ssh option %d", type);
- return -1;
- break;
- }
-
- return 0;
-}
-#endif
-
-/** @} */
-
-/* vim: set ts=4 sw=4 et cindent: */
diff --git a/libssh/packet.c b/libssh/packet.c
deleted file mode 100644
index a97db93b..00000000
--- a/libssh/packet.c
+++ /dev/null
@@ -1,529 +0,0 @@
-/*
- * packet.c - packet building 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 "config.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-
-#ifndef _WIN32
-#include <arpa/inet.h>
-#endif
-
-#include "libssh/priv.h"
-#include "libssh/ssh2.h"
-#include "libssh/crypto.h"
-#include "libssh/buffer.h"
-#include "libssh/packet.h"
-#include "libssh/socket.h"
-#include "libssh/channels.h"
-#include "libssh/misc.h"
-#include "libssh/session.h"
-#include "libssh/messages.h"
-#include "libssh/pcap.h"
-#include "libssh/kex.h"
-#include "libssh/auth.h"
-
-ssh_packet_callback default_packet_handlers[]= {
- ssh_packet_disconnect_callback, // SSH2_MSG_DISCONNECT 1
- ssh_packet_ignore_callback, // SSH2_MSG_IGNORE 2
- ssh_packet_unimplemented, // SSH2_MSG_UNIMPLEMENTED 3
- ssh_packet_ignore_callback, // SSH2_MSG_DEBUG 4
- ssh_packet_service_request, // SSH2_MSG_SERVICE_REQUEST 5
- ssh_packet_service_accept, // SSH2_MSG_SERVICE_ACCEPT 6
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, // 7-19
- ssh_packet_kexinit, // SSH2_MSG_KEXINIT 20
- ssh_packet_newkeys, // SSH2_MSG_NEWKEYS 21
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, // 22-29
-#if WITH_SERVER
- ssh_packet_kexdh_init, // SSH2_MSG_KEXDH_INIT 30
- // SSH2_MSG_KEX_DH_GEX_REQUEST_OLD 30
-#else
- NULL,
-#endif
- ssh_packet_dh_reply, // SSH2_MSG_KEXDH_REPLY 31
- // SSH2_MSG_KEX_DH_GEX_GROUP 31
- NULL, // SSH2_MSG_KEX_DH_GEX_INIT 32
- NULL, // SSH2_MSG_KEX_DH_GEX_REPLY 33
- NULL, // SSH2_MSG_KEX_DH_GEX_REQUEST 34
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, // 35-49
- ssh_packet_userauth_request, // SSH2_MSG_USERAUTH_REQUEST 50
- ssh_packet_userauth_failure, // SSH2_MSG_USERAUTH_FAILURE 51
- ssh_packet_userauth_success, // SSH2_MSG_USERAUTH_SUCCESS 52
- ssh_packet_userauth_banner, // SSH2_MSG_USERAUTH_BANNER 53
- NULL,NULL,NULL,NULL,NULL,NULL, // 54-59
- ssh_packet_userauth_pk_ok, // SSH2_MSG_USERAUTH_PK_OK 60
- // SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ 60
- // SSH2_MSG_USERAUTH_INFO_REQUEST 60
- NULL, // SSH2_MSG_USERAUTH_INFO_RESPONSE 61
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, // 62-79
- NULL, // SSH2_MSG_GLOBAL_REQUEST 80
- ssh_request_success, // SSH2_MSG_REQUEST_SUCCESS 81
- ssh_request_denied, // SSH2_MSG_REQUEST_FAILURE 82
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,// 83-89
- ssh_packet_channel_open, // SSH2_MSG_CHANNEL_OPEN 90
- ssh_packet_channel_open_conf, // SSH2_MSG_CHANNEL_OPEN_CONFIRMATION 91
- ssh_packet_channel_open_fail, // SSH2_MSG_CHANNEL_OPEN_FAILURE 92
- channel_rcv_change_window, // SSH2_MSG_CHANNEL_WINDOW_ADJUST 93
- channel_rcv_data, // SSH2_MSG_CHANNEL_DATA 94
- channel_rcv_data, // SSH2_MSG_CHANNEL_EXTENDED_DATA 95
- channel_rcv_eof, // SSH2_MSG_CHANNEL_EOF 96
- channel_rcv_close, // SSH2_MSG_CHANNEL_CLOSE 97
- channel_rcv_request, // SSH2_MSG_CHANNEL_REQUEST 98
- ssh_packet_channel_success, // SSH2_MSG_CHANNEL_SUCCESS 99
- ssh_packet_channel_failure, // SSH2_MSG_CHANNEL_FAILURE 100
-};
-
-/* XXX include selected mac size */
-static int macsize=SHA_DIGEST_LEN;
-
-/* in nonblocking mode, socket_read will read as much as it can, and return */
-/* SSH_OK if it has read at least len bytes, otherwise, SSH_AGAIN. */
-/* in blocking mode, it will read at least len bytes and will block until it's ok. */
-
-/** @internal
- * @handles a data received event. It then calls the handlers for the different packet types
- * or and exception handler callback.
- * @param user pointer to current ssh_session
- * @param data pointer to the data received
- * @len length of data received. It might not be enough for a complete packet
- * @returns number of bytes read and processed.
- */
-int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user){
- ssh_session session=(ssh_session) user;
- unsigned int blocksize = (session->current_crypto ?
- session->current_crypto->in_cipher->blocksize : 8);
- int current_macsize = session->current_crypto ? macsize : 0;
- unsigned char mac[30] = {0};
- char buffer[16] = {0};
- void *packet=NULL;
- int to_be_read;
- int rc;
- uint32_t len;
- uint8_t padding;
- size_t processed=0; /* number of byte processed from the callback */
-
- enter_function();
-
- switch(session->packet_state) {
- case PACKET_STATE_INIT:
- if(receivedlen < blocksize){
- /* We didn't receive enough data to read at least one block size, give up */
- leave_function();
- return 0;
- }
- memset(&session->in_packet, 0, sizeof(PACKET));
-
- if (session->in_buffer) {
- if (buffer_reinit(session->in_buffer) < 0) {
- goto error;
- }
- } else {
- session->in_buffer = ssh_buffer_new();
- if (session->in_buffer == NULL) {
- goto error;
- }
- }
-
- memcpy(buffer,data,blocksize);
- processed += blocksize;
- len = packet_decrypt_len(session, buffer);
-
- if (buffer_add_data(session->in_buffer, buffer, blocksize) < 0) {
- goto error;
- }
-
- if(len > MAX_PACKET_LEN) {
- ssh_set_error(session, SSH_FATAL,
- "read_packet(): Packet len too high(%u %.4x)", len, len);
- goto error;
- }
-
- to_be_read = len - blocksize + sizeof(uint32_t);
- if (to_be_read < 0) {
- /* remote sshd sends invalid sizes? */
- ssh_set_error(session, SSH_FATAL,
- "given numbers of bytes left to be read < 0 (%d)!", to_be_read);
- goto error;
- }
-
- /* saves the status of the current operations */
- session->in_packet.len = len;
- session->packet_state = PACKET_STATE_SIZEREAD;
- case PACKET_STATE_SIZEREAD:
- len = session->in_packet.len;
- to_be_read = len - blocksize + sizeof(uint32_t) + current_macsize;
- /* if to_be_read is zero, the whole packet was blocksize bytes. */
- if (to_be_read != 0) {
- if(receivedlen - processed < (unsigned int)to_be_read){
- /* give up, not enough data in buffer */
- return processed;
- }
-
- packet = (unsigned char *)data + processed;
-// ssh_socket_read(session->socket,packet,to_be_read-current_macsize);
-
- ssh_log(session,SSH_LOG_PACKET,"Read a %d bytes packet",len);
-
- if (buffer_add_data(session->in_buffer, packet,
- to_be_read - current_macsize) < 0) {
- goto error;
- }
- processed += to_be_read - current_macsize;
- }
-
- if (session->current_crypto) {
- /*
- * decrypt the rest of the packet (blocksize bytes already
- * have been decrypted)
- */
- if (packet_decrypt(session,
- ((uint8_t*)ssh_buffer_get_begin(session->in_buffer) + blocksize),
- ssh_buffer_get_len(session->in_buffer) - blocksize) < 0) {
- ssh_set_error(session, SSH_FATAL, "Decrypt error");
- goto error;
- }
- /* copy the last part from the incoming buffer */
- memcpy(mac,(unsigned char *)packet + to_be_read - current_macsize, macsize);
-
- if (packet_hmac_verify(session, session->in_buffer, mac) < 0) {
- ssh_set_error(session, SSH_FATAL, "HMAC error");
- goto error;
- }
- processed += current_macsize;
- }
-
- /* skip the size field which has been processed before */
- buffer_pass_bytes(session->in_buffer, sizeof(uint32_t));
-
- if (buffer_get_u8(session->in_buffer, &padding) == 0) {
- ssh_set_error(session, SSH_FATAL, "Packet too short to read padding");
- goto error;
- }
-
- ssh_log(session, SSH_LOG_PACKET,
- "%hhd bytes padding, %d bytes left in buffer",
- padding, buffer_get_rest_len(session->in_buffer));
-
- if (padding > buffer_get_rest_len(session->in_buffer)) {
- ssh_set_error(session, SSH_FATAL,
- "Invalid padding: %d (%d resting)",
- padding,
- buffer_get_rest_len(session->in_buffer));
-#ifdef DEBUG_CRYPTO
- ssh_print_hexa("incrimined packet",
- ssh_buffer_get_begin(session->in_buffer),
- ssh_buffer_get_len(session->in_buffer));
-#endif
- goto error;
- }
- buffer_pass_bytes_end(session->in_buffer, padding);
-
- ssh_log(session, SSH_LOG_PACKET,
- "After padding, %d bytes left in buffer",
- buffer_get_rest_len(session->in_buffer));
-#if defined(HAVE_LIBZ) && defined(WITH_LIBZ)
- if (session->current_crypto && session->current_crypto->do_compress_in) {
- ssh_log(session, SSH_LOG_PACKET, "Decompressing in_buffer ...");
- if (decompress_buffer(session, session->in_buffer,MAX_PACKET_LEN) < 0) {
- goto error;
- }
- }
-#endif
- session->recv_seq++;
- /* We don't want to rewrite a new packet while still executing the packet callbacks */
- session->packet_state = PACKET_STATE_PROCESSING;
- ssh_packet_parse_type(session);
- /* execute callbacks */
- ssh_packet_process(session, session->in_packet.type);
- session->packet_state = PACKET_STATE_INIT;
- if(processed < receivedlen){
- /* Handle a potential packet left in socket buffer */
- ssh_log(session,SSH_LOG_PACKET,"Processing %" PRIdS " bytes left in socket buffer",
- receivedlen-processed);
- rc = ssh_packet_socket_callback((char *)data + processed,
- receivedlen - processed,user);
- processed += rc;
- }
- leave_function();
- return processed;
- case PACKET_STATE_PROCESSING:
- ssh_log(session, SSH_LOG_RARE, "Nested packet processing. Delaying.");
- return 0;
- }
-
- ssh_set_error(session, SSH_FATAL,
- "Invalid state into packet_read2(): %d",
- session->packet_state);
-
-error:
- leave_function();
- return processed;
-}
-
-void ssh_packet_register_socket_callback(ssh_session session, ssh_socket s){
- session->socket_callbacks.data=ssh_packet_socket_callback;
- session->socket_callbacks.connected=NULL;
- session->socket_callbacks.controlflow=NULL;
- session->socket_callbacks.exception=NULL;
- session->socket_callbacks.userdata=session;
- ssh_socket_set_callbacks(s,&session->socket_callbacks);
-}
-
-/** @internal
- * @brief sets the callbacks for the packet layer
- */
-void ssh_packet_set_callbacks(ssh_session session, ssh_packet_callbacks callbacks){
- if(session->packet_callbacks == NULL){
- session->packet_callbacks = ssh_list_new();
- }
- ssh_list_append(session->packet_callbacks, callbacks);
-}
-
-/** @internal
- * @brief sets the default packet handlers
- */
-void ssh_packet_set_default_callbacks(ssh_session session){
-#ifdef WITH_SSH1
- if(session->version==1){
- ssh_packet_set_default_callbacks1(session);
- return;
- }
-#endif
- session->default_packet_callbacks.start=1;
- session->default_packet_callbacks.n_callbacks=sizeof(default_packet_handlers)/sizeof(ssh_packet_callback);
- session->default_packet_callbacks.user=session;
- session->default_packet_callbacks.callbacks=default_packet_handlers;
- ssh_packet_set_callbacks(session, &session->default_packet_callbacks);
-}
-
-/** @internal
- * @brief dispatch the call of packet handlers callbacks for a received packet
- * @param type type of packet
- */
-void ssh_packet_process(ssh_session session, uint8_t type){
- struct ssh_iterator *i;
- int r=SSH_PACKET_NOT_USED;
- ssh_packet_callbacks cb;
- enter_function();
- ssh_log(session,SSH_LOG_PACKET, "Dispatching handler for packet type %d",type);
- if(session->packet_callbacks == NULL){
- ssh_log(session,SSH_LOG_RARE,"Packet callback is not initialized !");
- goto error;
- }
- i=ssh_list_get_iterator(session->packet_callbacks);
- while(i != NULL){
- cb=ssh_iterator_value(ssh_packet_callbacks,i);
- i=i->next;
- if(!cb)
- continue;
- if(cb->start > type)
- continue;
- if(cb->start + cb->n_callbacks <= type)
- continue;
- if(cb->callbacks[type - cb->start]==NULL)
- continue;
- r=cb->callbacks[type - cb->start](session,type,session->in_buffer,cb->user);
- if(r==SSH_PACKET_USED)
- break;
- }
- if(r==SSH_PACKET_NOT_USED){
- ssh_log(session,SSH_LOG_RARE,"Couldn't do anything with packet type %d",type);
- ssh_packet_send_unimplemented(session, session->recv_seq-1);
- }
-error:
- leave_function();
-}
-
-/** @internal
- * @brief sends a SSH_MSG_UNIMPLEMENTED answer to an unhandled packet
- * @param session the SSH session
- * @param seqnum the sequence number of the unknown packet
- * @return SSH_ERROR on error, else SSH_OK
- */
-int ssh_packet_send_unimplemented(ssh_session session, uint32_t seqnum){
- int r;
- enter_function();
- buffer_add_u8(session->out_buffer, SSH2_MSG_UNIMPLEMENTED);
- buffer_add_u32(session->out_buffer, htonl(seqnum));
- r = packet_send(session);
- leave_function();
- return r;
-}
-
-/** @internal
- * @brief handles a SSH_MSG_UNIMPLEMENTED packet
- */
-SSH_PACKET_CALLBACK(ssh_packet_unimplemented){
- uint32_t seq;
- (void)type;
- (void)user;
- buffer_get_u32(packet,&seq);
- seq=ntohl(seq);
- ssh_log(session,SSH_LOG_RARE,
- "Received SSH_MSG_UNIMPLEMENTED (sequence number %d)",seq);
- return SSH_PACKET_USED;
-}
-
-/** @internal
- * @parse the "Type" header field of a packet and updates the session
- */
-int ssh_packet_parse_type(ssh_session session) {
- enter_function();
-
- memset(&session->in_packet, 0, sizeof(PACKET));
- if(session->in_buffer == NULL) {
- leave_function();
- return SSH_ERROR;
- }
-
- ssh_log(session, SSH_LOG_PACKET, "Final size %d",
- buffer_get_rest_len(session->in_buffer));
-
- if(buffer_get_u8(session->in_buffer, &session->in_packet.type) == 0) {
- ssh_set_error(session, SSH_FATAL, "Packet too short to read type");
- leave_function();
- return SSH_ERROR;
- }
-
- ssh_log(session, SSH_LOG_PACKET, "Type %hhd", session->in_packet.type);
- session->in_packet.valid = 1;
-
- leave_function();
- return SSH_OK;
-}
-
-/*
- * This function places the outgoing packet buffer into an outgoing
- * socket buffer
- */
-static int ssh_packet_write(ssh_session session) {
- int rc = SSH_ERROR;
-
- enter_function();
-
- rc=ssh_socket_write(session->socket,
- ssh_buffer_get_begin(session->out_buffer),
- ssh_buffer_get_len(session->out_buffer));
- if(rc == SSH_OK){
- rc=ssh_socket_nonblocking_flush(session->socket);
- }
- leave_function();
- return rc;
-}
-
-static int packet_send2(ssh_session session) {
- unsigned int blocksize = (session->current_crypto ?
- session->current_crypto->out_cipher->blocksize : 8);
- uint32_t currentlen = ssh_buffer_get_len(session->out_buffer);
- unsigned char *hmac = NULL;
- char padstring[32] = {0};
- int rc = SSH_ERROR;
- uint32_t finallen;
- uint8_t padding;
-
- enter_function();
-
- ssh_log(session, SSH_LOG_PACKET,
- "Writing on the wire a packet having %u bytes before", currentlen);
-
-#if defined(HAVE_LIBZ) && defined(WITH_LIBZ)
- if (session->current_crypto && session->current_crypto->do_compress_out) {
- ssh_log(session, SSH_LOG_PACKET, "Compressing in_buffer ...");
- if (compress_buffer(session,session->out_buffer) < 0) {
- goto error;
- }
- currentlen = ssh_buffer_get_len(session->out_buffer);
- }
-#endif
- padding = (blocksize - ((currentlen +5) % blocksize));
- if(padding < 4) {
- padding += blocksize;
- }
-
- if (session->current_crypto) {
- ssh_get_random(padstring, padding, 0);
- } else {
- memset(padstring,0,padding);
- }
-
- finallen = htonl(currentlen + padding + 1);
- ssh_log(session, SSH_LOG_PACKET,
- "%d bytes after comp + %d padding bytes = %lu bytes packet",
- currentlen, padding, (long unsigned int) ntohl(finallen));
-
- if (buffer_prepend_data(session->out_buffer, &padding, sizeof(uint8_t)) < 0) {
- goto error;
- }
- if (buffer_prepend_data(session->out_buffer, &finallen, sizeof(uint32_t)) < 0) {
- goto error;
- }
- if (buffer_add_data(session->out_buffer, padstring, padding) < 0) {
- goto error;
- }
-#ifdef WITH_PCAP
- if(session->pcap_ctx){
- ssh_pcap_context_write(session->pcap_ctx,SSH_PCAP_DIR_OUT,
- ssh_buffer_get_begin(session->out_buffer),ssh_buffer_get_len(session->out_buffer)
- ,ssh_buffer_get_len(session->out_buffer));
- }
-#endif
- hmac = packet_encrypt(session, ssh_buffer_get_begin(session->out_buffer),
- ssh_buffer_get_len(session->out_buffer));
- if (hmac) {
- if (buffer_add_data(session->out_buffer, hmac, 20) < 0) {
- goto error;
- }
- }
-
- rc = ssh_packet_write(session);
- session->send_seq++;
-
- if (buffer_reinit(session->out_buffer) < 0) {
- rc = SSH_ERROR;
- }
-error:
- leave_function();
- return rc; /* SSH_OK, AGAIN or ERROR */
-}
-
-
-int packet_send(ssh_session session) {
-#ifdef WITH_SSH1
- if (session->version == 1) {
- return packet_send1(session);
- }
-#endif
- return packet_send2(session);
-}
-
-
-/* vim: set ts=2 sw=2 et cindent: */
diff --git a/libssh/packet1.c b/libssh/packet1.c
deleted file mode 100644
index d4b2eaef..00000000
--- a/libssh/packet1.c
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- * This file is part of the SSH Library
- *
- * Copyright (c) 2010 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 "libssh/priv.h"
-#include "libssh/ssh1.h"
-#include "libssh/packet.h"
-#include "libssh/session.h"
-#include "libssh/buffer.h"
-#include "libssh/socket.h"
-#include "libssh/kex.h"
-#ifdef WITH_SSH1
-
-ssh_packet_callback default_packet_handlers1[]= {
- NULL, //SSH_MSG_NONE 0
- ssh_packet_disconnect1, //SSH_MSG_DISCONNECT 1
- ssh_packet_publickey1, //SSH_SMSG_PUBLIC_KEY 2
- NULL, //SSH_CMSG_SESSION_KEY 3
- NULL, //SSH_CMSG_USER 4
- NULL, //SSH_CMSG_AUTH_RHOSTS 5
- NULL, //SSH_CMSG_AUTH_RSA 6
- NULL, //SSH_SMSG_AUTH_RSA_CHALLENGE 7
- NULL, //SSH_CMSG_AUTH_RSA_RESPONSE 8
- NULL, //SSH_CMSG_AUTH_PASSWORD 9
- NULL, //SSH_CMSG_REQUEST_PTY 10
- NULL, //SSH_CMSG_WINDOW_SIZE 11
- NULL, //SSH_CMSG_EXEC_SHELL 12
- NULL, //SSH_CMSG_EXEC_CMD 13
- ssh_packet_smsg_success1, //SSH_SMSG_SUCCESS 14
- ssh_packet_smsg_failure1, //SSH_SMSG_FAILURE 15
- NULL, //SSH_CMSG_STDIN_DATA 16
- ssh_packet_data1, //SSH_SMSG_STDOUT_DATA 17
- ssh_packet_data1, //SSH_SMSG_STDERR_DATA 18
- NULL, //SSH_CMSG_EOF 19
- NULL, //SSH_SMSG_EXITSTATUS 20
- NULL, //SSH_MSG_CHANNEL_OPEN_CONFIRMATION 21
- NULL, //SSH_MSG_CHANNEL_OPEN_FAILURE 22
- NULL, //SSH_MSG_CHANNEL_DATA 23
- ssh_packet_close1, //SSH_MSG_CHANNEL_CLOSE 24
- NULL, //SSH_MSG_CHANNEL_CLOSE_CONFIRMATION 25
- NULL, //SSH_CMSG_X11_REQUEST_FORWARDING 26
- NULL, //SSH_SMSG_X11_OPEN 27
- NULL, //SSH_CMSG_PORT_FORWARD_REQUEST 28
- NULL, //SSH_MSG_PORT_OPEN 29
- NULL, //SSH_CMSG_AGENT_REQUEST_FORWARDING 30
- NULL, //SSH_SMSG_AGENT_OPEN 31
- ssh_packet_ignore_callback, //SSH_MSG_IGNORE 32
- NULL, //SSH_CMSG_EXIT_CONFIRMATION 33
- NULL, //SSH_CMSG_X11_REQUEST_FORWARDING 34
- NULL, //SSH_CMSG_AUTH_RHOSTS_RSA 35
- ssh_packet_ignore_callback, //SSH_MSG_DEBUG 36
-};
-
-/** @internal
- * @brief sets the default packet handlers
- */
-void ssh_packet_set_default_callbacks1(ssh_session session){
- session->default_packet_callbacks.start=0;
- session->default_packet_callbacks.n_callbacks=sizeof(default_packet_handlers1)/sizeof(ssh_packet_callback);
- session->default_packet_callbacks.user=session;
- session->default_packet_callbacks.callbacks=default_packet_handlers1;
- ssh_packet_set_callbacks(session, &session->default_packet_callbacks);
-}
-
-
-/** @internal
- * @handles a data received event. It then calls the handlers for the different packet types
- * or and exception handler callback. Adapted for SSH-1 packets.
- * @param user pointer to current ssh_session
- * @param data pointer to the data received
- * @len length of data received. It might not be enough for a complete packet
- * @returns number of bytes read and processed.
- */
-
-int ssh_packet_socket_callback1(const void *data, size_t receivedlen, void *user) {
- void *packet = NULL;
- int rc = SSH_ERROR;
- int to_be_read;
- size_t processed=0;
- uint32_t padding;
- uint32_t crc;
- uint32_t len;
- ssh_session session=(ssh_session)user;
- enter_function();
-
- switch (session->packet_state){
- case PACKET_STATE_INIT:
- memset(&session->in_packet, 0, sizeof(PACKET));
-
- if (session->in_buffer) {
- if (buffer_reinit(session->in_buffer) < 0) {
- goto error;
- }
- } else {
- session->in_buffer = ssh_buffer_new();
- if (session->in_buffer == NULL) {
- goto error;
- }
- }
- /* must have at least enough bytes for size */
- if(receivedlen < sizeof(uint32_t)){
- leave_function();
- return 0;
- }
- memcpy(&len,data,sizeof(uint32_t));
- processed += sizeof(uint32_t);
- rc = SSH_ERROR;
-
- /* len is not encrypted */
- len = ntohl(len);
- if (len > MAX_PACKET_LEN) {
- ssh_set_error(session, SSH_FATAL,
- "read_packet(): Packet len too high (%u %.8x)", len, len);
- goto error;
- }
-
- ssh_log(session, SSH_LOG_PACKET, "Reading a %d bytes packet", len);
-
- session->in_packet.len = len;
- session->packet_state = PACKET_STATE_SIZEREAD;
- case PACKET_STATE_SIZEREAD:
- len = session->in_packet.len;
- /* SSH-1 has a fixed padding lenght */
- padding = 8 - (len % 8);
- to_be_read = len + padding;
- if(to_be_read + processed > receivedlen){
- /* wait for rest of packet */
- leave_function();
- return processed;
- }
- /* it is _not_ possible that to_be_read be < 8. */
- packet = (char *)data + processed;
- rc = SSH_ERROR;
-
- if (buffer_add_data(session->in_buffer,packet,to_be_read) < 0) {
- SAFE_FREE(packet);
- goto error;
- }
- processed += to_be_read;
-#ifdef DEBUG_CRYPTO
- ssh_print_hexa("read packet:", ssh_buffer_get_begin(session->in_buffer),
- ssh_buffer_get_len(session->in_buffer));
-#endif
- if (session->current_crypto) {
- /*
- * We decrypt everything, missing the lenght part (which was
- * previously read, unencrypted, and is not part of the buffer
- */
- if (packet_decrypt(session,
- ssh_buffer_get_begin(session->in_buffer),
- ssh_buffer_get_len(session->in_buffer)) < 0) {
- ssh_set_error(session, SSH_FATAL, "Packet decrypt error");
- goto error;
- }
- }
-#ifdef DEBUG_CRYPTO
- ssh_print_hexa("read packet decrypted:", ssh_buffer_get_begin(session->in_buffer),
- ssh_buffer_get_len(session->in_buffer));
-#endif
- ssh_log(session, SSH_LOG_PACKET, "%d bytes padding", padding);
- if(((len + padding) != buffer_get_rest_len(session->in_buffer)) ||
- ((len + padding) < sizeof(uint32_t))) {
- ssh_log(session, SSH_LOG_RARE, "no crc32 in packet");
- ssh_set_error(session, SSH_FATAL, "no crc32 in packet");
- goto error;
- }
-
- memcpy(&crc,
- (unsigned char *)buffer_get_rest(session->in_buffer) + (len+padding) - sizeof(uint32_t),
- sizeof(uint32_t));
- buffer_pass_bytes_end(session->in_buffer, sizeof(uint32_t));
- crc = ntohl(crc);
- if (ssh_crc32(buffer_get_rest(session->in_buffer),
- (len + padding) - sizeof(uint32_t)) != crc) {
-#ifdef DEBUG_CRYPTO
- ssh_print_hexa("crc32 on",buffer_get_rest(session->in_buffer),
- len + padding - sizeof(uint32_t));
-#endif
- ssh_log(session, SSH_LOG_RARE, "Invalid crc32");
- ssh_set_error(session, SSH_FATAL,
- "Invalid crc32: expected %.8x, got %.8x",
- crc,
- ssh_crc32(buffer_get_rest(session->in_buffer),
- len + padding - sizeof(uint32_t)));
- goto error;
- }
- /* pass the padding */
- buffer_pass_bytes(session->in_buffer, padding);
- ssh_log(session, SSH_LOG_PACKET, "The packet is valid");
-
-/* TODO FIXME
-#if defined(HAVE_LIBZ) && defined(WITH_LIBZ)
- if(session->current_crypto && session->current_crypto->do_compress_in){
- decompress_buffer(session,session->in_buffer);
- }
-#endif
-*/
- session->recv_seq++;
- /* We don't want to rewrite a new packet while still executing the packet callbacks */
- session->packet_state = PACKET_STATE_PROCESSING;
- ssh_packet_parse_type(session);
- /* execute callbacks */
- ssh_packet_process(session, session->in_packet.type);
- session->packet_state = PACKET_STATE_INIT;
- if(processed < receivedlen){
- /* Handle a potential packet left in socket buffer */
- ssh_log(session,SSH_LOG_PACKET,"Processing %" PRIdS " bytes left in socket buffer",
- receivedlen-processed);
- rc = ssh_packet_socket_callback1((char *)data + processed,
- receivedlen - processed,user);
- processed += rc;
- }
- leave_function();
- return processed;
- case PACKET_STATE_PROCESSING:
- ssh_log(session, SSH_LOG_RARE, "Nested packet processing. Delaying.");
- return 0;
- }
-
-error:
- session->session_state=SSH_SESSION_STATE_ERROR;
- leave_function();
- return processed;
-}
-
-
-int packet_send1(ssh_session session) {
- unsigned int blocksize = (session->current_crypto ?
- session->current_crypto->out_cipher->blocksize : 8);
- uint32_t currentlen = ssh_buffer_get_len(session->out_buffer) + sizeof(uint32_t);
- char padstring[32] = {0};
- int rc = SSH_ERROR;
- uint32_t finallen;
- uint32_t crc;
- uint8_t padding;
-
- enter_function();
- ssh_log(session,SSH_LOG_PACKET,"Sending a %d bytes long packet",currentlen);
-
-/* TODO FIXME
-#if defined(HAVE_LIBZ) && defined(WITH_LIBZ)
- if (session->current_crypto && session->current_crypto->do_compress_out) {
- if (compress_buffer(session, session->out_buffer) < 0) {
- goto error;
- }
- currentlen = buffer_get_len(session->out_buffer);
- }
-#endif
-*/
- padding = blocksize - (currentlen % blocksize);
- if (session->current_crypto) {
- ssh_get_random(padstring, padding, 0);
- } else {
- memset(padstring, 0, padding);
- }
-
- finallen = htonl(currentlen);
- ssh_log(session, SSH_LOG_PACKET,
- "%d bytes after comp + %d padding bytes = %d bytes packet",
- currentlen, padding, ntohl(finallen));
-
- if (buffer_prepend_data(session->out_buffer, &padstring, padding) < 0) {
- goto error;
- }
- if (buffer_prepend_data(session->out_buffer, &finallen, sizeof(uint32_t)) < 0) {
- goto error;
- }
-
- crc = ssh_crc32((char *)ssh_buffer_get_begin(session->out_buffer) + sizeof(uint32_t),
- ssh_buffer_get_len(session->out_buffer) - sizeof(uint32_t));
-
- if (buffer_add_u32(session->out_buffer, ntohl(crc)) < 0) {
- goto error;
- }
-
-#ifdef DEBUG_CRYPTO
- ssh_print_hexa("Clear packet", ssh_buffer_get_begin(session->out_buffer),
- ssh_buffer_get_len(session->out_buffer));
-#endif
-
- packet_encrypt(session, (unsigned char *)ssh_buffer_get_begin(session->out_buffer) + sizeof(uint32_t),
- ssh_buffer_get_len(session->out_buffer) - sizeof(uint32_t));
-
-#ifdef DEBUG_CRYPTO
- ssh_print_hexa("encrypted packet",ssh_buffer_get_begin(session->out_buffer),
- ssh_buffer_get_len(session->out_buffer));
-#endif
- rc=ssh_socket_write(session->socket, ssh_buffer_get_begin(session->out_buffer),
- ssh_buffer_get_len(session->out_buffer));
- if(rc== SSH_ERROR) {
- goto error;
- }
-
- session->send_seq++;
-
- if (buffer_reinit(session->out_buffer) < 0) {
- rc = SSH_ERROR;
- }
-error:
- leave_function();
- return rc; /* SSH_OK, AGAIN or ERROR */
-}
-
-SSH_PACKET_CALLBACK(ssh_packet_disconnect1){
- (void)packet;
- (void)user;
- (void)type;
- ssh_log(session, SSH_LOG_PACKET, "Received SSH_MSG_DISCONNECT");
- ssh_set_error(session, SSH_FATAL, "Received SSH_MSG_DISCONNECT");
- ssh_socket_close(session->socket);
- session->alive = 0;
- session->session_state=SSH_SESSION_STATE_DISCONNECTED;
- return SSH_PACKET_USED;
-}
-
-SSH_PACKET_CALLBACK(ssh_packet_smsg_success1){
- if(session->session_state==SSH_SESSION_STATE_KEXINIT_RECEIVED){
- session->session_state=SSH_SESSION_STATE_AUTHENTICATING;
- return SSH_PACKET_USED;
- } else if(session->session_state==SSH_SESSION_STATE_AUTHENTICATING){
- ssh_auth1_handler(session,type);
- return SSH_PACKET_USED;
- } else {
- return ssh_packet_channel_success(session,type,packet,user);
- }
-}
-
-SSH_PACKET_CALLBACK(ssh_packet_smsg_failure1){
- if(session->session_state==SSH_SESSION_STATE_KEXINIT_RECEIVED){
- session->session_state=SSH_SESSION_STATE_ERROR;
- ssh_set_error(session,SSH_FATAL,"Key exchange failed: received SSH_SMSG_FAILURE");
- return SSH_PACKET_USED;
- } else if(session->session_state==SSH_SESSION_STATE_AUTHENTICATING){
- ssh_auth1_handler(session,type);
- return SSH_PACKET_USED;
- } else {
- return ssh_packet_channel_failure(session,type,packet,user);
- }
-}
-
-
-#endif /* WITH_SSH1 */
-
-/* vim: set ts=2 sw=2 et cindent: */
diff --git a/libssh/pcap.c b/libssh/pcap.c
deleted file mode 100644
index 56bf3316..00000000
--- a/libssh/pcap.c
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- * This file is part of the SSH Library
- *
- * Copyright (c) 2009 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.
- */
-
-/* pcap.c */
-#include "config.h"
-#ifdef WITH_PCAP
-
-#include <stdio.h>
-#ifdef _WIN32
-#include <ws2tcpip.h>
-#else
-#include <sys/time.h>
-#include <sys/socket.h>
-#endif
-#include <errno.h>
-
-#include "libssh/libssh.h"
-#include "libssh/pcap.h"
-#include "libssh/session.h"
-#include "libssh/buffer.h"
-#include "libssh/socket.h"
-
-/**
- * @internal
- *
- * @defgroup libssh_pcap The libssh pcap functions
- * @ingroup libssh
- *
- * The pcap file generation
- *
- *
- * @{
- */
-
-/* The header of a pcap file is the following. We are not going to make it
- * very complicated.
- * Just for information.
- */
-struct pcap_hdr_s {
- uint32_t magic_number; /* magic number */
- uint16_t version_major; /* major version number */
- uint16_t version_minor; /* minor version number */
- int32_t thiszone; /* GMT to local correction */
- uint32_t sigfigs; /* accuracy of timestamps */
- uint32_t snaplen; /* max length of captured packets, in octets */
- uint32_t network; /* data link type */
-};
-
-#define PCAP_MAGIC 0xa1b2c3d4
-#define PCAP_VERSION_MAJOR 2
-#define PCAP_VERSION_MINOR 4
-
-#define DLT_RAW 12 /* raw IP */
-
-/* TCP flags */
-#define TH_FIN 0x01
-#define TH_SYN 0x02
-#define TH_RST 0x04
-#define TH_PUSH 0x08
-#define TH_ACK 0x10
-#define TH_URG 0x20
-
-/* The header of a pcap packet.
- * Just for information.
- */
-struct pcaprec_hdr_s {
- uint32_t ts_sec; /* timestamp seconds */
- uint32_t ts_usec; /* timestamp microseconds */
- uint32_t incl_len; /* number of octets of packet saved in file */
- uint32_t orig_len; /* actual length of packet */
-};
-
-/** @private
- * @brief a pcap context expresses the state of a pcap dump
- * in a SSH session only. Multiple pcap contexts may be used into
- * a single pcap file.
- */
-
-struct ssh_pcap_context_struct {
- ssh_session session;
- ssh_pcap_file file;
- int connected;
- /* All of these information are useful to generate
- * the dummy IP and TCP packets
- */
- uint32_t ipsource;
- uint32_t ipdest;
- uint16_t portsource;
- uint16_t portdest;
- uint32_t outsequence;
- uint32_t insequence;
-};
-
-/** @private
- * @brief a pcap file expresses the state of a pcap file which may
- * contain several streams.
- */
-struct ssh_pcap_file_struct {
- FILE *output;
- uint16_t ipsequence;
-};
-
-/**
- * @brief create a new ssh_pcap_file object
- */
-ssh_pcap_file ssh_pcap_file_new(){
- struct ssh_pcap_file_struct *pcap;
-
- pcap = malloc(sizeof(struct ssh_pcap_file_struct));
- if (pcap == NULL) {
- return NULL;
- }
- ZERO_STRUCTP(pcap);
-
- return pcap;
-}
-
-/** @internal
- * @brief writes a packet on file
- */
-static int ssh_pcap_file_write(ssh_pcap_file pcap, ssh_buffer packet){
- int err;
- uint32_t len;
- if(pcap == NULL || pcap->output==NULL)
- return SSH_ERROR;
- len=ssh_buffer_get_len(packet);
- err=fwrite(ssh_buffer_get_begin(packet),len,1,pcap->output);
- if(err<0)
- return SSH_ERROR;
- else
- return SSH_OK;
-}
-
-/** @internal
- * @brief prepends a packet with the pcap header and writes packet
- * on file
- */
-int ssh_pcap_file_write_packet(ssh_pcap_file pcap, ssh_buffer packet, uint32_t original_len){
- ssh_buffer header=ssh_buffer_new();
- struct timeval now;
- int err;
- if(header == NULL)
- return SSH_ERROR;
- gettimeofday(&now,NULL);
- buffer_add_u32(header,htonl(now.tv_sec));
- buffer_add_u32(header,htonl(now.tv_usec));
- buffer_add_u32(header,htonl(ssh_buffer_get_len(packet)));
- buffer_add_u32(header,htonl(original_len));
- buffer_add_buffer(header,packet);
- err=ssh_pcap_file_write(pcap,header);
- ssh_buffer_free(header);
- return err;
-}
-
-/**
- * @brief opens a new pcap file and create header
- */
-int ssh_pcap_file_open(ssh_pcap_file pcap, const char *filename){
- ssh_buffer header;
- int err;
- if(pcap == NULL)
- return SSH_ERROR;
- if(pcap->output){
- fclose(pcap->output);
- pcap->output=NULL;
- }
- pcap->output=fopen(filename,"wb");
- if(pcap->output==NULL)
- return SSH_ERROR;
- header=ssh_buffer_new();
- if(header==NULL)
- return SSH_ERROR;
- buffer_add_u32(header,htonl(PCAP_MAGIC));
- buffer_add_u16(header,htons(PCAP_VERSION_MAJOR));
- buffer_add_u16(header,htons(PCAP_VERSION_MINOR));
- /* currently hardcode GMT to 0 */
- buffer_add_u32(header,htonl(0));
- /* accuracy */
- buffer_add_u32(header,htonl(0));
- /* size of the biggest packet */
- buffer_add_u32(header,htonl(MAX_PACKET_LEN));
- /* we will write sort-of IP */
- buffer_add_u32(header,htonl(DLT_RAW));
- err=ssh_pcap_file_write(pcap,header);
- ssh_buffer_free(header);
- return err;
-}
-
-int ssh_pcap_file_close(ssh_pcap_file pcap){
- int err;
- if(pcap ==NULL || pcap->output==NULL)
- return SSH_ERROR;
- err=fclose(pcap->output);
- pcap->output=NULL;
- if(err != 0)
- return SSH_ERROR;
- else
- return SSH_OK;
-}
-
-void ssh_pcap_file_free(ssh_pcap_file pcap){
- ssh_pcap_file_close(pcap);
- SAFE_FREE(pcap);
-}
-
-
-/** @internal
- * @brief allocates a new ssh_pcap_context object
- */
-
-ssh_pcap_context ssh_pcap_context_new(ssh_session session){
- ssh_pcap_context ctx=malloc(sizeof(struct ssh_pcap_context_struct));
- if(ctx==NULL){
- ssh_set_error_oom(session);
- return NULL;
- }
- ZERO_STRUCTP(ctx);
- ctx->session=session;
- return ctx;
-}
-
-void ssh_pcap_context_free(ssh_pcap_context ctx){
- SAFE_FREE(ctx);
-}
-
-void ssh_pcap_context_set_file(ssh_pcap_context ctx, ssh_pcap_file pcap){
- ctx->file=pcap;
-}
-
-/** @internal
- * @brief sets the IP and port parameters in the connection
- */
-static int ssh_pcap_context_connect(ssh_pcap_context ctx){
- ssh_session session=ctx->session;
- struct sockaddr_in local, remote;
- socket_t fd;
- socklen_t len;
- if(session==NULL)
- return SSH_ERROR;
- if(session->socket==NULL)
- return SSH_ERROR;
- fd=ssh_socket_get_fd_in(session->socket);
- /* TODO: adapt for windows */
- if(fd<0)
- return SSH_ERROR;
- len=sizeof(local);
- if(getsockname(fd,(struct sockaddr *)&local,&len)<0){
- ssh_set_error(session,SSH_REQUEST_DENIED,"Getting local IP address: %s",strerror(errno));
- return SSH_ERROR;
- }
- len=sizeof(remote);
- if(getpeername(fd,(struct sockaddr *)&remote,&len)<0){
- ssh_set_error(session,SSH_REQUEST_DENIED,"Getting remote IP address: %s",strerror(errno));
- return SSH_ERROR;
- }
- if(local.sin_family != AF_INET){
- ssh_set_error(session,SSH_REQUEST_DENIED,"Only IPv4 supported for pcap logging");
- return SSH_ERROR;
- }
- memcpy(&ctx->ipsource,&local.sin_addr,sizeof(ctx->ipsource));
- memcpy(&ctx->ipdest,&remote.sin_addr,sizeof(ctx->ipdest));
- memcpy(&ctx->portsource,&local.sin_port,sizeof(ctx->portsource));
- memcpy(&ctx->portdest,&remote.sin_port,sizeof(ctx->portdest));
-
- ctx->connected=1;
- return SSH_OK;
-}
-
-#define IPHDR_LEN 20
-#define TCPHDR_LEN 20
-#define TCPIPHDR_LEN (IPHDR_LEN + TCPHDR_LEN)
-/** @internal
- * @brief write a SSH packet as a TCP over IP in a pcap file
- * @param ctx open pcap context
- * @param direction SSH_PCAP_DIRECTION_IN if the packet has been received
- * @param direction SSH_PCAP_DIRECTION_OUT if the packet has been emitted
- * @param data pointer to the data to write
- * @param len data to write in the pcap file. May be smaller than origlen.
- * @param origlen number of bytes of complete data.
- * @returns SSH_OK write is successful
- * @returns SSH_ERROR an error happened.
- */
-int ssh_pcap_context_write(ssh_pcap_context ctx,enum ssh_pcap_direction direction
- , void *data, uint32_t len, uint32_t origlen){
- ssh_buffer ip;
- int err;
- if(ctx==NULL || ctx->file ==NULL)
- return SSH_ERROR;
- if(ctx->connected==0)
- if(ssh_pcap_context_connect(ctx)==SSH_ERROR)
- return SSH_ERROR;
- ip=ssh_buffer_new();
- if(ip==NULL){
- ssh_set_error_oom(ctx->session);
- return SSH_ERROR;
- }
- /* build an IP packet */
- /* V4, 20 bytes */
- buffer_add_u8(ip,4 << 4 | 5);
- /* tos */
- buffer_add_u8(ip,0);
- /* total len */
- buffer_add_u16(ip,htons(origlen + TCPIPHDR_LEN));
- /* IP id number */
- buffer_add_u16(ip,htons(ctx->file->ipsequence));
- ctx->file->ipsequence++;
- /* fragment offset */
- buffer_add_u16(ip,htons(0));
- /* TTL */
- buffer_add_u8(ip,64);
- /* protocol TCP=6 */
- buffer_add_u8(ip,6);
- /* checksum */
- buffer_add_u16(ip,0);
- if(direction==SSH_PCAP_DIR_OUT){
- buffer_add_u32(ip,ctx->ipsource);
- buffer_add_u32(ip,ctx->ipdest);
- } else {
- buffer_add_u32(ip,ctx->ipdest);
- buffer_add_u32(ip,ctx->ipsource);
- }
- /* TCP */
- if(direction==SSH_PCAP_DIR_OUT){
- buffer_add_u16(ip,ctx->portsource);
- buffer_add_u16(ip,ctx->portdest);
- } else {
- buffer_add_u16(ip,ctx->portdest);
- buffer_add_u16(ip,ctx->portsource);
- }
- /* sequence number */
- if(direction==SSH_PCAP_DIR_OUT){
- buffer_add_u32(ip,ntohl(ctx->outsequence));
- ctx->outsequence+=origlen;
- } else {
- buffer_add_u32(ip,ntohl(ctx->insequence));
- ctx->insequence+=origlen;
- }
- /* ack number */
- if(direction==SSH_PCAP_DIR_OUT){
- buffer_add_u32(ip,ntohl(ctx->insequence));
- } else {
- buffer_add_u32(ip,ntohl(ctx->outsequence));
- }
- /* header len = 20 = 5 * 32 bits, at offset 4*/
- buffer_add_u8(ip,5 << 4);
- /* flags */
- buffer_add_u8(ip,TH_PUSH | TH_ACK);
- /* window */
- buffer_add_u16(ip,htons(65535));
- /* checksum */
- buffer_add_u16(ip,htons(0));
- /* urgent data ptr */
- buffer_add_u16(ip,0);
- /* actual data */
- buffer_add_data(ip,data,len);
- err=ssh_pcap_file_write_packet(ctx->file,ip,origlen + TCPIPHDR_LEN);
- ssh_buffer_free(ip);
- return err;
-}
-
-/** @brief sets the pcap file used to trace the session
- * @param current session
- * @param pcap an handler to a pcap file. A pcap file may be used in several
- * sessions.
- * @returns SSH_ERROR in case of error, SSH_OK otherwise.
- */
-int ssh_set_pcap_file(ssh_session session, ssh_pcap_file pcap){
- ssh_pcap_context ctx=ssh_pcap_context_new(session);
- if(ctx==NULL){
- ssh_set_error_oom(session);
- return SSH_ERROR;
- }
- ctx->file=pcap;
- if(session->pcap_ctx)
- ssh_pcap_context_free(session->pcap_ctx);
- session->pcap_ctx=ctx;
- return SSH_OK;
-}
-
-
-#else /* WITH_PCAP */
-
-/* Simple stub returning errors when no pcap compiled in */
-
-#include "libssh/libssh.h"
-#include "libssh/priv.h"
-
-int ssh_pcap_file_close(ssh_pcap_file pcap){
- (void) pcap;
- return SSH_ERROR;
-}
-
-void ssh_pcap_file_free(ssh_pcap_file pcap){
- (void) pcap;
-}
-
-ssh_pcap_file ssh_pcap_file_new(void){
- return NULL;
-}
-int ssh_pcap_file_open(ssh_pcap_file pcap, const char *filename){
- (void) pcap;
- (void) filename;
- return SSH_ERROR;
-}
-
-int ssh_set_pcap_file(ssh_session session, ssh_pcap_file pcapfile){
- (void) pcapfile;
- ssh_set_error(session,SSH_REQUEST_DENIED,"Pcap support not compiled in");
- return SSH_ERROR;
-}
-
-#endif
-
-/** @} */
-
-/* vim: set ts=4 sw=4 et cindent: */
diff --git a/libssh/pki.c b/libssh/pki.c
deleted file mode 100644
index ef925dd0..00000000
--- a/libssh/pki.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * This file is part of the SSH Library
- *
- * Copyright (c) 2010 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.
- */
-
-/** @defgroup ssh_pki SSH Public Key Infrastructure
- * @ingroup libssh
- *
- * Functions for the creation, importation and manipulation of public and
- * private keys in the context of the SSH protocol
- *
- * @{
- */
-
-#include "libssh/priv.h"
-#include "libssh/pki.h"
-#include "libssh/keys.h"
-
-/**
- * @brief creates a new empty SSH key
- * @returns an empty ssh_key handle
- */
-ssh_key ssh_key_new (void){
- ssh_key ptr=malloc (sizeof (struct ssh_key_struct));
- ZERO_STRUCTP(ptr);
- return ptr;
-}
-
-/**
- * @brief clean up the key and deallocate all existing keys
- * @param[in] key ssh_key to clean
- */
-void ssh_key_clean (ssh_key key){
- if(key==NULL)
- return;
-#ifdef HAVE_LIBGCRYPT
- gcry_sexp_release(key->dsa);
- gcry_sexp_release(key->rsa);
-#elif defined HAVE_LIBCRYPTO
- DSA_free(key->dsa);
- RSA_free(key->rsa);
-#endif
- key->flags=SSH_KEY_FLAG_EMPTY;
- key->type=SSH_KEYTYPE_UNKNOWN;
- key->type_c=NULL;
-}
-
-/**
- * @brief deallocate a SSH key
- * @param[in] key ssh_key handle to free
- */
-void ssh_key_free (ssh_key key){
- if(key){
- ssh_key_clean(key);
- SAFE_FREE(key);
- }
-}
-
-/**
- * @brief returns the type of a ssh key
- * @param[in] key the ssh_key handle
- * @returns one of SSH_KEYTYPE_RSA,SSH_KEYTYPE_DSS,SSH_KEYTYPE_RSA1
- * @returns SSH_KEYTYPE_UNKNOWN if the type is unknown
- */
-enum ssh_keytypes_e ssh_key_type(ssh_key key){
- if (key==NULL)
- return SSH_KEYTYPE_UNKNOWN;
- return key->type;
-}
-
-/**
- * @brief import a key from a file
- * @param[out] key the ssh_key to update
- * @param[in] session The SSH Session to use. If a key decryption callback is set, it will
- * be used to ask for the passphrase.
- * @param[in] filename The filename of the the private key.
- * @param[in] passphrase The passphrase to decrypt the private key. Set to null
- * if none is needed or it is unknown.
- * @returns SSH_OK on success, SSH_ERROR otherwise.
- **/
-int ssh_key_import_private(ssh_key key, ssh_session session, const char *filename, const char *passphrase){
- ssh_private_key priv=privatekey_from_file(session,filename,0,passphrase);
- if(priv==NULL)
- return SSH_ERROR;
- ssh_key_clean(key);
- key->dsa=priv->dsa_priv;
- key->rsa=priv->rsa_priv;
- key->type=priv->type;
- key->flags=SSH_KEY_FLAG_PRIVATE | SSH_KEY_FLAG_PUBLIC;
- key->type_c=ssh_type_to_char(key->type);
- SAFE_FREE(priv);
- return SSH_OK;
-}
-
-/**
- * @}
- */
diff --git a/libssh/poll.c b/libssh/poll.c
deleted file mode 100644
index 7942ea0b..00000000
--- a/libssh/poll.c
+++ /dev/null
@@ -1,692 +0,0 @@
-/*
- * poll.c - poll wrapper
- *
- * This file is part of the SSH Library
- *
- * Copyright (c) 2009-2010 by Andreas Schneider <mail@cynapses.org>
- * Copyright (c) 2003-2009 by Aris Adamantiadis
- * Copyright (c) 2009 Aleksandar Kanchev
- *
- * 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.
- *
- * vim: ts=2 sw=2 et cindent
- */
-
-#include "config.h"
-
-#include <errno.h>
-
-#include "libssh/priv.h"
-#include "libssh/libssh.h"
-#include "libssh/poll.h"
-#include "libssh/socket.h"
-
-#ifndef SSH_POLL_CTX_CHUNK
-#define SSH_POLL_CTX_CHUNK 5
-#endif
-
-/**
- * @defgroup libssh_poll The SSH poll functions.
- * @ingroup libssh
- *
- * Add a generic way to handle sockets asynchronously.
- *
- * It's based on poll objects, each of which store a socket, it's events and a
- * callback, which gets called whenever an event is set. The poll objects are
- * attached to a poll context, which should be allocated on per thread basis.
- *
- * Polling the poll context will poll all the attached poll objects and call
- * their callbacks (handlers) if any of the socket events are set. This should
- * be done within the main loop of an application.
- *
- * @{
- */
-
-/** global poll context used for blocking operations */
-static ssh_poll_ctx global_poll_ctx;
-
-struct ssh_poll_handle_struct {
- ssh_poll_ctx ctx;
- union {
- socket_t fd;
- size_t idx;
- } x;
- short events;
- ssh_poll_callback cb;
- void *cb_data;
-};
-
-struct ssh_poll_ctx_struct {
- ssh_poll_handle *pollptrs;
- ssh_pollfd_t *pollfds;
- size_t polls_allocated;
- size_t polls_used;
- size_t chunk_size;
-};
-
-#ifdef HAVE_POLL
-#include <poll.h>
-
-void ssh_poll_init(void) {
- return;
-}
-
-void ssh_poll_cleanup(void) {
- return;
-}
-
-int ssh_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout) {
- return poll((struct pollfd *) fds, nfds, timeout);
-}
-
-#else /* HAVE_POLL */
-
-typedef int (*poll_fn)(ssh_pollfd_t *, nfds_t, int);
-static poll_fn ssh_poll_emu;
-
-#include <sys/types.h>
-
-#ifdef _WIN32
-#ifndef STRICT
-#define STRICT
-#endif /* STRICT */
-
-#include <time.h>
-#include <windows.h>
-#include <winsock2.h>
-
-#if (_WIN32_WINNT < 0x0600)
-typedef struct ssh_pollfd_struct WSAPOLLFD;
-#endif
-
-typedef int (WSAAPI* WSAPoll_FunctionType)(WSAPOLLFD fdarray[],
- ULONG nfds,
- INT timeout
-);
-
-static WSAPoll_FunctionType wsa_poll;
-
-int win_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout) {
- if (wsa_poll) {
- return (wsa_poll)(fds, nfds, timeout);
- }
-
- return SOCKET_ERROR;
-}
-
-#define WS2_LIBRARY "ws2_32.dll"
-static HINSTANCE hlib;
-
-#else /* _WIN32 */
-#include <sys/select.h>
-#include <sys/socket.h>
-#include <unistd.h>
-#include <sys/time.h>
-#endif /* _WIN32 */
-
-
-/*
- * This is a poll(2)-emulation using select for systems not providing a native
- * poll implementation.
- *
- * Keep in mind that select is terribly inefficient. The interface is simply not
- * meant to be used with maximum descriptor value greater, say, 32 or so. With
- * a value as high as 1024 on Linux you'll pay dearly in every single call.
- * poll() will be orders of magnitude faster.
- */
-static int bsd_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout) {
- fd_set readfds, writefds, exceptfds;
- struct timeval tv, *ptv;
- socket_t max_fd;
- int rc;
- nfds_t i;
-
- if (fds == NULL) {
- errno = EFAULT;
- return -1;
- }
-
- FD_ZERO (&readfds);
- FD_ZERO (&writefds);
- FD_ZERO (&exceptfds);
-
- /* compute fd_sets and find largest descriptor */
- for (rc = -1, max_fd = 0, i = 0; i < nfds; i++) {
- if (fds[i].fd == SSH_INVALID_SOCKET) {
- continue;
- }
-#ifndef _WIN32
- if (fds[i].fd >= FD_SETSIZE) {
- rc = -1;
- break;
- }
-#endif
-
- if (fds[i].events & (POLLIN | POLLRDNORM)) {
- FD_SET (fds[i].fd, &readfds);
- }
- if (fds[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND)) {
- FD_SET (fds[i].fd, &writefds);
- }
- if (fds[i].events & (POLLPRI | POLLRDBAND)) {
- FD_SET (fds[i].fd, &exceptfds);
- }
- if (fds[i].fd > max_fd &&
- (fds[i].events & (POLLIN | POLLOUT | POLLPRI |
- POLLRDNORM | POLLRDBAND |
- POLLWRNORM | POLLWRBAND))) {
- max_fd = fds[i].fd;
- rc = 0;
- }
- }
-
- if (max_fd == SSH_INVALID_SOCKET || rc == -1) {
- errno = EINVAL;
- return -1;
- }
-
- if (timeout < 0) {
- ptv = NULL;
- } else {
- ptv = &tv;
- if (timeout == 0) {
- tv.tv_sec = 0;
- tv.tv_usec = 0;
- } else {
- tv.tv_sec = timeout / 1000;
- tv.tv_usec = (timeout % 1000) * 1000;
- }
- }
-
- rc = select (max_fd + 1, &readfds, &writefds, &exceptfds, ptv);
- if (rc < 0) {
- return -1;
- }
-
- for (rc = 0, i = 0; i < nfds; i++)
- if (fds[i].fd >= 0) {
- fds[i].revents = 0;
-
- if (FD_ISSET(fds[i].fd, &readfds)) {
- int save_errno = errno;
- char data[64] = {0};
- int ret;
-
- /* support for POLLHUP */
- ret = recv(fds[i].fd, data, 64, MSG_PEEK);
-#ifdef _WIN32
- if ((ret == -1) &&
- (errno == WSAESHUTDOWN || errno == WSAECONNRESET ||
- errno == WSAECONNABORTED || errno == WSAENETRESET)) {
-#else
- if ((ret == -1) &&
- (errno == ESHUTDOWN || errno == ECONNRESET ||
- errno == ECONNABORTED || errno == ENETRESET)) {
-#endif
- fds[i].revents |= POLLHUP;
- } else {
- fds[i].revents |= fds[i].events & (POLLIN | POLLRDNORM);
- }
-
- errno = save_errno;
- }
- if (FD_ISSET(fds[i].fd, &writefds)) {
- fds[i].revents |= fds[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND);
- }
-
- if (FD_ISSET(fds[i].fd, &exceptfds)) {
- fds[i].revents |= fds[i].events & (POLLPRI | POLLRDBAND);
- }
-
- if (fds[i].revents & ~POLLHUP) {
- rc++;
- }
- } else {
- fds[i].revents = POLLNVAL;
- }
-
- return rc;
-}
-
-void ssh_poll_init(void) {
- ssh_poll_emu = bsd_poll;
-
-#ifdef _WIN32
- hlib = LoadLibrary(WS2_LIBRARY);
- if (hlib != NULL) {
- wsa_poll = (WSAPoll_FunctionType) (void *) GetProcAddress(hlib, "WSAPoll");
- }
-#endif /* _WIN32 */
-
- if (wsa_poll != NULL) {
- ssh_poll_emu = bsd_poll;
- }
-}
-
-void ssh_poll_cleanup(void) {
- ssh_poll_emu = bsd_poll;
-#ifdef _WIN32
- wsa_poll = NULL;
-
- FreeLibrary(hlib);
-
- hlib = NULL;
-#endif /* _WIN32 */
-}
-
-int ssh_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout) {
- return (ssh_poll_emu)(fds, nfds, timeout);
-}
-
-#endif /* HAVE_POLL */
-
-/**
- * @brief Allocate a new poll object, which could be used within a poll context.
- *
- * @param fd Socket that will be polled.
- * @param events Poll events that will be monitored for the socket. i.e.
- * POLLIN, POLLPRI, POLLOUT, POLLERR, POLLHUP, POLLNVAL
- * @param cb Function to be called if any of the events are set.
- * @param userdata Userdata to be passed to the callback function. NULL if
- * not needed.
- *
- * @return A new poll object, NULL on error
- */
-
-ssh_poll_handle ssh_poll_new(socket_t fd, short events, ssh_poll_callback cb,
- void *userdata) {
- ssh_poll_handle p;
-
- p = malloc(sizeof(struct ssh_poll_handle_struct));
- if (p != NULL) {
- p->ctx = NULL;
- p->x.fd = fd;
- p->events = events;
- p->cb = cb;
- p->cb_data = userdata;
- }
-
- return p;
-}
-
-
-/**
- * @brief Free a poll object.
- *
- * @param p Pointer to an already allocated poll object.
- */
-
-void ssh_poll_free(ssh_poll_handle p) {
- if(p->ctx != NULL){
- ssh_poll_ctx_remove(p->ctx,p);
- p->ctx=NULL;
- }
- SAFE_FREE(p);
-}
-
-/**
- * @brief Get the poll context of a poll object.
- *
- * @param p Pointer to an already allocated poll object.
- *
- * @return Poll context or NULL if the poll object isn't attached.
- */
-ssh_poll_ctx ssh_poll_get_ctx(ssh_poll_handle p) {
- return p->ctx;
-}
-
-/**
- * @brief Get the events of a poll object.
- *
- * @param p Pointer to an already allocated poll object.
- *
- * @return Poll events.
- */
-short ssh_poll_get_events(ssh_poll_handle p) {
- return p->events;
-}
-
-/**
- * @brief Set the events of a poll object. The events will also be propagated
- * to an associated poll context.
- *
- * @param p Pointer to an already allocated poll object.
- * @param events Poll events.
- */
-void ssh_poll_set_events(ssh_poll_handle p, short events) {
- p->events = events;
- if (p->ctx != NULL) {
- p->ctx->pollfds[p->x.idx].events = events;
- }
-}
-
-/**
- * @brief Set the file descriptor of a poll object. The FD will also be propagated
- * to an associated poll context.
- *
- * @param p Pointer to an already allocated poll object.
- * @param fd New file descriptor.
- */
-void ssh_poll_set_fd(ssh_poll_handle p, socket_t fd) {
- if (p->ctx != NULL) {
- p->ctx->pollfds[p->x.idx].fd = fd;
- } else {
- p->x.fd = fd;
- }
-}
-
-/**
- * @brief Add extra events to a poll object. Duplicates are ignored.
- * The events will also be propagated to an associated poll context.
- *
- * @param p Pointer to an already allocated poll object.
- * @param events Poll events.
- */
-void ssh_poll_add_events(ssh_poll_handle p, short events) {
- ssh_poll_set_events(p, ssh_poll_get_events(p) | events);
-}
-
-/**
- * @brief Remove events from a poll object. Non-existent are ignored.
- * The events will also be propagated to an associated poll context.
- *
- * @param p Pointer to an already allocated poll object.
- * @param events Poll events.
- */
-void ssh_poll_remove_events(ssh_poll_handle p, short events) {
- ssh_poll_set_events(p, ssh_poll_get_events(p) & ~events);
-}
-
-/**
- * @brief Get the raw socket of a poll object.
- *
- * @param p Pointer to an already allocated poll object.
- *
- * @return Raw socket.
- */
-
-socket_t ssh_poll_get_fd(ssh_poll_handle p) {
- if (p->ctx != NULL) {
- return p->ctx->pollfds[p->x.idx].fd;
- }
-
- return p->x.fd;
-}
-/**
- * @brief Set the callback of a poll object.
- *
- * @param p Pointer to an already allocated poll object.
- * @param cb Function to be called if any of the events are set.
- * @param userdata Userdata to be passed to the callback function. NULL if
- * not needed.
- */
-void ssh_poll_set_callback(ssh_poll_handle p, ssh_poll_callback cb, void *userdata) {
- if (cb != NULL) {
- p->cb = cb;
- p->cb_data = userdata;
- }
-}
-
-/**
- * @brief Create a new poll context. It could be associated with many poll object
- * which are going to be polled at the same time as the poll context. You
- * would need a single poll context per thread.
- *
- * @param chunk_size The size of the memory chunk that will be allocated, when
- * more memory is needed. This is for efficiency reasons,
- * i.e. don't allocate memory for each new poll object, but
- * for the next 5. Set it to 0 if you want to use the
- * library's default value.
- */
-ssh_poll_ctx ssh_poll_ctx_new(size_t chunk_size) {
- ssh_poll_ctx ctx;
-
- ctx = malloc(sizeof(struct ssh_poll_ctx_struct));
- if (ctx != NULL) {
- if (!chunk_size) {
- chunk_size = SSH_POLL_CTX_CHUNK;
- }
-
- ctx->chunk_size = chunk_size;
- ctx->pollptrs = NULL;
- ctx->pollfds = NULL;
- ctx->polls_allocated = 0;
- ctx->polls_used = 0;
- }
-
- return ctx;
-}
-
-/**
- * @brief Free a poll context.
- *
- * @param ctx Pointer to an already allocated poll context.
- */
-void ssh_poll_ctx_free(ssh_poll_ctx ctx) {
- if (ctx->polls_allocated > 0) {
- register size_t i, used;
-
- used = ctx->polls_used;
- for (i = 0; i < used; ) {
- ssh_poll_handle p = ctx->pollptrs[i];
- socket_t fd = ctx->pollfds[i].fd;
-
- /* force poll object removal */
- if (p->cb(p, fd, POLLERR, p->cb_data) < 0) {
- used = ctx->polls_used;
- } else {
- i++;
- }
- }
-
- SAFE_FREE(ctx->pollptrs);
- SAFE_FREE(ctx->pollfds);
- }
-
- SAFE_FREE(ctx);
-}
-
-static int ssh_poll_ctx_resize(ssh_poll_ctx ctx, size_t new_size) {
- ssh_poll_handle *pollptrs;
- ssh_pollfd_t *pollfds;
-
- pollptrs = realloc(ctx->pollptrs, sizeof(ssh_poll_handle *) * new_size);
- if (pollptrs == NULL) {
- return -1;
- }
-
- pollfds = realloc(ctx->pollfds, sizeof(ssh_pollfd_t) * new_size);
- if (pollfds == NULL) {
- ctx->pollptrs = realloc(pollptrs, sizeof(ssh_poll_handle *) * ctx->polls_allocated);
- return -1;
- }
-
- ctx->pollptrs = pollptrs;
- ctx->pollfds = pollfds;
- ctx->polls_allocated = new_size;
-
- return 0;
-}
-
-/**
- * @brief Add a poll object to a poll context.
- *
- * @param ctx Pointer to an already allocated poll context.
- * @param p Pointer to an already allocated poll object.
- *
- * @return 0 on success, < 0 on error
- */
-int ssh_poll_ctx_add(ssh_poll_ctx ctx, ssh_poll_handle p) {
- socket_t fd;
-
- if (p->ctx != NULL) {
- /* already attached to a context */
- return -1;
- }
-
- if (ctx->polls_used == ctx->polls_allocated &&
- ssh_poll_ctx_resize(ctx, ctx->polls_allocated + ctx->chunk_size) < 0) {
- return -1;
- }
-
- fd = p->x.fd;
- p->x.idx = ctx->polls_used++;
- ctx->pollptrs[p->x.idx] = p;
- ctx->pollfds[p->x.idx].fd = fd;
- ctx->pollfds[p->x.idx].events = p->events;
- ctx->pollfds[p->x.idx].revents = 0;
- p->ctx = ctx;
-
- return 0;
-}
-
-/**
- * @brief Add a socket object to a poll context.
- *
- * @param ctx Pointer to an already allocated poll context.
- * @param s A SSH socket handle
- *
- * @return 0 on success, < 0 on error
- */
-int ssh_poll_ctx_add_socket (ssh_poll_ctx ctx, ssh_socket s) {
- ssh_poll_handle p_in, p_out;
- int ret;
- p_in=ssh_socket_get_poll_handle_in(s);
- if(p_in==NULL)
- return -1;
- ret = ssh_poll_ctx_add(ctx,p_in);
- if(ret != 0)
- return ret;
- p_out=ssh_socket_get_poll_handle_out(s);
- if(p_in != p_out)
- ret = ssh_poll_ctx_add(ctx,p_out);
- return ret;
-}
-
-
-/**
- * @brief Remove a poll object from a poll context.
- *
- * @param ctx Pointer to an already allocated poll context.
- * @param p Pointer to an already allocated poll object.
- */
-void ssh_poll_ctx_remove(ssh_poll_ctx ctx, ssh_poll_handle p) {
- size_t i;
-
- i = p->x.idx;
- p->x.fd = ctx->pollfds[i].fd;
- p->ctx = NULL;
-
- ctx->polls_used--;
-
- /* fill the empty poll slot with the last one */
- if (ctx->polls_used > 0 && ctx->polls_used != i) {
- ctx->pollfds[i] = ctx->pollfds[ctx->polls_used];
- ctx->pollptrs[i] = ctx->pollptrs[ctx->polls_used];
- }
-
- /* this will always leave at least chunk_size polls allocated */
- if (ctx->polls_allocated - ctx->polls_used > ctx->chunk_size) {
- ssh_poll_ctx_resize(ctx, ctx->polls_allocated - ctx->chunk_size);
- }
-}
-
-/**
- * @brief Poll all the sockets associated through a poll object with a
- * poll context. If any of the events are set after the poll, the
- * call back function of the socket will be called.
- * This function should be called once within the programs main loop.
- *
- * @param ctx Pointer to an already allocated poll context.
- * @param timeout An upper limit on the time for which ssh_poll_ctx() will
- * block, in milliseconds. Specifying a negative value
- * means an infinite timeout. This parameter is passed to
- * the poll() function.
- * @returns SSH_OK No error.
- * SSH_ERROR Error happened during the poll.
- */
-
-int ssh_poll_ctx_dopoll(ssh_poll_ctx ctx, int timeout) {
- int rc;
- int i, used;
- ssh_poll_handle p;
- socket_t fd;
- int revents;
-
- if (!ctx->polls_used)
- return 0;
-
- rc = ssh_poll(ctx->pollfds, ctx->polls_used, timeout);
- if(rc < 0)
- rc=SSH_ERROR;
- if(rc <= 0)
- return rc;
- used = ctx->polls_used;
- for (i = 0; i < used && rc > 0; ) {
- if (!ctx->pollfds[i].revents) {
- i++;
- } else {
- p = ctx->pollptrs[i];
- fd = ctx->pollfds[i].fd;
- revents = ctx->pollfds[i].revents;
-
- if (p->cb(p, fd, revents, p->cb_data) < 0) {
- /* the poll was removed, reload the used counter and start again */
- used = ctx->polls_used;
- i=0;
- } else {
- ctx->pollfds[i].revents = 0;
- i++;
- }
-
- rc--;
- }
- }
-
- return rc;
-}
-
-/** @internal
- * @brief returns a pointer to the global poll context.
- * Allocates it if it does not exist.
- * @param session an optional session handler, used to store the error
- * message if needed.
- * @returns pointer to the global poll context.
- */
-ssh_poll_ctx ssh_get_global_poll_ctx(ssh_session session){
- if(global_poll_ctx != NULL)
- return global_poll_ctx;
- global_poll_ctx=ssh_poll_ctx_new(5);
- if(global_poll_ctx == NULL && session != NULL){
- ssh_set_error_oom(session);
- return NULL;
- }
- return global_poll_ctx;
-}
-
-/** @internal
- * @brief Deallocate the global poll context
- */
-void ssh_free_global_poll_ctx(){
- if(global_poll_ctx != NULL){
- ssh_poll_ctx_free(global_poll_ctx);
- global_poll_ctx=NULL;
- }
-}
-
-/** @} */
-
-/* vim: set ts=4 sw=4 et cindent: */
diff --git a/libssh/scp.c b/libssh/scp.c
deleted file mode 100644
index 4a6f6f14..00000000
--- a/libssh/scp.c
+++ /dev/null
@@ -1,752 +0,0 @@
-/*
- * scp - SSH scp wrapper functions
- *
- * This file is part of the SSH Library
- *
- * Copyright (c) 2009 by Aris Adamantiadis <aris@0xbadc0de.be>
- *
- * 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 <string.h>
-
-#include "libssh/priv.h"
-#include "libssh/scp.h"
-
-/**
- * @defgroup libssh_scp The SSH scp functions
- * @ingroup libssh
- *
- * SCP protocol over SSH functions
- *
- * @{
- */
-
-/**
- * @brief Create a new scp session.
- *
- * @param[in] session The SSH session to use.
- *
- * @param[in] mode One of SSH_SCP_WRITE or SSH_SCP_READ, depending if you
- * need to drop files remotely or read them.
- * It is not possible to combine read and write.
- *
- * @param[in] location The directory in which write or read will be done. Any
- * push or pull will be relative to this place.
- *
- * @returns A ssh_scp handle, NULL if the creation was impossible.
- */
-ssh_scp ssh_scp_new(ssh_session session, int mode, const char *location){
- ssh_scp scp=malloc(sizeof(struct ssh_scp_struct));
- if(scp == NULL){
- ssh_set_error(session,SSH_FATAL,"Error allocating memory for ssh_scp");
- return NULL;
- }
- ZERO_STRUCTP(scp);
- if((mode&~SSH_SCP_RECURSIVE) != SSH_SCP_WRITE && (mode &~SSH_SCP_RECURSIVE) != SSH_SCP_READ){
- ssh_set_error(session,SSH_FATAL,"Invalid mode %d for ssh_scp_new()",mode);
- ssh_scp_free(scp);
- return NULL;
- }
- scp->location=strdup(location);
- if (scp->location == NULL) {
- ssh_set_error(session,SSH_FATAL,"Error allocating memory for ssh_scp");
- ssh_scp_free(scp);
- return NULL;
- }
- scp->session=session;
- scp->mode=mode & ~SSH_SCP_RECURSIVE;
- scp->recursive = (mode & SSH_SCP_RECURSIVE) != 0;
- scp->channel=NULL;
- scp->state=SSH_SCP_NEW;
- return scp;
-}
-
-int ssh_scp_init(ssh_scp scp){
- int r;
- char execbuffer[1024];
- uint8_t code;
- if(scp==NULL)
- return SSH_ERROR;
- if(scp->state != SSH_SCP_NEW){
- ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_init called under invalid state");
- return SSH_ERROR;
- }
- ssh_log(scp->session,SSH_LOG_PROTOCOL,"Initializing scp session %s %son location '%s'",
- scp->mode==SSH_SCP_WRITE?"write":"read",
- scp->recursive?"recursive ":"",
- scp->location);
- scp->channel=ssh_channel_new(scp->session);
- if(scp->channel == NULL){
- scp->state=SSH_SCP_ERROR;
- return SSH_ERROR;
- }
- r= ssh_channel_open_session(scp->channel);
- if(r==SSH_ERROR){
- scp->state=SSH_SCP_ERROR;
- return SSH_ERROR;
- }
- if(scp->mode == SSH_SCP_WRITE)
- snprintf(execbuffer,sizeof(execbuffer),"scp -t %s %s",
- scp->recursive ? "-r":"", scp->location);
- else
- snprintf(execbuffer,sizeof(execbuffer),"scp -f %s %s",
- scp->recursive ? "-r":"", scp->location);
- if(ssh_channel_request_exec(scp->channel,execbuffer) == SSH_ERROR){
- scp->state=SSH_SCP_ERROR;
- return SSH_ERROR;
- }
- if(scp->mode == SSH_SCP_WRITE){
- r=ssh_channel_read(scp->channel,&code,1,0);
- if(r<=0){
- ssh_set_error(scp->session,SSH_FATAL, "Error reading status code: %s",ssh_get_error(scp->session));
- scp->state=SSH_SCP_ERROR;
- return SSH_ERROR;
- }
- if(code != 0){
- ssh_set_error(scp->session,SSH_FATAL, "scp status code %ud not valid", code);
- scp->state=SSH_SCP_ERROR;
- return SSH_ERROR;
- }
- } else {
- ssh_channel_write(scp->channel,"",1);
- }
- if(scp->mode == SSH_SCP_WRITE)
- scp->state=SSH_SCP_WRITE_INITED;
- else
- scp->state=SSH_SCP_READ_INITED;
- return SSH_OK;
-}
-
-int ssh_scp_close(ssh_scp scp){
- char buffer[128];
- int err;
- if(scp==NULL)
- return SSH_ERROR;
- if(scp->channel != NULL){
- if(ssh_channel_send_eof(scp->channel) == SSH_ERROR){
- scp->state=SSH_SCP_ERROR;
- return SSH_ERROR;
- }
- /* avoid situations where data are buffered and
- * not yet stored on disk. This can happen if the close is sent
- * before we got the EOF back
- */
- while(!ssh_channel_is_eof(scp->channel)){
- err=ssh_channel_read(scp->channel,buffer,sizeof(buffer),0);
- if(err==SSH_ERROR)
- break;
- }
- if(ssh_channel_close(scp->channel) == SSH_ERROR){
- scp->state=SSH_SCP_ERROR;
- return SSH_ERROR;
- }
- ssh_channel_free(scp->channel);
- scp->channel=NULL;
- }
- scp->state=SSH_SCP_NEW;
- return SSH_OK;
-}
-
-void ssh_scp_free(ssh_scp scp){
- if(scp==NULL)
- return;
- if(scp->state != SSH_SCP_NEW)
- ssh_scp_close(scp);
- if(scp->channel)
- ssh_channel_free(scp->channel);
- SAFE_FREE(scp->location);
- SAFE_FREE(scp->request_name);
- SAFE_FREE(scp->warning);
- SAFE_FREE(scp);
-}
-
-/**
- * @brief Create a directory in a scp in sink mode.
- *
- * @param[in] scp The scp handle.
- *
- * @param[in] dirname The name of the directory being created.
- *
- * @param[in] mode The UNIX permissions for the new directory, e.g. 0755.
- *
- * @returns SSH_OK if the directory has been created, SSH_ERROR if
- * an error occured.
- *
- * @see ssh_scp_leave_directory()
- */
-int ssh_scp_push_directory(ssh_scp scp, const char *dirname, int mode){
- char buffer[1024];
- int r;
- uint8_t code;
- char *dir;
- char *perms;
- if(scp==NULL)
- return SSH_ERROR;
- if(scp->state != SSH_SCP_WRITE_INITED){
- ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_push_directory called under invalid state");
- return SSH_ERROR;
- }
- dir=ssh_basename(dirname);
- perms=ssh_scp_string_mode(mode);
- snprintf(buffer, sizeof(buffer), "D%s 0 %s\n", perms, dir);
- SAFE_FREE(dir);
- SAFE_FREE(perms);
- r=ssh_channel_write(scp->channel,buffer,strlen(buffer));
- if(r==SSH_ERROR){
- scp->state=SSH_SCP_ERROR;
- return SSH_ERROR;
- }
- r=ssh_channel_read(scp->channel,&code,1,0);
- if(r<=0){
- ssh_set_error(scp->session,SSH_FATAL, "Error reading status code: %s",ssh_get_error(scp->session));
- scp->state=SSH_SCP_ERROR;
- return SSH_ERROR;
- }
- if(code != 0){
- ssh_set_error(scp->session,SSH_FATAL, "scp status code %ud not valid", code);
- scp->state=SSH_SCP_ERROR;
- return SSH_ERROR;
- }
- return SSH_OK;
-}
-
-/**
- * @brief Leave a directory.
- *
- * @returns SSH_OK if the directory has been left,SSH_ERROR if an
- * error occured.
- *
- * @see ssh_scp_push_directory()
- */
- int ssh_scp_leave_directory(ssh_scp scp){
- char buffer[]="E\n";
- int r;
- uint8_t code;
- if(scp==NULL)
- return SSH_ERROR;
- if(scp->state != SSH_SCP_WRITE_INITED){
- ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_leave_directory called under invalid state");
- return SSH_ERROR;
- }
- r=ssh_channel_write(scp->channel,buffer,strlen(buffer));
- if(r==SSH_ERROR){
- scp->state=SSH_SCP_ERROR;
- return SSH_ERROR;
- }
- r=ssh_channel_read(scp->channel,&code,1,0);
- if(r<=0){
- ssh_set_error(scp->session,SSH_FATAL, "Error reading status code: %s",ssh_get_error(scp->session));
- scp->state=SSH_SCP_ERROR;
- return SSH_ERROR;
- }
- if(code != 0){
- ssh_set_error(scp->session,SSH_FATAL, "scp status code %ud not valid", code);
- scp->state=SSH_SCP_ERROR;
- return SSH_ERROR;
- }
- return SSH_OK;
-}
-
-/**
- * @brief Initialize the sending of a file to a scp in sink mode.
- *
- * @param[in] scp The scp handle.
- *
- * @param[in] filename The name of the file being sent. It should not contain
- * any path indicator
- *
- * @param[in] size Exact size in bytes of the file being sent.
- *
- * @param[in] mode The UNIX permissions for the new file, e.g. 0644.
- *
- * @returns SSH_OK if the file is ready to be sent, SSH_ERROR if an
- * error occured.
- */
-int ssh_scp_push_file(ssh_scp scp, const char *filename, size_t size, int mode){
- char buffer[1024];
- int r;
- uint8_t code;
- char *file;
- char *perms;
- if(scp==NULL)
- return SSH_ERROR;
- if(scp->state != SSH_SCP_WRITE_INITED){
- ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_push_file called under invalid state");
- return SSH_ERROR;
- }
- file=ssh_basename(filename);
- perms=ssh_scp_string_mode(mode);
- ssh_log(scp->session,SSH_LOG_PROTOCOL,"SCP pushing file %s, size %" PRIdS " with permissions '%s'",file,size,perms);
- snprintf(buffer, sizeof(buffer), "C%s %" PRIdS " %s\n", perms, size, file);
- SAFE_FREE(file);
- SAFE_FREE(perms);
- r=ssh_channel_write(scp->channel,buffer,strlen(buffer));
- if(r==SSH_ERROR){
- scp->state=SSH_SCP_ERROR;
- return SSH_ERROR;
- }
- r=ssh_channel_read(scp->channel,&code,1,0);
- if(r<=0){
- ssh_set_error(scp->session,SSH_FATAL, "Error reading status code: %s",ssh_get_error(scp->session));
- scp->state=SSH_SCP_ERROR;
- return SSH_ERROR;
- }
- if(code != 0){
- ssh_set_error(scp->session,SSH_FATAL, "scp status code %ud not valid", code);
- scp->state=SSH_SCP_ERROR;
- return SSH_ERROR;
- }
- scp->filelen = size;
- scp->processed = 0;
- scp->state=SSH_SCP_WRITE_WRITING;
- return SSH_OK;
-}
-
-/**
- * @internal
- *
- * @brief Wait for a response of the scp server.
- *
- * @param[in] scp The scp handle.
- *
- * @param[out] response A pointer where the response message must be copied if
- * any. This pointer must then be free'd.
- *
- * @returns The return code, SSH_ERROR a error occured.
- */
-int ssh_scp_response(ssh_scp scp, char **response){
- unsigned char code;
- int r;
- char msg[128];
- if(scp==NULL)
- return SSH_ERROR;
- r=ssh_channel_read(scp->channel,&code,1,0);
- if(r == SSH_ERROR)
- return SSH_ERROR;
- if(code == 0)
- return 0;
- if(code > 2){
- ssh_set_error(scp->session,SSH_FATAL, "SCP: invalid status code %ud received", code);
- scp->state=SSH_SCP_ERROR;
- return SSH_ERROR;
- }
- r=ssh_scp_read_string(scp,msg,sizeof(msg));
- if(r==SSH_ERROR)
- return r;
- /* Warning */
- if(code == 1){
- ssh_set_error(scp->session,SSH_REQUEST_DENIED, "SCP: Warning: status code 1 received: %s", msg);
- ssh_log(scp->session,SSH_LOG_RARE,"SCP: Warning: status code 1 received: %s", msg);
- if(response)
- *response=strdup(msg);
- return 1;
- }
- if(code == 2){
- ssh_set_error(scp->session,SSH_FATAL, "SCP: Error: status code 2 received: %s", msg);
- if(response)
- *response=strdup(msg);
- return 2;
- }
- /* Not reached */
- return SSH_ERROR;
-}
-
-/**
- * @brief Write into a remote scp file.
- *
- * @param[in] scp The scp handle.
- *
- * @param[in] buffer The buffer to write.
- *
- * @param[in] len The number of bytes to write.
- *
- * @returns SSH_OK if the write was successful, SSH_ERROR an error
- * occured while writing.
- */
-int ssh_scp_write(ssh_scp scp, const void *buffer, size_t len){
- int w;
- //int r;
- //uint8_t code;
- if(scp==NULL)
- return SSH_ERROR;
- if(scp->state != SSH_SCP_WRITE_WRITING){
- ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_write called under invalid state");
- return SSH_ERROR;
- }
- if(scp->processed + len > scp->filelen)
- len = scp->filelen - scp->processed;
- /* hack to avoid waiting for window change */
- ssh_channel_poll(scp->channel,0);
- w=ssh_channel_write(scp->channel,buffer,len);
- if(w != SSH_ERROR)
- scp->processed += w;
- else {
- scp->state=SSH_SCP_ERROR;
- //return=channel_get_exit_status(scp->channel);
- return SSH_ERROR;
- }
- /* Check if we arrived at end of file */
- if(scp->processed == scp->filelen) {
-/* r=channel_read(scp->channel,&code,1,0);
- if(r==SSH_ERROR){
- scp->state=SSH_SCP_ERROR;
- return SSH_ERROR;
- }
- if(code != 0){
- ssh_set_error(scp->session,SSH_FATAL, "scp status code %ud not valid", code);
- scp->state=SSH_SCP_ERROR;
- return SSH_ERROR;
- }
-*/
- scp->processed=scp->filelen=0;
- scp->state=SSH_SCP_WRITE_INITED;
- }
- return SSH_OK;
-}
-
-/**
- * @brief Read a string on a channel, terminated by '\n'
- *
- * @param[in] scp The scp handle.
- *
- * @param[out] buffer A pointer to a buffer to place the string.
- *
- * @param[in] len The size of the buffer in bytes. If the string is bigger
- * than len-1, only len-1 bytes are read and the string is
- * null-terminated.
- *
- * @returns SSH_OK if the string was read, SSH_ERROR if an error
- * occured while reading.
- */
-int ssh_scp_read_string(ssh_scp scp, char *buffer, size_t len){
- size_t r=0;
- int err=SSH_OK;
- if(scp==NULL)
- return SSH_ERROR;
- while(r<len-1){
- err=ssh_channel_read(scp->channel,&buffer[r],1,0);
- if(err==SSH_ERROR){
- break;
- }
- if(err==0){
- ssh_set_error(scp->session,SSH_FATAL,"End of file while reading string");
- err=SSH_ERROR;
- break;
- }
- r++;
- if(buffer[r-1] == '\n')
- break;
- }
- buffer[r]=0;
- return err;
-}
-
-/**
- * @brief Wait for a scp request (file, directory).
- *
- * @returns SSH_SCP_REQUEST_NEWFILE: The other side is sending
- * a file
- * SSH_SCP_REQUEST_NEWDIRECTORY: The other side is sending
- * a directory
- * SSH_SCP_REQUEST_END_DIRECTORY: The other side has
- * finished with the current
- * directory
- * SSH_ERROR: Some error happened
- *
- * @see ssh_scp_read()
- * @see ssh_scp_deny_request()
- * @see ssh_scp_accept_request()
- */
-int ssh_scp_pull_request(ssh_scp scp){
- char buffer[4096];
- char *mode=NULL;
- char *p,*tmp;
- size_t size;
- char *name=NULL;
- int err;
- if(scp==NULL)
- return SSH_ERROR;
- if(scp->state != SSH_SCP_READ_INITED){
- ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_pull_request called under invalid state");
- return SSH_ERROR;
- }
- err=ssh_scp_read_string(scp,buffer,sizeof(buffer));
- if(err==SSH_ERROR){
- if(ssh_channel_is_eof(scp->channel)){
- scp->state=SSH_SCP_TERMINATED;
- return SSH_SCP_REQUEST_EOF;
- }
- return err;
- }
- p=strchr(buffer,'\n');
- if(p!=NULL)
- *p='\0';
- ssh_log(scp->session,SSH_LOG_PROTOCOL,"Received SCP request: '%s'",buffer);
- switch(buffer[0]){
- case 'C':
- /* File */
- case 'D':
- /* Directory */
- p=strchr(buffer,' ');
- if(p==NULL)
- goto error;
- *p='\0';
- p++;
- //mode=strdup(&buffer[1]);
- scp->request_mode=ssh_scp_integer_mode(&buffer[1]);
- tmp=p;
- p=strchr(p,' ');
- if(p==NULL)
- goto error;
- *p=0;
- size=strtoull(tmp,NULL,10);
- p++;
- name=strdup(p);
- SAFE_FREE(scp->request_name);
- scp->request_name=name;
- if(buffer[0]=='C'){
- scp->filelen=size;
- scp->request_type=SSH_SCP_REQUEST_NEWFILE;
- } else {
- scp->filelen='0';
- scp->request_type=SSH_SCP_REQUEST_NEWDIR;
- }
- scp->state=SSH_SCP_READ_REQUESTED;
- scp->processed = 0;
- return scp->request_type;
- break;
- case 'E':
- scp->request_type=SSH_SCP_REQUEST_ENDDIR;
- ssh_channel_write(scp->channel,"",1);
- return scp->request_type;
- case 0x1:
- ssh_set_error(scp->session,SSH_REQUEST_DENIED,"SCP: Warning: %s",&buffer[1]);
- scp->request_type=SSH_SCP_REQUEST_WARNING;
- SAFE_FREE(scp->warning);
- scp->warning=strdup(&buffer[1]);
- return scp->request_type;
- case 0x2:
- ssh_set_error(scp->session,SSH_FATAL,"SCP: Error: %s",&buffer[1]);
- return SSH_ERROR;
- case 'T':
- /* Timestamp */
- default:
- ssh_set_error(scp->session,SSH_FATAL,"Unhandled message: (%d)%s",buffer[0],buffer);
- return SSH_ERROR;
- }
-
- /* a parsing error occured */
- error:
- SAFE_FREE(name);
- SAFE_FREE(mode);
- ssh_set_error(scp->session,SSH_FATAL,"Parsing error while parsing message: %s",buffer);
- return SSH_ERROR;
-}
-
-/**
- * @brief Deny the transfer of a file or creation of a directory coming from the
- * remote party.
- *
- * @param[in] scp The scp handle.
- * @param[in] reason A nul-terminated string with a human-readable
- * explanation of the deny.
- *
- * @returns SSH_OK if the message was sent, SSH_ERROR if the sending
- * the message failed, or sending it in a bad state.
- */
-int ssh_scp_deny_request(ssh_scp scp, const char *reason){
- char buffer[4096];
- int err;
- if(scp==NULL)
- return SSH_ERROR;
- if(scp->state != SSH_SCP_READ_REQUESTED){
- ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_deny_request called under invalid state");
- return SSH_ERROR;
- }
- snprintf(buffer,sizeof(buffer),"%c%s\n",2,reason);
- err=ssh_channel_write(scp->channel,buffer,strlen(buffer));
- if(err==SSH_ERROR) {
- return SSH_ERROR;
- }
- else {
- scp->state=SSH_SCP_READ_INITED;
- return SSH_OK;
- }
-}
-
-/**
- * @brief Accepts transfer of a file or creation of a directory coming from the
- * remote party.
- *
- * @param[in] scp The scp handle.
- *
- * @returns SSH_OK if the message was sent, SSH_ERROR if sending the
- * message failed, or sending it in a bad state.
- */
-int ssh_scp_accept_request(ssh_scp scp){
- char buffer[]={0x00};
- int err;
- if(scp==NULL)
- return SSH_ERROR;
- if(scp->state != SSH_SCP_READ_REQUESTED){
- ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_deny_request called under invalid state");
- return SSH_ERROR;
- }
- err=ssh_channel_write(scp->channel,buffer,1);
- if(err==SSH_ERROR) {
- return SSH_ERROR;
- }
- if(scp->request_type==SSH_SCP_REQUEST_NEWFILE)
- scp->state=SSH_SCP_READ_READING;
- else
- scp->state=SSH_SCP_READ_INITED;
- return SSH_OK;
-}
-
-/** @brief Read from a remote scp file
- * @param[in] scp The scp handle.
- *
- * @param[in] buffer The destination buffer.
- *
- * @param[in] size The size of the buffer.
- *
- * @returns The nNumber of bytes read, SSH_ERROR if an error occured
- * while reading.
- */
-int ssh_scp_read(ssh_scp scp, void *buffer, size_t size){
- int r;
- int code;
- if(scp==NULL)
- return SSH_ERROR;
- if(scp->state == SSH_SCP_READ_REQUESTED && scp->request_type == SSH_SCP_REQUEST_NEWFILE){
- r=ssh_scp_accept_request(scp);
- if(r==SSH_ERROR)
- return r;
- }
- if(scp->state != SSH_SCP_READ_READING){
- ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_read called under invalid state");
- return SSH_ERROR;
- }
- if(scp->processed + size > scp->filelen)
- size = scp->filelen - scp->processed;
- if(size > 65536)
- size=65536; /* avoid too large reads */
- r=ssh_channel_read(scp->channel,buffer,size,0);
- if(r != SSH_ERROR)
- scp->processed += r;
- else {
- scp->state=SSH_SCP_ERROR;
- return SSH_ERROR;
- }
- /* Check if we arrived at end of file */
- if(scp->processed == scp->filelen) {
- scp->processed=scp->filelen=0;
- ssh_channel_write(scp->channel,"",1);
- code=ssh_scp_response(scp,NULL);
- if(code == 0){
- scp->state=SSH_SCP_READ_INITED;
- return r;
- }
- if(code==1){
- scp->state=SSH_SCP_READ_INITED;
- return SSH_ERROR;
- }
- scp->state=SSH_SCP_ERROR;
- return SSH_ERROR;
- }
- return r;
-}
-
-/**
- * @brief Get the name of the directory or file being pushed from the other
- * party.
- *
- * @returns The file name, NULL on error. The string should not be
- * freed.
- */
-const char *ssh_scp_request_get_filename(ssh_scp scp){
- if(scp==NULL)
- return NULL;
- return scp->request_name;
-}
-
-/**
- * @brief Get the permissions of the directory or file being pushed from the
- * other party.
- *
- * @returns The UNIX permission, e.g 0644, -1 on error.
- */
-int ssh_scp_request_get_permissions(ssh_scp scp){
- if(scp==NULL)
- return -1;
- return scp->request_mode;
-}
-
-/** @brief Get the size of the file being pushed from the other party.
- *
- * @returns The numeric size of the file being read.
- */
-size_t ssh_scp_request_get_size(ssh_scp scp){
- if(scp==NULL)
- return 0;
- return scp->filelen;
-}
-
-/**
- * @brief Convert a scp text mode to an integer.
- *
- * @param[in] mode The mode to convert, e.g. "0644".
- *
- * @returns An integer value, e.g. 420 for "0644".
- */
-int ssh_scp_integer_mode(const char *mode){
- int value=strtoul(mode,NULL,8) & 0xffff;
- return value;
-}
-
-/**
- * @brief Convert a unix mode into a scp string.
- *
- * @param[in] mode The mode to convert, e.g. 420 or 0644.
- *
- * @returns A pointer to a malloc'ed string containing the scp mode,
- * e.g. "0644".
- */
-char *ssh_scp_string_mode(int mode){
- char buffer[16];
- snprintf(buffer,sizeof(buffer),"%.4o",mode);
- return strdup(buffer);
-}
-
-/**
- * @brief Get the warning string from a scp handle.
- *
- * @param[in] scp The scp handle.
- *
- * @returns A warning string, or NULL on error. The string should
- * not be freed.
- */
-const char *ssh_scp_request_get_warning(ssh_scp scp){
- if(scp==NULL)
- return NULL;
- return scp->warning;
-}
-
-/** @} */
-
-/* vim: set ts=4 sw=4 et cindent: */
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: */
diff --git a/libssh/session.c b/libssh/session.c
deleted file mode 100644
index 42f5e772..00000000
--- a/libssh/session.c
+++ /dev/null
@@ -1,520 +0,0 @@
-/*
- * session.c - non-networking functions
- *
- * This file is part of the SSH Library
- *
- * Copyright (c) 2005-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 "config.h"
-#include <string.h>
-#include <stdlib.h>
-#include "libssh/libssh.h"
-#include "libssh/priv.h"
-#include "libssh/server.h"
-#include "libssh/socket.h"
-#include "libssh/ssh2.h"
-#include "libssh/agent.h"
-#include "libssh/packet.h"
-#include "libssh/session.h"
-#include "libssh/misc.h"
-#include "libssh/buffer.h"
-#include "libssh/poll.h"
-
-#define FIRST_CHANNEL 42 // why not ? it helps to find bugs.
-
-/**
- * @defgroup libssh_session The SSH session functions.
- * @ingroup libssh
- *
- * Functions that manage a session.
- *
- * @{
- */
-
-/**
- * @brief Create a new ssh session.
- *
- * @returns A new ssh_session pointer, NULL on error.
- */
-ssh_session ssh_new(void) {
- ssh_session session;
- char *id;
- int rc;
-
- session = malloc(sizeof (struct ssh_session_struct));
- if (session == NULL) {
- return NULL;
- }
- ZERO_STRUCTP(session);
-
- session->next_crypto = crypto_new();
- if (session->next_crypto == NULL) {
- goto err;
- }
-
- session->socket = ssh_socket_new(session);
- if (session->socket == NULL) {
- goto err;
- }
-
- session->out_buffer = ssh_buffer_new();
- if (session->out_buffer == NULL) {
- goto err;
- }
-
- session->in_buffer=ssh_buffer_new();
- if (session->in_buffer == NULL) {
- goto err;
- }
-
- session->alive = 0;
- session->auth_methods = 0;
- session->blocking = 1;
- session->log_indent = 0;
- session->maxchannel = FIRST_CHANNEL;
-
- /* options */
- session->StrictHostKeyChecking = 1;
- session->port = 22;
- session->fd = -1;
- session->ssh2 = 1;
-#ifdef WITH_SSH1
- session->ssh1 = 1;
-#else
- session->ssh1 = 0;
-#endif
-
-#ifndef _WIN32
- session->agent = agent_new(session);
- if (session->agent == NULL) {
- goto err;
- }
-#endif /* _WIN32 */
-
- session->identity = ssh_list_new();
- if (session->identity == NULL) {
- goto err;
- }
-
- id = strdup("%d/id_rsa");
- if (id == NULL) {
- goto err;
- }
- rc = ssh_list_append(session->identity, id);
- if (rc == SSH_ERROR) {
- goto err;
- }
-
- id = strdup("%d/id_dsa");
- if (id == NULL) {
- goto err;
- }
- rc = ssh_list_append(session->identity, id);
- if (rc == SSH_ERROR) {
- goto err;
- }
-
- id = strdup("%d/identity");
- if (id == NULL) {
- goto err;
- }
- rc = ssh_list_append(session->identity, id);
- if (rc == SSH_ERROR) {
- goto err;
- }
-
- return session;
-
-err:
- ssh_free(session);
- return NULL;
-}
-
-/**
- * @brief Deallocate a SSH session handle.
- *
- * @param[in] session The SSH session to free.
- *
- * @see ssh_disconnect()
- * @see ssh_new()
- */
-void ssh_free(ssh_session session) {
- int i;
- enter_function();
-
- if (session == NULL) {
- return;
- }
-
- SAFE_FREE(session->serverbanner);
- SAFE_FREE(session->clientbanner);
- SAFE_FREE(session->banner);
-#ifdef WITH_PCAP
- if(session->pcap_ctx){
- ssh_pcap_context_free(session->pcap_ctx);
- session->pcap_ctx=NULL;
- }
-#endif
- ssh_buffer_free(session->in_buffer);
- ssh_buffer_free(session->out_buffer);
- session->in_buffer=session->out_buffer=NULL;
- crypto_free(session->current_crypto);
- crypto_free(session->next_crypto);
- ssh_socket_free(session->socket);
- /* delete all channels */
- while (session->channels) {
- ssh_channel_free(session->channels);
- }
-#ifndef _WIN32
- agent_free(session->agent);
-#endif /* _WIN32 */
- if (session->client_kex.methods) {
- for (i = 0; i < 10; i++) {
- SAFE_FREE(session->client_kex.methods[i]);
- }
- }
-
- if (session->server_kex.methods) {
- for (i = 0; i < 10; i++) {
- SAFE_FREE(session->server_kex.methods[i]);
- }
- }
- SAFE_FREE(session->client_kex.methods);
- SAFE_FREE(session->server_kex.methods);
-
- privatekey_free(session->dsa_key);
- privatekey_free(session->rsa_key);
- if(session->ssh_message_list){
- ssh_message msg;
- while((msg=ssh_list_pop_head(ssh_message ,session->ssh_message_list))
- != NULL){
- ssh_message_free(msg);
- }
- ssh_list_free(session->ssh_message_list);
- }
-
- if (session->packet_callbacks)
- ssh_list_free(session->packet_callbacks);
-
- if (session->identity) {
- char *id;
-
- for (id = ssh_list_pop_head(char *, session->identity);
- id != NULL;
- id = ssh_list_pop_head(char *, session->identity)) {
- SAFE_FREE(id);
- }
- ssh_list_free(session->identity);
- }
-
- /* options */
- SAFE_FREE(session->username);
- SAFE_FREE(session->host);
- SAFE_FREE(session->sshdir);
- SAFE_FREE(session->knownhosts);
- SAFE_FREE(session->ProxyCommand);
-
- for (i = 0; i < 10; i++) {
- if (session->wanted_methods[i]) {
- SAFE_FREE(session->wanted_methods[i]);
- }
- }
-
- /* burn connection, it could hang sensitive datas */
- ZERO_STRUCTP(session);
- SAFE_FREE(session);
-}
-
-/**
- * @brief Disconnect impolitely from a remote host by closing the socket.
- *
- * Suitable if you forked and want to destroy this session.
- *
- * @param[in] session The SSH session to disconnect.
- */
-void ssh_silent_disconnect(ssh_session session) {
- enter_function();
-
- if (session == NULL) {
- return;
- }
-
- ssh_socket_close(session->socket);
- session->alive = 0;
- ssh_disconnect(session);
- leave_function();
-}
-
-/**
- * @brief Set the session in blocking/nonblocking mode.
- *
- * @param[in] session The ssh session to change.
- *
- * @param[in] blocking Zero for nonblocking mode.
- *
- * \bug nonblocking code is in development and won't work as expected
- */
-void ssh_set_blocking(ssh_session session, int blocking) {
- if (session == NULL) {
- return;
- }
-
- session->blocking = blocking ? 1 : 0;
-}
-
-/**
- * @brief Get the fd of a connection.
- *
- * In case you'd need the file descriptor of the connection to the server/client.
- *
- * @param[in] session The ssh session to use.
- *
- * @return The file descriptor of the connection, or -1 if it is
- * not connected
- */
-socket_t ssh_get_fd(ssh_session session) {
- if (session == NULL) {
- return -1;
- }
-
- return ssh_socket_get_fd_in(session->socket);
-}
-
-/**
- * @brief Tell the session it has data to read on the file descriptor without
- * blocking.
- *
- * @param[in] session The ssh session to use.
- */
-void ssh_set_fd_toread(ssh_session session) {
- if (session == NULL) {
- return;
- }
-
- ssh_socket_set_toread(session->socket);
-}
-
-/**
- * @brief Tell the session it may write to the file descriptor without blocking.
- *
- * @param[in] session The ssh session to use.
- */
-void ssh_set_fd_towrite(ssh_session session) {
- if (session == NULL) {
- return;
- }
-
- ssh_socket_set_towrite(session->socket);
-}
-
-/**
- * @brief Tell the session it has an exception to catch on the file descriptor.
- *
- * \param[in] session The ssh session to use.
- */
-void ssh_set_fd_except(ssh_session session) {
- if (session == NULL) {
- return;
- }
-
- ssh_socket_set_except(session->socket);
-}
-
-/**
- * @internal
- *
- * @brief Poll the current session for an event and call the appropriate
- * callbacks.
- *
- * This will block until one event happens.
- *
- * @param[in] session The session handle to use.
- *
- * @param[in] timeout Set an upper limit on the time for which this function
- * will block, in milliseconds. Specifying a negative value
- * means an infinite timeout. This parameter is passed to
- * the poll() function.
- *
- * @return SSH_OK on success, SSH_ERROR otherwise.
- */
-int ssh_handle_packets(ssh_session session, int timeout) {
- ssh_poll_handle spoll_in,spoll_out;
- ssh_poll_ctx ctx;
- if(session==NULL || session->socket==NULL)
- return SSH_ERROR;
- enter_function();
- spoll_in=ssh_socket_get_poll_handle_in(session->socket);
- spoll_out=ssh_socket_get_poll_handle_out(session->socket);
- ssh_poll_set_events(spoll_in, POLLIN | POLLERR);
- ctx=ssh_poll_get_ctx(spoll_in);
- if(ctx==NULL){
- ctx=ssh_get_global_poll_ctx(session);
- ssh_poll_ctx_add(ctx,spoll_in);
- if(spoll_in != spoll_out)
- ssh_poll_ctx_add(ctx,spoll_out);
- }
- ssh_poll_ctx_dopoll(ctx,timeout);
- leave_function();
- if (session->session_state != SSH_SESSION_STATE_ERROR)
- return SSH_OK;
- else
- return SSH_ERROR;
-}
-
-/**
- * @brief Get session status
- *
- * @param session The ssh session to use.
- *
- * @returns A bitmask including SSH_CLOSED, SSH_READ_PENDING or SSH_CLOSED_ERROR
- * which respectively means the session is closed, has data to read on
- * the connection socket and session was closed due to an error.
- */
-int ssh_get_status(ssh_session session) {
- int socketstate;
- int r = 0;
-
- if (session == NULL) {
- return 0;
- }
-
- socketstate = ssh_socket_get_status(session->socket);
-
- if (session->closed) {
- r |= SSH_CLOSED;
- }
- if (socketstate & SSH_READ_PENDING) {
- r |= SSH_READ_PENDING;
- }
- if (session->closed && (socketstate & SSH_CLOSED_ERROR)) {
- r |= SSH_CLOSED_ERROR;
- }
-
- return r;
-}
-
-/**
- * @brief Get the disconnect message from the server.
- *
- * @param[in] session The ssh session to use.
- *
- * @return The message sent by the server along with the
- * disconnect, or NULL in which case the reason of the
- * disconnect may be found with ssh_get_error.
- *
- * @see ssh_get_error()
- */
-const char *ssh_get_disconnect_message(ssh_session session) {
- if (session == NULL) {
- return NULL;
- }
-
- if (!session->closed) {
- ssh_set_error(session, SSH_REQUEST_DENIED,
- "Connection not closed yet");
- } else if(session->closed_by_except) {
- ssh_set_error(session, SSH_REQUEST_DENIED,
- "Connection closed by socket error");
- } else if(!session->discon_msg) {
- ssh_set_error(session, SSH_FATAL,
- "Connection correctly closed but no disconnect message");
- } else {
- return session->discon_msg;
- }
-
- return NULL;
-}
-
-/**
- * @brief Get the protocol version of the session.
- *
- * @param session The ssh session to use.
- *
- * @return 1 or 2, for ssh1 or ssh2, < 0 on error.
- */
-int ssh_get_version(ssh_session session) {
- if (session == NULL) {
- return -1;
- }
-
- return session->version;
-}
-
-/**
- * @internal
- *
- * @brief Handle a SSH_DISCONNECT packet.
- */
-SSH_PACKET_CALLBACK(ssh_packet_disconnect_callback){
- uint32_t code;
- char *error=NULL;
- ssh_string error_s;
- (void)user;
- (void)type;
- buffer_get_u32(packet, &code);
- error_s = buffer_get_ssh_string(packet);
- if (error_s != NULL) {
- error = ssh_string_to_char(error_s);
- ssh_string_free(error_s);
- }
- ssh_log(session, SSH_LOG_PACKET, "Received SSH_MSG_DISCONNECT %d:%s",code,
- error != NULL ? error : "no error");
- ssh_set_error(session, SSH_FATAL,
- "Received SSH_MSG_DISCONNECT: %d:%s",code,
- error != NULL ? error : "no error");
- SAFE_FREE(error);
-
- ssh_socket_close(session->socket);
- session->alive = 0;
- /* TODO: handle a graceful disconnect */
- return SSH_PACKET_USED;
-}
-
-/**
- * @internal
- *
- * @brief Handle a SSH_IGNORE and SSH_DEBUG packet.
- */
-SSH_PACKET_CALLBACK(ssh_packet_ignore_callback){
- (void)user;
- (void)type;
- (void)packet;
- ssh_log(session,SSH_LOG_PROTOCOL,"Received %s packet",type==SSH2_MSG_IGNORE ? "SSH_MSG_IGNORE" : "SSH_MSG_DEBUG");
- /* TODO: handle a graceful disconnect */
- return SSH_PACKET_USED;
-}
-
-/**
- * @internal
- * @brief Callback to be called when the socket received an exception code.
- * @param user is a pointer to session
- */
-void ssh_socket_exception_callback(int code, int errno_code, void *user){
- ssh_session session=(ssh_session)user;
- enter_function();
- ssh_log(session,SSH_LOG_RARE,"Socket exception callback: %d (%d)",code, errno_code);
- session->session_state=SSH_SESSION_STATE_ERROR;
- ssh_set_error(session,SSH_FATAL,"Socket error: %s",strerror(errno_code));
- session->ssh_connection_callback(session);
- leave_function();
-}
-
-/** @} */
-
-/* vim: set ts=4 sw=4 et cindent: */
diff --git a/libssh/sftp.c b/libssh/sftp.c
deleted file mode 100644
index e5c91af3..00000000
--- a/libssh/sftp.c
+++ /dev/null
@@ -1,3207 +0,0 @@
-/*
- * sftp.c - Secure FTP functions
- *
- * This file is part of the SSH Library
- *
- * Copyright (c) 2005-2008 by Aris Adamantiadis
- * Copyright (c) 2008-2009 by Andreas Schneider <mail@cynapses.org>
- *
- * 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.
- */
-
-/* This file contains code written by Nick Zitzmann */
-
-#include <errno.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#ifndef _WIN32
-#include <arpa/inet.h>
-#else
-#define S_IFSOCK 0140000
-#define S_IFLNK 0120000
-
-#ifdef _MSC_VER
-#define S_IFBLK 0060000
-#define S_IFIFO 0010000
-#endif
-#endif
-
-#include "libssh/priv.h"
-#include "libssh/ssh2.h"
-#include "libssh/sftp.h"
-#include "libssh/buffer.h"
-#include "libssh/channels.h"
-#include "libssh/session.h"
-#include "libssh/misc.h"
-
-#ifdef WITH_SFTP
-
-#define sftp_enter_function() _enter_function(sftp->channel->session)
-#define sftp_leave_function() _leave_function(sftp->channel->session)
-
-struct sftp_ext_struct {
- unsigned int count;
- char **name;
- char **data;
-};
-
-/* functions */
-static int sftp_enqueue(sftp_session session, sftp_message msg);
-static void sftp_message_free(sftp_message msg);
-static void sftp_set_error(sftp_session sftp, int errnum);
-static void status_msg_free(sftp_status_message status);
-
-static sftp_ext sftp_ext_new(void) {
- sftp_ext ext;
-
- ext = malloc(sizeof(struct sftp_ext_struct));
- if (ext == NULL) {
- return NULL;
- }
- ZERO_STRUCTP(ext);
-
- return ext;
-}
-
-static void sftp_ext_free(sftp_ext ext) {
- unsigned int i;
-
- if (ext == NULL) {
- return;
- }
-
- if (ext->count) {
- for (i = 0; i < ext->count; i++) {
- SAFE_FREE(ext->name[i]);
- SAFE_FREE(ext->data[i]);
- }
- SAFE_FREE(ext->name);
- SAFE_FREE(ext->data);
- }
-
- SAFE_FREE(ext);
-}
-
-sftp_session sftp_new(ssh_session session){
- sftp_session sftp;
-
- if (session == NULL) {
- return NULL;
- }
- enter_function();
-
- sftp = malloc(sizeof(struct sftp_session_struct));
- if (sftp == NULL) {
- ssh_set_error_oom(session);
- leave_function();
- return NULL;
- }
- ZERO_STRUCTP(sftp);
-
- sftp->ext = sftp_ext_new();
- if (sftp->ext == NULL) {
- ssh_set_error_oom(session);
- SAFE_FREE(sftp);
- leave_function();
- return NULL;
- }
-
- sftp->session = session;
- sftp->channel = ssh_channel_new(session);
- if (sftp->channel == NULL) {
- SAFE_FREE(sftp);
- leave_function();
- return NULL;
- }
-
- if (ssh_channel_open_session(sftp->channel)) {
- ssh_channel_free(sftp->channel);
- SAFE_FREE(sftp);
- leave_function();
- return NULL;
- }
-
- if (ssh_channel_request_sftp(sftp->channel)) {
- sftp_free(sftp);
- leave_function();
- return NULL;
- }
-
- leave_function();
- return sftp;
-}
-
-#ifdef WITH_SERVER
-sftp_session sftp_server_new(ssh_session session, ssh_channel chan){
- sftp_session sftp = NULL;
-
- sftp = malloc(sizeof(struct sftp_session_struct));
- if (sftp == NULL) {
- ssh_set_error_oom(session);
- return NULL;
- }
- ZERO_STRUCTP(sftp);
-
- sftp->session = session;
- sftp->channel = chan;
-
- return sftp;
-}
-
-int sftp_server_init(sftp_session sftp){
- ssh_session session = sftp->session;
- sftp_packet packet = NULL;
- ssh_buffer reply = NULL;
- uint32_t version;
-
- sftp_enter_function();
-
- packet = sftp_packet_read(sftp);
- if (packet == NULL) {
- sftp_leave_function();
- return -1;
- }
-
- if (packet->type != SSH_FXP_INIT) {
- ssh_set_error(session, SSH_FATAL,
- "Packet read of type %d instead of SSH_FXP_INIT",
- packet->type);
-
- sftp_packet_free(packet);
- sftp_leave_function();
- return -1;
- }
-
- ssh_log(session, SSH_LOG_PACKET, "Received SSH_FXP_INIT");
-
- buffer_get_u32(packet->payload, &version);
- version = ntohl(version);
- ssh_log(session, SSH_LOG_PACKET, "Client version: %d", version);
- sftp->client_version = version;
-
- sftp_packet_free(packet);
-
- reply = ssh_buffer_new();
- if (reply == NULL) {
- ssh_set_error_oom(session);
- sftp_leave_function();
- return -1;
- }
-
- if (buffer_add_u32(reply, ntohl(LIBSFTP_VERSION)) < 0) {
- ssh_set_error_oom(session);
- ssh_buffer_free(reply);
- sftp_leave_function();
- return -1;
- }
-
- if (sftp_packet_write(sftp, SSH_FXP_VERSION, reply) < 0) {
- ssh_buffer_free(reply);
- sftp_leave_function();
- return -1;
- }
- ssh_buffer_free(reply);
-
- ssh_log(session, SSH_LOG_RARE, "Server version sent");
-
- if (version > LIBSFTP_VERSION) {
- sftp->version = LIBSFTP_VERSION;
- } else {
- sftp->version=version;
- }
-
- sftp_leave_function();
- return 0;
-}
-#endif /* WITH_SERVER */
-
-void sftp_free(sftp_session sftp){
- sftp_request_queue ptr;
-
- if (sftp == NULL) {
- return;
- }
-
- ssh_channel_send_eof(sftp->channel);
- ptr = sftp->queue;
- while(ptr) {
- sftp_request_queue old;
- sftp_message_free(ptr->message);
- old = ptr->next;
- SAFE_FREE(ptr);
- ptr = old;
- }
-
- ssh_channel_free(sftp->channel);
- sftp_ext_free(sftp->ext);
- ZERO_STRUCTP(sftp);
-
- SAFE_FREE(sftp);
-}
-
-int sftp_packet_write(sftp_session sftp, uint8_t type, ssh_buffer payload){
- int size;
-
- if (buffer_prepend_data(payload, &type, sizeof(uint8_t)) < 0) {
- ssh_set_error_oom(sftp->session);
- return -1;
- }
-
- size = htonl(ssh_buffer_get_len(payload));
- if (buffer_prepend_data(payload, &size, sizeof(uint32_t)) < 0) {
- ssh_set_error_oom(sftp->session);
- return -1;
- }
-
- size = ssh_channel_write(sftp->channel, ssh_buffer_get_begin(payload),
- ssh_buffer_get_len(payload));
- if (size < 0) {
- return -1;
- } else if((uint32_t) size != ssh_buffer_get_len(payload)) {
- ssh_log(sftp->session, SSH_LOG_PACKET,
- "Had to write %d bytes, wrote only %d",
- ssh_buffer_get_len(payload),
- size);
- }
-
- return size;
-}
-
-sftp_packet sftp_packet_read(sftp_session sftp) {
- sftp_packet packet = NULL;
- uint32_t size;
-
- sftp_enter_function();
-
- packet = malloc(sizeof(struct sftp_packet_struct));
- if (packet == NULL) {
- ssh_set_error_oom(sftp->session);
- return NULL;
- }
- packet->sftp = sftp;
- packet->payload = ssh_buffer_new();
- if (packet->payload == NULL) {
- ssh_set_error_oom(sftp->session);
- SAFE_FREE(packet);
- return NULL;
- }
-
- if (channel_read_buffer(sftp->channel, packet->payload, 4, 0) <= 0) {
- ssh_buffer_free(packet->payload);
- SAFE_FREE(packet);
- sftp_leave_function();
- return NULL;
- }
-
- if (buffer_get_u32(packet->payload, &size) != sizeof(uint32_t)) {
- ssh_set_error(sftp->session, SSH_FATAL, "Short sftp packet!");
- ssh_buffer_free(packet->payload);
- SAFE_FREE(packet);
- sftp_leave_function();
- return NULL;
- }
-
- size = ntohl(size);
- if (channel_read_buffer(sftp->channel, packet->payload, 1, 0) <= 0) {
- /* TODO: check if there are cases where an error needs to be set here */
- ssh_buffer_free(packet->payload);
- SAFE_FREE(packet);
- sftp_leave_function();
- return NULL;
- }
-
- buffer_get_u8(packet->payload, &packet->type);
- if (size > 1) {
- if (channel_read_buffer(sftp->channel, packet->payload, size - 1, 0) <= 0) {
- /* TODO: check if there are cases where an error needs to be set here */
- ssh_buffer_free(packet->payload);
- SAFE_FREE(packet);
- sftp_leave_function();
- return NULL;
- }
- }
-
- sftp_leave_function();
- return packet;
-}
-
-static void sftp_set_error(sftp_session sftp, int errnum) {
- if (sftp != NULL) {
- sftp->errnum = errnum;
- }
-}
-
-/* Get the last sftp error */
-int sftp_get_error(sftp_session sftp) {
- if (sftp == NULL) {
- return -1;
- }
-
- return sftp->errnum;
-}
-
-static sftp_message sftp_message_new(sftp_session sftp){
- sftp_message msg = NULL;
-
- sftp_enter_function();
-
- msg = malloc(sizeof(struct sftp_message_struct));
- if (msg == NULL) {
- ssh_set_error_oom(sftp->session);
- return NULL;
- }
- ZERO_STRUCTP(msg);
-
- msg->payload = ssh_buffer_new();
- if (msg->payload == NULL) {
- ssh_set_error_oom(sftp->session);
- SAFE_FREE(msg);
- return NULL;
- }
- msg->sftp = sftp;
-
- sftp_leave_function();
- return msg;
-}
-
-static void sftp_message_free(sftp_message msg) {
- sftp_session sftp;
-
- if (msg == NULL) {
- return;
- }
-
- sftp = msg->sftp;
- sftp_enter_function();
-
- ssh_buffer_free(msg->payload);
- SAFE_FREE(msg);
-
- sftp_leave_function();
-}
-
-static sftp_message sftp_get_message(sftp_packet packet) {
- sftp_session sftp = packet->sftp;
- sftp_message msg = NULL;
-
- sftp_enter_function();
-
- msg = sftp_message_new(sftp);
- if (msg == NULL) {
- sftp_leave_function();
- return NULL;
- }
-
- msg->sftp = packet->sftp;
- msg->packet_type = packet->type;
-
- if ((packet->type != SSH_FXP_STATUS) && (packet->type!=SSH_FXP_HANDLE) &&
- (packet->type != SSH_FXP_DATA) && (packet->type != SSH_FXP_ATTRS) &&
- (packet->type != SSH_FXP_NAME) && (packet->type != SSH_FXP_EXTENDED_REPLY)) {
- ssh_set_error(packet->sftp->session, SSH_FATAL,
- "Unknown packet type %d", packet->type);
- sftp_message_free(msg);
- sftp_leave_function();
- return NULL;
- }
-
- if (buffer_get_u32(packet->payload, &msg->id) != sizeof(uint32_t)) {
- ssh_set_error(packet->sftp->session, SSH_FATAL,
- "Invalid packet %d: no ID", packet->type);
- sftp_message_free(msg);
- sftp_leave_function();
- return NULL;
- }
-
- ssh_log(packet->sftp->session, SSH_LOG_PACKET,
- "Packet with id %d type %d",
- msg->id,
- msg->packet_type);
-
- if (buffer_add_data(msg->payload, buffer_get_rest(packet->payload),
- buffer_get_rest_len(packet->payload)) < 0) {
- ssh_set_error_oom(sftp->session);
- sftp_message_free(msg);
- sftp_leave_function();
- return NULL;
- }
-
- sftp_leave_function();
- return msg;
-}
-
-static int sftp_read_and_dispatch(sftp_session sftp) {
- sftp_packet packet = NULL;
- sftp_message msg = NULL;
-
- sftp_enter_function();
-
- packet = sftp_packet_read(sftp);
- if (packet == NULL) {
- sftp_leave_function();
- return -1; /* something nasty happened reading the packet */
- }
-
- msg = sftp_get_message(packet);
- sftp_packet_free(packet);
- if (msg == NULL) {
- sftp_leave_function();
- return -1;
- }
-
- if (sftp_enqueue(sftp, msg) < 0) {
- sftp_message_free(msg);
- sftp_leave_function();
- return -1;
- }
-
- sftp_leave_function();
- return 0;
-}
-
-void sftp_packet_free(sftp_packet packet) {
- if (packet == NULL) {
- return;
- }
-
- ssh_buffer_free(packet->payload);
- free(packet);
-}
-
-/* Initialize the sftp session with the server. */
-int sftp_init(sftp_session sftp) {
- sftp_packet packet = NULL;
- ssh_buffer buffer = NULL;
- ssh_string ext_name_s = NULL;
- ssh_string ext_data_s = NULL;
- char *ext_name = NULL;
- char *ext_data = NULL;
- uint32_t version = htonl(LIBSFTP_VERSION);
-
- sftp_enter_function();
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- ssh_set_error_oom(sftp->session);
- sftp_leave_function();
- return -1;
- }
-
- if (buffer_add_u32(buffer, version) < 0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- sftp_leave_function();
- return -1;
- }
- if (sftp_packet_write(sftp, SSH_FXP_INIT, buffer) < 0) {
- ssh_buffer_free(buffer);
- sftp_leave_function();
- return -1;
- }
- ssh_buffer_free(buffer);
-
- packet = sftp_packet_read(sftp);
- if (packet == NULL) {
- sftp_leave_function();
- return -1;
- }
-
- if (packet->type != SSH_FXP_VERSION) {
- ssh_set_error(sftp->session, SSH_FATAL,
- "Received a %d messages instead of SSH_FXP_VERSION", packet->type);
- sftp_packet_free(packet);
- sftp_leave_function();
- return -1;
- }
-
- /* TODO: are we sure there are 4 bytes ready? */
- buffer_get_u32(packet->payload, &version);
- version = ntohl(version);
- ssh_log(sftp->session, SSH_LOG_RARE,
- "SFTP server version %d",
- version);
-
- ext_name_s = buffer_get_ssh_string(packet->payload);
- while (ext_name_s != NULL) {
- int count = sftp->ext->count;
- char **tmp;
-
- ext_data_s = buffer_get_ssh_string(packet->payload);
- if (ext_data_s == NULL) {
- ssh_string_free(ext_name_s);
- break;
- }
-
- ext_name = ssh_string_to_char(ext_name_s);
- ext_data = ssh_string_to_char(ext_data_s);
- if (ext_name == NULL || ext_data == NULL) {
- ssh_set_error_oom(sftp->session);
- SAFE_FREE(ext_name);
- SAFE_FREE(ext_data);
- ssh_string_free(ext_name_s);
- ssh_string_free(ext_data_s);
- return -1;
- }
- ssh_log(sftp->session, SSH_LOG_RARE,
- "SFTP server extension: %s, version: %s",
- ext_name, ext_data);
-
- count++;
- tmp = realloc(sftp->ext->name, count * sizeof(char *));
- if (tmp == NULL) {
- ssh_set_error_oom(sftp->session);
- SAFE_FREE(ext_name);
- SAFE_FREE(ext_data);
- ssh_string_free(ext_name_s);
- ssh_string_free(ext_data_s);
- return -1;
- }
- tmp[count - 1] = ext_name;
- sftp->ext->name = tmp;
-
- tmp = realloc(sftp->ext->data, count * sizeof(char *));
- if (tmp == NULL) {
- ssh_set_error_oom(sftp->session);
- SAFE_FREE(ext_name);
- SAFE_FREE(ext_data);
- ssh_string_free(ext_name_s);
- ssh_string_free(ext_data_s);
- return -1;
- }
- tmp[count - 1] = ext_data;
- sftp->ext->data = tmp;
-
- sftp->ext->count = count;
-
- ssh_string_free(ext_name_s);
- ssh_string_free(ext_data_s);
-
- ext_name_s = buffer_get_ssh_string(packet->payload);
- }
-
- sftp_packet_free(packet);
-
- sftp->version = sftp->server_version = version;
-
- sftp_leave_function();
-
- return 0;
-}
-
-unsigned int sftp_extensions_get_count(sftp_session sftp) {
- if (sftp == NULL || sftp->ext == NULL) {
- return 0;
- }
-
- return sftp->ext->count;
-}
-
-const char *sftp_extensions_get_name(sftp_session sftp, unsigned int idx) {
- if (sftp == NULL)
- return NULL;
- if (sftp->ext == NULL || sftp->ext->name == NULL) {
- ssh_set_error_invalid(sftp->session, __FUNCTION__);
- return NULL;
- }
-
- if (idx > sftp->ext->count) {
- ssh_set_error_invalid(sftp->session, __FUNCTION__);
- return NULL;
- }
-
- return sftp->ext->name[idx];
-}
-
-const char *sftp_extensions_get_data(sftp_session sftp, unsigned int idx) {
- if (sftp == NULL)
- return NULL;
- if (sftp->ext == NULL || sftp->ext->name == NULL) {
- ssh_set_error_invalid(sftp->session, __FUNCTION__);
- return NULL;
- }
-
- if (idx > sftp->ext->count) {
- ssh_set_error_invalid(sftp->session, __FUNCTION__);
- return NULL;
- }
-
- return sftp->ext->data[idx];
-}
-
-int sftp_extension_supported(sftp_session sftp, const char *name,
- const char *data) {
- int i, n;
-
- n = sftp_extensions_get_count(sftp);
- for (i = 0; i < n; i++) {
- if (strcmp(sftp_extensions_get_name(sftp, i), name) == 0 &&
- strcmp(sftp_extensions_get_data(sftp, i), data) == 0) {
- return 1;
- }
- }
-
- return 0;
-}
-
-static sftp_request_queue request_queue_new(sftp_message msg) {
- sftp_request_queue queue = NULL;
-
- queue = malloc(sizeof(struct sftp_request_queue_struct));
- if (queue == NULL) {
- ssh_set_error_oom(msg->sftp->session);
- return NULL;
- }
- ZERO_STRUCTP(queue);
-
- queue->message = msg;
-
- return queue;
-}
-
-static void request_queue_free(sftp_request_queue queue) {
- if (queue == NULL) {
- return;
- }
-
- ZERO_STRUCTP(queue);
- SAFE_FREE(queue);
-}
-
-static int sftp_enqueue(sftp_session sftp, sftp_message msg) {
- sftp_request_queue queue = NULL;
- sftp_request_queue ptr;
-
- queue = request_queue_new(msg);
- if (queue == NULL) {
- return -1;
- }
-
- ssh_log(sftp->session, SSH_LOG_PACKET,
- "Queued msg type %d id %d",
- msg->id, msg->packet_type);
-
- if(sftp->queue == NULL) {
- sftp->queue = queue;
- } else {
- ptr = sftp->queue;
- while(ptr->next) {
- ptr=ptr->next; /* find end of linked list */
- }
- ptr->next = queue; /* add it on bottom */
- }
-
- return 0;
-}
-
-/*
- * Pulls of a message from the queue based on the ID.
- * Returns NULL if no message has been found.
- */
-static sftp_message sftp_dequeue(sftp_session sftp, uint32_t id){
- sftp_request_queue prev = NULL;
- sftp_request_queue queue;
- sftp_message msg;
-
- if(sftp->queue == NULL) {
- return NULL;
- }
-
- queue = sftp->queue;
- while (queue) {
- if(queue->message->id == id) {
- /* remove from queue */
- if (prev == NULL) {
- sftp->queue = queue->next;
- } else {
- prev->next = queue->next;
- }
- msg = queue->message;
- request_queue_free(queue);
- ssh_log(sftp->session, SSH_LOG_PACKET,
- "Dequeued msg id %d type %d",
- msg->id,
- msg->packet_type);
- return msg;
- }
- prev = queue;
- queue = queue->next;
- }
-
- return NULL;
-}
-
-/*
- * Assigns a new SFTP ID for new requests and assures there is no collision
- * between them.
- * Returns a new ID ready to use in a request
- */
-static inline uint32_t sftp_get_new_id(sftp_session session) {
- return ++session->id_counter;
-}
-
-static sftp_status_message parse_status_msg(sftp_message msg){
- sftp_status_message status;
-
- if (msg->packet_type != SSH_FXP_STATUS) {
- ssh_set_error(msg->sftp->session, SSH_FATAL,
- "Not a ssh_fxp_status message passed in!");
- return NULL;
- }
-
- status = malloc(sizeof(struct sftp_status_message_struct));
- if (status == NULL) {
- ssh_set_error_oom(msg->sftp->session);
- return NULL;
- }
- ZERO_STRUCTP(status);
-
- status->id = msg->id;
- if (buffer_get_u32(msg->payload,&status->status) != 4){
- SAFE_FREE(status);
- ssh_set_error(msg->sftp->session, SSH_FATAL,
- "Invalid SSH_FXP_STATUS message");
- return NULL;
- }
- status->error = buffer_get_ssh_string(msg->payload);
- status->lang = buffer_get_ssh_string(msg->payload);
- if(status->error == NULL || status->lang == NULL){
- if(msg->sftp->version >=3){
- /* These are mandatory from version 3 */
- ssh_string_free(status->error);
- /* status->lang never get allocated if something failed */
- SAFE_FREE(status);
- ssh_set_error(msg->sftp->session, SSH_FATAL,
- "Invalid SSH_FXP_STATUS message");
- return NULL;
- }
- }
-
- status->status = ntohl(status->status);
- if(status->error)
- status->errormsg = ssh_string_to_char(status->error);
- else
- status->errormsg = strdup("No error message in packet");
- if(status->lang)
- status->langmsg = ssh_string_to_char(status->lang);
- else
- status->langmsg = strdup("");
- if (status->errormsg == NULL || status->langmsg == NULL) {
- ssh_set_error_oom(msg->sftp->session);
- status_msg_free(status);
- return NULL;
- }
-
- return status;
-}
-
-static void status_msg_free(sftp_status_message status){
- if (status == NULL) {
- return;
- }
-
- ssh_string_free(status->error);
- ssh_string_free(status->lang);
- SAFE_FREE(status->errormsg);
- SAFE_FREE(status->langmsg);
- SAFE_FREE(status);
-}
-
-static sftp_file parse_handle_msg(sftp_message msg){
- sftp_file file;
-
- if(msg->packet_type != SSH_FXP_HANDLE) {
- ssh_set_error(msg->sftp->session, SSH_FATAL,
- "Not a ssh_fxp_handle message passed in!");
- return NULL;
- }
-
- file = malloc(sizeof(struct sftp_file_struct));
- if (file == NULL) {
- ssh_set_error_oom(msg->sftp->session);
- return NULL;
- }
- ZERO_STRUCTP(file);
-
- file->handle = buffer_get_ssh_string(msg->payload);
- if (file->handle == NULL) {
- ssh_set_error(msg->sftp->session, SSH_FATAL,
- "Invalid SSH_FXP_HANDLE message");
- SAFE_FREE(file);
- return NULL;
- }
-
- file->sftp = msg->sftp;
- file->offset = 0;
- file->eof = 0;
-
- return file;
-}
-
-/* Open a directory */
-sftp_dir sftp_opendir(sftp_session sftp, const char *path){
- sftp_message msg = NULL;
- sftp_file file = NULL;
- sftp_dir dir = NULL;
- sftp_status_message status;
- ssh_string path_s;
- ssh_buffer payload;
- uint32_t id;
-
- payload = ssh_buffer_new();
- if (payload == NULL) {
- ssh_set_error_oom(sftp->session);
- return NULL;
- }
-
- path_s = ssh_string_from_char(path);
- if (path_s == NULL) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(payload);
- return NULL;
- }
-
- id = sftp_get_new_id(sftp);
- if (buffer_add_u32(payload, id) < 0 ||
- buffer_add_ssh_string(payload, path_s) < 0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(payload);
- ssh_string_free(path_s);
- return NULL;
- }
- ssh_string_free(path_s);
-
- if (sftp_packet_write(sftp, SSH_FXP_OPENDIR, payload) < 0) {
- ssh_buffer_free(payload);
- return NULL;
- }
- ssh_buffer_free(payload);
-
- while (msg == NULL) {
- if (sftp_read_and_dispatch(sftp) < 0) {
- /* something nasty has happened */
- return NULL;
- }
- msg = sftp_dequeue(sftp, id);
- }
-
- switch (msg->packet_type) {
- case SSH_FXP_STATUS:
- status = parse_status_msg(msg);
- sftp_message_free(msg);
- if (status == NULL) {
- return NULL;
- }
- sftp_set_error(sftp, status->status);
- ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
- "SFTP server: %s", status->errormsg);
- status_msg_free(status);
- return NULL;
- case SSH_FXP_HANDLE:
- file = parse_handle_msg(msg);
- sftp_message_free(msg);
- if (file != NULL) {
- dir = malloc(sizeof(struct sftp_dir_struct));
- if (dir == NULL) {
- ssh_set_error_oom(sftp->session);
- return NULL;
- }
- ZERO_STRUCTP(dir);
-
- dir->sftp = sftp;
- dir->name = strdup(path);
- if (dir->name == NULL) {
- SAFE_FREE(dir);
- SAFE_FREE(file);
- return NULL;
- }
- dir->handle = file->handle;
- SAFE_FREE(file);
- }
- return dir;
- default:
- ssh_set_error(sftp->session, SSH_FATAL,
- "Received message %d during opendir!", msg->packet_type);
- sftp_message_free(msg);
- }
-
- return NULL;
-}
-
-/*
- * Parse the attributes from a payload from some messages. It is coded on
- * baselines from the protocol version 4.
- * This code is more or less dead but maybe we need it in future.
- */
-static sftp_attributes sftp_parse_attr_4(sftp_session sftp, ssh_buffer buf,
- int expectnames) {
- sftp_attributes attr;
- ssh_string owner = NULL;
- ssh_string group = NULL;
- uint32_t flags = 0;
- int ok = 0;
-
- /* unused member variable */
- (void) expectnames;
-
- attr = malloc(sizeof(struct sftp_attributes_struct));
- if (attr == NULL) {
- ssh_set_error_oom(sftp->session);
- return NULL;
- }
- ZERO_STRUCTP(attr);
-
- /* This isn't really a loop, but it is like a try..catch.. */
- do {
- if (buffer_get_u32(buf, &flags) != 4) {
- break;
- }
-
- flags = ntohl(flags);
- attr->flags = flags;
-
- if (flags & SSH_FILEXFER_ATTR_SIZE) {
- if (buffer_get_u64(buf, &attr->size) != 8) {
- break;
- }
- attr->size = ntohll(attr->size);
- }
-
- if (flags & SSH_FILEXFER_ATTR_OWNERGROUP) {
- if((owner = buffer_get_ssh_string(buf)) == NULL ||
- (attr->owner = ssh_string_to_char(owner)) == NULL) {
- break;
- }
- if ((group = buffer_get_ssh_string(buf)) == NULL ||
- (attr->group = ssh_string_to_char(group)) == NULL) {
- break;
- }
- }
-
- if (flags & SSH_FILEXFER_ATTR_PERMISSIONS) {
- if (buffer_get_u32(buf, &attr->permissions) != 4) {
- break;
- }
- attr->permissions = ntohl(attr->permissions);
-
- /* FIXME on windows! */
- switch (attr->permissions & S_IFMT) {
- case S_IFSOCK:
- case S_IFBLK:
- case S_IFCHR:
- case S_IFIFO:
- attr->type = SSH_FILEXFER_TYPE_SPECIAL;
- break;
- case S_IFLNK:
- attr->type = SSH_FILEXFER_TYPE_SYMLINK;
- break;
- case S_IFREG:
- attr->type = SSH_FILEXFER_TYPE_REGULAR;
- break;
- case S_IFDIR:
- attr->type = SSH_FILEXFER_TYPE_DIRECTORY;
- break;
- default:
- attr->type = SSH_FILEXFER_TYPE_UNKNOWN;
- break;
- }
- }
-
- if (flags & SSH_FILEXFER_ATTR_ACCESSTIME) {
- if (buffer_get_u64(buf, &attr->atime64) != 8) {
- break;
- }
- attr->atime64 = ntohll(attr->atime64);
- }
-
- if (flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES) {
- if (buffer_get_u32(buf, &attr->atime_nseconds) != 4) {
- break;
- }
- attr->atime_nseconds = ntohl(attr->atime_nseconds);
- }
-
- if (flags & SSH_FILEXFER_ATTR_CREATETIME) {
- if (buffer_get_u64(buf, &attr->createtime) != 8) {
- break;
- }
- attr->createtime = ntohll(attr->createtime);
- }
-
- if (flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES) {
- if (buffer_get_u32(buf, &attr->createtime_nseconds) != 4) {
- break;
- }
- attr->createtime_nseconds = ntohl(attr->createtime_nseconds);
- }
-
- if (flags & SSH_FILEXFER_ATTR_MODIFYTIME) {
- if (buffer_get_u64(buf, &attr->mtime64) != 8) {
- break;
- }
- attr->mtime64 = ntohll(attr->mtime64);
- }
-
- if (flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES) {
- if (buffer_get_u32(buf, &attr->mtime_nseconds) != 4) {
- break;
- }
- attr->mtime_nseconds = ntohl(attr->mtime_nseconds);
- }
-
- if (flags & SSH_FILEXFER_ATTR_ACL) {
- if ((attr->acl = buffer_get_ssh_string(buf)) == NULL) {
- break;
- }
- }
-
- if (flags & SSH_FILEXFER_ATTR_EXTENDED) {
- if (buffer_get_u32(buf,&attr->extended_count) != 4) {
- break;
- }
- attr->extended_count = ntohl(attr->extended_count);
-
- while(attr->extended_count &&
- (attr->extended_type = buffer_get_ssh_string(buf)) &&
- (attr->extended_data = buffer_get_ssh_string(buf))){
- attr->extended_count--;
- }
-
- if (attr->extended_count) {
- break;
- }
- }
- ok = 1;
- } while (0);
-
- if (ok == 0) {
- /* break issued somewhere */
- ssh_string_free(owner);
- ssh_string_free(group);
- ssh_string_free(attr->acl);
- ssh_string_free(attr->extended_type);
- ssh_string_free(attr->extended_data);
- SAFE_FREE(attr->owner);
- SAFE_FREE(attr->group);
- SAFE_FREE(attr);
-
- ssh_set_error(sftp->session, SSH_FATAL, "Invalid ATTR structure");
-
- return NULL;
- }
-
- return attr;
-}
-
-enum sftp_longname_field_e {
- SFTP_LONGNAME_PERM = 0,
- SFTP_LONGNAME_FIXME,
- SFTP_LONGNAME_OWNER,
- SFTP_LONGNAME_GROUP,
- SFTP_LONGNAME_SIZE,
- SFTP_LONGNAME_DATE,
- SFTP_LONGNAME_TIME,
- SFTP_LONGNAME_NAME,
-};
-
-static char *sftp_parse_longname(const char *longname,
- enum sftp_longname_field_e longname_field) {
- const char *p, *q;
- size_t len, field = 0;
- char *x;
-
- p = longname;
- /* Find the beginning of the field which is specified by sftp_longanme_field_e. */
- while(field != longname_field) {
- if(isspace(*p)) {
- field++;
- p++;
- while(*p && isspace(*p)) {
- p++;
- }
- } else {
- p++;
- }
- }
-
- q = p;
- while (! isspace(*q)) {
- q++;
- }
-
- /* There is no strndup on windows */
- len = q - p + 1;
- x = malloc(len);
- if (x == NULL) {
- return NULL;
- }
-
- snprintf(x, len, "%s", p);
-
- return x;
-}
-
-/* sftp version 0-3 code. It is different from the v4 */
-/* maybe a paste of the draft is better than the code */
-/*
- uint32 flags
- uint64 size present only if flag SSH_FILEXFER_ATTR_SIZE
- uint32 uid present only if flag SSH_FILEXFER_ATTR_UIDGID
- uint32 gid present only if flag SSH_FILEXFER_ATTR_UIDGID
- uint32 permissions present only if flag SSH_FILEXFER_ATTR_PERMISSIONS
- uint32 atime present only if flag SSH_FILEXFER_ACMODTIME
- uint32 mtime present only if flag SSH_FILEXFER_ACMODTIME
- uint32 extended_count present only if flag SSH_FILEXFER_ATTR_EXTENDED
- string extended_type
- string extended_data
- ... more extended data (extended_type - extended_data pairs),
- so that number of pairs equals extended_count */
-static sftp_attributes sftp_parse_attr_3(sftp_session sftp, ssh_buffer buf,
- int expectname) {
- ssh_string longname = NULL;
- ssh_string name = NULL;
- sftp_attributes attr;
- uint32_t flags = 0;
- int ok = 0;
-
- attr = malloc(sizeof(struct sftp_attributes_struct));
- if (attr == NULL) {
- ssh_set_error_oom(sftp->session);
- return NULL;
- }
- ZERO_STRUCTP(attr);
-
- /* This isn't really a loop, but it is like a try..catch.. */
- do {
- if (expectname) {
- if ((name = buffer_get_ssh_string(buf)) == NULL ||
- (attr->name = ssh_string_to_char(name)) == NULL) {
- break;
- }
- ssh_string_free(name);
-
- ssh_log(sftp->session, SSH_LOG_RARE, "Name: %s", attr->name);
-
- if ((longname=buffer_get_ssh_string(buf)) == NULL ||
- (attr->longname=ssh_string_to_char(longname)) == NULL) {
- break;
- }
- ssh_string_free(longname);
-
- /* Set owner and group if we talk to openssh and have the longname */
- if (ssh_get_openssh_version(sftp->session)) {
- attr->owner = sftp_parse_longname(attr->longname, SFTP_LONGNAME_OWNER);
- if (attr->owner == NULL) {
- break;
- }
-
- attr->group = sftp_parse_longname(attr->longname, SFTP_LONGNAME_GROUP);
- if (attr->group == NULL) {
- break;
- }
- }
- }
-
- if (buffer_get_u32(buf, &flags) != sizeof(uint32_t)) {
- break;
- }
- flags = ntohl(flags);
- attr->flags = flags;
- ssh_log(sftp->session, SSH_LOG_RARE,
- "Flags: %.8lx\n", (long unsigned int) flags);
-
- if (flags & SSH_FILEXFER_ATTR_SIZE) {
- if(buffer_get_u64(buf, &attr->size) != sizeof(uint64_t)) {
- break;
- }
- attr->size = ntohll(attr->size);
- ssh_log(sftp->session, SSH_LOG_RARE,
- "Size: %llu\n",
- (long long unsigned int) attr->size);
- }
-
- if (flags & SSH_FILEXFER_ATTR_UIDGID) {
- if (buffer_get_u32(buf, &attr->uid) != sizeof(uint32_t)) {
- break;
- }
- if (buffer_get_u32(buf, &attr->gid) != sizeof(uint32_t)) {
- break;
- }
- attr->uid = ntohl(attr->uid);
- attr->gid = ntohl(attr->gid);
- }
-
- if (flags & SSH_FILEXFER_ATTR_PERMISSIONS) {
- if (buffer_get_u32(buf, &attr->permissions) != sizeof(uint32_t)) {
- break;
- }
- attr->permissions = ntohl(attr->permissions);
-
- switch (attr->permissions & S_IFMT) {
- case S_IFSOCK:
- case S_IFBLK:
- case S_IFCHR:
- case S_IFIFO:
- attr->type = SSH_FILEXFER_TYPE_SPECIAL;
- break;
- case S_IFLNK:
- attr->type = SSH_FILEXFER_TYPE_SYMLINK;
- break;
- case S_IFREG:
- attr->type = SSH_FILEXFER_TYPE_REGULAR;
- break;
- case S_IFDIR:
- attr->type = SSH_FILEXFER_TYPE_DIRECTORY;
- break;
- default:
- attr->type = SSH_FILEXFER_TYPE_UNKNOWN;
- break;
- }
- }
-
- if (flags & SSH_FILEXFER_ATTR_ACMODTIME) {
- if (buffer_get_u32(buf, &attr->atime) != sizeof(uint32_t)) {
- break;
- }
- attr->atime = ntohl(attr->atime);
- if (buffer_get_u32(buf, &attr->mtime) != sizeof(uint32_t)) {
- break;
- }
- attr->mtime = ntohl(attr->mtime);
- }
-
- if (flags & SSH_FILEXFER_ATTR_EXTENDED) {
- if (buffer_get_u32(buf, &attr->extended_count) != sizeof(uint32_t)) {
- break;
- }
-
- attr->extended_count = ntohl(attr->extended_count);
- while (attr->extended_count &&
- (attr->extended_type = buffer_get_ssh_string(buf))
- && (attr->extended_data = buffer_get_ssh_string(buf))) {
- attr->extended_count--;
- }
-
- if (attr->extended_count) {
- break;
- }
- }
- ok = 1;
- } while (0);
-
- if (!ok) {
- /* break issued somewhere */
- ssh_string_free(name);
- ssh_string_free(longname);
- ssh_string_free(attr->extended_type);
- ssh_string_free(attr->extended_data);
- SAFE_FREE(attr->name);
- SAFE_FREE(attr->longname);
- SAFE_FREE(attr->owner);
- SAFE_FREE(attr->group);
- SAFE_FREE(attr);
-
- ssh_set_error(sftp->session, SSH_FATAL, "Invalid ATTR structure");
-
- return NULL;
- }
-
- /* everything went smoothly */
- return attr;
-}
-
-/* FIXME is this really needed as a public function? */
-int buffer_add_attributes(ssh_buffer buffer, sftp_attributes attr) {
- uint32_t flags = (attr ? attr->flags : 0);
-
- flags &= (SSH_FILEXFER_ATTR_SIZE | SSH_FILEXFER_ATTR_UIDGID |
- SSH_FILEXFER_ATTR_PERMISSIONS | SSH_FILEXFER_ATTR_ACMODTIME);
-
- if (buffer_add_u32(buffer, htonl(flags)) < 0) {
- return -1;
- }
-
- if (attr) {
- if (flags & SSH_FILEXFER_ATTR_SIZE) {
- if (buffer_add_u64(buffer, htonll(attr->size)) < 0) {
- return -1;
- }
- }
-
- if (flags & SSH_FILEXFER_ATTR_UIDGID) {
- if (buffer_add_u32(buffer,htonl(attr->uid)) < 0 ||
- buffer_add_u32(buffer,htonl(attr->gid)) < 0) {
- return -1;
- }
- }
-
- if (flags & SSH_FILEXFER_ATTR_PERMISSIONS) {
- if (buffer_add_u32(buffer, htonl(attr->permissions)) < 0) {
- return -1;
- }
- }
-
- if (flags & SSH_FILEXFER_ATTR_ACMODTIME) {
- if (buffer_add_u32(buffer, htonl(attr->atime)) < 0 ||
- buffer_add_u32(buffer, htonl(attr->mtime)) < 0) {
- return -1;
- }
- }
- }
-
- return 0;
-}
-
-
-sftp_attributes sftp_parse_attr(sftp_session session, ssh_buffer buf,
- int expectname) {
- switch(session->version) {
- case 4:
- return sftp_parse_attr_4(session, buf, expectname);
- case 3:
- case 2:
- case 1:
- case 0:
- return sftp_parse_attr_3(session, buf, expectname);
- default:
- ssh_set_error(session->session, SSH_FATAL,
- "Version %d unsupported by client", session->server_version);
- return NULL;
- }
-
- return NULL;
-}
-
-/* Get the version of the SFTP protocol supported by the server */
-int sftp_server_version(sftp_session sftp) {
- return sftp->server_version;
-}
-
-/* Get a single file attributes structure of a directory. */
-sftp_attributes sftp_readdir(sftp_session sftp, sftp_dir dir) {
- sftp_message msg = NULL;
- sftp_status_message status;
- sftp_attributes attr;
- ssh_buffer payload;
- uint32_t id;
-
- if (dir->buffer == NULL) {
- payload = ssh_buffer_new();
- if (payload == NULL) {
- ssh_set_error_oom(sftp->session);
- return NULL;
- }
-
- id = sftp_get_new_id(sftp);
- if (buffer_add_u32(payload, id) < 0 ||
- buffer_add_ssh_string(payload, dir->handle) < 0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(payload);
- return NULL;
- }
-
- if (sftp_packet_write(sftp, SSH_FXP_READDIR, payload) < 0) {
- ssh_buffer_free(payload);
- return NULL;
- }
- ssh_buffer_free(payload);
-
- ssh_log(sftp->session, SSH_LOG_PACKET,
- "Sent a ssh_fxp_readdir with id %d", id);
-
- while (msg == NULL) {
- if (sftp_read_and_dispatch(sftp) < 0) {
- /* something nasty has happened */
- return NULL;
- }
- msg = sftp_dequeue(sftp, id);
- }
-
- switch (msg->packet_type){
- case SSH_FXP_STATUS:
- status = parse_status_msg(msg);
- sftp_message_free(msg);
- if (status == NULL) {
- return NULL;
- }
- sftp_set_error(sftp, status->status);
- switch (status->status) {
- case SSH_FX_EOF:
- dir->eof = 1;
- status_msg_free(status);
- return NULL;
- default:
- break;
- }
-
- ssh_set_error(sftp->session, SSH_FATAL,
- "Unknown error status: %d", status->status);
- status_msg_free(status);
-
- return NULL;
- case SSH_FXP_NAME:
- buffer_get_u32(msg->payload, &dir->count);
- dir->count = ntohl(dir->count);
- dir->buffer = msg->payload;
- msg->payload = NULL;
- sftp_message_free(msg);
- break;
- default:
- ssh_set_error(sftp->session, SSH_FATAL,
- "Unsupported message back %d", msg->packet_type);
- sftp_message_free(msg);
-
- return NULL;
- }
- }
-
- /* now dir->buffer contains a buffer and dir->count != 0 */
- if (dir->count == 0) {
- ssh_set_error(sftp->session, SSH_FATAL,
- "Count of files sent by the server is zero, which is invalid, or "
- "libsftp bug");
- return NULL;
- }
-
- ssh_log(sftp->session, SSH_LOG_RARE, "Count is %d", dir->count);
-
- attr = sftp_parse_attr(sftp, dir->buffer, 1);
- if (attr == NULL) {
- ssh_set_error(sftp->session, SSH_FATAL,
- "Couldn't parse the SFTP attributes");
- return NULL;
- }
-
- dir->count--;
- if (dir->count == 0) {
- ssh_buffer_free(dir->buffer);
- dir->buffer = NULL;
- }
-
- return attr;
-}
-
-/* Tell if the directory has reached EOF (End Of File). */
-int sftp_dir_eof(sftp_dir dir) {
- return dir->eof;
-}
-
-/* Free a SFTP_ATTRIBUTE handle */
-void sftp_attributes_free(sftp_attributes file){
- if (file == NULL) {
- return;
- }
-
- ssh_string_free(file->acl);
- ssh_string_free(file->extended_data);
- ssh_string_free(file->extended_type);
-
- SAFE_FREE(file->name);
- SAFE_FREE(file->longname);
- SAFE_FREE(file->group);
- SAFE_FREE(file->owner);
-
- SAFE_FREE(file);
-}
-
-static int sftp_handle_close(sftp_session sftp, ssh_string handle) {
- sftp_status_message status;
- sftp_message msg = NULL;
- ssh_buffer buffer = NULL;
- uint32_t id;
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- ssh_set_error_oom(sftp->session);
- return -1;
- }
-
- id = sftp_get_new_id(sftp);
- if (buffer_add_u32(buffer, id) < 0 ||
- buffer_add_ssh_string(buffer, handle) < 0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- return -1;
- }
- if (sftp_packet_write(sftp, SSH_FXP_CLOSE ,buffer) < 0) {
- ssh_buffer_free(buffer);
- return -1;
- }
- ssh_buffer_free(buffer);
-
- while (msg == NULL) {
- if (sftp_read_and_dispatch(sftp) < 0) {
- /* something nasty has happened */
- return -1;
- }
- msg = sftp_dequeue(sftp,id);
- }
-
- switch (msg->packet_type) {
- case SSH_FXP_STATUS:
- status = parse_status_msg(msg);
- sftp_message_free(msg);
- if(status == NULL) {
- return -1;
- }
- sftp_set_error(sftp, status->status);
- switch (status->status) {
- case SSH_FX_OK:
- status_msg_free(status);
- return 0;
- break;
- default:
- break;
- }
- ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
- "SFTP server: %s", status->errormsg);
- status_msg_free(status);
- return -1;
- default:
- ssh_set_error(sftp->session, SSH_FATAL,
- "Received message %d during sftp_handle_close!", msg->packet_type);
- sftp_message_free(msg);
- }
-
- return -1;
-}
-
-/* Close an open file handle. */
-int sftp_close(sftp_file file){
- int err = SSH_NO_ERROR;
-
- SAFE_FREE(file->name);
- if (file->handle){
- err = sftp_handle_close(file->sftp,file->handle);
- ssh_string_free(file->handle);
- }
- /* FIXME: check server response and implement errno */
- SAFE_FREE(file);
-
- return err;
-}
-
-/* Close an open directory. */
-int sftp_closedir(sftp_dir dir){
- int err = SSH_NO_ERROR;
-
- SAFE_FREE(dir->name);
- if (dir->handle) {
- err = sftp_handle_close(dir->sftp, dir->handle);
- ssh_string_free(dir->handle);
- }
- /* FIXME: check server response and implement errno */
- ssh_buffer_free(dir->buffer);
- SAFE_FREE(dir);
-
- return err;
-}
-
-/* Open a file on the server. */
-sftp_file sftp_open(sftp_session sftp, const char *file, int flags,
- mode_t mode) {
- sftp_message msg = NULL;
- sftp_status_message status;
- struct sftp_attributes_struct attr;
- sftp_file handle;
- ssh_string filename;
- ssh_buffer buffer;
- uint32_t sftp_flags = 0;
- uint32_t id;
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- ssh_set_error_oom(sftp->session);
- return NULL;
- }
-
- filename = ssh_string_from_char(file);
- if (filename == NULL) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- return NULL;
- }
-
- ZERO_STRUCT(attr);
- attr.permissions = mode;
- attr.flags = SSH_FILEXFER_ATTR_PERMISSIONS;
-
- if (flags == O_RDONLY)
- sftp_flags |= SSH_FXF_READ; /* if any of the other flag is set,
- READ should not be set initialy */
- if (flags & O_WRONLY)
- sftp_flags |= SSH_FXF_WRITE;
- if (flags & O_RDWR)
- sftp_flags |= (SSH_FXF_WRITE | SSH_FXF_READ);
- if (flags & O_CREAT)
- sftp_flags |= SSH_FXF_CREAT;
- if (flags & O_TRUNC)
- sftp_flags |= SSH_FXF_TRUNC;
- if (flags & O_EXCL)
- sftp_flags |= SSH_FXF_EXCL;
- ssh_log(sftp->session,SSH_LOG_PACKET,"Opening file %s with sftp flags %x",file,sftp_flags);
- id = sftp_get_new_id(sftp);
- if (buffer_add_u32(buffer, id) < 0 ||
- buffer_add_ssh_string(buffer, filename) < 0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- ssh_string_free(filename);
- return NULL;
- }
- ssh_string_free(filename);
-
- if (buffer_add_u32(buffer, htonl(sftp_flags)) < 0 ||
- buffer_add_attributes(buffer, &attr) < 0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- return NULL;
- }
- if (sftp_packet_write(sftp, SSH_FXP_OPEN, buffer) < 0) {
- ssh_buffer_free(buffer);
- return NULL;
- }
- ssh_buffer_free(buffer);
-
- while (msg == NULL) {
- if (sftp_read_and_dispatch(sftp) < 0) {
- /* something nasty has happened */
- return NULL;
- }
- msg = sftp_dequeue(sftp, id);
- }
-
- switch (msg->packet_type) {
- case SSH_FXP_STATUS:
- status = parse_status_msg(msg);
- sftp_message_free(msg);
- if (status == NULL) {
- return NULL;
- }
- sftp_set_error(sftp, status->status);
- ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
- "SFTP server: %s", status->errormsg);
- status_msg_free(status);
-
- return NULL;
- case SSH_FXP_HANDLE:
- handle = parse_handle_msg(msg);
- sftp_message_free(msg);
- return handle;
- default:
- ssh_set_error(sftp->session, SSH_FATAL,
- "Received message %d during open!", msg->packet_type);
- sftp_message_free(msg);
- }
-
- return NULL;
-}
-
-void sftp_file_set_nonblocking(sftp_file handle){
- handle->nonblocking=1;
-}
-void sftp_file_set_blocking(sftp_file handle){
- handle->nonblocking=0;
-}
-
-/* Read from a file using an opened sftp file handle. */
-ssize_t sftp_read(sftp_file handle, void *buf, size_t count) {
- sftp_session sftp = handle->sftp;
- sftp_message msg = NULL;
- sftp_status_message status;
- ssh_string datastring;
- ssh_buffer buffer;
- int id;
-
- if (handle->eof) {
- return 0;
- }
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- ssh_set_error_oom(sftp->session);
- return -1;
- }
- id = sftp_get_new_id(handle->sftp);
- if (buffer_add_u32(buffer, id) < 0 ||
- buffer_add_ssh_string(buffer, handle->handle) < 0 ||
- buffer_add_u64(buffer, htonll(handle->offset)) < 0 ||
- buffer_add_u32(buffer,htonl(count)) < 0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- return -1;
- }
- if (sftp_packet_write(handle->sftp, SSH_FXP_READ, buffer) < 0) {
- ssh_buffer_free(buffer);
- return -1;
- }
- ssh_buffer_free(buffer);
-
- while (msg == NULL) {
- if (handle->nonblocking) {
- if (ssh_channel_poll(handle->sftp->channel, 0) == 0) {
- /* we cannot block */
- return 0;
- }
- }
- if (sftp_read_and_dispatch(handle->sftp) < 0) {
- /* something nasty has happened */
- return -1;
- }
- msg = sftp_dequeue(handle->sftp, id);
- }
-
- switch (msg->packet_type) {
- case SSH_FXP_STATUS:
- status = parse_status_msg(msg);
- sftp_message_free(msg);
- if (status == NULL) {
- return -1;
- }
- sftp_set_error(sftp, status->status);
- switch (status->status) {
- case SSH_FX_EOF:
- handle->eof = 1;
- status_msg_free(status);
- return 0;
- default:
- break;
- }
- ssh_set_error(sftp->session,SSH_REQUEST_DENIED,
- "SFTP server: %s", status->errormsg);
- status_msg_free(status);
- return -1;
- case SSH_FXP_DATA:
- datastring = buffer_get_ssh_string(msg->payload);
- sftp_message_free(msg);
- if (datastring == NULL) {
- ssh_set_error(sftp->session, SSH_FATAL,
- "Received invalid DATA packet from sftp server");
- return -1;
- }
-
- if (ssh_string_len(datastring) > count) {
- ssh_set_error(sftp->session, SSH_FATAL,
- "Received a too big DATA packet from sftp server: "
- "%zu and asked for %zu",
- ssh_string_len(datastring), count);
- ssh_string_free(datastring);
- return -1;
- }
- count = ssh_string_len(datastring);
- handle->offset += count;
- memcpy(buf, ssh_string_data(datastring), count);
- ssh_string_free(datastring);
- return count;
- default:
- ssh_set_error(sftp->session, SSH_FATAL,
- "Received message %d during read!", msg->packet_type);
- sftp_message_free(msg);
- return -1;
- }
-
- return -1; /* not reached */
-}
-
-/* Start an asynchronous read from a file using an opened sftp file handle. */
-int sftp_async_read_begin(sftp_file file, uint32_t len){
- sftp_session sftp = file->sftp;
- ssh_buffer buffer;
- uint32_t id;
-
- sftp_enter_function();
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- ssh_set_error_oom(sftp->session);
- return -1;
- }
-
- id = sftp_get_new_id(sftp);
- if (buffer_add_u32(buffer, id) < 0 ||
- buffer_add_ssh_string(buffer, file->handle) < 0 ||
- buffer_add_u64(buffer, htonll(file->offset)) < 0 ||
- buffer_add_u32(buffer, htonl(len)) < 0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- return -1;
- }
- if (sftp_packet_write(sftp, SSH_FXP_READ, buffer) < 0) {
- ssh_buffer_free(buffer);
- return -1;
- }
- ssh_buffer_free(buffer);
-
- file->offset += len; /* assume we'll read len bytes */
-
- sftp_leave_function();
- return id;
-}
-
-/* Wait for an asynchronous read to complete and save the data. */
-int sftp_async_read(sftp_file file, void *data, uint32_t size, uint32_t id){
- sftp_session sftp = file->sftp;
- sftp_message msg = NULL;
- sftp_status_message status;
- ssh_string datastring;
- int err = SSH_OK;
- uint32_t len;
-
- sftp_enter_function();
-
- if (file->eof) {
- sftp_leave_function();
- return 0;
- }
-
- /* handle an existing request */
- while (msg == NULL) {
- if (file->nonblocking){
- if (ssh_channel_poll(sftp->channel, 0) == 0) {
- /* we cannot block */
- return SSH_AGAIN;
- }
- }
-
- if (sftp_read_and_dispatch(sftp) < 0) {
- /* something nasty has happened */
- sftp_leave_function();
- return SSH_ERROR;
- }
-
- msg = sftp_dequeue(sftp,id);
- }
-
- switch (msg->packet_type) {
- case SSH_FXP_STATUS:
- status = parse_status_msg(msg);
- sftp_message_free(msg);
- if (status == NULL) {
- sftp_leave_function();
- return -1;
- }
- sftp_set_error(sftp, status->status);
- if (status->status != SSH_FX_EOF) {
- ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
- "SFTP server : %s", status->errormsg);
- sftp_leave_function();
- err = SSH_ERROR;
- } else {
- file->eof = 1;
- }
- status_msg_free(status);
- sftp_leave_function();
- return err;
- case SSH_FXP_DATA:
- datastring = buffer_get_ssh_string(msg->payload);
- sftp_message_free(msg);
- if (datastring == NULL) {
- ssh_set_error(sftp->session, SSH_FATAL,
- "Received invalid DATA packet from sftp server");
- sftp_leave_function();
- return SSH_ERROR;
- }
- if (ssh_string_len(datastring) > size) {
- ssh_set_error(sftp->session, SSH_FATAL,
- "Received a too big DATA packet from sftp server: "
- "%zu and asked for %u",
- ssh_string_len(datastring), size);
- ssh_string_free(datastring);
- sftp_leave_function();
- return SSH_ERROR;
- }
- len = ssh_string_len(datastring);
- //handle->offset+=len;
- /* We already have set the offset previously. All we can do is warn that the expected len
- * and effective lengths are different */
- memcpy(data, ssh_string_data(datastring), len);
- ssh_string_free(datastring);
- sftp_leave_function();
- return len;
- default:
- ssh_set_error(sftp->session,SSH_FATAL,"Received message %d during read!",msg->packet_type);
- sftp_message_free(msg);
- sftp_leave_function();
- return SSH_ERROR;
- }
-
- sftp_leave_function();
- return SSH_ERROR;
-}
-
-ssize_t sftp_write(sftp_file file, const void *buf, size_t count) {
- sftp_session sftp = file->sftp;
- sftp_message msg = NULL;
- sftp_status_message status;
- ssh_string datastring;
- ssh_buffer buffer;
- uint32_t id;
- int len;
- int packetlen;
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- ssh_set_error_oom(sftp->session);
- return -1;
- }
-
- datastring = ssh_string_new(count);
- if (datastring == NULL) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- return -1;
- }
- ssh_string_fill(datastring, buf, count);
-
- id = sftp_get_new_id(file->sftp);
- if (buffer_add_u32(buffer, id) < 0 ||
- buffer_add_ssh_string(buffer, file->handle) < 0 ||
- buffer_add_u64(buffer, htonll(file->offset)) < 0 ||
- buffer_add_ssh_string(buffer, datastring) < 0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- ssh_string_free(datastring);
- return -1;
- }
- ssh_string_free(datastring);
- len = sftp_packet_write(file->sftp, SSH_FXP_WRITE, buffer);
- packetlen=ssh_buffer_get_len(buffer);
- ssh_buffer_free(buffer);
- if (len < 0) {
- return -1;
- } else if (len != packetlen) {
- ssh_log(sftp->session, SSH_LOG_PACKET,
- "Could not write as much data as expected");
- }
-
- while (msg == NULL) {
- if (sftp_read_and_dispatch(file->sftp) < 0) {
- /* something nasty has happened */
- return -1;
- }
- msg = sftp_dequeue(file->sftp, id);
- }
-
- switch (msg->packet_type) {
- case SSH_FXP_STATUS:
- status = parse_status_msg(msg);
- sftp_message_free(msg);
- if (status == NULL) {
- return -1;
- }
- sftp_set_error(sftp, status->status);
- switch (status->status) {
- case SSH_FX_OK:
- file->offset += count;
- status_msg_free(status);
- return count;
- default:
- break;
- }
- ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
- "SFTP server: %s", status->errormsg);
- file->offset += count;
- status_msg_free(status);
- return -1;
- default:
- ssh_set_error(sftp->session, SSH_FATAL,
- "Received message %d during write!", msg->packet_type);
- sftp_message_free(msg);
- return -1;
- }
-
- return -1; /* not reached */
-}
-
-/* Seek to a specific location in a file. */
-int sftp_seek(sftp_file file, uint32_t new_offset) {
- if (file == NULL) {
- return -1;
- }
-
- file->offset = new_offset;
-
- return 0;
-}
-
-int sftp_seek64(sftp_file file, uint64_t new_offset) {
- if (file == NULL) {
- return -1;
- }
-
- file->offset = new_offset;
-
- return 0;
-}
-
-/* Report current byte position in file. */
-unsigned long sftp_tell(sftp_file file) {
- return (unsigned long)file->offset;
-}
-/* Report current byte position in file. */
-uint64_t sftp_tell64(sftp_file file) {
- return (uint64_t) file->offset;
-}
-
-/* Rewinds the position of the file pointer to the beginning of the file.*/
-void sftp_rewind(sftp_file file) {
- file->offset = 0;
-}
-
-/* code written by Nick */
-int sftp_unlink(sftp_session sftp, const char *file) {
- sftp_status_message status = NULL;
- sftp_message msg = NULL;
- ssh_string filename;
- ssh_buffer buffer;
- uint32_t id;
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- ssh_set_error_oom(sftp->session);
- return -1;
- }
-
- filename = ssh_string_from_char(file);
- if (filename == NULL) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- return -1;
- }
-
- id = sftp_get_new_id(sftp);
- if (buffer_add_u32(buffer, id) < 0 ||
- buffer_add_ssh_string(buffer, filename) < 0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- ssh_string_free(filename);
- }
- if (sftp_packet_write(sftp, SSH_FXP_REMOVE, buffer) < 0) {
- ssh_buffer_free(buffer);
- ssh_string_free(filename);
- }
- ssh_string_free(filename);
- ssh_buffer_free(buffer);
-
- while (msg == NULL) {
- if (sftp_read_and_dispatch(sftp)) {
- return -1;
- }
- msg = sftp_dequeue(sftp, id);
- }
-
- if (msg->packet_type == SSH_FXP_STATUS) {
- /* by specification, this command's only supposed to return SSH_FXP_STATUS */
- status = parse_status_msg(msg);
- sftp_message_free(msg);
- if (status == NULL) {
- return -1;
- }
- sftp_set_error(sftp, status->status);
- switch (status->status) {
- case SSH_FX_OK:
- status_msg_free(status);
- return 0;
- default:
- break;
- }
-
- /*
- * The status should be SSH_FX_OK if the command was successful, if it
- * didn't, then there was an error
- */
- ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
- "SFTP server: %s", status->errormsg);
- status_msg_free(status);
- return -1;
- } else {
- ssh_set_error(sftp->session,SSH_FATAL,
- "Received message %d when attempting to remove file", msg->packet_type);
- sftp_message_free(msg);
- }
-
- return -1;
-}
-
-/* code written by Nick */
-int sftp_rmdir(sftp_session sftp, const char *directory) {
- sftp_status_message status = NULL;
- sftp_message msg = NULL;
- ssh_string filename;
- ssh_buffer buffer;
- uint32_t id;
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- ssh_set_error_oom(sftp->session);
- return -1;
- }
-
- filename = ssh_string_from_char(directory);
- if (filename == NULL) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- return -1;
- }
-
- id = sftp_get_new_id(sftp);
- if (buffer_add_u32(buffer, id) < 0 ||
- buffer_add_ssh_string(buffer, filename) < 0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- ssh_string_free(filename);
- return -1;
- }
- if (sftp_packet_write(sftp, SSH_FXP_RMDIR, buffer) < 0) {
- ssh_buffer_free(buffer);
- ssh_string_free(filename);
- return -1;
- }
- ssh_buffer_free(buffer);
- ssh_string_free(filename);
-
- while (msg == NULL) {
- if (sftp_read_and_dispatch(sftp) < 0) {
- return -1;
- }
- msg = sftp_dequeue(sftp, id);
- }
-
- /* By specification, this command returns SSH_FXP_STATUS */
- if (msg->packet_type == SSH_FXP_STATUS) {
- status = parse_status_msg(msg);
- sftp_message_free(msg);
- if (status == NULL) {
- return -1;
- }
- sftp_set_error(sftp, status->status);
- switch (status->status) {
- case SSH_FX_OK:
- status_msg_free(status);
- return 0;
- break;
- default:
- break;
- }
- ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
- "SFTP server: %s", status->errormsg);
- status_msg_free(status);
- return -1;
- } else {
- ssh_set_error(sftp->session, SSH_FATAL,
- "Received message %d when attempting to remove directory",
- msg->packet_type);
- sftp_message_free(msg);
- }
-
- return -1;
-}
-
-/* Code written by Nick */
-int sftp_mkdir(sftp_session sftp, const char *directory, mode_t mode) {
- sftp_status_message status = NULL;
- sftp_message msg = NULL;
- sftp_attributes errno_attr = NULL;
- struct sftp_attributes_struct attr;
- ssh_buffer buffer;
- ssh_string path;
- uint32_t id;
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- ssh_set_error_oom(sftp->session);
- return -1;
- }
-
- path = ssh_string_from_char(directory);
- if (path == NULL) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- return -1;
- }
-
- ZERO_STRUCT(attr);
- attr.permissions = mode;
- attr.flags = SSH_FILEXFER_ATTR_PERMISSIONS;
-
- id = sftp_get_new_id(sftp);
- if (buffer_add_u32(buffer, id) < 0 ||
- buffer_add_ssh_string(buffer, path) < 0 ||
- buffer_add_attributes(buffer, &attr) < 0 ||
- sftp_packet_write(sftp, SSH_FXP_MKDIR, buffer) < 0) {
- ssh_buffer_free(buffer);
- ssh_string_free(path);
- }
- ssh_buffer_free(buffer);
- ssh_string_free(path);
-
- while (msg == NULL) {
- if (sftp_read_and_dispatch(sftp) < 0) {
- return -1;
- }
- msg = sftp_dequeue(sftp, id);
- }
-
- /* By specification, this command only returns SSH_FXP_STATUS */
- if (msg->packet_type == SSH_FXP_STATUS) {
- status = parse_status_msg(msg);
- sftp_message_free(msg);
- if (status == NULL) {
- return -1;
- }
- sftp_set_error(sftp, status->status);
- switch (status->status) {
- case SSH_FX_FAILURE:
- /*
- * mkdir always returns a failure, even if the path already exists.
- * To be POSIX conform and to be able to map it to EEXIST a stat
- * call is needed here.
- */
- errno_attr = sftp_lstat(sftp, directory);
- if (errno_attr != NULL) {
- SAFE_FREE(errno_attr);
- sftp_set_error(sftp, SSH_FX_FILE_ALREADY_EXISTS);
- }
- break;
- case SSH_FX_OK:
- status_msg_free(status);
- return 0;
- break;
- default:
- break;
- }
- /*
- * The status should be SSH_FX_OK if the command was successful, if it
- * didn't, then there was an error
- */
- ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
- "SFTP server: %s", status->errormsg);
- status_msg_free(status);
- return -1;
- } else {
- ssh_set_error(sftp->session, SSH_FATAL,
- "Received message %d when attempting to make directory",
- msg->packet_type);
- sftp_message_free(msg);
- }
-
- return -1;
-}
-
-/* code written by nick */
-int sftp_rename(sftp_session sftp, const char *original, const char *newname) {
- sftp_status_message status = NULL;
- sftp_message msg = NULL;
- ssh_buffer buffer;
- ssh_string oldpath;
- ssh_string newpath;
- uint32_t id;
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- ssh_set_error_oom(sftp->session);
- return -1;
- }
-
- oldpath = ssh_string_from_char(original);
- if (oldpath == NULL) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- return -1;
- }
-
- newpath = ssh_string_from_char(newname);
- if (newpath == NULL) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- ssh_string_free(oldpath);
- return -1;
- }
-
- id = sftp_get_new_id(sftp);
- if (buffer_add_u32(buffer, id) < 0 ||
- buffer_add_ssh_string(buffer, oldpath) < 0 ||
- buffer_add_ssh_string(buffer, newpath) < 0 ||
- /* POSIX rename atomically replaces newpath, we should do the same
- * only available on >=v4 */
- sftp->version>=4 ? (buffer_add_u32(buffer, SSH_FXF_RENAME_OVERWRITE) < 0):0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- ssh_string_free(oldpath);
- ssh_string_free(newpath);
- return -1;
- }
- if (sftp_packet_write(sftp, SSH_FXP_RENAME, buffer) < 0) {
- ssh_buffer_free(buffer);
- ssh_string_free(oldpath);
- ssh_string_free(newpath);
- return -1;
- }
- ssh_buffer_free(buffer);
- ssh_string_free(oldpath);
- ssh_string_free(newpath);
-
- while (msg == NULL) {
- if (sftp_read_and_dispatch(sftp) < 0) {
- return -1;
- }
- msg = sftp_dequeue(sftp, id);
- }
-
- /* By specification, this command only returns SSH_FXP_STATUS */
- if (msg->packet_type == SSH_FXP_STATUS) {
- status = parse_status_msg(msg);
- sftp_message_free(msg);
- if (status == NULL) {
- return -1;
- }
- sftp_set_error(sftp, status->status);
- switch (status->status) {
- case SSH_FX_OK:
- status_msg_free(status);
- return 0;
- default:
- break;
- }
- /*
- * Status should be SSH_FX_OK if the command was successful, if it didn't,
- * then there was an error
- */
- ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
- "SFTP server: %s", status->errormsg);
- status_msg_free(status);
- return -1;
- } else {
- ssh_set_error(sftp->session, SSH_FATAL,
- "Received message %d when attempting to rename",
- msg->packet_type);
- sftp_message_free(msg);
- }
-
- return -1;
-}
-
-/* Code written by Nick */
-/* Set file attributes on a file, directory or symbolic link. */
-int sftp_setstat(sftp_session sftp, const char *file, sftp_attributes attr) {
- uint32_t id;
- ssh_buffer buffer;
- ssh_string path;
- sftp_message msg = NULL;
- sftp_status_message status = NULL;
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- ssh_set_error_oom(sftp->session);
- return -1;
- }
-
- path = ssh_string_from_char(file);
- if (path == NULL) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- return -1;
- }
-
- id = sftp_get_new_id(sftp);
- if (buffer_add_u32(buffer, id) < 0 ||
- buffer_add_ssh_string(buffer, path) < 0 ||
- buffer_add_attributes(buffer, attr) < 0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- ssh_string_free(path);
- return -1;
- }
- if (sftp_packet_write(sftp, SSH_FXP_SETSTAT, buffer) < 0) {
- ssh_buffer_free(buffer);
- ssh_string_free(path);
- return -1;
- }
- ssh_buffer_free(buffer);
- ssh_string_free(path);
-
- while (msg == NULL) {
- if (sftp_read_and_dispatch(sftp) < 0) {
- return -1;
- }
- msg = sftp_dequeue(sftp, id);
- }
-
- /* By specification, this command only returns SSH_FXP_STATUS */
- if (msg->packet_type == SSH_FXP_STATUS) {
- status = parse_status_msg(msg);
- sftp_message_free(msg);
- if (status == NULL) {
- return -1;
- }
- sftp_set_error(sftp, status->status);
- switch (status->status) {
- case SSH_FX_OK:
- status_msg_free(status);
- return 0;
- default:
- break;
- }
- /*
- * The status should be SSH_FX_OK if the command was successful, if it
- * didn't, then there was an error
- */
- ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
- "SFTP server: %s", status->errormsg);
- status_msg_free(status);
- return -1;
- } else {
- ssh_set_error(sftp->session, SSH_FATAL,
- "Received message %d when attempting to set stats", msg->packet_type);
- sftp_message_free(msg);
- }
-
- return -1;
-}
-
-/* Change the file owner and group */
-int sftp_chown(sftp_session sftp, const char *file, uid_t owner, gid_t group) {
- struct sftp_attributes_struct attr;
- ZERO_STRUCT(attr);
-
- attr.uid = owner;
- attr.gid = group;
-
- attr.flags = SSH_FILEXFER_ATTR_UIDGID;
-
- return sftp_setstat(sftp, file, &attr);
-}
-
-/* Change permissions of a file */
-int sftp_chmod(sftp_session sftp, const char *file, mode_t mode) {
- struct sftp_attributes_struct attr;
- ZERO_STRUCT(attr);
- attr.permissions = mode;
- attr.flags = SSH_FILEXFER_ATTR_PERMISSIONS;
-
- return sftp_setstat(sftp, file, &attr);
-}
-
-/* Change the last modification and access time of a file. */
-int sftp_utimes(sftp_session sftp, const char *file,
- const struct timeval *times) {
- struct sftp_attributes_struct attr;
- ZERO_STRUCT(attr);
-
- attr.atime = times[0].tv_sec;
- attr.atime_nseconds = times[0].tv_usec;
-
- attr.mtime = times[1].tv_sec;
- attr.mtime_nseconds = times[1].tv_usec;
-
- attr.flags |= SSH_FILEXFER_ATTR_ACCESSTIME | SSH_FILEXFER_ATTR_MODIFYTIME |
- SSH_FILEXFER_ATTR_SUBSECOND_TIMES;
-
- return sftp_setstat(sftp, file, &attr);
-}
-
-int sftp_symlink(sftp_session sftp, const char *target, const char *dest) {
- sftp_status_message status = NULL;
- sftp_message msg = NULL;
- ssh_string target_s;
- ssh_string dest_s;
- ssh_buffer buffer;
- uint32_t id;
-
- if (sftp == NULL)
- return -1;
- if (target == NULL || dest == NULL) {
- ssh_set_error_invalid(sftp->session, __FUNCTION__);
- return -1;
- }
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- ssh_set_error_oom(sftp->session);
- return -1;
- }
-
- target_s = ssh_string_from_char(target);
- if (target_s == NULL) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- return -1;
- }
-
- dest_s = ssh_string_from_char(dest);
- if (dest_s == NULL) {
- ssh_set_error_oom(sftp->session);
- ssh_string_free(target_s);
- ssh_buffer_free(buffer);
- return -1;
- }
-
- id = sftp_get_new_id(sftp);
- if (buffer_add_u32(buffer, id) < 0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- ssh_string_free(dest_s);
- ssh_string_free(target_s);
- return -1;
- }
- if (ssh_get_openssh_version(sftp->session)) {
- /* TODO check for version number if they ever fix it. */
- if (buffer_add_ssh_string(buffer, target_s) < 0 ||
- buffer_add_ssh_string(buffer, dest_s) < 0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- ssh_string_free(dest_s);
- ssh_string_free(target_s);
- return -1;
- }
- } else {
- if (buffer_add_ssh_string(buffer, dest_s) < 0 ||
- buffer_add_ssh_string(buffer, target_s) < 0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- ssh_string_free(dest_s);
- ssh_string_free(target_s);
- return -1;
- }
- }
-
- if (sftp_packet_write(sftp, SSH_FXP_SYMLINK, buffer) < 0) {
- ssh_buffer_free(buffer);
- ssh_string_free(dest_s);
- ssh_string_free(target_s);
- return -1;
- }
- ssh_buffer_free(buffer);
- ssh_string_free(dest_s);
- ssh_string_free(target_s);
-
- while (msg == NULL) {
- if (sftp_read_and_dispatch(sftp) < 0) {
- return -1;
- }
- msg = sftp_dequeue(sftp, id);
- }
-
- /* By specification, this command only returns SSH_FXP_STATUS */
- if (msg->packet_type == SSH_FXP_STATUS) {
- status = parse_status_msg(msg);
- sftp_message_free(msg);
- if (status == NULL) {
- return -1;
- }
- sftp_set_error(sftp, status->status);
- switch (status->status) {
- case SSH_FX_OK:
- status_msg_free(status);
- return 0;
- default:
- break;
- }
- /*
- * The status should be SSH_FX_OK if the command was successful, if it
- * didn't, then there was an error
- */
- ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
- "SFTP server: %s", status->errormsg);
- status_msg_free(status);
- return -1;
- } else {
- ssh_set_error(sftp->session, SSH_FATAL,
- "Received message %d when attempting to set stats", msg->packet_type);
- sftp_message_free(msg);
- }
-
- return -1;
-}
-
-char *sftp_readlink(sftp_session sftp, const char *path) {
- sftp_status_message status = NULL;
- sftp_message msg = NULL;
- ssh_string path_s = NULL;
- ssh_string link_s = NULL;
- ssh_buffer buffer;
- char *lnk;
- uint32_t ignored;
- uint32_t id;
-
- if (sftp == NULL)
- return NULL;
- if (path == NULL) {
- ssh_set_error_invalid(sftp, __FUNCTION__);
- return NULL;
- }
- if (sftp->version < 3){
- ssh_set_error(sftp,SSH_REQUEST_DENIED,"sftp version %d does not support sftp_readlink",sftp->version);
- return NULL;
- }
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- ssh_set_error_oom(sftp->session);
- return NULL;
- }
-
- path_s = ssh_string_from_char(path);
- if (path_s == NULL) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- return NULL;
- }
-
- id = sftp_get_new_id(sftp);
- if (buffer_add_u32(buffer, id) < 0 ||
- buffer_add_ssh_string(buffer, path_s) < 0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- ssh_string_free(path_s);
- return NULL;
- }
- if (sftp_packet_write(sftp, SSH_FXP_READLINK, buffer) < 0) {
- ssh_buffer_free(buffer);
- ssh_string_free(path_s);
- return NULL;
- }
- ssh_buffer_free(buffer);
- ssh_string_free(path_s);
-
- while (msg == NULL) {
- if (sftp_read_and_dispatch(sftp) < 0) {
- return NULL;
- }
- msg = sftp_dequeue(sftp, id);
- }
-
- if (msg->packet_type == SSH_FXP_NAME) {
- /* we don't care about "count" */
- buffer_get_u32(msg->payload, &ignored);
- /* we only care about the file name string */
- link_s = buffer_get_ssh_string(msg->payload);
- sftp_message_free(msg);
- if (link_s == NULL) {
- /* TODO: what error to set here? */
- return NULL;
- }
- lnk = ssh_string_to_char(link_s);
- ssh_string_free(link_s);
-
- return lnk;
- } else if (msg->packet_type == SSH_FXP_STATUS) { /* bad response (error) */
- status = parse_status_msg(msg);
- sftp_message_free(msg);
- if (status == NULL) {
- return NULL;
- }
- ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
- "SFTP server: %s", status->errormsg);
- status_msg_free(status);
- } else { /* this shouldn't happen */
- ssh_set_error(sftp->session, SSH_FATAL,
- "Received message %d when attempting to set stats", msg->packet_type);
- sftp_message_free(msg);
- }
-
- return NULL;
-}
-
-static sftp_statvfs_t sftp_parse_statvfs(sftp_session sftp, ssh_buffer buf) {
- sftp_statvfs_t statvfs;
- uint64_t tmp;
- int ok = 0;
-
- statvfs = malloc(sizeof(struct sftp_statvfs_struct));
- if (statvfs == NULL) {
- ssh_set_error_oom(sftp->session);
- return NULL;
- }
- ZERO_STRUCTP(statvfs);
-
- /* try .. catch */
- do {
- /* file system block size */
- if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
- break;
- }
- statvfs->f_bsize = ntohll(tmp);
-
- /* fundamental fs block size */
- if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
- break;
- }
- statvfs->f_frsize = ntohll(tmp);
-
- /* number of blocks (unit f_frsize) */
- if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
- break;
- }
- statvfs->f_blocks = ntohll(tmp);
-
- /* free blocks in file system */
- if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
- break;
- }
- statvfs->f_bfree = ntohll(tmp);
-
- /* free blocks for non-root */
- if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
- break;
- }
- statvfs->f_bavail = ntohll(tmp);
-
- /* total file inodes */
- if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
- break;
- }
- statvfs->f_files = ntohll(tmp);
-
- /* free file inodes */
- if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
- break;
- }
- statvfs->f_ffree = ntohll(tmp);
-
- /* free file inodes for to non-root */
- if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
- break;
- }
- statvfs->f_favail = ntohll(tmp);
-
- /* file system id */
- if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
- break;
- }
- statvfs->f_fsid = ntohll(tmp);
-
- /* bit mask of f_flag values */
- if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
- break;
- }
- statvfs->f_flag = ntohll(tmp);
-
- /* maximum filename length */
- if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
- break;
- }
- statvfs->f_namemax = ntohll(tmp);
-
- ok = 1;
- } while(0);
-
- if (!ok) {
- SAFE_FREE(statvfs);
- ssh_set_error(sftp->session, SSH_FATAL, "Invalid statvfs structure");
- return NULL;
- }
-
- return statvfs;
-}
-
-sftp_statvfs_t sftp_statvfs(sftp_session sftp, const char *path) {
- sftp_status_message status = NULL;
- sftp_message msg = NULL;
- ssh_string pathstr;
- ssh_string ext;
- ssh_buffer buffer;
- uint32_t id;
-
- if (sftp == NULL)
- return NULL;
- if (path == NULL) {
- ssh_set_error_invalid(sftp->session, __FUNCTION__);
- return NULL;
- }
- if (sftp->version < 3){
- ssh_set_error(sftp,SSH_REQUEST_DENIED,"sftp version %d does not support sftp_statvfs",sftp->version);
- return NULL;
- }
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- ssh_set_error_oom(sftp->session);
- return NULL;
- }
-
- ext = ssh_string_from_char("statvfs@openssh.com");
- if (ext == NULL) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- return NULL;
- }
-
- pathstr = ssh_string_from_char(path);
- if (pathstr == NULL) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- ssh_string_free(ext);
- return NULL;
- }
-
- id = sftp_get_new_id(sftp);
- if (buffer_add_u32(buffer, id) < 0 ||
- buffer_add_ssh_string(buffer, ext) < 0 ||
- buffer_add_ssh_string(buffer, pathstr) < 0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- ssh_string_free(ext);
- ssh_string_free(pathstr);
- return NULL;
- }
- if (sftp_packet_write(sftp, SSH_FXP_EXTENDED, buffer) < 0) {
- ssh_buffer_free(buffer);
- ssh_string_free(ext);
- ssh_string_free(pathstr);
- return NULL;
- }
- ssh_buffer_free(buffer);
- ssh_string_free(ext);
- ssh_string_free(pathstr);
-
- while (msg == NULL) {
- if (sftp_read_and_dispatch(sftp) < 0) {
- return NULL;
- }
- msg = sftp_dequeue(sftp, id);
- }
-
- if (msg->packet_type == SSH_FXP_EXTENDED_REPLY) {
- sftp_statvfs_t buf = sftp_parse_statvfs(sftp, msg->payload);
- sftp_message_free(msg);
- if (buf == NULL) {
- return NULL;
- }
-
- return buf;
- } else if (msg->packet_type == SSH_FXP_STATUS) { /* bad response (error) */
- status = parse_status_msg(msg);
- sftp_message_free(msg);
- if (status == NULL) {
- return NULL;
- }
- ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
- "SFTP server: %s", status->errormsg);
- status_msg_free(status);
- } else { /* this shouldn't happen */
- ssh_set_error(sftp->session, SSH_FATAL,
- "Received message %d when attempting to get statvfs", msg->packet_type);
- sftp_message_free(msg);
- }
-
- return NULL;
-}
-
-sftp_statvfs_t sftp_fstatvfs(sftp_file file) {
- sftp_status_message status = NULL;
- sftp_message msg = NULL;
- sftp_session sftp;
- ssh_string ext;
- ssh_buffer buffer;
- uint32_t id;
-
- if (file == NULL) {
- return NULL;
- }
- sftp = file->sftp;
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- ssh_set_error_oom(sftp->session);
- return NULL;
- }
-
- ext = ssh_string_from_char("fstatvfs@openssh.com");
- if (ext == NULL) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- return NULL;
- }
-
- id = sftp_get_new_id(sftp);
- if (buffer_add_u32(buffer, id) < 0 ||
- buffer_add_ssh_string(buffer, ext) < 0 ||
- buffer_add_ssh_string(buffer, file->handle) < 0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- ssh_string_free(ext);
- return NULL;
- }
- if (sftp_packet_write(sftp, SSH_FXP_EXTENDED, buffer) < 0) {
- ssh_buffer_free(buffer);
- ssh_string_free(ext);
- return NULL;
- }
- ssh_buffer_free(buffer);
- ssh_string_free(ext);
-
- while (msg == NULL) {
- if (sftp_read_and_dispatch(sftp) < 0) {
- return NULL;
- }
- msg = sftp_dequeue(sftp, id);
- }
-
- if (msg->packet_type == SSH_FXP_EXTENDED_REPLY) {
- sftp_statvfs_t buf = sftp_parse_statvfs(sftp, msg->payload);
- sftp_message_free(msg);
- if (buf == NULL) {
- return NULL;
- }
-
- return buf;
- } else if (msg->packet_type == SSH_FXP_STATUS) { /* bad response (error) */
- status = parse_status_msg(msg);
- sftp_message_free(msg);
- if (status == NULL) {
- return NULL;
- }
- ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
- "SFTP server: %s", status->errormsg);
- status_msg_free(status);
- } else { /* this shouldn't happen */
- ssh_set_error(sftp->session, SSH_FATAL,
- "Received message %d when attempting to set stats", msg->packet_type);
- sftp_message_free(msg);
- }
-
- return NULL;
-}
-
-void sftp_statvfs_free(sftp_statvfs_t statvfs) {
- if (statvfs == NULL) {
- return;
- }
-
- SAFE_FREE(statvfs);
-}
-
-/* another code written by Nick */
-char *sftp_canonicalize_path(sftp_session sftp, const char *path) {
- sftp_status_message status = NULL;
- sftp_message msg = NULL;
- ssh_string name = NULL;
- ssh_string pathstr;
- ssh_buffer buffer;
- char *cname;
- uint32_t ignored;
- uint32_t id;
-
- if (sftp == NULL)
- return NULL;
- if (path == NULL) {
- ssh_set_error_invalid(sftp->session, __FUNCTION__);
- return NULL;
- }
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- ssh_set_error_oom(sftp->session);
- return NULL;
- }
-
- pathstr = ssh_string_from_char(path);
- if (pathstr == NULL) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- return NULL;
- }
-
- id = sftp_get_new_id(sftp);
- if (buffer_add_u32(buffer, id) < 0 ||
- buffer_add_ssh_string(buffer, pathstr) < 0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- ssh_string_free(pathstr);
- return NULL;
- }
- if (sftp_packet_write(sftp, SSH_FXP_REALPATH, buffer) < 0) {
- ssh_buffer_free(buffer);
- ssh_string_free(pathstr);
- return NULL;
- }
- ssh_buffer_free(buffer);
- ssh_string_free(pathstr);
-
- while (msg == NULL) {
- if (sftp_read_and_dispatch(sftp) < 0) {
- return NULL;
- }
- msg = sftp_dequeue(sftp, id);
- }
-
- if (msg->packet_type == SSH_FXP_NAME) {
- /* we don't care about "count" */
- buffer_get_u32(msg->payload, &ignored);
- /* we only care about the file name string */
- name = buffer_get_ssh_string(msg->payload);
- sftp_message_free(msg);
- if (name == NULL) {
- /* TODO: error message? */
- return NULL;
- }
- cname = ssh_string_to_char(name);
- ssh_string_free(name);
- if (cname == NULL) {
- ssh_set_error_oom(sftp->session);
- }
- return cname;
- } else if (msg->packet_type == SSH_FXP_STATUS) { /* bad response (error) */
- status = parse_status_msg(msg);
- sftp_message_free(msg);
- if (status == NULL) {
- return NULL;
- }
- ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
- "SFTP server: %s", status->errormsg);
- status_msg_free(status);
- } else { /* this shouldn't happen */
- ssh_set_error(sftp->session, SSH_FATAL,
- "Received message %d when attempting to set stats", msg->packet_type);
- sftp_message_free(msg);
- }
-
- return NULL;
-}
-
-static sftp_attributes sftp_xstat(sftp_session sftp, const char *path,
- int param) {
- sftp_status_message status = NULL;
- sftp_message msg = NULL;
- ssh_string pathstr;
- ssh_buffer buffer;
- uint32_t id;
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- ssh_set_error_oom(sftp->session);
- return NULL;
- }
-
- pathstr = ssh_string_from_char(path);
- if (pathstr == NULL) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- return NULL;
- }
-
- id = sftp_get_new_id(sftp);
- if (buffer_add_u32(buffer, id) < 0 ||
- buffer_add_ssh_string(buffer, pathstr) < 0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- ssh_string_free(pathstr);
- return NULL;
- }
- if (sftp_packet_write(sftp, param, buffer) < 0) {
- ssh_buffer_free(buffer);
- ssh_string_free(pathstr);
- return NULL;
- }
- ssh_buffer_free(buffer);
- ssh_string_free(pathstr);
-
- while (msg == NULL) {
- if (sftp_read_and_dispatch(sftp) < 0) {
- return NULL;
- }
- msg = sftp_dequeue(sftp, id);
- }
-
- if (msg->packet_type == SSH_FXP_ATTRS) {
- return sftp_parse_attr(sftp, msg->payload, 0);
- } else if (msg->packet_type == SSH_FXP_STATUS) {
- status = parse_status_msg(msg);
- sftp_message_free(msg);
- if (status == NULL) {
- return NULL;
- }
- sftp_set_error(sftp, status->status);
- ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
- "SFTP server: %s", status->errormsg);
- status_msg_free(status);
- return NULL;
- }
- ssh_set_error(sftp->session, SSH_FATAL,
- "Received mesg %d during stat()", msg->packet_type);
- sftp_message_free(msg);
-
- return NULL;
-}
-
-sftp_attributes sftp_stat(sftp_session session, const char *path) {
- return sftp_xstat(session, path, SSH_FXP_STAT);
-}
-
-sftp_attributes sftp_lstat(sftp_session session, const char *path) {
- return sftp_xstat(session, path, SSH_FXP_LSTAT);
-}
-
-sftp_attributes sftp_fstat(sftp_file file) {
- sftp_status_message status = NULL;
- sftp_message msg = NULL;
- ssh_buffer buffer;
- uint32_t id;
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- ssh_set_error_oom(file->sftp->session);
- return NULL;
- }
-
- id = sftp_get_new_id(file->sftp);
- if (buffer_add_u32(buffer, id) < 0 ||
- buffer_add_ssh_string(buffer, file->handle) < 0) {
- ssh_set_error_oom(file->sftp->session);
- ssh_buffer_free(buffer);
- return NULL;
- }
- if (sftp_packet_write(file->sftp, SSH_FXP_FSTAT, buffer) < 0) {
- ssh_buffer_free(buffer);
- return NULL;
- }
- ssh_buffer_free(buffer);
-
- while (msg == NULL) {
- if (sftp_read_and_dispatch(file->sftp) < 0) {
- return NULL;
- }
- msg = sftp_dequeue(file->sftp, id);
- }
-
- if (msg->packet_type == SSH_FXP_ATTRS){
- return sftp_parse_attr(file->sftp, msg->payload, 0);
- } else if (msg->packet_type == SSH_FXP_STATUS) {
- status = parse_status_msg(msg);
- sftp_message_free(msg);
- if (status == NULL) {
- return NULL;
- }
- ssh_set_error(file->sftp->session, SSH_REQUEST_DENIED,
- "SFTP server: %s", status->errormsg);
- status_msg_free(status);
-
- return NULL;
- }
- ssh_set_error(file->sftp->session, SSH_FATAL,
- "Received msg %d during fstat()", msg->packet_type);
- sftp_message_free(msg);
-
- return NULL;
-}
-
-#endif /* WITH_SFTP */
-/* vim: set ts=2 sw=2 et cindent: */
diff --git a/libssh/sftpserver.c b/libssh/sftpserver.c
deleted file mode 100644
index 77f64198..00000000
--- a/libssh/sftpserver.c
+++ /dev/null
@@ -1,490 +0,0 @@
-/*
- * sftpserver.c - server based function for the sftp protocol
- *
- * This file is part of the SSH Library
- *
- * Copyright (c) 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 <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-
-#ifndef _WIN32
-#include <arpa/inet.h>
-#endif
-
-#include "libssh/libssh.h"
-#include "libssh/sftp.h"
-#include "libssh/ssh2.h"
-#include "libssh/priv.h"
-#include "libssh/buffer.h"
-#include "libssh/misc.h"
-
-sftp_client_message sftp_get_client_message(sftp_session sftp) {
- sftp_packet packet;
- sftp_client_message msg;
- ssh_buffer payload;
- ssh_string tmp;
-
- msg = malloc(sizeof (struct sftp_client_message_struct));
- if (msg == NULL) {
- return NULL;
- }
- ZERO_STRUCTP(msg);
-
- packet = sftp_packet_read(sftp);
- if (packet == NULL) {
- sftp_client_message_free(msg);
- return NULL;
- }
-
- payload = packet->payload;
- msg->type = packet->type;
- msg->sftp = sftp;
-
- buffer_get_u32(payload, &msg->id);
-
- switch(msg->type) {
- case SSH_FXP_CLOSE:
- case SSH_FXP_READDIR:
- msg->handle = buffer_get_ssh_string(payload);
- if (msg->handle == NULL) {
- sftp_client_message_free(msg);
- return NULL;
- }
- break;
- case SSH_FXP_READ:
- msg->handle = buffer_get_ssh_string(payload);
- if (msg->handle == NULL) {
- sftp_client_message_free(msg);
- return NULL;
- }
- buffer_get_u64(payload, &msg->offset);
- buffer_get_u32(payload, &msg->len);
- break;
- case SSH_FXP_WRITE:
- msg->handle = buffer_get_ssh_string(payload);
- if (msg->handle == NULL) {
- sftp_client_message_free(msg);
- return NULL;
- }
- buffer_get_u64(payload, &msg->offset);
- msg->data = buffer_get_ssh_string(payload);
- if (msg->data == NULL) {
- sftp_client_message_free(msg);
- return NULL;
- }
- break;
- case SSH_FXP_REMOVE:
- case SSH_FXP_RMDIR:
- case SSH_FXP_OPENDIR:
- case SSH_FXP_READLINK:
- case SSH_FXP_REALPATH:
- tmp = buffer_get_ssh_string(payload);
- if (tmp == NULL) {
- sftp_client_message_free(msg);
- return NULL;
- }
- msg->filename = ssh_string_to_char(tmp);
- ssh_string_free(tmp);
- if (msg->filename == NULL) {
- sftp_client_message_free(msg);
- return NULL;
- }
- break;
- case SSH_FXP_RENAME:
- case SSH_FXP_SYMLINK:
- tmp = buffer_get_ssh_string(payload);
- if (tmp == NULL) {
- sftp_client_message_free(msg);
- return NULL;
- }
- msg->filename = ssh_string_to_char(tmp);
- ssh_string_free(tmp);
- if (msg->filename == NULL) {
- sftp_client_message_free(msg);
- return NULL;
- }
- msg->data = buffer_get_ssh_string(payload);
- if (msg->data == NULL) {
- sftp_client_message_free(msg);
- return NULL;
- }
- break;
- case SSH_FXP_MKDIR:
- case SSH_FXP_SETSTAT:
- tmp = buffer_get_ssh_string(payload);
- if (tmp == NULL) {
- sftp_client_message_free(msg);
- return NULL;
- }
- msg->filename=ssh_string_to_char(tmp);
- ssh_string_free(tmp);
- if (msg->filename == NULL) {
- sftp_client_message_free(msg);
- return NULL;
- }
- msg->attr = sftp_parse_attr(sftp, payload, 0);
- if (msg->attr == NULL) {
- sftp_client_message_free(msg);
- return NULL;
- }
- break;
- case SSH_FXP_FSETSTAT:
- msg->handle = buffer_get_ssh_string(payload);
- if (msg->handle == NULL) {
- sftp_client_message_free(msg);
- return NULL;
- }
- msg->attr = sftp_parse_attr(sftp, payload, 0);
- if (msg->attr == NULL) {
- sftp_client_message_free(msg);
- return NULL;
- }
- break;
- case SSH_FXP_LSTAT:
- case SSH_FXP_STAT:
- tmp = buffer_get_ssh_string(payload);
- if (tmp == NULL) {
- sftp_client_message_free(msg);
- return NULL;
- }
- msg->filename = ssh_string_to_char(tmp);
- ssh_string_free(tmp);
- if (msg->filename == NULL) {
- sftp_client_message_free(msg);
- return NULL;
- }
- if(sftp->version > 3) {
- buffer_get_u32(payload,&msg->flags);
- }
- break;
- case SSH_FXP_OPEN:
- tmp=buffer_get_ssh_string(payload);
- if (tmp == NULL) {
- sftp_client_message_free(msg);
- return NULL;
- }
- msg->filename = ssh_string_to_char(tmp);
- ssh_string_free(tmp);
- if (msg->filename == NULL) {
- sftp_client_message_free(msg);
- return NULL;
- }
- buffer_get_u32(payload,&msg->flags);
- msg->attr = sftp_parse_attr(sftp, payload, 0);
- if (msg->attr == NULL) {
- sftp_client_message_free(msg);
- return NULL;
- }
- case SSH_FXP_FSTAT:
- msg->handle = buffer_get_ssh_string(payload);
- if (msg->handle == NULL) {
- sftp_client_message_free(msg);
- return NULL;
- }
- buffer_get_u32(payload, &msg->flags);
- break;
- default:
- fprintf(stderr, "Received unhandled sftp message %d\n", msg->type);
- }
-
- msg->flags = ntohl(msg->flags);
- msg->offset = ntohll(msg->offset);
- msg->len = ntohl(msg->len);
- sftp_packet_free(packet);
-
- return msg;
-}
-
-void sftp_client_message_free(sftp_client_message msg) {
- if (msg == NULL) {
- return;
- }
-
- SAFE_FREE(msg->filename);
- ssh_string_free(msg->data);
- ssh_string_free(msg->handle);
- sftp_attributes_free(msg->attr);
-
- ZERO_STRUCTP(msg);
- SAFE_FREE(msg);
-}
-
-int sftp_reply_name(sftp_client_message msg, const char *name,
- sftp_attributes attr) {
- ssh_buffer out;
- ssh_string file;
-
- out = ssh_buffer_new();
- if (out == NULL) {
- return -1;
- }
-
- file = ssh_string_from_char(name);
- if (file == NULL) {
- ssh_buffer_free(out);
- return -1;
- }
-
- if (buffer_add_u32(out, msg->id) < 0 ||
- buffer_add_u32(out, htonl(1)) < 0 ||
- buffer_add_ssh_string(out, file) < 0 ||
- buffer_add_ssh_string(out, file) < 0 || /* The protocol is broken here between 3 & 4 */
- buffer_add_attributes(out, attr) < 0 ||
- sftp_packet_write(msg->sftp, SSH_FXP_NAME, out) < 0) {
- ssh_buffer_free(out);
- ssh_string_free(file);
- return -1;
- }
- ssh_buffer_free(out);
- ssh_string_free(file);
-
- return 0;
-}
-
-int sftp_reply_handle(sftp_client_message msg, ssh_string handle){
- ssh_buffer out;
-
- out = ssh_buffer_new();
- if (out == NULL) {
- return -1;
- }
-
- if (buffer_add_u32(out, msg->id) < 0 ||
- buffer_add_ssh_string(out, handle) < 0 ||
- sftp_packet_write(msg->sftp, SSH_FXP_HANDLE, out) < 0) {
- ssh_buffer_free(out);
- return -1;
- }
- ssh_buffer_free(out);
-
- return 0;
-}
-
-int sftp_reply_attr(sftp_client_message msg, sftp_attributes attr) {
- ssh_buffer out;
-
- out = ssh_buffer_new();
- if (out == NULL) {
- return -1;
- }
-
- if (buffer_add_u32(out, msg->id) < 0 ||
- buffer_add_attributes(out, attr) < 0 ||
- sftp_packet_write(msg->sftp, SSH_FXP_ATTRS, out) < 0) {
- ssh_buffer_free(out);
- return -1;
- }
- ssh_buffer_free(out);
-
- return 0;
-}
-
-int sftp_reply_names_add(sftp_client_message msg, const char *file,
- const char *longname, sftp_attributes attr) {
- ssh_string name;
-
- name = ssh_string_from_char(file);
- if (name == NULL) {
- return -1;
- }
-
- if (msg->attrbuf == NULL) {
- msg->attrbuf = ssh_buffer_new();
- if (msg->attrbuf == NULL) {
- ssh_string_free(name);
- return -1;
- }
- }
-
- if (buffer_add_ssh_string(msg->attrbuf, name) < 0) {
- ssh_string_free(name);
- return -1;
- }
-
- ssh_string_free(name);
- name = ssh_string_from_char(longname);
- if (name == NULL) {
- return -1;
- }
- if (buffer_add_ssh_string(msg->attrbuf,name) < 0 ||
- buffer_add_attributes(msg->attrbuf,attr) < 0) {
- ssh_string_free(name);
- return -1;
- }
- ssh_string_free(name);
- msg->attr_num++;
-
- return 0;
-}
-
-int sftp_reply_names(sftp_client_message msg) {
- ssh_buffer out;
-
- out = ssh_buffer_new();
- if (out == NULL) {
- ssh_buffer_free(msg->attrbuf);
- return -1;
- }
-
- if (buffer_add_u32(out, msg->id) < 0 ||
- buffer_add_u32(out, htonl(msg->attr_num)) < 0 ||
- buffer_add_data(out, ssh_buffer_get_begin(msg->attrbuf),
- ssh_buffer_get_len(msg->attrbuf)) < 0 ||
- sftp_packet_write(msg->sftp, SSH_FXP_NAME, out) < 0) {
- ssh_buffer_free(out);
- ssh_buffer_free(msg->attrbuf);
- return -1;
- }
-
- ssh_buffer_free(out);
- ssh_buffer_free(msg->attrbuf);
-
- msg->attr_num = 0;
- msg->attrbuf = NULL;
-
- return 0;
-}
-
-int sftp_reply_status(sftp_client_message msg, uint32_t status,
- const char *message) {
- ssh_buffer out;
- ssh_string s;
-
- out = ssh_buffer_new();
- if (out == NULL) {
- return -1;
- }
-
- s = ssh_string_from_char(message ? message : "");
- if (s == NULL) {
- ssh_buffer_free(out);
- return -1;
- }
-
- if (buffer_add_u32(out, msg->id) < 0 ||
- buffer_add_u32(out, htonl(status)) < 0 ||
- buffer_add_ssh_string(out, s) < 0 ||
- buffer_add_u32(out, 0) < 0 || /* language string */
- sftp_packet_write(msg->sftp, SSH_FXP_STATUS, out) < 0) {
- ssh_buffer_free(out);
- ssh_string_free(s);
- return -1;
- }
-
- ssh_buffer_free(out);
- ssh_string_free(s);
-
- return 0;
-}
-
-int sftp_reply_data(sftp_client_message msg, const void *data, int len) {
- ssh_buffer out;
-
- out = ssh_buffer_new();
- if (out == NULL) {
- return -1;
- }
-
- if (buffer_add_u32(out, msg->id) < 0 ||
- buffer_add_u32(out, ntohl(len)) < 0 ||
- buffer_add_data(out, data, len) < 0 ||
- sftp_packet_write(msg->sftp, SSH_FXP_DATA, out) < 0) {
- ssh_buffer_free(out);
- return -1;
- }
- ssh_buffer_free(out);
-
- return 0;
-}
-
-/*
- * This function will return you a new handle to give the client.
- * the function accepts an info that can be retrieved later with
- * the handle. Care is given that a corrupted handle won't give a
- * valid info (or worse).
- */
-ssh_string sftp_handle_alloc(sftp_session sftp, void *info) {
- ssh_string ret;
- uint32_t val;
- int i;
-
- if (sftp->handles == NULL) {
- sftp->handles = malloc(sizeof(void *) * SFTP_HANDLES);
- if (sftp->handles == NULL) {
- return NULL;
- }
- memset(sftp->handles, 0, sizeof(void *) * SFTP_HANDLES);
- }
-
- for (i = 0; i < SFTP_HANDLES; i++) {
- if (sftp->handles[i] == NULL) {
- break;
- }
- }
-
- if (i == SFTP_HANDLES) {
- return NULL; /* no handle available */
- }
-
- val = i;
- ret = ssh_string_new(4);
- if (ret == NULL) {
- return NULL;
- }
-
- memcpy(ssh_string_data(ret), &val, sizeof(uint32_t));
- sftp->handles[i] = info;
-
- return ret;
-}
-
-void *sftp_handle(sftp_session sftp, ssh_string handle){
- uint32_t val;
-
- if (sftp->handles == NULL) {
- return NULL;
- }
-
- if (ssh_string_len(handle) != sizeof(uint32_t)) {
- return NULL;
- }
-
- memcpy(&val, ssh_string_data(handle), sizeof(uint32_t));
-
- if (val > SFTP_HANDLES) {
- return NULL;
- }
-
- return sftp->handles[val];
-}
-
-void sftp_handle_remove(sftp_session sftp, void *handle) {
- int i;
-
- for (i = 0; i < SFTP_HANDLES; i++) {
- if (sftp->handles[i] == handle) {
- sftp->handles[i] = NULL;
- break;
- }
- }
-}
-
-/* vim: set ts=2 sw=2 et cindent: */
diff --git a/libssh/socket.c b/libssh/socket.c
deleted file mode 100644
index 2f1f5534..00000000
--- a/libssh/socket.c
+++ /dev/null
@@ -1,719 +0,0 @@
-/*
- * socket.c - socket functions for the library
- *
- * This file is part of the SSH Library
- *
- * Copyright (c) 2008-2010 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 <errno.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#ifdef _WIN32
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#if _MSC_VER >= 1400
-#include <io.h>
-#undef open
-#define open _open
-#undef close
-#define close _close
-#undef read
-#define read _read
-#undef write
-#define write _write
-#endif /* _MSC_VER */
-#else /* _WIN32 */
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#endif /* _WIN32 */
-
-#include "libssh/priv.h"
-#include "libssh/callbacks.h"
-#include "libssh/socket.h"
-#include "libssh/buffer.h"
-#include "libssh/poll.h"
-#include "libssh/session.h"
-
-#ifndef _WIN32
-extern char **environ;
-#endif
-/**
- * @internal
- *
- * @defgroup libssh_socket The SSH socket functions.
- * @ingroup libssh
- *
- * Functions for handling sockets.
- *
- * @{
- */
-
-enum ssh_socket_states_e {
- SSH_SOCKET_NONE,
- SSH_SOCKET_CONNECTING,
- SSH_SOCKET_CONNECTED,
- SSH_SOCKET_EOF,
- SSH_SOCKET_ERROR,
- SSH_SOCKET_CLOSED
-};
-
-struct ssh_socket_struct {
- socket_t fd_in;
- socket_t fd_out;
- int fd_is_socket;
- int last_errno;
- int data_to_read; /* reading now on socket will
- not block */
- int data_to_write;
- int data_except;
- enum ssh_socket_states_e state;
- ssh_buffer out_buffer;
- ssh_buffer in_buffer;
- ssh_session session;
- ssh_socket_callbacks callbacks;
- ssh_poll_handle poll_in;
- ssh_poll_handle poll_out;
-};
-
-static int ssh_socket_unbuffered_read(ssh_socket s, void *buffer, uint32_t len);
-static int ssh_socket_unbuffered_write(ssh_socket s, const void *buffer,
- uint32_t len);
-
-/**
- * \internal
- * \brief inits the socket system (windows specific)
- */
-int ssh_socket_init(void) {
-#ifdef _WIN32
- struct WSAData wsaData;
-
- /* Initiates use of the Winsock DLL by a process. */
- if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) {
- return -1;
- }
-
-#endif
- ssh_poll_init();
-
- return 0;
-}
-
-/**
- * @brief Cleanup the socket system.
- */
-void ssh_socket_cleanup(void) {
- ssh_poll_cleanup();
-}
-
-
-/**
- * \internal
- * \brief creates a new Socket object
- */
-ssh_socket ssh_socket_new(ssh_session session) {
- ssh_socket s;
-
- s = malloc(sizeof(struct ssh_socket_struct));
- if (s == NULL) {
- return NULL;
- }
- s->fd_in = SSH_INVALID_SOCKET;
- s->fd_out= SSH_INVALID_SOCKET;
- s->last_errno = -1;
- s->fd_is_socket = 1;
- s->session = session;
- s->in_buffer = ssh_buffer_new();
- if (s->in_buffer == NULL) {
- SAFE_FREE(s);
- return NULL;
- }
- s->out_buffer=ssh_buffer_new();
- if (s->out_buffer == NULL) {
- ssh_buffer_free(s->in_buffer);
- SAFE_FREE(s);
- return NULL;
- }
- s->data_to_read = 0;
- s->data_to_write = 0;
- s->data_except = 0;
- s->poll_in=s->poll_out=NULL;
- s->state=SSH_SOCKET_NONE;
- return s;
-}
-
-/**
- * @internal
- * @brief the socket callbacks, i.e. callbacks to be called
- * upon a socket event.
- * @param s socket to set callbacks on.
- * @param callbacks a ssh_socket_callback object reference.
- */
-
-void ssh_socket_set_callbacks(ssh_socket s, ssh_socket_callbacks callbacks){
- s->callbacks=callbacks;
-}
-
-int ssh_socket_pollcallback(struct ssh_poll_handle_struct *p, socket_t fd, int revents, void *v_s){
- ssh_socket s=(ssh_socket )v_s;
- char buffer[4096];
- int r,w;
- int err=0;
- socklen_t errlen=sizeof(err);
- /* Do not do anything if this socket was already closed */
- if(!ssh_socket_is_open(s)){
- return -1;
- }
- if(revents & POLLERR){
- /* Check if we are in a connecting state */
- if(s->state==SSH_SOCKET_CONNECTING){
- s->state=SSH_SOCKET_ERROR;
- getsockopt(fd,SOL_SOCKET,SO_ERROR,(void *)&err,&errlen);
- s->last_errno=err;
- ssh_socket_close(s);
- if(s->callbacks && s->callbacks->connected)
- s->callbacks->connected(SSH_SOCKET_CONNECTED_ERROR,err,
- s->callbacks->userdata);
- return -1;
- }
- /* Then we are in a more standard kind of error */
- /* force a read to get an explanation */
- revents |= POLLIN;
- }
- if(revents & POLLIN){
- s->data_to_read=1;
- r=ssh_socket_unbuffered_read(s,buffer,sizeof(buffer));
- if(r<0){
- err=-1;
- if(p != NULL)
- ssh_poll_set_events(p,ssh_poll_get_events(p) & ~POLLIN);
- if(s->callbacks && s->callbacks->exception){
- s->callbacks->exception(
- SSH_SOCKET_EXCEPTION_ERROR,
- s->last_errno,s->callbacks->userdata);
- }
- }
- if(r==0){
- ssh_poll_set_events(p,ssh_poll_get_events(p) & ~POLLIN);
- if(s->callbacks && s->callbacks->exception){
- s->callbacks->exception(
- SSH_SOCKET_EXCEPTION_EOF,
- 0,s->callbacks->userdata);
- }
- }
- if(r>0){
- /* Bufferize the data and then call the callback */
- buffer_add_data(s->in_buffer,buffer,r);
- if(s->callbacks && s->callbacks->data){
- r= s->callbacks->data(buffer_get_rest(s->in_buffer),
- buffer_get_rest_len(s->in_buffer),
- s->callbacks->userdata);
- buffer_pass_bytes(s->in_buffer,r);
- }
- }
- }
-#ifdef _WIN32
- if(revents & POLLOUT || revents & POLLWRNORM){
-#else
- if(revents & POLLOUT){
-#endif
- /* First, POLLOUT is a sign we may be connected */
- if(s->state == SSH_SOCKET_CONNECTING){
- ssh_log(s->session,SSH_LOG_PACKET,"Received POLLOUT in connecting state");
- s->state = SSH_SOCKET_CONNECTED;
- ssh_poll_set_events(p,POLLOUT | POLLIN | POLLERR);
- ssh_sock_set_blocking(ssh_socket_get_fd_in(s));
- if(s->callbacks && s->callbacks->connected)
- s->callbacks->connected(SSH_SOCKET_CONNECTED_OK,0,s->callbacks->userdata);
- return 0;
- }
- /* So, we can write data */
- s->data_to_write=1;
- /* If buffered data is pending, write it */
- if(buffer_get_rest_len(s->out_buffer) > 0){
- w=ssh_socket_unbuffered_write(s, buffer_get_rest(s->out_buffer),
- buffer_get_rest_len(s->out_buffer));
- if(w>0)
- buffer_pass_bytes(s->out_buffer,w);
- } else if(s->callbacks && s->callbacks->controlflow){
- /* Otherwise advertise the upper level that write can be done */
- s->callbacks->controlflow(SSH_SOCKET_FLOW_WRITEWONTBLOCK,s->callbacks->userdata);
- }
- ssh_poll_remove_events(p,POLLOUT);
- /* TODO: Find a way to put back POLLOUT when buffering occurs */
- }
- return err;
-}
-
-/** @internal
- * @brief returns the input poll handle corresponding to the socket,
- * creates it if it does not exist.
- * @returns allocated and initialized ssh_poll_handle object
- */
-ssh_poll_handle ssh_socket_get_poll_handle_in(ssh_socket s){
- if(s->poll_in)
- return s->poll_in;
- s->poll_in=ssh_poll_new(s->fd_in,0,ssh_socket_pollcallback,s);
- if(s->fd_in == s->fd_out && s->poll_out == NULL)
- s->poll_out=s->poll_in;
- return s->poll_in;
-}
-
-/** @internal
- * @brief returns the output poll handle corresponding to the socket,
- * creates it if it does not exist.
- * @returns allocated and initialized ssh_poll_handle object
- */
-ssh_poll_handle ssh_socket_get_poll_handle_out(ssh_socket s){
- if(s->poll_out)
- return s->poll_out;
- s->poll_out=ssh_poll_new(s->fd_out,0,ssh_socket_pollcallback,s);
- if(s->fd_in == s->fd_out && s->poll_in == NULL)
- s->poll_in=s->poll_out;
- return s->poll_out;
-}
-
-/** \internal
- * \brief Deletes a socket object
- */
-void ssh_socket_free(ssh_socket s){
- if (s == NULL) {
- return;
- }
- ssh_socket_close(s);
- ssh_buffer_free(s->in_buffer);
- ssh_buffer_free(s->out_buffer);
- SAFE_FREE(s);
-}
-
-#ifndef _WIN32
-int ssh_socket_unix(ssh_socket s, const char *path) {
- struct sockaddr_un sunaddr;
- socket_t fd;
- sunaddr.sun_family = AF_UNIX;
- snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path), "%s", path);
-
- fd = socket(AF_UNIX, SOCK_STREAM, 0);
- if (fd == SSH_INVALID_SOCKET) {
- return -1;
- }
-
- if (fcntl(fd, F_SETFD, 1) == -1) {
- close(fd);
- return -1;
- }
-
- if (connect(fd, (struct sockaddr *) &sunaddr,
- sizeof(sunaddr)) < 0) {
- close(fd);
- return -1;
- }
- ssh_socket_set_fd(s,fd);
- return 0;
-}
-#endif
-
-/** \internal
- * \brief closes a socket
- */
-void ssh_socket_close(ssh_socket s){
- if (ssh_socket_is_open(s)) {
-#ifdef _WIN32
- closesocket(s->fd_in);
- /* fd_in = fd_out under win32 */
- s->last_errno = WSAGetLastError();
-#else
- close(s->fd_in);
- if(s->fd_out != s->fd_in && s->fd_out != -1)
- close(s->fd_out);
- s->last_errno = errno;
-#endif
- s->fd_in = s->fd_out = SSH_INVALID_SOCKET;
- }
- if(s->poll_in != NULL){
- if(s->poll_out == s->poll_in)
- s->poll_out = NULL;
- ssh_poll_free(s->poll_in);
- s->poll_in=NULL;
- }
- if(s->poll_out != NULL){
- ssh_poll_free(s->poll_out);
- s->poll_out=NULL;
- }
-}
-
-/**
- * @internal
- * @brief sets the file descriptor of the socket.
- * @param[out] s ssh_socket to update
- * @param[in] fd file descriptor to set
- * @warning this function updates boths the input and output
- * file descriptors
- */
-void ssh_socket_set_fd(ssh_socket s, socket_t fd) {
- s->fd_in = s->fd_out = fd;
- if(s->poll_in)
- ssh_poll_set_fd(s->poll_in,fd);
-}
-
-/**
- * @internal
- * @brief sets the input file descriptor of the socket.
- * @param[out] s ssh_socket to update
- * @param[in] fd file descriptor to set
- */
-void ssh_socket_set_fd_in(ssh_socket s, socket_t fd) {
- s->fd_in = fd;
- if(s->poll_in)
- ssh_poll_set_fd(s->poll_in,fd);
-}
-
-/**
- * @internal
- * @brief sets the output file descriptor of the socket.
- * @param[out] s ssh_socket to update
- * @param[in] fd file descriptor to set
- */
-void ssh_socket_set_fd_out(ssh_socket s, socket_t fd) {
- s->fd_out = fd;
- if(s->poll_out)
- ssh_poll_set_fd(s->poll_out,fd);
-}
-
-
-
-/** \internal
- * \brief returns the input file descriptor of the socket
- */
-socket_t ssh_socket_get_fd_in(ssh_socket s) {
- return s->fd_in;
-}
-
-/** \internal
- * \brief returns nonzero if the socket is open
- */
-int ssh_socket_is_open(ssh_socket s) {
- return s->fd_in != SSH_INVALID_SOCKET;
-}
-
-/** \internal
- * \brief read len bytes from socket into buffer
- */
-static int ssh_socket_unbuffered_read(ssh_socket s, void *buffer, uint32_t len) {
- int rc = -1;
-
- if (s->data_except) {
- return -1;
- }
- if(s->fd_is_socket)
- rc = recv(s->fd_in,buffer, len, 0);
- else
- rc = read(s->fd_in,buffer, len);
-#ifdef _WIN32
- s->last_errno = WSAGetLastError();
-#else
- s->last_errno = errno;
-#endif
- s->data_to_read = 0;
-
- if (rc < 0) {
- s->data_except = 1;
- }
-
- return rc;
-}
-
-/** \internal
- * \brief writes len bytes from buffer to socket
- */
-static int ssh_socket_unbuffered_write(ssh_socket s, const void *buffer,
- uint32_t len) {
- int w = -1;
-
- if (s->data_except) {
- return -1;
- }
- if (s->fd_is_socket)
- w = send(s->fd_out,buffer, len, 0);
- else
- w = write(s->fd_out, buffer, len);
-#ifdef _WIN32
- s->last_errno = WSAGetLastError();
-#else
- s->last_errno = errno;
-#endif
- s->data_to_write = 0;
- /* Reactive the POLLOUT detector in the poll multiplexer system */
- if(s->poll_out){
- ssh_log(s->session, SSH_LOG_PACKET, "Enabling POLLOUT for socket");
- ssh_poll_set_events(s->poll_out,ssh_poll_get_events(s->poll_out) | POLLOUT);
- }
- if (w < 0) {
- s->data_except = 1;
- }
-
- return w;
-}
-
-/** \internal
- * \brief returns nonzero if the current socket is in the fd_set
- */
-int ssh_socket_fd_isset(ssh_socket s, fd_set *set) {
- if(s->fd_in == SSH_INVALID_SOCKET) {
- return 0;
- }
- return FD_ISSET(s->fd_in,set) || FD_ISSET(s->fd_out,set);
-}
-
-/** \internal
- * \brief sets the current fd in a fd_set and updates the max_fd
- */
-
-void ssh_socket_fd_set(ssh_socket s, fd_set *set, socket_t *max_fd) {
- if (s->fd_in == SSH_INVALID_SOCKET) {
- return;
- }
-
- FD_SET(s->fd_in,set);
- FD_SET(s->fd_out,set);
-
- if (s->fd_in >= 0 && s->fd_in != SSH_INVALID_SOCKET) {
- *max_fd = s->fd_in + 1;
- }
- if (s->fd_out >= 0 && s->fd_in != SSH_INVALID_SOCKET) {
- *max_fd = s->fd_out + 1;
- }
-}
-
-/** \internal
- * \brief buffered write of data
- * \returns SSH_OK, or SSH_ERROR
- * \warning has no effect on socket before a flush
- */
-int ssh_socket_write(ssh_socket s, const void *buffer, int len) {
- ssh_session session = s->session;
- enter_function();
- if(len > 0) {
- if (buffer_add_data(s->out_buffer, buffer, len) < 0) {
- return SSH_ERROR;
- }
- ssh_socket_set_towrite(s);
- }
- leave_function();
- return SSH_OK;
-}
-
-
-/** \internal
- * \brief starts a nonblocking flush of the output buffer
- *
- */
-int ssh_socket_nonblocking_flush(ssh_socket s) {
- ssh_session session = s->session;
- int w;
-
- enter_function();
-
- if (!ssh_socket_is_open(s)) {
- session->alive = 0;
- /* FIXME use ssh_socket_get_errno */
- ssh_set_error(session, SSH_FATAL,
- "Writing packet: error on socket (or connection closed): %s",
- strerror(s->last_errno));
-
- leave_function();
- return SSH_ERROR;
- }
-
- if (s->data_to_write && buffer_get_rest_len(s->out_buffer) > 0) {
- w = ssh_socket_unbuffered_write(s, buffer_get_rest(s->out_buffer),
- buffer_get_rest_len(s->out_buffer));
- if (w < 0) {
- session->alive = 0;
- ssh_socket_close(s);
- /* FIXME use ssh_socket_get_errno() */
- /* FIXME use callback for errors */
- ssh_set_error(session, SSH_FATAL,
- "Writing packet: error on socket (or connection closed): %s",
- strerror(s->last_errno));
- leave_function();
- return SSH_ERROR;
- }
- buffer_pass_bytes(s->out_buffer, w);
- }
-
- /* Is there some data pending? */
- if (buffer_get_rest_len(s->out_buffer) > 0 && s->poll_out) {
- /* force the poll system to catch pollout events */
- ssh_poll_set_events(s->poll_out, ssh_poll_get_events(s->poll_out) |POLLOUT);
- leave_function();
- return SSH_AGAIN;
- }
-
- /* all data written */
- leave_function();
- return SSH_OK;
-}
-
-void ssh_socket_set_towrite(ssh_socket s) {
- s->data_to_write = 1;
-}
-
-void ssh_socket_set_toread(ssh_socket s) {
- s->data_to_read = 1;
-}
-
-void ssh_socket_set_except(ssh_socket s) {
- s->data_except = 1;
-}
-
-int ssh_socket_data_available(ssh_socket s) {
- return s->data_to_read;
-}
-
-int ssh_socket_data_writable(ssh_socket s) {
- return s->data_to_write;
-}
-
-int ssh_socket_get_status(ssh_socket s) {
- int r = 0;
-
- if (s->data_to_read) {
- r |= SSH_READ_PENDING;
- }
-
- if (s->data_except) {
- r |= SSH_CLOSED_ERROR;
- }
-
- return r;
-}
-
-/**
- * @internal
- * @brief Launches a socket connection
- * If a the socket connected callback has been defined and
- * a poll object exists, this call will be non blocking.
- * @param s socket to connect.
- * @param host hostname or ip address to connect to.
- * @param port port number to connect to.
- * @param bind_addr address to bind to, or NULL for default.
- * @returns SSH_OK socket is being connected.
- * @returns SSH_ERROR error while connecting to remote host.
- * @bug It only tries connecting to one of the available AI's
- * which is problematic for hosts having DNS fail-over.
- */
-
-int ssh_socket_connect(ssh_socket s, const char *host, int port, const char *bind_addr){
- socket_t fd;
- ssh_session session=s->session;
- enter_function();
- if(s->state != SSH_SOCKET_NONE)
- return SSH_ERROR;
- fd=ssh_connect_host_nonblocking(s->session,host,bind_addr,port);
- ssh_log(session,SSH_LOG_PROTOCOL,"Nonblocking connection socket: %d",fd);
- if(fd == SSH_INVALID_SOCKET)
- return SSH_ERROR;
- ssh_socket_set_fd(s,fd);
- s->state=SSH_SOCKET_CONNECTING;
- /* POLLOUT is the event to wait for in a nonblocking connect */
- ssh_poll_set_events(ssh_socket_get_poll_handle_in(s),POLLOUT);
-#ifdef _WIN32
- ssh_poll_add_events(ssh_socket_get_poll_handle_in(s),POLLWRNORM);
-#endif
- leave_function();
- return SSH_OK;
-}
-
-#ifndef _WIN32
-/**
- * @internal
- * @brief executes a command and redirect input and outputs
- * @param command command to execute
- * @param in input file descriptor
- * @param out output file descriptor
- */
-void ssh_execute_command(const char *command, socket_t in, socket_t out){
- const char *args[]={"/bin/sh","-c",command,NULL};
- /* redirect in and out to stdin, stdout and stderr */
- dup2(in, 0);
- dup2(out,1);
- dup2(out,2);
- close(in);
- close(out);
- execve(args[0],(char * const *)args,(char * const *)environ);
- exit(1);
-}
-
-/**
- * @internal
- * @brief Open a socket on a ProxyCommand
- * This call will always be nonblocking.
- * @param s socket to connect.
- * @param command Command to execute.
- * @returns SSH_OK socket is being connected.
- * @returns SSH_ERROR error while executing the command.
- */
-
-int ssh_socket_connect_proxycommand(ssh_socket s, const char *command){
- socket_t in_pipe[2];
- socket_t out_pipe[2];
- int pid;
- int rc;
- ssh_session session=s->session;
- enter_function();
- if(s->state != SSH_SOCKET_NONE)
- return SSH_ERROR;
-
- rc = pipe(in_pipe);
- if (rc < 0) {
- return SSH_ERROR;
- }
- rc = pipe(out_pipe);
- if (rc < 0) {
- return SSH_ERROR;
- }
-
- ssh_log(session,SSH_LOG_PROTOCOL,"Executing proxycommand '%s'",command);
- pid = fork();
- if(pid == 0){
- ssh_execute_command(command,out_pipe[0],in_pipe[1]);
- }
- close(in_pipe[1]);
- close(out_pipe[0]);
- ssh_log(session,SSH_LOG_PROTOCOL,"ProxyCommand connection pipe: [%d,%d]",in_pipe[0],out_pipe[1]);
- ssh_socket_set_fd_in(s,in_pipe[0]);
- ssh_socket_set_fd_out(s,out_pipe[1]);
- s->state=SSH_SOCKET_CONNECTED;
- s->fd_is_socket=0;
- /* POLLOUT is the event to wait for in a nonblocking connect */
- ssh_poll_set_events(ssh_socket_get_poll_handle_in(s),POLLIN | POLLERR);
- ssh_poll_set_events(ssh_socket_get_poll_handle_out(s),POLLOUT);
- if(s->callbacks && s->callbacks->connected)
- s->callbacks->connected(SSH_SOCKET_CONNECTED_OK,0,s->callbacks->userdata);
- leave_function();
- return SSH_OK;
-}
-
-#endif /* _WIN32 */
-/** @} */
-
-/* vim: set ts=4 sw=4 et cindent: */
diff --git a/libssh/string.c b/libssh/string.c
deleted file mode 100644
index 06042aea..00000000
--- a/libssh/string.c
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * string.c - ssh string 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 <stdlib.h>
-#include <string.h>
-
-#ifndef _WIN32
-#include <arpa/inet.h>
-#endif
-
-#include "libssh/priv.h"
-#include "libssh/string.h"
-
-/**
- * @defgroup libssh_string The SSH string functions
- * @ingroup libssh
- *
- * @brief String manipulations used in libssh.
- *
- * @{
- */
-
-/**
- * @brief Create a new SSH String object.
- *
- * @param[in] size The size of the string.
- *
- * @return The newly allocated string, NULL on error.
- */
-struct ssh_string_struct *ssh_string_new(size_t size) {
- struct ssh_string_struct *str = NULL;
-
- str = malloc(size + 4);
- if (str == NULL) {
- return NULL;
- }
-
- str->size = htonl(size);
- return str;
-}
-
-/**
- * @brief Fill a string with given data. The string should be big enough.
- *
- * @param s An allocated string to fill with data.
- *
- * @param data The data to fill the string with.
- *
- * @param len Size of data.
- *
- * @return 0 on success, < 0 on error.
- */
-int ssh_string_fill(struct ssh_string_struct *s, const void *data, size_t len) {
- if ((s == NULL) || (data == NULL) ||
- (len == 0) || (len > s->size)) {
- return -1;
- }
-
- memcpy(s->string, data, len);
- return 0;
-}
-
-/**
- * @brief Create a ssh string using a C string
- *
- * @param[in] what The source 0-terminated C string.
- *
- * @return The newly allocated string, NULL on error with errno
- * set.
- *
- * @note The nul byte is not copied nor counted in the ouput string.
- */
-struct ssh_string_struct *ssh_string_from_char(const char *what) {
- struct ssh_string_struct *ptr = NULL;
- size_t len = strlen(what);
-
- ptr = malloc(4 + len);
- if (ptr == NULL) {
- return NULL;
- }
- ptr->size = htonl(len);
- memcpy(ptr->string, what, len);
-
- return ptr;
-}
-
-/**
- * @brief Return the size of a SSH string.
- *
- * @param[in] s The the input SSH string.
- *
- * @return The size of the content of the string, 0 on error.
- */
-size_t ssh_string_len(struct ssh_string_struct *s) {
- if (s == NULL) {
- return ntohl(0);
- }
-
- return ntohl(s->size);
-}
-
-/**
- * @brief Convert a SSH string to a C nul-terminated string.
- *
- * @param[in] s The SSH input string.
- *
- * @return An allocated string pointer, NULL on error with errno
- * set.
- *
- * @note If the input SSH string contains zeroes, some parts of the output
- * string may not be readable with regular libc functions.
- */
-char *ssh_string_to_char(struct ssh_string_struct *s) {
- size_t len = ntohl(s->size) + 1;
- char *new = malloc(len);
-
- if (new == NULL) {
- return NULL;
- }
- memcpy(new, s->string, len - 1);
- new[len - 1] = '\0';
- return new;
-}
-
-/**
- * @brief Deallocate a char string object.
- *
- * @param[in] s The string to delete.
- */
-void ssh_string_free_char(char *s) {
- SAFE_FREE(s);
-}
-
-/**
- * @brief Copy a string, return a newly allocated string. The caller has to
- * free the string.
- *
- * @param[in] s String to copy.
- *
- * @return Newly allocated copy of the string, NULL on error.
- */
-struct ssh_string_struct *ssh_string_copy(struct ssh_string_struct *s) {
- struct ssh_string_struct *new = malloc(ntohl(s->size) + 4);
-
- if (new == NULL) {
- return NULL;
- }
- new->size = s->size;
- memcpy(new->string, s->string, ntohl(s->size));
-
- return new;
-}
-
-/**
- * @brief Destroy the data in a string so it couldn't appear in a core dump.
- *
- * @param[in] s The string to burn.
- */
-void ssh_string_burn(struct ssh_string_struct *s) {
- if (s == NULL) {
- return;
- }
- memset(s->string, 'X', ssh_string_len(s));
-}
-
-/**
- * @brief Get the payload of the string.
- *
- * @param s The string to get the data from.
- *
- * @return Return the data of the string or NULL on error.
- */
-void *ssh_string_data(struct ssh_string_struct *s) {
- if (s == NULL) {
- return NULL;
- }
-
- return s->string;
-}
-
-/**
- * @brief Deallocate a SSH string object.
- *
- * \param[in] s The SSH string to delete.
- */
-void ssh_string_free(struct ssh_string_struct *s) {
- SAFE_FREE(s);
-}
-
-/** @} */
-
-/* vim: set ts=4 sw=4 et cindent: */
diff --git a/libssh/threads.c b/libssh/threads.c
deleted file mode 100644
index 7cac6dbf..00000000
--- a/libssh/threads.c
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * This file is part of the SSH Library
- *
- * Copyright (c) 2010 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.
- */
-
-/**
- * @defgroup libssh_threads Threading with libssh
- * @ingroup libssh
- *
- * Threading with libssh
- * @{
- */
-
-#include "libssh/priv.h"
-#include "libssh/threads.h"
-
-#ifndef _WIN32
-
-#ifndef HAVE_PTHREAD
-#warning "You do not have any threading library installed. If the linked"
-#warning "application doesn't provide the threading callbacks, you're screwed"
-#endif
-
-
-#ifdef HAVE_PTHREAD
-
-#include <errno.h>
-#include <pthread.h>
-SSH_THREADS_PTHREAD(ssh_pthread_user_callbacks);
-#endif /* HAVE_PTHREAD */
-#endif /* _WIN32 */
-
-static struct ssh_threads_callbacks_struct *user_callbacks;
-
-#ifdef HAVE_LIBGCRYPT
-
-/* Libgcrypt specific way of handling thread callbacks */
-
-static struct gcry_thread_cbs gcrypt_threads_callbacks;
-
-static int libgcrypt_thread_init(void){
- if(user_callbacks == NULL)
- return SSH_ERROR;
- gcrypt_threads_callbacks.option= GCRY_THREAD_OPTION_VERSION << 8 || GCRY_THREAD_OPTION_USER;
- gcrypt_threads_callbacks.mutex_init=user_callbacks->mutex_init;
- gcrypt_threads_callbacks.mutex_destroy=user_callbacks->mutex_destroy;
- gcrypt_threads_callbacks.mutex_lock=user_callbacks->mutex_lock;
- gcrypt_threads_callbacks.mutex_unlock=user_callbacks->mutex_unlock;
- gcry_control(GCRYCTL_SET_THREAD_CBS, &gcrypt_threads_callbacks);
- return SSH_OK;
-}
-#else
-
-/* Libcrypto specific stuff */
-
-void **libcrypto_mutexes;
-
-static void libcrypto_lock_callback(int mode, int i, const char *file, int line){
- (void)file;
- (void)line;
- if(mode & CRYPTO_LOCK){
- user_callbacks->mutex_lock(&libcrypto_mutexes[i]);
- } else {
- user_callbacks->mutex_unlock(&libcrypto_mutexes[i]);
- }
-}
-
-static int libcrypto_thread_init(){
- int n=CRYPTO_num_locks();
- int i;
- libcrypto_mutexes=malloc(sizeof(void *) * n);
- if (libcrypto_mutexes == NULL)
- return SSH_ERROR;
- for (i=0;i<n;++i){
- user_callbacks->mutex_init(&libcrypto_mutexes[i]);
- }
- CRYPTO_set_id_callback(user_callbacks->thread_id);
- CRYPTO_set_locking_callback(libcrypto_lock_callback);
-
- return SSH_OK;
-}
-
-static void libcrypto_thread_finalize(){
- int n=CRYPTO_num_locks();
- int i;
- if (libcrypto_mutexes==NULL)
- return;
- for (i=0;i<n;++i){
- user_callbacks->mutex_destroy(&libcrypto_mutexes[i]);
- }
- SAFE_FREE(libcrypto_mutexes);
-
-}
-
-#endif
-
-/** @internal
- * @brief inits the threading with the backend cryptographic libraries
- */
-
-int ssh_threads_init(void){
- static int threads_initialized=0;
- int ret;
- if(threads_initialized)
- return SSH_OK;
- /* first initialize the user_callbacks with our default handlers if not
- * already the case
- */
- if(user_callbacks == NULL){
-#ifdef HAVE_PTHREAD
- user_callbacks=&ssh_pthread_user_callbacks;
- }
-#else
- return SSH_ERROR; // Can't do anything to initialize threading
- }
-#endif
-
- /* Then initialize the crypto libraries threading callbacks */
-#ifdef HAVE_LIBGCRYPT
- ret = libgcrypt_thread_init();
-#else /* Libcrypto */
- ret = libcrypto_thread_init();
-#endif
- if(ret == SSH_OK)
- threads_initialized=1;
- return ret;
-}
-
-void ssh_threads_finalize(void){
-#ifdef HAVE_LIBGCRYPT
-#else
- libcrypto_thread_finalize();
-#endif
-}
-
-int ssh_threads_set_callbacks(struct ssh_threads_callbacks_struct *cb){
- user_callbacks=cb;
- return SSH_OK;
-}
-
-/**
- * @}
- */
diff --git a/libssh/wrapper.c b/libssh/wrapper.c
deleted file mode 100644
index a78a93d9..00000000
--- a/libssh/wrapper.c
+++ /dev/null
@@ -1,325 +0,0 @@
-/*
- * wrapper.c - wrapper for crytpo functions
- *
- * This file is part of the SSH Library
- *
- * Copyright (c) 2003 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.
- */
-
-/*
- * Why a wrapper?
- *
- * Let's say you want to port libssh from libcrypto of openssl to libfoo
- * you are going to spend hours to remove every references to SHA1_Update()
- * to libfoo_sha1_update after the work is finished, you're going to have
- * only this file to modify it's not needed to say that your modifications
- * are welcome.
- */
-
-#include "config.h"
-
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "libssh/priv.h"
-#include "libssh/session.h"
-#include "libssh/crypto.h"
-#include "libssh/wrapper.h"
-
-/* it allocates a new cipher structure based on its offset into the global table */
-static struct crypto_struct *cipher_new(int offset) {
- struct crypto_struct *cipher = NULL;
-
- cipher = malloc(sizeof(struct crypto_struct));
- if (cipher == NULL) {
- return NULL;
- }
-
- /* note the memcpy will copy the pointers : so, you shouldn't free them */
- memcpy(cipher, &ssh_get_ciphertab()[offset], sizeof(*cipher));
-
- return cipher;
-}
-
-static void cipher_free(struct crypto_struct *cipher) {
-#ifdef HAVE_LIBGCRYPT
- unsigned int i;
-#endif
-
- if (cipher == NULL) {
- return;
- }
-
- if(cipher->key) {
-#ifdef HAVE_LIBGCRYPT
- for (i = 0; i < (cipher->keylen / sizeof(gcry_cipher_hd_t)); i++) {
- gcry_cipher_close(cipher->key[i]);
- }
-#elif defined HAVE_LIBCRYPTO
- /* destroy the key */
- memset(cipher->key, 0, cipher->keylen);
-#endif
- SAFE_FREE(cipher->key);
- }
- SAFE_FREE(cipher);
-}
-
-struct ssh_crypto_struct *crypto_new(void) {
- struct ssh_crypto_struct *crypto;
-
- crypto = malloc(sizeof(struct ssh_crypto_struct));
- if (crypto == NULL) {
- return NULL;
- }
- ZERO_STRUCTP(crypto);
- return crypto;
-}
-
-void crypto_free(struct ssh_crypto_struct *crypto){
- if (crypto == NULL) {
- return;
- }
-
- SAFE_FREE(crypto->server_pubkey);
-
- cipher_free(crypto->in_cipher);
- cipher_free(crypto->out_cipher);
-
- bignum_free(crypto->e);
- bignum_free(crypto->f);
- bignum_free(crypto->x);
- bignum_free(crypto->y);
- bignum_free(crypto->k);
- /* lot of other things */
- /* i'm lost in my own code. good work */
- memset(crypto,0,sizeof(*crypto));
-
- SAFE_FREE(crypto);
-}
-
-static int crypt_set_algorithms2(ssh_session session){
- const char *wanted;
- int i = 0;
- struct crypto_struct *ssh_ciphertab=ssh_get_ciphertab();
- /* we must scan the kex entries to find crypto algorithms and set their appropriate structure */
- /* out */
- wanted = session->client_kex.methods[SSH_CRYPT_C_S];
- while (ssh_ciphertab[i].name && strcmp(wanted, ssh_ciphertab[i].name)) {
- i++;
- }
-
- if (ssh_ciphertab[i].name == NULL) {
- ssh_set_error(session, SSH_FATAL,
- "Crypt_set_algorithms2: no crypto algorithm function found for %s",
- wanted);
- return SSH_ERROR;
- }
- ssh_log(session, SSH_LOG_PACKET, "Set output algorithm to %s", wanted);
-
- session->next_crypto->out_cipher = cipher_new(i);
- if (session->next_crypto->out_cipher == NULL) {
- ssh_set_error(session, SSH_FATAL, "No space left");
- return SSH_ERROR;
- }
- i = 0;
-
- /* in */
- wanted = session->client_kex.methods[SSH_CRYPT_S_C];
- while (ssh_ciphertab[i].name && strcmp(wanted, ssh_ciphertab[i].name)) {
- i++;
- }
-
- if (ssh_ciphertab[i].name == NULL) {
- ssh_set_error(session, SSH_FATAL,
- "Crypt_set_algorithms: no crypto algorithm function found for %s",
- wanted);
- return SSH_ERROR;
- }
- ssh_log(session, SSH_LOG_PACKET, "Set input algorithm to %s", wanted);
-
- session->next_crypto->in_cipher = cipher_new(i);
- if (session->next_crypto->in_cipher == NULL) {
- ssh_set_error(session, SSH_FATAL, "Not enough space");
- return SSH_ERROR;
- }
-
- /* compression */
- if (strcmp(session->client_kex.methods[SSH_COMP_C_S], "zlib") == 0) {
- session->next_crypto->do_compress_out = 1;
- }
- if (strcmp(session->client_kex.methods[SSH_COMP_S_C], "zlib") == 0) {
- session->next_crypto->do_compress_in = 1;
- }
- if (strcmp(session->client_kex.methods[SSH_COMP_C_S], "zlib@openssh.org") == 0) {
- session->next_crypto->delayed_compress_out = 1;
- }
- if (strcmp(session->client_kex.methods[SSH_COMP_S_C], "zlib@openssh.org") == 0) {
- session->next_crypto->delayed_compress_in = 1;
- }
- return SSH_OK;
-}
-
-static int crypt_set_algorithms1(ssh_session session) {
- int i = 0;
- struct crypto_struct *ssh_ciphertab=ssh_get_ciphertab();
-
- /* right now, we force 3des-cbc to be taken */
- while (ssh_ciphertab[i].name && strcmp(ssh_ciphertab[i].name,
- "3des-cbc-ssh1")) {
- i++;
- }
-
- if (ssh_ciphertab[i].name == NULL) {
- ssh_set_error(session, SSH_FATAL, "cipher 3des-cbc-ssh1 not found!");
- return -1;
- }
-
- session->next_crypto->out_cipher = cipher_new(i);
- if (session->next_crypto->out_cipher == NULL) {
- ssh_set_error(session, SSH_FATAL, "No space left");
- return SSH_ERROR;
- }
-
- session->next_crypto->in_cipher = cipher_new(i);
- if (session->next_crypto->in_cipher == NULL) {
- ssh_set_error(session, SSH_FATAL, "No space left");
- return SSH_ERROR;
- }
-
- return SSH_OK;
-}
-
-int crypt_set_algorithms(ssh_session session) {
- return (session->version == 1) ? crypt_set_algorithms1(session) :
- crypt_set_algorithms2(session);
-}
-
-// TODO Obviously too much cut and paste here
-int crypt_set_algorithms_server(ssh_session session){
- char *server = NULL;
- char *client = NULL;
- char *match = NULL;
- int i = 0;
- struct crypto_struct *ssh_ciphertab=ssh_get_ciphertab();
-
- /* we must scan the kex entries to find crypto algorithms and set their appropriate structure */
- enter_function();
- /* out */
- server = session->server_kex.methods[SSH_CRYPT_S_C];
- if(session && session->client_kex.methods) {
- client = session->client_kex.methods[SSH_CRYPT_S_C];
- } else {
- ssh_log(session,SSH_LOG_PROTOCOL, "Client KEX empty");
- }
- /* That's the client algorithms that are more important */
- match = ssh_find_matching(server,client);
-
-
- if(!match){
- ssh_set_error(session,SSH_FATAL,"Crypt_set_algorithms_server : no matching algorithm function found for %s",server);
- free(match);
- leave_function();
- return SSH_ERROR;
- }
- while(ssh_ciphertab[i].name && strcmp(match,ssh_ciphertab[i].name))
- i++;
- if(!ssh_ciphertab[i].name){
- ssh_set_error(session,SSH_FATAL,"Crypt_set_algorithms_server : no crypto algorithm function found for %s",server);
- free(match);
- leave_function();
- return SSH_ERROR;
- }
- ssh_log(session,SSH_LOG_PACKET,"Set output algorithm %s",match);
- SAFE_FREE(match);
-
- session->next_crypto->out_cipher = cipher_new(i);
- if (session->next_crypto->out_cipher == NULL) {
- ssh_set_error(session, SSH_FATAL, "No space left");
- leave_function();
- return SSH_ERROR;
- }
- i=0;
- /* in */
- client=session->client_kex.methods[SSH_CRYPT_C_S];
- server=session->server_kex.methods[SSH_CRYPT_S_C];
- match=ssh_find_matching(server,client);
- if(!match){
- ssh_set_error(session,SSH_FATAL,"Crypt_set_algorithms_server : no matching algorithm function found for %s",server);
- free(match);
- leave_function();
- return SSH_ERROR;
- }
- while(ssh_ciphertab[i].name && strcmp(match,ssh_ciphertab[i].name))
- i++;
- if(!ssh_ciphertab[i].name){
- ssh_set_error(session,SSH_FATAL,"Crypt_set_algorithms_server : no crypto algorithm function found for %s",server);
- free(match);
- leave_function();
- return SSH_ERROR;
- }
- ssh_log(session,SSH_LOG_PACKET,"Set input algorithm %s",match);
- SAFE_FREE(match);
-
- session->next_crypto->in_cipher = cipher_new(i);
- if (session->next_crypto->in_cipher == NULL) {
- ssh_set_error(session, SSH_FATAL, "No space left");
- leave_function();
- return SSH_ERROR;
- }
-
- /* compression */
- client=session->client_kex.methods[SSH_CRYPT_C_S];
- server=session->server_kex.methods[SSH_CRYPT_C_S];
- match=ssh_find_matching(server,client);
- if(match && !strcmp(match,"zlib")){
- ssh_log(session,SSH_LOG_PACKET,"enabling C->S compression");
- session->next_crypto->do_compress_in=1;
- }
- SAFE_FREE(match);
-
- client=session->client_kex.methods[SSH_CRYPT_S_C];
- server=session->server_kex.methods[SSH_CRYPT_S_C];
- match=ssh_find_matching(server,client);
- if(match && !strcmp(match,"zlib")){
- ssh_log(session,SSH_LOG_PACKET,"enabling S->C compression\n");
- session->next_crypto->do_compress_out=1;
- }
- SAFE_FREE(match);
-
- server=session->server_kex.methods[SSH_HOSTKEYS];
- client=session->client_kex.methods[SSH_HOSTKEYS];
- match=ssh_find_matching(server,client);
- if(match && !strcmp(match,"ssh-dss"))
- session->hostkeys=SSH_KEYTYPE_DSS;
- else if(match && !strcmp(match,"ssh-rsa"))
- session->hostkeys=SSH_KEYTYPE_RSA;
- else {
- ssh_set_error(session, SSH_FATAL, "Cannot know what %s is into %s",
- match ? match : NULL, server);
- SAFE_FREE(match);
- leave_function();
- return SSH_ERROR;
- }
- SAFE_FREE(match);
- leave_function();
- return SSH_OK;
-}
-
-/* vim: set ts=2 sw=2 et cindent: */