From f7842e3a4b9acea2126ff725f993c299aef0e6db Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Mon, 6 Sep 2010 14:28:38 +0200 Subject: misc: Rename libssh/ to src/ --- libssh/CMakeLists.txt | 204 --- libssh/agent.c | 502 -------- libssh/auth.c | 1682 ------------------------- libssh/auth1.c | 206 --- libssh/base64.c | 287 ----- libssh/buffer.c | 578 --------- libssh/callbacks.c | 43 - libssh/channels.c | 2495 ------------------------------------ libssh/channels1.c | 298 ----- libssh/client.c | 814 ------------ libssh/config.c | 347 ----- libssh/connect.c | 600 --------- libssh/crc32.c | 92 -- libssh/crypt.c | 216 ---- libssh/dh.c | 1049 ---------------- libssh/error.c | 123 -- libssh/gcrypt_missing.c | 99 -- libssh/gzip.c | 222 ---- libssh/init.c | 94 -- libssh/kex.c | 835 ------------ libssh/keyfiles.c | 1902 ---------------------------- libssh/keys.c | 1497 ---------------------- libssh/legacy.c | 237 ---- libssh/libcrypto.c | 443 ------- libssh/libgcrypt.c | 423 ------- libssh/log.c | 82 -- libssh/match.c | 185 --- libssh/messages.c | 848 ------------- libssh/misc.c | 685 ---------- libssh/options.c | 1138 ----------------- libssh/packet.c | 529 -------- libssh/packet1.c | 362 ------ libssh/pcap.c | 434 ------- libssh/pki.c | 113 -- libssh/poll.c | 692 ---------- libssh/scp.c | 752 ----------- libssh/server.c | 1174 ----------------- libssh/session.c | 520 -------- libssh/sftp.c | 3207 ----------------------------------------------- libssh/sftpserver.c | 490 -------- libssh/socket.c | 719 ----------- libssh/string.c | 212 ---- libssh/threads.c | 159 --- libssh/wrapper.c | 325 ----- 44 files changed, 27914 deletions(-) delete mode 100644 libssh/CMakeLists.txt delete mode 100644 libssh/agent.c delete mode 100644 libssh/auth.c delete mode 100644 libssh/auth1.c delete mode 100644 libssh/base64.c delete mode 100644 libssh/buffer.c delete mode 100644 libssh/callbacks.c delete mode 100644 libssh/channels.c delete mode 100644 libssh/channels1.c delete mode 100644 libssh/client.c delete mode 100644 libssh/config.c delete mode 100644 libssh/connect.c delete mode 100644 libssh/crc32.c delete mode 100644 libssh/crypt.c delete mode 100644 libssh/dh.c delete mode 100644 libssh/error.c delete mode 100644 libssh/gcrypt_missing.c delete mode 100644 libssh/gzip.c delete mode 100644 libssh/init.c delete mode 100644 libssh/kex.c delete mode 100644 libssh/keyfiles.c delete mode 100644 libssh/keys.c delete mode 100644 libssh/legacy.c delete mode 100644 libssh/libcrypto.c delete mode 100644 libssh/libgcrypt.c delete mode 100644 libssh/log.c delete mode 100644 libssh/match.c delete mode 100644 libssh/messages.c delete mode 100644 libssh/misc.c delete mode 100644 libssh/options.c delete mode 100644 libssh/packet.c delete mode 100644 libssh/packet1.c delete mode 100644 libssh/pcap.c delete mode 100644 libssh/pki.c delete mode 100644 libssh/poll.c delete mode 100644 libssh/scp.c delete mode 100644 libssh/server.c delete mode 100644 libssh/session.c delete mode 100644 libssh/sftp.c delete mode 100644 libssh/sftpserver.c delete mode 100644 libssh/socket.c delete mode 100644 libssh/string.c delete mode 100644 libssh/threads.c delete mode 100644 libssh/wrapper.c (limited to 'libssh') 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 - * - * 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 -#include -#include -#include - -#include - -#ifndef _WIN32 -#include -#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 - * - * 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 -#include -#include - -#ifndef _WIN32 -#include -#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 -#include - -#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 -#include -#include - -#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 -#include - -#ifndef _WIN32 -#include -#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 - * - * 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 - * - * 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 -#include -#include -#include -#include - -#ifndef _WIN32 -#include -#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 - * - * 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 -#include -#include -#include -#ifndef _WIN32 -#include -#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 -#include -#include - -#ifndef _WIN32 -#include -#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;ipcap_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 - * - * 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 -#include -#include - -#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 -#include -#include -#include -#include - -#ifdef _WIN32 -/* - * Only use Windows API functions available on Windows 2000 SP4 or later. - * The available constants are in . - * 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 -#undef close -#define close _close -#endif /* _MSC_VER */ -#include -#include - -/* is necessary for getaddrinfo before Windows XP, but it isn't - * available on some platforms like MinGW. */ -#ifdef HAVE_WSPIAPI_H -#include -#endif - -#else /* _WIN32 */ - -#include -#include -#include -#include - -#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 -#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 -#include -#include - -#ifndef _WIN32 -#include -#endif - -#ifdef OPENSSL_CRYPTO -#include -#include -#include -#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 - * - * 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 -#include -#include - -#ifndef _WIN32 -#include -#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 -#include -#include -#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 -#include -#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 -#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 - * - * 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 -#include -#include - -#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 -#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 -#include -#include - -#ifndef _WIN32 -#include -#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;iserver; - 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 - * - * 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 -#include -#include -#include -#include -#include -#include -#include - -#ifndef _WIN32 -#if _MSC_VER >= 1400 -#include -#undef open -#define open _open -#undef close -#define close _close -#undef read -#define read _read -#endif /* _MSC_VER */ -#include -#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 -#elif defined HAVE_LIBCRYPTO -#include -#include -#include -#include -#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 -#include -#ifdef HAVE_LIBCRYPTO -#include -#include -#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 -#include -#include - -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 -#include -#include - -#include "libssh/priv.h" -#include "libssh/session.h" -#include "libssh/crypto.h" -#include "libssh/wrapper.h" -#include "libssh/libcrypto.h" - -#ifdef HAVE_LIBCRYPTO - -#include -#include -#include -#include -#include -#include -#ifdef HAVE_OPENSSL_AES_H -#define HAS_AES -#include -#endif -#ifdef HAVE_OPENSSL_BLOWFISH_H -#define HAS_BLOWFISH -#include -#endif -#ifdef HAVE_OPENSSL_DES_H -#define HAS_DES -#include -#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 -#include -#include - -#include "libssh/priv.h" -#include "libssh/session.h" -#include "libssh/crypto.h" -#include "libssh/wrapper.h" - -#ifdef HAVE_LIBGCRYPT -#include - - -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 -#include -#include - -#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 - * Copyright (c) 1995 Tatu Ylonen , 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 -#include -#include - -#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 -#include - -#ifndef _WIN32 -#include -#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 - * - * 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 -#include -#include -#include -#include -#include -#include - -#ifdef _WIN32 -#define _WIN32_IE 0x0501 //SHGetSpecialFolderPath -#include // Must be the first to include -#include -#include -#include -#if _MSC_VER >= 1400 -#include -#endif /* _MSC_VER */ -#else /* _WIN32 */ -/* This is needed for a standard getpwuid_r on opensolaris */ -#define _POSIX_PTHREAD_SEMANTICS -#include -#include -#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 - * - * 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 -#include -#include -#ifndef _WIN32 -#include -#else -#include -#endif -#include -#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 -#include -#include -#include - -#ifndef _WIN32 -#include -#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 -#ifdef _WIN32 -#include -#else -#include -#include -#endif -#include - -#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 - * 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 - -#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 - -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 - -#ifdef _WIN32 -#ifndef STRICT -#define STRICT -#endif /* STRICT */ - -#include -#include -#include - -#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 -#include -#include -#include -#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 - * - * 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 -#include - -#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(rchannel,&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 -#include -#include -#include -#include - -#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 -#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 -#include -#include -#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 -#include -#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 - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef _WIN32 -#include -#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 -#include -#include - -#ifndef _WIN32 -#include -#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 -#include -#include -#include -#ifdef _WIN32 -#include -#include -#if _MSC_VER >= 1400 -#include -#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 -#include -#include -#include -#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 -#include - -#ifndef _WIN32 -#include -#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 -#include -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;imutex_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;imutex_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 -#include -#include - -#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: */ -- cgit v1.2.3