From 8b202a5bdb05140ca11f882faea15090b8c5512c Mon Sep 17 00:00:00 2001 From: lsv Date: Tue, 7 Jul 2020 23:12:14 +0500 Subject: [PATCH] remove libssh2 source --- include/libssh2/Win32/libssh2_config.h | 47 - include/libssh2/blf.h | 89 - include/libssh2/channel.h | 141 - include/libssh2/comp.h | 44 - include/libssh2/crypto.h | 248 -- include/libssh2/libgcrypt.h | 237 -- include/libssh2/libssh2.h | 1346 ------- include/libssh2/libssh2_config.h | 47 - include/libssh2/libssh2_config.h.in | 223 -- include/libssh2/libssh2_priv.h | 1149 ------ include/libssh2/libssh2_publickey.h | 122 - include/libssh2/libssh2_sftp.h | 351 -- include/libssh2/mac.h | 66 - include/libssh2/mbedtls.h | 451 --- include/libssh2/misc.h | 125 - include/libssh2/module.mk | 35 - include/libssh2/openssl.h | 398 --- include/libssh2/os400qc3.h | 391 --- include/libssh2/packet.h | 76 - include/libssh2/session.h | 93 - include/libssh2/sftp.h | 238 -- include/libssh2/transport.h | 86 - include/libssh2/userauth.h | 51 - include/libssh2/wincng.h | 575 --- libssh2/agent.c | 862 ----- libssh2/bcrypt_pbkdf.c | 180 - libssh2/blowfish.c | 697 ---- libssh2/channel.c | 2891 --------------- libssh2/comp.c | 376 -- libssh2/crypt.c | 349 -- libssh2/global.c | 78 - libssh2/hostkey.c | 1129 ------ libssh2/keepalive.c | 100 - libssh2/kex.c | 4453 ------------------------ libssh2/knownhost.c | 1271 ------- libssh2/libgcrypt.c | 667 ---- libssh2/mac.c | 414 --- libssh2/mbedtls.c | 733 ---- libssh2/misc.c | 872 ----- libssh2/module.mk | 40 - libssh2/openssl.c | 3294 ------------------ libssh2/os400qc3.c | 2411 ------------- libssh2/packet.c | 1336 ------- libssh2/pem.c | 902 ----- libssh2/publickey.c | 1278 ------- libssh2/scp.c | 1145 ------ libssh2/session.c | 1832 ---------- libssh2/sftp.c | 3755 -------------------- libssh2/transport.c | 917 ----- libssh2/userauth.c | 2110 ----------- libssh2/version.c | 54 - libssh2/wincng.c | 2166 ------------ 52 files changed, 42941 deletions(-) delete mode 100644 include/libssh2/Win32/libssh2_config.h delete mode 100644 include/libssh2/blf.h delete mode 100644 include/libssh2/channel.h delete mode 100644 include/libssh2/comp.h delete mode 100644 include/libssh2/crypto.h delete mode 100644 include/libssh2/libgcrypt.h delete mode 100644 include/libssh2/libssh2.h delete mode 100644 include/libssh2/libssh2_config.h delete mode 100644 include/libssh2/libssh2_config.h.in delete mode 100644 include/libssh2/libssh2_priv.h delete mode 100644 include/libssh2/libssh2_publickey.h delete mode 100644 include/libssh2/libssh2_sftp.h delete mode 100644 include/libssh2/mac.h delete mode 100644 include/libssh2/mbedtls.h delete mode 100644 include/libssh2/misc.h delete mode 100644 include/libssh2/module.mk delete mode 100644 include/libssh2/openssl.h delete mode 100644 include/libssh2/os400qc3.h delete mode 100644 include/libssh2/packet.h delete mode 100644 include/libssh2/session.h delete mode 100644 include/libssh2/sftp.h delete mode 100644 include/libssh2/transport.h delete mode 100644 include/libssh2/userauth.h delete mode 100644 include/libssh2/wincng.h delete mode 100644 libssh2/agent.c delete mode 100644 libssh2/bcrypt_pbkdf.c delete mode 100644 libssh2/blowfish.c delete mode 100644 libssh2/channel.c delete mode 100644 libssh2/comp.c delete mode 100644 libssh2/crypt.c delete mode 100644 libssh2/global.c delete mode 100644 libssh2/hostkey.c delete mode 100644 libssh2/keepalive.c delete mode 100644 libssh2/kex.c delete mode 100644 libssh2/knownhost.c delete mode 100644 libssh2/libgcrypt.c delete mode 100644 libssh2/mac.c delete mode 100644 libssh2/mbedtls.c delete mode 100644 libssh2/misc.c delete mode 100644 libssh2/module.mk delete mode 100644 libssh2/openssl.c delete mode 100644 libssh2/os400qc3.c delete mode 100644 libssh2/packet.c delete mode 100644 libssh2/pem.c delete mode 100644 libssh2/publickey.c delete mode 100644 libssh2/scp.c delete mode 100644 libssh2/session.c delete mode 100644 libssh2/sftp.c delete mode 100644 libssh2/transport.c delete mode 100644 libssh2/userauth.c delete mode 100644 libssh2/version.c delete mode 100644 libssh2/wincng.c diff --git a/include/libssh2/Win32/libssh2_config.h b/include/libssh2/Win32/libssh2_config.h deleted file mode 100644 index 6ac2ef4..0000000 --- a/include/libssh2/Win32/libssh2_config.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef LIBSSH2_CONFIG_H -#define LIBSSH2_CONFIG_H - -#ifndef WIN32 -#define WIN32 -#endif -#ifndef _CRT_SECURE_NO_DEPRECATE -#define _CRT_SECURE_NO_DEPRECATE 1 -#endif /* _CRT_SECURE_NO_DEPRECATE */ -#include -#include -#include - -#ifdef __MINGW32__ -#define HAVE_UNISTD_H -#define HAVE_INTTYPES_H -#define HAVE_SYS_TIME_H -#define HAVE_GETTIMEOFDAY -#endif /* __MINGW32__ */ - -#define HAVE_LIBCRYPT32 -#define HAVE_WINSOCK2_H -#define HAVE_IOCTLSOCKET -#define HAVE_SELECT - -#ifdef _MSC_VER -#if _MSC_VER < 1900 -#define snprintf _snprintf -#if _MSC_VER < 1500 -#define vsnprintf _vsnprintf -#endif -#define strdup _strdup -#define strncasecmp _strnicmp -#define strcasecmp _stricmp -#endif -#else -#ifndef __MINGW32__ -#define strncasecmp strnicmp -#define strcasecmp stricmp -#endif /* __MINGW32__ */ -#endif /* _MSC_VER */ - -/* Enable newer diffie-hellman-group-exchange-sha1 syntax */ -#define LIBSSH2_DH_GEX_NEW 1 - -#endif /* LIBSSH2_CONFIG_H */ - diff --git a/include/libssh2/blf.h b/include/libssh2/blf.h deleted file mode 100644 index 5b7c8aa..0000000 --- a/include/libssh2/blf.h +++ /dev/null @@ -1,89 +0,0 @@ -#ifndef __LIBSSH2_BLF_H -#define __LIBSSH2_BLF_H -/* $OpenBSD: blf.h,v 1.7 2007/03/14 17:59:41 grunk Exp $ */ -/* - * Blowfish - a fast block cipher designed by Bruce Schneier - * - * Copyright 1997 Niels Provos - * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Niels Provos. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * 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. - */ - -#if !defined(HAVE_BCRYPT_PBKDF) && !defined(HAVE_BLH_H) - -/* Schneier specifies a maximum key length of 56 bytes. - * This ensures that every key bit affects every cipher - * bit. However, the subkeys can hold up to 72 bytes. - * Warning: For normal blowfish encryption only 56 bytes - * of the key affect all cipherbits. - */ - -#define BLF_N 16 /* Number of Subkeys */ -#define BLF_MAXKEYLEN ((BLF_N-2)*4) /* 448 bits */ -#define BLF_MAXUTILIZED ((BLF_N + 2)*4) /* 576 bits */ - -/* Blowfish context */ -typedef struct BlowfishContext { - uint32_t S[4][256]; /* S-Boxes */ - uint32_t P[BLF_N + 2]; /* Subkeys */ -} blf_ctx; - -/* Raw access to customized Blowfish - * blf_key is just: - * Blowfish_initstate( state ) - * Blowfish_expand0state( state, key, keylen ) - */ - -void Blowfish_encipher(blf_ctx *, uint32_t *, uint32_t *); -void Blowfish_decipher(blf_ctx *, uint32_t *, uint32_t *); -void Blowfish_initstate(blf_ctx *); -void Blowfish_expand0state(blf_ctx *, const uint8_t *, uint16_t); -void Blowfish_expandstate -(blf_ctx *, const uint8_t *, uint16_t, const uint8_t *, uint16_t); - -/* Standard Blowfish */ - -void blf_key(blf_ctx *, const uint8_t *, uint16_t); -void blf_enc(blf_ctx *, uint32_t *, uint16_t); -void blf_dec(blf_ctx *, uint32_t *, uint16_t); - -void blf_ecb_encrypt(blf_ctx *, uint8_t *, uint32_t); -void blf_ecb_decrypt(blf_ctx *, uint8_t *, uint32_t); - -void blf_cbc_encrypt(blf_ctx *, uint8_t *, uint8_t *, uint32_t); -void blf_cbc_decrypt(blf_ctx *, uint8_t *, uint8_t *, uint32_t); - -/* Converts uint8_t to uint32_t */ -uint32_t Blowfish_stream2word(const uint8_t *, uint16_t, uint16_t *); - -/* bcrypt with pbkd */ -int bcrypt_pbkdf(const char *pass, size_t passlen, const uint8_t *salt, - size_t saltlen, - uint8_t *key, size_t keylen, unsigned int rounds); - -#endif /* !defined(HAVE_BCRYPT_PBKDF) && !defined(HAVE_BLH_H) */ -#endif /* __LIBSSH2_BLF_H */ diff --git a/include/libssh2/channel.h b/include/libssh2/channel.h deleted file mode 100644 index dc0ee37..0000000 --- a/include/libssh2/channel.h +++ /dev/null @@ -1,141 +0,0 @@ -#ifndef __LIBSSH2_CHANNEL_H -#define __LIBSSH2_CHANNEL_H -/* Copyright (c) 2008-2010 by Daniel Stenberg - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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. - */ - -/* - * _libssh2_channel_receive_window_adjust - * - * Adjust the receive window for a channel by adjustment bytes. If the amount - * to be adjusted is less than LIBSSH2_CHANNEL_MINADJUST and force is 0 the - * adjustment amount will be queued for a later packet. - * - * Always non-blocking. - */ -int _libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL * channel, - uint32_t adjustment, - unsigned char force, - unsigned int *store); - -/* - * _libssh2_channel_flush - * - * Flush data from one (or all) stream - * Returns number of bytes flushed, or negative on failure - */ -int _libssh2_channel_flush(LIBSSH2_CHANNEL *channel, int streamid); - -/* - * _libssh2_channel_free - * - * Make sure a channel is closed, then remove the channel from the session - * and free its resource(s) - * - * Returns 0 on success, negative on failure - */ -int _libssh2_channel_free(LIBSSH2_CHANNEL *channel); - -int -_libssh2_channel_extended_data(LIBSSH2_CHANNEL *channel, int ignore_mode); - -/* - * _libssh2_channel_write - * - * Send data to a channel - */ -ssize_t -_libssh2_channel_write(LIBSSH2_CHANNEL *channel, int stream_id, - const unsigned char *buf, size_t buflen); - -/* - * _libssh2_channel_open - * - * Establish a generic session channel - */ -LIBSSH2_CHANNEL * -_libssh2_channel_open(LIBSSH2_SESSION * session, const char *channel_type, - uint32_t channel_type_len, - uint32_t window_size, - uint32_t packet_size, - const unsigned char *message, size_t message_len); - - -/* - * _libssh2_channel_process_startup - * - * Primitive for libssh2_channel_(shell|exec|subsystem) - */ -int -_libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, - const char *request, size_t request_len, - const char *message, size_t message_len); - -/* - * _libssh2_channel_read - * - * Read data from a channel - * - * It is important to not return 0 until the currently read channel is - * complete. If we read stuff from the wire but it was no payload data to fill - * in the buffer with, we MUST make sure to return PACKET_EAGAIN. - */ -ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id, - char *buf, size_t buflen); - -uint32_t _libssh2_channel_nextid(LIBSSH2_SESSION * session); - -LIBSSH2_CHANNEL *_libssh2_channel_locate(LIBSSH2_SESSION * session, - uint32_t channel_id); - -size_t _libssh2_channel_packet_data_len(LIBSSH2_CHANNEL * channel, - int stream_id); - -int _libssh2_channel_close(LIBSSH2_CHANNEL * channel); - -/* - * _libssh2_channel_forward_cancel - * - * Stop listening on a remote port and free the listener - * Toss out any pending (un-accept()ed) connections - * - * Return 0 on success, LIBSSH2_ERROR_EAGAIN if would block, -1 on error - */ -int _libssh2_channel_forward_cancel(LIBSSH2_LISTENER *listener); - -#endif /* __LIBSSH2_CHANNEL_H */ - diff --git a/include/libssh2/comp.h b/include/libssh2/comp.h deleted file mode 100644 index 82ac2dc..0000000 --- a/include/libssh2/comp.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef __LIBSSH2_COMP_H -#define __LIBSSH2_COMP_H -/* Copyright (C) 2009-2010 by Daniel Stenberg - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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 "libssh2_priv.h" - -const LIBSSH2_COMP_METHOD **_libssh2_comp_methods(LIBSSH2_SESSION *session); - -#endif /* __LIBSSH2_COMP_H */ diff --git a/include/libssh2/crypto.h b/include/libssh2/crypto.h deleted file mode 100644 index c36dde1..0000000 --- a/include/libssh2/crypto.h +++ /dev/null @@ -1,248 +0,0 @@ -#ifndef __LIBSSH2_CRYPTO_H -#define __LIBSSH2_CRYPTO_H -/* Copyright (C) 2009, 2010 Simon Josefsson - * Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved. - * Copyright (C) 2010-2019 Daniel Stenberg - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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. - */ - -#ifdef LIBSSH2_OPENSSL -#include "openssl.h" -#endif - -#ifdef LIBSSH2_LIBGCRYPT -#include "libgcrypt.h" -#endif - -#ifdef LIBSSH2_WINCNG -#include "wincng.h" -#endif - -#ifdef LIBSSH2_OS400QC3 -#include "os400qc3.h" -#endif - -#ifdef LIBSSH2_MBEDTLS -#include "mbedtls.h" -#endif - -#define LIBSSH2_ED25519_KEY_LEN 32 -#define LIBSSH2_ED25519_PRIVATE_KEY_LEN 64 -#define LIBSSH2_ED25519_SIG_LEN 64 - -#if LIBSSH2_RSA -int _libssh2_rsa_new(libssh2_rsa_ctx ** rsa, - const unsigned char *edata, - unsigned long elen, - const unsigned char *ndata, - unsigned long nlen, - const unsigned char *ddata, - unsigned long dlen, - const unsigned char *pdata, - unsigned long plen, - const unsigned char *qdata, - unsigned long qlen, - const unsigned char *e1data, - unsigned long e1len, - const unsigned char *e2data, - unsigned long e2len, - const unsigned char *coeffdata, unsigned long coefflen); -int _libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa, - LIBSSH2_SESSION * session, - const char *filename, - unsigned const char *passphrase); -int _libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsa, - const unsigned char *sig, - unsigned long sig_len, - const unsigned char *m, unsigned long m_len); -int _libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session, - libssh2_rsa_ctx * rsactx, - const unsigned char *hash, - size_t hash_len, - unsigned char **signature, - size_t *signature_len); -int _libssh2_rsa_new_private_frommemory(libssh2_rsa_ctx ** rsa, - LIBSSH2_SESSION * session, - const char *filedata, - size_t filedata_len, - unsigned const char *passphrase); -#endif - -#if LIBSSH2_DSA -int _libssh2_dsa_new(libssh2_dsa_ctx ** dsa, - const unsigned char *pdata, - unsigned long plen, - const unsigned char *qdata, - unsigned long qlen, - const unsigned char *gdata, - unsigned long glen, - const unsigned char *ydata, - unsigned long ylen, - const unsigned char *x, unsigned long x_len); -int _libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa, - LIBSSH2_SESSION * session, - const char *filename, - unsigned const char *passphrase); -int _libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx, - const unsigned char *sig, - const unsigned char *m, unsigned long m_len); -int _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx, - const unsigned char *hash, - unsigned long hash_len, unsigned char *sig); -int _libssh2_dsa_new_private_frommemory(libssh2_dsa_ctx ** dsa, - LIBSSH2_SESSION * session, - const char *filedata, - size_t filedata_len, - unsigned const char *passphrase); -#endif - -#if LIBSSH2_ECDSA -int -_libssh2_ecdsa_curve_name_with_octal_new(libssh2_ecdsa_ctx ** ecdsactx, - const unsigned char *k, - size_t k_len, - libssh2_curve_type type); -int -_libssh2_ecdsa_new_private(libssh2_ecdsa_ctx ** ec_ctx, - LIBSSH2_SESSION * session, - const char *filename, - unsigned const char *passphrase); - -int -_libssh2_ecdsa_verify(libssh2_ecdsa_ctx * ctx, - const unsigned char *r, size_t r_len, - const unsigned char *s, size_t s_len, - const unsigned char *m, size_t m_len); - -int -_libssh2_ecdsa_create_key(LIBSSH2_SESSION *session, - _libssh2_ec_key **out_private_key, - unsigned char **out_public_key_octal, - size_t *out_public_key_octal_len, - libssh2_curve_type curve_type); - -int -_libssh2_ecdh_gen_k(_libssh2_bn **k, _libssh2_ec_key *private_key, - const unsigned char *server_public_key, - size_t server_public_key_len); - -int -_libssh2_ecdsa_sign(LIBSSH2_SESSION *session, libssh2_ecdsa_ctx *ec_ctx, - const unsigned char *hash, unsigned long hash_len, - unsigned char **signature, size_t *signature_len); - -int _libssh2_ecdsa_new_private_frommemory(libssh2_ecdsa_ctx ** ec_ctx, - LIBSSH2_SESSION * session, - const char *filedata, - size_t filedata_len, - unsigned const char *passphrase); - -libssh2_curve_type -_libssh2_ecdsa_get_curve_type(libssh2_ecdsa_ctx *ec_ctx); - -int -_libssh2_ecdsa_curve_type_from_name(const char *name, - libssh2_curve_type *out_type); - -#endif /* LIBSSH2_ECDSA */ - -#if LIBSSH2_ED25519 - -int -_libssh2_curve25519_new(LIBSSH2_SESSION *session, libssh2_ed25519_ctx **ctx, - uint8_t **out_public_key, uint8_t **out_private_key); - -int -_libssh2_curve25519_gen_k(_libssh2_bn **k, - uint8_t private_key[LIBSSH2_ED25519_KEY_LEN], - uint8_t server_public_key[LIBSSH2_ED25519_KEY_LEN]); - -int -_libssh2_ed25519_verify(libssh2_ed25519_ctx *ctx, const uint8_t *s, - size_t s_len, const uint8_t *m, size_t m_len); - -int -_libssh2_ed25519_new_private(libssh2_ed25519_ctx **ed_ctx, - LIBSSH2_SESSION *session, - const char *filename, const uint8_t *passphrase); - -int -_libssh2_ed25519_new_public(libssh2_ed25519_ctx **ed_ctx, - LIBSSH2_SESSION *session, - const unsigned char *raw_pub_key, - const uint8_t key_len); - -int -_libssh2_ed25519_sign(libssh2_ed25519_ctx *ctx, LIBSSH2_SESSION *session, - uint8_t **out_sig, size_t *out_sig_len, - const uint8_t *message, size_t message_len); - -int -_libssh2_ed25519_new_private_frommemory(libssh2_ed25519_ctx **ed_ctx, - LIBSSH2_SESSION *session, - const char *filedata, - size_t filedata_len, - unsigned const char *passphrase); - -#endif /* LIBSSH2_ED25519 */ - - -int _libssh2_cipher_init(_libssh2_cipher_ctx * h, - _libssh2_cipher_type(algo), - unsigned char *iv, - unsigned char *secret, int encrypt); - -int _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx, - _libssh2_cipher_type(algo), - int encrypt, unsigned char *block, size_t blocksize); - -int _libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - const char *privatekey, - const char *passphrase); - -int _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - const char *privatekeydata, - size_t privatekeydata_len, - const char *passphrase); - -#endif /* __LIBSSH2_CRYPTO_H */ diff --git a/include/libssh2/libgcrypt.h b/include/libssh2/libgcrypt.h deleted file mode 100644 index 92b48b8..0000000 --- a/include/libssh2/libgcrypt.h +++ /dev/null @@ -1,237 +0,0 @@ -#ifndef __LIBSSH2_LIBGCRYPT_H -#define __LIBSSH2_LIBGCRYPT_H -/* - * Copyright (C) 2008, 2009, 2010 Simon Josefsson - * Copyright (C) 2006, 2007, The Written Word, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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 - -#define LIBSSH2_MD5 1 - -#define LIBSSH2_HMAC_RIPEMD 1 -#define LIBSSH2_HMAC_SHA256 1 -#define LIBSSH2_HMAC_SHA512 1 - -#define LIBSSH2_AES 1 -#define LIBSSH2_AES_CTR 1 -#define LIBSSH2_BLOWFISH 1 -#define LIBSSH2_RC4 1 -#define LIBSSH2_CAST 1 -#define LIBSSH2_3DES 1 - -#define LIBSSH2_RSA 1 -#define LIBSSH2_DSA 1 -#define LIBSSH2_ECDSA 0 -#define LIBSSH2_ED25519 0 - -#define MD5_DIGEST_LENGTH 16 -#define SHA_DIGEST_LENGTH 20 -#define SHA256_DIGEST_LENGTH 32 -#define SHA384_DIGEST_LENGTH 48 -#define SHA512_DIGEST_LENGTH 64 - -#define EC_MAX_POINT_LEN ((528 * 2 / 8) + 1) - -#define _libssh2_random(buf, len) \ - (gcry_randomize ((buf), (len), GCRY_STRONG_RANDOM), 1) - -#define libssh2_prepare_iovec(vec, len) /* Empty. */ - -#define libssh2_sha1_ctx gcry_md_hd_t - -/* returns 0 in case of failure */ -#define libssh2_sha1_init(ctx) \ - (GPG_ERR_NO_ERROR == gcry_md_open(ctx, GCRY_MD_SHA1, 0)) -#define libssh2_sha1_update(ctx, data, len) \ - gcry_md_write(ctx, (unsigned char *) data, len) -#define libssh2_sha1_final(ctx, out) \ - memcpy(out, gcry_md_read(ctx, 0), SHA_DIGEST_LENGTH), gcry_md_close(ctx) -#define libssh2_sha1(message, len, out) \ - gcry_md_hash_buffer(GCRY_MD_SHA1, out, message, len) - -#define libssh2_sha256_ctx gcry_md_hd_t - -#define libssh2_sha256_init(ctx) \ - (GPG_ERR_NO_ERROR == gcry_md_open(ctx, GCRY_MD_SHA256, 0)) -#define libssh2_sha256_update(ctx, data, len) \ - gcry_md_write(ctx, (unsigned char *) data, len) -#define libssh2_sha256_final(ctx, out) \ - memcpy(out, gcry_md_read(ctx, 0), SHA256_DIGEST_LENGTH), gcry_md_close(ctx) -#define libssh2_sha256(message, len, out) \ - gcry_md_hash_buffer(GCRY_MD_SHA256, out, message, len) - -#define libssh2_sha384_ctx gcry_md_hd_t - -#define libssh2_sha384_init(ctx) \ - (GPG_ERR_NO_ERROR == gcry_md_open(ctx, GCRY_MD_SHA384, 0)) -#define libssh2_sha384_update(ctx, data, len) \ - gcry_md_write(ctx, (unsigned char *) data, len) -#define libssh2_sha384_final(ctx, out) \ - memcpy(out, gcry_md_read(ctx, 0), SHA384_DIGEST_LENGTH), gcry_md_close(ctx) -#define libssh2_sha384(message, len, out) \ - gcry_md_hash_buffer(GCRY_MD_SHA384, out, message, len) - -#define libssh2_sha512_ctx gcry_md_hd_t - -#define libssh2_sha512_init(ctx) \ - (GPG_ERR_NO_ERROR == gcry_md_open(ctx, GCRY_MD_SHA512, 0)) -#define libssh2_sha512_update(ctx, data, len) \ - gcry_md_write(ctx, (unsigned char *) data, len) -#define libssh2_sha512_final(ctx, out) \ - memcpy(out, gcry_md_read(ctx, 0), SHA512_DIGEST_LENGTH), gcry_md_close(ctx) -#define libssh2_sha512(message, len, out) \ - gcry_md_hash_buffer(GCRY_MD_SHA512, out, message, len) - -#define libssh2_md5_ctx gcry_md_hd_t - -/* returns 0 in case of failure */ -#define libssh2_md5_init(ctx) \ - (GPG_ERR_NO_ERROR == gcry_md_open(ctx, GCRY_MD_MD5, 0)) - -#define libssh2_md5_update(ctx, data, len) \ - gcry_md_write(ctx, (unsigned char *) data, len) -#define libssh2_md5_final(ctx, out) \ - memcpy(out, gcry_md_read(ctx, 0), MD5_DIGEST_LENGTH), gcry_md_close(ctx) -#define libssh2_md5(message, len, out) \ - gcry_md_hash_buffer(GCRY_MD_MD5, out, message, len) - -#define libssh2_hmac_ctx gcry_md_hd_t -#define libssh2_hmac_ctx_init(ctx) -#define libssh2_hmac_sha1_init(ctx, key, keylen) \ - gcry_md_open(ctx, GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC), \ - gcry_md_setkey(*ctx, key, keylen) -#define libssh2_hmac_md5_init(ctx, key, keylen) \ - gcry_md_open(ctx, GCRY_MD_MD5, GCRY_MD_FLAG_HMAC), \ - gcry_md_setkey(*ctx, key, keylen) -#define libssh2_hmac_ripemd160_init(ctx, key, keylen) \ - gcry_md_open(ctx, GCRY_MD_RMD160, GCRY_MD_FLAG_HMAC), \ - gcry_md_setkey(*ctx, key, keylen) -#define libssh2_hmac_sha256_init(ctx, key, keylen) \ - gcry_md_open(ctx, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC), \ - gcry_md_setkey(*ctx, key, keylen) -#define libssh2_hmac_sha512_init(ctx, key, keylen) \ - gcry_md_open(ctx, GCRY_MD_SHA512, GCRY_MD_FLAG_HMAC), \ - gcry_md_setkey(*ctx, key, keylen) -#define libssh2_hmac_update(ctx, data, datalen) \ - gcry_md_write(ctx, (unsigned char *) data, datalen) -#define libssh2_hmac_final(ctx, data) \ - memcpy(data, gcry_md_read(ctx, 0), \ - gcry_md_get_algo_dlen(gcry_md_get_algo(ctx))) -#define libssh2_hmac_cleanup(ctx) gcry_md_close (*ctx); - -#define libssh2_crypto_init() gcry_control (GCRYCTL_DISABLE_SECMEM) -#define libssh2_crypto_exit() - -#define libssh2_rsa_ctx struct gcry_sexp - -#define _libssh2_rsa_free(rsactx) gcry_sexp_release (rsactx) - -#define libssh2_dsa_ctx struct gcry_sexp - -#define _libssh2_dsa_free(dsactx) gcry_sexp_release (dsactx) - -#if LIBSSH2_ECDSA -#else -#define _libssh2_ec_key void -#endif - -#define _libssh2_cipher_type(name) int name -#define _libssh2_cipher_ctx gcry_cipher_hd_t - -#define _libssh2_gcry_ciphermode(c,m) ((c << 8) | m) -#define _libssh2_gcry_cipher(c) (c >> 8) -#define _libssh2_gcry_mode(m) (m & 0xFF) - -#define _libssh2_cipher_aes256ctr \ - _libssh2_gcry_ciphermode(GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CTR) -#define _libssh2_cipher_aes192ctr \ - _libssh2_gcry_ciphermode(GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CTR) -#define _libssh2_cipher_aes128ctr \ - _libssh2_gcry_ciphermode(GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CTR) -#define _libssh2_cipher_aes256 \ - _libssh2_gcry_ciphermode(GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC) -#define _libssh2_cipher_aes192 \ - _libssh2_gcry_ciphermode(GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CBC) -#define _libssh2_cipher_aes128 \ - _libssh2_gcry_ciphermode(GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC) -#define _libssh2_cipher_blowfish \ - _libssh2_gcry_ciphermode(GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CBC) -#define _libssh2_cipher_arcfour \ - _libssh2_gcry_ciphermode(GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM) -#define _libssh2_cipher_cast5 \ - _libssh2_gcry_ciphermode(GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_CBC) -#define _libssh2_cipher_3des \ - _libssh2_gcry_ciphermode(GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CBC) - - -#define _libssh2_cipher_dtor(ctx) gcry_cipher_close(*(ctx)) - -#define _libssh2_bn struct gcry_mpi -#define _libssh2_bn_ctx int -#define _libssh2_bn_ctx_new() 0 -#define _libssh2_bn_ctx_free(bnctx) ((void)0) -#define _libssh2_bn_init() gcry_mpi_new(0) -#define _libssh2_bn_init_from_bin() NULL /* because gcry_mpi_scan() creates a - new bignum */ -#define _libssh2_bn_set_word(bn, val) gcry_mpi_set_ui(bn, val) -#define _libssh2_bn_from_bin(bn, len, val) \ - gcry_mpi_scan(&((bn)), GCRYMPI_FMT_USG, val, len, NULL) -#define _libssh2_bn_to_bin(bn, val) \ - gcry_mpi_print(GCRYMPI_FMT_USG, val, _libssh2_bn_bytes(bn), NULL, bn) -#define _libssh2_bn_bytes(bn) \ - (gcry_mpi_get_nbits (bn) / 8 + \ - ((gcry_mpi_get_nbits (bn) % 8 == 0) ? 0 : 1)) -#define _libssh2_bn_bits(bn) gcry_mpi_get_nbits (bn) -#define _libssh2_bn_free(bn) gcry_mpi_release(bn) - -#define _libssh2_dh_ctx struct gcry_mpi * -#define libssh2_dh_init(dhctx) _libssh2_dh_init(dhctx) -#define libssh2_dh_key_pair(dhctx, public, g, p, group_order, bnctx) \ - _libssh2_dh_key_pair(dhctx, public, g, p, group_order) -#define libssh2_dh_secret(dhctx, secret, f, p, bnctx) \ - _libssh2_dh_secret(dhctx, secret, f, p) -#define libssh2_dh_dtor(dhctx) _libssh2_dh_dtor(dhctx) -extern void _libssh2_dh_init(_libssh2_dh_ctx *dhctx); -extern int _libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public, - _libssh2_bn *g, _libssh2_bn *p, - int group_order); -extern int _libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret, - _libssh2_bn *f, _libssh2_bn *p); -extern void _libssh2_dh_dtor(_libssh2_dh_ctx *dhctx); - -#endif /* __LIBSSH2_LIBGCRYPT_H */ diff --git a/include/libssh2/libssh2.h b/include/libssh2/libssh2.h deleted file mode 100644 index 386bcc8..0000000 --- a/include/libssh2/libssh2.h +++ /dev/null @@ -1,1346 +0,0 @@ -/* Copyright (c) 2004-2009, Sara Golemon - * Copyright (c) 2009-2015 Daniel Stenberg - * Copyright (c) 2010 Simon Josefsson - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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. - */ - -#ifndef LIBSSH2_H -#define LIBSSH2_H 1 - -#define LIBSSH2_COPYRIGHT "2004-2019 The libssh2 project and its contributors." - -/* We use underscore instead of dash when appending DEV in dev versions just - to make the BANNER define (used by src/session.c) be a valid SSH - banner. Release versions have no appended strings and may of course not - have dashes either. */ -#define LIBSSH2_VERSION "1.9.0_DEV" - -/* The numeric version number is also available "in parts" by using these - defines: */ -#define LIBSSH2_VERSION_MAJOR 1 -#define LIBSSH2_VERSION_MINOR 9 -#define LIBSSH2_VERSION_PATCH 0 - -/* This is the numeric version of the libssh2 version number, meant for easier - parsing and comparions by programs. The LIBSSH2_VERSION_NUM define will - always follow this syntax: - - 0xXXYYZZ - - Where XX, YY and ZZ are the main version, release and patch numbers in - hexadecimal (using 8 bits each). All three numbers are always represented - using two digits. 1.2 would appear as "0x010200" while version 9.11.7 - appears as "0x090b07". - - This 6-digit (24 bits) hexadecimal number does not show pre-release number, - and it is always a greater number in a more recent release. It makes - comparisons with greater than and less than work. -*/ -#define LIBSSH2_VERSION_NUM 0x010900 - -/* - * This is the date and time when the full source package was created. The - * timestamp is not stored in the source code repo, as the timestamp is - * properly set in the tarballs by the maketgz script. - * - * The format of the date should follow this template: - * - * "Mon Feb 12 11:35:33 UTC 2007" - */ -#define LIBSSH2_TIMESTAMP "DEV" - -#ifndef RC_INVOKED - -#ifdef __cplusplus -extern "C" { -#endif -#ifdef _WIN32 -# include -# include -#endif - -#include -#include -#include -#include - -/* Allow alternate API prefix from CFLAGS or calling app */ -#ifndef LIBSSH2_API -# ifdef LIBSSH2_WIN32 -# ifdef _WINDLL -# ifdef LIBSSH2_LIBRARY -# define LIBSSH2_API __declspec(dllexport) -# else -# define LIBSSH2_API __declspec(dllimport) -# endif /* LIBSSH2_LIBRARY */ -# else -# define LIBSSH2_API -# endif -# else /* !LIBSSH2_WIN32 */ -# define LIBSSH2_API -# endif /* LIBSSH2_WIN32 */ -#endif /* LIBSSH2_API */ - -#ifdef HAVE_SYS_UIO_H -# include -#endif - -#if (defined(NETWARE) && !defined(__NOVELL_LIBC__)) -# include -typedef unsigned char uint8_t; -typedef unsigned short int uint16_t; -typedef unsigned int uint32_t; -typedef int int32_t; -typedef unsigned long long uint64_t; -typedef long long int64_t; -#endif - -#ifdef _MSC_VER -typedef unsigned char uint8_t; -typedef unsigned short int uint16_t; -typedef unsigned int uint32_t; -typedef __int32 int32_t; -typedef __int64 int64_t; -typedef unsigned __int64 uint64_t; -typedef unsigned __int64 libssh2_uint64_t; -typedef __int64 libssh2_int64_t; -#if (!defined(HAVE_SSIZE_T) && !defined(ssize_t)) -typedef SSIZE_T ssize_t; -#define HAVE_SSIZE_T -#endif -#else -#include -typedef unsigned long long libssh2_uint64_t; -typedef long long libssh2_int64_t; -#endif - -#ifdef WIN32 -typedef SOCKET libssh2_socket_t; -#define LIBSSH2_INVALID_SOCKET INVALID_SOCKET -#else /* !WIN32 */ -typedef int libssh2_socket_t; -#define LIBSSH2_INVALID_SOCKET -1 -#endif /* WIN32 */ - -/* - * Determine whether there is small or large file support on windows. - */ - -#if defined(_MSC_VER) && !defined(_WIN32_WCE) -# if (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64) -# define LIBSSH2_USE_WIN32_LARGE_FILES -# else -# define LIBSSH2_USE_WIN32_SMALL_FILES -# endif -#endif - -#if defined(__MINGW32__) && !defined(LIBSSH2_USE_WIN32_LARGE_FILES) -# define LIBSSH2_USE_WIN32_LARGE_FILES -#endif - -#if defined(__WATCOMC__) && !defined(LIBSSH2_USE_WIN32_LARGE_FILES) -# define LIBSSH2_USE_WIN32_LARGE_FILES -#endif - -#if defined(__POCC__) -# undef LIBSSH2_USE_WIN32_LARGE_FILES -#endif - -#if defined(_WIN32) && !defined(LIBSSH2_USE_WIN32_LARGE_FILES) && \ - !defined(LIBSSH2_USE_WIN32_SMALL_FILES) -# define LIBSSH2_USE_WIN32_SMALL_FILES -#endif - -/* - * Large file (>2Gb) support using WIN32 functions. - */ - -#ifdef LIBSSH2_USE_WIN32_LARGE_FILES -# include -# include -# include -# define LIBSSH2_STRUCT_STAT_SIZE_FORMAT "%I64d" -typedef struct _stati64 libssh2_struct_stat; -typedef __int64 libssh2_struct_stat_size; -#endif - -/* - * Small file (<2Gb) support using WIN32 functions. - */ - -#ifdef LIBSSH2_USE_WIN32_SMALL_FILES -# include -# include -# ifndef _WIN32_WCE -# define LIBSSH2_STRUCT_STAT_SIZE_FORMAT "%d" -typedef struct _stat libssh2_struct_stat; -typedef off_t libssh2_struct_stat_size; -# endif -#endif - -#ifndef LIBSSH2_STRUCT_STAT_SIZE_FORMAT -# ifdef __VMS -/* We have to roll our own format here because %z is a C99-ism we don't - have. */ -# if __USE_OFF64_T || __USING_STD_STAT -# define LIBSSH2_STRUCT_STAT_SIZE_FORMAT "%Ld" -# else -# define LIBSSH2_STRUCT_STAT_SIZE_FORMAT "%d" -# endif -# else -# define LIBSSH2_STRUCT_STAT_SIZE_FORMAT "%zd" -# endif -typedef struct stat libssh2_struct_stat; -typedef off_t libssh2_struct_stat_size; -#endif - -/* Part of every banner, user specified or not */ -#define LIBSSH2_SSH_BANNER "SSH-2.0-libssh2_" LIBSSH2_VERSION - -#define LIBSSH2_SSH_DEFAULT_BANNER LIBSSH2_SSH_BANNER -#define LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF LIBSSH2_SSH_DEFAULT_BANNER "\r\n" - -/* Default generate and safe prime sizes for - diffie-hellman-group-exchange-sha1 */ -#define LIBSSH2_DH_GEX_MINGROUP 1024 -#define LIBSSH2_DH_GEX_OPTGROUP 1536 -#define LIBSSH2_DH_GEX_MAXGROUP 2048 - -/* Defaults for pty requests */ -#define LIBSSH2_TERM_WIDTH 80 -#define LIBSSH2_TERM_HEIGHT 24 -#define LIBSSH2_TERM_WIDTH_PX 0 -#define LIBSSH2_TERM_HEIGHT_PX 0 - -/* 1/4 second */ -#define LIBSSH2_SOCKET_POLL_UDELAY 250000 -/* 0.25 * 120 == 30 seconds */ -#define LIBSSH2_SOCKET_POLL_MAXLOOPS 120 - -/* Maximum size to allow a payload to compress to, plays it safe by falling - short of spec limits */ -#define LIBSSH2_PACKET_MAXCOMP 32000 - -/* Maximum size to allow a payload to deccompress to, plays it safe by - allowing more than spec requires */ -#define LIBSSH2_PACKET_MAXDECOMP 40000 - -/* Maximum size for an inbound compressed payload, plays it safe by - overshooting spec limits */ -#define LIBSSH2_PACKET_MAXPAYLOAD 40000 - -/* Malloc callbacks */ -#define LIBSSH2_ALLOC_FUNC(name) void *name(size_t count, void **abstract) -#define LIBSSH2_REALLOC_FUNC(name) void *name(void *ptr, size_t count, \ - void **abstract) -#define LIBSSH2_FREE_FUNC(name) void name(void *ptr, void **abstract) - -typedef struct _LIBSSH2_USERAUTH_KBDINT_PROMPT -{ - char *text; - unsigned int length; - unsigned char echo; -} LIBSSH2_USERAUTH_KBDINT_PROMPT; - -typedef struct _LIBSSH2_USERAUTH_KBDINT_RESPONSE -{ - char *text; - unsigned int length; -} LIBSSH2_USERAUTH_KBDINT_RESPONSE; - -/* 'publickey' authentication callback */ -#define LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC(name) \ - int name(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, \ - const unsigned char *data, size_t data_len, void **abstract) - -/* 'keyboard-interactive' authentication callback */ -#define LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC(name_) \ - void name_(const char *name, int name_len, const char *instruction, \ - int instruction_len, int num_prompts, \ - const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts, \ - LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses, void **abstract) - -/* Callbacks for special SSH packets */ -#define LIBSSH2_IGNORE_FUNC(name) \ - void name(LIBSSH2_SESSION *session, const char *message, int message_len, \ - void **abstract) - -#define LIBSSH2_DEBUG_FUNC(name) \ - void name(LIBSSH2_SESSION *session, int always_display, const char *message, \ - int message_len, const char *language, int language_len, \ - void **abstract) - -#define LIBSSH2_DISCONNECT_FUNC(name) \ - void name(LIBSSH2_SESSION *session, int reason, const char *message, \ - int message_len, const char *language, int language_len, \ - void **abstract) - -#define LIBSSH2_PASSWD_CHANGEREQ_FUNC(name) \ - void name(LIBSSH2_SESSION *session, char **newpw, int *newpw_len, \ - void **abstract) - -#define LIBSSH2_MACERROR_FUNC(name) \ - int name(LIBSSH2_SESSION *session, const char *packet, int packet_len, \ - void **abstract) - -#define LIBSSH2_X11_OPEN_FUNC(name) \ - void name(LIBSSH2_SESSION *session, LIBSSH2_CHANNEL *channel, \ - const char *shost, int sport, void **abstract) - -#define LIBSSH2_CHANNEL_CLOSE_FUNC(name) \ - void name(LIBSSH2_SESSION *session, void **session_abstract, \ - LIBSSH2_CHANNEL *channel, void **channel_abstract) - -/* I/O callbacks */ -#define LIBSSH2_RECV_FUNC(name) \ - ssize_t name(libssh2_socket_t socket, \ - void *buffer, size_t length, \ - int flags, void **abstract) -#define LIBSSH2_SEND_FUNC(name) \ - ssize_t name(libssh2_socket_t socket, \ - const void *buffer, size_t length, \ - int flags, void **abstract) - -/* libssh2_session_callback_set() constants */ -#define LIBSSH2_CALLBACK_IGNORE 0 -#define LIBSSH2_CALLBACK_DEBUG 1 -#define LIBSSH2_CALLBACK_DISCONNECT 2 -#define LIBSSH2_CALLBACK_MACERROR 3 -#define LIBSSH2_CALLBACK_X11 4 -#define LIBSSH2_CALLBACK_SEND 5 -#define LIBSSH2_CALLBACK_RECV 6 - -/* libssh2_session_method_pref() constants */ -#define LIBSSH2_METHOD_KEX 0 -#define LIBSSH2_METHOD_HOSTKEY 1 -#define LIBSSH2_METHOD_CRYPT_CS 2 -#define LIBSSH2_METHOD_CRYPT_SC 3 -#define LIBSSH2_METHOD_MAC_CS 4 -#define LIBSSH2_METHOD_MAC_SC 5 -#define LIBSSH2_METHOD_COMP_CS 6 -#define LIBSSH2_METHOD_COMP_SC 7 -#define LIBSSH2_METHOD_LANG_CS 8 -#define LIBSSH2_METHOD_LANG_SC 9 - -/* flags */ -#define LIBSSH2_FLAG_SIGPIPE 1 -#define LIBSSH2_FLAG_COMPRESS 2 - -typedef struct _LIBSSH2_SESSION LIBSSH2_SESSION; -typedef struct _LIBSSH2_CHANNEL LIBSSH2_CHANNEL; -typedef struct _LIBSSH2_LISTENER LIBSSH2_LISTENER; -typedef struct _LIBSSH2_KNOWNHOSTS LIBSSH2_KNOWNHOSTS; -typedef struct _LIBSSH2_AGENT LIBSSH2_AGENT; - -typedef struct _LIBSSH2_POLLFD { - unsigned char type; /* LIBSSH2_POLLFD_* below */ - - union { - libssh2_socket_t socket; /* File descriptors -- examined with - system select() call */ - LIBSSH2_CHANNEL *channel; /* Examined by checking internal state */ - LIBSSH2_LISTENER *listener; /* Read polls only -- are inbound - connections waiting to be accepted? */ - } fd; - - unsigned long events; /* Requested Events */ - unsigned long revents; /* Returned Events */ -} LIBSSH2_POLLFD; - -/* Poll FD Descriptor Types */ -#define LIBSSH2_POLLFD_SOCKET 1 -#define LIBSSH2_POLLFD_CHANNEL 2 -#define LIBSSH2_POLLFD_LISTENER 3 - -/* Note: Win32 Doesn't actually have a poll() implementation, so some of these - values are faked with select() data */ -/* Poll FD events/revents -- Match sys/poll.h where possible */ -#define LIBSSH2_POLLFD_POLLIN 0x0001 /* Data available to be read or - connection available -- - All */ -#define LIBSSH2_POLLFD_POLLPRI 0x0002 /* Priority data available to - be read -- Socket only */ -#define LIBSSH2_POLLFD_POLLEXT 0x0002 /* Extended data available to - be read -- Channel only */ -#define LIBSSH2_POLLFD_POLLOUT 0x0004 /* Can may be written -- - Socket/Channel */ -/* revents only */ -#define LIBSSH2_POLLFD_POLLERR 0x0008 /* Error Condition -- Socket */ -#define LIBSSH2_POLLFD_POLLHUP 0x0010 /* HangUp/EOF -- Socket */ -#define LIBSSH2_POLLFD_SESSION_CLOSED 0x0010 /* Session Disconnect */ -#define LIBSSH2_POLLFD_POLLNVAL 0x0020 /* Invalid request -- Socket - Only */ -#define LIBSSH2_POLLFD_POLLEX 0x0040 /* Exception Condition -- - Socket/Win32 */ -#define LIBSSH2_POLLFD_CHANNEL_CLOSED 0x0080 /* Channel Disconnect */ -#define LIBSSH2_POLLFD_LISTENER_CLOSED 0x0080 /* Listener Disconnect */ - -#define HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION -/* Block Direction Types */ -#define LIBSSH2_SESSION_BLOCK_INBOUND 0x0001 -#define LIBSSH2_SESSION_BLOCK_OUTBOUND 0x0002 - -/* Hash Types */ -#define LIBSSH2_HOSTKEY_HASH_MD5 1 -#define LIBSSH2_HOSTKEY_HASH_SHA1 2 -#define LIBSSH2_HOSTKEY_HASH_SHA256 3 - -/* Hostkey Types */ -#define LIBSSH2_HOSTKEY_TYPE_UNKNOWN 0 -#define LIBSSH2_HOSTKEY_TYPE_RSA 1 -#define LIBSSH2_HOSTKEY_TYPE_DSS 2 -#define LIBSSH2_HOSTKEY_TYPE_ECDSA_256 3 -#define LIBSSH2_HOSTKEY_TYPE_ECDSA_384 4 -#define LIBSSH2_HOSTKEY_TYPE_ECDSA_521 5 -#define LIBSSH2_HOSTKEY_TYPE_ED25519 6 - -/* Disconnect Codes (defined by SSH protocol) */ -#define SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT 1 -#define SSH_DISCONNECT_PROTOCOL_ERROR 2 -#define SSH_DISCONNECT_KEY_EXCHANGE_FAILED 3 -#define SSH_DISCONNECT_RESERVED 4 -#define SSH_DISCONNECT_MAC_ERROR 5 -#define SSH_DISCONNECT_COMPRESSION_ERROR 6 -#define SSH_DISCONNECT_SERVICE_NOT_AVAILABLE 7 -#define SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED 8 -#define SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE 9 -#define SSH_DISCONNECT_CONNECTION_LOST 10 -#define SSH_DISCONNECT_BY_APPLICATION 11 -#define SSH_DISCONNECT_TOO_MANY_CONNECTIONS 12 -#define SSH_DISCONNECT_AUTH_CANCELLED_BY_USER 13 -#define SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE 14 -#define SSH_DISCONNECT_ILLEGAL_USER_NAME 15 - -/* Error Codes (defined by libssh2) */ -#define LIBSSH2_ERROR_NONE 0 - -/* The library once used -1 as a generic error return value on numerous places - through the code, which subsequently was converted to - LIBSSH2_ERROR_SOCKET_NONE uses over time. As this is a generic error code, - the goal is to never ever return this code but instead make sure that a - more accurate and descriptive error code is used. */ -#define LIBSSH2_ERROR_SOCKET_NONE -1 - -#define LIBSSH2_ERROR_BANNER_RECV -2 -#define LIBSSH2_ERROR_BANNER_SEND -3 -#define LIBSSH2_ERROR_INVALID_MAC -4 -#define LIBSSH2_ERROR_KEX_FAILURE -5 -#define LIBSSH2_ERROR_ALLOC -6 -#define LIBSSH2_ERROR_SOCKET_SEND -7 -#define LIBSSH2_ERROR_KEY_EXCHANGE_FAILURE -8 -#define LIBSSH2_ERROR_TIMEOUT -9 -#define LIBSSH2_ERROR_HOSTKEY_INIT -10 -#define LIBSSH2_ERROR_HOSTKEY_SIGN -11 -#define LIBSSH2_ERROR_DECRYPT -12 -#define LIBSSH2_ERROR_SOCKET_DISCONNECT -13 -#define LIBSSH2_ERROR_PROTO -14 -#define LIBSSH2_ERROR_PASSWORD_EXPIRED -15 -#define LIBSSH2_ERROR_FILE -16 -#define LIBSSH2_ERROR_METHOD_NONE -17 -#define LIBSSH2_ERROR_AUTHENTICATION_FAILED -18 -#define LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED \ - LIBSSH2_ERROR_AUTHENTICATION_FAILED -#define LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED -19 -#define LIBSSH2_ERROR_CHANNEL_OUTOFORDER -20 -#define LIBSSH2_ERROR_CHANNEL_FAILURE -21 -#define LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED -22 -#define LIBSSH2_ERROR_CHANNEL_UNKNOWN -23 -#define LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED -24 -#define LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED -25 -#define LIBSSH2_ERROR_CHANNEL_CLOSED -26 -#define LIBSSH2_ERROR_CHANNEL_EOF_SENT -27 -#define LIBSSH2_ERROR_SCP_PROTOCOL -28 -#define LIBSSH2_ERROR_ZLIB -29 -#define LIBSSH2_ERROR_SOCKET_TIMEOUT -30 -#define LIBSSH2_ERROR_SFTP_PROTOCOL -31 -#define LIBSSH2_ERROR_REQUEST_DENIED -32 -#define LIBSSH2_ERROR_METHOD_NOT_SUPPORTED -33 -#define LIBSSH2_ERROR_INVAL -34 -#define LIBSSH2_ERROR_INVALID_POLL_TYPE -35 -#define LIBSSH2_ERROR_PUBLICKEY_PROTOCOL -36 -#define LIBSSH2_ERROR_EAGAIN -37 -#define LIBSSH2_ERROR_BUFFER_TOO_SMALL -38 -#define LIBSSH2_ERROR_BAD_USE -39 -#define LIBSSH2_ERROR_COMPRESS -40 -#define LIBSSH2_ERROR_OUT_OF_BOUNDARY -41 -#define LIBSSH2_ERROR_AGENT_PROTOCOL -42 -#define LIBSSH2_ERROR_SOCKET_RECV -43 -#define LIBSSH2_ERROR_ENCRYPT -44 -#define LIBSSH2_ERROR_BAD_SOCKET -45 -#define LIBSSH2_ERROR_KNOWN_HOSTS -46 -#define LIBSSH2_ERROR_CHANNEL_WINDOW_FULL -47 -#define LIBSSH2_ERROR_KEYFILE_AUTH_FAILED -48 - -/* this is a define to provide the old (<= 1.2.7) name */ -#define LIBSSH2_ERROR_BANNER_NONE LIBSSH2_ERROR_BANNER_RECV - -/* Global API */ -#define LIBSSH2_INIT_NO_CRYPTO 0x0001 - -/* - * libssh2_init() - * - * Initialize the libssh2 functions. This typically initialize the - * crypto library. It uses a global state, and is not thread safe -- - * you must make sure this function is not called concurrently. - * - * Flags can be: - * 0: Normal initialize - * LIBSSH2_INIT_NO_CRYPTO: Do not initialize the crypto library (ie. - * OPENSSL_add_cipher_algoritms() for OpenSSL - * - * Returns 0 if succeeded, or a negative value for error. - */ -LIBSSH2_API int libssh2_init(int flags); - -/* - * libssh2_exit() - * - * Exit the libssh2 functions and free's all memory used internal. - */ -LIBSSH2_API void libssh2_exit(void); - -/* - * libssh2_free() - * - * Deallocate memory allocated by earlier call to libssh2 functions. - */ -LIBSSH2_API void libssh2_free(LIBSSH2_SESSION *session, void *ptr); - -/* - * libssh2_session_supported_algs() - * - * Fills algs with a list of supported acryptographic algorithms. Returns a - * non-negative number (number of supported algorithms) on success or a - * negative number (an error code) on failure. - * - * NOTE: on success, algs must be deallocated (by calling libssh2_free) when - * not needed anymore - */ -LIBSSH2_API int libssh2_session_supported_algs(LIBSSH2_SESSION* session, - int method_type, - const char ***algs); - -/* Session API */ -LIBSSH2_API LIBSSH2_SESSION * -libssh2_session_init_ex(LIBSSH2_ALLOC_FUNC((*my_alloc)), - LIBSSH2_FREE_FUNC((*my_free)), - LIBSSH2_REALLOC_FUNC((*my_realloc)), void *abstract); -#define libssh2_session_init() libssh2_session_init_ex(NULL, NULL, NULL, NULL) - -LIBSSH2_API void **libssh2_session_abstract(LIBSSH2_SESSION *session); - -LIBSSH2_API void *libssh2_session_callback_set(LIBSSH2_SESSION *session, - int cbtype, void *callback); -LIBSSH2_API int libssh2_session_banner_set(LIBSSH2_SESSION *session, - const char *banner); -LIBSSH2_API int libssh2_banner_set(LIBSSH2_SESSION *session, - const char *banner); - -LIBSSH2_API int libssh2_session_startup(LIBSSH2_SESSION *session, int sock); -LIBSSH2_API int libssh2_session_handshake(LIBSSH2_SESSION *session, - libssh2_socket_t sock); -LIBSSH2_API int libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, - int reason, - const char *description, - const char *lang); -#define libssh2_session_disconnect(session, description) \ - libssh2_session_disconnect_ex((session), SSH_DISCONNECT_BY_APPLICATION, \ - (description), "") - -LIBSSH2_API int libssh2_session_free(LIBSSH2_SESSION *session); - -LIBSSH2_API const char *libssh2_hostkey_hash(LIBSSH2_SESSION *session, - int hash_type); - -LIBSSH2_API const char *libssh2_session_hostkey(LIBSSH2_SESSION *session, - size_t *len, int *type); - -LIBSSH2_API int libssh2_session_method_pref(LIBSSH2_SESSION *session, - int method_type, - const char *prefs); -LIBSSH2_API const char *libssh2_session_methods(LIBSSH2_SESSION *session, - int method_type); -LIBSSH2_API int libssh2_session_last_error(LIBSSH2_SESSION *session, - char **errmsg, - int *errmsg_len, int want_buf); -LIBSSH2_API int libssh2_session_last_errno(LIBSSH2_SESSION *session); -LIBSSH2_API int libssh2_session_set_last_error(LIBSSH2_SESSION* session, - int errcode, - const char *errmsg); -LIBSSH2_API int libssh2_session_block_directions(LIBSSH2_SESSION *session); - -LIBSSH2_API int libssh2_session_flag(LIBSSH2_SESSION *session, int flag, - int value); -LIBSSH2_API const char *libssh2_session_banner_get(LIBSSH2_SESSION *session); - -/* Userauth API */ -LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, - const char *username, - unsigned int username_len); -LIBSSH2_API int libssh2_userauth_authenticated(LIBSSH2_SESSION *session); - -LIBSSH2_API int -libssh2_userauth_password_ex(LIBSSH2_SESSION *session, - const char *username, - unsigned int username_len, - const char *password, - unsigned int password_len, - LIBSSH2_PASSWD_CHANGEREQ_FUNC - ((*passwd_change_cb))); - -#define libssh2_userauth_password(session, username, password) \ - libssh2_userauth_password_ex((session), (username), \ - (unsigned int)strlen(username), \ - (password), (unsigned int)strlen(password), NULL) - -LIBSSH2_API int -libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, - const char *username, - unsigned int username_len, - const char *publickey, - const char *privatekey, - const char *passphrase); - -#define libssh2_userauth_publickey_fromfile(session, username, publickey, \ - privatekey, passphrase) \ - libssh2_userauth_publickey_fromfile_ex((session), (username), \ - (unsigned int)strlen(username), \ - (publickey), \ - (privatekey), (passphrase)) - -LIBSSH2_API int -libssh2_userauth_publickey(LIBSSH2_SESSION *session, - const char *username, - const unsigned char *pubkeydata, - size_t pubkeydata_len, - LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC - ((*sign_callback)), - void **abstract); - -LIBSSH2_API int -libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session, - const char *username, - unsigned int username_len, - const char *publickey, - const char *privatekey, - const char *passphrase, - const char *hostname, - unsigned int hostname_len, - const char *local_username, - unsigned int local_username_len); - -#define libssh2_userauth_hostbased_fromfile(session, username, publickey, \ - privatekey, passphrase, hostname) \ - libssh2_userauth_hostbased_fromfile_ex((session), (username), \ - (unsigned int)strlen(username), \ - (publickey), \ - (privatekey), (passphrase), \ - (hostname), \ - (unsigned int)strlen(hostname), \ - (username), \ - (unsigned int)strlen(username)) - -LIBSSH2_API int -libssh2_userauth_publickey_frommemory(LIBSSH2_SESSION *session, - const char *username, - size_t username_len, - const char *publickeyfiledata, - size_t publickeyfiledata_len, - const char *privatekeyfiledata, - size_t privatekeyfiledata_len, - const char *passphrase); - -/* - * response_callback is provided with filled by library prompts array, - * but client must allocate and fill individual responses. Responses - * array is already allocated. Responses data will be freed by libssh2 - * after callback return, but before subsequent callback invocation. - */ -LIBSSH2_API int -libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION* session, - const char *username, - unsigned int username_len, - LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC( - (*response_callback))); - -#define libssh2_userauth_keyboard_interactive(session, username, \ - response_callback) \ - libssh2_userauth_keyboard_interactive_ex((session), (username), \ - (unsigned int)strlen(username), \ - (response_callback)) - -LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds, - long timeout); - -/* Channel API */ -#define LIBSSH2_CHANNEL_WINDOW_DEFAULT (2*1024*1024) -#define LIBSSH2_CHANNEL_PACKET_DEFAULT 32768 -#define LIBSSH2_CHANNEL_MINADJUST 1024 - -/* Extended Data Handling */ -#define LIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL 0 -#define LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE 1 -#define LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE 2 - -#define SSH_EXTENDED_DATA_STDERR 1 - -/* Returned by any function that would block during a read/write operation */ -#define LIBSSH2CHANNEL_EAGAIN LIBSSH2_ERROR_EAGAIN - -LIBSSH2_API LIBSSH2_CHANNEL * -libssh2_channel_open_ex(LIBSSH2_SESSION *session, const char *channel_type, - unsigned int channel_type_len, - unsigned int window_size, unsigned int packet_size, - const char *message, unsigned int message_len); - -#define libssh2_channel_open_session(session) \ - libssh2_channel_open_ex((session), "session", sizeof("session") - 1, \ - LIBSSH2_CHANNEL_WINDOW_DEFAULT, \ - LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0) - -LIBSSH2_API LIBSSH2_CHANNEL * -libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *session, const char *host, - int port, const char *shost, int sport); -#define libssh2_channel_direct_tcpip(session, host, port) \ - libssh2_channel_direct_tcpip_ex((session), (host), (port), "127.0.0.1", 22) - -LIBSSH2_API LIBSSH2_LISTENER * -libssh2_channel_forward_listen_ex(LIBSSH2_SESSION *session, const char *host, - int port, int *bound_port, - int queue_maxsize); -#define libssh2_channel_forward_listen(session, port) \ - libssh2_channel_forward_listen_ex((session), NULL, (port), NULL, 16) - -LIBSSH2_API int libssh2_channel_forward_cancel(LIBSSH2_LISTENER *listener); - -LIBSSH2_API LIBSSH2_CHANNEL * -libssh2_channel_forward_accept(LIBSSH2_LISTENER *listener); - -LIBSSH2_API int libssh2_channel_setenv_ex(LIBSSH2_CHANNEL *channel, - const char *varname, - unsigned int varname_len, - const char *value, - unsigned int value_len); - -#define libssh2_channel_setenv(channel, varname, value) \ - libssh2_channel_setenv_ex((channel), (varname), \ - (unsigned int)strlen(varname), (value), \ - (unsigned int)strlen(value)) - -LIBSSH2_API int libssh2_channel_request_auth_agent(LIBSSH2_CHANNEL *channel); - -LIBSSH2_API int libssh2_channel_request_pty_ex(LIBSSH2_CHANNEL *channel, - const char *term, - unsigned int term_len, - const char *modes, - unsigned int modes_len, - int width, int height, - int width_px, int height_px); -#define libssh2_channel_request_pty(channel, term) \ - libssh2_channel_request_pty_ex((channel), (term), \ - (unsigned int)strlen(term), \ - NULL, 0, \ - LIBSSH2_TERM_WIDTH, \ - LIBSSH2_TERM_HEIGHT, \ - LIBSSH2_TERM_WIDTH_PX, \ - LIBSSH2_TERM_HEIGHT_PX) - -LIBSSH2_API int libssh2_channel_request_pty_size_ex(LIBSSH2_CHANNEL *channel, - int width, int height, - int width_px, - int height_px); -#define libssh2_channel_request_pty_size(channel, width, height) \ - libssh2_channel_request_pty_size_ex((channel), (width), (height), 0, 0) - -LIBSSH2_API int libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL *channel, - int single_connection, - const char *auth_proto, - const char *auth_cookie, - int screen_number); -#define libssh2_channel_x11_req(channel, screen_number) \ - libssh2_channel_x11_req_ex((channel), 0, NULL, NULL, (screen_number)) - -LIBSSH2_API int libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, - const char *request, - unsigned int request_len, - const char *message, - unsigned int message_len); -#define libssh2_channel_shell(channel) \ - libssh2_channel_process_startup((channel), "shell", sizeof("shell") - 1, \ - NULL, 0) -#define libssh2_channel_exec(channel, command) \ - libssh2_channel_process_startup((channel), "exec", sizeof("exec") - 1, \ - (command), (unsigned int)strlen(command)) -#define libssh2_channel_subsystem(channel, subsystem) \ - libssh2_channel_process_startup((channel), "subsystem", \ - sizeof("subsystem") - 1, (subsystem), \ - (unsigned int)strlen(subsystem)) - -LIBSSH2_API ssize_t libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, - int stream_id, char *buf, - size_t buflen); -#define libssh2_channel_read(channel, buf, buflen) \ - libssh2_channel_read_ex((channel), 0, (buf), (buflen)) -#define libssh2_channel_read_stderr(channel, buf, buflen) \ - libssh2_channel_read_ex((channel), SSH_EXTENDED_DATA_STDERR, (buf), (buflen)) - -LIBSSH2_API int libssh2_poll_channel_read(LIBSSH2_CHANNEL *channel, - int extended); - -LIBSSH2_API unsigned long -libssh2_channel_window_read_ex(LIBSSH2_CHANNEL *channel, - unsigned long *read_avail, - unsigned long *window_size_initial); -#define libssh2_channel_window_read(channel) \ - libssh2_channel_window_read_ex((channel), NULL, NULL) - -/* libssh2_channel_receive_window_adjust is DEPRECATED, do not use! */ -LIBSSH2_API unsigned long -libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL *channel, - unsigned long adjustment, - unsigned char force); - -LIBSSH2_API int -libssh2_channel_receive_window_adjust2(LIBSSH2_CHANNEL *channel, - unsigned long adjustment, - unsigned char force, - unsigned int *storewindow); - -LIBSSH2_API ssize_t libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel, - int stream_id, const char *buf, - size_t buflen); - -#define libssh2_channel_write(channel, buf, buflen) \ - libssh2_channel_write_ex((channel), 0, (buf), (buflen)) -#define libssh2_channel_write_stderr(channel, buf, buflen) \ - libssh2_channel_write_ex((channel), SSH_EXTENDED_DATA_STDERR, \ - (buf), (buflen)) - -LIBSSH2_API unsigned long -libssh2_channel_window_write_ex(LIBSSH2_CHANNEL *channel, - unsigned long *window_size_initial); -#define libssh2_channel_window_write(channel) \ - libssh2_channel_window_write_ex((channel), NULL) - -LIBSSH2_API void libssh2_session_set_blocking(LIBSSH2_SESSION* session, - int blocking); -LIBSSH2_API int libssh2_session_get_blocking(LIBSSH2_SESSION* session); - -LIBSSH2_API void libssh2_channel_set_blocking(LIBSSH2_CHANNEL *channel, - int blocking); - -LIBSSH2_API void libssh2_session_set_timeout(LIBSSH2_SESSION* session, - long timeout); -LIBSSH2_API long libssh2_session_get_timeout(LIBSSH2_SESSION* session); - -/* libssh2_channel_handle_extended_data is DEPRECATED, do not use! */ -LIBSSH2_API void libssh2_channel_handle_extended_data(LIBSSH2_CHANNEL *channel, - int ignore_mode); -LIBSSH2_API int libssh2_channel_handle_extended_data2(LIBSSH2_CHANNEL *channel, - int ignore_mode); - -/* libssh2_channel_ignore_extended_data() is defined below for BC with version - * 0.1 - * - * Future uses should use libssh2_channel_handle_extended_data() directly if - * LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE is passed, extended data will be read - * (FIFO) from the standard data channel - */ -/* DEPRECATED */ -#define libssh2_channel_ignore_extended_data(channel, ignore) \ - libssh2_channel_handle_extended_data((channel), \ - (ignore) ? \ - LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE : \ - LIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL) - -#define LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA -1 -#define LIBSSH2_CHANNEL_FLUSH_ALL -2 -LIBSSH2_API int libssh2_channel_flush_ex(LIBSSH2_CHANNEL *channel, - int streamid); -#define libssh2_channel_flush(channel) libssh2_channel_flush_ex((channel), 0) -#define libssh2_channel_flush_stderr(channel) \ - libssh2_channel_flush_ex((channel), SSH_EXTENDED_DATA_STDERR) - -LIBSSH2_API int libssh2_channel_get_exit_status(LIBSSH2_CHANNEL* channel); -LIBSSH2_API int libssh2_channel_get_exit_signal(LIBSSH2_CHANNEL* channel, - char **exitsignal, - size_t *exitsignal_len, - char **errmsg, - size_t *errmsg_len, - char **langtag, - size_t *langtag_len); -LIBSSH2_API int libssh2_channel_send_eof(LIBSSH2_CHANNEL *channel); -LIBSSH2_API int libssh2_channel_eof(LIBSSH2_CHANNEL *channel); -LIBSSH2_API int libssh2_channel_wait_eof(LIBSSH2_CHANNEL *channel); -LIBSSH2_API int libssh2_channel_close(LIBSSH2_CHANNEL *channel); -LIBSSH2_API int libssh2_channel_wait_closed(LIBSSH2_CHANNEL *channel); -LIBSSH2_API int libssh2_channel_free(LIBSSH2_CHANNEL *channel); - -/* libssh2_scp_recv is DEPRECATED, do not use! */ -LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, - const char *path, - struct stat *sb); -/* Use libssh2_scp_recv2 for large (> 2GB) file support on windows */ -LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv2(LIBSSH2_SESSION *session, - const char *path, - libssh2_struct_stat *sb); -LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, - const char *path, int mode, - size_t size, long mtime, - long atime); -LIBSSH2_API LIBSSH2_CHANNEL * -libssh2_scp_send64(LIBSSH2_SESSION *session, const char *path, int mode, - libssh2_int64_t size, time_t mtime, time_t atime); - -#define libssh2_scp_send(session, path, mode, size) \ - libssh2_scp_send_ex((session), (path), (mode), (size), 0, 0) - -LIBSSH2_API int libssh2_base64_decode(LIBSSH2_SESSION *session, char **dest, - unsigned int *dest_len, - const char *src, unsigned int src_len); - -LIBSSH2_API -const char *libssh2_version(int req_version_num); - -#define HAVE_LIBSSH2_KNOWNHOST_API 0x010101 /* since 1.1.1 */ -#define HAVE_LIBSSH2_VERSION_API 0x010100 /* libssh2_version since 1.1 */ - -struct libssh2_knownhost { - unsigned int magic; /* magic stored by the library */ - void *node; /* handle to the internal representation of this host */ - char *name; /* this is NULL if no plain text host name exists */ - char *key; /* key in base64/printable format */ - int typemask; -}; - -/* - * libssh2_knownhost_init - * - * Init a collection of known hosts. Returns the pointer to a collection. - * - */ -LIBSSH2_API LIBSSH2_KNOWNHOSTS * -libssh2_knownhost_init(LIBSSH2_SESSION *session); - -/* - * libssh2_knownhost_add - * - * Add a host and its associated key to the collection of known hosts. - * - * The 'type' argument specifies on what format the given host and keys are: - * - * plain - ascii "hostname.domain.tld" - * sha1 - SHA1( ) base64-encoded! - * custom - another hash - * - * If 'sha1' is selected as type, the salt must be provided to the salt - * argument. This too base64 encoded. - * - * The SHA-1 hash is what OpenSSH can be told to use in known_hosts files. If - * a custom type is used, salt is ignored and you must provide the host - * pre-hashed when checking for it in the libssh2_knownhost_check() function. - * - * The keylen parameter may be omitted (zero) if the key is provided as a - * NULL-terminated base64-encoded string. - */ - -/* host format (2 bits) */ -#define LIBSSH2_KNOWNHOST_TYPE_MASK 0xffff -#define LIBSSH2_KNOWNHOST_TYPE_PLAIN 1 -#define LIBSSH2_KNOWNHOST_TYPE_SHA1 2 /* always base64 encoded */ -#define LIBSSH2_KNOWNHOST_TYPE_CUSTOM 3 - -/* key format (2 bits) */ -#define LIBSSH2_KNOWNHOST_KEYENC_MASK (3<<16) -#define LIBSSH2_KNOWNHOST_KEYENC_RAW (1<<16) -#define LIBSSH2_KNOWNHOST_KEYENC_BASE64 (2<<16) - -/* type of key (4 bits) */ -#define LIBSSH2_KNOWNHOST_KEY_MASK (15<<18) -#define LIBSSH2_KNOWNHOST_KEY_SHIFT 18 -#define LIBSSH2_KNOWNHOST_KEY_RSA1 (1<<18) -#define LIBSSH2_KNOWNHOST_KEY_SSHRSA (2<<18) -#define LIBSSH2_KNOWNHOST_KEY_SSHDSS (3<<18) -#define LIBSSH2_KNOWNHOST_KEY_ECDSA_256 (4<<18) -#define LIBSSH2_KNOWNHOST_KEY_ECDSA_384 (5<<18) -#define LIBSSH2_KNOWNHOST_KEY_ECDSA_521 (6<<18) -#define LIBSSH2_KNOWNHOST_KEY_ED25519 (7<<18) -#define LIBSSH2_KNOWNHOST_KEY_UNKNOWN (15<<18) - -LIBSSH2_API int -libssh2_knownhost_add(LIBSSH2_KNOWNHOSTS *hosts, - const char *host, - const char *salt, - const char *key, size_t keylen, int typemask, - struct libssh2_knownhost **store); - -/* - * libssh2_knownhost_addc - * - * Add a host and its associated key to the collection of known hosts. - * - * Takes a comment argument that may be NULL. A NULL comment indicates - * there is no comment and the entry will end directly after the key - * when written out to a file. An empty string "" comment will indicate an - * empty comment which will cause a single space to be written after the key. - * - * The 'type' argument specifies on what format the given host and keys are: - * - * plain - ascii "hostname.domain.tld" - * sha1 - SHA1( ) base64-encoded! - * custom - another hash - * - * If 'sha1' is selected as type, the salt must be provided to the salt - * argument. This too base64 encoded. - * - * The SHA-1 hash is what OpenSSH can be told to use in known_hosts files. If - * a custom type is used, salt is ignored and you must provide the host - * pre-hashed when checking for it in the libssh2_knownhost_check() function. - * - * The keylen parameter may be omitted (zero) if the key is provided as a - * NULL-terminated base64-encoded string. - */ - -LIBSSH2_API int -libssh2_knownhost_addc(LIBSSH2_KNOWNHOSTS *hosts, - const char *host, - const char *salt, - const char *key, size_t keylen, - const char *comment, size_t commentlen, int typemask, - struct libssh2_knownhost **store); - -/* - * libssh2_knownhost_check - * - * Check a host and its associated key against the collection of known hosts. - * - * The type is the type/format of the given host name. - * - * plain - ascii "hostname.domain.tld" - * custom - prehashed base64 encoded. Note that this cannot use any salts. - * - * - * 'knownhost' may be set to NULL if you don't care about that info. - * - * Returns: - * - * LIBSSH2_KNOWNHOST_CHECK_* values, see below - * - */ - -#define LIBSSH2_KNOWNHOST_CHECK_MATCH 0 -#define LIBSSH2_KNOWNHOST_CHECK_MISMATCH 1 -#define LIBSSH2_KNOWNHOST_CHECK_NOTFOUND 2 -#define LIBSSH2_KNOWNHOST_CHECK_FAILURE 3 - -LIBSSH2_API int -libssh2_knownhost_check(LIBSSH2_KNOWNHOSTS *hosts, - const char *host, const char *key, size_t keylen, - int typemask, - struct libssh2_knownhost **knownhost); - -/* this function is identital to the above one, but also takes a port - argument that allows libssh2 to do a better check */ -LIBSSH2_API int -libssh2_knownhost_checkp(LIBSSH2_KNOWNHOSTS *hosts, - const char *host, int port, - const char *key, size_t keylen, - int typemask, - struct libssh2_knownhost **knownhost); - -/* - * libssh2_knownhost_del - * - * Remove a host from the collection of known hosts. The 'entry' struct is - * retrieved by a call to libssh2_knownhost_check(). - * - */ -LIBSSH2_API int -libssh2_knownhost_del(LIBSSH2_KNOWNHOSTS *hosts, - struct libssh2_knownhost *entry); - -/* - * libssh2_knownhost_free - * - * Free an entire collection of known hosts. - * - */ -LIBSSH2_API void -libssh2_knownhost_free(LIBSSH2_KNOWNHOSTS *hosts); - -/* - * libssh2_knownhost_readline() - * - * Pass in a line of a file of 'type'. It makes libssh2 read this line. - * - * LIBSSH2_KNOWNHOST_FILE_OPENSSH is the only supported type. - * - */ -LIBSSH2_API int -libssh2_knownhost_readline(LIBSSH2_KNOWNHOSTS *hosts, - const char *line, size_t len, int type); - -/* - * libssh2_knownhost_readfile - * - * Add hosts+key pairs from a given file. - * - * Returns a negative value for error or number of successfully added hosts. - * - * This implementation currently only knows one 'type' (openssh), all others - * are reserved for future use. - */ - -#define LIBSSH2_KNOWNHOST_FILE_OPENSSH 1 - -LIBSSH2_API int -libssh2_knownhost_readfile(LIBSSH2_KNOWNHOSTS *hosts, - const char *filename, int type); - -/* - * libssh2_knownhost_writeline() - * - * Ask libssh2 to convert a known host to an output line for storage. - * - * Note that this function returns LIBSSH2_ERROR_BUFFER_TOO_SMALL if the given - * output buffer is too small to hold the desired output. - * - * This implementation currently only knows one 'type' (openssh), all others - * are reserved for future use. - * - */ -LIBSSH2_API int -libssh2_knownhost_writeline(LIBSSH2_KNOWNHOSTS *hosts, - struct libssh2_knownhost *known, - char *buffer, size_t buflen, - size_t *outlen, /* the amount of written data */ - int type); - -/* - * libssh2_knownhost_writefile - * - * Write hosts+key pairs to a given file. - * - * This implementation currently only knows one 'type' (openssh), all others - * are reserved for future use. - */ - -LIBSSH2_API int -libssh2_knownhost_writefile(LIBSSH2_KNOWNHOSTS *hosts, - const char *filename, int type); - -/* - * libssh2_knownhost_get() - * - * Traverse the internal list of known hosts. Pass NULL to 'prev' to get - * the first one. Or pass a pointer to the previously returned one to get the - * next. - * - * Returns: - * 0 if a fine host was stored in 'store' - * 1 if end of hosts - * [negative] on errors - */ -LIBSSH2_API int -libssh2_knownhost_get(LIBSSH2_KNOWNHOSTS *hosts, - struct libssh2_knownhost **store, - struct libssh2_knownhost *prev); - -#define HAVE_LIBSSH2_AGENT_API 0x010202 /* since 1.2.2 */ - -struct libssh2_agent_publickey { - unsigned int magic; /* magic stored by the library */ - void *node; /* handle to the internal representation of key */ - unsigned char *blob; /* public key blob */ - size_t blob_len; /* length of the public key blob */ - char *comment; /* comment in printable format */ -}; - -/* - * libssh2_agent_init - * - * Init an ssh-agent handle. Returns the pointer to the handle. - * - */ -LIBSSH2_API LIBSSH2_AGENT * -libssh2_agent_init(LIBSSH2_SESSION *session); - -/* - * libssh2_agent_connect() - * - * Connect to an ssh-agent. - * - * Returns 0 if succeeded, or a negative value for error. - */ -LIBSSH2_API int -libssh2_agent_connect(LIBSSH2_AGENT *agent); - -/* - * libssh2_agent_list_identities() - * - * Request an ssh-agent to list identities. - * - * Returns 0 if succeeded, or a negative value for error. - */ -LIBSSH2_API int -libssh2_agent_list_identities(LIBSSH2_AGENT *agent); - -/* - * libssh2_agent_get_identity() - * - * Traverse the internal list of public keys. Pass NULL to 'prev' to get - * the first one. Or pass a pointer to the previously returned one to get the - * next. - * - * Returns: - * 0 if a fine public key was stored in 'store' - * 1 if end of public keys - * [negative] on errors - */ -LIBSSH2_API int -libssh2_agent_get_identity(LIBSSH2_AGENT *agent, - struct libssh2_agent_publickey **store, - struct libssh2_agent_publickey *prev); - -/* - * libssh2_agent_userauth() - * - * Do publickey user authentication with the help of ssh-agent. - * - * Returns 0 if succeeded, or a negative value for error. - */ -LIBSSH2_API int -libssh2_agent_userauth(LIBSSH2_AGENT *agent, - const char *username, - struct libssh2_agent_publickey *identity); - -/* - * libssh2_agent_disconnect() - * - * Close a connection to an ssh-agent. - * - * Returns 0 if succeeded, or a negative value for error. - */ -LIBSSH2_API int -libssh2_agent_disconnect(LIBSSH2_AGENT *agent); - -/* - * libssh2_agent_free() - * - * Free an ssh-agent handle. This function also frees the internal - * collection of public keys. - */ -LIBSSH2_API void -libssh2_agent_free(LIBSSH2_AGENT *agent); - -/* - * libssh2_agent_set_identity_path() - * - * Allows a custom agent identity socket path beyond SSH_AUTH_SOCK env - * - */ -LIBSSH2_API void -libssh2_agent_set_identity_path(LIBSSH2_AGENT *agent, - const char *path); - -/* - * libssh2_agent_get_identity_path() - * - * Returns the custom agent identity socket path if set - * - */ -LIBSSH2_API const char * -libssh2_agent_get_identity_path(LIBSSH2_AGENT *agent); - -/* - * libssh2_keepalive_config() - * - * Set how often keepalive messages should be sent. WANT_REPLY - * indicates whether the keepalive messages should request a response - * from the server. INTERVAL is number of seconds that can pass - * without any I/O, use 0 (the default) to disable keepalives. To - * avoid some busy-loop corner-cases, if you specify an interval of 1 - * it will be treated as 2. - * - * Note that non-blocking applications are responsible for sending the - * keepalive messages using libssh2_keepalive_send(). - */ -LIBSSH2_API void libssh2_keepalive_config(LIBSSH2_SESSION *session, - int want_reply, - unsigned interval); - -/* - * libssh2_keepalive_send() - * - * Send a keepalive message if needed. SECONDS_TO_NEXT indicates how - * many seconds you can sleep after this call before you need to call - * it again. Returns 0 on success, or LIBSSH2_ERROR_SOCKET_SEND on - * I/O errors. - */ -LIBSSH2_API int libssh2_keepalive_send(LIBSSH2_SESSION *session, - int *seconds_to_next); - -/* NOTE NOTE NOTE - libssh2_trace() has no function in builds that aren't built with debug - enabled - */ -LIBSSH2_API int libssh2_trace(LIBSSH2_SESSION *session, int bitmask); -#define LIBSSH2_TRACE_TRANS (1<<1) -#define LIBSSH2_TRACE_KEX (1<<2) -#define LIBSSH2_TRACE_AUTH (1<<3) -#define LIBSSH2_TRACE_CONN (1<<4) -#define LIBSSH2_TRACE_SCP (1<<5) -#define LIBSSH2_TRACE_SFTP (1<<6) -#define LIBSSH2_TRACE_ERROR (1<<7) -#define LIBSSH2_TRACE_PUBLICKEY (1<<8) -#define LIBSSH2_TRACE_SOCKET (1<<9) - -typedef void (*libssh2_trace_handler_func)(LIBSSH2_SESSION*, - void *, - const char *, - size_t); -LIBSSH2_API int libssh2_trace_sethandler(LIBSSH2_SESSION *session, - void *context, - libssh2_trace_handler_func callback); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* !RC_INVOKED */ - -#endif /* LIBSSH2_H */ diff --git a/include/libssh2/libssh2_config.h b/include/libssh2/libssh2_config.h deleted file mode 100644 index 6ac2ef4..0000000 --- a/include/libssh2/libssh2_config.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef LIBSSH2_CONFIG_H -#define LIBSSH2_CONFIG_H - -#ifndef WIN32 -#define WIN32 -#endif -#ifndef _CRT_SECURE_NO_DEPRECATE -#define _CRT_SECURE_NO_DEPRECATE 1 -#endif /* _CRT_SECURE_NO_DEPRECATE */ -#include -#include -#include - -#ifdef __MINGW32__ -#define HAVE_UNISTD_H -#define HAVE_INTTYPES_H -#define HAVE_SYS_TIME_H -#define HAVE_GETTIMEOFDAY -#endif /* __MINGW32__ */ - -#define HAVE_LIBCRYPT32 -#define HAVE_WINSOCK2_H -#define HAVE_IOCTLSOCKET -#define HAVE_SELECT - -#ifdef _MSC_VER -#if _MSC_VER < 1900 -#define snprintf _snprintf -#if _MSC_VER < 1500 -#define vsnprintf _vsnprintf -#endif -#define strdup _strdup -#define strncasecmp _strnicmp -#define strcasecmp _stricmp -#endif -#else -#ifndef __MINGW32__ -#define strncasecmp strnicmp -#define strcasecmp stricmp -#endif /* __MINGW32__ */ -#endif /* _MSC_VER */ - -/* Enable newer diffie-hellman-group-exchange-sha1 syntax */ -#define LIBSSH2_DH_GEX_NEW 1 - -#endif /* LIBSSH2_CONFIG_H */ - diff --git a/include/libssh2/libssh2_config.h.in b/include/libssh2/libssh2_config.h.in deleted file mode 100644 index 6a52f0c..0000000 --- a/include/libssh2/libssh2_config.h.in +++ /dev/null @@ -1,223 +0,0 @@ -/* src/libssh2_config.h.in. Generated from configure.ac by autoheader. */ - -/* Define if building universal (internal helper macro) */ -#undef AC_APPLE_UNIVERSAL_BUILD - -/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP - systems. This function is required for `alloca.c' support on those systems. - */ -#undef CRAY_STACKSEG_END - -/* Define to 1 if using `alloca.c'. */ -#undef C_ALLOCA - -/* Define to 1 if you have `alloca', as a function or macro. */ -#undef HAVE_ALLOCA - -/* Define to 1 if you have and it should be used (not on Ultrix). - */ -#undef HAVE_ALLOCA_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_ARPA_INET_H - -/* disabled non-blocking sockets */ -#undef HAVE_DISABLED_NONBLOCKING - -/* Define to 1 if you have the header file. */ -#undef HAVE_DLFCN_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_ERRNO_H - -/* Define to 1 if you have the `EVP_aes_128_ctr' function. */ -#undef HAVE_EVP_AES_128_CTR - -/* Define to 1 if you have the header file. */ -#undef HAVE_FCNTL_H - -/* use FIONBIO for non-blocking sockets */ -#undef HAVE_FIONBIO - -/* Define to 1 if you have the `gettimeofday' function. */ -#undef HAVE_GETTIMEOFDAY - -/* Define to 1 if you have the header file. */ -#undef HAVE_INTTYPES_H - -/* use ioctlsocket() for non-blocking sockets */ -#undef HAVE_IOCTLSOCKET - -/* use Ioctlsocket() for non-blocking sockets */ -#undef HAVE_IOCTLSOCKET_CASE - -/* Define if you have the gcrypt library. */ -#undef HAVE_LIBGCRYPT - -/* Define if you have the ssl library. */ -#undef HAVE_LIBSSL - -/* Define if you have the z library. */ -#undef HAVE_LIBZ - -/* Define to 1 if the compiler supports the 'long long' data type. */ -#undef HAVE_LONGLONG - -/* Define to 1 if you have the header file. */ -#undef HAVE_MEMORY_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_NETINET_IN_H - -/* use O_NONBLOCK for non-blocking sockets */ -#undef HAVE_O_NONBLOCK - -/* Define to 1 if you have the `poll' function. */ -#undef HAVE_POLL - -/* Define to 1 if you have the select function. */ -#undef HAVE_SELECT - -/* use SO_NONBLOCK for non-blocking sockets */ -#undef HAVE_SO_NONBLOCK - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDINT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDIO_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDLIB_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRINGS_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRING_H - -/* Define to 1 if you have the `strtoll' function. */ -#undef HAVE_STRTOLL - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_IOCTL_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_SELECT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_SOCKET_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_STAT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_TIME_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_TYPES_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_UIO_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_UN_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_UNISTD_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_WINDOWS_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_WINSOCK2_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_WS2TCPIP_H - -/* to make a symbol visible */ -#undef LIBSSH2_API - -/* Enable "none" cipher -- NOT RECOMMENDED */ -#undef LIBSSH2_CRYPT_NONE - -/* Enable newer diffie-hellman-group-exchange-sha1 syntax */ -#undef LIBSSH2_DH_GEX_NEW - -/* Compile in zlib support */ -#undef LIBSSH2_HAVE_ZLIB - -/* Use libgcrypt */ -#undef LIBSSH2_LIBGCRYPT - -/* Enable "none" MAC -- NOT RECOMMENDED */ -#undef LIBSSH2_MAC_NONE - -/* Define to the sub-directory in which libtool stores uninstalled libraries. - */ -#undef LT_OBJDIR - -/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */ -#undef NEED_REENTRANT - -/* Name of package */ -#undef PACKAGE - -/* Define to the address where bug reports for this package should be sent. */ -#undef PACKAGE_BUGREPORT - -/* Define to the full name of this package. */ -#undef PACKAGE_NAME - -/* Define to the full name and version of this package. */ -#undef PACKAGE_STRING - -/* Define to the one symbol short name of this package. */ -#undef PACKAGE_TARNAME - -/* Define to the home page for this package. */ -#undef PACKAGE_URL - -/* Define to the version of this package. */ -#undef PACKAGE_VERSION - -/* If using the C implementation of alloca, define if you know the - direction of stack growth for your system; otherwise it will be - automatically deduced at runtime. - STACK_DIRECTION > 0 => grows toward higher addresses - STACK_DIRECTION < 0 => grows toward lower addresses - STACK_DIRECTION = 0 => direction of growth unknown */ -#undef STACK_DIRECTION - -/* Define to 1 if you have the ANSI C header files. */ -#undef STDC_HEADERS - -/* Version number of package */ -#undef VERSION - -/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most - significant byte first (like Motorola and SPARC, unlike Intel). */ -#if defined AC_APPLE_UNIVERSAL_BUILD -# if defined __BIG_ENDIAN__ -# define WORDS_BIGENDIAN 1 -# endif -#else -# ifndef WORDS_BIGENDIAN -# undef WORDS_BIGENDIAN -# endif -#endif - -/* Number of bits in a file offset, on hosts where this is settable. */ -#undef _FILE_OFFSET_BITS - -/* Define for large files, on AIX-style hosts. */ -#undef _LARGE_FILES - -/* Define to empty if `const' does not conform to ANSI C. */ -#undef const - -/* Define to `__inline__' or `__inline' if that's what the C compiler - calls it, or to nothing if 'inline' is not supported under any name. */ -#ifndef __cplusplus -#undef inline -#endif diff --git a/include/libssh2/libssh2_priv.h b/include/libssh2/libssh2_priv.h deleted file mode 100644 index 474698e..0000000 --- a/include/libssh2/libssh2_priv.h +++ /dev/null @@ -1,1149 +0,0 @@ -#ifndef __LIBSSH2_PRIV_H -#define __LIBSSH2_PRIV_H -/* Copyright (c) 2004-2008, 2010, Sara Golemon - * Copyright (c) 2009-2014 by Daniel Stenberg - * Copyright (c) 2010 Simon Josefsson - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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. - */ - -#define LIBSSH2_LIBRARY -#include "libssh2_config.h" - -#ifdef HAVE_WINDOWS_H -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#include -#undef WIN32_LEAN_AND_MEAN -#endif - -#ifdef HAVE_WS2TCPIP_H -#include -#endif - -#include -#include - -/* The following CPP block should really only be in session.c and packet.c. - However, AIX have #define's for 'events' and 'revents' and we are using - those names in libssh2.h, so we need to include the AIX headers first, to - make sure all code is compiled with consistent names of these fields. - While arguable the best would to change libssh2.h to use other names, that - would break backwards compatibility. -*/ -#ifdef HAVE_POLL -# include -#else -# if defined(HAVE_SELECT) && !defined(WIN32) -# ifdef HAVE_SYS_SELECT_H -# include -# else -# include -# include -# endif -# endif -#endif - -/* Needed for struct iovec on some platforms */ -#ifdef HAVE_SYS_UIO_H -#include -#endif - -#ifdef HAVE_SYS_SOCKET_H -# include -#endif -#ifdef HAVE_SYS_IOCTL_H -# include -#endif -#ifdef HAVE_INTTYPES_H -#include -#endif - -#include "libssh2.h" -#include "libssh2_publickey.h" -#include "libssh2_sftp.h" -#include "misc.h" /* for the linked list stuff */ - -#ifndef FALSE -#define FALSE 0 -#endif -#ifndef TRUE -#define TRUE 1 -#endif - -#ifdef _MSC_VER -/* "inline" keyword is valid only with C++ engine! */ -#define inline __inline -#endif - -/* Provide iovec / writev on WIN32 platform. */ -#ifdef WIN32 - -struct iovec { - size_t iov_len; - void *iov_base; -}; - -static inline int writev(int sock, struct iovec *iov, int nvecs) -{ - DWORD ret; - if(WSASend(sock, (LPWSABUF)iov, nvecs, &ret, 0, NULL, NULL) == 0) { - return ret; - } - return -1; -} - -#endif /* WIN32 */ - -#ifdef __OS400__ -/* Force parameter type. */ -#define send(s, b, l, f) send((s), (unsigned char *) (b), (l), (f)) -#endif - -#include "crypto.h" - -#ifdef HAVE_WINSOCK2_H - -#include -#include - -#endif - -#ifndef SIZE_MAX -#if _WIN64 -#define SIZE_MAX 0xFFFFFFFFFFFFFFFF -#else -#define SIZE_MAX 0xFFFFFFFF -#endif -#endif - -#ifndef UINT_MAX -#define UINT_MAX 0xFFFFFFFF -#endif - -/* RFC4253 section 6.1 Maximum Packet Length says: - * - * "All implementations MUST be able to process packets with - * uncompressed payload length of 32768 bytes or less and - * total packet size of 35000 bytes or less (including length, - * padding length, payload, padding, and MAC.)." - */ -#define MAX_SSH_PACKET_LEN 35000 -#define MAX_SHA_DIGEST_LEN SHA512_DIGEST_LENGTH - -#define LIBSSH2_ALLOC(session, count) \ - session->alloc((count), &(session)->abstract) -#define LIBSSH2_CALLOC(session, count) _libssh2_calloc(session, count) -#define LIBSSH2_REALLOC(session, ptr, count) \ - ((ptr) ? session->realloc((ptr), (count), &(session)->abstract) : \ - session->alloc((count), &(session)->abstract)) -#define LIBSSH2_FREE(session, ptr) \ - session->free((ptr), &(session)->abstract) -#define LIBSSH2_IGNORE(session, data, datalen) \ - session->ssh_msg_ignore((session), (data), (datalen), &(session)->abstract) -#define LIBSSH2_DEBUG(session, always_display, message, message_len, \ - language, language_len) \ - session->ssh_msg_debug((session), (always_display), (message), \ - (message_len), (language), (language_len), \ - &(session)->abstract) -#define LIBSSH2_DISCONNECT(session, reason, message, message_len, \ - language, language_len) \ - session->ssh_msg_disconnect((session), (reason), (message), \ - (message_len), (language), (language_len), \ - &(session)->abstract) - -#define LIBSSH2_MACERROR(session, data, datalen) \ - session->macerror((session), (data), (datalen), &(session)->abstract) -#define LIBSSH2_X11_OPEN(channel, shost, sport) \ - channel->session->x11(((channel)->session), (channel), \ - (shost), (sport), (&(channel)->session->abstract)) - -#define LIBSSH2_CHANNEL_CLOSE(session, channel) \ - channel->close_cb((session), &(session)->abstract, \ - (channel), &(channel)->abstract) - -#define LIBSSH2_SEND_FD(session, fd, buffer, length, flags) \ - (session->send)(fd, buffer, length, flags, &session->abstract) -#define LIBSSH2_RECV_FD(session, fd, buffer, length, flags) \ - (session->recv)(fd, buffer, length, flags, &session->abstract) - -#define LIBSSH2_SEND(session, buffer, length, flags) \ - LIBSSH2_SEND_FD(session, session->socket_fd, buffer, length, flags) -#define LIBSSH2_RECV(session, buffer, length, flags) \ - LIBSSH2_RECV_FD(session, session->socket_fd, buffer, length, flags) - -typedef struct _LIBSSH2_KEX_METHOD LIBSSH2_KEX_METHOD; -typedef struct _LIBSSH2_HOSTKEY_METHOD LIBSSH2_HOSTKEY_METHOD; -typedef struct _LIBSSH2_CRYPT_METHOD LIBSSH2_CRYPT_METHOD; -typedef struct _LIBSSH2_COMP_METHOD LIBSSH2_COMP_METHOD; - -typedef struct _LIBSSH2_PACKET LIBSSH2_PACKET; - -typedef enum -{ - libssh2_NB_state_idle = 0, - libssh2_NB_state_allocated, - libssh2_NB_state_created, - libssh2_NB_state_sent, - libssh2_NB_state_sent1, - libssh2_NB_state_sent2, - libssh2_NB_state_sent3, - libssh2_NB_state_sent4, - libssh2_NB_state_sent5, - libssh2_NB_state_sent6, - libssh2_NB_state_sent7, - libssh2_NB_state_jump1, - libssh2_NB_state_jump2, - libssh2_NB_state_jump3, - libssh2_NB_state_jump4, - libssh2_NB_state_jump5, - libssh2_NB_state_end -} libssh2_nonblocking_states; - -typedef struct packet_require_state_t -{ - libssh2_nonblocking_states state; - time_t start; -} packet_require_state_t; - -typedef struct packet_requirev_state_t -{ - time_t start; -} packet_requirev_state_t; - -typedef struct kmdhgGPshakex_state_t -{ - libssh2_nonblocking_states state; - unsigned char *e_packet; - unsigned char *s_packet; - unsigned char *tmp; - unsigned char h_sig_comp[MAX_SHA_DIGEST_LEN]; - unsigned char c; - size_t e_packet_len; - size_t s_packet_len; - size_t tmp_len; - _libssh2_bn_ctx *ctx; - _libssh2_dh_ctx x; - _libssh2_bn *e; - _libssh2_bn *f; - _libssh2_bn *k; - unsigned char *f_value; - unsigned char *k_value; - unsigned char *h_sig; - size_t f_value_len; - size_t k_value_len; - size_t h_sig_len; - void *exchange_hash; - packet_require_state_t req_state; - libssh2_nonblocking_states burn_state; -} kmdhgGPshakex_state_t; - -typedef struct key_exchange_state_low_t -{ - libssh2_nonblocking_states state; - packet_require_state_t req_state; - kmdhgGPshakex_state_t exchange_state; - _libssh2_bn *p; /* SSH2 defined value (p_value) */ - _libssh2_bn *g; /* SSH2 defined value (2) */ - unsigned char request[256]; /* Must fit EC_MAX_POINT_LEN + data */ - unsigned char *data; - size_t request_len; - size_t data_len; - _libssh2_ec_key *private_key; /* SSH2 ecdh private key */ - unsigned char *public_key_oct; /* SSH2 ecdh public key octal value */ - size_t public_key_oct_len; /* SSH2 ecdh public key octal value - length */ - unsigned char *curve25519_public_key; /* curve25519 public key, 32 - bytes */ - unsigned char *curve25519_private_key; /* curve25519 private key, 32 - bytes */ -} key_exchange_state_low_t; - -typedef struct key_exchange_state_t -{ - libssh2_nonblocking_states state; - packet_require_state_t req_state; - key_exchange_state_low_t key_state_low; - unsigned char *data; - size_t data_len; - unsigned char *oldlocal; - size_t oldlocal_len; -} key_exchange_state_t; - -#define FwdNotReq "Forward not requested" - -typedef struct packet_queue_listener_state_t -{ - libssh2_nonblocking_states state; - unsigned char packet[17 + (sizeof(FwdNotReq) - 1)]; - unsigned char *host; - unsigned char *shost; - uint32_t sender_channel; - uint32_t initial_window_size; - uint32_t packet_size; - uint32_t port; - uint32_t sport; - uint32_t host_len; - uint32_t shost_len; - LIBSSH2_CHANNEL *channel; -} packet_queue_listener_state_t; - -#define X11FwdUnAvil "X11 Forward Unavailable" - -typedef struct packet_x11_open_state_t -{ - libssh2_nonblocking_states state; - unsigned char packet[17 + (sizeof(X11FwdUnAvil) - 1)]; - unsigned char *shost; - uint32_t sender_channel; - uint32_t initial_window_size; - uint32_t packet_size; - uint32_t sport; - uint32_t shost_len; - LIBSSH2_CHANNEL *channel; -} packet_x11_open_state_t; - -struct _LIBSSH2_PACKET -{ - struct list_node node; /* linked list header */ - - /* the raw unencrypted payload */ - unsigned char *data; - size_t data_len; - - /* Where to start reading data from, - * used for channel data that's been partially consumed */ - size_t data_head; -}; - -typedef struct _libssh2_channel_data -{ - /* Identifier */ - uint32_t id; - - /* Limits and restrictions */ - uint32_t window_size_initial, window_size, packet_size; - - /* Set to 1 when CHANNEL_CLOSE / CHANNEL_EOF sent/received */ - char close, eof, extended_data_ignore_mode; -} libssh2_channel_data; - -struct _LIBSSH2_CHANNEL -{ - struct list_node node; - - unsigned char *channel_type; - unsigned channel_type_len; - - /* channel's program exit status */ - int exit_status; - - /* channel's program exit signal (without the SIG prefix) */ - char *exit_signal; - - libssh2_channel_data local, remote; - /* Amount of bytes to be refunded to receive window (but not yet sent) */ - uint32_t adjust_queue; - /* Data immediately available for reading */ - uint32_t read_avail; - - LIBSSH2_SESSION *session; - - void *abstract; - LIBSSH2_CHANNEL_CLOSE_FUNC((*close_cb)); - - /* State variables used in libssh2_channel_setenv_ex() */ - libssh2_nonblocking_states setenv_state; - unsigned char *setenv_packet; - size_t setenv_packet_len; - unsigned char setenv_local_channel[4]; - packet_requirev_state_t setenv_packet_requirev_state; - - /* State variables used in libssh2_channel_request_pty_ex() - libssh2_channel_request_pty_size_ex() */ - libssh2_nonblocking_states reqPTY_state; - unsigned char reqPTY_packet[41 + 256]; - size_t reqPTY_packet_len; - unsigned char reqPTY_local_channel[4]; - packet_requirev_state_t reqPTY_packet_requirev_state; - - /* State variables used in libssh2_channel_x11_req_ex() */ - libssh2_nonblocking_states reqX11_state; - unsigned char *reqX11_packet; - size_t reqX11_packet_len; - unsigned char reqX11_local_channel[4]; - packet_requirev_state_t reqX11_packet_requirev_state; - - /* State variables used in libssh2_channel_process_startup() */ - libssh2_nonblocking_states process_state; - unsigned char *process_packet; - size_t process_packet_len; - unsigned char process_local_channel[4]; - packet_requirev_state_t process_packet_requirev_state; - - /* State variables used in libssh2_channel_flush_ex() */ - libssh2_nonblocking_states flush_state; - size_t flush_refund_bytes; - size_t flush_flush_bytes; - - /* State variables used in libssh2_channel_receive_window_adjust() */ - libssh2_nonblocking_states adjust_state; - unsigned char adjust_adjust[9]; /* packet_type(1) + channel(4) + - adjustment(4) */ - - /* State variables used in libssh2_channel_read_ex() */ - libssh2_nonblocking_states read_state; - - uint32_t read_local_id; - - /* State variables used in libssh2_channel_write_ex() */ - libssh2_nonblocking_states write_state; - unsigned char write_packet[13]; - size_t write_packet_len; - size_t write_bufwrite; - - /* State variables used in libssh2_channel_close() */ - libssh2_nonblocking_states close_state; - unsigned char close_packet[5]; - - /* State variables used in libssh2_channel_wait_closedeof() */ - libssh2_nonblocking_states wait_eof_state; - - /* State variables used in libssh2_channel_wait_closed() */ - libssh2_nonblocking_states wait_closed_state; - - /* State variables used in libssh2_channel_free() */ - libssh2_nonblocking_states free_state; - - /* State variables used in libssh2_channel_handle_extended_data2() */ - libssh2_nonblocking_states extData2_state; - - /* State variables used in libssh2_channel_request_auth_agent() */ - libssh2_nonblocking_states req_auth_agent_try_state; - libssh2_nonblocking_states req_auth_agent_state; - unsigned char req_auth_agent_packet[36]; - size_t req_auth_agent_packet_len; - unsigned char req_auth_agent_local_channel[4]; - packet_requirev_state_t req_auth_agent_requirev_state; -}; - -struct _LIBSSH2_LISTENER -{ - struct list_node node; /* linked list header */ - - LIBSSH2_SESSION *session; - - char *host; - int port; - - /* a list of CHANNELs for this listener */ - struct list_head queue; - - int queue_size; - int queue_maxsize; - - /* State variables used in libssh2_channel_forward_cancel() */ - libssh2_nonblocking_states chanFwdCncl_state; - unsigned char *chanFwdCncl_data; - size_t chanFwdCncl_data_len; -}; - -typedef struct _libssh2_endpoint_data -{ - unsigned char *banner; - - unsigned char *kexinit; - size_t kexinit_len; - - const LIBSSH2_CRYPT_METHOD *crypt; - void *crypt_abstract; - - const struct _LIBSSH2_MAC_METHOD *mac; - uint32_t seqno; - void *mac_abstract; - - const LIBSSH2_COMP_METHOD *comp; - void *comp_abstract; - - /* Method Preferences -- NULL yields "load order" */ - char *crypt_prefs; - char *mac_prefs; - char *comp_prefs; - char *lang_prefs; -} libssh2_endpoint_data; - -#define PACKETBUFSIZE (1024*16) - -struct transportpacket -{ - /* ------------- for incoming data --------------- */ - unsigned char buf[PACKETBUFSIZE]; - unsigned char init[5]; /* first 5 bytes of the incoming data stream, - still encrypted */ - size_t writeidx; /* at what array index we do the next write into - the buffer */ - size_t readidx; /* at what array index we do the next read from - the buffer */ - uint32_t packet_length; /* the most recent packet_length as read from the - network data */ - uint8_t padding_length; /* the most recent padding_length as read from the - network data */ - size_t data_num; /* How much of the total package that has been read - so far. */ - size_t total_num; /* How much a total package is supposed to be, in - number of bytes. A full package is - packet_length + padding_length + 4 + - mac_length. */ - unsigned char *payload; /* this is a pointer to a LIBSSH2_ALLOC() - area to which we write decrypted data */ - unsigned char *wptr; /* write pointer into the payload to where we - are currently writing decrypted data */ - - /* ------------- for outgoing data --------------- */ - unsigned char outbuf[MAX_SSH_PACKET_LEN]; /* area for the outgoing data */ - - int ototal_num; /* size of outbuf in number of bytes */ - const unsigned char *odata; /* original pointer to the data */ - size_t olen; /* original size of the data we stored in - outbuf */ - size_t osent; /* number of bytes already sent */ -}; - -struct _LIBSSH2_PUBLICKEY -{ - LIBSSH2_CHANNEL *channel; - uint32_t version; - - /* State variables used in libssh2_publickey_packet_receive() */ - libssh2_nonblocking_states receive_state; - unsigned char *receive_packet; - size_t receive_packet_len; - - /* State variables used in libssh2_publickey_add_ex() */ - libssh2_nonblocking_states add_state; - unsigned char *add_packet; - unsigned char *add_s; - - /* State variables used in libssh2_publickey_remove_ex() */ - libssh2_nonblocking_states remove_state; - unsigned char *remove_packet; - unsigned char *remove_s; - - /* State variables used in libssh2_publickey_list_fetch() */ - libssh2_nonblocking_states listFetch_state; - unsigned char *listFetch_s; - unsigned char listFetch_buffer[12]; - unsigned char *listFetch_data; - size_t listFetch_data_len; -}; - -#define LIBSSH2_SCP_RESPONSE_BUFLEN 256 - -struct flags { - int sigpipe; /* LIBSSH2_FLAG_SIGPIPE */ - int compress; /* LIBSSH2_FLAG_COMPRESS */ -}; - -struct _LIBSSH2_SESSION -{ - /* Memory management callbacks */ - void *abstract; - LIBSSH2_ALLOC_FUNC((*alloc)); - LIBSSH2_REALLOC_FUNC((*realloc)); - LIBSSH2_FREE_FUNC((*free)); - - /* Other callbacks */ - LIBSSH2_IGNORE_FUNC((*ssh_msg_ignore)); - LIBSSH2_DEBUG_FUNC((*ssh_msg_debug)); - LIBSSH2_DISCONNECT_FUNC((*ssh_msg_disconnect)); - LIBSSH2_MACERROR_FUNC((*macerror)); - LIBSSH2_X11_OPEN_FUNC((*x11)); - LIBSSH2_SEND_FUNC((*send)); - LIBSSH2_RECV_FUNC((*recv)); - - /* Method preferences -- NULL yields "load order" */ - char *kex_prefs; - char *hostkey_prefs; - - int state; - - /* Flag options */ - struct flags flag; - - /* Agreed Key Exchange Method */ - const LIBSSH2_KEX_METHOD *kex; - unsigned int burn_optimistic_kexinit:1; - - unsigned char *session_id; - uint32_t session_id_len; - - /* this is set to TRUE if a blocking API behavior is requested */ - int api_block_mode; - - /* Timeout used when blocking API behavior is active */ - long api_timeout; - - /* Server's public key */ - const LIBSSH2_HOSTKEY_METHOD *hostkey; - void *server_hostkey_abstract; - - /* Either set with libssh2_session_hostkey() (for server mode) - * Or read from server in (eg) KEXDH_INIT (for client mode) - */ - unsigned char *server_hostkey; - uint32_t server_hostkey_len; -#if LIBSSH2_MD5 - unsigned char server_hostkey_md5[MD5_DIGEST_LENGTH]; - int server_hostkey_md5_valid; -#endif /* ! LIBSSH2_MD5 */ - unsigned char server_hostkey_sha1[SHA_DIGEST_LENGTH]; - int server_hostkey_sha1_valid; - - unsigned char server_hostkey_sha256[SHA256_DIGEST_LENGTH]; - int server_hostkey_sha256_valid; - - /* (remote as source of data -- packet_read ) */ - libssh2_endpoint_data remote; - - /* (local as source of data -- packet_write ) */ - libssh2_endpoint_data local; - - /* Inbound Data linked list -- Sometimes the packet that comes in isn't the - packet we're ready for */ - struct list_head packets; - - /* Active connection channels */ - struct list_head channels; - - uint32_t next_channel; - - struct list_head listeners; /* list of LIBSSH2_LISTENER structs */ - - /* Actual I/O socket */ - libssh2_socket_t socket_fd; - int socket_state; - int socket_block_directions; - int socket_prev_blockstate; /* stores the state of the socket blockiness - when libssh2_session_startup() is called */ - - /* Error tracking */ - const char *err_msg; - int err_code; - int err_flags; - - /* struct members for packet-level reading */ - struct transportpacket packet; -#ifdef LIBSSH2DEBUG - int showmask; /* what debug/trace messages to display */ - libssh2_trace_handler_func tracehandler; /* callback to display trace - messages */ - void *tracehandler_context; /* context for the trace handler */ -#endif - - /* State variables used in libssh2_banner_send() */ - libssh2_nonblocking_states banner_TxRx_state; - char banner_TxRx_banner[256]; - ssize_t banner_TxRx_total_send; - - /* State variables used in libssh2_kexinit() */ - libssh2_nonblocking_states kexinit_state; - unsigned char *kexinit_data; - size_t kexinit_data_len; - - /* State variables used in libssh2_session_startup() */ - libssh2_nonblocking_states startup_state; - unsigned char *startup_data; - size_t startup_data_len; - unsigned char startup_service[sizeof("ssh-userauth") + 5 - 1]; - size_t startup_service_length; - packet_require_state_t startup_req_state; - key_exchange_state_t startup_key_state; - - /* State variables used in libssh2_session_free() */ - libssh2_nonblocking_states free_state; - - /* State variables used in libssh2_session_disconnect_ex() */ - libssh2_nonblocking_states disconnect_state; - unsigned char disconnect_data[256 + 13]; - size_t disconnect_data_len; - - /* State variables used in libssh2_packet_read() */ - libssh2_nonblocking_states readPack_state; - int readPack_encrypted; - - /* State variables used in libssh2_userauth_list() */ - libssh2_nonblocking_states userauth_list_state; - unsigned char *userauth_list_data; - size_t userauth_list_data_len; - packet_requirev_state_t userauth_list_packet_requirev_state; - - /* State variables used in libssh2_userauth_password_ex() */ - libssh2_nonblocking_states userauth_pswd_state; - unsigned char *userauth_pswd_data; - unsigned char userauth_pswd_data0; - size_t userauth_pswd_data_len; - char *userauth_pswd_newpw; - int userauth_pswd_newpw_len; - packet_requirev_state_t userauth_pswd_packet_requirev_state; - - /* State variables used in libssh2_userauth_hostbased_fromfile_ex() */ - libssh2_nonblocking_states userauth_host_state; - unsigned char *userauth_host_data; - size_t userauth_host_data_len; - unsigned char *userauth_host_packet; - size_t userauth_host_packet_len; - unsigned char *userauth_host_method; - size_t userauth_host_method_len; - unsigned char *userauth_host_s; - packet_requirev_state_t userauth_host_packet_requirev_state; - - /* State variables used in libssh2_userauth_publickey_fromfile_ex() */ - libssh2_nonblocking_states userauth_pblc_state; - unsigned char *userauth_pblc_data; - size_t userauth_pblc_data_len; - unsigned char *userauth_pblc_packet; - size_t userauth_pblc_packet_len; - unsigned char *userauth_pblc_method; - size_t userauth_pblc_method_len; - unsigned char *userauth_pblc_s; - unsigned char *userauth_pblc_b; - packet_requirev_state_t userauth_pblc_packet_requirev_state; - - /* State variables used in libssh2_userauth_keyboard_interactive_ex() */ - libssh2_nonblocking_states userauth_kybd_state; - unsigned char *userauth_kybd_data; - size_t userauth_kybd_data_len; - unsigned char *userauth_kybd_packet; - size_t userauth_kybd_packet_len; - unsigned int userauth_kybd_auth_name_len; - char *userauth_kybd_auth_name; - unsigned userauth_kybd_auth_instruction_len; - char *userauth_kybd_auth_instruction; - unsigned int userauth_kybd_num_prompts; - int userauth_kybd_auth_failure; - LIBSSH2_USERAUTH_KBDINT_PROMPT *userauth_kybd_prompts; - LIBSSH2_USERAUTH_KBDINT_RESPONSE *userauth_kybd_responses; - packet_requirev_state_t userauth_kybd_packet_requirev_state; - - /* State variables used in libssh2_channel_open_ex() */ - libssh2_nonblocking_states open_state; - packet_requirev_state_t open_packet_requirev_state; - LIBSSH2_CHANNEL *open_channel; - unsigned char *open_packet; - size_t open_packet_len; - unsigned char *open_data; - size_t open_data_len; - uint32_t open_local_channel; - - /* State variables used in libssh2_channel_direct_tcpip_ex() */ - libssh2_nonblocking_states direct_state; - unsigned char *direct_message; - size_t direct_host_len; - size_t direct_shost_len; - size_t direct_message_len; - - /* State variables used in libssh2_channel_forward_listen_ex() */ - libssh2_nonblocking_states fwdLstn_state; - unsigned char *fwdLstn_packet; - uint32_t fwdLstn_host_len; - uint32_t fwdLstn_packet_len; - packet_requirev_state_t fwdLstn_packet_requirev_state; - - /* State variables used in libssh2_publickey_init() */ - libssh2_nonblocking_states pkeyInit_state; - LIBSSH2_PUBLICKEY *pkeyInit_pkey; - LIBSSH2_CHANNEL *pkeyInit_channel; - unsigned char *pkeyInit_data; - size_t pkeyInit_data_len; - /* 19 = packet_len(4) + version_len(4) + "version"(7) + version_num(4) */ - unsigned char pkeyInit_buffer[19]; - size_t pkeyInit_buffer_sent; /* how much of buffer that has been sent */ - - /* State variables used in libssh2_packet_add() */ - libssh2_nonblocking_states packAdd_state; - LIBSSH2_CHANNEL *packAdd_channelp; /* keeper of the channel during EAGAIN - states */ - packet_queue_listener_state_t packAdd_Qlstn_state; - packet_x11_open_state_t packAdd_x11open_state; - - /* State variables used in fullpacket() */ - libssh2_nonblocking_states fullpacket_state; - int fullpacket_macstate; - size_t fullpacket_payload_len; - int fullpacket_packet_type; - - /* State variables used in libssh2_sftp_init() */ - libssh2_nonblocking_states sftpInit_state; - LIBSSH2_SFTP *sftpInit_sftp; - LIBSSH2_CHANNEL *sftpInit_channel; - unsigned char sftpInit_buffer[9]; /* sftp_header(5){excludes request_id} - + version_id(4) */ - int sftpInit_sent; /* number of bytes from the buffer that have been - sent */ - - /* State variables used in libssh2_scp_recv() / libssh_scp_recv2() */ - libssh2_nonblocking_states scpRecv_state; - unsigned char *scpRecv_command; - size_t scpRecv_command_len; - unsigned char scpRecv_response[LIBSSH2_SCP_RESPONSE_BUFLEN]; - size_t scpRecv_response_len; - long scpRecv_mode; -#if defined(HAVE_LONGLONG) && defined(HAVE_STRTOLL) - /* we have the type and we can parse such numbers */ - long long scpRecv_size; -#define scpsize_strtol strtoll -#elif defined(HAVE_STRTOI64) - __int64 scpRecv_size; -#define scpsize_strtol _strtoi64 -#else - long scpRecv_size; -#define scpsize_strtol strtol -#endif - long scpRecv_mtime; - long scpRecv_atime; - LIBSSH2_CHANNEL *scpRecv_channel; - - /* State variables used in libssh2_scp_send_ex() */ - libssh2_nonblocking_states scpSend_state; - unsigned char *scpSend_command; - size_t scpSend_command_len; - unsigned char scpSend_response[LIBSSH2_SCP_RESPONSE_BUFLEN]; - size_t scpSend_response_len; - LIBSSH2_CHANNEL *scpSend_channel; - - /* Keepalive variables used by keepalive.c. */ - int keepalive_interval; - int keepalive_want_reply; - time_t keepalive_last_sent; -}; - -/* session.state bits */ -#define LIBSSH2_STATE_EXCHANGING_KEYS 0x00000001 -#define LIBSSH2_STATE_NEWKEYS 0x00000002 -#define LIBSSH2_STATE_AUTHENTICATED 0x00000004 -#define LIBSSH2_STATE_KEX_ACTIVE 0x00000008 - -/* session.flag helpers */ -#ifdef MSG_NOSIGNAL -#define LIBSSH2_SOCKET_SEND_FLAGS(session) \ - (((session)->flag.sigpipe) ? 0 : MSG_NOSIGNAL) -#define LIBSSH2_SOCKET_RECV_FLAGS(session) \ - (((session)->flag.sigpipe) ? 0 : MSG_NOSIGNAL) -#else -/* If MSG_NOSIGNAL isn't defined we're SOL on blocking SIGPIPE */ -#define LIBSSH2_SOCKET_SEND_FLAGS(session) 0 -#define LIBSSH2_SOCKET_RECV_FLAGS(session) 0 -#endif - -/* --------- */ - -/* libssh2 extensible ssh api, ultimately I'd like to allow loading additional - methods via .so/.dll */ - -struct _LIBSSH2_KEX_METHOD -{ - const char *name; - - /* Key exchange, populates session->* and returns 0 on success, non-0 on - error */ - int (*exchange_keys) (LIBSSH2_SESSION * session, - key_exchange_state_low_t * key_state); - - long flags; -}; - -struct _LIBSSH2_HOSTKEY_METHOD -{ - const char *name; - unsigned long hash_len; - - int (*init) (LIBSSH2_SESSION * session, const unsigned char *hostkey_data, - size_t hostkey_data_len, void **abstract); - int (*initPEM) (LIBSSH2_SESSION * session, const char *privkeyfile, - unsigned const char *passphrase, void **abstract); - int (*initPEMFromMemory) (LIBSSH2_SESSION * session, - const char *privkeyfiledata, - size_t privkeyfiledata_len, - unsigned const char *passphrase, - void **abstract); - int (*sig_verify) (LIBSSH2_SESSION * session, const unsigned char *sig, - size_t sig_len, const unsigned char *m, - size_t m_len, void **abstract); - int (*signv) (LIBSSH2_SESSION * session, unsigned char **signature, - size_t *signature_len, int veccount, - const struct iovec datavec[], void **abstract); - int (*encrypt) (LIBSSH2_SESSION * session, unsigned char **dst, - size_t *dst_len, const unsigned char *src, - size_t src_len, void **abstract); - int (*dtor) (LIBSSH2_SESSION * session, void **abstract); -}; - -struct _LIBSSH2_CRYPT_METHOD -{ - const char *name; - const char *pem_annotation; - - int blocksize; - - /* iv and key sizes (-1 for variable length) */ - int iv_len; - int secret_len; - - long flags; - - int (*init) (LIBSSH2_SESSION * session, - const LIBSSH2_CRYPT_METHOD * method, unsigned char *iv, - int *free_iv, unsigned char *secret, int *free_secret, - int encrypt, void **abstract); - int (*crypt) (LIBSSH2_SESSION * session, unsigned char *block, - size_t blocksize, void **abstract); - int (*dtor) (LIBSSH2_SESSION * session, void **abstract); - - _libssh2_cipher_type(algo); -}; - -struct _LIBSSH2_COMP_METHOD -{ - const char *name; - int compress; /* 1 if it does compress, 0 if it doesn't */ - int use_in_auth; /* 1 if compression should be used in userauth */ - int (*init) (LIBSSH2_SESSION *session, int compress, void **abstract); - int (*comp) (LIBSSH2_SESSION *session, - unsigned char *dest, - size_t *dest_len, - const unsigned char *src, - size_t src_len, - void **abstract); - int (*decomp) (LIBSSH2_SESSION *session, - unsigned char **dest, - size_t *dest_len, - size_t payload_limit, - const unsigned char *src, - size_t src_len, - void **abstract); - int (*dtor) (LIBSSH2_SESSION * session, int compress, void **abstract); -}; - -#ifdef LIBSSH2DEBUG -void _libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, - ...); -#else -#if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ - defined(__GNUC__) -/* C99 supported and also by older GCC */ -#define _libssh2_debug(x,y,z,...) do {} while (0) -#else -/* no gcc and not C99, do static and hopefully inline */ -static inline void -_libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, ...) -{ - (void)session; - (void)context; - (void)format; -} -#endif -#endif - -#define LIBSSH2_SOCKET_UNKNOWN 1 -#define LIBSSH2_SOCKET_CONNECTED 0 -#define LIBSSH2_SOCKET_DISCONNECTED -1 - -/* Initial packet state, prior to MAC check */ -#define LIBSSH2_MAC_UNCONFIRMED 1 -/* When MAC type is "none" (proto initiation phase) all packets are deemed - "confirmed" */ -#define LIBSSH2_MAC_CONFIRMED 0 -/* Something very bad is going on */ -#define LIBSSH2_MAC_INVALID -1 - -/* Flags for _libssh2_error_flags */ -/* Error message is allocated on the heap */ -#define LIBSSH2_ERR_FLAG_DUP 1 - -/* SSH Packet Types -- Defined by internet draft */ -/* Transport Layer */ -#define SSH_MSG_DISCONNECT 1 -#define SSH_MSG_IGNORE 2 -#define SSH_MSG_UNIMPLEMENTED 3 -#define SSH_MSG_DEBUG 4 -#define SSH_MSG_SERVICE_REQUEST 5 -#define SSH_MSG_SERVICE_ACCEPT 6 - -#define SSH_MSG_KEXINIT 20 -#define SSH_MSG_NEWKEYS 21 - -/* diffie-hellman-group1-sha1 */ -#define SSH_MSG_KEXDH_INIT 30 -#define SSH_MSG_KEXDH_REPLY 31 - -/* diffie-hellman-group-exchange-sha1 and - diffie-hellman-group-exchange-sha256 */ -#define SSH_MSG_KEX_DH_GEX_REQUEST_OLD 30 -#define SSH_MSG_KEX_DH_GEX_REQUEST 34 -#define SSH_MSG_KEX_DH_GEX_GROUP 31 -#define SSH_MSG_KEX_DH_GEX_INIT 32 -#define SSH_MSG_KEX_DH_GEX_REPLY 33 - -/* ecdh */ -#define SSH2_MSG_KEX_ECDH_INIT 30 -#define SSH2_MSG_KEX_ECDH_REPLY 31 - -/* User Authentication */ -#define SSH_MSG_USERAUTH_REQUEST 50 -#define SSH_MSG_USERAUTH_FAILURE 51 -#define SSH_MSG_USERAUTH_SUCCESS 52 -#define SSH_MSG_USERAUTH_BANNER 53 - -/* "public key" method */ -#define SSH_MSG_USERAUTH_PK_OK 60 -/* "password" method */ -#define SSH_MSG_USERAUTH_PASSWD_CHANGEREQ 60 -/* "keyboard-interactive" method */ -#define SSH_MSG_USERAUTH_INFO_REQUEST 60 -#define SSH_MSG_USERAUTH_INFO_RESPONSE 61 - -/* Channels */ -#define SSH_MSG_GLOBAL_REQUEST 80 -#define SSH_MSG_REQUEST_SUCCESS 81 -#define SSH_MSG_REQUEST_FAILURE 82 - -#define SSH_MSG_CHANNEL_OPEN 90 -#define SSH_MSG_CHANNEL_OPEN_CONFIRMATION 91 -#define SSH_MSG_CHANNEL_OPEN_FAILURE 92 -#define SSH_MSG_CHANNEL_WINDOW_ADJUST 93 -#define SSH_MSG_CHANNEL_DATA 94 -#define SSH_MSG_CHANNEL_EXTENDED_DATA 95 -#define SSH_MSG_CHANNEL_EOF 96 -#define SSH_MSG_CHANNEL_CLOSE 97 -#define SSH_MSG_CHANNEL_REQUEST 98 -#define SSH_MSG_CHANNEL_SUCCESS 99 -#define SSH_MSG_CHANNEL_FAILURE 100 - -/* Error codes returned in SSH_MSG_CHANNEL_OPEN_FAILURE message - (see RFC4254) */ -#define SSH_OPEN_ADMINISTRATIVELY_PROHIBITED 1 -#define SSH_OPEN_CONNECT_FAILED 2 -#define SSH_OPEN_UNKNOWN_CHANNELTYPE 3 -#define SSH_OPEN_RESOURCE_SHORTAGE 4 - -ssize_t _libssh2_recv(libssh2_socket_t socket, void *buffer, - size_t length, int flags, void **abstract); -ssize_t _libssh2_send(libssh2_socket_t socket, const void *buffer, - size_t length, int flags, void **abstract); - -#define LIBSSH2_READ_TIMEOUT 60 /* generic timeout in seconds used when - waiting for more data to arrive */ - - -int _libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange, - key_exchange_state_t * state); - -/* Let crypt.c/hostkey.c expose their method structs */ -const LIBSSH2_CRYPT_METHOD **libssh2_crypt_methods(void); -const LIBSSH2_HOSTKEY_METHOD **libssh2_hostkey_methods(void); - -/* misc.c */ -int _libssh2_bcrypt_pbkdf(const char *pass, - size_t passlen, - const uint8_t *salt, - size_t saltlen, - uint8_t *key, - size_t keylen, - unsigned int rounds); - -/* pem.c */ -int _libssh2_pem_parse(LIBSSH2_SESSION * session, - const char *headerbegin, - const char *headerend, - const unsigned char *passphrase, - FILE * fp, unsigned char **data, unsigned int *datalen); -int _libssh2_pem_parse_memory(LIBSSH2_SESSION * session, - const char *headerbegin, - const char *headerend, - const char *filedata, size_t filedata_len, - unsigned char **data, unsigned int *datalen); - /* OpenSSL keys */ -int -_libssh2_openssh_pem_parse(LIBSSH2_SESSION * session, - const unsigned char *passphrase, - FILE * fp, struct string_buf **decrypted_buf); -int -_libssh2_openssh_pem_parse_memory(LIBSSH2_SESSION * session, - const unsigned char *passphrase, - const char *filedata, size_t filedata_len, - struct string_buf **decrypted_buf); - -int _libssh2_pem_decode_sequence(unsigned char **data, unsigned int *datalen); -int _libssh2_pem_decode_integer(unsigned char **data, unsigned int *datalen, - unsigned char **i, unsigned int *ilen); - -/* global.c */ -void _libssh2_init_if_needed(void); - - -#define ARRAY_SIZE(a) (sizeof ((a)) / sizeof ((a)[0])) - -/* define to output the libssh2_int64_t type in a *printf() */ -#if defined(__BORLANDC__) || defined(_MSC_VER) || defined(__MINGW32__) -#define LIBSSH2_INT64_T_FORMAT "I64d" -#else -#define LIBSSH2_INT64_T_FORMAT "lld" -#endif - -/* In Windows the default file mode is text but an application can override it. -Therefore we specify it explicitly. https://github.com/curl/curl/pull/258 -*/ -#if defined(WIN32) || defined(MSDOS) -#define FOPEN_READTEXT "rt" -#define FOPEN_WRITETEXT "wt" -#define FOPEN_APPENDTEXT "at" -#elif defined(__CYGWIN__) -/* Cygwin has specific behavior we need to address when WIN32 is not defined. -https://cygwin.com/cygwin-ug-net/using-textbinary.html -For write we want our output to have line endings of LF and be compatible with -other Cygwin utilities. For read we want to handle input that may have line -endings either CRLF or LF so 't' is appropriate. -*/ -#define FOPEN_READTEXT "rt" -#define FOPEN_WRITETEXT "w" -#define FOPEN_APPENDTEXT "a" -#else -#define FOPEN_READTEXT "r" -#define FOPEN_WRITETEXT "w" -#define FOPEN_APPENDTEXT "a" -#endif - -#endif /* __LIBSSH2_PRIV_H */ diff --git a/include/libssh2/libssh2_publickey.h b/include/libssh2/libssh2_publickey.h deleted file mode 100644 index 5dbdcf9..0000000 --- a/include/libssh2/libssh2_publickey.h +++ /dev/null @@ -1,122 +0,0 @@ -/* Copyright (c) 2004-2006, Sara Golemon - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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. - */ - -/* Note: This include file is only needed for using the - * publickey SUBSYSTEM which is not the same as publickey - * authentication. For authentication you only need libssh2.h - * - * For more information on the publickey subsystem, - * refer to IETF draft: secsh-publickey - */ - -#ifndef LIBSSH2_PUBLICKEY_H -#define LIBSSH2_PUBLICKEY_H 1 - -#include "libssh2.h" - -typedef struct _LIBSSH2_PUBLICKEY LIBSSH2_PUBLICKEY; - -typedef struct _libssh2_publickey_attribute { - const char *name; - unsigned long name_len; - const char *value; - unsigned long value_len; - char mandatory; -} libssh2_publickey_attribute; - -typedef struct _libssh2_publickey_list { - unsigned char *packet; /* For freeing */ - - const unsigned char *name; - unsigned long name_len; - const unsigned char *blob; - unsigned long blob_len; - unsigned long num_attrs; - libssh2_publickey_attribute *attrs; /* free me */ -} libssh2_publickey_list; - -/* Generally use the first macro here, but if both name and value are string - literals, you can use _fast() to take advantage of preprocessing */ -#define libssh2_publickey_attribute(name, value, mandatory) \ - { (name), strlen(name), (value), strlen(value), (mandatory) }, -#define libssh2_publickey_attribute_fast(name, value, mandatory) \ - { (name), sizeof(name) - 1, (value), sizeof(value) - 1, (mandatory) }, - -#ifdef __cplusplus -extern "C" { -#endif - -/* Publickey Subsystem */ -LIBSSH2_API LIBSSH2_PUBLICKEY * -libssh2_publickey_init(LIBSSH2_SESSION *session); - -LIBSSH2_API int -libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY *pkey, - const unsigned char *name, - unsigned long name_len, - const unsigned char *blob, - unsigned long blob_len, char overwrite, - unsigned long num_attrs, - const libssh2_publickey_attribute attrs[]); -#define libssh2_publickey_add(pkey, name, blob, blob_len, overwrite, \ - num_attrs, attrs) \ - libssh2_publickey_add_ex((pkey), (name), strlen(name), (blob), (blob_len), \ - (overwrite), (num_attrs), (attrs)) - -LIBSSH2_API int libssh2_publickey_remove_ex(LIBSSH2_PUBLICKEY *pkey, - const unsigned char *name, - unsigned long name_len, - const unsigned char *blob, - unsigned long blob_len); -#define libssh2_publickey_remove(pkey, name, blob, blob_len) \ - libssh2_publickey_remove_ex((pkey), (name), strlen(name), (blob), (blob_len)) - -LIBSSH2_API int -libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY *pkey, - unsigned long *num_keys, - libssh2_publickey_list **pkey_list); -LIBSSH2_API void -libssh2_publickey_list_free(LIBSSH2_PUBLICKEY *pkey, - libssh2_publickey_list *pkey_list); - -LIBSSH2_API int libssh2_publickey_shutdown(LIBSSH2_PUBLICKEY *pkey); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* ifndef: LIBSSH2_PUBLICKEY_H */ diff --git a/include/libssh2/libssh2_sftp.h b/include/libssh2/libssh2_sftp.h deleted file mode 100644 index 476ea87..0000000 --- a/include/libssh2/libssh2_sftp.h +++ /dev/null @@ -1,351 +0,0 @@ -/* Copyright (c) 2004-2008, Sara Golemon - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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. - */ - -#ifndef LIBSSH2_SFTP_H -#define LIBSSH2_SFTP_H 1 - -#include "libssh2.h" - -#ifndef WIN32 -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* Note: Version 6 was documented at the time of writing - * However it was marked as "DO NOT IMPLEMENT" due to pending changes - * - * Let's start with Version 3 (The version found in OpenSSH) and go from there - */ -#define LIBSSH2_SFTP_VERSION 3 - -typedef struct _LIBSSH2_SFTP LIBSSH2_SFTP; -typedef struct _LIBSSH2_SFTP_HANDLE LIBSSH2_SFTP_HANDLE; -typedef struct _LIBSSH2_SFTP_ATTRIBUTES LIBSSH2_SFTP_ATTRIBUTES; -typedef struct _LIBSSH2_SFTP_STATVFS LIBSSH2_SFTP_STATVFS; - -/* Flags for open_ex() */ -#define LIBSSH2_SFTP_OPENFILE 0 -#define LIBSSH2_SFTP_OPENDIR 1 - -/* Flags for rename_ex() */ -#define LIBSSH2_SFTP_RENAME_OVERWRITE 0x00000001 -#define LIBSSH2_SFTP_RENAME_ATOMIC 0x00000002 -#define LIBSSH2_SFTP_RENAME_NATIVE 0x00000004 - -/* Flags for stat_ex() */ -#define LIBSSH2_SFTP_STAT 0 -#define LIBSSH2_SFTP_LSTAT 1 -#define LIBSSH2_SFTP_SETSTAT 2 - -/* Flags for symlink_ex() */ -#define LIBSSH2_SFTP_SYMLINK 0 -#define LIBSSH2_SFTP_READLINK 1 -#define LIBSSH2_SFTP_REALPATH 2 - -/* Flags for sftp_mkdir() */ -#define LIBSSH2_SFTP_DEFAULT_MODE -1 - -/* SFTP attribute flag bits */ -#define LIBSSH2_SFTP_ATTR_SIZE 0x00000001 -#define LIBSSH2_SFTP_ATTR_UIDGID 0x00000002 -#define LIBSSH2_SFTP_ATTR_PERMISSIONS 0x00000004 -#define LIBSSH2_SFTP_ATTR_ACMODTIME 0x00000008 -#define LIBSSH2_SFTP_ATTR_EXTENDED 0x80000000 - -/* SFTP statvfs flag bits */ -#define LIBSSH2_SFTP_ST_RDONLY 0x00000001 -#define LIBSSH2_SFTP_ST_NOSUID 0x00000002 - -struct _LIBSSH2_SFTP_ATTRIBUTES { - /* If flags & ATTR_* bit is set, then the value in this struct will be - * meaningful Otherwise it should be ignored - */ - unsigned long flags; - - libssh2_uint64_t filesize; - unsigned long uid, gid; - unsigned long permissions; - unsigned long atime, mtime; -}; - -struct _LIBSSH2_SFTP_STATVFS { - libssh2_uint64_t f_bsize; /* file system block size */ - libssh2_uint64_t f_frsize; /* fragment size */ - libssh2_uint64_t f_blocks; /* size of fs in f_frsize units */ - libssh2_uint64_t f_bfree; /* # free blocks */ - libssh2_uint64_t f_bavail; /* # free blocks for non-root */ - libssh2_uint64_t f_files; /* # inodes */ - libssh2_uint64_t f_ffree; /* # free inodes */ - libssh2_uint64_t f_favail; /* # free inodes for non-root */ - libssh2_uint64_t f_fsid; /* file system ID */ - libssh2_uint64_t f_flag; /* mount flags */ - libssh2_uint64_t f_namemax; /* maximum filename length */ -}; - -/* SFTP filetypes */ -#define LIBSSH2_SFTP_TYPE_REGULAR 1 -#define LIBSSH2_SFTP_TYPE_DIRECTORY 2 -#define LIBSSH2_SFTP_TYPE_SYMLINK 3 -#define LIBSSH2_SFTP_TYPE_SPECIAL 4 -#define LIBSSH2_SFTP_TYPE_UNKNOWN 5 -#define LIBSSH2_SFTP_TYPE_SOCKET 6 -#define LIBSSH2_SFTP_TYPE_CHAR_DEVICE 7 -#define LIBSSH2_SFTP_TYPE_BLOCK_DEVICE 8 -#define LIBSSH2_SFTP_TYPE_FIFO 9 - -/* - * Reproduce the POSIX file modes here for systems that are not POSIX - * compliant. - * - * These is used in "permissions" of "struct _LIBSSH2_SFTP_ATTRIBUTES" - */ -/* File type */ -#define LIBSSH2_SFTP_S_IFMT 0170000 /* type of file mask */ -#define LIBSSH2_SFTP_S_IFIFO 0010000 /* named pipe (fifo) */ -#define LIBSSH2_SFTP_S_IFCHR 0020000 /* character special */ -#define LIBSSH2_SFTP_S_IFDIR 0040000 /* directory */ -#define LIBSSH2_SFTP_S_IFBLK 0060000 /* block special */ -#define LIBSSH2_SFTP_S_IFREG 0100000 /* regular */ -#define LIBSSH2_SFTP_S_IFLNK 0120000 /* symbolic link */ -#define LIBSSH2_SFTP_S_IFSOCK 0140000 /* socket */ - -/* File mode */ -/* Read, write, execute/search by owner */ -#define LIBSSH2_SFTP_S_IRWXU 0000700 /* RWX mask for owner */ -#define LIBSSH2_SFTP_S_IRUSR 0000400 /* R for owner */ -#define LIBSSH2_SFTP_S_IWUSR 0000200 /* W for owner */ -#define LIBSSH2_SFTP_S_IXUSR 0000100 /* X for owner */ -/* Read, write, execute/search by group */ -#define LIBSSH2_SFTP_S_IRWXG 0000070 /* RWX mask for group */ -#define LIBSSH2_SFTP_S_IRGRP 0000040 /* R for group */ -#define LIBSSH2_SFTP_S_IWGRP 0000020 /* W for group */ -#define LIBSSH2_SFTP_S_IXGRP 0000010 /* X for group */ -/* Read, write, execute/search by others */ -#define LIBSSH2_SFTP_S_IRWXO 0000007 /* RWX mask for other */ -#define LIBSSH2_SFTP_S_IROTH 0000004 /* R for other */ -#define LIBSSH2_SFTP_S_IWOTH 0000002 /* W for other */ -#define LIBSSH2_SFTP_S_IXOTH 0000001 /* X for other */ - -/* macros to check for specific file types, added in 1.2.5 */ -#define LIBSSH2_SFTP_S_ISLNK(m) \ - (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFLNK) -#define LIBSSH2_SFTP_S_ISREG(m) \ - (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFREG) -#define LIBSSH2_SFTP_S_ISDIR(m) \ - (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFDIR) -#define LIBSSH2_SFTP_S_ISCHR(m) \ - (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFCHR) -#define LIBSSH2_SFTP_S_ISBLK(m) \ - (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFBLK) -#define LIBSSH2_SFTP_S_ISFIFO(m) \ - (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFIFO) -#define LIBSSH2_SFTP_S_ISSOCK(m) \ - (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFSOCK) - -/* SFTP File Transfer Flags -- (e.g. flags parameter to sftp_open()) - * Danger will robinson... APPEND doesn't have any effect on OpenSSH servers */ -#define LIBSSH2_FXF_READ 0x00000001 -#define LIBSSH2_FXF_WRITE 0x00000002 -#define LIBSSH2_FXF_APPEND 0x00000004 -#define LIBSSH2_FXF_CREAT 0x00000008 -#define LIBSSH2_FXF_TRUNC 0x00000010 -#define LIBSSH2_FXF_EXCL 0x00000020 - -/* SFTP Status Codes (returned by libssh2_sftp_last_error() ) */ -#define LIBSSH2_FX_OK 0UL -#define LIBSSH2_FX_EOF 1UL -#define LIBSSH2_FX_NO_SUCH_FILE 2UL -#define LIBSSH2_FX_PERMISSION_DENIED 3UL -#define LIBSSH2_FX_FAILURE 4UL -#define LIBSSH2_FX_BAD_MESSAGE 5UL -#define LIBSSH2_FX_NO_CONNECTION 6UL -#define LIBSSH2_FX_CONNECTION_LOST 7UL -#define LIBSSH2_FX_OP_UNSUPPORTED 8UL -#define LIBSSH2_FX_INVALID_HANDLE 9UL -#define LIBSSH2_FX_NO_SUCH_PATH 10UL -#define LIBSSH2_FX_FILE_ALREADY_EXISTS 11UL -#define LIBSSH2_FX_WRITE_PROTECT 12UL -#define LIBSSH2_FX_NO_MEDIA 13UL -#define LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM 14UL -#define LIBSSH2_FX_QUOTA_EXCEEDED 15UL -#define LIBSSH2_FX_UNKNOWN_PRINCIPLE 16UL /* Initial mis-spelling */ -#define LIBSSH2_FX_UNKNOWN_PRINCIPAL 16UL -#define LIBSSH2_FX_LOCK_CONFlICT 17UL /* Initial mis-spelling */ -#define LIBSSH2_FX_LOCK_CONFLICT 17UL -#define LIBSSH2_FX_DIR_NOT_EMPTY 18UL -#define LIBSSH2_FX_NOT_A_DIRECTORY 19UL -#define LIBSSH2_FX_INVALID_FILENAME 20UL -#define LIBSSH2_FX_LINK_LOOP 21UL - -/* Returned by any function that would block during a read/write operation */ -#define LIBSSH2SFTP_EAGAIN LIBSSH2_ERROR_EAGAIN - -/* SFTP API */ -LIBSSH2_API LIBSSH2_SFTP *libssh2_sftp_init(LIBSSH2_SESSION *session); -LIBSSH2_API int libssh2_sftp_shutdown(LIBSSH2_SFTP *sftp); -LIBSSH2_API unsigned long libssh2_sftp_last_error(LIBSSH2_SFTP *sftp); -LIBSSH2_API LIBSSH2_CHANNEL *libssh2_sftp_get_channel(LIBSSH2_SFTP *sftp); - -/* File / Directory Ops */ -LIBSSH2_API LIBSSH2_SFTP_HANDLE * -libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, - const char *filename, - unsigned int filename_len, - unsigned long flags, - long mode, int open_type); -#define libssh2_sftp_open(sftp, filename, flags, mode) \ - libssh2_sftp_open_ex((sftp), (filename), strlen(filename), (flags), \ - (mode), LIBSSH2_SFTP_OPENFILE) -#define libssh2_sftp_opendir(sftp, path) \ - libssh2_sftp_open_ex((sftp), (path), strlen(path), 0, 0, \ - LIBSSH2_SFTP_OPENDIR) - -LIBSSH2_API ssize_t libssh2_sftp_read(LIBSSH2_SFTP_HANDLE *handle, - char *buffer, size_t buffer_maxlen); - -LIBSSH2_API int libssh2_sftp_readdir_ex(LIBSSH2_SFTP_HANDLE *handle, \ - char *buffer, size_t buffer_maxlen, - char *longentry, - size_t longentry_maxlen, - LIBSSH2_SFTP_ATTRIBUTES *attrs); -#define libssh2_sftp_readdir(handle, buffer, buffer_maxlen, attrs) \ - libssh2_sftp_readdir_ex((handle), (buffer), (buffer_maxlen), NULL, 0, \ - (attrs)) - -LIBSSH2_API ssize_t libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *handle, - const char *buffer, size_t count); -LIBSSH2_API int libssh2_sftp_fsync(LIBSSH2_SFTP_HANDLE *handle); - -LIBSSH2_API int libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle); -#define libssh2_sftp_close(handle) libssh2_sftp_close_handle(handle) -#define libssh2_sftp_closedir(handle) libssh2_sftp_close_handle(handle) - -LIBSSH2_API void libssh2_sftp_seek(LIBSSH2_SFTP_HANDLE *handle, size_t offset); -LIBSSH2_API void libssh2_sftp_seek64(LIBSSH2_SFTP_HANDLE *handle, - libssh2_uint64_t offset); -#define libssh2_sftp_rewind(handle) libssh2_sftp_seek64((handle), 0) - -LIBSSH2_API size_t libssh2_sftp_tell(LIBSSH2_SFTP_HANDLE *handle); -LIBSSH2_API libssh2_uint64_t libssh2_sftp_tell64(LIBSSH2_SFTP_HANDLE *handle); - -LIBSSH2_API int libssh2_sftp_fstat_ex(LIBSSH2_SFTP_HANDLE *handle, - LIBSSH2_SFTP_ATTRIBUTES *attrs, - int setstat); -#define libssh2_sftp_fstat(handle, attrs) \ - libssh2_sftp_fstat_ex((handle), (attrs), 0) -#define libssh2_sftp_fsetstat(handle, attrs) \ - libssh2_sftp_fstat_ex((handle), (attrs), 1) - -/* Miscellaneous Ops */ -LIBSSH2_API int libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp, - const char *source_filename, - unsigned int srouce_filename_len, - const char *dest_filename, - unsigned int dest_filename_len, - long flags); -#define libssh2_sftp_rename(sftp, sourcefile, destfile) \ - libssh2_sftp_rename_ex((sftp), (sourcefile), strlen(sourcefile), \ - (destfile), strlen(destfile), \ - LIBSSH2_SFTP_RENAME_OVERWRITE | \ - LIBSSH2_SFTP_RENAME_ATOMIC | \ - LIBSSH2_SFTP_RENAME_NATIVE) - -LIBSSH2_API int libssh2_sftp_unlink_ex(LIBSSH2_SFTP *sftp, - const char *filename, - unsigned int filename_len); -#define libssh2_sftp_unlink(sftp, filename) \ - libssh2_sftp_unlink_ex((sftp), (filename), strlen(filename)) - -LIBSSH2_API int libssh2_sftp_fstatvfs(LIBSSH2_SFTP_HANDLE *handle, - LIBSSH2_SFTP_STATVFS *st); - -LIBSSH2_API int libssh2_sftp_statvfs(LIBSSH2_SFTP *sftp, - const char *path, - size_t path_len, - LIBSSH2_SFTP_STATVFS *st); - -LIBSSH2_API int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, - const char *path, - unsigned int path_len, long mode); -#define libssh2_sftp_mkdir(sftp, path, mode) \ - libssh2_sftp_mkdir_ex((sftp), (path), strlen(path), (mode)) - -LIBSSH2_API int libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp, - const char *path, - unsigned int path_len); -#define libssh2_sftp_rmdir(sftp, path) \ - libssh2_sftp_rmdir_ex((sftp), (path), strlen(path)) - -LIBSSH2_API int libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp, - const char *path, - unsigned int path_len, - int stat_type, - LIBSSH2_SFTP_ATTRIBUTES *attrs); -#define libssh2_sftp_stat(sftp, path, attrs) \ - libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_STAT, \ - (attrs)) -#define libssh2_sftp_lstat(sftp, path, attrs) \ - libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_LSTAT, \ - (attrs)) -#define libssh2_sftp_setstat(sftp, path, attrs) \ - libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_SETSTAT, \ - (attrs)) - -LIBSSH2_API int libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, - const char *path, - unsigned int path_len, - char *target, - unsigned int target_len, - int link_type); -#define libssh2_sftp_symlink(sftp, orig, linkpath) \ - libssh2_sftp_symlink_ex((sftp), (orig), strlen(orig), (linkpath), \ - strlen(linkpath), LIBSSH2_SFTP_SYMLINK) -#define libssh2_sftp_readlink(sftp, path, target, maxlen) \ - libssh2_sftp_symlink_ex((sftp), (path), strlen(path), (target), (maxlen), \ - LIBSSH2_SFTP_READLINK) -#define libssh2_sftp_realpath(sftp, path, target, maxlen) \ - libssh2_sftp_symlink_ex((sftp), (path), strlen(path), (target), (maxlen), \ - LIBSSH2_SFTP_REALPATH) - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* LIBSSH2_SFTP_H */ diff --git a/include/libssh2/mac.h b/include/libssh2/mac.h deleted file mode 100644 index 46fce54..0000000 --- a/include/libssh2/mac.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef __LIBSSH2_MAC_H -#define __LIBSSH2_MAC_H -/* Copyright (C) 2009-2010 by Daniel Stenberg - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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 "libssh2_priv.h" - -struct _LIBSSH2_MAC_METHOD -{ - const char *name; - - /* The length of a given MAC packet */ - int mac_len; - - /* integrity key length */ - int key_len; - - /* Message Authentication Code Hashing algo */ - int (*init) (LIBSSH2_SESSION * session, unsigned char *key, int *free_key, - void **abstract); - int (*hash) (LIBSSH2_SESSION * session, unsigned char *buf, - uint32_t seqno, const unsigned char *packet, - uint32_t packet_len, const unsigned char *addtl, - uint32_t addtl_len, void **abstract); - int (*dtor) (LIBSSH2_SESSION * session, void **abstract); -}; - -typedef struct _LIBSSH2_MAC_METHOD LIBSSH2_MAC_METHOD; - -const LIBSSH2_MAC_METHOD **_libssh2_mac_methods(void); - -#endif /* __LIBSSH2_MAC_H */ diff --git a/include/libssh2/mbedtls.h b/include/libssh2/mbedtls.h deleted file mode 100644 index 7832c45..0000000 --- a/include/libssh2/mbedtls.h +++ /dev/null @@ -1,451 +0,0 @@ -#ifndef __LIBSSH2_MBEDTLS_H -#define __LIBSSH2_MBEDTLS_H -/* Copyright (c) 2016, Art - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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 -#include -#include -#include -#include -#include -#include -#include - -/* Define which features are supported. */ -#define LIBSSH2_MD5 1 - -#define LIBSSH2_HMAC_RIPEMD 1 -#define LIBSSH2_HMAC_SHA256 1 -#define LIBSSH2_HMAC_SHA512 1 - -#define LIBSSH2_AES 1 -#define LIBSSH2_AES_CTR 1 -#define LIBSSH2_BLOWFISH 1 -#define LIBSSH2_RC4 1 -#define LIBSSH2_CAST 0 -#define LIBSSH2_3DES 1 - -#define LIBSSH2_RSA 1 -#define LIBSSH2_DSA 0 -#define LIBSSH2_ECDSA 0 -#define LIBSSH2_ED25519 0 - -#define MD5_DIGEST_LENGTH 16 -#define SHA_DIGEST_LENGTH 20 -#define SHA256_DIGEST_LENGTH 32 -#define SHA384_DIGEST_LENGTH 48 -#define SHA512_DIGEST_LENGTH 64 - -#define EC_MAX_POINT_LEN ((528 * 2 / 8) + 1) - -#if LIBSSH2_ECDSA -#else -#define _libssh2_ec_key void -#endif - -/*******************************************************************/ -/* - * mbedTLS backend: Generic functions - */ - -#define libssh2_crypto_init() \ - _libssh2_mbedtls_init() -#define libssh2_crypto_exit() \ - _libssh2_mbedtls_free() - -#define _libssh2_random(buf, len) \ - _libssh2_mbedtls_random(buf, len) - -#define libssh2_prepare_iovec(vec, len) /* Empty. */ - - -/*******************************************************************/ -/* - * mbedTLS backend: HMAC functions - */ - -#define libssh2_hmac_ctx mbedtls_md_context_t - -#define libssh2_hmac_ctx_init(ctx) -#define libssh2_hmac_cleanup(pctx) \ - mbedtls_md_free(pctx) -#define libssh2_hmac_update(ctx, data, datalen) \ - mbedtls_md_hmac_update(&ctx, (unsigned char *) data, datalen) -#define libssh2_hmac_final(ctx, hash) \ - mbedtls_md_hmac_finish(&ctx, hash) - -#define libssh2_hmac_sha1_init(pctx, key, keylen) \ - _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA1, key, keylen) -#define libssh2_hmac_md5_init(pctx, key, keylen) \ - _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_MD5, key, keylen) -#define libssh2_hmac_ripemd160_init(pctx, key, keylen) \ - _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_RIPEMD160, key, keylen) -#define libssh2_hmac_sha256_init(pctx, key, keylen) \ - _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA256, key, keylen) -#define libssh2_hmac_sha384_init(pctx, key, keylen) \ - _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA384, key, keylen) -#define libssh2_hmac_sha512_init(pctx, key, keylen) \ - _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA512, key, keylen) - - -/*******************************************************************/ -/* - * mbedTLS backend: SHA1 functions - */ - -#define libssh2_sha1_ctx mbedtls_md_context_t - -#define libssh2_sha1_init(pctx) \ - _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA1, NULL, 0) -#define libssh2_sha1_update(ctx, data, datalen) \ - mbedtls_md_update(&ctx, (unsigned char *) data, datalen) -#define libssh2_sha1_final(ctx, hash) \ - _libssh2_mbedtls_hash_final(&ctx, hash) -#define libssh2_sha1(data, datalen, hash) \ - _libssh2_mbedtls_hash(data, datalen, MBEDTLS_MD_SHA1, hash) - -/*******************************************************************/ -/* - * mbedTLS backend: SHA256 functions - */ - -#define libssh2_sha256_ctx mbedtls_md_context_t - -#define libssh2_sha256_init(pctx) \ - _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA256, NULL, 0) -#define libssh2_sha256_update(ctx, data, datalen) \ - mbedtls_md_update(&ctx, (unsigned char *) data, datalen) -#define libssh2_sha256_final(ctx, hash) \ - _libssh2_mbedtls_hash_final(&ctx, hash) -#define libssh2_sha256(data, datalen, hash) \ - _libssh2_mbedtls_hash(data, datalen, MBEDTLS_MD_SHA256, hash) - - -/*******************************************************************/ -/* - * mbedTLS backend: SHA384 functions - */ - -#define libssh2_sha384_ctx mbedtls_md_context_t - -#define libssh2_sha384_init(pctx) \ - _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA384, NULL, 0) -#define libssh2_sha384_update(ctx, data, datalen) \ - mbedtls_md_update(&ctx, (unsigned char *) data, datalen) -#define libssh2_sha384_final(ctx, hash) \ - _libssh2_mbedtls_hash_final(&ctx, hash) -#define libssh2_sha384(data, datalen, hash) \ - _libssh2_mbedtls_hash(data, datalen, MBEDTLS_MD_SHA384, hash) - - -/*******************************************************************/ -/* - * mbedTLS backend: SHA512 functions - */ - -#define libssh2_sha512_ctx mbedtls_md_context_t - -#define libssh2_sha512_init(pctx) \ - _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA512, NULL, 0) -#define libssh2_sha512_update(ctx, data, datalen) \ - mbedtls_md_update(&ctx, (unsigned char *) data, datalen) -#define libssh2_sha512_final(ctx, hash) \ - _libssh2_mbedtls_hash_final(&ctx, hash) -#define libssh2_sha512(data, datalen, hash) \ - _libssh2_mbedtls_hash(data, datalen, MBEDTLS_MD_SHA512, hash) - - -/*******************************************************************/ -/* - * mbedTLS backend: MD5 functions - */ - -#define libssh2_md5_ctx mbedtls_md_context_t - -#define libssh2_md5_init(pctx) \ - _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_MD5, NULL, 0) -#define libssh2_md5_update(ctx, data, datalen) \ - mbedtls_md_update(&ctx, (unsigned char *) data, datalen) -#define libssh2_md5_final(ctx, hash) \ - _libssh2_mbedtls_hash_final(&ctx, hash) -#define libssh2_md5(data, datalen, hash) \ - _libssh2_mbedtls_hash(data, datalen, MBEDTLS_MD_MD5, hash) - -/*******************************************************************/ -/* - * mbedTLS backend: RSA structure - */ - -#define libssh2_rsa_ctx mbedtls_rsa_context - -#define _libssh2_rsa_new(rsactx, e, e_len, n, n_len, \ - d, d_len, p, p_len, q, q_len, \ - e1, e1_len, e2, e2_len, c, c_len) \ - _libssh2_mbedtls_rsa_new(rsactx, e, e_len, n, n_len, \ - d, d_len, p, p_len, q, q_len, \ - e1, e1_len, e2, e2_len, c, c_len) - -#define _libssh2_rsa_new_private(rsactx, s, filename, passphrase) \ - _libssh2_mbedtls_rsa_new_private(rsactx, s, filename, passphrase) - -#define _libssh2_rsa_new_private_frommemory(rsactx, s, filedata, \ - filedata_len, passphrase) \ - _libssh2_mbedtls_rsa_new_private_frommemory(rsactx, s, filedata, \ - filedata_len, passphrase) - -#define _libssh2_rsa_sha1_sign(s, rsactx, hash, hash_len, sig, sig_len) \ - _libssh2_mbedtls_rsa_sha1_sign(s, rsactx, hash, hash_len, sig, sig_len) - -#define _libssh2_rsa_sha1_verify(rsactx, sig, sig_len, m, m_len) \ - _libssh2_mbedtls_rsa_sha1_verify(rsactx, sig, sig_len, m, m_len) - -#define _libssh2_rsa_free(rsactx) \ - _libssh2_mbedtls_rsa_free(rsactx) - -/* - * mbedTLS backend: Key functions - */ - -#define _libssh2_pub_priv_keyfile(s, m, m_len, p, p_len, pk, pw) \ - _libssh2_mbedtls_pub_priv_keyfile(s, m, m_len, p, p_len, pk, pw) -#define _libssh2_pub_priv_keyfilememory(s, m, m_len, p, p_len, \ - pk, pk_len, pw) \ - _libssh2_mbedtls_pub_priv_keyfilememory(s, m, m_len, p, p_len, \ - pk, pk_len, pw) - - - /*******************************************************************/ -/* - * mbedTLS backend: Cipher Context structure - */ -#define _libssh2_cipher_ctx mbedtls_cipher_context_t - -#define _libssh2_cipher_type(algo) mbedtls_cipher_type_t algo - -#define _libssh2_cipher_aes256ctr MBEDTLS_CIPHER_AES_256_CTR -#define _libssh2_cipher_aes192ctr MBEDTLS_CIPHER_AES_192_CTR -#define _libssh2_cipher_aes128ctr MBEDTLS_CIPHER_AES_128_CTR -#define _libssh2_cipher_aes256 MBEDTLS_CIPHER_AES_256_CBC -#define _libssh2_cipher_aes192 MBEDTLS_CIPHER_AES_192_CBC -#define _libssh2_cipher_aes128 MBEDTLS_CIPHER_AES_128_CBC -#define _libssh2_cipher_blowfish MBEDTLS_CIPHER_BLOWFISH_CBC -#define _libssh2_cipher_arcfour MBEDTLS_CIPHER_ARC4_128 -#define _libssh2_cipher_cast5 MBEDTLS_CIPHER_NULL -#define _libssh2_cipher_3des MBEDTLS_CIPHER_DES_EDE3_CBC - -/* - * mbedTLS backend: Cipher functions - */ - -#define _libssh2_cipher_init(ctx, type, iv, secret, encrypt) \ - _libssh2_mbedtls_cipher_init(ctx, type, iv, secret, encrypt) -#define _libssh2_cipher_crypt(ctx, type, encrypt, block, blocklen) \ - _libssh2_mbedtls_cipher_crypt(ctx, type, encrypt, block, blocklen) -#define _libssh2_cipher_dtor(ctx) \ - _libssh2_mbedtls_cipher_dtor(ctx) - - -/*******************************************************************/ -/* - * mbedTLS backend: BigNumber Support - */ - -#define _libssh2_bn_ctx int /* not used */ -#define _libssh2_bn_ctx_new() 0 /* not used */ -#define _libssh2_bn_ctx_free(bnctx) ((void)0) /* not used */ - -#define _libssh2_bn mbedtls_mpi - -#define _libssh2_bn_init() \ - _libssh2_mbedtls_bignum_init() -#define _libssh2_bn_init_from_bin() \ - _libssh2_mbedtls_bignum_init() -#define _libssh2_bn_set_word(bn, word) \ - mbedtls_mpi_lset(bn, word) -#define _libssh2_bn_from_bin(bn, len, bin) \ - mbedtls_mpi_read_binary(bn, bin, len) -#define _libssh2_bn_to_bin(bn, bin) \ - mbedtls_mpi_write_binary(bn, bin, mbedtls_mpi_size(bn)) -#define _libssh2_bn_bytes(bn) \ - mbedtls_mpi_size(bn) -#define _libssh2_bn_bits(bn) \ - mbedtls_mpi_bitlen(bn) -#define _libssh2_bn_free(bn) \ - _libssh2_mbedtls_bignum_free(bn) - - -/*******************************************************************/ -/* - * mbedTLS backend: Diffie-Hellman support. - */ - -#define _libssh2_dh_ctx mbedtls_mpi * -#define libssh2_dh_init(dhctx) _libssh2_dh_init(dhctx) -#define libssh2_dh_key_pair(dhctx, public, g, p, group_order, bnctx) \ - _libssh2_dh_key_pair(dhctx, public, g, p, group_order) -#define libssh2_dh_secret(dhctx, secret, f, p, bnctx) \ - _libssh2_dh_secret(dhctx, secret, f, p) -#define libssh2_dh_dtor(dhctx) _libssh2_dh_dtor(dhctx) - - -/*******************************************************************/ -/* - * mbedTLS backend: forward declarations - */ -void -_libssh2_mbedtls_init(void); - -void -_libssh2_mbedtls_free(void); - -int -_libssh2_mbedtls_random(unsigned char *buf, int len); - -int -_libssh2_mbedtls_cipher_init(_libssh2_cipher_ctx *ctx, - _libssh2_cipher_type(type), - unsigned char *iv, - unsigned char *secret, - int encrypt); -int -_libssh2_mbedtls_cipher_crypt(_libssh2_cipher_ctx *ctx, - _libssh2_cipher_type(type), - int encrypt, - unsigned char *block, - size_t blocklen); -void -_libssh2_mbedtls_cipher_dtor(_libssh2_cipher_ctx *ctx); - -int -_libssh2_mbedtls_hash_init(mbedtls_md_context_t *ctx, - mbedtls_md_type_t mdtype, - const unsigned char *key, unsigned long keylen); - -int -_libssh2_mbedtls_hash_final(mbedtls_md_context_t *ctx, unsigned char *hash); -int -_libssh2_mbedtls_hash(const unsigned char *data, unsigned long datalen, - mbedtls_md_type_t mdtype, unsigned char *hash); - -_libssh2_bn * -_libssh2_mbedtls_bignum_init(void); - -void -_libssh2_mbedtls_bignum_free(_libssh2_bn *bn); - -int -_libssh2_mbedtls_rsa_new(libssh2_rsa_ctx **rsa, - const unsigned char *edata, - unsigned long elen, - const unsigned char *ndata, - unsigned long nlen, - const unsigned char *ddata, - unsigned long dlen, - const unsigned char *pdata, - unsigned long plen, - const unsigned char *qdata, - unsigned long qlen, - const unsigned char *e1data, - unsigned long e1len, - const unsigned char *e2data, - unsigned long e2len, - const unsigned char *coeffdata, - unsigned long coefflen); - -int -_libssh2_mbedtls_rsa_new_private(libssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - const char *filename, - const unsigned char *passphrase); - -int -_libssh2_mbedtls_rsa_new_private_frommemory(libssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - const char *filedata, - size_t filedata_len, - unsigned const char *passphrase); -int -_libssh2_mbedtls_rsa_sha1_verify(libssh2_rsa_ctx *rsa, - const unsigned char *sig, - unsigned long sig_len, - const unsigned char *m, - unsigned long m_len); -int -_libssh2_mbedtls_rsa_sha1_sign(LIBSSH2_SESSION *session, - libssh2_rsa_ctx *rsa, - const unsigned char *hash, - size_t hash_len, - unsigned char **signature, - size_t *signature_len); -void -_libssh2_mbedtls_rsa_free(libssh2_rsa_ctx *rsa); - -int -_libssh2_mbedtls_pub_priv_keyfile(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - const char *privatekey, - const char *passphrase); -int -_libssh2_mbedtls_pub_priv_keyfilememory(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - const char *privatekeydata, - size_t privatekeydata_len, - const char *passphrase); - -extern void -_libssh2_dh_init(_libssh2_dh_ctx *dhctx); -extern int -_libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public, - _libssh2_bn *g, _libssh2_bn *p, int group_order); -extern int -_libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret, - _libssh2_bn *f, _libssh2_bn *p); -extern void -_libssh2_dh_dtor(_libssh2_dh_ctx *dhctx); - -#endif /* __LIBSSH2_MBEDTLS_H */ diff --git a/include/libssh2/misc.h b/include/libssh2/misc.h deleted file mode 100644 index 5481e66..0000000 --- a/include/libssh2/misc.h +++ /dev/null @@ -1,125 +0,0 @@ -#ifndef __LIBSSH2_MISC_H -#define __LIBSSH2_MISC_H -/* Copyright (c) 2009-2019 by Daniel Stenberg - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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. - */ - -struct list_head { - struct list_node *last; - struct list_node *first; -}; - -struct list_node { - struct list_node *next; - struct list_node *prev; - struct list_head *head; -}; - -struct string_buf { - unsigned char *data; - unsigned char *dataptr; - size_t len; -}; - -int _libssh2_error_flags(LIBSSH2_SESSION* session, int errcode, - const char *errmsg, int errflags); -int _libssh2_error(LIBSSH2_SESSION* session, int errcode, const char *errmsg); - -void _libssh2_list_init(struct list_head *head); - -/* add a node last in the list */ -void _libssh2_list_add(struct list_head *head, - struct list_node *entry); - -/* return the "first" node in the list this head points to */ -void *_libssh2_list_first(struct list_head *head); - -/* return the next node in the list */ -void *_libssh2_list_next(struct list_node *node); - -/* return the prev node in the list */ -void *_libssh2_list_prev(struct list_node *node); - -/* remove this node from the list */ -void _libssh2_list_remove(struct list_node *entry); - -size_t _libssh2_base64_encode(LIBSSH2_SESSION *session, - const char *inp, size_t insize, char **outptr); - -unsigned int _libssh2_ntohu32(const unsigned char *buf); -libssh2_uint64_t _libssh2_ntohu64(const unsigned char *buf); -void _libssh2_htonu32(unsigned char *buf, uint32_t val); -void _libssh2_store_u32(unsigned char **buf, uint32_t value); -void _libssh2_store_str(unsigned char **buf, const char *str, size_t len); -void *_libssh2_calloc(LIBSSH2_SESSION *session, size_t size); -void _libssh2_explicit_zero(void *buf, size_t size); - -struct string_buf* _libssh2_string_buf_new(LIBSSH2_SESSION *session); -void _libssh2_string_buf_free(LIBSSH2_SESSION *session, - struct string_buf *buf); -int _libssh2_get_u32(struct string_buf *buf, uint32_t *out); -int _libssh2_get_u64(struct string_buf *buf, libssh2_uint64_t *out); -int _libssh2_match_string(struct string_buf *buf, const char *match); -int _libssh2_get_string(struct string_buf *buf, unsigned char **outbuf, - size_t *outlen); -int _libssh2_copy_string(LIBSSH2_SESSION* session, struct string_buf *buf, - unsigned char **outbuf, size_t *outlen); -int _libssh2_get_bignum_bytes(struct string_buf *buf, unsigned char **outbuf, - size_t *outlen); -int _libssh2_check_length(struct string_buf *buf, size_t requested_len); - -#if defined(LIBSSH2_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__) -/* provide a private one */ -#undef HAVE_GETTIMEOFDAY -int __cdecl _libssh2_gettimeofday(struct timeval *tp, void *tzp); -#define HAVE_LIBSSH2_GETTIMEOFDAY -#define LIBSSH2_GETTIMEOFDAY_WIN32 /* enable the win32 implementation */ -#else -#ifdef HAVE_GETTIMEOFDAY -#define _libssh2_gettimeofday(x,y) gettimeofday(x,y) -#define HAVE_LIBSSH2_GETTIMEOFDAY -#endif -#endif - -void _libssh2_xor_data(unsigned char *output, - const unsigned char *input1, - const unsigned char *input2, - size_t length); - -void _libssh2_aes_ctr_increment(unsigned char *ctr, size_t length); - -#endif /* _LIBSSH2_MISC_H */ diff --git a/include/libssh2/module.mk b/include/libssh2/module.mk deleted file mode 100644 index e882048..0000000 --- a/include/libssh2/module.mk +++ /dev/null @@ -1,35 +0,0 @@ -####################################################################### -# -# pgAdmin III - PostgreSQL Tools -# -# Copyright (C) 2002 - 2016, The pgAdmin Development Team -# This software is released under the PostgreSQL Licence -# -# module.mk - pgadmin/include/ Makefile fragment -# -####################################################################### - -if BUILD_SSH_TUNNEL - -pgadmin3_SOURCES += \ - include/libssh2/channel.h \ - include/libssh2/comp.h \ - include/libssh2/crypto.h \ - include/libssh2/libgcrypt.h \ - include/libssh2/libssh2.h \ - include/libssh2/libssh2_priv.h \ - include/libssh2/libssh2_publickey.h \ - include/libssh2/libssh2_sftp.h \ - include/libssh2/mac.h \ - include/libssh2/misc.h \ - include/libssh2/openssl.h \ - include/libssh2/packet.h \ - include/libssh2/session.h \ - include/libssh2/sftp.h \ - include/libssh2/transport.h \ - include/libssh2/userauth.h - -EXTRA_DIST += \ - include/libssh2/module.mk \ - include/libssh2/Win32/libssh2_config.h -endif diff --git a/include/libssh2/openssl.h b/include/libssh2/openssl.h deleted file mode 100644 index f65192d..0000000 --- a/include/libssh2/openssl.h +++ /dev/null @@ -1,398 +0,0 @@ -#ifndef __LIBSSH2_OPENSSL_H -#define __LIBSSH2_OPENSSL_H -/* Copyright (C) 2009, 2010 Simon Josefsson - * Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved. - * - * Author: Simon Josefsson - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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 -#ifndef OPENSSL_NO_ENGINE -#include -#endif -#ifndef OPENSSL_NO_DSA -#include -#endif -#ifndef OPENSSL_NO_MD5 -#include -#endif -#include -#include -#include -#include -#include - -#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \ - !defined(LIBRESSL_VERSION_NUMBER) -# define HAVE_OPAQUE_STRUCTS 1 -#endif - -#ifdef OPENSSL_NO_RSA -# define LIBSSH2_RSA 0 -#else -# define LIBSSH2_RSA 1 -#endif - -#ifdef OPENSSL_NO_DSA -# define LIBSSH2_DSA 0 -#else -# define LIBSSH2_DSA 1 -#endif - -#ifdef OPENSSL_NO_ECDSA -# define LIBSSH2_ECDSA 0 -#else -# define LIBSSH2_ECDSA 1 -#endif - -#if OPENSSL_VERSION_NUMBER >= 0x10101000L && \ -!defined(LIBRESSL_VERSION_NUMBER) -# define LIBSSH2_ED25519 1 -#else -# define LIBSSH2_ED25519 0 -#endif - - -#ifdef OPENSSL_NO_MD5 -# define LIBSSH2_MD5 0 -#else -# define LIBSSH2_MD5 1 -#endif - -#ifdef OPENSSL_NO_RIPEMD -# define LIBSSH2_HMAC_RIPEMD 0 -#else -# define LIBSSH2_HMAC_RIPEMD 1 -#endif - -#define LIBSSH2_HMAC_SHA256 1 -#define LIBSSH2_HMAC_SHA512 1 - -#if OPENSSL_VERSION_NUMBER >= 0x00907000L && !defined(OPENSSL_NO_AES) -# define LIBSSH2_AES_CTR 1 -# define LIBSSH2_AES 1 -#else -# define LIBSSH2_AES_CTR 0 -# define LIBSSH2_AES 0 -#endif - -#ifdef OPENSSL_NO_BF -# define LIBSSH2_BLOWFISH 0 -#else -# define LIBSSH2_BLOWFISH 1 -#endif - -#ifdef OPENSSL_NO_RC4 -# define LIBSSH2_RC4 0 -#else -# define LIBSSH2_RC4 1 -#endif - -#ifdef OPENSSL_NO_CAST -# define LIBSSH2_CAST 0 -#else -# define LIBSSH2_CAST 1 -#endif - -#ifdef OPENSSL_NO_DES -# define LIBSSH2_3DES 0 -#else -# define LIBSSH2_3DES 1 -#endif - -#define EC_MAX_POINT_LEN ((528 * 2 / 8) + 1) - -#define _libssh2_random(buf, len) RAND_bytes ((buf), (len)) - -#define libssh2_prepare_iovec(vec, len) /* Empty. */ - -#ifdef HAVE_OPAQUE_STRUCTS -#define libssh2_sha1_ctx EVP_MD_CTX * -#else -#define libssh2_sha1_ctx EVP_MD_CTX -#endif - -/* returns 0 in case of failure */ -int _libssh2_sha1_init(libssh2_sha1_ctx *ctx); -#define libssh2_sha1_init(x) _libssh2_sha1_init(x) -#ifdef HAVE_OPAQUE_STRUCTS -#define libssh2_sha1_update(ctx, data, len) EVP_DigestUpdate(ctx, data, len) -#define libssh2_sha1_final(ctx, out) do { \ - EVP_DigestFinal(ctx, out, NULL); \ - EVP_MD_CTX_free(ctx); \ - } while(0) -#else -#define libssh2_sha1_update(ctx, data, len) EVP_DigestUpdate(&(ctx), data, len) -#define libssh2_sha1_final(ctx, out) EVP_DigestFinal(&(ctx), out, NULL) -#endif -int _libssh2_sha1(const unsigned char *message, unsigned long len, - unsigned char *out); -#define libssh2_sha1(x,y,z) _libssh2_sha1(x,y,z) - -#ifdef HAVE_OPAQUE_STRUCTS -#define libssh2_sha256_ctx EVP_MD_CTX * -#else -#define libssh2_sha256_ctx EVP_MD_CTX -#endif - -/* returns 0 in case of failure */ -int _libssh2_sha256_init(libssh2_sha256_ctx *ctx); -#define libssh2_sha256_init(x) _libssh2_sha256_init(x) -#ifdef HAVE_OPAQUE_STRUCTS -#define libssh2_sha256_update(ctx, data, len) EVP_DigestUpdate(ctx, data, len) -#define libssh2_sha256_final(ctx, out) do { \ - EVP_DigestFinal(ctx, out, NULL); \ - EVP_MD_CTX_free(ctx); \ - } while(0) -#else -#define libssh2_sha256_update(ctx, data, len) \ - EVP_DigestUpdate(&(ctx), data, len) -#define libssh2_sha256_final(ctx, out) EVP_DigestFinal(&(ctx), out, NULL) -#endif -int _libssh2_sha256(const unsigned char *message, unsigned long len, - unsigned char *out); -#define libssh2_sha256(x,y,z) _libssh2_sha256(x,y,z) - -#ifdef HAVE_OPAQUE_STRUCTS -#define libssh2_sha384_ctx EVP_MD_CTX * -#else -#define libssh2_sha384_ctx EVP_MD_CTX -#endif - -/* returns 0 in case of failure */ -int _libssh2_sha384_init(libssh2_sha384_ctx *ctx); -#define libssh2_sha384_init(x) _libssh2_sha384_init(x) -#ifdef HAVE_OPAQUE_STRUCTS -#define libssh2_sha384_update(ctx, data, len) EVP_DigestUpdate(ctx, data, len) -#define libssh2_sha384_final(ctx, out) do { \ - EVP_DigestFinal(ctx, out, NULL); \ - EVP_MD_CTX_free(ctx); \ - } while(0) -#else -#define libssh2_sha384_update(ctx, data, len) \ - EVP_DigestUpdate(&(ctx), data, len) -#define libssh2_sha384_final(ctx, out) EVP_DigestFinal(&(ctx), out, NULL) -#endif -int _libssh2_sha384(const unsigned char *message, unsigned long len, - unsigned char *out); -#define libssh2_sha384(x,y,z) _libssh2_sha384(x,y,z) - -#ifdef HAVE_OPAQUE_STRUCTS -#define libssh2_sha512_ctx EVP_MD_CTX * -#else -#define libssh2_sha512_ctx EVP_MD_CTX -#endif - -/* returns 0 in case of failure */ -int _libssh2_sha512_init(libssh2_sha512_ctx *ctx); -#define libssh2_sha512_init(x) _libssh2_sha512_init(x) -#ifdef HAVE_OPAQUE_STRUCTS -#define libssh2_sha512_update(ctx, data, len) EVP_DigestUpdate(ctx, data, len) -#define libssh2_sha512_final(ctx, out) do { \ - EVP_DigestFinal(ctx, out, NULL); \ - EVP_MD_CTX_free(ctx); \ - } while(0) -#else -#define libssh2_sha512_update(ctx, data, len) \ - EVP_DigestUpdate(&(ctx), data, len) -#define libssh2_sha512_final(ctx, out) EVP_DigestFinal(&(ctx), out, NULL) -#endif -int _libssh2_sha512(const unsigned char *message, unsigned long len, - unsigned char *out); -#define libssh2_sha512(x,y,z) _libssh2_sha512(x,y,z) - -#ifdef HAVE_OPAQUE_STRUCTS -#define libssh2_md5_ctx EVP_MD_CTX * -#else -#define libssh2_md5_ctx EVP_MD_CTX -#endif - -/* returns 0 in case of failure */ -int _libssh2_md5_init(libssh2_md5_ctx *ctx); -#define libssh2_md5_init(x) _libssh2_md5_init(x) -#ifdef HAVE_OPAQUE_STRUCTS -#define libssh2_md5_update(ctx, data, len) EVP_DigestUpdate(ctx, data, len) -#define libssh2_md5_final(ctx, out) do { \ - EVP_DigestFinal(ctx, out, NULL); \ - EVP_MD_CTX_free(ctx); \ - } while(0) -#else -#define libssh2_md5_update(ctx, data, len) EVP_DigestUpdate(&(ctx), data, len) -#define libssh2_md5_final(ctx, out) EVP_DigestFinal(&(ctx), out, NULL) -#endif - -#ifdef HAVE_OPAQUE_STRUCTS -#define libssh2_hmac_ctx HMAC_CTX * -#define libssh2_hmac_ctx_init(ctx) ctx = HMAC_CTX_new() -#define libssh2_hmac_sha1_init(ctx, key, keylen) \ - HMAC_Init_ex(*(ctx), key, keylen, EVP_sha1(), NULL) -#define libssh2_hmac_md5_init(ctx, key, keylen) \ - HMAC_Init_ex(*(ctx), key, keylen, EVP_md5(), NULL) -#define libssh2_hmac_ripemd160_init(ctx, key, keylen) \ - HMAC_Init_ex(*(ctx), key, keylen, EVP_ripemd160(), NULL) -#define libssh2_hmac_sha256_init(ctx, key, keylen) \ - HMAC_Init_ex(*(ctx), key, keylen, EVP_sha256(), NULL) -#define libssh2_hmac_sha512_init(ctx, key, keylen) \ - HMAC_Init_ex(*(ctx), key, keylen, EVP_sha512(), NULL) - -#define libssh2_hmac_update(ctx, data, datalen) \ - HMAC_Update(ctx, data, datalen) -#define libssh2_hmac_final(ctx, data) HMAC_Final(ctx, data, NULL) -#define libssh2_hmac_cleanup(ctx) HMAC_CTX_free(*(ctx)) -#else -#define libssh2_hmac_ctx HMAC_CTX -#define libssh2_hmac_ctx_init(ctx) \ - HMAC_CTX_init(&ctx) -#define libssh2_hmac_sha1_init(ctx, key, keylen) \ - HMAC_Init_ex(ctx, key, keylen, EVP_sha1(), NULL) -#define libssh2_hmac_md5_init(ctx, key, keylen) \ - HMAC_Init_ex(ctx, key, keylen, EVP_md5(), NULL) -#define libssh2_hmac_ripemd160_init(ctx, key, keylen) \ - HMAC_Init_ex(ctx, key, keylen, EVP_ripemd160(), NULL) -#define libssh2_hmac_sha256_init(ctx, key, keylen) \ - HMAC_Init_ex(ctx, key, keylen, EVP_sha256(), NULL) -#define libssh2_hmac_sha512_init(ctx, key, keylen) \ - HMAC_Init_ex(ctx, key, keylen, EVP_sha512(), NULL) - -#define libssh2_hmac_update(ctx, data, datalen) \ - HMAC_Update(&(ctx), data, datalen) -#define libssh2_hmac_final(ctx, data) HMAC_Final(&(ctx), data, NULL) -#define libssh2_hmac_cleanup(ctx) HMAC_cleanup(ctx) -#endif - -extern void _libssh2_openssl_crypto_init(void); -extern void _libssh2_openssl_crypto_exit(void); -#define libssh2_crypto_init() _libssh2_openssl_crypto_init() -#define libssh2_crypto_exit() _libssh2_openssl_crypto_exit() - -#define libssh2_rsa_ctx RSA - -#define _libssh2_rsa_free(rsactx) RSA_free(rsactx) - -#define libssh2_dsa_ctx DSA - -#define _libssh2_dsa_free(dsactx) DSA_free(dsactx) - -#if LIBSSH2_ECDSA -#define libssh2_ecdsa_ctx EC_KEY -#define _libssh2_ecdsa_free(ecdsactx) EC_KEY_free(ecdsactx) -#define _libssh2_ec_key EC_KEY - -typedef enum { - LIBSSH2_EC_CURVE_NISTP256 = NID_X9_62_prime256v1, - LIBSSH2_EC_CURVE_NISTP384 = NID_secp384r1, - LIBSSH2_EC_CURVE_NISTP521 = NID_secp521r1 -} -libssh2_curve_type; -#else -#define _libssh2_ec_key void -#endif /* LIBSSH2_ECDSA */ - -#if LIBSSH2_ED25519 -#define libssh2_ed25519_ctx EVP_PKEY -#define libssh2_x25519_ctx EVP_PKEY - -#define _libssh2_ed25519_free(ctx) EVP_PKEY_free(ctx) -#define _libssh2_x25519_free(ctx) EVP_PKEY_free(ctx) -#endif /* ED25519 */ - -#define _libssh2_cipher_type(name) const EVP_CIPHER *(*name)(void) -#ifdef HAVE_OPAQUE_STRUCTS -#define _libssh2_cipher_ctx EVP_CIPHER_CTX * -#else -#define _libssh2_cipher_ctx EVP_CIPHER_CTX -#endif - -#define _libssh2_cipher_aes256 EVP_aes_256_cbc -#define _libssh2_cipher_aes192 EVP_aes_192_cbc -#define _libssh2_cipher_aes128 EVP_aes_128_cbc -#ifdef HAVE_EVP_AES_128_CTR -#define _libssh2_cipher_aes128ctr EVP_aes_128_ctr -#define _libssh2_cipher_aes192ctr EVP_aes_192_ctr -#define _libssh2_cipher_aes256ctr EVP_aes_256_ctr -#else -#define _libssh2_cipher_aes128ctr _libssh2_EVP_aes_128_ctr -#define _libssh2_cipher_aes192ctr _libssh2_EVP_aes_192_ctr -#define _libssh2_cipher_aes256ctr _libssh2_EVP_aes_256_ctr -#endif -#define _libssh2_cipher_blowfish EVP_bf_cbc -#define _libssh2_cipher_arcfour EVP_rc4 -#define _libssh2_cipher_cast5 EVP_cast5_cbc -#define _libssh2_cipher_3des EVP_des_ede3_cbc - -#ifdef HAVE_OPAQUE_STRUCTS -#define _libssh2_cipher_dtor(ctx) EVP_CIPHER_CTX_free(*(ctx)) -#else -#define _libssh2_cipher_dtor(ctx) EVP_CIPHER_CTX_cleanup(ctx) -#endif - -#define _libssh2_bn BIGNUM -#define _libssh2_bn_ctx BN_CTX -#define _libssh2_bn_ctx_new() BN_CTX_new() -#define _libssh2_bn_ctx_free(bnctx) BN_CTX_free(bnctx) -#define _libssh2_bn_init() BN_new() -#define _libssh2_bn_init_from_bin() _libssh2_bn_init() -#define _libssh2_bn_set_word(bn, val) BN_set_word(bn, val) -#define _libssh2_bn_from_bin(bn, len, val) BN_bin2bn(val, len, bn) -#define _libssh2_bn_to_bin(bn, val) BN_bn2bin(bn, val) -#define _libssh2_bn_bytes(bn) BN_num_bytes(bn) -#define _libssh2_bn_bits(bn) BN_num_bits(bn) -#define _libssh2_bn_free(bn) BN_clear_free(bn) - -#define _libssh2_dh_ctx BIGNUM * -#define libssh2_dh_init(dhctx) _libssh2_dh_init(dhctx) -#define libssh2_dh_key_pair(dhctx, public, g, p, group_order, bnctx) \ - _libssh2_dh_key_pair(dhctx, public, g, p, group_order, bnctx) -#define libssh2_dh_secret(dhctx, secret, f, p, bnctx) \ - _libssh2_dh_secret(dhctx, secret, f, p, bnctx) -#define libssh2_dh_dtor(dhctx) _libssh2_dh_dtor(dhctx) -extern void _libssh2_dh_init(_libssh2_dh_ctx *dhctx); -extern int _libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public, - _libssh2_bn *g, _libssh2_bn *p, - int group_order, - _libssh2_bn_ctx *bnctx); -extern int _libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret, - _libssh2_bn *f, _libssh2_bn *p, - _libssh2_bn_ctx *bnctx); -extern void _libssh2_dh_dtor(_libssh2_dh_ctx *dhctx); - -const EVP_CIPHER *_libssh2_EVP_aes_128_ctr(void); -const EVP_CIPHER *_libssh2_EVP_aes_192_ctr(void); -const EVP_CIPHER *_libssh2_EVP_aes_256_ctr(void); - -#endif /* __LIBSSH2_OPENSSL_H */ diff --git a/include/libssh2/os400qc3.h b/include/libssh2/os400qc3.h deleted file mode 100644 index d915dc2..0000000 --- a/include/libssh2/os400qc3.h +++ /dev/null @@ -1,391 +0,0 @@ -#ifndef __LIBSSH2_OS400QC3_H -#define __LIBSSH2_OS400QC3_H -/* - * Copyright (C) 2015-2016 Patrick Monnerat, D+H - * Copyright (C) 2020 Patrick Monnerat . - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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 - - -/* Redefine character/string literals as always EBCDIC. */ -#undef Qc3_Alg_Token -#define Qc3_Alg_Token "\xC1\xD3\xC7\xC4\xF0\xF1\xF0\xF0" /* ALGD0100 */ -#undef Qc3_Alg_Block_Cipher -#define Qc3_Alg_Block_Cipher "\xC1\xD3\xC7\xC4\xF0\xF2\xF0\xF0" /* ALGD0200 */ -#undef Qc3_Alg_Block_CipherAuth -#define Qc3_Alg_Block_CipherAuth \ - "\xC1\xD3\xC7\xC4\xF0\xF2\xF1\xF0" /* ALGD0210 */ -#undef Qc3_Alg_Stream_Cipher -#define Qc3_Alg_Stream_Cipher \ - "\xC1\xD3\xC7\xC4\xF0\xF3\xF0\xF0" /* ALGD0300 */ -#undef Qc3_Alg_Public_Key -#define Qc3_Alg_Public_Key "\xC1\xD3\xC7\xC4\xF0\xF4\xF0\xF0" /* ALGD0400 */ -#undef Qc3_Alg_Hash -#define Qc3_Alg_Hash "\xC1\xD3\xC7\xC4\xF0\xF5\xF0\xF0" /* ALGD0500 */ -#undef Qc3_Data -#define Qc3_Data "\xC4\xC1\xE3\xC1\xF0\xF1\xF0\xF0" /* DATA0100 */ -#undef Qc3_Array -#define Qc3_Array "\xC4\xC1\xE3\xC1\xF0\xF2\xF0\xF0" /* DATA0200 */ -#undef Qc3_Key_Token -#define Qc3_Key_Token "\xD2\xC5\xE8\xC4\xF0\xF1\xF0\xF0" /* KEYD0100 */ -#undef Qc3_Key_Parms -#define Qc3_Key_Parms "\xD2\xC5\xE8\xC4\xF0\xF2\xF0\xF0" /* KEYD0200 */ -#undef Qc3_Key_KSLabel -#define Qc3_Key_KSLabel "\xD2\xC5\xE8\xC4\xF0\xF4\xF0\xF0" /* KEYD0400 */ -#undef Qc3_Key_PKCS5 -#define Qc3_Key_PKCS5 "\xD2\xC5\xE8\xC4\xF0\xF5\xF0\xF0" /* KEYD0500 */ -#undef Qc3_Key_PEMCert -#define Qc3_Key_PEMCert "\xD2\xC5\xE8\xC4\xF0\xF6\xF0\xF0" /* KEYD0600 */ -#undef Qc3_Key_CSLabel -#define Qc3_Key_CSLabel "\xD2\xC5\xE8\xC4\xF0\xF7\xF0\xF0" /* KEYD0700 */ -#undef Qc3_Key_CSDN -#define Qc3_Key_CSDN "\xD2\xC5\xE8\xC4\xF0\xF8\xF0\xF0" /* KEYD0800 */ -#undef Qc3_Key_AppID -#define Qc3_Key_AppID "\xD2\xC5\xE8\xC4\xF0\xF9\xF0\xF0" /* KEYD0900 */ - -#undef Qc3_ECB -#define Qc3_ECB '\xF0' /* '0' */ -#undef Qc3_CBC -#define Qc3_CBC '\xF1' /* '1' */ -#undef Qc3_OFB -#define Qc3_OFB '\xF2' /* '2' */ -#undef Qc3_CFB1Bit -#define Qc3_CFB1Bit '\xF3' /* '3' */ -#undef Qc3_CFB8Bit -#define Qc3_CFB8Bit '\xF4' /* '4' */ -#undef Qc3_CFB64Bit -#define Qc3_CFB64Bit '\xF5' /* '5' */ -#undef Qc3_CUSP -#define Qc3_CUSP '\xF6' /* '6' */ -#undef Qc3_CTR -#define Qc3_CTR '\xF7' /* '7' */ -#undef Qc3_CCM -#define Qc3_CCM '\xF8' /* '8' */ -#undef Qc3_No_Pad -#define Qc3_No_Pad '\xF0' /* '0' */ -#undef Qc3_Pad_Char -#define Qc3_Pad_Char '\xF1' /* '1' */ -#undef Qc3_Pad_Counter -#define Qc3_Pad_Counter '\xF2' /* '2' */ -#undef Qc3_PKCS1_00 -#define Qc3_PKCS1_00 '\xF0' /* '0' */ -#undef Qc3_PKCS1_01 -#define Qc3_PKCS1_01 '\xF1' /* '1' */ -#undef Qc3_PKCS1_02 -#define Qc3_PKCS1_02 '\xF2' /* '2' */ -#undef Qc3_ISO9796 -#define Qc3_ISO9796 '\xF3' /* '3' */ -#undef Qc3_Zero_Pad -#define Qc3_Zero_Pad '\xF4' /* '4' */ -#undef Qc3_ANSI_X931 -#define Qc3_ANSI_X931 '\xF5' /* '5' */ -#undef Qc3_OAEP -#define Qc3_OAEP '\xF6' /* '6' */ -#undef Qc3_Bin_String -#define Qc3_Bin_String '\xF0' /* '0' */ -#undef Qc3_BER_String -#define Qc3_BER_String '\xF1' /* '1' */ -#undef Qc3_MK_Struct -#define Qc3_MK_Struct '\xF3' /* '3' */ -#undef Qc3_KSLabel_Struct -#define Qc3_KSLabel_Struct '\xF4' /* '4' */ -#undef Qc3_PKCS5_Struct -#define Qc3_PKCS5_Struct '\xF5' /* '5' */ -#undef Qc3_PEMCert_String -#define Qc3_PEMCert_String '\xF6' /* '6' */ -#undef Qc3_CSLabel_String -#define Qc3_CSLabel_String '\xF7' /* '7' */ -#undef Qc3_CSDN_String -#define Qc3_CSDN_String '\xF8' /* '8' */ -#undef Qc3_Clear -#define Qc3_Clear '\xF0' /* '0' */ -#undef Qc3_Encrypted -#define Qc3_Encrypted '\xF1' /* '1' */ -#undef Qc3_MK_Encrypted -#define Qc3_MK_Encrypted '\xF2' /* '2' */ -#undef Qc3_Any_CSP -#define Qc3_Any_CSP '\xF0' /* '0' */ -#undef Qc3_Sfw_CSP -#define Qc3_Sfw_CSP '\xF1' /* '1' */ -#undef Qc3_Hdw_CSP -#define Qc3_Hdw_CSP '\xF2' /* '2' */ -#undef Qc3_Continue -#define Qc3_Continue '\xF0' /* '0' */ -#undef Qc3_Final -#define Qc3_Final '\xF1' /* '1' */ -#undef Qc3_MK_New -#define Qc3_MK_New '\xF0' /* '0' */ -#undef Qc3_MK_Current -#define Qc3_MK_Current '\xF1' /* '1' */ -#undef Qc3_MK_Old -#define Qc3_MK_Old '\xF2' /* '2' */ -#undef Qc3_MK_Pending -#define Qc3_MK_Pending '\xF3' /* '3' */ - - -/* Define which features are supported. */ -#define LIBSSH2_MD5 1 -#define LIBSSH2_HMAC_RIPEMD 0 -#define LIBSSH2_HMAC_SHA256 1 -#define LIBSSH2_HMAC_SHA512 1 - -#define LIBSSH2_AES 1 -#define LIBSSH2_AES_CTR 1 -#define LIBSSH2_BLOWFISH 0 -#define LIBSSH2_RC4 1 -#define LIBSSH2_CAST 0 -#define LIBSSH2_3DES 1 - -#define LIBSSH2_RSA 1 -#define LIBSSH2_DSA 0 -#define LIBSSH2_ECDSA 0 -#define LIBSSH2_ED25519 0 - -#define MD5_DIGEST_LENGTH 16 -#define SHA_DIGEST_LENGTH 20 -#define SHA256_DIGEST_LENGTH 32 -#define SHA512_DIGEST_LENGTH 64 - -#define EC_MAX_POINT_LEN ((528 * 2 / 8) + 1) - -#if LIBSSH2_ECDSA -#else -#define _libssh2_ec_key void -#endif - -/******************************************************************* - * - * OS/400 QC3 crypto-library backend: global handles structures. - * - *******************************************************************/ - -/* HMAC & private key algorithms support structure. */ -typedef struct _libssh2_os400qc3_crypto_ctx _libssh2_os400qc3_crypto_ctx; -struct _libssh2_os400qc3_crypto_ctx { - Qc3_Format_ALGD0100_T hash; /* Hash algorithm. */ - Qc3_Format_KEYD0100_T key; /* Key. */ - _libssh2_os400qc3_crypto_ctx * kek; /* Key encryption. */ -}; - -typedef struct { /* Big number. */ - unsigned char * bignum; /* Number bits, little-endian. */ - unsigned int length; /* Length of bignum (# bytes). */ -} _libssh2_bn; - -typedef struct { /* Algorithm description. */ - char * fmt; /* Format of Qc3 structure. */ - int algo; /* Algorithm identifier. */ - unsigned char size; /* Block length. */ - unsigned char mode; /* Block mode. */ - int keylen; /* Key length. */ -} _libssh2_os400qc3_cipher_t; - -typedef struct { /* Diffie-Hellman context. */ - char token[8]; /* Context token. */ -} _libssh2_os400qc3_dh_ctx; - -/******************************************************************* - * - * OS/400 QC3 crypto-library backend: Define global types/codes. - * - *******************************************************************/ - -#define libssh2_crypto_init() -#define libssh2_crypto_exit() - -#define libssh2_sha1_ctx Qc3_Format_ALGD0100_T -#define libssh2_sha256_ctx Qc3_Format_ALGD0100_T -#define libssh2_sha512_ctx Qc3_Format_ALGD0100_T -#define libssh2_md5_ctx Qc3_Format_ALGD0100_T -#define libssh2_hmac_ctx _libssh2_os400qc3_crypto_ctx -#define _libssh2_cipher_ctx _libssh2_os400qc3_crypto_ctx - -#define libssh2_sha1_init(x) libssh2_os400qc3_hash_init(x, Qc3_SHA1) -#define libssh2_sha1_update(ctx, data, len) \ - libssh2_os400qc3_hash_update(&(ctx), data, len) -#define libssh2_sha1_final(ctx, out) \ - libssh2_os400qc3_hash_final(&(ctx), out) -#define libssh2_sha256_init(x) libssh2_os400qc3_hash_init(x, Qc3_SHA256) -#define libssh2_sha256_update(ctx, data, len) \ - libssh2_os400qc3_hash_update(&(ctx), data, len) -#define libssh2_sha256_final(ctx, out) \ - libssh2_os400qc3_hash_final(&(ctx), out) -#define libssh2_sha256(message, len, out) \ - libssh2_os400qc3_hash(message, len, out, \ - Qc3_SHA256) -#define libssh2_sha512_init(x) libssh2_os400qc3_hash_init(x, Qc3_SHA512) -#define libssh2_sha512_update(ctx, data, len) \ - libssh2_os400qc3_hash_update(&(ctx), data, len) -#define libssh2_sha512_final(ctx, out) \ - libssh2_os400qc3_hash_final(&(ctx), out) -#define libssh2_sha512(message, len, out) \ - libssh2_os400qc3_hash(message, len, out, \ - Qc3_SHA512) -#define libssh2_md5_init(x) libssh2_os400qc3_hash_init(x, Qc3_MD5) -#define libssh2_md5_update(ctx, data, len) \ - libssh2_os400qc3_hash_update(&(ctx), data, len) -#define libssh2_md5_final(ctx, out) \ - libssh2_os400qc3_hash_final(&(ctx), out) -#define libssh2_hmac_ctx_init(ctx) \ - memset((char *) &(ctx), 0, \ - sizeof(libssh2_hmac_ctx)) -#define libssh2_hmac_md5_init(ctx, key, keylen) \ - libssh2_os400qc3_hmac_init(ctx, Qc3_MD5, \ - MD5_DIGEST_LENGTH, \ - key, keylen) -#define libssh2_hmac_sha1_init(ctx, key, keylen) \ - libssh2_os400qc3_hmac_init(ctx, Qc3_SHA1, \ - SHA_DIGEST_LENGTH, \ - key, keylen) -#define libssh2_hmac_sha256_init(ctx, key, keylen) \ - libssh2_os400qc3_hmac_init(ctx, Qc3_SHA256, \ - SHA256_DIGEST_LENGTH, \ - key, keylen) -#define libssh2_hmac_sha512_init(ctx, key, keylen) \ - libssh2_os400qc3_hmac_init(ctx, Qc3_SHA512, \ - SHA512_DIGEST_LENGTH, \ - key, keylen) -#define libssh2_hmac_update(ctx, data, datalen) \ - libssh2_os400qc3_hmac_update(&(ctx), \ - data, datalen) -#define libssh2_hmac_final(ctx, data) \ - libssh2_os400qc3_hmac_final(&(ctx), data) -#define libssh2_hmac_cleanup(ctx) \ - _libssh2_os400qc3_crypto_dtor(ctx) - - -#define _libssh2_bn_ctx int /* Not used. */ - -#define _libssh2_bn_ctx_new() 0 -#define _libssh2_bn_ctx_free(bnctx) ((void) 0) - -#define _libssh2_bn_init_from_bin() _libssh2_bn_init() -#define _libssh2_bn_bytes(bn) ((bn)->length) - -#define _libssh2_cipher_type(name) _libssh2_os400qc3_cipher_t name -#define _libssh2_cipher_aes128 {Qc3_Alg_Block_Cipher, Qc3_AES, 16, \ - Qc3_CBC, 16} -#define _libssh2_cipher_aes192 {Qc3_Alg_Block_Cipher, Qc3_AES, 24, \ - Qc3_CBC, 24} -#define _libssh2_cipher_aes256 {Qc3_Alg_Block_Cipher, Qc3_AES, 32, \ - Qc3_CBC, 32} -#define _libssh2_cipher_aes128ctr {Qc3_Alg_Block_Cipher, Qc3_AES, 16, \ - Qc3_CTR, 16} -#define _libssh2_cipher_aes192ctr {Qc3_Alg_Block_Cipher, Qc3_AES, 24, \ - Qc3_CTR, 24} -#define _libssh2_cipher_aes256ctr {Qc3_Alg_Block_Cipher, Qc3_AES, 32, \ - Qc3_CTR, 32} -#define _libssh2_cipher_3des {Qc3_Alg_Block_Cipher, Qc3_TDES, 0, \ - Qc3_CBC, 24} -#define _libssh2_cipher_arcfour {Qc3_Alg_Stream_Cipher, Qc3_RC4, 0, 0, 16} - -#define _libssh2_cipher_dtor(ctx) _libssh2_os400qc3_crypto_dtor(ctx) - -#define libssh2_rsa_ctx _libssh2_os400qc3_crypto_ctx -#define _libssh2_rsa_free(ctx) (_libssh2_os400qc3_crypto_dtor(ctx), \ - free((char *) ctx)) -#define libssh2_prepare_iovec(vec, len) memset((char *) (vec), 0, \ - (len) * sizeof(struct iovec)) -#define _libssh2_rsa_sha1_signv(session, sig, siglen, count, vector, ctx) \ - _libssh2_os400qc3_rsa_sha1_signv(session, sig, siglen, \ - count, vector, ctx) - -#define _libssh2_dh_ctx _libssh2_os400qc3_dh_ctx -#define libssh2_dh_init(dhctx) _libssh2_os400qc3_dh_init(dhctx) -#define libssh2_dh_key_pair(dhctx, public, g, p, group_order, bnctx) \ - _libssh2_os400qc3_dh_key_pair(dhctx, public, g, p, group_order) -#define libssh2_dh_secret(dhctx, secret, f, p, bnctx) \ - _libssh2_os400qc3_dh_secret(dhctx, secret, f, p) -#define libssh2_dh_dtor(dhctx) _libssh2_os400qc3_dh_dtor(dhctx) - - -/******************************************************************* - * - * OS/400 QC3 crypto-library backend: Support procedure prototypes. - * - *******************************************************************/ - -extern _libssh2_bn * _libssh2_bn_init(void); -extern void _libssh2_bn_free(_libssh2_bn *bn); -extern unsigned long _libssh2_bn_bits(_libssh2_bn *bn); -extern int _libssh2_bn_from_bin(_libssh2_bn *bn, int len, - const unsigned char *v); -extern int _libssh2_bn_set_word(_libssh2_bn *bn, unsigned long val); -extern int _libssh2_bn_to_bin(_libssh2_bn *bn, unsigned char *val); -extern void _libssh2_random(unsigned char *buf, int len); -extern void _libssh2_os400qc3_crypto_dtor(_libssh2_os400qc3_crypto_ctx *x); -extern int libssh2_os400qc3_hash_init(Qc3_Format_ALGD0100_T *x, - unsigned int algo); -extern void libssh2_os400qc3_hash_update(Qc3_Format_ALGD0100_T *ctx, - const unsigned char *data, - int len); -extern void libssh2_os400qc3_hash_final(Qc3_Format_ALGD0100_T *ctx, - unsigned char *out); -extern int libssh2_os400qc3_hash(const unsigned char *message, - unsigned long len, unsigned char *out, - unsigned int algo); -extern void libssh2_os400qc3_hmac_init(_libssh2_os400qc3_crypto_ctx *x, - int algo, size_t minkeylen, - void *key, int keylen); -extern void libssh2_os400qc3_hmac_update(_libssh2_os400qc3_crypto_ctx *ctx, - const unsigned char *data, - int len); -extern void libssh2_os400qc3_hmac_final(_libssh2_os400qc3_crypto_ctx *ctx, - unsigned char *out); -extern int _libssh2_os400qc3_rsa_sha1_signv(LIBSSH2_SESSION *session, - unsigned char **signature, - size_t *signature_len, - int veccount, - const struct iovec vector[], - libssh2_rsa_ctx *ctx); -extern void _libssh2_os400qc3_dh_init(_libssh2_dh_ctx *dhctx); -extern int _libssh2_os400qc3_dh_key_pair(_libssh2_dh_ctx *dhctx, - _libssh2_bn *public, - _libssh2_bn *g, - _libssh2_bn *p, int group_order); -extern int _libssh2_os400qc3_dh_secret(_libssh2_dh_ctx *dhctx, - _libssh2_bn *secret, - _libssh2_bn *f, _libssh2_bn *p); -extern void _libssh2_os400qc3_dh_dtor(_libssh2_dh_ctx *dhctx); - -#endif /* __LIBSSH2_OS400QC3_H */ - -/* vim: set expandtab ts=4 sw=4: */ diff --git a/include/libssh2/packet.h b/include/libssh2/packet.h deleted file mode 100644 index 79018bc..0000000 --- a/include/libssh2/packet.h +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef __LIBSSH2_PACKET_H -#define __LIBSSH2_PACKET_H -/* - * Copyright (C) 2010 by Daniel Stenberg - * Author: Daniel Stenberg - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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. - * - */ - -int _libssh2_packet_read(LIBSSH2_SESSION * session); - -int _libssh2_packet_ask(LIBSSH2_SESSION * session, unsigned char packet_type, - unsigned char **data, size_t *data_len, - int match_ofs, - const unsigned char *match_buf, - size_t match_len); - -int _libssh2_packet_askv(LIBSSH2_SESSION * session, - const unsigned char *packet_types, - unsigned char **data, size_t *data_len, - int match_ofs, - const unsigned char *match_buf, - size_t match_len); -int _libssh2_packet_require(LIBSSH2_SESSION * session, - unsigned char packet_type, unsigned char **data, - size_t *data_len, int match_ofs, - const unsigned char *match_buf, - size_t match_len, - packet_require_state_t * state); -int _libssh2_packet_requirev(LIBSSH2_SESSION *session, - const unsigned char *packet_types, - unsigned char **data, size_t *data_len, - int match_ofs, - const unsigned char *match_buf, - size_t match_len, - packet_requirev_state_t * state); -int _libssh2_packet_burn(LIBSSH2_SESSION * session, - libssh2_nonblocking_states * state); -int _libssh2_packet_write(LIBSSH2_SESSION * session, unsigned char *data, - unsigned long data_len); -int _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, - size_t datalen, int macstate); - -#endif /* __LIBSSH2_PACKET_H */ diff --git a/include/libssh2/session.h b/include/libssh2/session.h deleted file mode 100644 index 9f8f2c7..0000000 --- a/include/libssh2/session.h +++ /dev/null @@ -1,93 +0,0 @@ -#ifndef __LIBSSH2_SESSION_H -#define __LIBSSH2_SESSION_H -/* Copyright (c) 2004-2007 Sara Golemon - * Copyright (c) 2009-2010 by Daniel Stenberg - * Copyright (c) 2010 Simon Josefsson - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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. - */ - -/* Conveniance-macros to allow code like this; - - int rc = BLOCK_ADJUST(rc, session, session_startup(session, sock) ); - - int rc = BLOCK_ADJUST_ERRNO(ptr, session, session_startup(session, sock) ); - - The point of course being to make sure that while in non-blocking mode - these always return no matter what the return code is, but in blocking mode - it blocks if EAGAIN is the reason for the return from the underlying - function. - -*/ -#define BLOCK_ADJUST(rc, sess, x) \ - do { \ - time_t entry_time = time(NULL); \ - do { \ - rc = x; \ - /* the order of the check below is important to properly deal with \ - the case when the 'sess' is freed */ \ - if((rc != LIBSSH2_ERROR_EAGAIN) || !sess->api_block_mode) \ - break; \ - rc = _libssh2_wait_socket(sess, entry_time); \ - } while(!rc); \ - } while(0) - -/* - * For functions that returns a pointer, we need to check if the API is - * non-blocking and return immediately. If the pointer is non-NULL we return - * immediately. If the API is blocking and we get a NULL we check the errno - * and *only* if that is EAGAIN we loop and wait for socket action. - */ -#define BLOCK_ADJUST_ERRNO(ptr, sess, x) \ - do { \ - time_t entry_time = time(NULL); \ - int rc; \ - do { \ - ptr = x; \ - if(!sess->api_block_mode || \ - (ptr != NULL) || \ - (libssh2_session_last_errno(sess) != LIBSSH2_ERROR_EAGAIN) ) \ - break; \ - rc = _libssh2_wait_socket(sess, entry_time); \ - } while(!rc); \ - } while(0) - - -int _libssh2_wait_socket(LIBSSH2_SESSION *session, time_t entry_time); - -/* this is the lib-internal set blocking function */ -int _libssh2_session_set_blocking(LIBSSH2_SESSION * session, int blocking); - -#endif /* __LIBSSH2_SESSION_H */ diff --git a/include/libssh2/sftp.h b/include/libssh2/sftp.h deleted file mode 100644 index 129b8f0..0000000 --- a/include/libssh2/sftp.h +++ /dev/null @@ -1,238 +0,0 @@ -#ifndef __LIBSSH2_SFTP_H -#define __LIBSSH2_SFTP_H -/* - * Copyright (C) 2010 - 2012 by Daniel Stenberg - * Author: Daniel Stenberg - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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. - * - */ - -/* - * MAX_SFTP_OUTGOING_SIZE MUST not be larger than 32500 or so. This is the - * amount of data sent in each FXP_WRITE packet - */ -#define MAX_SFTP_OUTGOING_SIZE 30000 - -/* MAX_SFTP_READ_SIZE is how much data is asked for at max in each FXP_READ - * packets. - */ -#define MAX_SFTP_READ_SIZE 30000 - -struct sftp_pipeline_chunk { - struct list_node node; - libssh2_uint64_t offset; /* READ: offset at which to start reading - WRITE: not used */ - size_t len; /* WRITE: size of the data to write - READ: how many bytes that was asked for */ - size_t sent; - ssize_t lefttosend; /* if 0, the entire packet has been sent off */ - uint32_t request_id; - unsigned char packet[1]; /* data */ -}; - -struct sftp_zombie_requests { - struct list_node node; - uint32_t request_id; -}; - -#ifndef MIN -#define MIN(x,y) ((x)<(y)?(x):(y)) -#endif - -struct _LIBSSH2_SFTP_PACKET -{ - struct list_node node; /* linked list header */ - uint32_t request_id; - unsigned char *data; - size_t data_len; /* payload size */ -}; - -typedef struct _LIBSSH2_SFTP_PACKET LIBSSH2_SFTP_PACKET; - -#define SFTP_HANDLE_MAXLEN 256 /* according to spec! */ - -struct _LIBSSH2_SFTP_HANDLE -{ - struct list_node node; - - LIBSSH2_SFTP *sftp; - - char handle[SFTP_HANDLE_MAXLEN]; - size_t handle_len; - - enum { - LIBSSH2_SFTP_HANDLE_FILE, - LIBSSH2_SFTP_HANDLE_DIR - } handle_type; - - union _libssh2_sftp_handle_data - { - struct _libssh2_sftp_handle_file_data - { - libssh2_uint64_t offset; - libssh2_uint64_t offset_sent; - size_t acked; /* container for acked data that hasn't been - returned to caller yet, used for sftp_write */ - - /* 'data' is used by sftp_read() and is allocated data that has - been received already from the server but wasn't returned to - the caller yet. It is of size 'data_len' and 'data_left is the - number of bytes not yet returned, counted from the end of the - buffer. */ - unsigned char *data; - size_t data_len; - size_t data_left; - - char eof; /* we have read to the end */ - } file; - struct _libssh2_sftp_handle_dir_data - { - uint32_t names_left; - void *names_packet; - char *next_name; - size_t names_packet_len; - } dir; - } u; - - /* State variables used in libssh2_sftp_close_handle() */ - libssh2_nonblocking_states close_state; - uint32_t close_request_id; - unsigned char *close_packet; - - /* list of outstanding packets sent to server */ - struct list_head packet_list; - -}; - -struct _LIBSSH2_SFTP -{ - LIBSSH2_CHANNEL *channel; - - uint32_t request_id, version; - - struct list_head packets; - - /* List of FXP_READ responses to ignore because EOF already received. */ - struct list_head zombie_requests; - - /* a list of _LIBSSH2_SFTP_HANDLE structs */ - struct list_head sftp_handles; - - uint32_t last_errno; - - /* Holder for partial packet, use in libssh2_sftp_packet_read() */ - unsigned char partial_size[4]; /* buffer for size field */ - size_t partial_size_len; /* size field length */ - unsigned char *partial_packet; /* The data */ - uint32_t partial_len; /* Desired number of bytes */ - size_t partial_received; /* Bytes received so far */ - - /* Time that libssh2_sftp_packet_requirev() started reading */ - time_t requirev_start; - - /* State variables used in libssh2_sftp_open_ex() */ - libssh2_nonblocking_states open_state; - unsigned char *open_packet; - uint32_t open_packet_len; /* 32 bit on the wire */ - size_t open_packet_sent; - uint32_t open_request_id; - - /* State variable used in sftp_read() */ - libssh2_nonblocking_states read_state; - - /* State variable used in sftp_packet_read() */ - libssh2_nonblocking_states packet_state; - - /* State variable used in sftp_write() */ - libssh2_nonblocking_states write_state; - - /* State variables used in sftp_fsync() */ - libssh2_nonblocking_states fsync_state; - unsigned char *fsync_packet; - uint32_t fsync_request_id; - - /* State variables used in libssh2_sftp_readdir() */ - libssh2_nonblocking_states readdir_state; - unsigned char *readdir_packet; - uint32_t readdir_request_id; - - /* State variables used in libssh2_sftp_fstat_ex() */ - libssh2_nonblocking_states fstat_state; - unsigned char *fstat_packet; - uint32_t fstat_request_id; - - /* State variables used in libssh2_sftp_unlink_ex() */ - libssh2_nonblocking_states unlink_state; - unsigned char *unlink_packet; - uint32_t unlink_request_id; - - /* State variables used in libssh2_sftp_rename_ex() */ - libssh2_nonblocking_states rename_state; - unsigned char *rename_packet; - unsigned char *rename_s; - uint32_t rename_request_id; - - /* State variables used in libssh2_sftp_fstatvfs() */ - libssh2_nonblocking_states fstatvfs_state; - unsigned char *fstatvfs_packet; - uint32_t fstatvfs_request_id; - - /* State variables used in libssh2_sftp_statvfs() */ - libssh2_nonblocking_states statvfs_state; - unsigned char *statvfs_packet; - uint32_t statvfs_request_id; - - /* State variables used in libssh2_sftp_mkdir() */ - libssh2_nonblocking_states mkdir_state; - unsigned char *mkdir_packet; - uint32_t mkdir_request_id; - - /* State variables used in libssh2_sftp_rmdir() */ - libssh2_nonblocking_states rmdir_state; - unsigned char *rmdir_packet; - uint32_t rmdir_request_id; - - /* State variables used in libssh2_sftp_stat() */ - libssh2_nonblocking_states stat_state; - unsigned char *stat_packet; - uint32_t stat_request_id; - - /* State variables used in libssh2_sftp_symlink() */ - libssh2_nonblocking_states symlink_state; - unsigned char *symlink_packet; - uint32_t symlink_request_id; -}; - -#endif /* __LIBSSH2_SFTP_H */ diff --git a/include/libssh2/transport.h b/include/libssh2/transport.h deleted file mode 100644 index 7d395d0..0000000 --- a/include/libssh2/transport.h +++ /dev/null @@ -1,86 +0,0 @@ -#ifndef __LIBSSH2_TRANSPORT_H -#define __LIBSSH2_TRANSPORT_H -/* Copyright (C) 2007 The Written Word, Inc. All rights reserved. - * Copyright (C) 2009-2010 by Daniel Stenberg - * Author: Daniel Stenberg - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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. - * - * This file handles reading and writing to the SECSH transport layer. RFC4253. - */ - -#include "libssh2_priv.h" -#include "packet.h" - - -/* - * libssh2_transport_send - * - * Send a packet, encrypting it and adding a MAC code if necessary - * Returns 0 on success, non-zero on failure. - * - * The data is provided as _two_ data areas that are combined by this - * function. The 'data' part is sent immediately before 'data2'. 'data2' can - * be set to NULL (or data2_len to 0) to only use a single part. - * - * Returns LIBSSH2_ERROR_EAGAIN if it would block or if the whole packet was - * not sent yet. If it does so, the caller should call this function again as - * soon as it is likely that more data can be sent, and this function MUST - * then be called with the same argument set (same data pointer and same - * data_len) until ERROR_NONE or failure is returned. - * - * This function DOES NOT call _libssh2_error() on any errors. - */ -int _libssh2_transport_send(LIBSSH2_SESSION *session, - const unsigned char *data, size_t data_len, - const unsigned char *data2, size_t data2_len); - -/* - * _libssh2_transport_read - * - * Collect a packet into the input brigade block only controls whether or not - * to wait for a packet to start. - * - * Returns packet type added to input brigade (PACKET_NONE if nothing added), - * or PACKET_FAIL on failure and PACKET_EAGAIN if it couldn't process a full - * packet. - */ - -/* - * This function reads the binary stream as specified in chapter 6 of RFC4253 - * "The Secure Shell (SSH) Transport Layer Protocol" - */ -int _libssh2_transport_read(LIBSSH2_SESSION * session); - -#endif /* __LIBSSH2_TRANSPORT_H */ diff --git a/include/libssh2/userauth.h b/include/libssh2/userauth.h deleted file mode 100644 index 6b402dd..0000000 --- a/include/libssh2/userauth.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef __LIBSSH2_USERAUTH_H -#define __LIBSSH2_USERAUTH_H -/* Copyright (c) 2004-2007, Sara Golemon - * Copyright (c) 2009-2010 by Daniel Stenberg - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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. - */ - -int -_libssh2_userauth_publickey(LIBSSH2_SESSION *session, - const char *username, - unsigned int username_len, - const unsigned char *pubkeydata, - unsigned long pubkeydata_len, - LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC - ((*sign_callback)), - void *abstract); - -#endif /* __LIBSSH2_USERAUTH_H */ diff --git a/include/libssh2/wincng.h b/include/libssh2/wincng.h deleted file mode 100644 index c817f09..0000000 --- a/include/libssh2/wincng.h +++ /dev/null @@ -1,575 +0,0 @@ -#ifndef __LIBSSH2_WINCNG_H -#define __LIBSSH2_WINCNG_H -/* - * Copyright (C) 2013-2020 Marc Hoersken - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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. - */ - -/* required for cross-compilation against the w64 mingw-runtime package */ -#if defined(_WIN32_WINNT) && (_WIN32_WINNT < 0x0600) -#undef _WIN32_WINNT -#endif -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0600 -#endif - -#include -#include - - -#define LIBSSH2_MD5 1 - -#define LIBSSH2_HMAC_RIPEMD 0 -#define LIBSSH2_HMAC_SHA256 1 -#define LIBSSH2_HMAC_SHA512 1 - -#define LIBSSH2_AES 1 -#define LIBSSH2_AES_CTR 1 -#define LIBSSH2_BLOWFISH 0 -#define LIBSSH2_RC4 1 -#define LIBSSH2_CAST 0 -#define LIBSSH2_3DES 1 - -#define LIBSSH2_RSA 1 -#define LIBSSH2_DSA 1 -#define LIBSSH2_ECDSA 0 -#define LIBSSH2_ED25519 0 - -#define MD5_DIGEST_LENGTH 16 -#define SHA_DIGEST_LENGTH 20 -#define SHA256_DIGEST_LENGTH 32 -#define SHA512_DIGEST_LENGTH 64 - -#define EC_MAX_POINT_LEN ((528 * 2 / 8) + 1) - -#if LIBSSH2_ECDSA -#else -#define _libssh2_ec_key void -#endif - -/*******************************************************************/ -/* - * Windows CNG backend: Global context handles - */ - -struct _libssh2_wincng_ctx { - BCRYPT_ALG_HANDLE hAlgRNG; - BCRYPT_ALG_HANDLE hAlgHashMD5; - BCRYPT_ALG_HANDLE hAlgHashSHA1; - BCRYPT_ALG_HANDLE hAlgHashSHA256; - BCRYPT_ALG_HANDLE hAlgHashSHA512; - BCRYPT_ALG_HANDLE hAlgHmacMD5; - BCRYPT_ALG_HANDLE hAlgHmacSHA1; - BCRYPT_ALG_HANDLE hAlgHmacSHA256; - BCRYPT_ALG_HANDLE hAlgHmacSHA512; - BCRYPT_ALG_HANDLE hAlgRSA; - BCRYPT_ALG_HANDLE hAlgDSA; - BCRYPT_ALG_HANDLE hAlgAES_CBC; - BCRYPT_ALG_HANDLE hAlgAES_ECB; - BCRYPT_ALG_HANDLE hAlgRC4_NA; - BCRYPT_ALG_HANDLE hAlg3DES_CBC; -}; - -extern struct _libssh2_wincng_ctx _libssh2_wincng; - - -/*******************************************************************/ -/* - * Windows CNG backend: Generic functions - */ - -void _libssh2_wincng_init(void); -void _libssh2_wincng_free(void); - -#define libssh2_crypto_init() \ - _libssh2_wincng_init() -#define libssh2_crypto_exit() \ - _libssh2_wincng_free() - -#define _libssh2_random(buf, len) \ - _libssh2_wincng_random(buf, len) - -#define libssh2_prepare_iovec(vec, len) /* Empty. */ - - -/*******************************************************************/ -/* - * Windows CNG backend: Hash structure - */ - -typedef struct __libssh2_wincng_hash_ctx { - BCRYPT_HASH_HANDLE hHash; - unsigned char *pbHashObject; - unsigned long dwHashObject; - unsigned long cbHash; -} _libssh2_wincng_hash_ctx; - -/* - * Windows CNG backend: Hash functions - */ - -#define libssh2_sha1_ctx _libssh2_wincng_hash_ctx -#define libssh2_sha1_init(ctx) \ - (_libssh2_wincng_hash_init(ctx, _libssh2_wincng.hAlgHashSHA1, \ - SHA_DIGEST_LENGTH, NULL, 0) == 0) -#define libssh2_sha1_update(ctx, data, datalen) \ - _libssh2_wincng_hash_update(&ctx, (unsigned char *) data, datalen) -#define libssh2_sha1_final(ctx, hash) \ - _libssh2_wincng_hash_final(&ctx, hash) -#define libssh2_sha1(data, datalen, hash) \ - _libssh2_wincng_hash(data, datalen, _libssh2_wincng.hAlgHashSHA1, \ - hash, SHA_DIGEST_LENGTH) - -#define libssh2_sha256_ctx _libssh2_wincng_hash_ctx -#define libssh2_sha256_init(ctx) \ - (_libssh2_wincng_hash_init(ctx, _libssh2_wincng.hAlgHashSHA256, \ - SHA256_DIGEST_LENGTH, NULL, 0) == 0) -#define libssh2_sha256_update(ctx, data, datalen) \ - _libssh2_wincng_hash_update(&ctx, (unsigned char *) data, datalen) -#define libssh2_sha256_final(ctx, hash) \ - _libssh2_wincng_hash_final(&ctx, hash) -#define libssh2_sha256(data, datalen, hash) \ - _libssh2_wincng_hash(data, datalen, _libssh2_wincng.hAlgHashSHA256, \ - hash, SHA256_DIGEST_LENGTH) - -#define libssh2_sha512_ctx _libssh2_wincng_hash_ctx -#define libssh2_sha512_init(ctx) \ - (_libssh2_wincng_hash_init(ctx, _libssh2_wincng.hAlgHashSHA512, \ - SHA512_DIGEST_LENGTH, NULL, 0) == 0) -#define libssh2_sha512_update(ctx, data, datalen) \ - _libssh2_wincng_hash_update(&ctx, (unsigned char *) data, datalen) -#define libssh2_sha512_final(ctx, hash) \ - _libssh2_wincng_hash_final(&ctx, hash) -#define libssh2_sha512(data, datalen, hash) \ - _libssh2_wincng_hash(data, datalen, _libssh2_wincng.hAlgHashSHA512, \ - hash, SHA512_DIGEST_LENGTH) - -#define libssh2_md5_ctx _libssh2_wincng_hash_ctx -#define libssh2_md5_init(ctx) \ - (_libssh2_wincng_hash_init(ctx, _libssh2_wincng.hAlgHashMD5, \ - MD5_DIGEST_LENGTH, NULL, 0) == 0) -#define libssh2_md5_update(ctx, data, datalen) \ - _libssh2_wincng_hash_update(&ctx, (unsigned char *) data, datalen) -#define libssh2_md5_final(ctx, hash) \ - _libssh2_wincng_hash_final(&ctx, hash) -#define libssh2_md5(data, datalen, hash) \ - _libssh2_wincng_hash(data, datalen, _libssh2_wincng.hAlgHashMD5, \ - hash, MD5_DIGEST_LENGTH) - -/* - * Windows CNG backend: HMAC functions - */ - -#define libssh2_hmac_ctx _libssh2_wincng_hash_ctx -#define libssh2_hmac_ctx_init(ctx) -#define libssh2_hmac_sha1_init(ctx, key, keylen) \ - _libssh2_wincng_hash_init(ctx, _libssh2_wincng.hAlgHmacSHA1, \ - SHA_DIGEST_LENGTH, key, keylen) -#define libssh2_hmac_md5_init(ctx, key, keylen) \ - _libssh2_wincng_hash_init(ctx, _libssh2_wincng.hAlgHmacMD5, \ - MD5_DIGEST_LENGTH, key, keylen) -#define libssh2_hmac_ripemd160_init(ctx, key, keylen) - /* not implemented */ -#define libssh2_hmac_sha256_init(ctx, key, keylen) \ - _libssh2_wincng_hash_init(ctx, _libssh2_wincng.hAlgHmacSHA256, \ - SHA256_DIGEST_LENGTH, key, keylen) -#define libssh2_hmac_sha512_init(ctx, key, keylen) \ - _libssh2_wincng_hash_init(ctx, _libssh2_wincng.hAlgHmacSHA512, \ - SHA512_DIGEST_LENGTH, key, keylen) -#define libssh2_hmac_update(ctx, data, datalen) \ - _libssh2_wincng_hash_update(&ctx, (unsigned char *) data, datalen) -#define libssh2_hmac_final(ctx, hash) \ - _libssh2_wincng_hmac_final(&ctx, hash) -#define libssh2_hmac_cleanup(ctx) \ - _libssh2_wincng_hmac_cleanup(ctx) - - -/*******************************************************************/ -/* - * Windows CNG backend: Key Context structure - */ - -typedef struct __libssh2_wincng_key_ctx { - BCRYPT_KEY_HANDLE hKey; - unsigned char *pbKeyObject; - unsigned long cbKeyObject; -} _libssh2_wincng_key_ctx; - - -/* - * Windows CNG backend: RSA functions - */ - -#define libssh2_rsa_ctx _libssh2_wincng_key_ctx -#define _libssh2_rsa_new(rsactx, e, e_len, n, n_len, \ - d, d_len, p, p_len, q, q_len, \ - e1, e1_len, e2, e2_len, c, c_len) \ - _libssh2_wincng_rsa_new(rsactx, e, e_len, n, n_len, \ - d, d_len, p, p_len, q, q_len, \ - e1, e1_len, e2, e2_len, c, c_len) -#define _libssh2_rsa_new_private(rsactx, s, filename, passphrase) \ - _libssh2_wincng_rsa_new_private(rsactx, s, filename, passphrase) -#define _libssh2_rsa_new_private_frommemory(rsactx, s, filedata, \ - filedata_len, passphrase) \ - _libssh2_wincng_rsa_new_private_frommemory(rsactx, s, filedata, \ - filedata_len, passphrase) -#define _libssh2_rsa_sha1_sign(s, rsactx, hash, hash_len, sig, sig_len) \ - _libssh2_wincng_rsa_sha1_sign(s, rsactx, hash, hash_len, sig, sig_len) -#define _libssh2_rsa_sha1_verify(rsactx, sig, sig_len, m, m_len) \ - _libssh2_wincng_rsa_sha1_verify(rsactx, sig, sig_len, m, m_len) -#define _libssh2_rsa_free(rsactx) \ - _libssh2_wincng_rsa_free(rsactx) - -/* - * Windows CNG backend: DSA functions - */ - -#define libssh2_dsa_ctx _libssh2_wincng_key_ctx -#define _libssh2_dsa_new(dsactx, p, p_len, q, q_len, \ - g, g_len, y, y_len, x, x_len) \ - _libssh2_wincng_dsa_new(dsactx, p, p_len, q, q_len, \ - g, g_len, y, y_len, x, x_len) -#define _libssh2_dsa_new_private(dsactx, s, filename, passphrase) \ - _libssh2_wincng_dsa_new_private(dsactx, s, filename, passphrase) -#define _libssh2_dsa_new_private_frommemory(dsactx, s, filedata, \ - filedata_len, passphrase) \ - _libssh2_wincng_dsa_new_private_frommemory(dsactx, s, filedata, \ - filedata_len, passphrase) -#define _libssh2_dsa_sha1_sign(dsactx, hash, hash_len, sig) \ - _libssh2_wincng_dsa_sha1_sign(dsactx, hash, hash_len, sig) -#define _libssh2_dsa_sha1_verify(dsactx, sig, m, m_len) \ - _libssh2_wincng_dsa_sha1_verify(dsactx, sig, m, m_len) -#define _libssh2_dsa_free(dsactx) \ - _libssh2_wincng_dsa_free(dsactx) - -/* - * Windows CNG backend: Key functions - */ - -#define _libssh2_pub_priv_keyfile(s, m, m_len, p, p_len, pk, pw) \ - _libssh2_wincng_pub_priv_keyfile(s, m, m_len, p, p_len, pk, pw) -#define _libssh2_pub_priv_keyfilememory(s, m, m_len, p, p_len, \ - pk, pk_len, pw) \ - _libssh2_wincng_pub_priv_keyfilememory(s, m, m_len, p, p_len, \ - pk, pk_len, pw) - - -/*******************************************************************/ -/* - * Windows CNG backend: Cipher Context structure - */ - -struct _libssh2_wincng_cipher_ctx { - BCRYPT_KEY_HANDLE hKey; - unsigned char *pbKeyObject; - unsigned char *pbIV; - unsigned char *pbCtr; - unsigned long dwKeyObject; - unsigned long dwIV; - unsigned long dwBlockLength; - unsigned long dwCtrLength; -}; - -#define _libssh2_cipher_ctx struct _libssh2_wincng_cipher_ctx - -/* - * Windows CNG backend: Cipher Type structure - */ - -struct _libssh2_wincng_cipher_type { - BCRYPT_ALG_HANDLE *phAlg; - unsigned long dwKeyLength; - int useIV; /* TODO: Convert to bool when a C89 compatible bool type - is defined */ - int ctrMode; -}; - -#define _libssh2_cipher_type(type) struct _libssh2_wincng_cipher_type type - -#define _libssh2_cipher_aes256ctr { &_libssh2_wincng.hAlgAES_ECB, 32, 0, 1 } -#define _libssh2_cipher_aes192ctr { &_libssh2_wincng.hAlgAES_ECB, 24, 0, 1 } -#define _libssh2_cipher_aes128ctr { &_libssh2_wincng.hAlgAES_ECB, 16, 0, 1 } -#define _libssh2_cipher_aes256 { &_libssh2_wincng.hAlgAES_CBC, 32, 1, 0 } -#define _libssh2_cipher_aes192 { &_libssh2_wincng.hAlgAES_CBC, 24, 1, 0 } -#define _libssh2_cipher_aes128 { &_libssh2_wincng.hAlgAES_CBC, 16, 1, 0 } -#define _libssh2_cipher_arcfour { &_libssh2_wincng.hAlgRC4_NA, 16, 0, 0 } -#define _libssh2_cipher_3des { &_libssh2_wincng.hAlg3DES_CBC, 24, 1, 0 } - -/* - * Windows CNG backend: Cipher functions - */ - -#define _libssh2_cipher_init(ctx, type, iv, secret, encrypt) \ - _libssh2_wincng_cipher_init(ctx, type, iv, secret, encrypt) -#define _libssh2_cipher_crypt(ctx, type, encrypt, block, blocklen) \ - _libssh2_wincng_cipher_crypt(ctx, type, encrypt, block, blocklen) -#define _libssh2_cipher_dtor(ctx) \ - _libssh2_wincng_cipher_dtor(ctx) - -/*******************************************************************/ -/* - * Windows CNG backend: BigNumber Context - */ - -#define _libssh2_bn_ctx int /* not used */ -#define _libssh2_bn_ctx_new() 0 /* not used */ -#define _libssh2_bn_ctx_free(bnctx) ((void)0) /* not used */ - - -/*******************************************************************/ -/* - * Windows CNG backend: BigNumber structure - */ - -struct _libssh2_wincng_bignum { - unsigned char *bignum; - unsigned long length; -}; - -#define _libssh2_bn struct _libssh2_wincng_bignum - -/* - * Windows CNG backend: BigNumber functions - */ - -_libssh2_bn *_libssh2_wincng_bignum_init(void); - -#define _libssh2_bn_init() \ - _libssh2_wincng_bignum_init() -#define _libssh2_bn_init_from_bin() \ - _libssh2_bn_init() -#define _libssh2_bn_set_word(bn, word) \ - _libssh2_wincng_bignum_set_word(bn, word) -#define _libssh2_bn_from_bin(bn, len, bin) \ - _libssh2_wincng_bignum_from_bin(bn, len, bin) -#define _libssh2_bn_to_bin(bn, bin) \ - _libssh2_wincng_bignum_to_bin(bn, bin) -#define _libssh2_bn_bytes(bn) bn->length -#define _libssh2_bn_bits(bn) \ - _libssh2_wincng_bignum_bits(bn) -#define _libssh2_bn_free(bn) \ - _libssh2_wincng_bignum_free(bn) - -/* - * Windows CNG backend: Diffie-Hellman support - */ - -#define _libssh2_dh_ctx struct _libssh2_wincng_bignum * -#define libssh2_dh_init(dhctx) _libssh2_dh_init(dhctx) -#define libssh2_dh_key_pair(dhctx, public, g, p, group_order, bnctx) \ - _libssh2_dh_key_pair(dhctx, public, g, p, group_order) -#define libssh2_dh_secret(dhctx, secret, f, p, bnctx) \ - _libssh2_dh_secret(dhctx, secret, f, p) -#define libssh2_dh_dtor(dhctx) _libssh2_dh_dtor(dhctx) - -/*******************************************************************/ -/* - * Windows CNG backend: forward declarations - */ -void _libssh2_wincng_init(void); -void _libssh2_wincng_free(void); -int _libssh2_wincng_random(void *buf, int len); - -int -_libssh2_wincng_hash_init(_libssh2_wincng_hash_ctx *ctx, - BCRYPT_ALG_HANDLE hAlg, unsigned long hashlen, - unsigned char *key, unsigned long keylen); -int -_libssh2_wincng_hash_update(_libssh2_wincng_hash_ctx *ctx, - const unsigned char *data, unsigned long datalen); -int -_libssh2_wincng_hash_final(_libssh2_wincng_hash_ctx *ctx, - unsigned char *hash); -int -_libssh2_wincng_hash(unsigned char *data, unsigned long datalen, - BCRYPT_ALG_HANDLE hAlg, - unsigned char *hash, unsigned long hashlen); - -int -_libssh2_wincng_hmac_final(_libssh2_wincng_hash_ctx *ctx, - unsigned char *hash); -void -_libssh2_wincng_hmac_cleanup(_libssh2_wincng_hash_ctx *ctx); - -int -_libssh2_wincng_key_sha1_verify(_libssh2_wincng_key_ctx *ctx, - const unsigned char *sig, - unsigned long sig_len, - const unsigned char *m, - unsigned long m_len, - unsigned long flags); - -int -_libssh2_wincng_rsa_new(libssh2_rsa_ctx **rsa, - const unsigned char *edata, - unsigned long elen, - const unsigned char *ndata, - unsigned long nlen, - const unsigned char *ddata, - unsigned long dlen, - const unsigned char *pdata, - unsigned long plen, - const unsigned char *qdata, - unsigned long qlen, - const unsigned char *e1data, - unsigned long e1len, - const unsigned char *e2data, - unsigned long e2len, - const unsigned char *coeffdata, - unsigned long coefflen); -int -_libssh2_wincng_rsa_new_private(libssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - const char *filename, - const unsigned char *passphrase); -int -_libssh2_wincng_rsa_new_private_frommemory(libssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - const char *filedata, - size_t filedata_len, - unsigned const char *passphrase); -int -_libssh2_wincng_rsa_sha1_verify(libssh2_rsa_ctx *rsa, - const unsigned char *sig, - unsigned long sig_len, - const unsigned char *m, - unsigned long m_len); -int -_libssh2_wincng_rsa_sha1_sign(LIBSSH2_SESSION *session, - libssh2_rsa_ctx *rsa, - const unsigned char *hash, - size_t hash_len, - unsigned char **signature, - size_t *signature_len); -void -_libssh2_wincng_rsa_free(libssh2_rsa_ctx *rsa); - -#if LIBSSH2_DSA -int -_libssh2_wincng_dsa_new(libssh2_dsa_ctx **dsa, - const unsigned char *pdata, - unsigned long plen, - const unsigned char *qdata, - unsigned long qlen, - const unsigned char *gdata, - unsigned long glen, - const unsigned char *ydata, - unsigned long ylen, - const unsigned char *xdata, - unsigned long xlen); -int -_libssh2_wincng_dsa_new_private(libssh2_dsa_ctx **dsa, - LIBSSH2_SESSION *session, - const char *filename, - const unsigned char *passphrase); -int -_libssh2_wincng_dsa_new_private_frommemory(libssh2_dsa_ctx **dsa, - LIBSSH2_SESSION *session, - const char *filedata, - size_t filedata_len, - unsigned const char *passphrase); -int -_libssh2_wincng_dsa_sha1_verify(libssh2_dsa_ctx *dsa, - const unsigned char *sig_fixed, - const unsigned char *m, - unsigned long m_len); -int -_libssh2_wincng_dsa_sha1_sign(libssh2_dsa_ctx *dsa, - const unsigned char *hash, - unsigned long hash_len, - unsigned char *sig_fixed); -void -_libssh2_wincng_dsa_free(libssh2_dsa_ctx *dsa); -#endif - -int -_libssh2_wincng_pub_priv_keyfile(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - const char *privatekey, - const char *passphrase); -int -_libssh2_wincng_pub_priv_keyfilememory(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - const char *privatekeydata, - size_t privatekeydata_len, - const char *passphrase); - -int -_libssh2_wincng_cipher_init(_libssh2_cipher_ctx *ctx, - _libssh2_cipher_type(type), - unsigned char *iv, - unsigned char *secret, - int encrypt); -int -_libssh2_wincng_cipher_crypt(_libssh2_cipher_ctx *ctx, - _libssh2_cipher_type(type), - int encrypt, - unsigned char *block, - size_t blocklen); -void -_libssh2_wincng_cipher_dtor(_libssh2_cipher_ctx *ctx); - -_libssh2_bn * -_libssh2_wincng_bignum_init(void); -int -_libssh2_wincng_bignum_set_word(_libssh2_bn *bn, unsigned long word); -unsigned long -_libssh2_wincng_bignum_bits(const _libssh2_bn *bn); -void -_libssh2_wincng_bignum_from_bin(_libssh2_bn *bn, unsigned long len, - const unsigned char *bin); -void -_libssh2_wincng_bignum_to_bin(const _libssh2_bn *bn, unsigned char *bin); -void -_libssh2_wincng_bignum_free(_libssh2_bn *bn); -extern void -_libssh2_dh_init(_libssh2_dh_ctx *dhctx); -extern int -_libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public, - _libssh2_bn *g, _libssh2_bn *p, int group_order); -extern int -_libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret, - _libssh2_bn *f, _libssh2_bn *p); -extern void -_libssh2_dh_dtor(_libssh2_dh_ctx *dhctx); - -#endif /* __LIBSSH2_WINCNG_H */ diff --git a/libssh2/agent.c b/libssh2/agent.c deleted file mode 100644 index c9efe30..0000000 --- a/libssh2/agent.c +++ /dev/null @@ -1,862 +0,0 @@ -/* - * Copyright (c) 2009 by Daiki Ueno - * Copyright (C) 2010-2014 by Daniel Stenberg - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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 "libssh2_priv.h" -#include "misc.h" -#include -#ifdef HAVE_SYS_UN_H -#include -#else -/* Use the existence of sys/un.h as a test if Unix domain socket is - supported. winsock*.h define PF_UNIX/AF_UNIX but do not actually - support them. */ -#undef PF_UNIX -#endif -#include "userauth.h" -#include "session.h" - -/* Requests from client to agent for protocol 1 key operations */ -#define SSH_AGENTC_REQUEST_RSA_IDENTITIES 1 -#define SSH_AGENTC_RSA_CHALLENGE 3 -#define SSH_AGENTC_ADD_RSA_IDENTITY 7 -#define SSH_AGENTC_REMOVE_RSA_IDENTITY 8 -#define SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES 9 -#define SSH_AGENTC_ADD_RSA_ID_CONSTRAINED 24 - -/* Requests from client to agent for protocol 2 key operations */ -#define SSH2_AGENTC_REQUEST_IDENTITIES 11 -#define SSH2_AGENTC_SIGN_REQUEST 13 -#define SSH2_AGENTC_ADD_IDENTITY 17 -#define SSH2_AGENTC_REMOVE_IDENTITY 18 -#define SSH2_AGENTC_REMOVE_ALL_IDENTITIES 19 -#define SSH2_AGENTC_ADD_ID_CONSTRAINED 25 - -/* Key-type independent requests from client to agent */ -#define SSH_AGENTC_ADD_SMARTCARD_KEY 20 -#define SSH_AGENTC_REMOVE_SMARTCARD_KEY 21 -#define SSH_AGENTC_LOCK 22 -#define SSH_AGENTC_UNLOCK 23 -#define SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED 26 - -/* Generic replies from agent to client */ -#define SSH_AGENT_FAILURE 5 -#define SSH_AGENT_SUCCESS 6 - -/* Replies from agent to client for protocol 1 key operations */ -#define SSH_AGENT_RSA_IDENTITIES_ANSWER 2 -#define SSH_AGENT_RSA_RESPONSE 4 - -/* Replies from agent to client for protocol 2 key operations */ -#define SSH2_AGENT_IDENTITIES_ANSWER 12 -#define SSH2_AGENT_SIGN_RESPONSE 14 - -/* Key constraint identifiers */ -#define SSH_AGENT_CONSTRAIN_LIFETIME 1 -#define SSH_AGENT_CONSTRAIN_CONFIRM 2 - -/* non-blocking mode on agent connection is not yet implemented, but - for future use. */ -typedef enum { - agent_NB_state_init = 0, - agent_NB_state_request_created, - agent_NB_state_request_length_sent, - agent_NB_state_request_sent, - agent_NB_state_response_length_received, - agent_NB_state_response_received -} agent_nonblocking_states; - -typedef struct agent_transaction_ctx { - unsigned char *request; - size_t request_len; - unsigned char *response; - size_t response_len; - agent_nonblocking_states state; -} *agent_transaction_ctx_t; - -typedef int (*agent_connect_func)(LIBSSH2_AGENT *agent); -typedef int (*agent_transact_func)(LIBSSH2_AGENT *agent, - agent_transaction_ctx_t transctx); -typedef int (*agent_disconnect_func)(LIBSSH2_AGENT *agent); - -struct agent_publickey { - struct list_node node; - - /* this is the struct we expose externally */ - struct libssh2_agent_publickey external; -}; - -struct agent_ops { - agent_connect_func connect; - agent_transact_func transact; - agent_disconnect_func disconnect; -}; - -struct _LIBSSH2_AGENT -{ - LIBSSH2_SESSION *session; /* the session this "belongs to" */ - - libssh2_socket_t fd; - - struct agent_ops *ops; - - struct agent_transaction_ctx transctx; - struct agent_publickey *identity; - struct list_head head; /* list of public keys */ - - char *identity_agent_path; /* Path to a custom identity agent socket */ -}; - -#ifdef PF_UNIX -static int -agent_connect_unix(LIBSSH2_AGENT *agent) -{ - const char *path; - struct sockaddr_un s_un; - - path = agent->identity_agent_path; - if(!path) { - path = getenv("SSH_AUTH_SOCK"); - if(!path) - return _libssh2_error(agent->session, LIBSSH2_ERROR_BAD_USE, - "no auth sock variable"); - } - - agent->fd = socket(PF_UNIX, SOCK_STREAM, 0); - if(agent->fd < 0) - return _libssh2_error(agent->session, LIBSSH2_ERROR_BAD_SOCKET, - "failed creating socket"); - - s_un.sun_family = AF_UNIX; - strncpy(s_un.sun_path, path, sizeof s_un.sun_path); - s_un.sun_path[sizeof(s_un.sun_path)-1] = 0; /* make sure there's a trailing - zero */ - if(connect(agent->fd, (struct sockaddr*)(&s_un), sizeof s_un) != 0) { - close(agent->fd); - return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL, - "failed connecting with agent"); - } - - return LIBSSH2_ERROR_NONE; -} - -static int -agent_transact_unix(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx) -{ - unsigned char buf[4]; - int rc; - - /* Send the length of the request */ - if(transctx->state == agent_NB_state_request_created) { - _libssh2_htonu32(buf, transctx->request_len); - rc = LIBSSH2_SEND_FD(agent->session, agent->fd, buf, sizeof buf, 0); - if(rc == -EAGAIN) - return LIBSSH2_ERROR_EAGAIN; - else if(rc < 0) - return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_SEND, - "agent send failed"); - transctx->state = agent_NB_state_request_length_sent; - } - - /* Send the request body */ - if(transctx->state == agent_NB_state_request_length_sent) { - rc = LIBSSH2_SEND_FD(agent->session, agent->fd, transctx->request, - transctx->request_len, 0); - if(rc == -EAGAIN) - return LIBSSH2_ERROR_EAGAIN; - else if(rc < 0) - return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_SEND, - "agent send failed"); - transctx->state = agent_NB_state_request_sent; - } - - /* Receive the length of a response */ - if(transctx->state == agent_NB_state_request_sent) { - rc = LIBSSH2_RECV_FD(agent->session, agent->fd, buf, sizeof buf, 0); - if(rc < 0) { - if(rc == -EAGAIN) - return LIBSSH2_ERROR_EAGAIN; - return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_RECV, - "agent recv failed"); - } - transctx->response_len = _libssh2_ntohu32(buf); - transctx->response = LIBSSH2_ALLOC(agent->session, - transctx->response_len); - if(!transctx->response) - return LIBSSH2_ERROR_ALLOC; - - transctx->state = agent_NB_state_response_length_received; - } - - /* Receive the response body */ - if(transctx->state == agent_NB_state_response_length_received) { - rc = LIBSSH2_RECV_FD(agent->session, agent->fd, transctx->response, - transctx->response_len, 0); - if(rc < 0) { - if(rc == -EAGAIN) - return LIBSSH2_ERROR_EAGAIN; - return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_SEND, - "agent recv failed"); - } - transctx->state = agent_NB_state_response_received; - } - - return 0; -} - -static int -agent_disconnect_unix(LIBSSH2_AGENT *agent) -{ - int ret; - ret = close(agent->fd); - if(ret != -1) - agent->fd = LIBSSH2_INVALID_SOCKET; - else - return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_DISCONNECT, - "failed closing the agent socket"); - return LIBSSH2_ERROR_NONE; -} - -struct agent_ops agent_ops_unix = { - agent_connect_unix, - agent_transact_unix, - agent_disconnect_unix -}; -#endif /* PF_UNIX */ - -#ifdef WIN32 -/* Code to talk to Pageant was taken from PuTTY. - * - * Portions copyright Robert de Bath, Joris van Rantwijk, Delian - * Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas - * Barry, Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, - * Markus Kuhn, Colin Watson, and CORE SDI S.A. - */ -#define PAGEANT_COPYDATA_ID 0x804e50ba /* random goop */ -#define PAGEANT_MAX_MSGLEN 8192 - -static int -agent_connect_pageant(LIBSSH2_AGENT *agent) -{ - HWND hwnd; - hwnd = FindWindowA("Pageant", "Pageant"); - if(!hwnd) - return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL, - "failed connecting agent"); - agent->fd = 0; /* Mark as the connection has been established */ - return LIBSSH2_ERROR_NONE; -} - -static int -agent_transact_pageant(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx) -{ - HWND hwnd; - char mapname[23]; - HANDLE filemap; - unsigned char *p; - unsigned char *p2; - int id; - COPYDATASTRUCT cds; - - if(!transctx || 4 + transctx->request_len > PAGEANT_MAX_MSGLEN) - return _libssh2_error(agent->session, LIBSSH2_ERROR_INVAL, - "illegal input"); - - hwnd = FindWindowA("Pageant", "Pageant"); - if(!hwnd) - return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL, - "found no pageant"); - - snprintf(mapname, sizeof(mapname), - "PageantRequest%08x%c", (unsigned)GetCurrentThreadId(), '\0'); - filemap = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, - 0, PAGEANT_MAX_MSGLEN, mapname); - - if(filemap == NULL || filemap == INVALID_HANDLE_VALUE) - return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL, - "failed setting up pageant filemap"); - - p2 = p = MapViewOfFile(filemap, FILE_MAP_WRITE, 0, 0, 0); - if(p == NULL || p2 == NULL) { - CloseHandle(filemap); - return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL, - "failed to open pageant filemap for writing"); - } - - _libssh2_store_str(&p2, (const char *)transctx->request, - transctx->request_len); - - cds.dwData = PAGEANT_COPYDATA_ID; - cds.cbData = 1 + strlen(mapname); - cds.lpData = mapname; - - id = SendMessage(hwnd, WM_COPYDATA, (WPARAM) NULL, (LPARAM) &cds); - if(id > 0) { - transctx->response_len = _libssh2_ntohu32(p); - if(transctx->response_len > PAGEANT_MAX_MSGLEN) { - UnmapViewOfFile(p); - CloseHandle(filemap); - return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL, - "agent setup fail"); - } - transctx->response = LIBSSH2_ALLOC(agent->session, - transctx->response_len); - if(!transctx->response) { - UnmapViewOfFile(p); - CloseHandle(filemap); - return _libssh2_error(agent->session, LIBSSH2_ERROR_ALLOC, - "agent malloc"); - } - memcpy(transctx->response, p + 4, transctx->response_len); - } - - UnmapViewOfFile(p); - CloseHandle(filemap); - return 0; -} - -static int -agent_disconnect_pageant(LIBSSH2_AGENT *agent) -{ - agent->fd = LIBSSH2_INVALID_SOCKET; - return 0; -} - -struct agent_ops agent_ops_pageant = { - agent_connect_pageant, - agent_transact_pageant, - agent_disconnect_pageant -}; -#endif /* WIN32 */ - -static struct { - const char *name; - struct agent_ops *ops; -} supported_backends[] = { -#ifdef WIN32 - {"Pageant", &agent_ops_pageant}, -#endif /* WIN32 */ -#ifdef PF_UNIX - {"Unix", &agent_ops_unix}, -#endif /* PF_UNIX */ - {NULL, NULL} -}; - -static int -agent_sign(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, - const unsigned char *data, size_t data_len, void **abstract) -{ - LIBSSH2_AGENT *agent = (LIBSSH2_AGENT *) (*abstract); - agent_transaction_ctx_t transctx = &agent->transctx; - struct agent_publickey *identity = agent->identity; - ssize_t len = 1 + 4 + identity->external.blob_len + 4 + data_len + 4; - ssize_t method_len; - unsigned char *s; - int rc; - - /* Create a request to sign the data */ - if(transctx->state == agent_NB_state_init) { - s = transctx->request = LIBSSH2_ALLOC(session, len); - if(!transctx->request) - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "out of memory"); - - *s++ = SSH2_AGENTC_SIGN_REQUEST; - /* key blob */ - _libssh2_store_str(&s, (const char *)identity->external.blob, - identity->external.blob_len); - /* data */ - _libssh2_store_str(&s, (const char *)data, data_len); - - /* flags */ - _libssh2_store_u32(&s, 0); - - transctx->request_len = s - transctx->request; - transctx->state = agent_NB_state_request_created; - } - - /* Make sure to be re-called as a result of EAGAIN. */ - if(*transctx->request != SSH2_AGENTC_SIGN_REQUEST) - return _libssh2_error(session, LIBSSH2_ERROR_BAD_USE, - "illegal request"); - - if(!agent->ops) - /* if no agent has been connected, bail out */ - return _libssh2_error(session, LIBSSH2_ERROR_BAD_USE, - "agent not connected"); - - rc = agent->ops->transact(agent, transctx); - if(rc) { - goto error; - } - LIBSSH2_FREE(session, transctx->request); - transctx->request = NULL; - - len = transctx->response_len; - s = transctx->response; - len--; - if(len < 0) { - rc = LIBSSH2_ERROR_AGENT_PROTOCOL; - goto error; - } - if(*s != SSH2_AGENT_SIGN_RESPONSE) { - rc = LIBSSH2_ERROR_AGENT_PROTOCOL; - goto error; - } - s++; - - /* Skip the entire length of the signature */ - len -= 4; - if(len < 0) { - rc = LIBSSH2_ERROR_AGENT_PROTOCOL; - goto error; - } - s += 4; - - /* Skip signing method */ - len -= 4; - if(len < 0) { - rc = LIBSSH2_ERROR_AGENT_PROTOCOL; - goto error; - } - method_len = _libssh2_ntohu32(s); - s += 4; - len -= method_len; - if(len < 0) { - rc = LIBSSH2_ERROR_AGENT_PROTOCOL; - goto error; - } - s += method_len; - - /* Read the signature */ - len -= 4; - if(len < 0) { - rc = LIBSSH2_ERROR_AGENT_PROTOCOL; - goto error; - } - *sig_len = _libssh2_ntohu32(s); - s += 4; - len -= *sig_len; - if(len < 0) { - rc = LIBSSH2_ERROR_AGENT_PROTOCOL; - goto error; - } - - *sig = LIBSSH2_ALLOC(session, *sig_len); - if(!*sig) { - rc = LIBSSH2_ERROR_ALLOC; - goto error; - } - memcpy(*sig, s, *sig_len); - - error: - LIBSSH2_FREE(session, transctx->request); - transctx->request = NULL; - - LIBSSH2_FREE(session, transctx->response); - transctx->response = NULL; - - return _libssh2_error(session, rc, "agent sign failure"); -} - -static int -agent_list_identities(LIBSSH2_AGENT *agent) -{ - agent_transaction_ctx_t transctx = &agent->transctx; - ssize_t len, num_identities; - unsigned char *s; - int rc; - unsigned char c = SSH2_AGENTC_REQUEST_IDENTITIES; - - /* Create a request to list identities */ - if(transctx->state == agent_NB_state_init) { - transctx->request = &c; - transctx->request_len = 1; - transctx->state = agent_NB_state_request_created; - } - - /* Make sure to be re-called as a result of EAGAIN. */ - if(*transctx->request != SSH2_AGENTC_REQUEST_IDENTITIES) - return _libssh2_error(agent->session, LIBSSH2_ERROR_BAD_USE, - "illegal agent request"); - - if(!agent->ops) - /* if no agent has been connected, bail out */ - return _libssh2_error(agent->session, LIBSSH2_ERROR_BAD_USE, - "agent not connected"); - - rc = agent->ops->transact(agent, transctx); - if(rc) { - LIBSSH2_FREE(agent->session, transctx->response); - transctx->response = NULL; - return rc; - } - transctx->request = NULL; - - len = transctx->response_len; - s = transctx->response; - len--; - if(len < 0) { - rc = LIBSSH2_ERROR_AGENT_PROTOCOL; - goto error; - } - if(*s != SSH2_AGENT_IDENTITIES_ANSWER) { - rc = LIBSSH2_ERROR_AGENT_PROTOCOL; - goto error; - } - s++; - - /* Read the length of identities */ - len -= 4; - if(len < 0) { - rc = LIBSSH2_ERROR_AGENT_PROTOCOL; - goto error; - } - num_identities = _libssh2_ntohu32(s); - s += 4; - - while(num_identities--) { - struct agent_publickey *identity; - ssize_t comment_len; - - /* Read the length of the blob */ - len -= 4; - if(len < 0) { - rc = LIBSSH2_ERROR_AGENT_PROTOCOL; - goto error; - } - identity = LIBSSH2_ALLOC(agent->session, sizeof *identity); - if(!identity) { - rc = LIBSSH2_ERROR_ALLOC; - goto error; - } - identity->external.blob_len = _libssh2_ntohu32(s); - s += 4; - - /* Read the blob */ - len -= identity->external.blob_len; - if(len < 0) { - rc = LIBSSH2_ERROR_AGENT_PROTOCOL; - LIBSSH2_FREE(agent->session, identity); - goto error; - } - - identity->external.blob = LIBSSH2_ALLOC(agent->session, - identity->external.blob_len); - if(!identity->external.blob) { - rc = LIBSSH2_ERROR_ALLOC; - LIBSSH2_FREE(agent->session, identity); - goto error; - } - memcpy(identity->external.blob, s, identity->external.blob_len); - s += identity->external.blob_len; - - /* Read the length of the comment */ - len -= 4; - if(len < 0) { - rc = LIBSSH2_ERROR_AGENT_PROTOCOL; - LIBSSH2_FREE(agent->session, identity->external.blob); - LIBSSH2_FREE(agent->session, identity); - goto error; - } - comment_len = _libssh2_ntohu32(s); - s += 4; - - /* Read the comment */ - len -= comment_len; - if(len < 0) { - rc = LIBSSH2_ERROR_AGENT_PROTOCOL; - LIBSSH2_FREE(agent->session, identity->external.blob); - LIBSSH2_FREE(agent->session, identity); - goto error; - } - - identity->external.comment = LIBSSH2_ALLOC(agent->session, - comment_len + 1); - if(!identity->external.comment) { - rc = LIBSSH2_ERROR_ALLOC; - LIBSSH2_FREE(agent->session, identity->external.blob); - LIBSSH2_FREE(agent->session, identity); - goto error; - } - identity->external.comment[comment_len] = '\0'; - memcpy(identity->external.comment, s, comment_len); - s += comment_len; - - _libssh2_list_add(&agent->head, &identity->node); - } - error: - LIBSSH2_FREE(agent->session, transctx->response); - transctx->response = NULL; - - return _libssh2_error(agent->session, rc, - "agent list id failed"); -} - -static void -agent_free_identities(LIBSSH2_AGENT *agent) -{ - struct agent_publickey *node; - struct agent_publickey *next; - - for(node = _libssh2_list_first(&agent->head); node; node = next) { - next = _libssh2_list_next(&node->node); - LIBSSH2_FREE(agent->session, node->external.blob); - LIBSSH2_FREE(agent->session, node->external.comment); - LIBSSH2_FREE(agent->session, node); - } - _libssh2_list_init(&agent->head); -} - -#define AGENT_PUBLICKEY_MAGIC 0x3bdefed2 -/* - * agent_publickey_to_external() - * - * Copies data from the internal to the external representation struct. - * - */ -static struct libssh2_agent_publickey * -agent_publickey_to_external(struct agent_publickey *node) -{ - struct libssh2_agent_publickey *ext = &node->external; - - ext->magic = AGENT_PUBLICKEY_MAGIC; - ext->node = node; - - return ext; -} - -/* - * libssh2_agent_init - * - * Init an ssh-agent handle. Returns the pointer to the handle. - * - */ -LIBSSH2_API LIBSSH2_AGENT * -libssh2_agent_init(LIBSSH2_SESSION *session) -{ - LIBSSH2_AGENT *agent; - - agent = LIBSSH2_CALLOC(session, sizeof *agent); - if(!agent) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate space for agent connection"); - return NULL; - } - agent->fd = LIBSSH2_INVALID_SOCKET; - agent->session = session; - agent->identity_agent_path = NULL; - _libssh2_list_init(&agent->head); - - return agent; -} - -/* - * libssh2_agent_connect() - * - * Connect to an ssh-agent. - * - * Returns 0 if succeeded, or a negative value for error. - */ -LIBSSH2_API int -libssh2_agent_connect(LIBSSH2_AGENT *agent) -{ - int i, rc = -1; - for(i = 0; supported_backends[i].name; i++) { - agent->ops = supported_backends[i].ops; - rc = (agent->ops->connect)(agent); - if(!rc) - return 0; - } - return rc; -} - -/* - * libssh2_agent_list_identities() - * - * Request ssh-agent to list identities. - * - * Returns 0 if succeeded, or a negative value for error. - */ -LIBSSH2_API int -libssh2_agent_list_identities(LIBSSH2_AGENT *agent) -{ - memset(&agent->transctx, 0, sizeof agent->transctx); - /* Abandon the last fetched identities */ - agent_free_identities(agent); - return agent_list_identities(agent); -} - -/* - * libssh2_agent_get_identity() - * - * Traverse the internal list of public keys. Pass NULL to 'prev' to get - * the first one. Or pass a pointer to the previously returned one to get the - * next. - * - * Returns: - * 0 if a fine public key was stored in 'store' - * 1 if end of public keys - * [negative] on errors - */ -LIBSSH2_API int -libssh2_agent_get_identity(LIBSSH2_AGENT *agent, - struct libssh2_agent_publickey **ext, - struct libssh2_agent_publickey *oprev) -{ - struct agent_publickey *node; - if(oprev && oprev->node) { - /* we have a starting point */ - struct agent_publickey *prev = oprev->node; - - /* get the next node in the list */ - node = _libssh2_list_next(&prev->node); - } - else - node = _libssh2_list_first(&agent->head); - - if(!node) - /* no (more) node */ - return 1; - - *ext = agent_publickey_to_external(node); - - return 0; -} - -/* - * libssh2_agent_userauth() - * - * Do publickey user authentication with the help of ssh-agent. - * - * Returns 0 if succeeded, or a negative value for error. - */ -LIBSSH2_API int -libssh2_agent_userauth(LIBSSH2_AGENT *agent, - const char *username, - struct libssh2_agent_publickey *identity) -{ - void *abstract = agent; - int rc; - - if(agent->session->userauth_pblc_state == libssh2_NB_state_idle) { - memset(&agent->transctx, 0, sizeof agent->transctx); - agent->identity = identity->node; - } - - BLOCK_ADJUST(rc, agent->session, - _libssh2_userauth_publickey(agent->session, username, - strlen(username), - identity->blob, - identity->blob_len, - agent_sign, - &abstract)); - return rc; -} - -/* - * libssh2_agent_disconnect() - * - * Close a connection to an ssh-agent. - * - * Returns 0 if succeeded, or a negative value for error. - */ -LIBSSH2_API int -libssh2_agent_disconnect(LIBSSH2_AGENT *agent) -{ - if(agent->ops && agent->fd != LIBSSH2_INVALID_SOCKET) - return agent->ops->disconnect(agent); - return 0; -} - -/* - * libssh2_agent_free() - * - * Free an ssh-agent handle. This function also frees the internal - * collection of public keys. - */ -LIBSSH2_API void -libssh2_agent_free(LIBSSH2_AGENT *agent) -{ - /* Allow connection freeing when the socket has lost its connection */ - if(agent->fd != LIBSSH2_INVALID_SOCKET) { - libssh2_agent_disconnect(agent); - } - - if(agent->identity_agent_path != NULL) - LIBSSH2_FREE(agent->session, agent->identity_agent_path); - - agent_free_identities(agent); - LIBSSH2_FREE(agent->session, agent); -} - -/* - * libssh2_agent_set_identity_path() - * - * Allows a custom agent socket path beyond SSH_AUTH_SOCK env - * - */ -LIBSSH2_API void -libssh2_agent_set_identity_path(LIBSSH2_AGENT *agent, const char *path) -{ - if(agent->identity_agent_path) { - LIBSSH2_FREE(agent->session, agent->identity_agent_path); - agent->identity_agent_path = NULL; - } - - if(path) { - size_t path_len = strlen(path); - if(path_len < SIZE_MAX - 1) { - char *path_buf = LIBSSH2_ALLOC(agent->session, path_len + 1); - memcpy(path_buf, path, path_len); - path_buf[path_len] = '\0'; - agent->identity_agent_path = path_buf; - } - } -} - -/* - * libssh2_agent_get_identity_path() - * - * Returns the custom agent socket path if set - * - */ -LIBSSH2_API const char *libssh2_agent_get_identity_path(LIBSSH2_AGENT *agent) -{ - return agent->identity_agent_path; -} diff --git a/libssh2/bcrypt_pbkdf.c b/libssh2/bcrypt_pbkdf.c deleted file mode 100644 index f9a9758..0000000 --- a/libssh2/bcrypt_pbkdf.c +++ /dev/null @@ -1,180 +0,0 @@ -/* $OpenBSD: bcrypt_pbkdf.c,v 1.4 2013/07/29 00:55:53 tedu Exp $ */ -/* - * Copyright (c) 2013 Ted Unangst - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - - -#ifndef HAVE_BCRYPT_PBKDF - -#include "libssh2_priv.h" -#include -#include -#ifdef HAVE_SYS_PARAM_H -#include -#endif - -#include "blf.h" - -#define MINIMUM(a,b) (((a) < (b)) ? (a) : (b)) - -/* - * pkcs #5 pbkdf2 implementation using the "bcrypt" hash - * - * The bcrypt hash function is derived from the bcrypt password hashing - * function with the following modifications: - * 1. The input password and salt are preprocessed with SHA512. - * 2. The output length is expanded to 256 bits. - * 3. Subsequently the magic string to be encrypted is lengthened and modified - * to "OxychromaticBlowfishSwatDynamite" - * 4. The hash function is defined to perform 64 rounds of initial state - * expansion. (More rounds are performed by iterating the hash.) - * - * Note that this implementation pulls the SHA512 operations into the caller - * as a performance optimization. - * - * One modification from official pbkdf2. Instead of outputting key material - * linearly, we mix it. pbkdf2 has a known weakness where if one uses it to - * generate (i.e.) 512 bits of key material for use as two 256 bit keys, an - * attacker can merely run once through the outer loop below, but the user - * always runs it twice. Shuffling output bytes requires computing the - * entirety of the key material to assemble any subkey. This is something a - * wise caller could do; we just do it for you. - */ - -#define BCRYPT_BLOCKS 8 -#define BCRYPT_HASHSIZE (BCRYPT_BLOCKS * 4) - -static void -bcrypt_hash(uint8_t *sha2pass, uint8_t *sha2salt, uint8_t *out) -{ - blf_ctx state; - uint8_t ciphertext[BCRYPT_HASHSIZE] = - "OxychromaticBlowfishSwatDynamite"; - uint32_t cdata[BCRYPT_BLOCKS]; - int i; - uint16_t j; - size_t shalen = SHA512_DIGEST_LENGTH; - - /* key expansion */ - Blowfish_initstate(&state); - Blowfish_expandstate(&state, sha2salt, shalen, sha2pass, shalen); - for(i = 0; i < 64; i++) { - Blowfish_expand0state(&state, sha2salt, shalen); - Blowfish_expand0state(&state, sha2pass, shalen); - } - - /* encryption */ - j = 0; - for(i = 0; i < BCRYPT_BLOCKS; i++) - cdata[i] = Blowfish_stream2word(ciphertext, sizeof(ciphertext), - &j); - for(i = 0; i < 64; i++) - blf_enc(&state, cdata, sizeof(cdata) / sizeof(uint64_t)); - - /* copy out */ - for(i = 0; i < BCRYPT_BLOCKS; i++) { - out[4 * i + 3] = (cdata[i] >> 24) & 0xff; - out[4 * i + 2] = (cdata[i] >> 16) & 0xff; - out[4 * i + 1] = (cdata[i] >> 8) & 0xff; - out[4 * i + 0] = cdata[i] & 0xff; - } - - /* zap */ - _libssh2_explicit_zero(ciphertext, sizeof(ciphertext)); - _libssh2_explicit_zero(cdata, sizeof(cdata)); - _libssh2_explicit_zero(&state, sizeof(state)); -} - -int -bcrypt_pbkdf(const char *pass, size_t passlen, const uint8_t *salt, - size_t saltlen, - uint8_t *key, size_t keylen, unsigned int rounds) -{ - uint8_t sha2pass[SHA512_DIGEST_LENGTH]; - uint8_t sha2salt[SHA512_DIGEST_LENGTH]; - uint8_t out[BCRYPT_HASHSIZE]; - uint8_t tmpout[BCRYPT_HASHSIZE]; - uint8_t *countsalt; - size_t i, j, amt, stride; - uint32_t count; - size_t origkeylen = keylen; - libssh2_sha512_ctx ctx; - - /* nothing crazy */ - if(rounds < 1) - return -1; - if(passlen == 0 || saltlen == 0 || keylen == 0 || - keylen > sizeof(out) * sizeof(out) || saltlen > 1<<20) - return -1; - countsalt = calloc(1, saltlen + 4); - if(countsalt == NULL) - return -1; - stride = (keylen + sizeof(out) - 1) / sizeof(out); - amt = (keylen + stride - 1) / stride; - - memcpy(countsalt, salt, saltlen); - - /* collapse password */ - libssh2_sha512_init(&ctx); - libssh2_sha512_update(ctx, pass, passlen); - libssh2_sha512_final(ctx, sha2pass); - - /* generate key, sizeof(out) at a time */ - for(count = 1; keylen > 0; count++) { - countsalt[saltlen + 0] = (count >> 24) & 0xff; - countsalt[saltlen + 1] = (count >> 16) & 0xff; - countsalt[saltlen + 2] = (count >> 8) & 0xff; - countsalt[saltlen + 3] = count & 0xff; - - /* first round, salt is salt */ - libssh2_sha512_init(&ctx); - libssh2_sha512_update(ctx, countsalt, saltlen + 4); - libssh2_sha512_final(ctx, sha2salt); - - bcrypt_hash(sha2pass, sha2salt, tmpout); - memcpy(out, tmpout, sizeof(out)); - - for(i = 1; i < rounds; i++) { - /* subsequent rounds, salt is previous output */ - libssh2_sha512_init(&ctx); - libssh2_sha512_update(ctx, tmpout, sizeof(tmpout)); - libssh2_sha512_final(ctx, sha2salt); - - bcrypt_hash(sha2pass, sha2salt, tmpout); - for(j = 0; j < sizeof(out); j++) - out[j] ^= tmpout[j]; - } - - /* - * pbkdf2 deviation: output the key material non-linearly. - */ - amt = MINIMUM(amt, keylen); - for(i = 0; i < amt; i++) { - size_t dest = i * stride + (count - 1); - if(dest >= origkeylen) { - break; - } - key[dest] = out[i]; - } - keylen -= i; - } - - /* zap */ - _libssh2_explicit_zero(out, sizeof(out)); - free(countsalt); - - return 0; -} -#endif /* HAVE_BCRYPT_PBKDF */ diff --git a/libssh2/blowfish.c b/libssh2/blowfish.c deleted file mode 100644 index 4aefc66..0000000 --- a/libssh2/blowfish.c +++ /dev/null @@ -1,697 +0,0 @@ -/* $OpenBSD: blowfish.c,v 1.18 2004/11/02 17:23:26 hshoexer Exp $ */ -/* - * Blowfish block cipher for OpenBSD - * Copyright 1997 Niels Provos - * All rights reserved. - * - * Implementation advice by David Mazieres . - * - * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Niels Provos. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * 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. - */ - -/* - * This code is derived from section 14.3 and the given source - * in section V of Applied Cryptography, second edition. - * Blowfish is an unpatented fast block cipher designed by - * Bruce Schneier. - */ - - -#if !defined(HAVE_BCRYPT_PBKDF) && (!defined(HAVE_BLOWFISH_INITSTATE) || \ - !defined(HAVE_BLOWFISH_EXPAND0STATE) || \ - !defined(HAVE_BLF_ENC)) - -#if 0 -#include /* used for debugging */ -#include -#endif - -#include - -#include "libssh2.h" -#include "blf.h" - -#undef inline -#ifdef __GNUC__ -#define inline __inline -#else /* !__GNUC__ */ -#define inline -#endif /* !__GNUC__ */ - -/* Function for Feistel Networks */ - -#define F(s, x) ((((s)[ (((x)>>24)&0xFF)] \ - + (s)[0x100 + (((x)>>16)&0xFF)]) \ - ^ (s)[0x200 + (((x)>> 8)&0xFF)]) \ - + (s)[0x300 + ( (x) &0xFF)]) - -#define BLFRND(s,p,i,j,n) (i ^= F(s,j) ^ (p)[n]) - -void -Blowfish_encipher(blf_ctx *c, uint32_t *xl, uint32_t *xr) -{ - uint32_t Xl; - uint32_t Xr; - uint32_t *s = c->S[0]; - uint32_t *p = c->P; - - Xl = *xl; - Xr = *xr; - - Xl ^= p[0]; - BLFRND(s, p, Xr, Xl, 1); BLFRND(s, p, Xl, Xr, 2); - BLFRND(s, p, Xr, Xl, 3); BLFRND(s, p, Xl, Xr, 4); - BLFRND(s, p, Xr, Xl, 5); BLFRND(s, p, Xl, Xr, 6); - BLFRND(s, p, Xr, Xl, 7); BLFRND(s, p, Xl, Xr, 8); - BLFRND(s, p, Xr, Xl, 9); BLFRND(s, p, Xl, Xr, 10); - BLFRND(s, p, Xr, Xl, 11); BLFRND(s, p, Xl, Xr, 12); - BLFRND(s, p, Xr, Xl, 13); BLFRND(s, p, Xl, Xr, 14); - BLFRND(s, p, Xr, Xl, 15); BLFRND(s, p, Xl, Xr, 16); - - *xl = Xr ^ p[17]; - *xr = Xl; -} - -void -Blowfish_decipher(blf_ctx *c, uint32_t *xl, uint32_t *xr) -{ - uint32_t Xl; - uint32_t Xr; - uint32_t *s = c->S[0]; - uint32_t *p = c->P; - - Xl = *xl; - Xr = *xr; - - Xl ^= p[17]; - BLFRND(s, p, Xr, Xl, 16); BLFRND(s, p, Xl, Xr, 15); - BLFRND(s, p, Xr, Xl, 14); BLFRND(s, p, Xl, Xr, 13); - BLFRND(s, p, Xr, Xl, 12); BLFRND(s, p, Xl, Xr, 11); - BLFRND(s, p, Xr, Xl, 10); BLFRND(s, p, Xl, Xr, 9); - BLFRND(s, p, Xr, Xl, 8); BLFRND(s, p, Xl, Xr, 7); - BLFRND(s, p, Xr, Xl, 6); BLFRND(s, p, Xl, Xr, 5); - BLFRND(s, p, Xr, Xl, 4); BLFRND(s, p, Xl, Xr, 3); - BLFRND(s, p, Xr, Xl, 2); BLFRND(s, p, Xl, Xr, 1); - - *xl = Xr ^ p[0]; - *xr = Xl; -} - -void -Blowfish_initstate(blf_ctx *c) -{ - /* P-box and S-box tables initialized with digits of Pi */ - - static const blf_ctx initstate = - { { - { - 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, - 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, - 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, - 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, - 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, - 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, - 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, - 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, - 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, - 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, - 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, - 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, - 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, - 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, - 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, - 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, - 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, - 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, - 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, - 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, - 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, - 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, - 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, - 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, - 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, - 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, - 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, - 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, - 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, - 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, - 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, - 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, - 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, - 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, - 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, - 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, - 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, - 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, - 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, - 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, - 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, - 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, - 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, - 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, - 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, - 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, - 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, - 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, - 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, - 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, - 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, - 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, - 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, - 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, - 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, - 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, - 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, - 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, - 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, - 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, - 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, - 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, - 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, - 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a}, - { - 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, - 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, - 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, - 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, - 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, - 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, - 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, - 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, - 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, - 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, - 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, - 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, - 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, - 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, - 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, - 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, - 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, - 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, - 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, - 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, - 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, - 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, - 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, - 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, - 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, - 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, - 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, - 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, - 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, - 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, - 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, - 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, - 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, - 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, - 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, - 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, - 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, - 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, - 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, - 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, - 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, - 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, - 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, - 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, - 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, - 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, - 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, - 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, - 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, - 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, - 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, - 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, - 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, - 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, - 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, - 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, - 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, - 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, - 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, - 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, - 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, - 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, - 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, - 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7}, - { - 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, - 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, - 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, - 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, - 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, - 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, - 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, - 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, - 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, - 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, - 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, - 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, - 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, - 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, - 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, - 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, - 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, - 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, - 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, - 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, - 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, - 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, - 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, - 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, - 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, - 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, - 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, - 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, - 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, - 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, - 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, - 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, - 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, - 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, - 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, - 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, - 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, - 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, - 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, - 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, - 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, - 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, - 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, - 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, - 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, - 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, - 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, - 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, - 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, - 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, - 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, - 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, - 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, - 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, - 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, - 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, - 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, - 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, - 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, - 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, - 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, - 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, - 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, - 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0}, - { - 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, - 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, - 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, - 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, - 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, - 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, - 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, - 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, - 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, - 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, - 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, - 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, - 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, - 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, - 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, - 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, - 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, - 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, - 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, - 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, - 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, - 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, - 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, - 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, - 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, - 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, - 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, - 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, - 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, - 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, - 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, - 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, - 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, - 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, - 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, - 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, - 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, - 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, - 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, - 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, - 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, - 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, - 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, - 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, - 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, - 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, - 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, - 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, - 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, - 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, - 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, - 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, - 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, - 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, - 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, - 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, - 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, - 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, - 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, - 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, - 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, - 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, - 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, - 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6} - }, - { - 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, - 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, - 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, - 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, - 0x9216d5d9, 0x8979fb1b - } }; - - *c = initstate; -} - -uint32_t -Blowfish_stream2word(const uint8_t *data, uint16_t databytes, - uint16_t *current) -{ - uint8_t i; - uint16_t j; - uint32_t temp; - - temp = 0x00000000; - j = *current; - - for(i = 0; i < 4; i++, j++) { - if(j >= databytes) - j = 0; - temp = (temp << 8) | data[j]; - } - - *current = j; - return temp; -} - -void -Blowfish_expand0state(blf_ctx *c, const uint8_t *key, uint16_t keybytes) -{ - uint16_t i; - uint16_t j; - uint16_t k; - uint32_t temp; - uint32_t datal; - uint32_t datar; - - j = 0; - for(i = 0; i < BLF_N + 2; i++) { - /* Extract 4 int8 to 1 int32 from keystream */ - temp = Blowfish_stream2word(key, keybytes, &j); - c->P[i] = c->P[i] ^ temp; - } - - j = 0; - datal = 0x00000000; - datar = 0x00000000; - for(i = 0; i < BLF_N + 2; i += 2) { - Blowfish_encipher(c, &datal, &datar); - - c->P[i] = datal; - c->P[i + 1] = datar; - } - - for(i = 0; i < 4; i++) { - for(k = 0; k < 256; k += 2) { - Blowfish_encipher(c, &datal, &datar); - - c->S[i][k] = datal; - c->S[i][k + 1] = datar; - } - } -} - - -void -Blowfish_expandstate(blf_ctx *c, const uint8_t *data, uint16_t databytes, - const uint8_t *key, uint16_t keybytes) -{ - uint16_t i; - uint16_t j; - uint16_t k; - uint32_t temp; - uint32_t datal; - uint32_t datar; - - j = 0; - for(i = 0; i < BLF_N + 2; i++) { - /* Extract 4 int8 to 1 int32 from keystream */ - temp = Blowfish_stream2word(key, keybytes, &j); - c->P[i] = c->P[i] ^ temp; - } - - j = 0; - datal = 0x00000000; - datar = 0x00000000; - for(i = 0; i < BLF_N + 2; i += 2) { - datal ^= Blowfish_stream2word(data, databytes, &j); - datar ^= Blowfish_stream2word(data, databytes, &j); - Blowfish_encipher(c, &datal, &datar); - - c->P[i] = datal; - c->P[i + 1] = datar; - } - - for(i = 0; i < 4; i++) { - for(k = 0; k < 256; k += 2) { - datal ^= Blowfish_stream2word(data, databytes, &j); - datar ^= Blowfish_stream2word(data, databytes, &j); - Blowfish_encipher(c, &datal, &datar); - - c->S[i][k] = datal; - c->S[i][k + 1] = datar; - } - } - -} - -void -blf_key(blf_ctx *c, const uint8_t *k, uint16_t len) -{ - /* Initialize S-boxes and subkeys with Pi */ - Blowfish_initstate(c); - - /* Transform S-boxes and subkeys with key */ - Blowfish_expand0state(c, k, len); -} - -void -blf_enc(blf_ctx *c, uint32_t *data, uint16_t blocks) -{ - uint32_t *d; - uint16_t i; - - d = data; - for(i = 0; i < blocks; i++) { - Blowfish_encipher(c, d, d + 1); - d += 2; - } -} - -void -blf_dec(blf_ctx *c, uint32_t *data, uint16_t blocks) -{ - uint32_t *d; - uint16_t i; - - d = data; - for(i = 0; i < blocks; i++) { - Blowfish_decipher(c, d, d + 1); - d += 2; - } -} - -void -blf_ecb_encrypt(blf_ctx *c, uint8_t *data, uint32_t len) -{ - uint32_t l, r; - uint32_t i; - - for(i = 0; i < len; i += 8) { - l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; - r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7]; - Blowfish_encipher(c, &l, &r); - data[0] = l >> 24 & 0xff; - data[1] = l >> 16 & 0xff; - data[2] = l >> 8 & 0xff; - data[3] = l & 0xff; - data[4] = r >> 24 & 0xff; - data[5] = r >> 16 & 0xff; - data[6] = r >> 8 & 0xff; - data[7] = r & 0xff; - data += 8; - } -} - -void -blf_ecb_decrypt(blf_ctx *c, uint8_t *data, uint32_t len) -{ - uint32_t l, r; - uint32_t i; - - for(i = 0; i < len; i += 8) { - l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; - r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7]; - Blowfish_decipher(c, &l, &r); - data[0] = l >> 24 & 0xff; - data[1] = l >> 16 & 0xff; - data[2] = l >> 8 & 0xff; - data[3] = l & 0xff; - data[4] = r >> 24 & 0xff; - data[5] = r >> 16 & 0xff; - data[6] = r >> 8 & 0xff; - data[7] = r & 0xff; - data += 8; - } -} - -void -blf_cbc_encrypt(blf_ctx *c, uint8_t *iv, uint8_t *data, uint32_t len) -{ - uint32_t l, r; - uint32_t i, j; - - for(i = 0; i < len; i += 8) { - for(j = 0; j < 8; j++) - data[j] ^= iv[j]; - l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; - r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7]; - Blowfish_encipher(c, &l, &r); - data[0] = l >> 24 & 0xff; - data[1] = l >> 16 & 0xff; - data[2] = l >> 8 & 0xff; - data[3] = l & 0xff; - data[4] = r >> 24 & 0xff; - data[5] = r >> 16 & 0xff; - data[6] = r >> 8 & 0xff; - data[7] = r & 0xff; - iv = data; - data += 8; - } -} - -void -blf_cbc_decrypt(blf_ctx *c, uint8_t *iva, uint8_t *data, uint32_t len) -{ - uint32_t l, r; - uint8_t *iv; - uint32_t i, j; - - iv = data + len - 16; - data = data + len - 8; - for(i = len - 8; i >= 8; i -= 8) { - l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; - r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7]; - Blowfish_decipher(c, &l, &r); - data[0] = l >> 24 & 0xff; - data[1] = l >> 16 & 0xff; - data[2] = l >> 8 & 0xff; - data[3] = l & 0xff; - data[4] = r >> 24 & 0xff; - data[5] = r >> 16 & 0xff; - data[6] = r >> 8 & 0xff; - data[7] = r & 0xff; - for(j = 0; j < 8; j++) - data[j] ^= iv[j]; - iv -= 8; - data -= 8; - } - l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; - r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7]; - Blowfish_decipher(c, &l, &r); - data[0] = l >> 24 & 0xff; - data[1] = l >> 16 & 0xff; - data[2] = l >> 8 & 0xff; - data[3] = l & 0xff; - data[4] = r >> 24 & 0xff; - data[5] = r >> 16 & 0xff; - data[6] = r >> 8 & 0xff; - data[7] = r & 0xff; - for(j = 0; j < 8; j++) - data[j] ^= iva[j]; -} - -#if 0 -void -report(uint32_t data[], uint16_t len) -{ - uint16_t i; - for(i = 0; i < len; i += 2) - printf("Block %0hd: %08lx %08lx.\n", - i / 2, data[i], data[i + 1]); -} -void -main(void) -{ - - blf_ctx c; - char key[] = "AAAAA"; - char key2[] = "abcdefghijklmnopqrstuvwxyz"; - - uint32_t data[10]; - uint32_t data2[] = - {0x424c4f57l, 0x46495348l}; - - uint16_t i; - - /* First test */ - for(i = 0; i < 10; i++) - data[i] = i; - - blf_key(&c, (uint8_t *) key, 5); - blf_enc(&c, data, 5); - blf_dec(&c, data, 1); - blf_dec(&c, data + 2, 4); - printf("Should read as 0 - 9.\n"); - report(data, 10); - - /* Second test */ - blf_key(&c, (uint8_t *) key2, strlen(key2)); - blf_enc(&c, data2, 1); - printf("\nShould read as: 0x324ed0fe 0xf413a203.\n"); - report(data2, 2); - blf_dec(&c, data2, 1); - report(data2, 2); -} -#endif - -#endif /* !defined(HAVE_BCRYPT_PBKDF) && \ - (!defined(HAVE_BLOWFISH_INITSTATE) || \ - !defined(HAVE_BLOWFISH_EXPAND0STATE) || \ - '!defined(HAVE_BLF_ENC)) */ diff --git a/libssh2/channel.c b/libssh2/channel.c deleted file mode 100644 index 55a16e9..0000000 --- a/libssh2/channel.c +++ /dev/null @@ -1,2891 +0,0 @@ -/* Copyright (c) 2004-2007 Sara Golemon - * Copyright (c) 2005 Mikhail Gusarov - * Copyright (c) 2008-2019 by Daniel Stenberg - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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 "libssh2_priv.h" -#ifdef HAVE_UNISTD_H -#include -#endif -#include -#ifdef HAVE_INTTYPES_H -#include -#endif -#include - -#include "channel.h" -#include "transport.h" -#include "packet.h" -#include "session.h" - -/* - * _libssh2_channel_nextid - * - * Determine the next channel ID we can use at our end - */ -uint32_t -_libssh2_channel_nextid(LIBSSH2_SESSION * session) -{ - uint32_t id = session->next_channel; - LIBSSH2_CHANNEL *channel; - - channel = _libssh2_list_first(&session->channels); - - while(channel) { - if(channel->local.id > id) { - id = channel->local.id; - } - channel = _libssh2_list_next(&channel->node); - } - - /* This is a shortcut to avoid waiting for close packets on channels we've - * forgotten about, This *could* be a problem if we request and close 4 - * billion or so channels in too rapid succession for the remote end to - * respond, but the worst case scenario is that some data meant for - * another channel Gets picked up by the new one.... Pretty unlikely all - * told... - */ - session->next_channel = id + 1; - _libssh2_debug(session, LIBSSH2_TRACE_CONN, "Allocated new channel ID#%lu", - id); - return id; -} - -/* - * _libssh2_channel_locate - * - * Locate a channel pointer by number - */ -LIBSSH2_CHANNEL * -_libssh2_channel_locate(LIBSSH2_SESSION *session, uint32_t channel_id) -{ - LIBSSH2_CHANNEL *channel; - LIBSSH2_LISTENER *l; - - for(channel = _libssh2_list_first(&session->channels); - channel; - channel = _libssh2_list_next(&channel->node)) { - if(channel->local.id == channel_id) - return channel; - } - - /* We didn't find the channel in the session, let's then check its - listeners since each listener may have its own set of pending channels - */ - for(l = _libssh2_list_first(&session->listeners); l; - l = _libssh2_list_next(&l->node)) { - for(channel = _libssh2_list_first(&l->queue); - channel; - channel = _libssh2_list_next(&channel->node)) { - if(channel->local.id == channel_id) - return channel; - } - } - - return NULL; -} - -/* - * _libssh2_channel_open - * - * Establish a generic session channel - */ -LIBSSH2_CHANNEL * -_libssh2_channel_open(LIBSSH2_SESSION * session, const char *channel_type, - uint32_t channel_type_len, - uint32_t window_size, - uint32_t packet_size, - const unsigned char *message, - size_t message_len) -{ - static const unsigned char reply_codes[3] = { - SSH_MSG_CHANNEL_OPEN_CONFIRMATION, - SSH_MSG_CHANNEL_OPEN_FAILURE, - 0 - }; - unsigned char *s; - int rc; - - if(session->open_state == libssh2_NB_state_idle) { - session->open_channel = NULL; - session->open_packet = NULL; - session->open_data = NULL; - /* 17 = packet_type(1) + channel_type_len(4) + sender_channel(4) + - * window_size(4) + packet_size(4) */ - session->open_packet_len = channel_type_len + 17; - session->open_local_channel = _libssh2_channel_nextid(session); - - /* Zero the whole thing out */ - memset(&session->open_packet_requirev_state, 0, - sizeof(session->open_packet_requirev_state)); - - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Opening Channel - win %d pack %d", window_size, - packet_size); - session->open_channel = - LIBSSH2_CALLOC(session, sizeof(LIBSSH2_CHANNEL)); - if(!session->open_channel) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate space for channel data"); - return NULL; - } - session->open_channel->channel_type_len = channel_type_len; - session->open_channel->channel_type = - LIBSSH2_ALLOC(session, channel_type_len); - if(!session->open_channel->channel_type) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Failed allocating memory for channel type name"); - LIBSSH2_FREE(session, session->open_channel); - session->open_channel = NULL; - return NULL; - } - memcpy(session->open_channel->channel_type, channel_type, - channel_type_len); - - /* REMEMBER: local as in locally sourced */ - session->open_channel->local.id = session->open_local_channel; - session->open_channel->remote.window_size = window_size; - session->open_channel->remote.window_size_initial = window_size; - session->open_channel->remote.packet_size = packet_size; - session->open_channel->session = session; - - _libssh2_list_add(&session->channels, - &session->open_channel->node); - - s = session->open_packet = - LIBSSH2_ALLOC(session, session->open_packet_len); - if(!session->open_packet) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate temporary space for packet"); - goto channel_error; - } - *(s++) = SSH_MSG_CHANNEL_OPEN; - _libssh2_store_str(&s, channel_type, channel_type_len); - _libssh2_store_u32(&s, session->open_local_channel); - _libssh2_store_u32(&s, window_size); - _libssh2_store_u32(&s, packet_size); - - /* Do not copy the message */ - - session->open_state = libssh2_NB_state_created; - } - - if(session->open_state == libssh2_NB_state_created) { - rc = _libssh2_transport_send(session, - session->open_packet, - session->open_packet_len, - message, message_len); - if(rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, rc, - "Would block sending channel-open request"); - return NULL; - } - else if(rc) { - _libssh2_error(session, rc, - "Unable to send channel-open request"); - goto channel_error; - } - - session->open_state = libssh2_NB_state_sent; - } - - if(session->open_state == libssh2_NB_state_sent) { - rc = _libssh2_packet_requirev(session, reply_codes, - &session->open_data, - &session->open_data_len, 1, - session->open_packet + 5 + - channel_type_len, 4, - &session->open_packet_requirev_state); - if(rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block"); - return NULL; - } - else if(rc) { - _libssh2_error(session, rc, "Unexpected error"); - goto channel_error; - } - - if(session->open_data_len < 1) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unexpected packet size"); - goto channel_error; - } - - if(session->open_data[0] == SSH_MSG_CHANNEL_OPEN_CONFIRMATION) { - - if(session->open_data_len < 17) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unexpected packet size"); - goto channel_error; - } - - session->open_channel->remote.id = - _libssh2_ntohu32(session->open_data + 5); - session->open_channel->local.window_size = - _libssh2_ntohu32(session->open_data + 9); - session->open_channel->local.window_size_initial = - _libssh2_ntohu32(session->open_data + 9); - session->open_channel->local.packet_size = - _libssh2_ntohu32(session->open_data + 13); - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Connection Established - ID: %lu/%lu win: %lu/%lu" - " pack: %lu/%lu", - session->open_channel->local.id, - session->open_channel->remote.id, - session->open_channel->local.window_size, - session->open_channel->remote.window_size, - session->open_channel->local.packet_size, - session->open_channel->remote.packet_size); - LIBSSH2_FREE(session, session->open_packet); - session->open_packet = NULL; - LIBSSH2_FREE(session, session->open_data); - session->open_data = NULL; - - session->open_state = libssh2_NB_state_idle; - return session->open_channel; - } - - if(session->open_data[0] == SSH_MSG_CHANNEL_OPEN_FAILURE) { - unsigned int reason_code = - _libssh2_ntohu32(session->open_data + 5); - switch(reason_code) { - case SSH_OPEN_ADMINISTRATIVELY_PROHIBITED: - _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, - "Channel open failure " - "(administratively prohibited)"); - break; - case SSH_OPEN_CONNECT_FAILED: - _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, - "Channel open failure (connect failed)"); - break; - case SSH_OPEN_UNKNOWN_CHANNELTYPE: - _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, - "Channel open failure (unknown channel type)"); - break; - case SSH_OPEN_RESOURCE_SHORTAGE: - _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, - "Channel open failure (resource shortage)"); - break; - default: - _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, - "Channel open failure"); - } - } - } - - channel_error: - - if(session->open_data) { - LIBSSH2_FREE(session, session->open_data); - session->open_data = NULL; - } - if(session->open_packet) { - LIBSSH2_FREE(session, session->open_packet); - session->open_packet = NULL; - } - if(session->open_channel) { - unsigned char channel_id[4]; - LIBSSH2_FREE(session, session->open_channel->channel_type); - - _libssh2_list_remove(&session->open_channel->node); - - /* Clear out packets meant for this channel */ - _libssh2_htonu32(channel_id, session->open_channel->local.id); - while((_libssh2_packet_ask(session, SSH_MSG_CHANNEL_DATA, - &session->open_data, - &session->open_data_len, 1, - channel_id, 4) >= 0) - || - (_libssh2_packet_ask(session, SSH_MSG_CHANNEL_EXTENDED_DATA, - &session->open_data, - &session->open_data_len, 1, - channel_id, 4) >= 0)) { - LIBSSH2_FREE(session, session->open_data); - session->open_data = NULL; - } - - LIBSSH2_FREE(session, session->open_channel); - session->open_channel = NULL; - } - - session->open_state = libssh2_NB_state_idle; - return NULL; -} - -/* - * libssh2_channel_open_ex - * - * Establish a generic session channel - */ -LIBSSH2_API LIBSSH2_CHANNEL * -libssh2_channel_open_ex(LIBSSH2_SESSION *session, const char *type, - unsigned int type_len, - unsigned int window_size, unsigned int packet_size, - const char *msg, unsigned int msg_len) -{ - LIBSSH2_CHANNEL *ptr; - - if(!session) - return NULL; - - BLOCK_ADJUST_ERRNO(ptr, session, - _libssh2_channel_open(session, type, type_len, - window_size, packet_size, - (unsigned char *)msg, - msg_len)); - return ptr; -} - -/* - * libssh2_channel_direct_tcpip_ex - * - * Tunnel TCP/IP connect through the SSH session to direct host/port - */ -static LIBSSH2_CHANNEL * -channel_direct_tcpip(LIBSSH2_SESSION * session, const char *host, - int port, const char *shost, int sport) -{ - LIBSSH2_CHANNEL *channel; - unsigned char *s; - - if(session->direct_state == libssh2_NB_state_idle) { - session->direct_host_len = strlen(host); - session->direct_shost_len = strlen(shost); - /* host_len(4) + port(4) + shost_len(4) + sport(4) */ - session->direct_message_len = - session->direct_host_len + session->direct_shost_len + 16; - - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Requesting direct-tcpip session from %s:%d to %s:%d", - shost, sport, host, port); - - s = session->direct_message = - LIBSSH2_ALLOC(session, session->direct_message_len); - if(!session->direct_message) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "direct-tcpip connection"); - return NULL; - } - _libssh2_store_str(&s, host, session->direct_host_len); - _libssh2_store_u32(&s, port); - _libssh2_store_str(&s, shost, session->direct_shost_len); - _libssh2_store_u32(&s, sport); - } - - channel = - _libssh2_channel_open(session, "direct-tcpip", - sizeof("direct-tcpip") - 1, - LIBSSH2_CHANNEL_WINDOW_DEFAULT, - LIBSSH2_CHANNEL_PACKET_DEFAULT, - session->direct_message, - session->direct_message_len); - - if(!channel && - libssh2_session_last_errno(session) == LIBSSH2_ERROR_EAGAIN) { - /* The error code is still set to LIBSSH2_ERROR_EAGAIN, set our state - to created to avoid re-creating the package on next invoke */ - session->direct_state = libssh2_NB_state_created; - return NULL; - } - /* by default we set (keep?) idle state... */ - session->direct_state = libssh2_NB_state_idle; - - LIBSSH2_FREE(session, session->direct_message); - session->direct_message = NULL; - - return channel; -} - -/* - * libssh2_channel_direct_tcpip_ex - * - * Tunnel TCP/IP connect through the SSH session to direct host/port - */ -LIBSSH2_API LIBSSH2_CHANNEL * -libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *session, const char *host, - int port, const char *shost, int sport) -{ - LIBSSH2_CHANNEL *ptr; - - if(!session) - return NULL; - - BLOCK_ADJUST_ERRNO(ptr, session, - channel_direct_tcpip(session, host, port, - shost, sport)); - return ptr; -} - -/* - * channel_forward_listen - * - * Bind a port on the remote host and listen for connections - */ -static LIBSSH2_LISTENER * -channel_forward_listen(LIBSSH2_SESSION * session, const char *host, - int port, int *bound_port, int queue_maxsize) -{ - unsigned char *s; - static const unsigned char reply_codes[3] = - { SSH_MSG_REQUEST_SUCCESS, SSH_MSG_REQUEST_FAILURE, 0 }; - int rc; - - if(!host) - host = "0.0.0.0"; - - if(session->fwdLstn_state == libssh2_NB_state_idle) { - session->fwdLstn_host_len = strlen(host); - /* 14 = packet_type(1) + request_len(4) + want_replay(1) + host_len(4) - + port(4) */ - session->fwdLstn_packet_len = - session->fwdLstn_host_len + (sizeof("tcpip-forward") - 1) + 14; - - /* Zero the whole thing out */ - memset(&session->fwdLstn_packet_requirev_state, 0, - sizeof(session->fwdLstn_packet_requirev_state)); - - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Requesting tcpip-forward session for %s:%d", host, - port); - - s = session->fwdLstn_packet = - LIBSSH2_ALLOC(session, session->fwdLstn_packet_len); - if(!session->fwdLstn_packet) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for setenv packet"); - return NULL; - } - - *(s++) = SSH_MSG_GLOBAL_REQUEST; - _libssh2_store_str(&s, "tcpip-forward", sizeof("tcpip-forward") - 1); - *(s++) = 0x01; /* want_reply */ - - _libssh2_store_str(&s, host, session->fwdLstn_host_len); - _libssh2_store_u32(&s, port); - - session->fwdLstn_state = libssh2_NB_state_created; - } - - if(session->fwdLstn_state == libssh2_NB_state_created) { - rc = _libssh2_transport_send(session, - session->fwdLstn_packet, - session->fwdLstn_packet_len, - NULL, 0); - if(rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block sending global-request packet for " - "forward listen request"); - return NULL; - } - else if(rc) { - _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send global-request packet for forward " - "listen request"); - LIBSSH2_FREE(session, session->fwdLstn_packet); - session->fwdLstn_packet = NULL; - session->fwdLstn_state = libssh2_NB_state_idle; - return NULL; - } - LIBSSH2_FREE(session, session->fwdLstn_packet); - session->fwdLstn_packet = NULL; - - session->fwdLstn_state = libssh2_NB_state_sent; - } - - if(session->fwdLstn_state == libssh2_NB_state_sent) { - unsigned char *data; - size_t data_len; - rc = _libssh2_packet_requirev(session, reply_codes, &data, &data_len, - 0, NULL, 0, - &session->fwdLstn_packet_requirev_state); - if(rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block"); - return NULL; - } - else if(rc || (data_len < 1)) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, "Unknown"); - session->fwdLstn_state = libssh2_NB_state_idle; - return NULL; - } - - if(data[0] == SSH_MSG_REQUEST_SUCCESS) { - LIBSSH2_LISTENER *listener; - - listener = LIBSSH2_CALLOC(session, sizeof(LIBSSH2_LISTENER)); - if(!listener) - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for listener queue"); - else { - listener->host = - LIBSSH2_ALLOC(session, session->fwdLstn_host_len + 1); - if(!listener->host) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory " - "for listener queue"); - LIBSSH2_FREE(session, listener); - listener = NULL; - } - else { - listener->session = session; - memcpy(listener->host, host, session->fwdLstn_host_len); - listener->host[session->fwdLstn_host_len] = 0; - if(data_len >= 5 && !port) { - listener->port = _libssh2_ntohu32(data + 1); - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Dynamic tcpip-forward port " - "allocated: %d", - listener->port); - } - else - listener->port = port; - - listener->queue_size = 0; - listener->queue_maxsize = queue_maxsize; - - /* append this to the parent's list of listeners */ - _libssh2_list_add(&session->listeners, &listener->node); - - if(bound_port) { - *bound_port = listener->port; - } - } - } - - LIBSSH2_FREE(session, data); - session->fwdLstn_state = libssh2_NB_state_idle; - return listener; - } - else if(data[0] == SSH_MSG_REQUEST_FAILURE) { - LIBSSH2_FREE(session, data); - _libssh2_error(session, LIBSSH2_ERROR_REQUEST_DENIED, - "Unable to complete request for forward-listen"); - session->fwdLstn_state = libssh2_NB_state_idle; - return NULL; - } - } - - session->fwdLstn_state = libssh2_NB_state_idle; - - return NULL; -} - -/* - * libssh2_channel_forward_listen_ex - * - * Bind a port on the remote host and listen for connections - */ -LIBSSH2_API LIBSSH2_LISTENER * -libssh2_channel_forward_listen_ex(LIBSSH2_SESSION *session, const char *host, - int port, int *bound_port, int queue_maxsize) -{ - LIBSSH2_LISTENER *ptr; - - if(!session) - return NULL; - - BLOCK_ADJUST_ERRNO(ptr, session, - channel_forward_listen(session, host, port, bound_port, - queue_maxsize)); - return ptr; -} - -/* - * _libssh2_channel_forward_cancel - * - * Stop listening on a remote port and free the listener - * Toss out any pending (un-accept()ed) connections - * - * Return 0 on success, LIBSSH2_ERROR_EAGAIN if would block, -1 on error - */ -int _libssh2_channel_forward_cancel(LIBSSH2_LISTENER *listener) -{ - LIBSSH2_SESSION *session = listener->session; - LIBSSH2_CHANNEL *queued; - unsigned char *packet, *s; - size_t host_len = strlen(listener->host); - /* 14 = packet_type(1) + request_len(4) + want_replay(1) + host_len(4) + - port(4) */ - size_t packet_len = - host_len + 14 + sizeof("cancel-tcpip-forward") - 1; - int rc; - int retcode = 0; - - if(listener->chanFwdCncl_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Cancelling tcpip-forward session for %s:%d", - listener->host, listener->port); - - s = packet = LIBSSH2_ALLOC(session, packet_len); - if(!packet) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for setenv packet"); - return LIBSSH2_ERROR_ALLOC; - } - - *(s++) = SSH_MSG_GLOBAL_REQUEST; - _libssh2_store_str(&s, "cancel-tcpip-forward", - sizeof("cancel-tcpip-forward") - 1); - *(s++) = 0x00; /* want_reply */ - - _libssh2_store_str(&s, listener->host, host_len); - _libssh2_store_u32(&s, listener->port); - - listener->chanFwdCncl_state = libssh2_NB_state_created; - } - else { - packet = listener->chanFwdCncl_data; - } - - if(listener->chanFwdCncl_state == libssh2_NB_state_created) { - rc = _libssh2_transport_send(session, packet, packet_len, NULL, 0); - if(rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, rc, - "Would block sending forward request"); - listener->chanFwdCncl_data = packet; - return rc; - } - else if(rc) { - _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send global-request packet for forward " - "listen request"); - /* set the state to something we don't check for, for the - unfortunate situation where we get an EAGAIN further down - when trying to bail out due to errors! */ - listener->chanFwdCncl_state = libssh2_NB_state_sent; - retcode = LIBSSH2_ERROR_SOCKET_SEND; - } - LIBSSH2_FREE(session, packet); - - listener->chanFwdCncl_state = libssh2_NB_state_sent; - } - - queued = _libssh2_list_first(&listener->queue); - while(queued) { - LIBSSH2_CHANNEL *next = _libssh2_list_next(&queued->node); - - rc = _libssh2_channel_free(queued); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - queued = next; - } - LIBSSH2_FREE(session, listener->host); - - /* remove this entry from the parent's list of listeners */ - _libssh2_list_remove(&listener->node); - - LIBSSH2_FREE(session, listener); - - return retcode; -} - -/* - * libssh2_channel_forward_cancel - * - * Stop listening on a remote port and free the listener - * Toss out any pending (un-accept()ed) connections - * - * Return 0 on success, LIBSSH2_ERROR_EAGAIN if would block, -1 on error - */ -LIBSSH2_API int -libssh2_channel_forward_cancel(LIBSSH2_LISTENER *listener) -{ - int rc; - - if(!listener) - return LIBSSH2_ERROR_BAD_USE; - - BLOCK_ADJUST(rc, listener->session, - _libssh2_channel_forward_cancel(listener)); - return rc; -} - -/* - * channel_forward_accept - * - * Accept a connection - */ -static LIBSSH2_CHANNEL * -channel_forward_accept(LIBSSH2_LISTENER *listener) -{ - int rc; - - do { - rc = _libssh2_transport_read(listener->session); - } while(rc > 0); - - if(_libssh2_list_first(&listener->queue)) { - LIBSSH2_CHANNEL *channel = _libssh2_list_first(&listener->queue); - - /* detach channel from listener's queue */ - _libssh2_list_remove(&channel->node); - - listener->queue_size--; - - /* add channel to session's channel list */ - _libssh2_list_add(&channel->session->channels, &channel->node); - - return channel; - } - - if(rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(listener->session, LIBSSH2_ERROR_EAGAIN, - "Would block waiting for packet"); - } - else - _libssh2_error(listener->session, LIBSSH2_ERROR_CHANNEL_UNKNOWN, - "Channel not found"); - return NULL; -} - -/* - * libssh2_channel_forward_accept - * - * Accept a connection - */ -LIBSSH2_API LIBSSH2_CHANNEL * -libssh2_channel_forward_accept(LIBSSH2_LISTENER *listener) -{ - LIBSSH2_CHANNEL *ptr; - - if(!listener) - return NULL; - - BLOCK_ADJUST_ERRNO(ptr, listener->session, - channel_forward_accept(listener)); - return ptr; - -} - -/* - * channel_setenv - * - * Set an environment variable prior to requesting a shell/program/subsystem - */ -static int channel_setenv(LIBSSH2_CHANNEL *channel, - const char *varname, unsigned int varname_len, - const char *value, unsigned int value_len) -{ - LIBSSH2_SESSION *session = channel->session; - unsigned char *s, *data; - static const unsigned char reply_codes[3] = - { SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 }; - size_t data_len; - int rc; - - if(channel->setenv_state == libssh2_NB_state_idle) { - /* 21 = packet_type(1) + channel_id(4) + request_len(4) + - * request(3)"env" + want_reply(1) + varname_len(4) + value_len(4) */ - channel->setenv_packet_len = varname_len + value_len + 21; - - /* Zero the whole thing out */ - memset(&channel->setenv_packet_requirev_state, 0, - sizeof(channel->setenv_packet_requirev_state)); - - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Setting remote environment variable: %s=%s on " - "channel %lu/%lu", - varname, value, channel->local.id, channel->remote.id); - - s = channel->setenv_packet = - LIBSSH2_ALLOC(session, channel->setenv_packet_len); - if(!channel->setenv_packet) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory " - "for setenv packet"); - } - - *(s++) = SSH_MSG_CHANNEL_REQUEST; - _libssh2_store_u32(&s, channel->remote.id); - _libssh2_store_str(&s, "env", sizeof("env") - 1); - *(s++) = 0x01; - _libssh2_store_str(&s, varname, varname_len); - _libssh2_store_str(&s, value, value_len); - - channel->setenv_state = libssh2_NB_state_created; - } - - if(channel->setenv_state == libssh2_NB_state_created) { - rc = _libssh2_transport_send(session, - channel->setenv_packet, - channel->setenv_packet_len, - NULL, 0); - if(rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, rc, - "Would block sending setenv request"); - return rc; - } - else if(rc) { - LIBSSH2_FREE(session, channel->setenv_packet); - channel->setenv_packet = NULL; - channel->setenv_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send channel-request packet for " - "setenv request"); - } - LIBSSH2_FREE(session, channel->setenv_packet); - channel->setenv_packet = NULL; - - _libssh2_htonu32(channel->setenv_local_channel, channel->local.id); - - channel->setenv_state = libssh2_NB_state_sent; - } - - if(channel->setenv_state == libssh2_NB_state_sent) { - rc = _libssh2_packet_requirev(session, reply_codes, &data, &data_len, - 1, channel->setenv_local_channel, 4, - &channel-> - setenv_packet_requirev_state); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - if(rc) { - channel->setenv_state = libssh2_NB_state_idle; - return rc; - } - else if(data_len < 1) { - channel->setenv_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unexpected packet size"); - } - - if(data[0] == SSH_MSG_CHANNEL_SUCCESS) { - LIBSSH2_FREE(session, data); - channel->setenv_state = libssh2_NB_state_idle; - return 0; - } - - LIBSSH2_FREE(session, data); - } - - channel->setenv_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED, - "Unable to complete request for channel-setenv"); -} - -/* - * libssh2_channel_setenv_ex - * - * Set an environment variable prior to requesting a shell/program/subsystem - */ -LIBSSH2_API int -libssh2_channel_setenv_ex(LIBSSH2_CHANNEL *channel, - const char *varname, unsigned int varname_len, - const char *value, unsigned int value_len) -{ - int rc; - - if(!channel) - return LIBSSH2_ERROR_BAD_USE; - - BLOCK_ADJUST(rc, channel->session, - channel_setenv(channel, varname, varname_len, - value, value_len)); - return rc; -} - -/* - * channel_request_pty - * Duh... Request a PTY - */ -static int channel_request_pty(LIBSSH2_CHANNEL *channel, - const char *term, unsigned int term_len, - const char *modes, unsigned int modes_len, - int width, int height, - int width_px, int height_px) -{ - LIBSSH2_SESSION *session = channel->session; - unsigned char *s; - static const unsigned char reply_codes[3] = - { SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 }; - int rc; - - if(channel->reqPTY_state == libssh2_NB_state_idle) { - /* 41 = packet_type(1) + channel(4) + pty_req_len(4) + "pty_req"(7) + - * want_reply(1) + term_len(4) + width(4) + height(4) + width_px(4) + - * height_px(4) + modes_len(4) */ - if(term_len + modes_len > 256) { - return _libssh2_error(session, LIBSSH2_ERROR_INVAL, - "term + mode lengths too large"); - } - - channel->reqPTY_packet_len = term_len + modes_len + 41; - - /* Zero the whole thing out */ - memset(&channel->reqPTY_packet_requirev_state, 0, - sizeof(channel->reqPTY_packet_requirev_state)); - - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Allocating tty on channel %lu/%lu", channel->local.id, - channel->remote.id); - - s = channel->reqPTY_packet; - - *(s++) = SSH_MSG_CHANNEL_REQUEST; - _libssh2_store_u32(&s, channel->remote.id); - _libssh2_store_str(&s, (char *)"pty-req", sizeof("pty-req") - 1); - - *(s++) = 0x01; - - _libssh2_store_str(&s, term, term_len); - _libssh2_store_u32(&s, width); - _libssh2_store_u32(&s, height); - _libssh2_store_u32(&s, width_px); - _libssh2_store_u32(&s, height_px); - _libssh2_store_str(&s, modes, modes_len); - - channel->reqPTY_state = libssh2_NB_state_created; - } - - if(channel->reqPTY_state == libssh2_NB_state_created) { - rc = _libssh2_transport_send(session, channel->reqPTY_packet, - channel->reqPTY_packet_len, - NULL, 0); - if(rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, rc, - "Would block sending pty request"); - return rc; - } - else if(rc) { - channel->reqPTY_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, - "Unable to send pty-request packet"); - } - _libssh2_htonu32(channel->reqPTY_local_channel, channel->local.id); - - channel->reqPTY_state = libssh2_NB_state_sent; - } - - if(channel->reqPTY_state == libssh2_NB_state_sent) { - unsigned char *data; - size_t data_len; - unsigned char code; - rc = _libssh2_packet_requirev(session, reply_codes, &data, &data_len, - 1, channel->reqPTY_local_channel, 4, - &channel->reqPTY_packet_requirev_state); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc || data_len < 1) { - channel->reqPTY_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Failed to require the PTY package"); - } - - code = data[0]; - - LIBSSH2_FREE(session, data); - channel->reqPTY_state = libssh2_NB_state_idle; - - if(code == SSH_MSG_CHANNEL_SUCCESS) - return 0; - } - - return _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED, - "Unable to complete request for " - "channel request-pty"); -} - -/** - * channel_request_auth_agent - * The actual re-entrant method which requests an auth agent. - * */ -static int channel_request_auth_agent(LIBSSH2_CHANNEL *channel, - const char *request_str, - int request_str_len) -{ - LIBSSH2_SESSION *session = channel->session; - unsigned char *s; - static const unsigned char reply_codes[3] = - { SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 }; - int rc; - - if(channel->req_auth_agent_state == libssh2_NB_state_idle) { - /* Only valid options are "auth-agent-req" and - * "auth-agent-req_at_openssh.com" so we make sure it is not - * actually longer than the longest possible. */ - if(request_str_len > 26) { - return _libssh2_error(session, LIBSSH2_ERROR_INVAL, - "request_str length too large"); - } - - /* - * Length: 24 or 36 = packet_type(1) + channel(4) + req_len(4) + - * request_str (variable) + want_reply (1) */ - channel->req_auth_agent_packet_len = 10 + request_str_len; - - /* Zero out the requireev state to reset */ - memset(&channel->req_auth_agent_requirev_state, 0, - sizeof(channel->req_auth_agent_requirev_state)); - - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Requesting auth agent on channel %lu/%lu", - channel->local.id, channel->remote.id); - - /* - * byte SSH_MSG_CHANNEL_REQUEST - * uint32 recipient channel - * string "auth-agent-req" - * boolean want reply - * */ - s = channel->req_auth_agent_packet; - *(s++) = SSH_MSG_CHANNEL_REQUEST; - _libssh2_store_u32(&s, channel->remote.id); - _libssh2_store_str(&s, (char *)request_str, request_str_len); - *(s++) = 0x01; - - channel->req_auth_agent_state = libssh2_NB_state_created; - } - - if(channel->req_auth_agent_state == libssh2_NB_state_created) { - /* Send the packet, we can use sizeof() on the packet because it - * is always completely filled; there are no variable length fields. */ - rc = _libssh2_transport_send(session, channel->req_auth_agent_packet, - channel->req_auth_agent_packet_len, - NULL, 0); - - if(rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, rc, - "Would block sending auth-agent request"); - } - else if(rc) { - channel->req_auth_agent_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, - "Unable to send auth-agent request"); - } - _libssh2_htonu32(channel->req_auth_agent_local_channel, - channel->local.id); - channel->req_auth_agent_state = libssh2_NB_state_sent; - } - - if(channel->req_auth_agent_state == libssh2_NB_state_sent) { - unsigned char *data; - size_t data_len; - unsigned char code; - - rc = _libssh2_packet_requirev( - session, reply_codes, &data, &data_len, 1, - channel->req_auth_agent_local_channel, - 4, &channel->req_auth_agent_requirev_state); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc) { - channel->req_auth_agent_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Failed to request auth-agent"); - } - - code = data[0]; - - LIBSSH2_FREE(session, data); - channel->req_auth_agent_state = libssh2_NB_state_idle; - - if(code == SSH_MSG_CHANNEL_SUCCESS) - return 0; - } - - return _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED, - "Unable to complete request for auth-agent"); -} - -/** - * libssh2_channel_request_auth_agent - * Requests that agent forwarding be enabled for the session. The - * request must be sent over a specific channel, which starts the agent - * listener on the remote side. Once the channel is closed, the agent - * listener continues to exist. - * */ -LIBSSH2_API int -libssh2_channel_request_auth_agent(LIBSSH2_CHANNEL *channel) -{ - int rc; - - if(!channel) - return LIBSSH2_ERROR_BAD_USE; - - /* The current RFC draft for agent forwarding says you're supposed to - * send "auth-agent-req," but most SSH servers out there right now - * actually expect "auth-agent-req@openssh.com", so we try that - * first. */ - if(channel->req_auth_agent_try_state == libssh2_NB_state_idle) { - BLOCK_ADJUST(rc, channel->session, - channel_request_auth_agent(channel, - "auth-agent-req@openssh.com", - 26)); - - /* If we failed (but not with EAGAIN), then we move onto - * the next step to try another request type. */ - if(rc != 0 && rc != LIBSSH2_ERROR_EAGAIN) - channel->req_auth_agent_try_state = libssh2_NB_state_sent; - } - - if(channel->req_auth_agent_try_state == libssh2_NB_state_sent) { - BLOCK_ADJUST(rc, channel->session, - channel_request_auth_agent(channel, - "auth-agent-req", 14)); - - /* If we failed without an EAGAIN, then move on with this - * state machine. */ - if(rc != 0 && rc != LIBSSH2_ERROR_EAGAIN) - channel->req_auth_agent_try_state = libssh2_NB_state_sent1; - } - - /* If things are good, reset the try state. */ - if(rc == 0) - channel->req_auth_agent_try_state = libssh2_NB_state_idle; - - return rc; -} - -/* - * libssh2_channel_request_pty_ex - * Duh... Request a PTY - */ -LIBSSH2_API int -libssh2_channel_request_pty_ex(LIBSSH2_CHANNEL *channel, const char *term, - unsigned int term_len, const char *modes, - unsigned int modes_len, int width, int height, - int width_px, int height_px) -{ - int rc; - - if(!channel) - return LIBSSH2_ERROR_BAD_USE; - - BLOCK_ADJUST(rc, channel->session, - channel_request_pty(channel, term, term_len, modes, - modes_len, width, height, - width_px, height_px)); - return rc; -} - -static int -channel_request_pty_size(LIBSSH2_CHANNEL * channel, int width, - int height, int width_px, int height_px) -{ - LIBSSH2_SESSION *session = channel->session; - unsigned char *s; - int rc; - int retcode = LIBSSH2_ERROR_PROTO; - - if(channel->reqPTY_state == libssh2_NB_state_idle) { - channel->reqPTY_packet_len = 39; - - /* Zero the whole thing out */ - memset(&channel->reqPTY_packet_requirev_state, 0, - sizeof(channel->reqPTY_packet_requirev_state)); - - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "changing tty size on channel %lu/%lu", - channel->local.id, - channel->remote.id); - - s = channel->reqPTY_packet; - - *(s++) = SSH_MSG_CHANNEL_REQUEST; - _libssh2_store_u32(&s, channel->remote.id); - _libssh2_store_str(&s, (char *)"window-change", - sizeof("window-change") - 1); - *(s++) = 0x00; /* Don't reply */ - _libssh2_store_u32(&s, width); - _libssh2_store_u32(&s, height); - _libssh2_store_u32(&s, width_px); - _libssh2_store_u32(&s, height_px); - - channel->reqPTY_state = libssh2_NB_state_created; - } - - if(channel->reqPTY_state == libssh2_NB_state_created) { - rc = _libssh2_transport_send(session, channel->reqPTY_packet, - channel->reqPTY_packet_len, - NULL, 0); - if(rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, rc, - "Would block sending window-change request"); - return rc; - } - else if(rc) { - channel->reqPTY_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, - "Unable to send window-change packet"); - } - _libssh2_htonu32(channel->reqPTY_local_channel, channel->local.id); - retcode = LIBSSH2_ERROR_NONE; - } - - channel->reqPTY_state = libssh2_NB_state_idle; - return retcode; -} - -LIBSSH2_API int -libssh2_channel_request_pty_size_ex(LIBSSH2_CHANNEL *channel, int width, - int height, int width_px, int height_px) -{ - int rc; - - if(!channel) - return LIBSSH2_ERROR_BAD_USE; - - BLOCK_ADJUST(rc, channel->session, - channel_request_pty_size(channel, width, height, width_px, - height_px)); - return rc; -} - -/* Keep this an even number */ -#define LIBSSH2_X11_RANDOM_COOKIE_LEN 32 - -/* - * channel_x11_req - * Request X11 forwarding - */ -static int -channel_x11_req(LIBSSH2_CHANNEL *channel, int single_connection, - const char *auth_proto, const char *auth_cookie, - int screen_number) -{ - LIBSSH2_SESSION *session = channel->session; - unsigned char *s; - static const unsigned char reply_codes[3] = - { SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 }; - size_t proto_len = - auth_proto ? strlen(auth_proto) : (sizeof("MIT-MAGIC-COOKIE-1") - 1); - size_t cookie_len = - auth_cookie ? strlen(auth_cookie) : LIBSSH2_X11_RANDOM_COOKIE_LEN; - int rc; - - if(channel->reqX11_state == libssh2_NB_state_idle) { - /* 30 = packet_type(1) + channel(4) + x11_req_len(4) + "x11-req"(7) + - * want_reply(1) + single_cnx(1) + proto_len(4) + cookie_len(4) + - * screen_num(4) */ - channel->reqX11_packet_len = proto_len + cookie_len + 30; - - /* Zero the whole thing out */ - memset(&channel->reqX11_packet_requirev_state, 0, - sizeof(channel->reqX11_packet_requirev_state)); - - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Requesting x11-req for channel %lu/%lu: single=%d " - "proto=%s cookie=%s screen=%d", - channel->local.id, channel->remote.id, - single_connection, - auth_proto ? auth_proto : "MIT-MAGIC-COOKIE-1", - auth_cookie ? auth_cookie : "", screen_number); - - s = channel->reqX11_packet = - LIBSSH2_ALLOC(session, channel->reqX11_packet_len); - if(!channel->reqX11_packet) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for pty-request"); - } - - *(s++) = SSH_MSG_CHANNEL_REQUEST; - _libssh2_store_u32(&s, channel->remote.id); - _libssh2_store_str(&s, "x11-req", sizeof("x11-req") - 1); - - *(s++) = 0x01; /* want_reply */ - *(s++) = single_connection ? 0x01 : 0x00; - - _libssh2_store_str(&s, auth_proto ? auth_proto : "MIT-MAGIC-COOKIE-1", - proto_len); - - _libssh2_store_u32(&s, cookie_len); - if(auth_cookie) { - memcpy(s, auth_cookie, cookie_len); - } - else { - int i; - /* note: the extra +1 below is necessary since the sprintf() - loop will always write 3 bytes so the last one will write - the trailing zero at the LIBSSH2_X11_RANDOM_COOKIE_LEN/2 - border */ - unsigned char buffer[(LIBSSH2_X11_RANDOM_COOKIE_LEN / 2) + 1]; - - _libssh2_random(buffer, LIBSSH2_X11_RANDOM_COOKIE_LEN / 2); - for(i = 0; i < (LIBSSH2_X11_RANDOM_COOKIE_LEN / 2); i++) { - snprintf((char *)&s[i*2], 3, "%02X", buffer[i]); - } - } - s += cookie_len; - - _libssh2_store_u32(&s, screen_number); - channel->reqX11_state = libssh2_NB_state_created; - } - - if(channel->reqX11_state == libssh2_NB_state_created) { - rc = _libssh2_transport_send(session, channel->reqX11_packet, - channel->reqX11_packet_len, - NULL, 0); - if(rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, rc, - "Would block sending X11-req packet"); - return rc; - } - if(rc) { - LIBSSH2_FREE(session, channel->reqX11_packet); - channel->reqX11_packet = NULL; - channel->reqX11_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, - "Unable to send x11-req packet"); - } - LIBSSH2_FREE(session, channel->reqX11_packet); - channel->reqX11_packet = NULL; - - _libssh2_htonu32(channel->reqX11_local_channel, channel->local.id); - - channel->reqX11_state = libssh2_NB_state_sent; - } - - if(channel->reqX11_state == libssh2_NB_state_sent) { - size_t data_len; - unsigned char *data; - unsigned char code; - - rc = _libssh2_packet_requirev(session, reply_codes, &data, &data_len, - 1, channel->reqX11_local_channel, 4, - &channel->reqX11_packet_requirev_state); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc || data_len < 1) { - channel->reqX11_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, - "waiting for x11-req response packet"); - } - - code = data[0]; - LIBSSH2_FREE(session, data); - channel->reqX11_state = libssh2_NB_state_idle; - - if(code == SSH_MSG_CHANNEL_SUCCESS) - return 0; - } - - return _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED, - "Unable to complete request for channel x11-req"); -} - -/* - * libssh2_channel_x11_req_ex - * Request X11 forwarding - */ -LIBSSH2_API int -libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL *channel, int single_connection, - const char *auth_proto, const char *auth_cookie, - int screen_number) -{ - int rc; - - if(!channel) - return LIBSSH2_ERROR_BAD_USE; - - BLOCK_ADJUST(rc, channel->session, - channel_x11_req(channel, single_connection, auth_proto, - auth_cookie, screen_number)); - return rc; -} - - -/* - * _libssh2_channel_process_startup - * - * Primitive for libssh2_channel_(shell|exec|subsystem) - */ -int -_libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, - const char *request, size_t request_len, - const char *message, size_t message_len) -{ - LIBSSH2_SESSION *session = channel->session; - unsigned char *s; - static const unsigned char reply_codes[3] = - { SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 }; - int rc; - - if(channel->process_state == libssh2_NB_state_end) { - return _libssh2_error(session, LIBSSH2_ERROR_BAD_USE, - "Channel can not be reused"); - } - - if(channel->process_state == libssh2_NB_state_idle) { - /* 10 = packet_type(1) + channel(4) + request_len(4) + want_reply(1) */ - channel->process_packet_len = request_len + 10; - - /* Zero the whole thing out */ - memset(&channel->process_packet_requirev_state, 0, - sizeof(channel->process_packet_requirev_state)); - - if(message) - channel->process_packet_len += + 4; - - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "starting request(%s) on channel %lu/%lu, message=%s", - request, channel->local.id, channel->remote.id, - message ? message : ""); - s = channel->process_packet = - LIBSSH2_ALLOC(session, channel->process_packet_len); - if(!channel->process_packet) - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory " - "for channel-process request"); - - *(s++) = SSH_MSG_CHANNEL_REQUEST; - _libssh2_store_u32(&s, channel->remote.id); - _libssh2_store_str(&s, request, request_len); - *(s++) = 0x01; - - if(message) - _libssh2_store_u32(&s, message_len); - - channel->process_state = libssh2_NB_state_created; - } - - if(channel->process_state == libssh2_NB_state_created) { - rc = _libssh2_transport_send(session, - channel->process_packet, - channel->process_packet_len, - (unsigned char *)message, message_len); - if(rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, rc, - "Would block sending channel request"); - return rc; - } - else if(rc) { - LIBSSH2_FREE(session, channel->process_packet); - channel->process_packet = NULL; - channel->process_state = libssh2_NB_state_end; - return _libssh2_error(session, rc, - "Unable to send channel request"); - } - LIBSSH2_FREE(session, channel->process_packet); - channel->process_packet = NULL; - - _libssh2_htonu32(channel->process_local_channel, channel->local.id); - - channel->process_state = libssh2_NB_state_sent; - } - - if(channel->process_state == libssh2_NB_state_sent) { - unsigned char *data; - size_t data_len; - unsigned char code; - rc = _libssh2_packet_requirev(session, reply_codes, &data, &data_len, - 1, channel->process_local_channel, 4, - &channel->process_packet_requirev_state); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc || data_len < 1) { - channel->process_state = libssh2_NB_state_end; - return _libssh2_error(session, rc, - "Failed waiting for channel success"); - } - - code = data[0]; - LIBSSH2_FREE(session, data); - channel->process_state = libssh2_NB_state_end; - - if(code == SSH_MSG_CHANNEL_SUCCESS) - return 0; - } - - return _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED, - "Unable to complete request for " - "channel-process-startup"); -} - -/* - * libssh2_channel_process_startup - * - * Primitive for libssh2_channel_(shell|exec|subsystem) - */ -LIBSSH2_API int -libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, - const char *req, unsigned int req_len, - const char *msg, unsigned int msg_len) -{ - int rc; - - if(!channel) - return LIBSSH2_ERROR_BAD_USE; - - BLOCK_ADJUST(rc, channel->session, - _libssh2_channel_process_startup(channel, req, req_len, - msg, msg_len)); - return rc; -} - - -/* - * libssh2_channel_set_blocking - * - * Set a channel's BEHAVIOR blocking on or off. The socket will remain non- - * blocking. - */ -LIBSSH2_API void -libssh2_channel_set_blocking(LIBSSH2_CHANNEL * channel, int blocking) -{ - if(channel) - (void) _libssh2_session_set_blocking(channel->session, blocking); -} - -/* - * _libssh2_channel_flush - * - * Flush data from one (or all) stream - * Returns number of bytes flushed, or negative on failure - */ -int -_libssh2_channel_flush(LIBSSH2_CHANNEL *channel, int streamid) -{ - if(channel->flush_state == libssh2_NB_state_idle) { - LIBSSH2_PACKET *packet = - _libssh2_list_first(&channel->session->packets); - channel->flush_refund_bytes = 0; - channel->flush_flush_bytes = 0; - - while(packet) { - unsigned char packet_type; - LIBSSH2_PACKET *next = _libssh2_list_next(&packet->node); - - if(packet->data_len < 1) { - packet = next; - _libssh2_debug(channel->session, LIBSSH2_TRACE_ERROR, - "Unexpected packet length"); - continue; - } - - packet_type = packet->data[0]; - - if(((packet_type == SSH_MSG_CHANNEL_DATA) - || (packet_type == SSH_MSG_CHANNEL_EXTENDED_DATA)) - && ((packet->data_len >= 5) - && (_libssh2_ntohu32(packet->data + 1) - == channel->local.id))) { - /* It's our channel at least */ - int packet_stream_id; - - if(packet_type == SSH_MSG_CHANNEL_DATA) { - packet_stream_id = 0; - } - else if(packet->data_len >= 9) { - packet_stream_id = _libssh2_ntohu32(packet->data + 5); - } - else { - channel->flush_state = libssh2_NB_state_idle; - return _libssh2_error(channel->session, - LIBSSH2_ERROR_PROTO, - "Unexpected packet length"); - } - - if((streamid == LIBSSH2_CHANNEL_FLUSH_ALL) - || ((packet_type == SSH_MSG_CHANNEL_EXTENDED_DATA) - && ((streamid == LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA) - || (streamid == packet_stream_id))) - || ((packet_type == SSH_MSG_CHANNEL_DATA) - && (streamid == 0))) { - size_t bytes_to_flush = packet->data_len - - packet->data_head; - - _libssh2_debug(channel->session, LIBSSH2_TRACE_CONN, - "Flushing %d bytes of data from stream " - "%lu on channel %lu/%lu", - bytes_to_flush, packet_stream_id, - channel->local.id, channel->remote.id); - - /* It's one of the streams we wanted to flush */ - channel->flush_refund_bytes += packet->data_len - 13; - channel->flush_flush_bytes += bytes_to_flush; - - LIBSSH2_FREE(channel->session, packet->data); - - /* remove this packet from the parent's list */ - _libssh2_list_remove(&packet->node); - LIBSSH2_FREE(channel->session, packet); - } - } - packet = next; - } - - channel->flush_state = libssh2_NB_state_created; - } - - channel->read_avail -= channel->flush_flush_bytes; - channel->remote.window_size -= channel->flush_flush_bytes; - - if(channel->flush_refund_bytes) { - int rc = - _libssh2_channel_receive_window_adjust(channel, - channel->flush_refund_bytes, - 1, NULL); - if(rc == LIBSSH2_ERROR_EAGAIN) - return rc; - } - - channel->flush_state = libssh2_NB_state_idle; - - return channel->flush_flush_bytes; -} - -/* - * libssh2_channel_flush_ex - * - * Flush data from one (or all) stream - * Returns number of bytes flushed, or negative on failure - */ -LIBSSH2_API int -libssh2_channel_flush_ex(LIBSSH2_CHANNEL *channel, int stream) -{ - int rc; - - if(!channel) - return LIBSSH2_ERROR_BAD_USE; - - BLOCK_ADJUST(rc, channel->session, - _libssh2_channel_flush(channel, stream)); - return rc; -} - -/* - * libssh2_channel_get_exit_status - * - * Return the channel's program exit status. Note that the actual protocol - * provides the full 32bit this function returns. We cannot abuse it to - * return error values in case of errors so we return a zero if channel is - * NULL. - */ -LIBSSH2_API int -libssh2_channel_get_exit_status(LIBSSH2_CHANNEL *channel) -{ - if(!channel) - return 0; - - return channel->exit_status; -} - -/* - * libssh2_channel_get_exit_signal - * - * Get exit signal (without leading "SIG"), error message, and language - * tag into newly allocated buffers of indicated length. Caller can - * use NULL pointers to indicate that the value should not be set. The - * *_len variables are set if they are non-NULL even if the - * corresponding string parameter is NULL. Returns LIBSSH2_ERROR_NONE - * on success, or an API error code. - */ -LIBSSH2_API int -libssh2_channel_get_exit_signal(LIBSSH2_CHANNEL *channel, - char **exitsignal, - size_t *exitsignal_len, - char **errmsg, - size_t *errmsg_len, - char **langtag, - size_t *langtag_len) -{ - size_t namelen = 0; - - if(channel) { - LIBSSH2_SESSION *session = channel->session; - - if(channel->exit_signal) { - namelen = strlen(channel->exit_signal); - if(exitsignal) { - *exitsignal = LIBSSH2_ALLOC(session, namelen + 1); - if(!*exitsignal) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for signal name"); - } - memcpy(*exitsignal, channel->exit_signal, namelen); - (*exitsignal)[namelen] = '\0'; - } - if(exitsignal_len) - *exitsignal_len = namelen; - } - else { - if(exitsignal) - *exitsignal = NULL; - if(exitsignal_len) - *exitsignal_len = 0; - } - - /* TODO: set error message and language tag */ - - if(errmsg) - *errmsg = NULL; - - if(errmsg_len) - *errmsg_len = 0; - - if(langtag) - *langtag = NULL; - - if(langtag_len) - *langtag_len = 0; - } - - return LIBSSH2_ERROR_NONE; -} - -/* - * _libssh2_channel_receive_window_adjust - * - * Adjust the receive window for a channel by adjustment bytes. If the amount - * to be adjusted is less than LIBSSH2_CHANNEL_MINADJUST and force is 0 the - * adjustment amount will be queued for a later packet. - * - * Calls _libssh2_error() ! - */ -int -_libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL * channel, - uint32_t adjustment, - unsigned char force, - unsigned int *store) -{ - int rc; - - if(store) - *store = channel->remote.window_size; - - if(channel->adjust_state == libssh2_NB_state_idle) { - if(!force - && (adjustment + channel->adjust_queue < - LIBSSH2_CHANNEL_MINADJUST)) { - _libssh2_debug(channel->session, LIBSSH2_TRACE_CONN, - "Queueing %lu bytes for receive window adjustment " - "for channel %lu/%lu", - adjustment, channel->local.id, channel->remote.id); - channel->adjust_queue += adjustment; - return 0; - } - - if(!adjustment && !channel->adjust_queue) { - return 0; - } - - adjustment += channel->adjust_queue; - channel->adjust_queue = 0; - - /* Adjust the window based on the block we just freed */ - channel->adjust_adjust[0] = SSH_MSG_CHANNEL_WINDOW_ADJUST; - _libssh2_htonu32(&channel->adjust_adjust[1], channel->remote.id); - _libssh2_htonu32(&channel->adjust_adjust[5], adjustment); - _libssh2_debug(channel->session, LIBSSH2_TRACE_CONN, - "Adjusting window %lu bytes for data on " - "channel %lu/%lu", - adjustment, channel->local.id, channel->remote.id); - - channel->adjust_state = libssh2_NB_state_created; - } - - rc = _libssh2_transport_send(channel->session, channel->adjust_adjust, 9, - NULL, 0); - if(rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(channel->session, rc, - "Would block sending window adjust"); - return rc; - } - else if(rc) { - channel->adjust_queue = adjustment; - return _libssh2_error(channel->session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send transfer-window adjustment " - "packet, deferring"); - } - else { - channel->remote.window_size += adjustment; - } - - channel->adjust_state = libssh2_NB_state_idle; - - return 0; -} - -/* - * libssh2_channel_receive_window_adjust - * - * DEPRECATED - * - * Adjust the receive window for a channel by adjustment bytes. If the amount - * to be adjusted is less than LIBSSH2_CHANNEL_MINADJUST and force is 0 the - * adjustment amount will be queued for a later packet. - * - * Returns the new size of the receive window (as understood by remote end). - * Note that it might return EAGAIN too which is highly stupid. - * - */ -LIBSSH2_API unsigned long -libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL *channel, - unsigned long adj, - unsigned char force) -{ - unsigned int window; - int rc; - - if(!channel) - return (unsigned long)LIBSSH2_ERROR_BAD_USE; - - BLOCK_ADJUST(rc, channel->session, - _libssh2_channel_receive_window_adjust(channel, adj, - force, &window)); - - /* stupid - but this is how it was made to work before and this is just - kept for backwards compatibility */ - return rc ? (unsigned long)rc : window; -} - -/* - * libssh2_channel_receive_window_adjust2 - * - * Adjust the receive window for a channel by adjustment bytes. If the amount - * to be adjusted is less than LIBSSH2_CHANNEL_MINADJUST and force is 0 the - * adjustment amount will be queued for a later packet. - * - * Stores the new size of the receive window in the data 'window' points to. - * - * Returns the "normal" error code: 0 for success, negative for failure. - */ -LIBSSH2_API int -libssh2_channel_receive_window_adjust2(LIBSSH2_CHANNEL *channel, - unsigned long adj, - unsigned char force, - unsigned int *window) -{ - int rc; - - if(!channel) - return LIBSSH2_ERROR_BAD_USE; - - BLOCK_ADJUST(rc, channel->session, - _libssh2_channel_receive_window_adjust(channel, adj, force, - window)); - return rc; -} - -int -_libssh2_channel_extended_data(LIBSSH2_CHANNEL *channel, int ignore_mode) -{ - if(channel->extData2_state == libssh2_NB_state_idle) { - _libssh2_debug(channel->session, LIBSSH2_TRACE_CONN, - "Setting channel %lu/%lu handle_extended_data" - " mode to %d", - channel->local.id, channel->remote.id, ignore_mode); - channel->remote.extended_data_ignore_mode = (char)ignore_mode; - - channel->extData2_state = libssh2_NB_state_created; - } - - if(channel->extData2_state == libssh2_NB_state_idle) { - if(ignore_mode == LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE) { - int rc = - _libssh2_channel_flush(channel, - LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA); - if(LIBSSH2_ERROR_EAGAIN == rc) - return rc; - } - } - - channel->extData2_state = libssh2_NB_state_idle; - return 0; -} - -/* - * libssh2_channel_handle_extended_data2() - * - */ -LIBSSH2_API int -libssh2_channel_handle_extended_data2(LIBSSH2_CHANNEL *channel, - int mode) -{ - int rc; - - if(!channel) - return LIBSSH2_ERROR_BAD_USE; - - BLOCK_ADJUST(rc, channel->session, _libssh2_channel_extended_data(channel, - mode)); - return rc; -} - -/* - * libssh2_channel_handle_extended_data - * - * DEPRECATED DO NOTE USE! - * - * How should extended data look to the calling app? Keep it in separate - * channels[_read() _read_stdder()]? (NORMAL) Merge the extended data to the - * standard data? [everything via _read()]? (MERGE) Ignore it entirely [toss - * out packets as they come in]? (IGNORE) - */ -LIBSSH2_API void -libssh2_channel_handle_extended_data(LIBSSH2_CHANNEL *channel, - int ignore_mode) -{ - (void)libssh2_channel_handle_extended_data2(channel, ignore_mode); -} - - - -/* - * _libssh2_channel_read - * - * Read data from a channel - * - * It is important to not return 0 until the currently read channel is - * complete. If we read stuff from the wire but it was no payload data to fill - * in the buffer with, we MUST make sure to return LIBSSH2_ERROR_EAGAIN. - * - * The receive window must be maintained (enlarged) by the user of this - * function. - */ -ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id, - char *buf, size_t buflen) -{ - LIBSSH2_SESSION *session = channel->session; - int rc; - size_t bytes_read = 0; - size_t bytes_want; - int unlink_packet; - LIBSSH2_PACKET *read_packet; - LIBSSH2_PACKET *read_next; - - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "channel_read() wants %d bytes from channel %lu/%lu " - "stream #%d", - (int) buflen, channel->local.id, channel->remote.id, - stream_id); - - /* expand the receiving window first if it has become too narrow */ - if((channel->read_state == libssh2_NB_state_jump1) || - (channel->remote.window_size < - channel->remote.window_size_initial / 4 * 3 + buflen) ) { - - uint32_t adjustment = channel->remote.window_size_initial + buflen - - channel->remote.window_size; - if(adjustment < LIBSSH2_CHANNEL_MINADJUST) - adjustment = LIBSSH2_CHANNEL_MINADJUST; - - /* the actual window adjusting may not finish so we need to deal with - this special state here */ - channel->read_state = libssh2_NB_state_jump1; - rc = _libssh2_channel_receive_window_adjust(channel, adjustment, - 0, NULL); - if(rc) - return rc; - - channel->read_state = libssh2_NB_state_idle; - } - - /* Process all pending incoming packets. Tests prove that this way - produces faster transfers. */ - do { - rc = _libssh2_transport_read(session); - } while(rc > 0); - - if((rc < 0) && (rc != LIBSSH2_ERROR_EAGAIN)) - return _libssh2_error(session, rc, "transport read"); - - read_packet = _libssh2_list_first(&session->packets); - while(read_packet && (bytes_read < buflen)) { - /* previously this loop condition also checked for - !channel->remote.close but we cannot let it do this: - - We may have a series of packets to read that are still pending even - if a close has been received. Acknowledging the close too early - makes us flush buffers prematurely and loose data. - */ - - LIBSSH2_PACKET *readpkt = read_packet; - - /* In case packet gets destroyed during this iteration */ - read_next = _libssh2_list_next(&readpkt->node); - - if(readpkt->data_len < 5) { - read_packet = read_next; - _libssh2_debug(channel->session, LIBSSH2_TRACE_ERROR, - "Unexpected packet length"); - continue; - } - - channel->read_local_id = - _libssh2_ntohu32(readpkt->data + 1); - - /* - * Either we asked for a specific extended data stream - * (and data was available), - * or the standard stream (and data was available), - * or the standard stream with extended_data_merge - * enabled and data was available - */ - if((stream_id - && (readpkt->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) - && (channel->local.id == channel->read_local_id) - && (readpkt->data_len >= 9) - && (stream_id == (int) _libssh2_ntohu32(readpkt->data + 5))) - || (!stream_id && (readpkt->data[0] == SSH_MSG_CHANNEL_DATA) - && (channel->local.id == channel->read_local_id)) - || (!stream_id - && (readpkt->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) - && (channel->local.id == channel->read_local_id) - && (channel->remote.extended_data_ignore_mode == - LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE))) { - - /* figure out much more data we want to read */ - bytes_want = buflen - bytes_read; - unlink_packet = FALSE; - - if(bytes_want >= (readpkt->data_len - readpkt->data_head)) { - /* we want more than this node keeps, so adjust the number and - delete this node after the copy */ - bytes_want = readpkt->data_len - readpkt->data_head; - unlink_packet = TRUE; - } - - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "channel_read() got %d of data from %lu/%lu/%d%s", - bytes_want, channel->local.id, - channel->remote.id, stream_id, - unlink_packet?" [ul]":""); - - /* copy data from this struct to the target buffer */ - memcpy(&buf[bytes_read], - &readpkt->data[readpkt->data_head], bytes_want); - - /* advance pointer and counter */ - readpkt->data_head += bytes_want; - bytes_read += bytes_want; - - /* if drained, remove from list */ - if(unlink_packet) { - /* detach readpkt from session->packets list */ - _libssh2_list_remove(&readpkt->node); - - LIBSSH2_FREE(session, readpkt->data); - LIBSSH2_FREE(session, readpkt); - } - } - - /* check the next struct in the chain */ - read_packet = read_next; - } - - if(!bytes_read) { - /* If the channel is already at EOF or even closed, we need to signal - that back. We may have gotten that info while draining the incoming - transport layer until EAGAIN so we must not be fooled by that - return code. */ - if(channel->remote.eof || channel->remote.close) - return 0; - else if(rc != LIBSSH2_ERROR_EAGAIN) - return 0; - - /* if the transport layer said EAGAIN then we say so as well */ - return _libssh2_error(session, rc, "would block"); - } - - channel->read_avail -= bytes_read; - channel->remote.window_size -= bytes_read; - - return bytes_read; -} - -/* - * libssh2_channel_read_ex - * - * Read data from a channel (blocking or non-blocking depending on set state) - * - * When this is done non-blocking, it is important to not return 0 until the - * currently read channel is complete. If we read stuff from the wire but it - * was no payload data to fill in the buffer with, we MUST make sure to return - * LIBSSH2_ERROR_EAGAIN. - * - * This function will first make sure there's a receive window enough to - * receive a full buffer's wort of contents. An application may choose to - * adjust the receive window more to increase transfer performance. - */ -LIBSSH2_API ssize_t -libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id, char *buf, - size_t buflen) -{ - int rc; - unsigned long recv_window; - - if(!channel) - return LIBSSH2_ERROR_BAD_USE; - - recv_window = libssh2_channel_window_read_ex(channel, NULL, NULL); - - if(buflen > recv_window) { - BLOCK_ADJUST(rc, channel->session, - _libssh2_channel_receive_window_adjust(channel, buflen, - 1, NULL)); - } - - BLOCK_ADJUST(rc, channel->session, - _libssh2_channel_read(channel, stream_id, buf, buflen)); - return rc; -} - -/* - * _libssh2_channel_packet_data_len - * - * Return the size of the data block of the current packet, or 0 if there - * isn't a packet. - */ -size_t -_libssh2_channel_packet_data_len(LIBSSH2_CHANNEL * channel, int stream_id) -{ - LIBSSH2_SESSION *session = channel->session; - LIBSSH2_PACKET *read_packet; - LIBSSH2_PACKET *next_packet; - uint32_t read_local_id; - - read_packet = _libssh2_list_first(&session->packets); - if(read_packet == NULL) - return 0; - - while(read_packet) { - - next_packet = _libssh2_list_next(&read_packet->node); - - if(read_packet->data_len < 5) { - read_packet = next_packet; - _libssh2_debug(channel->session, LIBSSH2_TRACE_ERROR, - "Unexpected packet length"); - continue; - } - - read_local_id = _libssh2_ntohu32(read_packet->data + 1); - - /* - * Either we asked for a specific extended data stream - * (and data was available), - * or the standard stream (and data was available), - * or the standard stream with extended_data_merge - * enabled and data was available - */ - if((stream_id - && (read_packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) - && (channel->local.id == read_local_id) - && (read_packet->data_len >= 9) - && (stream_id == (int) _libssh2_ntohu32(read_packet->data + 5))) - || - (!stream_id - && (read_packet->data[0] == SSH_MSG_CHANNEL_DATA) - && (channel->local.id == read_local_id)) - || - (!stream_id - && (read_packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) - && (channel->local.id == read_local_id) - && (channel->remote.extended_data_ignore_mode - == LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE))) { - return (read_packet->data_len - read_packet->data_head); - } - - read_packet = next_packet; - } - - return 0; -} - -/* - * _libssh2_channel_write - * - * Send data to a channel. Note that if this returns EAGAIN, the caller must - * call this function again with the SAME input arguments. - * - * Returns: number of bytes sent, or if it returns a negative number, that is - * the error code! - */ -ssize_t -_libssh2_channel_write(LIBSSH2_CHANNEL *channel, int stream_id, - const unsigned char *buf, size_t buflen) -{ - int rc = 0; - LIBSSH2_SESSION *session = channel->session; - ssize_t wrote = 0; /* counter for this specific this call */ - - /* In theory we could split larger buffers into several smaller packets - * but it turns out to be really hard and nasty to do while still offering - * the API/prototype. - * - * Instead we only deal with the first 32K in this call and for the parent - * function to call it again with the remainder! 32K is a conservative - * limit based on the text in RFC4253 section 6.1. - */ - if(buflen > 32700) - buflen = 32700; - - if(channel->write_state == libssh2_NB_state_idle) { - unsigned char *s = channel->write_packet; - - _libssh2_debug(channel->session, LIBSSH2_TRACE_CONN, - "Writing %d bytes on channel %lu/%lu, stream #%d", - (int) buflen, channel->local.id, channel->remote.id, - stream_id); - - if(channel->local.close) - return _libssh2_error(channel->session, - LIBSSH2_ERROR_CHANNEL_CLOSED, - "We've already closed this channel"); - else if(channel->local.eof) - return _libssh2_error(channel->session, - LIBSSH2_ERROR_CHANNEL_EOF_SENT, - "EOF has already been received, " - "data might be ignored"); - - /* drain the incoming flow first, mostly to make sure we get all - * pending window adjust packets */ - do - rc = _libssh2_transport_read(session); - while(rc > 0); - - if((rc < 0) && (rc != LIBSSH2_ERROR_EAGAIN)) { - return _libssh2_error(channel->session, rc, - "Failure while draining incoming flow"); - } - - if(channel->local.window_size <= 0) { - /* there's no room for data so we stop */ - - /* Waiting on the socket to be writable would be wrong because we - * would be back here immediately, but a readable socket might - * herald an incoming window adjustment. - */ - session->socket_block_directions = LIBSSH2_SESSION_BLOCK_INBOUND; - - return (rc == LIBSSH2_ERROR_EAGAIN?rc:0); - } - - channel->write_bufwrite = buflen; - - *(s++) = stream_id ? SSH_MSG_CHANNEL_EXTENDED_DATA : - SSH_MSG_CHANNEL_DATA; - _libssh2_store_u32(&s, channel->remote.id); - if(stream_id) - _libssh2_store_u32(&s, stream_id); - - /* Don't exceed the remote end's limits */ - /* REMEMBER local means local as the SOURCE of the data */ - if(channel->write_bufwrite > channel->local.window_size) { - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Splitting write block due to %lu byte " - "window_size on %lu/%lu/%d", - channel->local.window_size, channel->local.id, - channel->remote.id, stream_id); - channel->write_bufwrite = channel->local.window_size; - } - if(channel->write_bufwrite > channel->local.packet_size) { - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Splitting write block due to %lu byte " - "packet_size on %lu/%lu/%d", - channel->local.packet_size, channel->local.id, - channel->remote.id, stream_id); - channel->write_bufwrite = channel->local.packet_size; - } - /* store the size here only, the buffer is passed in as-is to - _libssh2_transport_send() */ - _libssh2_store_u32(&s, channel->write_bufwrite); - channel->write_packet_len = s - channel->write_packet; - - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Sending %d bytes on channel %lu/%lu, stream_id=%d", - (int) channel->write_bufwrite, channel->local.id, - channel->remote.id, stream_id); - - channel->write_state = libssh2_NB_state_created; - } - - if(channel->write_state == libssh2_NB_state_created) { - rc = _libssh2_transport_send(session, channel->write_packet, - channel->write_packet_len, - buf, channel->write_bufwrite); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return _libssh2_error(session, rc, - "Unable to send channel data"); - } - else if(rc) { - channel->write_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, - "Unable to send channel data"); - } - /* Shrink local window size */ - channel->local.window_size -= channel->write_bufwrite; - - wrote += channel->write_bufwrite; - - /* Since _libssh2_transport_write() succeeded, we must return - now to allow the caller to provide the next chunk of data. - - We cannot move on to send the next piece of data that may - already have been provided in this same function call, as we - risk getting EAGAIN for that and we can't return information - both about sent data as well as EAGAIN. So, by returning short - now, the caller will call this function again with new data to - send */ - - channel->write_state = libssh2_NB_state_idle; - - return wrote; - } - - return LIBSSH2_ERROR_INVAL; /* reaching this point is really bad */ -} - -/* - * libssh2_channel_write_ex - * - * Send data to a channel - */ -LIBSSH2_API ssize_t -libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel, int stream_id, - const char *buf, size_t buflen) -{ - ssize_t rc; - - if(!channel) - return LIBSSH2_ERROR_BAD_USE; - - BLOCK_ADJUST(rc, channel->session, - _libssh2_channel_write(channel, stream_id, - (unsigned char *)buf, buflen)); - return rc; -} - -/* - * channel_send_eof - * - * Send EOF on channel - */ -static int channel_send_eof(LIBSSH2_CHANNEL *channel) -{ - LIBSSH2_SESSION *session = channel->session; - unsigned char packet[5]; /* packet_type(1) + channelno(4) */ - int rc; - - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Sending EOF on channel %lu/%lu", - channel->local.id, channel->remote.id); - packet[0] = SSH_MSG_CHANNEL_EOF; - _libssh2_htonu32(packet + 1, channel->remote.id); - rc = _libssh2_transport_send(session, packet, 5, NULL, 0); - if(rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, rc, - "Would block sending EOF"); - return rc; - } - else if(rc) { - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send EOF on channel"); - } - channel->local.eof = 1; - - return 0; -} - -/* - * libssh2_channel_send_eof - * - * Send EOF on channel - */ -LIBSSH2_API int -libssh2_channel_send_eof(LIBSSH2_CHANNEL *channel) -{ - int rc; - - if(!channel) - return LIBSSH2_ERROR_BAD_USE; - - BLOCK_ADJUST(rc, channel->session, channel_send_eof(channel)); - return rc; -} - -/* - * libssh2_channel_eof - * - * Read channel's eof status - */ -LIBSSH2_API int -libssh2_channel_eof(LIBSSH2_CHANNEL * channel) -{ - LIBSSH2_SESSION *session; - LIBSSH2_PACKET *packet; - LIBSSH2_PACKET *next_packet; - - if(!channel) - return LIBSSH2_ERROR_BAD_USE; - - session = channel->session; - packet = _libssh2_list_first(&session->packets); - - while(packet) { - - next_packet = _libssh2_list_next(&packet->node); - - if(packet->data_len < 1) { - packet = next_packet; - _libssh2_debug(channel->session, LIBSSH2_TRACE_ERROR, - "Unexpected packet length"); - continue; - } - - if(((packet->data[0] == SSH_MSG_CHANNEL_DATA) - || (packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA)) - && ((packet->data_len >= 5) - && (channel->local.id == _libssh2_ntohu32(packet->data + 1)))) { - /* There's data waiting to be read yet, mask the EOF status */ - return 0; - } - packet = next_packet; - } - - return channel->remote.eof; -} - -/* - * channel_wait_eof - * - * Awaiting channel EOF - */ -static int channel_wait_eof(LIBSSH2_CHANNEL *channel) -{ - LIBSSH2_SESSION *session = channel->session; - int rc; - - if(channel->wait_eof_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Awaiting EOF for channel %lu/%lu", channel->local.id, - channel->remote.id); - - channel->wait_eof_state = libssh2_NB_state_created; - } - - /* - * While channel is not eof, read more packets from the network. - * Either the EOF will be set or network timeout will occur. - */ - do { - if(channel->remote.eof) { - break; - } - - if((channel->remote.window_size == channel->read_avail) && - session->api_block_mode) - return _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_WINDOW_FULL, - "Receiving channel window " - "has been exhausted"); - - rc = _libssh2_transport_read(session); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc < 0) { - channel->wait_eof_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, - "_libssh2_transport_read() bailed out!"); - } - } while(1); - - channel->wait_eof_state = libssh2_NB_state_idle; - - return 0; -} - -/* - * libssh2_channel_wait_eof - * - * Awaiting channel EOF - */ -LIBSSH2_API int -libssh2_channel_wait_eof(LIBSSH2_CHANNEL *channel) -{ - int rc; - - if(!channel) - return LIBSSH2_ERROR_BAD_USE; - - BLOCK_ADJUST(rc, channel->session, channel_wait_eof(channel)); - return rc; -} - -int _libssh2_channel_close(LIBSSH2_CHANNEL * channel) -{ - LIBSSH2_SESSION *session = channel->session; - int rc = 0; - - if(channel->local.close) { - /* Already closed, act like we sent another close, - * even though we didn't... shhhhhh */ - channel->close_state = libssh2_NB_state_idle; - return 0; - } - - if(!channel->local.eof) { - rc = channel_send_eof(channel); - if(rc) { - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - _libssh2_error(session, rc, - "Unable to send EOF, but closing channel anyway"); - } - } - - /* ignore if we have received a remote eof or not, as it is now too - late for us to wait for it. Continue closing! */ - - if(channel->close_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_CONN, "Closing channel %lu/%lu", - channel->local.id, channel->remote.id); - - channel->close_packet[0] = SSH_MSG_CHANNEL_CLOSE; - _libssh2_htonu32(channel->close_packet + 1, channel->remote.id); - - channel->close_state = libssh2_NB_state_created; - } - - if(channel->close_state == libssh2_NB_state_created) { - rc = _libssh2_transport_send(session, channel->close_packet, 5, - NULL, 0); - if(rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, rc, - "Would block sending close-channel"); - return rc; - - } - else if(rc) { - _libssh2_error(session, rc, - "Unable to send close-channel request, " - "but closing anyway"); - /* skip waiting for the response and fall through to - LIBSSH2_CHANNEL_CLOSE below */ - - } - else - channel->close_state = libssh2_NB_state_sent; - } - - if(channel->close_state == libssh2_NB_state_sent) { - /* We must wait for the remote SSH_MSG_CHANNEL_CLOSE message */ - - while(!channel->remote.close && !rc && - (session->socket_state != LIBSSH2_SOCKET_DISCONNECTED)) - rc = _libssh2_transport_read(session); - } - - if(rc != LIBSSH2_ERROR_EAGAIN) { - /* set the local close state first when we're perfectly confirmed to - not do any more EAGAINs */ - channel->local.close = 1; - - /* We call the callback last in this function to make it keep the local - data as long as EAGAIN is returned. */ - if(channel->close_cb) { - LIBSSH2_CHANNEL_CLOSE(session, channel); - } - - channel->close_state = libssh2_NB_state_idle; - } - - /* return 0 or an error */ - return rc >= 0 ? 0 : rc; -} - -/* - * libssh2_channel_close - * - * Close a channel - */ -LIBSSH2_API int -libssh2_channel_close(LIBSSH2_CHANNEL *channel) -{ - int rc; - - if(!channel) - return LIBSSH2_ERROR_BAD_USE; - - BLOCK_ADJUST(rc, channel->session, _libssh2_channel_close(channel) ); - return rc; -} - -/* - * channel_wait_closed - * - * Awaiting channel close after EOF - */ -static int channel_wait_closed(LIBSSH2_CHANNEL *channel) -{ - LIBSSH2_SESSION *session = channel->session; - int rc; - - if(!channel->remote.eof) { - return _libssh2_error(session, LIBSSH2_ERROR_INVAL, - "libssh2_channel_wait_closed() invoked when " - "channel is not in EOF state"); - } - - if(channel->wait_closed_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Awaiting close of channel %lu/%lu", channel->local.id, - channel->remote.id); - - channel->wait_closed_state = libssh2_NB_state_created; - } - - /* - * While channel is not closed, read more packets from the network. - * Either the channel will be closed or network timeout will occur. - */ - if(!channel->remote.close) { - do { - rc = _libssh2_transport_read(session); - if(channel->remote.close) - /* it is now closed, move on! */ - break; - } while(rc > 0); - if(rc < 0) - return rc; - } - - channel->wait_closed_state = libssh2_NB_state_idle; - - return 0; -} - -/* - * libssh2_channel_wait_closed - * - * Awaiting channel close after EOF - */ -LIBSSH2_API int -libssh2_channel_wait_closed(LIBSSH2_CHANNEL *channel) -{ - int rc; - - if(!channel) - return LIBSSH2_ERROR_BAD_USE; - - BLOCK_ADJUST(rc, channel->session, channel_wait_closed(channel)); - return rc; -} - -/* - * _libssh2_channel_free - * - * Make sure a channel is closed, then remove the channel from the session - * and free its resource(s) - * - * Returns 0 on success, negative on failure - */ -int _libssh2_channel_free(LIBSSH2_CHANNEL *channel) -{ - LIBSSH2_SESSION *session = channel->session; - unsigned char channel_id[4]; - unsigned char *data; - size_t data_len; - int rc; - - assert(session); - - if(channel->free_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Freeing channel %lu/%lu resources", channel->local.id, - channel->remote.id); - - channel->free_state = libssh2_NB_state_created; - } - - /* Allow channel freeing even when the socket has lost its connection */ - if(!channel->local.close - && (session->socket_state == LIBSSH2_SOCKET_CONNECTED)) { - rc = _libssh2_channel_close(channel); - - if(rc == LIBSSH2_ERROR_EAGAIN) - return rc; - - /* ignore all other errors as they otherwise risk blocking the channel - free from happening */ - } - - channel->free_state = libssh2_NB_state_idle; - - if(channel->exit_signal) { - LIBSSH2_FREE(session, channel->exit_signal); - } - - /* - * channel->remote.close *might* not be set yet, Well... - * We've sent the close packet, what more do you want? - * Just let packet_add ignore it when it finally arrives - */ - - /* Clear out packets meant for this channel */ - _libssh2_htonu32(channel_id, channel->local.id); - while((_libssh2_packet_ask(session, SSH_MSG_CHANNEL_DATA, &data, - &data_len, 1, channel_id, 4) >= 0) - || - (_libssh2_packet_ask(session, SSH_MSG_CHANNEL_EXTENDED_DATA, &data, - &data_len, 1, channel_id, 4) >= 0)) { - LIBSSH2_FREE(session, data); - } - - /* free "channel_type" */ - if(channel->channel_type) { - LIBSSH2_FREE(session, channel->channel_type); - } - - /* Unlink from channel list */ - _libssh2_list_remove(&channel->node); - - /* - * Make sure all memory used in the state variables are free - */ - if(channel->setenv_packet) { - LIBSSH2_FREE(session, channel->setenv_packet); - } - if(channel->reqX11_packet) { - LIBSSH2_FREE(session, channel->reqX11_packet); - } - if(channel->process_packet) { - LIBSSH2_FREE(session, channel->process_packet); - } - - LIBSSH2_FREE(session, channel); - - return 0; -} - -/* - * libssh2_channel_free - * - * Make sure a channel is closed, then remove the channel from the session - * and free its resource(s) - * - * Returns 0 on success, negative on failure - */ -LIBSSH2_API int -libssh2_channel_free(LIBSSH2_CHANNEL *channel) -{ - int rc; - - if(!channel) - return LIBSSH2_ERROR_BAD_USE; - - BLOCK_ADJUST(rc, channel->session, _libssh2_channel_free(channel)); - return rc; -} -/* - * libssh2_channel_window_read_ex - * - * Check the status of the read window. Returns the number of bytes which the - * remote end may send without overflowing the window limit read_avail (if - * passed) will be populated with the number of bytes actually available to be - * read window_size_initial (if passed) will be populated with the - * window_size_initial as defined by the channel_open request - */ -LIBSSH2_API unsigned long -libssh2_channel_window_read_ex(LIBSSH2_CHANNEL *channel, - unsigned long *read_avail, - unsigned long *window_size_initial) -{ - if(!channel) - return 0; /* no channel, no window! */ - - if(window_size_initial) { - *window_size_initial = channel->remote.window_size_initial; - } - - if(read_avail) { - size_t bytes_queued = 0; - LIBSSH2_PACKET *next_packet; - LIBSSH2_PACKET *packet = - _libssh2_list_first(&channel->session->packets); - - while(packet) { - unsigned char packet_type; - next_packet = _libssh2_list_next(&packet->node); - - if(packet->data_len < 1) { - packet = next_packet; - _libssh2_debug(channel->session, LIBSSH2_TRACE_ERROR, - "Unexpected packet length"); - continue; - } - - packet_type = packet->data[0]; - - if(((packet_type == SSH_MSG_CHANNEL_DATA) - || (packet_type == SSH_MSG_CHANNEL_EXTENDED_DATA)) - && ((packet->data_len >= 5) - && (_libssh2_ntohu32(packet->data + 1) == - channel->local.id))) { - bytes_queued += packet->data_len - packet->data_head; - } - - packet = next_packet; - } - - *read_avail = bytes_queued; - } - - return channel->remote.window_size; -} - -/* - * libssh2_channel_window_write_ex - * - * Check the status of the write window Returns the number of bytes which may - * be safely written on the channel without blocking window_size_initial (if - * passed) will be populated with the size of the initial window as defined by - * the channel_open request - */ -LIBSSH2_API unsigned long -libssh2_channel_window_write_ex(LIBSSH2_CHANNEL *channel, - unsigned long *window_size_initial) -{ - if(!channel) - return 0; /* no channel, no window! */ - - if(window_size_initial) { - /* For locally initiated channels this is very often 0, so it's not - * *that* useful as information goes */ - *window_size_initial = channel->local.window_size_initial; - } - - return channel->local.window_size; -} diff --git a/libssh2/comp.c b/libssh2/comp.c deleted file mode 100644 index fec82a7..0000000 --- a/libssh2/comp.c +++ /dev/null @@ -1,376 +0,0 @@ -/* Copyright (c) 2004-2007, 2019, Sara Golemon - * Copyright (c) 2010-2014, Daniel Stenberg - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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 "libssh2_priv.h" -#ifdef LIBSSH2_HAVE_ZLIB -# include -#endif - -#include "comp.h" - -/* ******** - * none * - ******** */ - -/* - * comp_method_none_comp - * - * Minimalist compression: Absolutely none - */ -static int -comp_method_none_comp(LIBSSH2_SESSION *session, - unsigned char *dest, - size_t *dest_len, - const unsigned char *src, - size_t src_len, - void **abstract) -{ - (void) session; - (void) abstract; - (void) dest; - (void) dest_len; - (void) src; - (void) src_len; - - return 0; -} - -/* - * comp_method_none_decomp - * - * Minimalist decompression: Absolutely none - */ -static int -comp_method_none_decomp(LIBSSH2_SESSION * session, - unsigned char **dest, - size_t *dest_len, - size_t payload_limit, - const unsigned char *src, - size_t src_len, void **abstract) -{ - (void) session; - (void) payload_limit; - (void) abstract; - *dest = (unsigned char *) src; - *dest_len = src_len; - return 0; -} - - - -static const LIBSSH2_COMP_METHOD comp_method_none = { - "none", - 0, /* not really compressing */ - 0, /* isn't used in userauth, go figure */ - NULL, - comp_method_none_comp, - comp_method_none_decomp, - NULL -}; - -#ifdef LIBSSH2_HAVE_ZLIB -/* ******** - * zlib * - ******** */ - -/* Memory management wrappers - * Yes, I realize we're doing a callback to a callback, - * Deal... - */ - -static voidpf -comp_method_zlib_alloc(voidpf opaque, uInt items, uInt size) -{ - LIBSSH2_SESSION *session = (LIBSSH2_SESSION *) opaque; - - return (voidpf) LIBSSH2_ALLOC(session, items * size); -} - -static void -comp_method_zlib_free(voidpf opaque, voidpf address) -{ - LIBSSH2_SESSION *session = (LIBSSH2_SESSION *) opaque; - - LIBSSH2_FREE(session, address); -} - - - -/* libssh2_comp_method_zlib_init - * All your bandwidth are belong to us (so save some) - */ -static int -comp_method_zlib_init(LIBSSH2_SESSION * session, int compr, - void **abstract) -{ - z_stream *strm; - int status; - - strm = LIBSSH2_CALLOC(session, sizeof(z_stream)); - if(!strm) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "zlib compression/decompression"); - } - - strm->opaque = (voidpf) session; - strm->zalloc = (alloc_func) comp_method_zlib_alloc; - strm->zfree = (free_func) comp_method_zlib_free; - if(compr) { - /* deflate */ - status = deflateInit(strm, Z_DEFAULT_COMPRESSION); - } - else { - /* inflate */ - status = inflateInit(strm); - } - - if(status != Z_OK) { - LIBSSH2_FREE(session, strm); - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "unhandled zlib error %d", status); - return LIBSSH2_ERROR_COMPRESS; - } - *abstract = strm; - - return LIBSSH2_ERROR_NONE; -} - -/* - * libssh2_comp_method_zlib_comp - * - * Compresses source to destination. Without allocation. - */ -static int -comp_method_zlib_comp(LIBSSH2_SESSION *session, - unsigned char *dest, - - /* dest_len is a pointer to allow this function to - update it with the final actual size used */ - size_t *dest_len, - const unsigned char *src, - size_t src_len, - void **abstract) -{ - z_stream *strm = *abstract; - int out_maxlen = *dest_len; - int status; - - strm->next_in = (unsigned char *) src; - strm->avail_in = src_len; - strm->next_out = dest; - strm->avail_out = out_maxlen; - - status = deflate(strm, Z_PARTIAL_FLUSH); - - if((status == Z_OK) && (strm->avail_out > 0)) { - *dest_len = out_maxlen - strm->avail_out; - return 0; - } - - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "unhandled zlib compression error %d, avail_out", - status, strm->avail_out); - return _libssh2_error(session, LIBSSH2_ERROR_ZLIB, "compression failure"); -} - -/* - * libssh2_comp_method_zlib_decomp - * - * Decompresses source to destination. Allocates the output memory. - */ -static int -comp_method_zlib_decomp(LIBSSH2_SESSION * session, - unsigned char **dest, - size_t *dest_len, - size_t payload_limit, - const unsigned char *src, - size_t src_len, void **abstract) -{ - z_stream *strm = *abstract; - /* A short-term alloc of a full data chunk is better than a series of - reallocs */ - char *out; - size_t out_maxlen = src_len; - - if(src_len <= SIZE_MAX / 4) - out_maxlen = src_len * 4; - else - out_maxlen = payload_limit; - - /* If strm is null, then we have not yet been initialized. */ - if(strm == NULL) - return _libssh2_error(session, LIBSSH2_ERROR_COMPRESS, - "decompression uninitialized");; - - /* In practice they never come smaller than this */ - if(out_maxlen < 25) - out_maxlen = 25; - - if(out_maxlen > payload_limit) - out_maxlen = payload_limit; - - strm->next_in = (unsigned char *) src; - strm->avail_in = src_len; - strm->next_out = (unsigned char *) LIBSSH2_ALLOC(session, out_maxlen); - out = (char *) strm->next_out; - strm->avail_out = out_maxlen; - if(!strm->next_out) - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate decompression buffer"); - - /* Loop until it's all inflated or hit error */ - for(;;) { - int status; - size_t out_ofs; - char *newout; - - status = inflate(strm, Z_PARTIAL_FLUSH); - - if(status == Z_OK) { - if(strm->avail_out > 0) - /* status is OK and the output buffer has not been exhausted - so we're done */ - break; - } - else if(status == Z_BUF_ERROR) { - /* the input data has been exhausted so we are done */ - break; - } - else { - /* error state */ - LIBSSH2_FREE(session, out); - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "unhandled zlib error %d", status); - return _libssh2_error(session, LIBSSH2_ERROR_ZLIB, - "decompression failure"); - } - - if(out_maxlen > payload_limit || out_maxlen > SIZE_MAX / 2) { - LIBSSH2_FREE(session, out); - return _libssh2_error(session, LIBSSH2_ERROR_ZLIB, - "Excessive growth in decompression phase"); - } - - /* If we get here we need to grow the output buffer and try again */ - out_ofs = out_maxlen - strm->avail_out; - out_maxlen *= 2; - newout = LIBSSH2_REALLOC(session, out, out_maxlen); - if(!newout) { - LIBSSH2_FREE(session, out); - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to expand decompression buffer"); - } - out = newout; - strm->next_out = (unsigned char *) out + out_ofs; - strm->avail_out = out_maxlen - out_ofs; - } - - *dest = (unsigned char *) out; - *dest_len = out_maxlen - strm->avail_out; - - return 0; -} - - -/* libssh2_comp_method_zlib_dtor - * All done, no more compression for you - */ -static int -comp_method_zlib_dtor(LIBSSH2_SESSION *session, int compr, void **abstract) -{ - z_stream *strm = *abstract; - - if(strm) { - if(compr) - deflateEnd(strm); - else - inflateEnd(strm); - LIBSSH2_FREE(session, strm); - } - - *abstract = NULL; - return 0; -} - -static const LIBSSH2_COMP_METHOD comp_method_zlib = { - "zlib", - 1, /* yes, this compresses */ - 1, /* do compression during userauth */ - comp_method_zlib_init, - comp_method_zlib_comp, - comp_method_zlib_decomp, - comp_method_zlib_dtor, -}; - -static const LIBSSH2_COMP_METHOD comp_method_zlib_openssh = { - "zlib@openssh.com", - 1, /* yes, this compresses */ - 0, /* don't use compression during userauth */ - comp_method_zlib_init, - comp_method_zlib_comp, - comp_method_zlib_decomp, - comp_method_zlib_dtor, -}; -#endif /* LIBSSH2_HAVE_ZLIB */ - -/* If compression is enabled by the API, then this array is used which then - may allow compression if zlib is available at build time */ -static const LIBSSH2_COMP_METHOD *comp_methods[] = { -#ifdef LIBSSH2_HAVE_ZLIB - &comp_method_zlib, - &comp_method_zlib_openssh, -#endif /* LIBSSH2_HAVE_ZLIB */ - &comp_method_none, - NULL -}; - -/* If compression is disabled by the API, then this array is used */ -static const LIBSSH2_COMP_METHOD *no_comp_methods[] = { - &comp_method_none, - NULL -}; - -const LIBSSH2_COMP_METHOD ** -_libssh2_comp_methods(LIBSSH2_SESSION *session) -{ - if(session->flag.compress) - return comp_methods; - else - return no_comp_methods; -} diff --git a/libssh2/crypt.c b/libssh2/crypt.c deleted file mode 100644 index 8d493b4..0000000 --- a/libssh2/crypt.c +++ /dev/null @@ -1,349 +0,0 @@ -/* Copyright (c) 2009, 2010 Simon Josefsson - * Copyright (c) 2004-2007, Sara Golemon - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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 "libssh2_priv.h" - -#ifdef LIBSSH2_CRYPT_NONE - -/* crypt_none_crypt - * Minimalist cipher: VERY secure *wink* - */ -static int -crypt_none_crypt(LIBSSH2_SESSION * session, unsigned char *buf, - void **abstract) -{ - /* Do nothing to the data! */ - return 0; -} - -static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_none = { - "none", - "DEK-Info: NONE", - 8, /* blocksize (SSH2 defines minimum blocksize as 8) */ - 0, /* iv_len */ - 0, /* secret_len */ - 0, /* flags */ - NULL, - crypt_none_crypt, - NULL -}; -#endif /* LIBSSH2_CRYPT_NONE */ - -struct crypt_ctx -{ - int encrypt; - _libssh2_cipher_type(algo); - _libssh2_cipher_ctx h; -}; - -static int -crypt_init(LIBSSH2_SESSION * session, - const LIBSSH2_CRYPT_METHOD * method, - unsigned char *iv, int *free_iv, - unsigned char *secret, int *free_secret, - int encrypt, void **abstract) -{ - struct crypt_ctx *ctx = LIBSSH2_ALLOC(session, - sizeof(struct crypt_ctx)); - if(!ctx) - return LIBSSH2_ERROR_ALLOC; - - ctx->encrypt = encrypt; - ctx->algo = method->algo; - if(_libssh2_cipher_init(&ctx->h, ctx->algo, iv, secret, encrypt)) { - LIBSSH2_FREE(session, ctx); - return -1; - } - *abstract = ctx; - *free_iv = 1; - *free_secret = 1; - return 0; -} - -static int -crypt_encrypt(LIBSSH2_SESSION * session, unsigned char *block, - size_t blocksize, void **abstract) -{ - struct crypt_ctx *cctx = *(struct crypt_ctx **) abstract; - (void) session; - return _libssh2_cipher_crypt(&cctx->h, cctx->algo, cctx->encrypt, block, - blocksize); -} - -static int -crypt_dtor(LIBSSH2_SESSION * session, void **abstract) -{ - struct crypt_ctx **cctx = (struct crypt_ctx **) abstract; - if(cctx && *cctx) { - _libssh2_cipher_dtor(&(*cctx)->h); - LIBSSH2_FREE(session, *cctx); - *abstract = NULL; - } - return 0; -} - -#if LIBSSH2_AES_CTR -static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes128_ctr = { - "aes128-ctr", - "", - 16, /* blocksize */ - 16, /* initial value length */ - 16, /* secret length -- 16*8 == 128bit */ - 0, /* flags */ - &crypt_init, - &crypt_encrypt, - &crypt_dtor, - _libssh2_cipher_aes128ctr -}; - -static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes192_ctr = { - "aes192-ctr", - "", - 16, /* blocksize */ - 16, /* initial value length */ - 24, /* secret length -- 24*8 == 192bit */ - 0, /* flags */ - &crypt_init, - &crypt_encrypt, - &crypt_dtor, - _libssh2_cipher_aes192ctr -}; - -static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes256_ctr = { - "aes256-ctr", - "", - 16, /* blocksize */ - 16, /* initial value length */ - 32, /* secret length -- 32*8 == 256bit */ - 0, /* flags */ - &crypt_init, - &crypt_encrypt, - &crypt_dtor, - _libssh2_cipher_aes256ctr -}; -#endif - -#if LIBSSH2_AES -static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes128_cbc = { - "aes128-cbc", - "DEK-Info: AES-128-CBC", - 16, /* blocksize */ - 16, /* initial value length */ - 16, /* secret length -- 16*8 == 128bit */ - 0, /* flags */ - &crypt_init, - &crypt_encrypt, - &crypt_dtor, - _libssh2_cipher_aes128 -}; - -static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes192_cbc = { - "aes192-cbc", - "DEK-Info: AES-192-CBC", - 16, /* blocksize */ - 16, /* initial value length */ - 24, /* secret length -- 24*8 == 192bit */ - 0, /* flags */ - &crypt_init, - &crypt_encrypt, - &crypt_dtor, - _libssh2_cipher_aes192 -}; - -static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes256_cbc = { - "aes256-cbc", - "DEK-Info: AES-256-CBC", - 16, /* blocksize */ - 16, /* initial value length */ - 32, /* secret length -- 32*8 == 256bit */ - 0, /* flags */ - &crypt_init, - &crypt_encrypt, - &crypt_dtor, - _libssh2_cipher_aes256 -}; - -/* rijndael-cbc@lysator.liu.se == aes256-cbc */ -static const LIBSSH2_CRYPT_METHOD - libssh2_crypt_method_rijndael_cbc_lysator_liu_se = { - "rijndael-cbc@lysator.liu.se", - "DEK-Info: AES-256-CBC", - 16, /* blocksize */ - 16, /* initial value length */ - 32, /* secret length -- 32*8 == 256bit */ - 0, /* flags */ - &crypt_init, - &crypt_encrypt, - &crypt_dtor, - _libssh2_cipher_aes256 -}; -#endif /* LIBSSH2_AES */ - -#if LIBSSH2_BLOWFISH -static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_blowfish_cbc = { - "blowfish-cbc", - "", - 8, /* blocksize */ - 8, /* initial value length */ - 16, /* secret length */ - 0, /* flags */ - &crypt_init, - &crypt_encrypt, - &crypt_dtor, - _libssh2_cipher_blowfish -}; -#endif /* LIBSSH2_BLOWFISH */ - -#if LIBSSH2_RC4 -static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_arcfour = { - "arcfour", - "DEK-Info: RC4", - 8, /* blocksize */ - 8, /* initial value length */ - 16, /* secret length */ - 0, /* flags */ - &crypt_init, - &crypt_encrypt, - &crypt_dtor, - _libssh2_cipher_arcfour -}; - -static int -crypt_init_arcfour128(LIBSSH2_SESSION * session, - const LIBSSH2_CRYPT_METHOD * method, - unsigned char *iv, int *free_iv, - unsigned char *secret, int *free_secret, - int encrypt, void **abstract) -{ - int rc; - - rc = crypt_init(session, method, iv, free_iv, secret, free_secret, - encrypt, abstract); - if(rc == 0) { - struct crypt_ctx *cctx = *(struct crypt_ctx **) abstract; - unsigned char block[8]; - size_t discard = 1536; - for(; discard; discard -= 8) - _libssh2_cipher_crypt(&cctx->h, cctx->algo, cctx->encrypt, block, - method->blocksize); - } - - return rc; -} - -static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_arcfour128 = { - "arcfour128", - "", - 8, /* blocksize */ - 8, /* initial value length */ - 16, /* secret length */ - 0, /* flags */ - &crypt_init_arcfour128, - &crypt_encrypt, - &crypt_dtor, - _libssh2_cipher_arcfour -}; -#endif /* LIBSSH2_RC4 */ - -#if LIBSSH2_CAST -static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_cast128_cbc = { - "cast128-cbc", - "", - 8, /* blocksize */ - 8, /* initial value length */ - 16, /* secret length */ - 0, /* flags */ - &crypt_init, - &crypt_encrypt, - &crypt_dtor, - _libssh2_cipher_cast5 -}; -#endif /* LIBSSH2_CAST */ - -#if LIBSSH2_3DES -static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_3des_cbc = { - "3des-cbc", - "DEK-Info: DES-EDE3-CBC", - 8, /* blocksize */ - 8, /* initial value length */ - 24, /* secret length */ - 0, /* flags */ - &crypt_init, - &crypt_encrypt, - &crypt_dtor, - _libssh2_cipher_3des -}; -#endif - -static const LIBSSH2_CRYPT_METHOD *_libssh2_crypt_methods[] = { -#if LIBSSH2_AES_CTR - &libssh2_crypt_method_aes128_ctr, - &libssh2_crypt_method_aes192_ctr, - &libssh2_crypt_method_aes256_ctr, -#endif /* LIBSSH2_AES */ -#if LIBSSH2_AES - &libssh2_crypt_method_aes256_cbc, - &libssh2_crypt_method_rijndael_cbc_lysator_liu_se, /* == aes256-cbc */ - &libssh2_crypt_method_aes192_cbc, - &libssh2_crypt_method_aes128_cbc, -#endif /* LIBSSH2_AES */ -#if LIBSSH2_BLOWFISH - &libssh2_crypt_method_blowfish_cbc, -#endif /* LIBSSH2_BLOWFISH */ -#if LIBSSH2_RC4 - &libssh2_crypt_method_arcfour128, - &libssh2_crypt_method_arcfour, -#endif /* LIBSSH2_RC4 */ -#if LIBSSH2_CAST - &libssh2_crypt_method_cast128_cbc, -#endif /* LIBSSH2_CAST */ -#if LIBSSH2_3DES - &libssh2_crypt_method_3des_cbc, -#endif /* LIBSSH2_DES */ -#ifdef LIBSSH2_CRYPT_NONE - &libssh2_crypt_method_none, -#endif - NULL -}; - -/* Expose to kex.c */ -const LIBSSH2_CRYPT_METHOD ** -libssh2_crypt_methods(void) -{ - return _libssh2_crypt_methods; -} diff --git a/libssh2/global.c b/libssh2/global.c deleted file mode 100644 index 6828984..0000000 --- a/libssh2/global.c +++ /dev/null @@ -1,78 +0,0 @@ -/* Copyright (c) 2010 Lars Nordin - * Copyright (C) 2010 Simon Josefsson - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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 "libssh2_priv.h" - -static int _libssh2_initialized = 0; -static int _libssh2_init_flags = 0; - -LIBSSH2_API int -libssh2_init(int flags) -{ - if(_libssh2_initialized == 0 && !(flags & LIBSSH2_INIT_NO_CRYPTO)) { - libssh2_crypto_init(); - } - - _libssh2_initialized++; - _libssh2_init_flags |= flags; - - return 0; -} - -LIBSSH2_API void -libssh2_exit(void) -{ - if(_libssh2_initialized == 0) - return; - - _libssh2_initialized--; - - if(_libssh2_initialized == 0 && - !(_libssh2_init_flags & LIBSSH2_INIT_NO_CRYPTO)) { - libssh2_crypto_exit(); - } - - return; -} - -void -_libssh2_init_if_needed(void) -{ - if(_libssh2_initialized == 0) - (void)libssh2_init (0); -} diff --git a/libssh2/hostkey.c b/libssh2/hostkey.c deleted file mode 100644 index 1631aae..0000000 --- a/libssh2/hostkey.c +++ /dev/null @@ -1,1129 +0,0 @@ -/* Copyright (c) 2004-2006, Sara Golemon - * Copyright (c) 2009-2019 by Daniel Stenberg - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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 "libssh2_priv.h" -#include "misc.h" - -/* Needed for struct iovec on some platforms */ -#ifdef HAVE_SYS_UIO_H -#include -#endif - -#if LIBSSH2_RSA -/* *********** - * ssh-rsa * - *********** */ - -static int hostkey_method_ssh_rsa_dtor(LIBSSH2_SESSION * session, - void **abstract); - -/* - * hostkey_method_ssh_rsa_init - * - * Initialize the server hostkey working area with e/n pair - */ -static int -hostkey_method_ssh_rsa_init(LIBSSH2_SESSION * session, - const unsigned char *hostkey_data, - size_t hostkey_data_len, - void **abstract) -{ - libssh2_rsa_ctx *rsactx; - unsigned char *e, *n; - size_t e_len, n_len; - struct string_buf buf; - - if(*abstract) { - hostkey_method_ssh_rsa_dtor(session, abstract); - *abstract = NULL; - } - - if(hostkey_data_len < 19) { - _libssh2_debug(session, LIBSSH2_TRACE_ERROR, - "host key length too short"); - return -1; - } - - buf.data = (unsigned char *)hostkey_data; - buf.dataptr = buf.data; - buf.len = hostkey_data_len; - - if(_libssh2_match_string(&buf, "ssh-rsa")) - return -1; - - if(_libssh2_get_string(&buf, &e, &e_len)) - return -1; - - if(_libssh2_get_string(&buf, &n, &n_len)) - return -1; - - if(_libssh2_rsa_new(&rsactx, e, e_len, n, n_len, NULL, 0, - NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0)) { - return -1; - } - - *abstract = rsactx; - - return 0; -} - -/* - * hostkey_method_ssh_rsa_initPEM - * - * Load a Private Key from a PEM file - */ -static int -hostkey_method_ssh_rsa_initPEM(LIBSSH2_SESSION * session, - const char *privkeyfile, - unsigned const char *passphrase, - void **abstract) -{ - libssh2_rsa_ctx *rsactx; - int ret; - - if(*abstract) { - hostkey_method_ssh_rsa_dtor(session, abstract); - *abstract = NULL; - } - - ret = _libssh2_rsa_new_private(&rsactx, session, privkeyfile, passphrase); - if(ret) { - return -1; - } - - *abstract = rsactx; - - return 0; -} - -/* - * hostkey_method_ssh_rsa_initPEMFromMemory - * - * Load a Private Key from a memory - */ -static int -hostkey_method_ssh_rsa_initPEMFromMemory(LIBSSH2_SESSION * session, - const char *privkeyfiledata, - size_t privkeyfiledata_len, - unsigned const char *passphrase, - void **abstract) -{ - libssh2_rsa_ctx *rsactx; - int ret; - - if(*abstract) { - hostkey_method_ssh_rsa_dtor(session, abstract); - *abstract = NULL; - } - - ret = _libssh2_rsa_new_private_frommemory(&rsactx, session, - privkeyfiledata, - privkeyfiledata_len, passphrase); - if(ret) { - return -1; - } - - *abstract = rsactx; - - return 0; -} - -/* - * hostkey_method_ssh_rsa_sign - * - * Verify signature created by remote - */ -static int -hostkey_method_ssh_rsa_sig_verify(LIBSSH2_SESSION * session, - const unsigned char *sig, - size_t sig_len, - const unsigned char *m, - size_t m_len, void **abstract) -{ - libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract); - (void) session; - - /* Skip past keyname_len(4) + keyname(7){"ssh-rsa"} + signature_len(4) */ - if(sig_len < 15) - return -1; - - sig += 15; - sig_len -= 15; - return _libssh2_rsa_sha1_verify(rsactx, sig, sig_len, m, m_len); -} - -/* - * hostkey_method_ssh_rsa_signv - * - * Construct a signature from an array of vectors - */ -static int -hostkey_method_ssh_rsa_signv(LIBSSH2_SESSION * session, - unsigned char **signature, - size_t *signature_len, - int veccount, - const struct iovec datavec[], - void **abstract) -{ - libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract); - -#ifdef _libssh2_rsa_sha1_signv - return _libssh2_rsa_sha1_signv(session, signature, signature_len, - veccount, datavec, rsactx); -#else - int ret; - int i; - unsigned char hash[SHA_DIGEST_LENGTH]; - libssh2_sha1_ctx ctx; - - libssh2_sha1_init(&ctx); - for(i = 0; i < veccount; i++) { - libssh2_sha1_update(ctx, datavec[i].iov_base, datavec[i].iov_len); - } - libssh2_sha1_final(ctx, hash); - - ret = _libssh2_rsa_sha1_sign(session, rsactx, hash, SHA_DIGEST_LENGTH, - signature, signature_len); - if(ret) { - return -1; - } - - return 0; -#endif -} - -/* - * hostkey_method_ssh_rsa_dtor - * - * Shutdown the hostkey - */ -static int -hostkey_method_ssh_rsa_dtor(LIBSSH2_SESSION * session, void **abstract) -{ - libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract); - (void) session; - - _libssh2_rsa_free(rsactx); - - *abstract = NULL; - - return 0; -} - -#ifdef OPENSSL_NO_MD5 -#define MD5_DIGEST_LENGTH 16 -#endif - -static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_rsa = { - "ssh-rsa", - MD5_DIGEST_LENGTH, - hostkey_method_ssh_rsa_init, - hostkey_method_ssh_rsa_initPEM, - hostkey_method_ssh_rsa_initPEMFromMemory, - hostkey_method_ssh_rsa_sig_verify, - hostkey_method_ssh_rsa_signv, - NULL, /* encrypt */ - hostkey_method_ssh_rsa_dtor, -}; -#endif /* LIBSSH2_RSA */ - -#if LIBSSH2_DSA -/* *********** - * ssh-dss * - *********** */ - -static int hostkey_method_ssh_dss_dtor(LIBSSH2_SESSION * session, - void **abstract); - -/* - * hostkey_method_ssh_dss_init - * - * Initialize the server hostkey working area with p/q/g/y set - */ -static int -hostkey_method_ssh_dss_init(LIBSSH2_SESSION * session, - const unsigned char *hostkey_data, - size_t hostkey_data_len, - void **abstract) -{ - libssh2_dsa_ctx *dsactx; - unsigned char *p, *q, *g, *y; - size_t p_len, q_len, g_len, y_len; - struct string_buf buf; - - if(*abstract) { - hostkey_method_ssh_dss_dtor(session, abstract); - *abstract = NULL; - } - - if(hostkey_data_len < 27) { - _libssh2_debug(session, LIBSSH2_TRACE_ERROR, - "host key length too short"); - return -1; - } - - buf.data = (unsigned char *)hostkey_data; - buf.dataptr = buf.data; - buf.len = hostkey_data_len; - - if(_libssh2_match_string(&buf, "ssh-dss")) - return -1; - - if(_libssh2_get_string(&buf, &p, &p_len)) - return -1; - - if(_libssh2_get_string(&buf, &q, &q_len)) - return -1; - - if(_libssh2_get_string(&buf, &g, &g_len)) - return -1; - - if(_libssh2_get_string(&buf, &y, &y_len)) - return -1; - - if(_libssh2_dsa_new(&dsactx, p, p_len, q, q_len, - g, g_len, y, y_len, NULL, 0)) { - return -1; - } - - *abstract = dsactx; - - return 0; -} - -/* - * hostkey_method_ssh_dss_initPEM - * - * Load a Private Key from a PEM file - */ -static int -hostkey_method_ssh_dss_initPEM(LIBSSH2_SESSION * session, - const char *privkeyfile, - unsigned const char *passphrase, - void **abstract) -{ - libssh2_dsa_ctx *dsactx; - int ret; - - if(*abstract) { - hostkey_method_ssh_dss_dtor(session, abstract); - *abstract = NULL; - } - - ret = _libssh2_dsa_new_private(&dsactx, session, privkeyfile, passphrase); - if(ret) { - return -1; - } - - *abstract = dsactx; - - return 0; -} - -/* - * hostkey_method_ssh_dss_initPEMFromMemory - * - * Load a Private Key from memory - */ -static int -hostkey_method_ssh_dss_initPEMFromMemory(LIBSSH2_SESSION * session, - const char *privkeyfiledata, - size_t privkeyfiledata_len, - unsigned const char *passphrase, - void **abstract) -{ - libssh2_dsa_ctx *dsactx; - int ret; - - if(*abstract) { - hostkey_method_ssh_dss_dtor(session, abstract); - *abstract = NULL; - } - - ret = _libssh2_dsa_new_private_frommemory(&dsactx, session, - privkeyfiledata, - privkeyfiledata_len, passphrase); - if(ret) { - return -1; - } - - *abstract = dsactx; - - return 0; -} - -/* - * libssh2_hostkey_method_ssh_dss_sign - * - * Verify signature created by remote - */ -static int -hostkey_method_ssh_dss_sig_verify(LIBSSH2_SESSION * session, - const unsigned char *sig, - size_t sig_len, - const unsigned char *m, - size_t m_len, void **abstract) -{ - libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx *) (*abstract); - - /* Skip past keyname_len(4) + keyname(7){"ssh-dss"} + signature_len(4) */ - if(sig_len != 55) { - return _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Invalid DSS signature length"); - } - - sig += 15; - sig_len -= 15; - - return _libssh2_dsa_sha1_verify(dsactx, sig, m, m_len); -} - -/* - * hostkey_method_ssh_dss_signv - * - * Construct a signature from an array of vectors - */ -static int -hostkey_method_ssh_dss_signv(LIBSSH2_SESSION * session, - unsigned char **signature, - size_t *signature_len, - int veccount, - const struct iovec datavec[], - void **abstract) -{ - libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx *) (*abstract); - unsigned char hash[SHA_DIGEST_LENGTH]; - libssh2_sha1_ctx ctx; - int i; - - *signature = LIBSSH2_CALLOC(session, 2 * SHA_DIGEST_LENGTH); - if(!*signature) { - return -1; - } - - *signature_len = 2 * SHA_DIGEST_LENGTH; - - libssh2_sha1_init(&ctx); - for(i = 0; i < veccount; i++) { - libssh2_sha1_update(ctx, datavec[i].iov_base, datavec[i].iov_len); - } - libssh2_sha1_final(ctx, hash); - - if(_libssh2_dsa_sha1_sign(dsactx, hash, SHA_DIGEST_LENGTH, *signature)) { - LIBSSH2_FREE(session, *signature); - return -1; - } - - return 0; -} - -/* - * libssh2_hostkey_method_ssh_dss_dtor - * - * Shutdown the hostkey method - */ -static int -hostkey_method_ssh_dss_dtor(LIBSSH2_SESSION * session, void **abstract) -{ - libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx *) (*abstract); - (void) session; - - _libssh2_dsa_free(dsactx); - - *abstract = NULL; - - return 0; -} - -static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_dss = { - "ssh-dss", - MD5_DIGEST_LENGTH, - hostkey_method_ssh_dss_init, - hostkey_method_ssh_dss_initPEM, - hostkey_method_ssh_dss_initPEMFromMemory, - hostkey_method_ssh_dss_sig_verify, - hostkey_method_ssh_dss_signv, - NULL, /* encrypt */ - hostkey_method_ssh_dss_dtor, -}; -#endif /* LIBSSH2_DSA */ - -#if LIBSSH2_ECDSA - -/* *********** - * ecdsa-sha2-nistp256/384/521 * - *********** */ - -static int -hostkey_method_ssh_ecdsa_dtor(LIBSSH2_SESSION * session, - void **abstract); - -/* - * hostkey_method_ssh_ecdsa_init - * - * Initialize the server hostkey working area with e/n pair - */ -static int -hostkey_method_ssh_ecdsa_init(LIBSSH2_SESSION * session, - const unsigned char *hostkey_data, - size_t hostkey_data_len, - void **abstract) -{ - libssh2_ecdsa_ctx *ecdsactx = NULL; - unsigned char *type_str, *domain, *public_key; - size_t key_len, len; - libssh2_curve_type type; - struct string_buf buf; - - if(abstract != NULL && *abstract) { - hostkey_method_ssh_ecdsa_dtor(session, abstract); - *abstract = NULL; - } - - if(hostkey_data_len < 39) { - _libssh2_debug(session, LIBSSH2_TRACE_ERROR, - "host key length too short"); - return -1; - } - - buf.data = (unsigned char *)hostkey_data; - buf.dataptr = buf.data; - buf.len = hostkey_data_len; - - if(_libssh2_get_string(&buf, &type_str, &len) || len != 19) - return -1; - - if(strncmp((char *) type_str, "ecdsa-sha2-nistp256", 19) == 0) { - type = LIBSSH2_EC_CURVE_NISTP256; - } - else if(strncmp((char *) type_str, "ecdsa-sha2-nistp384", 19) == 0) { - type = LIBSSH2_EC_CURVE_NISTP384; - } - else if(strncmp((char *) type_str, "ecdsa-sha2-nistp521", 19) == 0) { - type = LIBSSH2_EC_CURVE_NISTP521; - } - else { - return -1; - } - - if(_libssh2_get_string(&buf, &domain, &len) || len != 8) - return -1; - - if(type == LIBSSH2_EC_CURVE_NISTP256 && - strncmp((char *)domain, "nistp256", 8) != 0) { - return -1; - } - else if(type == LIBSSH2_EC_CURVE_NISTP384 && - strncmp((char *)domain, "nistp384", 8) != 0) { - return -1; - } - else if(type == LIBSSH2_EC_CURVE_NISTP521 && - strncmp((char *)domain, "nistp521", 8) != 0) { - return -1; - } - - /* public key */ - if(_libssh2_get_string(&buf, &public_key, &key_len)) - return -1; - - if(_libssh2_ecdsa_curve_name_with_octal_new(&ecdsactx, public_key, - key_len, type)) - return -1; - - if(abstract != NULL) - *abstract = ecdsactx; - - return 0; -} - -/* - * hostkey_method_ssh_ecdsa_initPEM - * - * Load a Private Key from a PEM file - */ -static int -hostkey_method_ssh_ecdsa_initPEM(LIBSSH2_SESSION * session, - const char *privkeyfile, - unsigned const char *passphrase, - void **abstract) -{ - libssh2_ecdsa_ctx *ec_ctx = NULL; - int ret; - - if(abstract != NULL && *abstract) { - hostkey_method_ssh_ecdsa_dtor(session, abstract); - *abstract = NULL; - } - - ret = _libssh2_ecdsa_new_private(&ec_ctx, session, - privkeyfile, passphrase); - - if(abstract != NULL) - *abstract = ec_ctx; - - return ret; -} - -/* - * hostkey_method_ssh_ecdsa_initPEMFromMemory - * - * Load a Private Key from memory - */ -static int -hostkey_method_ssh_ecdsa_initPEMFromMemory(LIBSSH2_SESSION * session, - const char *privkeyfiledata, - size_t privkeyfiledata_len, - unsigned const char *passphrase, - void **abstract) -{ - libssh2_ecdsa_ctx *ec_ctx = NULL; - int ret; - - if(abstract != NULL && *abstract) { - hostkey_method_ssh_ecdsa_dtor(session, abstract); - *abstract = NULL; - } - - ret = _libssh2_ecdsa_new_private_frommemory(&ec_ctx, session, - privkeyfiledata, - privkeyfiledata_len, - passphrase); - if(ret) { - return -1; - } - - if(abstract != NULL) - *abstract = ec_ctx; - - return 0; -} - -/* - * hostkey_method_ecdsa_sig_verify - * - * Verify signature created by remote - */ -static int -hostkey_method_ssh_ecdsa_sig_verify(LIBSSH2_SESSION * session, - const unsigned char *sig, - size_t sig_len, - const unsigned char *m, - size_t m_len, void **abstract) -{ - unsigned char *r, *s, *name; - size_t r_len, s_len, name_len; - uint32_t len; - struct string_buf buf; - libssh2_ecdsa_ctx *ctx = (libssh2_ecdsa_ctx *) (*abstract); - - (void) session; - - if(sig_len < 35) - return -1; - - /* keyname_len(4) + keyname(19){"ecdsa-sha2-nistp256"} + - signature_len(4) */ - buf.data = (unsigned char *)sig; - buf.dataptr = buf.data; - buf.len = sig_len; - - if(_libssh2_get_string(&buf, &name, &name_len) || name_len != 19) - return -1; - - if(_libssh2_get_u32(&buf, &len) != 0 || len < 8) - return -1; - - if(_libssh2_get_string(&buf, &r, &r_len)) - return -1; - - if(_libssh2_get_string(&buf, &s, &s_len)) - return -1; - - return _libssh2_ecdsa_verify(ctx, r, r_len, s, s_len, m, m_len); -} - - -#define LIBSSH2_HOSTKEY_METHOD_EC_SIGNV_HASH(digest_type) \ - { \ - unsigned char hash[SHA##digest_type##_DIGEST_LENGTH]; \ - libssh2_sha##digest_type##_ctx ctx; \ - int i; \ - libssh2_sha##digest_type##_init(&ctx); \ - for(i = 0; i < veccount; i++) { \ - libssh2_sha##digest_type##_update(ctx, datavec[i].iov_base, \ - datavec[i].iov_len); \ - } \ - libssh2_sha##digest_type##_final(ctx, hash); \ - ret = _libssh2_ecdsa_sign(session, ec_ctx, hash, \ - SHA##digest_type##_DIGEST_LENGTH, \ - signature, signature_len); \ - } - - -/* - * hostkey_method_ecdsa_signv - * - * Construct a signature from an array of vectors - */ -static int -hostkey_method_ssh_ecdsa_signv(LIBSSH2_SESSION * session, - unsigned char **signature, - size_t *signature_len, - int veccount, - const struct iovec datavec[], - void **abstract) -{ - libssh2_ecdsa_ctx *ec_ctx = (libssh2_ecdsa_ctx *) (*abstract); - libssh2_curve_type type = _libssh2_ecdsa_get_curve_type(ec_ctx); - int ret = 0; - - if(type == LIBSSH2_EC_CURVE_NISTP256) { - LIBSSH2_HOSTKEY_METHOD_EC_SIGNV_HASH(256); - } - else if(type == LIBSSH2_EC_CURVE_NISTP384) { - LIBSSH2_HOSTKEY_METHOD_EC_SIGNV_HASH(384); - } - else if(type == LIBSSH2_EC_CURVE_NISTP521) { - LIBSSH2_HOSTKEY_METHOD_EC_SIGNV_HASH(512); - } - else { - return -1; - } - - return ret; -} - -/* - * hostkey_method_ssh_ecdsa_dtor - * - * Shutdown the hostkey by freeing EC_KEY context - */ -static int -hostkey_method_ssh_ecdsa_dtor(LIBSSH2_SESSION * session, void **abstract) -{ - libssh2_ecdsa_ctx *keyctx = (libssh2_ecdsa_ctx *) (*abstract); - (void) session; - - if(keyctx != NULL) - _libssh2_ecdsa_free(keyctx); - - *abstract = NULL; - - return 0; -} - -static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ecdsa_ssh_nistp256 = { - "ecdsa-sha2-nistp256", - SHA256_DIGEST_LENGTH, - hostkey_method_ssh_ecdsa_init, - hostkey_method_ssh_ecdsa_initPEM, - hostkey_method_ssh_ecdsa_initPEMFromMemory, - hostkey_method_ssh_ecdsa_sig_verify, - hostkey_method_ssh_ecdsa_signv, - NULL, /* encrypt */ - hostkey_method_ssh_ecdsa_dtor, -}; - -static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ecdsa_ssh_nistp384 = { - "ecdsa-sha2-nistp384", - SHA384_DIGEST_LENGTH, - hostkey_method_ssh_ecdsa_init, - hostkey_method_ssh_ecdsa_initPEM, - hostkey_method_ssh_ecdsa_initPEMFromMemory, - hostkey_method_ssh_ecdsa_sig_verify, - hostkey_method_ssh_ecdsa_signv, - NULL, /* encrypt */ - hostkey_method_ssh_ecdsa_dtor, -}; - -static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ecdsa_ssh_nistp521 = { - "ecdsa-sha2-nistp521", - SHA512_DIGEST_LENGTH, - hostkey_method_ssh_ecdsa_init, - hostkey_method_ssh_ecdsa_initPEM, - hostkey_method_ssh_ecdsa_initPEMFromMemory, - hostkey_method_ssh_ecdsa_sig_verify, - hostkey_method_ssh_ecdsa_signv, - NULL, /* encrypt */ - hostkey_method_ssh_ecdsa_dtor, -}; - -#endif /* LIBSSH2_ECDSA */ - -#if LIBSSH2_ED25519 - -/* *********** - * ed25519 * - *********** */ - -static int hostkey_method_ssh_ed25519_dtor(LIBSSH2_SESSION * session, - void **abstract); - -/* - * hostkey_method_ssh_ed25519_init - * - * Initialize the server hostkey working area with e/n pair - */ -static int -hostkey_method_ssh_ed25519_init(LIBSSH2_SESSION * session, - const unsigned char *hostkey_data, - size_t hostkey_data_len, - void **abstract) -{ - const unsigned char *s; - unsigned long len, key_len; - libssh2_ed25519_ctx *ctx = NULL; - - if(*abstract) { - hostkey_method_ssh_ed25519_dtor(session, abstract); - *abstract = NULL; - } - - if(hostkey_data_len < 19) { - _libssh2_debug(session, LIBSSH2_TRACE_ERROR, - "host key length too short"); - return -1; - } - - s = hostkey_data; - len = _libssh2_ntohu32(s); - s += 4; - - if(len != 11 || strncmp((char *) s, "ssh-ed25519", 11) != 0) { - return -1; - } - - s += 11; - - /* public key */ - key_len = _libssh2_ntohu32(s); - s += 4; - - if(_libssh2_ed25519_new_public(&ctx, session, s, key_len) != 0) { - return -1; - } - - *abstract = ctx; - - return 0; -} - -/* - * hostkey_method_ssh_ed25519_initPEM - * - * Load a Private Key from a PEM file - */ -static int -hostkey_method_ssh_ed25519_initPEM(LIBSSH2_SESSION * session, - const char *privkeyfile, - unsigned const char *passphrase, - void **abstract) -{ - libssh2_ed25519_ctx *ec_ctx = NULL; - int ret; - - if(*abstract) { - hostkey_method_ssh_ed25519_dtor(session, abstract); - *abstract = NULL; - } - - ret = _libssh2_ed25519_new_private(&ec_ctx, session, - privkeyfile, passphrase); - if(ret) { - return -1; - } - - *abstract = ec_ctx; - - return ret; -} - -/* - * hostkey_method_ssh_ed25519_initPEMFromMemory - * - * Load a Private Key from memory - */ -static int -hostkey_method_ssh_ed25519_initPEMFromMemory(LIBSSH2_SESSION * session, - const char *privkeyfiledata, - size_t privkeyfiledata_len, - unsigned const char *passphrase, - void **abstract) -{ - libssh2_ed25519_ctx *ed_ctx = NULL; - int ret; - - if(abstract != NULL && *abstract) { - hostkey_method_ssh_ed25519_dtor(session, abstract); - *abstract = NULL; - } - - ret = _libssh2_ed25519_new_private_frommemory(&ed_ctx, session, - privkeyfiledata, - privkeyfiledata_len, - passphrase); - if(ret) { - return -1; - } - - if(abstract != NULL) - *abstract = ed_ctx; - - return 0; -} - -/* - * hostkey_method_ssh_ed25519_sig_verify - * - * Verify signature created by remote - */ -static int -hostkey_method_ssh_ed25519_sig_verify(LIBSSH2_SESSION * session, - const unsigned char *sig, - size_t sig_len, - const unsigned char *m, - size_t m_len, void **abstract) -{ - libssh2_ed25519_ctx *ctx = (libssh2_ed25519_ctx *) (*abstract); - (void) session; - - if(sig_len < 19) - return -1; - - /* Skip past keyname_len(4) + keyname(11){"ssh-ed25519"} + - signature_len(4) */ - sig += 19; - sig_len -= 19; - - if(sig_len != LIBSSH2_ED25519_SIG_LEN) - return -1; - - return _libssh2_ed25519_verify(ctx, sig, sig_len, m, m_len); -} - -/* - * hostkey_method_ssh_ed25519_signv - * - * Construct a signature from an array of vectors - */ -static int -hostkey_method_ssh_ed25519_signv(LIBSSH2_SESSION * session, - unsigned char **signature, - size_t *signature_len, - int veccount, - const struct iovec datavec[], - void **abstract) -{ - libssh2_ed25519_ctx *ctx = (libssh2_ed25519_ctx *) (*abstract); - - if(veccount != 1) { - return -1; - } - - return _libssh2_ed25519_sign(ctx, session, signature, signature_len, - datavec[0].iov_base, datavec[0].iov_len); -} - - -/* - * hostkey_method_ssh_ed25519_dtor - * - * Shutdown the hostkey by freeing key context - */ -static int -hostkey_method_ssh_ed25519_dtor(LIBSSH2_SESSION * session, void **abstract) -{ - libssh2_ed25519_ctx *keyctx = (libssh2_ed25519_ctx*) (*abstract); - (void) session; - - if(keyctx) - _libssh2_ed25519_free(keyctx); - - *abstract = NULL; - - return 0; -} - -static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_ed25519 = { - "ssh-ed25519", - SHA256_DIGEST_LENGTH, - hostkey_method_ssh_ed25519_init, - hostkey_method_ssh_ed25519_initPEM, - hostkey_method_ssh_ed25519_initPEMFromMemory, - hostkey_method_ssh_ed25519_sig_verify, - hostkey_method_ssh_ed25519_signv, - NULL, /* encrypt */ - hostkey_method_ssh_ed25519_dtor, -}; - -#endif /*LIBSSH2_ED25519*/ - - -static const LIBSSH2_HOSTKEY_METHOD *hostkey_methods[] = { -#if LIBSSH2_ECDSA - &hostkey_method_ecdsa_ssh_nistp256, - &hostkey_method_ecdsa_ssh_nistp384, - &hostkey_method_ecdsa_ssh_nistp521, -#endif -#if LIBSSH2_ED25519 - &hostkey_method_ssh_ed25519, -#endif -#if LIBSSH2_RSA - &hostkey_method_ssh_rsa, -#endif /* LIBSSH2_RSA */ -#if LIBSSH2_DSA - &hostkey_method_ssh_dss, -#endif /* LIBSSH2_DSA */ - NULL -}; - -const LIBSSH2_HOSTKEY_METHOD ** -libssh2_hostkey_methods(void) -{ - return hostkey_methods; -} - -/* - * libssh2_hostkey_hash - * - * Returns hash signature - * Returned buffer should NOT be freed - * Length of buffer is determined by hash type - * i.e. MD5 == 16, SHA1 == 20, SHA256 == 32 - */ -LIBSSH2_API const char * -libssh2_hostkey_hash(LIBSSH2_SESSION * session, int hash_type) -{ - switch(hash_type) { -#if LIBSSH2_MD5 - case LIBSSH2_HOSTKEY_HASH_MD5: - return (session->server_hostkey_md5_valid) - ? (char *) session->server_hostkey_md5 - : NULL; - break; -#endif /* LIBSSH2_MD5 */ - case LIBSSH2_HOSTKEY_HASH_SHA1: - return (session->server_hostkey_sha1_valid) - ? (char *) session->server_hostkey_sha1 - : NULL; - break; - case LIBSSH2_HOSTKEY_HASH_SHA256: - return (session->server_hostkey_sha256_valid) - ? (char *) session->server_hostkey_sha256 - : NULL; - break; - default: - return NULL; - } -} - -static int hostkey_type(const unsigned char *hostkey, size_t len) -{ - static const unsigned char rsa[] = { - 0, 0, 0, 0x07, 's', 's', 'h', '-', 'r', 's', 'a' - }; - static const unsigned char dss[] = { - 0, 0, 0, 0x07, 's', 's', 'h', '-', 'd', 's', 's' - }; - static const unsigned char ecdsa_256[] = { - 0, 0, 0, 0x13, 'e', 'c', 'd', 's', 'a', '-', 's', 'h', 'a', '2', '-', - 'n', 'i', 's', 't', 'p', '2', '5', '6' - }; - static const unsigned char ecdsa_384[] = { - 0, 0, 0, 0x13, 'e', 'c', 'd', 's', 'a', '-', 's', 'h', 'a', '2', '-', - 'n', 'i', 's', 't', 'p', '3', '8', '4' - }; - static const unsigned char ecdsa_521[] = { - 0, 0, 0, 0x13, 'e', 'c', 'd', 's', 'a', '-', 's', 'h', 'a', '2', '-', - 'n', 'i', 's', 't', 'p', '5', '2', '1' - }; - static const unsigned char ed25519[] = { - 0, 0, 0, 0x0b, 's', 's', 'h', '-', 'e', 'd', '2', '5', '5', '1', '9' - }; - - if(len < 11) - return LIBSSH2_HOSTKEY_TYPE_UNKNOWN; - - if(!memcmp(rsa, hostkey, 11)) - return LIBSSH2_HOSTKEY_TYPE_RSA; - - if(!memcmp(dss, hostkey, 11)) - return LIBSSH2_HOSTKEY_TYPE_DSS; - - if(len < 15) - return LIBSSH2_HOSTKEY_TYPE_UNKNOWN; - - if(!memcmp(ed25519, hostkey, 15)) - return LIBSSH2_HOSTKEY_TYPE_ED25519; - - if(len < 23) - return LIBSSH2_HOSTKEY_TYPE_UNKNOWN; - - if(!memcmp(ecdsa_256, hostkey, 23)) - return LIBSSH2_HOSTKEY_TYPE_ECDSA_256; - - if(!memcmp(ecdsa_384, hostkey, 23)) - return LIBSSH2_HOSTKEY_TYPE_ECDSA_384; - - if(!memcmp(ecdsa_521, hostkey, 23)) - return LIBSSH2_HOSTKEY_TYPE_ECDSA_521; - - return LIBSSH2_HOSTKEY_TYPE_UNKNOWN; -} - -/* - * libssh2_session_hostkey() - * - * Returns the server key and length. - * - */ -LIBSSH2_API const char * -libssh2_session_hostkey(LIBSSH2_SESSION *session, size_t *len, int *type) -{ - if(session->server_hostkey_len) { - if(len) - *len = session->server_hostkey_len; - if(type) - *type = hostkey_type(session->server_hostkey, - session->server_hostkey_len); - return (char *) session->server_hostkey; - } - if(len) - *len = 0; - return NULL; -} diff --git a/libssh2/keepalive.c b/libssh2/keepalive.c deleted file mode 100644 index 2151b17..0000000 --- a/libssh2/keepalive.c +++ /dev/null @@ -1,100 +0,0 @@ -/* Copyright (C) 2010 Simon Josefsson - * Author: Simon Josefsson - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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 "libssh2_priv.h" -#include "transport.h" /* _libssh2_transport_write */ - -/* Keep-alive stuff. */ - -LIBSSH2_API void -libssh2_keepalive_config (LIBSSH2_SESSION *session, - int want_reply, - unsigned interval) -{ - if(interval == 1) - session->keepalive_interval = 2; - else - session->keepalive_interval = interval; - session->keepalive_want_reply = want_reply ? 1 : 0; -} - -LIBSSH2_API int -libssh2_keepalive_send (LIBSSH2_SESSION *session, - int *seconds_to_next) -{ - time_t now; - - if(!session->keepalive_interval) { - if(seconds_to_next) - *seconds_to_next = 0; - return 0; - } - - now = time(NULL); - - if(session->keepalive_last_sent + session->keepalive_interval <= now) { - /* Format is - "SSH_MSG_GLOBAL_REQUEST || 4-byte len || str || want-reply". */ - unsigned char keepalive_data[] - = "\x50\x00\x00\x00\x15keepalive@libssh2.orgW"; - size_t len = sizeof(keepalive_data) - 1; - int rc; - - keepalive_data[len - 1] = - (unsigned char)session->keepalive_want_reply; - - rc = _libssh2_transport_send(session, keepalive_data, len, NULL, 0); - /* Silently ignore PACKET_EAGAIN here: if the write buffer is - already full, sending another keepalive is not useful. */ - if(rc && rc != LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send keepalive message"); - return rc; - } - - session->keepalive_last_sent = now; - if(seconds_to_next) - *seconds_to_next = session->keepalive_interval; - } - else if(seconds_to_next) { - *seconds_to_next = (int) (session->keepalive_last_sent - now) - + session->keepalive_interval; - } - - return 0; -} diff --git a/libssh2/kex.c b/libssh2/kex.c deleted file mode 100644 index b225a2f..0000000 --- a/libssh2/kex.c +++ /dev/null @@ -1,4453 +0,0 @@ -/* Copyright (c) 2004-2007, Sara Golemon - * Copyright (c) 2010-2019, Daniel Stenberg - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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 "libssh2_priv.h" - -#include "transport.h" -#include "comp.h" -#include "mac.h" - -/* TODO: Switch this to an inline and handle alloc() failures */ -/* Helper macro called from - kex_method_diffie_hellman_group1_sha1_key_exchange */ -#define LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(value, reqlen, version) \ - { \ - libssh2_sha1_ctx hash; \ - unsigned long len = 0; \ - if(!(value)) { \ - value = LIBSSH2_ALLOC(session, reqlen + SHA_DIGEST_LENGTH); \ - } \ - if(value) \ - while(len < (unsigned long)reqlen) { \ - libssh2_sha1_init(&hash); \ - libssh2_sha1_update(hash, exchange_state->k_value, \ - exchange_state->k_value_len); \ - libssh2_sha1_update(hash, exchange_state->h_sig_comp, \ - SHA_DIGEST_LENGTH); \ - if(len > 0) { \ - libssh2_sha1_update(hash, value, len); \ - } \ - else { \ - libssh2_sha1_update(hash, (version), 1); \ - libssh2_sha1_update(hash, session->session_id, \ - session->session_id_len); \ - } \ - libssh2_sha1_final(hash, (value) + len); \ - len += SHA_DIGEST_LENGTH; \ - } \ - } \ - - -#define LIBSSH2_KEX_METHOD_EC_SHA_VALUE_HASH(value, reqlen, version) \ - { \ - if(type == LIBSSH2_EC_CURVE_NISTP256) { \ - LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(256, value, reqlen, version); \ - } \ - else if(type == LIBSSH2_EC_CURVE_NISTP384) { \ - LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(384, value, reqlen, version); \ - } \ - else if(type == LIBSSH2_EC_CURVE_NISTP521) { \ - LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(512, value, reqlen, version); \ - } \ - } \ - - -#define LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(digest_type, value, \ - reqlen, version) \ -{ \ - libssh2_sha##digest_type##_ctx hash; \ - unsigned long len = 0; \ - if(!(value)) { \ - value = LIBSSH2_ALLOC(session, \ - reqlen + SHA##digest_type##_DIGEST_LENGTH); \ - } \ - if(value) \ - while(len < (unsigned long)reqlen) { \ - libssh2_sha##digest_type##_init(&hash); \ - libssh2_sha##digest_type##_update(hash, \ - exchange_state->k_value, \ - exchange_state->k_value_len); \ - libssh2_sha##digest_type##_update(hash, \ - exchange_state->h_sig_comp, \ - SHA##digest_type##_DIGEST_LENGTH); \ - if(len > 0) { \ - libssh2_sha##digest_type##_update(hash, value, len); \ - } \ - else { \ - libssh2_sha##digest_type##_update(hash, (version), 1); \ - libssh2_sha##digest_type##_update(hash, session->session_id, \ - session->session_id_len); \ - } \ - libssh2_sha##digest_type##_final(hash, (value) + len); \ - len += SHA##digest_type##_DIGEST_LENGTH; \ - } \ -} - - -/* - * diffie_hellman_sha1 - * - * Diffie Hellman Key Exchange, Group Agnostic - */ -static int diffie_hellman_sha1(LIBSSH2_SESSION *session, - _libssh2_bn *g, - _libssh2_bn *p, - int group_order, - unsigned char packet_type_init, - unsigned char packet_type_reply, - unsigned char *midhash, - unsigned long midhash_len, - kmdhgGPshakex_state_t *exchange_state) -{ - int ret = 0; - int rc; - libssh2_sha1_ctx exchange_hash_ctx; - - if(exchange_state->state == libssh2_NB_state_idle) { - /* Setup initial values */ - exchange_state->e_packet = NULL; - exchange_state->s_packet = NULL; - exchange_state->k_value = NULL; - exchange_state->ctx = _libssh2_bn_ctx_new(); - libssh2_dh_init(&exchange_state->x); - exchange_state->e = _libssh2_bn_init(); /* g^x mod p */ - exchange_state->f = _libssh2_bn_init_from_bin(); /* g^(Random from - server) mod p */ - exchange_state->k = _libssh2_bn_init(); /* The shared secret: f^x mod - p */ - - /* Zero the whole thing out */ - memset(&exchange_state->req_state, 0, sizeof(packet_require_state_t)); - - /* Generate x and e */ - rc = libssh2_dh_key_pair(&exchange_state->x, exchange_state->e, g, p, - group_order, exchange_state->ctx); - if(rc) - goto clean_exit; - - /* Send KEX init */ - /* packet_type(1) + String Length(4) + leading 0(1) */ - exchange_state->e_packet_len = - _libssh2_bn_bytes(exchange_state->e) + 6; - if(_libssh2_bn_bits(exchange_state->e) % 8) { - /* Leading 00 not needed */ - exchange_state->e_packet_len--; - } - - exchange_state->e_packet = - LIBSSH2_ALLOC(session, exchange_state->e_packet_len); - if(!exchange_state->e_packet) { - ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Out of memory error"); - goto clean_exit; - } - exchange_state->e_packet[0] = packet_type_init; - _libssh2_htonu32(exchange_state->e_packet + 1, - exchange_state->e_packet_len - 5); - if(_libssh2_bn_bits(exchange_state->e) % 8) { - _libssh2_bn_to_bin(exchange_state->e, - exchange_state->e_packet + 5); - } - else { - exchange_state->e_packet[5] = 0; - _libssh2_bn_to_bin(exchange_state->e, - exchange_state->e_packet + 6); - } - - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sending KEX packet %d", - (int) packet_type_init); - exchange_state->state = libssh2_NB_state_created; - } - - if(exchange_state->state == libssh2_NB_state_created) { - rc = _libssh2_transport_send(session, exchange_state->e_packet, - exchange_state->e_packet_len, - NULL, 0); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc) { - ret = _libssh2_error(session, rc, - "Unable to send KEX init message"); - goto clean_exit; - } - exchange_state->state = libssh2_NB_state_sent; - } - - if(exchange_state->state == libssh2_NB_state_sent) { - if(session->burn_optimistic_kexinit) { - /* The first KEX packet to come along will be the guess initially - * sent by the server. That guess turned out to be wrong so we - * need to silently ignore it */ - int burn_type; - - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Waiting for badly guessed KEX packet " - "(to be ignored)"); - burn_type = - _libssh2_packet_burn(session, &exchange_state->burn_state); - if(burn_type == LIBSSH2_ERROR_EAGAIN) { - return burn_type; - } - else if(burn_type <= 0) { - /* Failed to receive a packet */ - ret = burn_type; - goto clean_exit; - } - session->burn_optimistic_kexinit = 0; - - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Burnt packet of type: %02x", - (unsigned int) burn_type); - } - - exchange_state->state = libssh2_NB_state_sent1; - } - - if(exchange_state->state == libssh2_NB_state_sent1) { - /* Wait for KEX reply */ - struct string_buf buf; - size_t host_key_len; - - rc = _libssh2_packet_require(session, packet_type_reply, - &exchange_state->s_packet, - &exchange_state->s_packet_len, 0, NULL, - 0, &exchange_state->req_state); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - if(rc) { - ret = _libssh2_error(session, LIBSSH2_ERROR_TIMEOUT, - "Timed out waiting for KEX reply"); - goto clean_exit; - } - - /* Parse KEXDH_REPLY */ - if(exchange_state->s_packet_len < 5) { - ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unexpected packet length"); - goto clean_exit; - } - - buf.data = exchange_state->s_packet; - buf.len = exchange_state->s_packet_len; - buf.dataptr = buf.data; - buf.dataptr++; /* advance past type */ - - if(session->server_hostkey) - LIBSSH2_FREE(session, session->server_hostkey); - - if(_libssh2_copy_string(session, &buf, &(session->server_hostkey), - &host_key_len)) { - ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Could not copy host key"); - goto clean_exit; - } - - session->server_hostkey_len = (uint32_t)host_key_len; - -#if LIBSSH2_MD5 - { - libssh2_md5_ctx fingerprint_ctx; - - if(libssh2_md5_init(&fingerprint_ctx)) { - libssh2_md5_update(fingerprint_ctx, session->server_hostkey, - session->server_hostkey_len); - libssh2_md5_final(fingerprint_ctx, - session->server_hostkey_md5); - session->server_hostkey_md5_valid = TRUE; - } - else { - session->server_hostkey_md5_valid = FALSE; - } - } -#ifdef LIBSSH2DEBUG - { - char fingerprint[50], *fprint = fingerprint; - int i; - for(i = 0; i < 16; i++, fprint += 3) { - snprintf(fprint, 4, "%02x:", session->server_hostkey_md5[i]); - } - *(--fprint) = '\0'; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server's MD5 Fingerprint: %s", fingerprint); - } -#endif /* LIBSSH2DEBUG */ -#endif /* ! LIBSSH2_MD5 */ - - { - libssh2_sha1_ctx fingerprint_ctx; - - if(libssh2_sha1_init(&fingerprint_ctx)) { - libssh2_sha1_update(fingerprint_ctx, session->server_hostkey, - session->server_hostkey_len); - libssh2_sha1_final(fingerprint_ctx, - session->server_hostkey_sha1); - session->server_hostkey_sha1_valid = TRUE; - } - else { - session->server_hostkey_sha1_valid = FALSE; - } - } -#ifdef LIBSSH2DEBUG - { - char fingerprint[64], *fprint = fingerprint; - int i; - - for(i = 0; i < 20; i++, fprint += 3) { - snprintf(fprint, 4, "%02x:", session->server_hostkey_sha1[i]); - } - *(--fprint) = '\0'; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server's SHA1 Fingerprint: %s", fingerprint); - } -#endif /* LIBSSH2DEBUG */ - - { - libssh2_sha256_ctx fingerprint_ctx; - - if(libssh2_sha256_init(&fingerprint_ctx)) { - libssh2_sha256_update(fingerprint_ctx, session->server_hostkey, - session->server_hostkey_len); - libssh2_sha256_final(fingerprint_ctx, - session->server_hostkey_sha256); - session->server_hostkey_sha256_valid = TRUE; - } - else { - session->server_hostkey_sha256_valid = FALSE; - } - } -#ifdef LIBSSH2DEBUG - { - char *base64Fingerprint = NULL; - _libssh2_base64_encode(session, - (const char *) - session->server_hostkey_sha256, - SHA256_DIGEST_LENGTH, &base64Fingerprint); - if(base64Fingerprint != NULL) { - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server's SHA256 Fingerprint: %s", - base64Fingerprint); - LIBSSH2_FREE(session, base64Fingerprint); - } - } -#endif /* LIBSSH2DEBUG */ - - - if(session->hostkey->init(session, session->server_hostkey, - session->server_hostkey_len, - &session->server_hostkey_abstract)) { - ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT, - "Unable to initialize hostkey importer"); - goto clean_exit; - } - - if(_libssh2_get_string(&buf, &(exchange_state->f_value), - &(exchange_state->f_value_len))) { - ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT, - "Unable to get f value"); - goto clean_exit; - } - - _libssh2_bn_from_bin(exchange_state->f, exchange_state->f_value_len, - exchange_state->f_value); - - if(_libssh2_get_string(&buf, &(exchange_state->h_sig), - &(exchange_state->h_sig_len))) { - ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT, - "Unable to get h sig"); - goto clean_exit; - } - - /* Compute the shared secret */ - libssh2_dh_secret(&exchange_state->x, exchange_state->k, - exchange_state->f, p, exchange_state->ctx); - exchange_state->k_value_len = _libssh2_bn_bytes(exchange_state->k) + 5; - if(_libssh2_bn_bits(exchange_state->k) % 8) { - /* don't need leading 00 */ - exchange_state->k_value_len--; - } - exchange_state->k_value = - LIBSSH2_ALLOC(session, exchange_state->k_value_len); - if(!exchange_state->k_value) { - ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate buffer for K"); - goto clean_exit; - } - _libssh2_htonu32(exchange_state->k_value, - exchange_state->k_value_len - 4); - if(_libssh2_bn_bits(exchange_state->k) % 8) { - _libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 4); - } - else { - exchange_state->k_value[4] = 0; - _libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 5); - } - - exchange_state->exchange_hash = (void *)&exchange_hash_ctx; - libssh2_sha1_init(&exchange_hash_ctx); - - if(session->local.banner) { - _libssh2_htonu32(exchange_state->h_sig_comp, - strlen((char *) session->local.banner) - 2); - libssh2_sha1_update(exchange_hash_ctx, - exchange_state->h_sig_comp, 4); - libssh2_sha1_update(exchange_hash_ctx, - session->local.banner, - strlen((char *) session->local.banner) - 2); - } - else { - _libssh2_htonu32(exchange_state->h_sig_comp, - sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1); - libssh2_sha1_update(exchange_hash_ctx, - exchange_state->h_sig_comp, 4); - libssh2_sha1_update(exchange_hash_ctx, - (const unsigned char *) - LIBSSH2_SSH_DEFAULT_BANNER, - sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1); - } - - _libssh2_htonu32(exchange_state->h_sig_comp, - strlen((char *) session->remote.banner)); - libssh2_sha1_update(exchange_hash_ctx, - exchange_state->h_sig_comp, 4); - libssh2_sha1_update(exchange_hash_ctx, - session->remote.banner, - strlen((char *) session->remote.banner)); - - _libssh2_htonu32(exchange_state->h_sig_comp, - session->local.kexinit_len); - libssh2_sha1_update(exchange_hash_ctx, - exchange_state->h_sig_comp, 4); - libssh2_sha1_update(exchange_hash_ctx, - session->local.kexinit, - session->local.kexinit_len); - - _libssh2_htonu32(exchange_state->h_sig_comp, - session->remote.kexinit_len); - libssh2_sha1_update(exchange_hash_ctx, - exchange_state->h_sig_comp, 4); - libssh2_sha1_update(exchange_hash_ctx, - session->remote.kexinit, - session->remote.kexinit_len); - - _libssh2_htonu32(exchange_state->h_sig_comp, - session->server_hostkey_len); - libssh2_sha1_update(exchange_hash_ctx, - exchange_state->h_sig_comp, 4); - libssh2_sha1_update(exchange_hash_ctx, - session->server_hostkey, - session->server_hostkey_len); - - if(packet_type_init == SSH_MSG_KEX_DH_GEX_INIT) { - /* diffie-hellman-group-exchange hashes additional fields */ -#ifdef LIBSSH2_DH_GEX_NEW - _libssh2_htonu32(exchange_state->h_sig_comp, - LIBSSH2_DH_GEX_MINGROUP); - _libssh2_htonu32(exchange_state->h_sig_comp + 4, - LIBSSH2_DH_GEX_OPTGROUP); - _libssh2_htonu32(exchange_state->h_sig_comp + 8, - LIBSSH2_DH_GEX_MAXGROUP); - libssh2_sha1_update(exchange_hash_ctx, - exchange_state->h_sig_comp, 12); -#else - _libssh2_htonu32(exchange_state->h_sig_comp, - LIBSSH2_DH_GEX_OPTGROUP); - libssh2_sha1_update(exchange_hash_ctx, - exchange_state->h_sig_comp, 4); -#endif - } - - if(midhash) { - libssh2_sha1_update(exchange_hash_ctx, midhash, - midhash_len); - } - - libssh2_sha1_update(exchange_hash_ctx, - exchange_state->e_packet + 1, - exchange_state->e_packet_len - 1); - - _libssh2_htonu32(exchange_state->h_sig_comp, - exchange_state->f_value_len); - libssh2_sha1_update(exchange_hash_ctx, - exchange_state->h_sig_comp, 4); - libssh2_sha1_update(exchange_hash_ctx, - exchange_state->f_value, - exchange_state->f_value_len); - - libssh2_sha1_update(exchange_hash_ctx, - exchange_state->k_value, - exchange_state->k_value_len); - - libssh2_sha1_final(exchange_hash_ctx, - exchange_state->h_sig_comp); - - if(session->hostkey-> - sig_verify(session, exchange_state->h_sig, - exchange_state->h_sig_len, exchange_state->h_sig_comp, - 20, &session->server_hostkey_abstract)) { - ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_SIGN, - "Unable to verify hostkey signature"); - goto clean_exit; - } - - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sending NEWKEYS message"); - exchange_state->c = SSH_MSG_NEWKEYS; - - exchange_state->state = libssh2_NB_state_sent2; - } - - if(exchange_state->state == libssh2_NB_state_sent2) { - rc = _libssh2_transport_send(session, &exchange_state->c, 1, NULL, 0); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc) { - ret = _libssh2_error(session, rc, - "Unable to send NEWKEYS message"); - goto clean_exit; - } - - exchange_state->state = libssh2_NB_state_sent3; - } - - if(exchange_state->state == libssh2_NB_state_sent3) { - rc = _libssh2_packet_require(session, SSH_MSG_NEWKEYS, - &exchange_state->tmp, - &exchange_state->tmp_len, 0, NULL, 0, - &exchange_state->req_state); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc) { - ret = _libssh2_error(session, rc, "Timed out waiting for NEWKEYS"); - goto clean_exit; - } - /* The first key exchange has been performed, - switch to active crypt/comp/mac mode */ - session->state |= LIBSSH2_STATE_NEWKEYS; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Received NEWKEYS message"); - - /* This will actually end up being just packet_type(1) - for this packet type anyway */ - LIBSSH2_FREE(session, exchange_state->tmp); - - if(!session->session_id) { - session->session_id = LIBSSH2_ALLOC(session, SHA_DIGEST_LENGTH); - if(!session->session_id) { - ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate buffer for " - "SHA digest"); - goto clean_exit; - } - memcpy(session->session_id, exchange_state->h_sig_comp, - SHA_DIGEST_LENGTH); - session->session_id_len = SHA_DIGEST_LENGTH; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "session_id calculated"); - } - - /* Cleanup any existing cipher */ - if(session->local.crypt->dtor) { - session->local.crypt->dtor(session, - &session->local.crypt_abstract); - } - - /* Calculate IV/Secret/Key for each direction */ - if(session->local.crypt->init) { - unsigned char *iv = NULL, *secret = NULL; - int free_iv = 0, free_secret = 0; - - LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(iv, - session->local.crypt-> - iv_len, - (const unsigned char *) - "A"); - if(!iv) { - ret = -1; - goto clean_exit; - } - LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(secret, - session->local.crypt-> - secret_len, - (const unsigned char *) - "C"); - if(!secret) { - LIBSSH2_FREE(session, iv); - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - if(session->local.crypt-> - init(session, session->local.crypt, iv, &free_iv, secret, - &free_secret, 1, &session->local.crypt_abstract)) { - LIBSSH2_FREE(session, iv); - LIBSSH2_FREE(session, secret); - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - - if(free_iv) { - _libssh2_explicit_zero(iv, session->local.crypt->iv_len); - LIBSSH2_FREE(session, iv); - } - - if(free_secret) { - _libssh2_explicit_zero(secret, - session->local.crypt->secret_len); - LIBSSH2_FREE(session, secret); - } - } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Client to Server IV and Key calculated"); - - if(session->remote.crypt->dtor) { - /* Cleanup any existing cipher */ - session->remote.crypt->dtor(session, - &session->remote.crypt_abstract); - } - - if(session->remote.crypt->init) { - unsigned char *iv = NULL, *secret = NULL; - int free_iv = 0, free_secret = 0; - - LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(iv, - session->remote.crypt-> - iv_len, - (const unsigned char *) - "B"); - if(!iv) { - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(secret, - session->remote.crypt-> - secret_len, - (const unsigned char *) - "D"); - if(!secret) { - LIBSSH2_FREE(session, iv); - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - if(session->remote.crypt-> - init(session, session->remote.crypt, iv, &free_iv, secret, - &free_secret, 0, &session->remote.crypt_abstract)) { - LIBSSH2_FREE(session, iv); - LIBSSH2_FREE(session, secret); - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - - if(free_iv) { - _libssh2_explicit_zero(iv, session->remote.crypt->iv_len); - LIBSSH2_FREE(session, iv); - } - - if(free_secret) { - _libssh2_explicit_zero(secret, - session->remote.crypt->secret_len); - LIBSSH2_FREE(session, secret); - } - } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server to Client IV and Key calculated"); - - if(session->local.mac->dtor) { - session->local.mac->dtor(session, &session->local.mac_abstract); - } - - if(session->local.mac->init) { - unsigned char *key = NULL; - int free_key = 0; - - LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(key, - session->local.mac-> - key_len, - (const unsigned char *) - "E"); - if(!key) { - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - session->local.mac->init(session, key, &free_key, - &session->local.mac_abstract); - - if(free_key) { - _libssh2_explicit_zero(key, session->local.mac->key_len); - LIBSSH2_FREE(session, key); - } - } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Client to Server HMAC Key calculated"); - - if(session->remote.mac->dtor) { - session->remote.mac->dtor(session, &session->remote.mac_abstract); - } - - if(session->remote.mac->init) { - unsigned char *key = NULL; - int free_key = 0; - - LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(key, - session->remote.mac-> - key_len, - (const unsigned char *) - "F"); - if(!key) { - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - session->remote.mac->init(session, key, &free_key, - &session->remote.mac_abstract); - - if(free_key) { - _libssh2_explicit_zero(key, session->remote.mac->key_len); - LIBSSH2_FREE(session, key); - } - } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server to Client HMAC Key calculated"); - - /* Initialize compression for each direction */ - - /* Cleanup any existing compression */ - if(session->local.comp && session->local.comp->dtor) { - session->local.comp->dtor(session, 1, - &session->local.comp_abstract); - } - - if(session->local.comp && session->local.comp->init) { - if(session->local.comp->init(session, 1, - &session->local.comp_abstract)) { - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Client to Server compression initialized"); - - if(session->remote.comp && session->remote.comp->dtor) { - session->remote.comp->dtor(session, 0, - &session->remote.comp_abstract); - } - - if(session->remote.comp && session->remote.comp->init) { - if(session->remote.comp->init(session, 0, - &session->remote.comp_abstract)) { - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server to Client compression initialized"); - - } - - clean_exit: - libssh2_dh_dtor(&exchange_state->x); - _libssh2_bn_free(exchange_state->e); - exchange_state->e = NULL; - _libssh2_bn_free(exchange_state->f); - exchange_state->f = NULL; - _libssh2_bn_free(exchange_state->k); - exchange_state->k = NULL; - _libssh2_bn_ctx_free(exchange_state->ctx); - exchange_state->ctx = NULL; - - if(exchange_state->e_packet) { - LIBSSH2_FREE(session, exchange_state->e_packet); - exchange_state->e_packet = NULL; - } - - if(exchange_state->s_packet) { - LIBSSH2_FREE(session, exchange_state->s_packet); - exchange_state->s_packet = NULL; - } - - if(exchange_state->k_value) { - LIBSSH2_FREE(session, exchange_state->k_value); - exchange_state->k_value = NULL; - } - - exchange_state->state = libssh2_NB_state_idle; - - return ret; -} - - -/* - * diffie_hellman_sha256 - * - * Diffie Hellman Key Exchange, Group Agnostic - */ -static int diffie_hellman_sha256(LIBSSH2_SESSION *session, - _libssh2_bn *g, - _libssh2_bn *p, - int group_order, - unsigned char packet_type_init, - unsigned char packet_type_reply, - unsigned char *midhash, - unsigned long midhash_len, - kmdhgGPshakex_state_t *exchange_state) -{ - int ret = 0; - int rc; - libssh2_sha256_ctx exchange_hash_ctx; - - if(exchange_state->state == libssh2_NB_state_idle) { - /* Setup initial values */ - exchange_state->e_packet = NULL; - exchange_state->s_packet = NULL; - exchange_state->k_value = NULL; - exchange_state->ctx = _libssh2_bn_ctx_new(); - libssh2_dh_init(&exchange_state->x); - exchange_state->e = _libssh2_bn_init(); /* g^x mod p */ - exchange_state->f = _libssh2_bn_init_from_bin(); /* g^(Random from - server) mod p */ - exchange_state->k = _libssh2_bn_init(); /* The shared secret: f^x mod - p */ - - /* Zero the whole thing out */ - memset(&exchange_state->req_state, 0, sizeof(packet_require_state_t)); - - /* Generate x and e */ - rc = libssh2_dh_key_pair(&exchange_state->x, exchange_state->e, g, p, - group_order, exchange_state->ctx); - if(rc) - goto clean_exit; - - /* Send KEX init */ - /* packet_type(1) + String Length(4) + leading 0(1) */ - exchange_state->e_packet_len = - _libssh2_bn_bytes(exchange_state->e) + 6; - if(_libssh2_bn_bits(exchange_state->e) % 8) { - /* Leading 00 not needed */ - exchange_state->e_packet_len--; - } - - exchange_state->e_packet = - LIBSSH2_ALLOC(session, exchange_state->e_packet_len); - if(!exchange_state->e_packet) { - ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Out of memory error"); - goto clean_exit; - } - exchange_state->e_packet[0] = packet_type_init; - _libssh2_htonu32(exchange_state->e_packet + 1, - exchange_state->e_packet_len - 5); - if(_libssh2_bn_bits(exchange_state->e) % 8) { - _libssh2_bn_to_bin(exchange_state->e, - exchange_state->e_packet + 5); - } - else { - exchange_state->e_packet[5] = 0; - _libssh2_bn_to_bin(exchange_state->e, - exchange_state->e_packet + 6); - } - - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sending KEX packet %d", - (int) packet_type_init); - exchange_state->state = libssh2_NB_state_created; - } - - if(exchange_state->state == libssh2_NB_state_created) { - rc = _libssh2_transport_send(session, exchange_state->e_packet, - exchange_state->e_packet_len, - NULL, 0); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc) { - ret = _libssh2_error(session, rc, - "Unable to send KEX init message"); - goto clean_exit; - } - exchange_state->state = libssh2_NB_state_sent; - } - - if(exchange_state->state == libssh2_NB_state_sent) { - if(session->burn_optimistic_kexinit) { - /* The first KEX packet to come along will be the guess initially - * sent by the server. That guess turned out to be wrong so we - * need to silently ignore it */ - int burn_type; - - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Waiting for badly guessed KEX packet " - "(to be ignored)"); - burn_type = - _libssh2_packet_burn(session, &exchange_state->burn_state); - if(burn_type == LIBSSH2_ERROR_EAGAIN) { - return burn_type; - } - else if(burn_type <= 0) { - /* Failed to receive a packet */ - ret = burn_type; - goto clean_exit; - } - session->burn_optimistic_kexinit = 0; - - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Burnt packet of type: %02x", - (unsigned int) burn_type); - } - - exchange_state->state = libssh2_NB_state_sent1; - } - - if(exchange_state->state == libssh2_NB_state_sent1) { - /* Wait for KEX reply */ - struct string_buf buf; - size_t host_key_len; - - rc = _libssh2_packet_require(session, packet_type_reply, - &exchange_state->s_packet, - &exchange_state->s_packet_len, 0, NULL, - 0, &exchange_state->req_state); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - if(rc) { - ret = _libssh2_error(session, LIBSSH2_ERROR_TIMEOUT, - "Timed out waiting for KEX reply"); - goto clean_exit; - } - - /* Parse KEXDH_REPLY */ - if(exchange_state->s_packet_len < 5) { - ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unexpected packet length"); - goto clean_exit; - } - - buf.data = exchange_state->s_packet; - buf.len = exchange_state->s_packet_len; - buf.dataptr = buf.data; - buf.dataptr++; /* advance past type */ - - if(session->server_hostkey) - LIBSSH2_FREE(session, session->server_hostkey); - - if(_libssh2_copy_string(session, &buf, &(session->server_hostkey), - &host_key_len)) { - ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Could not copy host key"); - goto clean_exit; - } - - session->server_hostkey_len = (uint32_t)host_key_len; - -#if LIBSSH2_MD5 - { - libssh2_md5_ctx fingerprint_ctx; - - if(libssh2_md5_init(&fingerprint_ctx)) { - libssh2_md5_update(fingerprint_ctx, session->server_hostkey, - session->server_hostkey_len); - libssh2_md5_final(fingerprint_ctx, - session->server_hostkey_md5); - session->server_hostkey_md5_valid = TRUE; - } - else { - session->server_hostkey_md5_valid = FALSE; - } - } -#ifdef LIBSSH2DEBUG - { - char fingerprint[50], *fprint = fingerprint; - int i; - for(i = 0; i < 16; i++, fprint += 3) { - snprintf(fprint, 4, "%02x:", session->server_hostkey_md5[i]); - } - *(--fprint) = '\0'; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server's MD5 Fingerprint: %s", fingerprint); - } -#endif /* LIBSSH2DEBUG */ -#endif /* ! LIBSSH2_MD5 */ - - { - libssh2_sha1_ctx fingerprint_ctx; - - if(libssh2_sha1_init(&fingerprint_ctx)) { - libssh2_sha1_update(fingerprint_ctx, session->server_hostkey, - session->server_hostkey_len); - libssh2_sha1_final(fingerprint_ctx, - session->server_hostkey_sha1); - session->server_hostkey_sha1_valid = TRUE; - } - else { - session->server_hostkey_sha1_valid = FALSE; - } - } -#ifdef LIBSSH2DEBUG - { - char fingerprint[64], *fprint = fingerprint; - int i; - - for(i = 0; i < 20; i++, fprint += 3) { - snprintf(fprint, 4, "%02x:", session->server_hostkey_sha1[i]); - } - *(--fprint) = '\0'; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server's SHA1 Fingerprint: %s", fingerprint); - } -#endif /* LIBSSH2DEBUG */ - - { - libssh2_sha256_ctx fingerprint_ctx; - - if(libssh2_sha256_init(&fingerprint_ctx)) { - libssh2_sha256_update(fingerprint_ctx, session->server_hostkey, - session->server_hostkey_len); - libssh2_sha256_final(fingerprint_ctx, - session->server_hostkey_sha256); - session->server_hostkey_sha256_valid = TRUE; - } - else { - session->server_hostkey_sha256_valid = FALSE; - } - } -#ifdef LIBSSH2DEBUG - { - char *base64Fingerprint = NULL; - _libssh2_base64_encode(session, - (const char *) - session->server_hostkey_sha256, - SHA256_DIGEST_LENGTH, &base64Fingerprint); - if(base64Fingerprint != NULL) { - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server's SHA256 Fingerprint: %s", - base64Fingerprint); - LIBSSH2_FREE(session, base64Fingerprint); - } - } -#endif /* LIBSSH2DEBUG */ - - if(session->hostkey->init(session, session->server_hostkey, - session->server_hostkey_len, - &session->server_hostkey_abstract)) { - ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT, - "Unable to initialize hostkey importer"); - goto clean_exit; - } - - if(_libssh2_get_string(&buf, &(exchange_state->f_value), - &(exchange_state->f_value_len))) { - ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT, - "Unable to get f value"); - goto clean_exit; - } - - _libssh2_bn_from_bin(exchange_state->f, exchange_state->f_value_len, - exchange_state->f_value); - - if(_libssh2_get_string(&buf, &(exchange_state->h_sig), - &(exchange_state->h_sig_len))) { - ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT, - "Unable to get h sig"); - goto clean_exit; - } - - /* Compute the shared secret */ - libssh2_dh_secret(&exchange_state->x, exchange_state->k, - exchange_state->f, p, exchange_state->ctx); - exchange_state->k_value_len = _libssh2_bn_bytes(exchange_state->k) + 5; - if(_libssh2_bn_bits(exchange_state->k) % 8) { - /* don't need leading 00 */ - exchange_state->k_value_len--; - } - exchange_state->k_value = - LIBSSH2_ALLOC(session, exchange_state->k_value_len); - if(!exchange_state->k_value) { - ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate buffer for K"); - goto clean_exit; - } - _libssh2_htonu32(exchange_state->k_value, - exchange_state->k_value_len - 4); - if(_libssh2_bn_bits(exchange_state->k) % 8) { - _libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 4); - } - else { - exchange_state->k_value[4] = 0; - _libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 5); - } - - exchange_state->exchange_hash = (void *)&exchange_hash_ctx; - libssh2_sha256_init(&exchange_hash_ctx); - - if(session->local.banner) { - _libssh2_htonu32(exchange_state->h_sig_comp, - strlen((char *) session->local.banner) - 2); - libssh2_sha256_update(exchange_hash_ctx, - exchange_state->h_sig_comp, 4); - libssh2_sha256_update(exchange_hash_ctx, - session->local.banner, - strlen((char *) session->local.banner) - 2); - } - else { - _libssh2_htonu32(exchange_state->h_sig_comp, - sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1); - libssh2_sha256_update(exchange_hash_ctx, - exchange_state->h_sig_comp, 4); - libssh2_sha256_update(exchange_hash_ctx, - (const unsigned char *) - LIBSSH2_SSH_DEFAULT_BANNER, - sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1); - } - - _libssh2_htonu32(exchange_state->h_sig_comp, - strlen((char *) session->remote.banner)); - libssh2_sha256_update(exchange_hash_ctx, - exchange_state->h_sig_comp, 4); - libssh2_sha256_update(exchange_hash_ctx, - session->remote.banner, - strlen((char *) session->remote.banner)); - - _libssh2_htonu32(exchange_state->h_sig_comp, - session->local.kexinit_len); - libssh2_sha256_update(exchange_hash_ctx, - exchange_state->h_sig_comp, 4); - libssh2_sha256_update(exchange_hash_ctx, - session->local.kexinit, - session->local.kexinit_len); - - _libssh2_htonu32(exchange_state->h_sig_comp, - session->remote.kexinit_len); - libssh2_sha256_update(exchange_hash_ctx, - exchange_state->h_sig_comp, 4); - libssh2_sha256_update(exchange_hash_ctx, - session->remote.kexinit, - session->remote.kexinit_len); - - _libssh2_htonu32(exchange_state->h_sig_comp, - session->server_hostkey_len); - libssh2_sha256_update(exchange_hash_ctx, - exchange_state->h_sig_comp, 4); - libssh2_sha256_update(exchange_hash_ctx, - session->server_hostkey, - session->server_hostkey_len); - - if(packet_type_init == SSH_MSG_KEX_DH_GEX_INIT) { - /* diffie-hellman-group-exchange hashes additional fields */ -#ifdef LIBSSH2_DH_GEX_NEW - _libssh2_htonu32(exchange_state->h_sig_comp, - LIBSSH2_DH_GEX_MINGROUP); - _libssh2_htonu32(exchange_state->h_sig_comp + 4, - LIBSSH2_DH_GEX_OPTGROUP); - _libssh2_htonu32(exchange_state->h_sig_comp + 8, - LIBSSH2_DH_GEX_MAXGROUP); - libssh2_sha256_update(exchange_hash_ctx, - exchange_state->h_sig_comp, 12); -#else - _libssh2_htonu32(exchange_state->h_sig_comp, - LIBSSH2_DH_GEX_OPTGROUP); - libssh2_sha256_update(exchange_hash_ctx, - exchange_state->h_sig_comp, 4); -#endif - } - - if(midhash) { - libssh2_sha256_update(exchange_hash_ctx, midhash, - midhash_len); - } - - libssh2_sha256_update(exchange_hash_ctx, - exchange_state->e_packet + 1, - exchange_state->e_packet_len - 1); - - _libssh2_htonu32(exchange_state->h_sig_comp, - exchange_state->f_value_len); - libssh2_sha256_update(exchange_hash_ctx, - exchange_state->h_sig_comp, 4); - libssh2_sha256_update(exchange_hash_ctx, - exchange_state->f_value, - exchange_state->f_value_len); - - libssh2_sha256_update(exchange_hash_ctx, - exchange_state->k_value, - exchange_state->k_value_len); - - libssh2_sha256_final(exchange_hash_ctx, - exchange_state->h_sig_comp); - - if(session->hostkey-> - sig_verify(session, exchange_state->h_sig, - exchange_state->h_sig_len, exchange_state->h_sig_comp, - SHA256_DIGEST_LENGTH, - &session->server_hostkey_abstract)) { - ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_SIGN, - "Unable to verify hostkey signature"); - goto clean_exit; - } - - - - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sending NEWKEYS message"); - exchange_state->c = SSH_MSG_NEWKEYS; - - exchange_state->state = libssh2_NB_state_sent2; - } - - if(exchange_state->state == libssh2_NB_state_sent2) { - rc = _libssh2_transport_send(session, &exchange_state->c, 1, NULL, 0); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc) { - ret = _libssh2_error(session, rc, - "Unable to send NEWKEYS message"); - goto clean_exit; - } - - exchange_state->state = libssh2_NB_state_sent3; - } - - if(exchange_state->state == libssh2_NB_state_sent3) { - rc = _libssh2_packet_require(session, SSH_MSG_NEWKEYS, - &exchange_state->tmp, - &exchange_state->tmp_len, 0, NULL, 0, - &exchange_state->req_state); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc) { - ret = _libssh2_error(session, rc, "Timed out waiting for NEWKEYS"); - goto clean_exit; - } - /* The first key exchange has been performed, - switch to active crypt/comp/mac mode */ - session->state |= LIBSSH2_STATE_NEWKEYS; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Received NEWKEYS message"); - - /* This will actually end up being just packet_type(1) - for this packet type anyway */ - LIBSSH2_FREE(session, exchange_state->tmp); - - if(!session->session_id) { - session->session_id = LIBSSH2_ALLOC(session, SHA256_DIGEST_LENGTH); - if(!session->session_id) { - ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate buffer for " - "SHA digest"); - goto clean_exit; - } - memcpy(session->session_id, exchange_state->h_sig_comp, - SHA256_DIGEST_LENGTH); - session->session_id_len = SHA256_DIGEST_LENGTH; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "session_id calculated"); - } - - /* Cleanup any existing cipher */ - if(session->local.crypt->dtor) { - session->local.crypt->dtor(session, - &session->local.crypt_abstract); - } - - /* Calculate IV/Secret/Key for each direction */ - if(session->local.crypt->init) { - unsigned char *iv = NULL, *secret = NULL; - int free_iv = 0, free_secret = 0; - - LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(256, iv, - session->local.crypt-> - iv_len, - (const unsigned char *)"A"); - if(!iv) { - ret = -1; - goto clean_exit; - } - LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(256, secret, - session->local.crypt-> - secret_len, - (const unsigned char *)"C"); - if(!secret) { - LIBSSH2_FREE(session, iv); - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - if(session->local.crypt-> - init(session, session->local.crypt, iv, &free_iv, secret, - &free_secret, 1, &session->local.crypt_abstract)) { - LIBSSH2_FREE(session, iv); - LIBSSH2_FREE(session, secret); - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - - if(free_iv) { - _libssh2_explicit_zero(iv, session->local.crypt->iv_len); - LIBSSH2_FREE(session, iv); - } - - if(free_secret) { - _libssh2_explicit_zero(secret, - session->local.crypt->secret_len); - LIBSSH2_FREE(session, secret); - } - } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Client to Server IV and Key calculated"); - - if(session->remote.crypt->dtor) { - /* Cleanup any existing cipher */ - session->remote.crypt->dtor(session, - &session->remote.crypt_abstract); - } - - if(session->remote.crypt->init) { - unsigned char *iv = NULL, *secret = NULL; - int free_iv = 0, free_secret = 0; - - LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(256, iv, - session->remote.crypt-> - iv_len, - (const unsigned char *)"B"); - if(!iv) { - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(256, secret, - session->remote.crypt-> - secret_len, - (const unsigned char *)"D"); - if(!secret) { - LIBSSH2_FREE(session, iv); - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - if(session->remote.crypt-> - init(session, session->remote.crypt, iv, &free_iv, secret, - &free_secret, 0, &session->remote.crypt_abstract)) { - LIBSSH2_FREE(session, iv); - LIBSSH2_FREE(session, secret); - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - - if(free_iv) { - _libssh2_explicit_zero(iv, session->remote.crypt->iv_len); - LIBSSH2_FREE(session, iv); - } - - if(free_secret) { - _libssh2_explicit_zero(secret, - session->remote.crypt->secret_len); - LIBSSH2_FREE(session, secret); - } - } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server to Client IV and Key calculated"); - - if(session->local.mac->dtor) { - session->local.mac->dtor(session, &session->local.mac_abstract); - } - - if(session->local.mac->init) { - unsigned char *key = NULL; - int free_key = 0; - - LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(256, key, - session->local.mac-> - key_len, - (const unsigned char *)"E"); - if(!key) { - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - session->local.mac->init(session, key, &free_key, - &session->local.mac_abstract); - - if(free_key) { - _libssh2_explicit_zero(key, session->local.mac->key_len); - LIBSSH2_FREE(session, key); - } - } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Client to Server HMAC Key calculated"); - - if(session->remote.mac->dtor) { - session->remote.mac->dtor(session, &session->remote.mac_abstract); - } - - if(session->remote.mac->init) { - unsigned char *key = NULL; - int free_key = 0; - - LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(256, key, - session->remote.mac-> - key_len, - (const unsigned char *)"F"); - if(!key) { - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - session->remote.mac->init(session, key, &free_key, - &session->remote.mac_abstract); - - if(free_key) { - _libssh2_explicit_zero(key, session->remote.mac->key_len); - LIBSSH2_FREE(session, key); - } - } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server to Client HMAC Key calculated"); - - /* Initialize compression for each direction */ - - /* Cleanup any existing compression */ - if(session->local.comp && session->local.comp->dtor) { - session->local.comp->dtor(session, 1, - &session->local.comp_abstract); - } - - if(session->local.comp && session->local.comp->init) { - if(session->local.comp->init(session, 1, - &session->local.comp_abstract)) { - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Client to Server compression initialized"); - - if(session->remote.comp && session->remote.comp->dtor) { - session->remote.comp->dtor(session, 0, - &session->remote.comp_abstract); - } - - if(session->remote.comp && session->remote.comp->init) { - if(session->remote.comp->init(session, 0, - &session->remote.comp_abstract)) { - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server to Client compression initialized"); - - } - - clean_exit: - libssh2_dh_dtor(&exchange_state->x); - _libssh2_bn_free(exchange_state->e); - exchange_state->e = NULL; - _libssh2_bn_free(exchange_state->f); - exchange_state->f = NULL; - _libssh2_bn_free(exchange_state->k); - exchange_state->k = NULL; - _libssh2_bn_ctx_free(exchange_state->ctx); - exchange_state->ctx = NULL; - - if(exchange_state->e_packet) { - LIBSSH2_FREE(session, exchange_state->e_packet); - exchange_state->e_packet = NULL; - } - - if(exchange_state->s_packet) { - LIBSSH2_FREE(session, exchange_state->s_packet); - exchange_state->s_packet = NULL; - } - - if(exchange_state->k_value) { - LIBSSH2_FREE(session, exchange_state->k_value); - exchange_state->k_value = NULL; - } - - exchange_state->state = libssh2_NB_state_idle; - - return ret; -} - - - -/* kex_method_diffie_hellman_group1_sha1_key_exchange - * Diffie-Hellman Group1 (Actually Group2) Key Exchange using SHA1 - */ -static int -kex_method_diffie_hellman_group1_sha1_key_exchange(LIBSSH2_SESSION *session, - key_exchange_state_low_t - * key_state) -{ - static const unsigned char p_value[128] = { - 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 - }; - - int ret; - - if(key_state->state == libssh2_NB_state_idle) { - /* g == 2 */ - key_state->p = _libssh2_bn_init_from_bin(); /* SSH2 defined value - (p_value) */ - key_state->g = _libssh2_bn_init(); /* SSH2 defined value (2) */ - - /* Initialize P and G */ - _libssh2_bn_set_word(key_state->g, 2); - _libssh2_bn_from_bin(key_state->p, 128, p_value); - - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Initiating Diffie-Hellman Group1 Key Exchange"); - - key_state->state = libssh2_NB_state_created; - } - ret = diffie_hellman_sha1(session, key_state->g, key_state->p, 128, - SSH_MSG_KEXDH_INIT, SSH_MSG_KEXDH_REPLY, - NULL, 0, &key_state->exchange_state); - if(ret == LIBSSH2_ERROR_EAGAIN) { - return ret; - } - - _libssh2_bn_free(key_state->p); - key_state->p = NULL; - _libssh2_bn_free(key_state->g); - key_state->g = NULL; - key_state->state = libssh2_NB_state_idle; - - return ret; -} - - - -/* kex_method_diffie_hellman_group14_key_exchange - * Diffie-Hellman Group14 Key Exchange with hash function callback - */ -typedef int (*diffie_hellman_hash_func_t)(LIBSSH2_SESSION *, - _libssh2_bn *, - _libssh2_bn *, - int, - unsigned char, - unsigned char, - unsigned char *, - unsigned long, - kmdhgGPshakex_state_t *); -static int -kex_method_diffie_hellman_group14_key_exchange(LIBSSH2_SESSION *session, - key_exchange_state_low_t - * key_state, - diffie_hellman_hash_func_t - hashfunc) -{ - static const unsigned char p_value[256] = { - 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, 0xE4, 0x5B, 0x3D, - 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, - 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, - 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, - 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, - 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, - 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, - 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, - 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, - 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, - 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, - 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, - 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, - 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, - 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, - 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, - 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF - }; - int ret; - - if(key_state->state == libssh2_NB_state_idle) { - key_state->p = _libssh2_bn_init_from_bin(); /* SSH2 defined value - (p_value) */ - key_state->g = _libssh2_bn_init(); /* SSH2 defined value (2) */ - - /* g == 2 */ - /* Initialize P and G */ - _libssh2_bn_set_word(key_state->g, 2); - _libssh2_bn_from_bin(key_state->p, 256, p_value); - - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Initiating Diffie-Hellman Group14 Key Exchange"); - - key_state->state = libssh2_NB_state_created; - } - ret = hashfunc(session, key_state->g, key_state->p, - 256, SSH_MSG_KEXDH_INIT, SSH_MSG_KEXDH_REPLY, - NULL, 0, &key_state->exchange_state); - if(ret == LIBSSH2_ERROR_EAGAIN) { - return ret; - } - - key_state->state = libssh2_NB_state_idle; - _libssh2_bn_free(key_state->p); - key_state->p = NULL; - _libssh2_bn_free(key_state->g); - key_state->g = NULL; - - return ret; -} - - - -/* kex_method_diffie_hellman_group14_sha1_key_exchange - * Diffie-Hellman Group14 Key Exchange using SHA1 - */ -static int -kex_method_diffie_hellman_group14_sha1_key_exchange(LIBSSH2_SESSION *session, - key_exchange_state_low_t - * key_state) -{ - return kex_method_diffie_hellman_group14_key_exchange(session, key_state, - diffie_hellman_sha1); -} - - - -/* kex_method_diffie_hellman_group14_sha256_key_exchange - * Diffie-Hellman Group14 Key Exchange using SHA256 - */ -static int -kex_method_diffie_hellman_group14_sha256_key_exchange(LIBSSH2_SESSION *session, - key_exchange_state_low_t - * key_state) -{ - return kex_method_diffie_hellman_group14_key_exchange(session, key_state, - diffie_hellman_sha256); -} - - - -/* kex_method_diffie_hellman_group_exchange_sha1_key_exchange - * Diffie-Hellman Group Exchange Key Exchange using SHA1 - * Negotiates random(ish) group for secret derivation - */ -static int -kex_method_diffie_hellman_group_exchange_sha1_key_exchange -(LIBSSH2_SESSION * session, key_exchange_state_low_t * key_state) -{ - int ret = 0; - int rc; - - if(key_state->state == libssh2_NB_state_idle) { - key_state->p = _libssh2_bn_init_from_bin(); - key_state->g = _libssh2_bn_init_from_bin(); - /* Ask for a P and G pair */ -#ifdef LIBSSH2_DH_GEX_NEW - key_state->request[0] = SSH_MSG_KEX_DH_GEX_REQUEST; - _libssh2_htonu32(key_state->request + 1, LIBSSH2_DH_GEX_MINGROUP); - _libssh2_htonu32(key_state->request + 5, LIBSSH2_DH_GEX_OPTGROUP); - _libssh2_htonu32(key_state->request + 9, LIBSSH2_DH_GEX_MAXGROUP); - key_state->request_len = 13; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Initiating Diffie-Hellman Group-Exchange " - "(New Method)"); -#else - key_state->request[0] = SSH_MSG_KEX_DH_GEX_REQUEST_OLD; - _libssh2_htonu32(key_state->request + 1, LIBSSH2_DH_GEX_OPTGROUP); - key_state->request_len = 5; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Initiating Diffie-Hellman Group-Exchange " - "(Old Method)"); -#endif - - key_state->state = libssh2_NB_state_created; - } - - if(key_state->state == libssh2_NB_state_created) { - rc = _libssh2_transport_send(session, key_state->request, - key_state->request_len, NULL, 0); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc) { - ret = _libssh2_error(session, rc, - "Unable to send Group Exchange Request"); - goto dh_gex_clean_exit; - } - - key_state->state = libssh2_NB_state_sent; - } - - if(key_state->state == libssh2_NB_state_sent) { - rc = _libssh2_packet_require(session, SSH_MSG_KEX_DH_GEX_GROUP, - &key_state->data, &key_state->data_len, - 0, NULL, 0, &key_state->req_state); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc) { - ret = _libssh2_error(session, rc, - "Timeout waiting for GEX_GROUP reply"); - goto dh_gex_clean_exit; - } - - key_state->state = libssh2_NB_state_sent1; - } - - if(key_state->state == libssh2_NB_state_sent1) { - size_t p_len, g_len; - unsigned char *p, *g; - struct string_buf buf; - - if(key_state->data_len < 9) { - ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unexpected key length"); - goto dh_gex_clean_exit; - } - - buf.data = key_state->data; - buf.dataptr = buf.data; - buf.len = key_state->data_len; - - buf.dataptr++; /* increment to big num */ - - if(_libssh2_get_bignum_bytes(&buf, &p, &p_len)) { - ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unexpected value"); - goto dh_gex_clean_exit; - } - - if(_libssh2_get_bignum_bytes(&buf, &g, &g_len)) { - ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unexpected value"); - goto dh_gex_clean_exit; - } - - _libssh2_bn_from_bin(key_state->p, p_len, p); - _libssh2_bn_from_bin(key_state->g, g_len, g); - - ret = diffie_hellman_sha1(session, key_state->g, key_state->p, p_len, - SSH_MSG_KEX_DH_GEX_INIT, - SSH_MSG_KEX_DH_GEX_REPLY, - key_state->data + 1, - key_state->data_len - 1, - &key_state->exchange_state); - if(ret == LIBSSH2_ERROR_EAGAIN) { - return ret; - } - - LIBSSH2_FREE(session, key_state->data); - } - - dh_gex_clean_exit: - key_state->state = libssh2_NB_state_idle; - _libssh2_bn_free(key_state->g); - key_state->g = NULL; - _libssh2_bn_free(key_state->p); - key_state->p = NULL; - - return ret; -} - - - -/* kex_method_diffie_hellman_group_exchange_sha256_key_exchange - * Diffie-Hellman Group Exchange Key Exchange using SHA256 - * Negotiates random(ish) group for secret derivation - */ -static int -kex_method_diffie_hellman_group_exchange_sha256_key_exchange -(LIBSSH2_SESSION * session, key_exchange_state_low_t * key_state) -{ - int ret = 0; - int rc; - - if(key_state->state == libssh2_NB_state_idle) { - key_state->p = _libssh2_bn_init(); - key_state->g = _libssh2_bn_init(); - /* Ask for a P and G pair */ -#ifdef LIBSSH2_DH_GEX_NEW - key_state->request[0] = SSH_MSG_KEX_DH_GEX_REQUEST; - _libssh2_htonu32(key_state->request + 1, LIBSSH2_DH_GEX_MINGROUP); - _libssh2_htonu32(key_state->request + 5, LIBSSH2_DH_GEX_OPTGROUP); - _libssh2_htonu32(key_state->request + 9, LIBSSH2_DH_GEX_MAXGROUP); - key_state->request_len = 13; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Initiating Diffie-Hellman Group-Exchange " - "(New Method SHA256)"); -#else - key_state->request[0] = SSH_MSG_KEX_DH_GEX_REQUEST_OLD; - _libssh2_htonu32(key_state->request + 1, LIBSSH2_DH_GEX_OPTGROUP); - key_state->request_len = 5; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Initiating Diffie-Hellman Group-Exchange " - "(Old Method SHA256)"); -#endif - - key_state->state = libssh2_NB_state_created; - } - - if(key_state->state == libssh2_NB_state_created) { - rc = _libssh2_transport_send(session, key_state->request, - key_state->request_len, NULL, 0); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc) { - ret = _libssh2_error(session, rc, - "Unable to send " - "Group Exchange Request SHA256"); - goto dh_gex_clean_exit; - } - - key_state->state = libssh2_NB_state_sent; - } - - if(key_state->state == libssh2_NB_state_sent) { - rc = _libssh2_packet_require(session, SSH_MSG_KEX_DH_GEX_GROUP, - &key_state->data, &key_state->data_len, - 0, NULL, 0, &key_state->req_state); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc) { - ret = _libssh2_error(session, rc, - "Timeout waiting for GEX_GROUP reply SHA256"); - goto dh_gex_clean_exit; - } - - key_state->state = libssh2_NB_state_sent1; - } - - if(key_state->state == libssh2_NB_state_sent1) { - unsigned char *p, *g; - size_t p_len, g_len; - struct string_buf buf; - - if(key_state->data_len < 9) { - ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unexpected key length"); - goto dh_gex_clean_exit; - } - - buf.data = key_state->data; - buf.dataptr = buf.data; - buf.len = key_state->data_len; - - buf.dataptr++; /* increment to big num */ - - if(_libssh2_get_bignum_bytes(&buf, &p, &p_len)) { - ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unexpected value"); - goto dh_gex_clean_exit; - } - - if(_libssh2_get_bignum_bytes(&buf, &g, &g_len)) { - ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unexpected value"); - goto dh_gex_clean_exit; - } - - _libssh2_bn_from_bin(key_state->p, p_len, p); - _libssh2_bn_from_bin(key_state->g, g_len, g); - - ret = diffie_hellman_sha256(session, key_state->g, key_state->p, p_len, - SSH_MSG_KEX_DH_GEX_INIT, - SSH_MSG_KEX_DH_GEX_REPLY, - key_state->data + 1, - key_state->data_len - 1, - &key_state->exchange_state); - if(ret == LIBSSH2_ERROR_EAGAIN) { - return ret; - } - - LIBSSH2_FREE(session, key_state->data); - } - - dh_gex_clean_exit: - key_state->state = libssh2_NB_state_idle; - _libssh2_bn_free(key_state->g); - key_state->g = NULL; - _libssh2_bn_free(key_state->p); - key_state->p = NULL; - - return ret; -} - - -#if LIBSSH2_ECDSA - -/* kex_session_ecdh_curve_type - * returns the EC curve type by name used in key exchange - */ - -static int -kex_session_ecdh_curve_type(const char *name, libssh2_curve_type *out_type) -{ - int ret = 0; - libssh2_curve_type type; - - if(name == NULL) - return -1; - - if(strcmp(name, "ecdh-sha2-nistp256") == 0) - type = LIBSSH2_EC_CURVE_NISTP256; - else if(strcmp(name, "ecdh-sha2-nistp384") == 0) - type = LIBSSH2_EC_CURVE_NISTP384; - else if(strcmp(name, "ecdh-sha2-nistp521") == 0) - type = LIBSSH2_EC_CURVE_NISTP521; - else { - ret = -1; - } - - if(ret == 0 && out_type) { - *out_type = type; - } - - return ret; -} - - -/* LIBSSH2_KEX_METHOD_EC_SHA_HASH_CREATE_VERIFY - * - * Macro that create and verifies EC SHA hash with a given digest bytes - * - * Payload format: - * - * string V_C, client's identification string (CR and LF excluded) - * string V_S, server's identification string (CR and LF excluded) - * string I_C, payload of the client's SSH_MSG_KEXINIT - * string I_S, payload of the server's SSH_MSG_KEXINIT - * string K_S, server's public host key - * string Q_C, client's ephemeral public key octet string - * string Q_S, server's ephemeral public key octet string - * mpint K, shared secret - * - */ - -#define LIBSSH2_KEX_METHOD_EC_SHA_HASH_CREATE_VERIFY(digest_type) \ -{ \ - libssh2_sha##digest_type##_ctx ctx; \ - exchange_state->exchange_hash = (void *)&ctx; \ - libssh2_sha##digest_type##_init(&ctx); \ - if(session->local.banner) { \ - _libssh2_htonu32(exchange_state->h_sig_comp, \ - strlen((char *) session->local.banner) - 2); \ - libssh2_sha##digest_type##_update(ctx, \ - exchange_state->h_sig_comp, 4); \ - libssh2_sha##digest_type##_update(ctx, \ - (char *) session->local.banner, \ - strlen((char *) \ - session->local.banner) \ - - 2); \ - } \ - else { \ - _libssh2_htonu32(exchange_state->h_sig_comp, \ - sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1); \ - libssh2_sha##digest_type##_update(ctx, \ - exchange_state->h_sig_comp, 4); \ - libssh2_sha##digest_type##_update(ctx, \ - LIBSSH2_SSH_DEFAULT_BANNER, \ - sizeof(LIBSSH2_SSH_DEFAULT_BANNER) \ - - 1); \ - } \ - \ - _libssh2_htonu32(exchange_state->h_sig_comp, \ - strlen((char *) session->remote.banner)); \ - libssh2_sha##digest_type##_update(ctx, \ - exchange_state->h_sig_comp, 4); \ - libssh2_sha##digest_type##_update(ctx, \ - session->remote.banner, \ - strlen((char *) \ - session->remote.banner)); \ - \ - _libssh2_htonu32(exchange_state->h_sig_comp, \ - session->local.kexinit_len); \ - libssh2_sha##digest_type##_update(ctx, \ - exchange_state->h_sig_comp, 4); \ - libssh2_sha##digest_type##_update(ctx, \ - session->local.kexinit, \ - session->local.kexinit_len); \ - \ - _libssh2_htonu32(exchange_state->h_sig_comp, \ - session->remote.kexinit_len); \ - libssh2_sha##digest_type##_update(ctx, \ - exchange_state->h_sig_comp, 4); \ - libssh2_sha##digest_type##_update(ctx, \ - session->remote.kexinit, \ - session->remote.kexinit_len); \ - \ - _libssh2_htonu32(exchange_state->h_sig_comp, \ - session->server_hostkey_len); \ - libssh2_sha##digest_type##_update(ctx, \ - exchange_state->h_sig_comp, 4); \ - libssh2_sha##digest_type##_update(ctx, \ - session->server_hostkey, \ - session->server_hostkey_len); \ - \ - _libssh2_htonu32(exchange_state->h_sig_comp, \ - public_key_len); \ - libssh2_sha##digest_type##_update(ctx, \ - exchange_state->h_sig_comp, 4); \ - libssh2_sha##digest_type##_update(ctx, \ - public_key, \ - public_key_len); \ - \ - _libssh2_htonu32(exchange_state->h_sig_comp, \ - server_public_key_len); \ - libssh2_sha##digest_type##_update(ctx, \ - exchange_state->h_sig_comp, 4); \ - libssh2_sha##digest_type##_update(ctx, \ - server_public_key, \ - server_public_key_len); \ - \ - libssh2_sha##digest_type##_update(ctx, \ - exchange_state->k_value, \ - exchange_state->k_value_len); \ - \ - libssh2_sha##digest_type##_final(ctx, exchange_state->h_sig_comp); \ - \ - if(session->hostkey-> \ - sig_verify(session, exchange_state->h_sig, \ - exchange_state->h_sig_len, exchange_state->h_sig_comp, \ - SHA##digest_type##_DIGEST_LENGTH, \ - &session->server_hostkey_abstract)) { \ - rc = -1; \ - } \ -} \ - - -/* ecdh_sha2_nistp - * Elliptic Curve Diffie Hellman Key Exchange - */ - -static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, - unsigned char *data, size_t data_len, - unsigned char *public_key, - size_t public_key_len, _libssh2_ec_key *private_key, - kmdhgGPshakex_state_t *exchange_state) -{ - int ret = 0; - int rc; - - if(data_len < 5) { - ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT, - "Host key data is too short"); - return ret; - } - - if(exchange_state->state == libssh2_NB_state_idle) { - - /* Setup initial values */ - exchange_state->k = _libssh2_bn_init(); - - exchange_state->state = libssh2_NB_state_created; - } - - if(exchange_state->state == libssh2_NB_state_created) { - /* parse INIT reply data */ - - /* host key K_S */ - unsigned char *s = data + 1; /* Advance past packet type */ - unsigned char *server_public_key; - size_t server_public_key_len; - size_t host_sig_len; - - session->server_hostkey_len = - _libssh2_ntohu32((const unsigned char *)s); - s += 4; - - session->server_hostkey = LIBSSH2_ALLOC(session, - session->server_hostkey_len); - if(!session->server_hostkey) { - ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for a copy " - "of the host key"); - goto clean_exit; - } - - memcpy(session->server_hostkey, s, session->server_hostkey_len); - s += session->server_hostkey_len; - -#if LIBSSH2_MD5 - { - libssh2_md5_ctx fingerprint_ctx; - - if(libssh2_md5_init(&fingerprint_ctx)) { - libssh2_md5_update(fingerprint_ctx, session->server_hostkey, - session->server_hostkey_len); - libssh2_md5_final(fingerprint_ctx, - session->server_hostkey_md5); - session->server_hostkey_md5_valid = TRUE; - } - else { - session->server_hostkey_md5_valid = FALSE; - } - } -#ifdef LIBSSH2DEBUG - { - char fingerprint[50], *fprint = fingerprint; - int i; - for(i = 0; i < 16; i++, fprint += 3) { - snprintf(fprint, 4, "%02x:", session->server_hostkey_md5[i]); - } - *(--fprint) = '\0'; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server's MD5 Fingerprint: %s", fingerprint); - } -#endif /* LIBSSH2DEBUG */ -#endif /* ! LIBSSH2_MD5 */ - - { - libssh2_sha1_ctx fingerprint_ctx; - - if(libssh2_sha1_init(&fingerprint_ctx)) { - libssh2_sha1_update(fingerprint_ctx, session->server_hostkey, - session->server_hostkey_len); - libssh2_sha1_final(fingerprint_ctx, - session->server_hostkey_sha1); - session->server_hostkey_sha1_valid = TRUE; - } - else { - session->server_hostkey_sha1_valid = FALSE; - } - } -#ifdef LIBSSH2DEBUG - { - char fingerprint[64], *fprint = fingerprint; - int i; - - for(i = 0; i < 20; i++, fprint += 3) { - snprintf(fprint, 4, "%02x:", session->server_hostkey_sha1[i]); - } - *(--fprint) = '\0'; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server's SHA1 Fingerprint: %s", fingerprint); - } -#endif /* LIBSSH2DEBUG */ - - /* SHA256 */ - { - libssh2_sha256_ctx fingerprint_ctx; - - if(libssh2_sha256_init(&fingerprint_ctx)) { - libssh2_sha256_update(fingerprint_ctx, session->server_hostkey, - session->server_hostkey_len); - libssh2_sha256_final(fingerprint_ctx, - session->server_hostkey_sha256); - session->server_hostkey_sha256_valid = TRUE; - } - else { - session->server_hostkey_sha256_valid = FALSE; - } - } -#ifdef LIBSSH2DEBUG - { - char *base64Fingerprint = NULL; - _libssh2_base64_encode(session, - (const char *) - session->server_hostkey_sha256, - SHA256_DIGEST_LENGTH, &base64Fingerprint); - if(base64Fingerprint != NULL) { - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server's SHA256 Fingerprint: %s", - base64Fingerprint); - LIBSSH2_FREE(session, base64Fingerprint); - } - } -#endif /* LIBSSH2DEBUG */ - - if(session->hostkey->init(session, session->server_hostkey, - session->server_hostkey_len, - &session->server_hostkey_abstract)) { - ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT, - "Unable to initialize hostkey importer"); - goto clean_exit; - } - - /* server public key Q_S */ - server_public_key_len = _libssh2_ntohu32((const unsigned char *)s); - s += 4; - - server_public_key = s; - s += server_public_key_len; - - /* server signature */ - host_sig_len = _libssh2_ntohu32((const unsigned char *)s); - s += 4; - - exchange_state->h_sig = s; - exchange_state->h_sig_len = host_sig_len; - s += host_sig_len; - - /* Compute the shared secret K */ - rc = _libssh2_ecdh_gen_k(&exchange_state->k, private_key, - server_public_key, server_public_key_len); - if(rc != 0) { - ret = _libssh2_error(session, LIBSSH2_ERROR_KEX_FAILURE, - "Unable to create ECDH shared secret"); - goto clean_exit; - } - - exchange_state->k_value_len = _libssh2_bn_bytes(exchange_state->k) + 5; - if(_libssh2_bn_bits(exchange_state->k) % 8) { - /* don't need leading 00 */ - exchange_state->k_value_len--; - } - exchange_state->k_value = - LIBSSH2_ALLOC(session, exchange_state->k_value_len); - if(!exchange_state->k_value) { - ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate buffer for K"); - goto clean_exit; - } - _libssh2_htonu32(exchange_state->k_value, - exchange_state->k_value_len - 4); - if(_libssh2_bn_bits(exchange_state->k) % 8) { - _libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 4); - } - else { - exchange_state->k_value[4] = 0; - _libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 5); - } - - /* verify hash */ - - switch(type) { - case LIBSSH2_EC_CURVE_NISTP256: - LIBSSH2_KEX_METHOD_EC_SHA_HASH_CREATE_VERIFY(256); - break; - - case LIBSSH2_EC_CURVE_NISTP384: - LIBSSH2_KEX_METHOD_EC_SHA_HASH_CREATE_VERIFY(384); - break; - case LIBSSH2_EC_CURVE_NISTP521: - LIBSSH2_KEX_METHOD_EC_SHA_HASH_CREATE_VERIFY(512); - break; - } - - if(rc != 0) { - ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_SIGN, - "Unable to verify hostkey signature"); - goto clean_exit; - } - - exchange_state->c = SSH_MSG_NEWKEYS; - exchange_state->state = libssh2_NB_state_sent; - } - - if(exchange_state->state == libssh2_NB_state_sent) { - rc = _libssh2_transport_send(session, &exchange_state->c, 1, NULL, 0); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc) { - ret = _libssh2_error(session, rc, - "Unable to send NEWKEYS message"); - goto clean_exit; - } - - exchange_state->state = libssh2_NB_state_sent2; - } - - if(exchange_state->state == libssh2_NB_state_sent2) { - rc = _libssh2_packet_require(session, SSH_MSG_NEWKEYS, - &exchange_state->tmp, - &exchange_state->tmp_len, 0, NULL, 0, - &exchange_state->req_state); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc) { - ret = _libssh2_error(session, rc, "Timed out waiting for NEWKEYS"); - goto clean_exit; - } - - /* The first key exchange has been performed, - switch to active crypt/comp/mac mode */ - session->state |= LIBSSH2_STATE_NEWKEYS; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Received NEWKEYS message"); - - /* This will actually end up being just packet_type(1) - for this packet type anyway */ - LIBSSH2_FREE(session, exchange_state->tmp); - - if(!session->session_id) { - - size_t digest_length = 0; - - if(type == LIBSSH2_EC_CURVE_NISTP256) - digest_length = SHA256_DIGEST_LENGTH; - else if(type == LIBSSH2_EC_CURVE_NISTP384) - digest_length = SHA384_DIGEST_LENGTH; - else if(type == LIBSSH2_EC_CURVE_NISTP521) - digest_length = SHA512_DIGEST_LENGTH; - else{ - ret = _libssh2_error(session, LIBSSH2_ERROR_KEX_FAILURE, - "Unknown SHA digest for EC curve"); - goto clean_exit; - - } - session->session_id = LIBSSH2_ALLOC(session, digest_length); - if(!session->session_id) { - ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate buffer for " - "SHA digest"); - goto clean_exit; - } - memcpy(session->session_id, exchange_state->h_sig_comp, - digest_length); - session->session_id_len = digest_length; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "session_id calculated"); - } - - /* Cleanup any existing cipher */ - if(session->local.crypt->dtor) { - session->local.crypt->dtor(session, - &session->local.crypt_abstract); - } - - /* Calculate IV/Secret/Key for each direction */ - if(session->local.crypt->init) { - unsigned char *iv = NULL, *secret = NULL; - int free_iv = 0, free_secret = 0; - - LIBSSH2_KEX_METHOD_EC_SHA_VALUE_HASH(iv, - session->local.crypt-> - iv_len, "A"); - if(!iv) { - ret = -1; - goto clean_exit; - } - - LIBSSH2_KEX_METHOD_EC_SHA_VALUE_HASH(secret, - session->local.crypt-> - secret_len, "C"); - - if(!secret) { - LIBSSH2_FREE(session, iv); - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - if(session->local.crypt-> - init(session, session->local.crypt, iv, &free_iv, secret, - &free_secret, 1, &session->local.crypt_abstract)) { - LIBSSH2_FREE(session, iv); - LIBSSH2_FREE(session, secret); - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - - if(free_iv) { - _libssh2_explicit_zero(iv, session->local.crypt->iv_len); - LIBSSH2_FREE(session, iv); - } - - if(free_secret) { - _libssh2_explicit_zero(secret, - session->local.crypt->secret_len); - LIBSSH2_FREE(session, secret); - } - } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Client to Server IV and Key calculated"); - - if(session->remote.crypt->dtor) { - /* Cleanup any existing cipher */ - session->remote.crypt->dtor(session, - &session->remote.crypt_abstract); - } - - if(session->remote.crypt->init) { - unsigned char *iv = NULL, *secret = NULL; - int free_iv = 0, free_secret = 0; - - LIBSSH2_KEX_METHOD_EC_SHA_VALUE_HASH(iv, - session->remote.crypt-> - iv_len, "B"); - - if(!iv) { - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - LIBSSH2_KEX_METHOD_EC_SHA_VALUE_HASH(secret, - session->remote.crypt-> - secret_len, "D"); - - if(!secret) { - LIBSSH2_FREE(session, iv); - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - if(session->remote.crypt-> - init(session, session->remote.crypt, iv, &free_iv, secret, - &free_secret, 0, &session->remote.crypt_abstract)) { - LIBSSH2_FREE(session, iv); - LIBSSH2_FREE(session, secret); - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - - if(free_iv) { - _libssh2_explicit_zero(iv, session->remote.crypt->iv_len); - LIBSSH2_FREE(session, iv); - } - - if(free_secret) { - _libssh2_explicit_zero(secret, - session->remote.crypt->secret_len); - LIBSSH2_FREE(session, secret); - } - } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server to Client IV and Key calculated"); - - if(session->local.mac->dtor) { - session->local.mac->dtor(session, &session->local.mac_abstract); - } - - if(session->local.mac->init) { - unsigned char *key = NULL; - int free_key = 0; - - LIBSSH2_KEX_METHOD_EC_SHA_VALUE_HASH(key, - session->local.mac-> - key_len, "E"); - - if(!key) { - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - session->local.mac->init(session, key, &free_key, - &session->local.mac_abstract); - - if(free_key) { - _libssh2_explicit_zero(key, session->local.mac->key_len); - LIBSSH2_FREE(session, key); - } - } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Client to Server HMAC Key calculated"); - - if(session->remote.mac->dtor) { - session->remote.mac->dtor(session, &session->remote.mac_abstract); - } - - if(session->remote.mac->init) { - unsigned char *key = NULL; - int free_key = 0; - - LIBSSH2_KEX_METHOD_EC_SHA_VALUE_HASH(key, - session->remote.mac-> - key_len, "F"); - - if(!key) { - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - session->remote.mac->init(session, key, &free_key, - &session->remote.mac_abstract); - - if(free_key) { - _libssh2_explicit_zero(key, session->remote.mac->key_len); - LIBSSH2_FREE(session, key); - } - } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server to Client HMAC Key calculated"); - - /* Initialize compression for each direction */ - - /* Cleanup any existing compression */ - if(session->local.comp && session->local.comp->dtor) { - session->local.comp->dtor(session, 1, - &session->local.comp_abstract); - } - - if(session->local.comp && session->local.comp->init) { - if(session->local.comp->init(session, 1, - &session->local.comp_abstract)) { - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Client to Server compression initialized"); - - if(session->remote.comp && session->remote.comp->dtor) { - session->remote.comp->dtor(session, 0, - &session->remote.comp_abstract); - } - - if(session->remote.comp && session->remote.comp->init) { - if(session->remote.comp->init(session, 0, - &session->remote.comp_abstract)) { - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server to Client compression initialized"); - - } - -clean_exit: - _libssh2_bn_free(exchange_state->k); - exchange_state->k = NULL; - - if(exchange_state->k_value) { - LIBSSH2_FREE(session, exchange_state->k_value); - exchange_state->k_value = NULL; - } - - exchange_state->state = libssh2_NB_state_idle; - - return ret; -} - -/* kex_method_ecdh_key_exchange - * - * Elliptic Curve Diffie Hellman Key Exchange - * supports SHA256/384/512 hashes based on negotated ecdh method - * - */ - -static int -kex_method_ecdh_key_exchange -(LIBSSH2_SESSION * session, key_exchange_state_low_t * key_state) -{ - int ret = 0; - int rc = 0; - unsigned char *s; - libssh2_curve_type type; - - if(key_state->state == libssh2_NB_state_idle) { - - key_state->public_key_oct = NULL; - key_state->state = libssh2_NB_state_created; - } - - if(key_state->state == libssh2_NB_state_created) { - rc = kex_session_ecdh_curve_type(session->kex->name, &type); - - if(rc != 0) { - ret = _libssh2_error(session, -1, - "Unknown KEX nistp curve type"); - goto ecdh_clean_exit; - } - - rc = _libssh2_ecdsa_create_key(session, &key_state->private_key, - &key_state->public_key_oct, - &key_state->public_key_oct_len, type); - - if(rc != 0) { - ret = _libssh2_error(session, rc, - "Unable to create private key"); - goto ecdh_clean_exit; - } - - key_state->request[0] = SSH2_MSG_KEX_ECDH_INIT; - s = key_state->request + 1; - _libssh2_store_str(&s, (const char *)key_state->public_key_oct, - key_state->public_key_oct_len); - key_state->request_len = key_state->public_key_oct_len + 5; - - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Initiating ECDH SHA2 NISTP256"); - - key_state->state = libssh2_NB_state_sent; - } - - if(key_state->state == libssh2_NB_state_sent) { - rc = _libssh2_transport_send(session, key_state->request, - key_state->request_len, NULL, 0); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc) { - ret = _libssh2_error(session, rc, - "Unable to send ECDH_INIT"); - goto ecdh_clean_exit; - } - - key_state->state = libssh2_NB_state_sent1; - } - - if(key_state->state == libssh2_NB_state_sent1) { - rc = _libssh2_packet_require(session, SSH2_MSG_KEX_ECDH_REPLY, - &key_state->data, &key_state->data_len, - 0, NULL, 0, &key_state->req_state); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc) { - ret = _libssh2_error(session, rc, - "Timeout waiting for ECDH_REPLY reply"); - goto ecdh_clean_exit; - } - - key_state->state = libssh2_NB_state_sent2; - } - - if(key_state->state == libssh2_NB_state_sent2) { - - (void)kex_session_ecdh_curve_type(session->kex->name, &type); - - ret = ecdh_sha2_nistp(session, type, key_state->data, - key_state->data_len, - (unsigned char *)key_state->public_key_oct, - key_state->public_key_oct_len, - key_state->private_key, - &key_state->exchange_state); - - if(ret == LIBSSH2_ERROR_EAGAIN) { - return ret; - } - - LIBSSH2_FREE(session, key_state->data); - } - -ecdh_clean_exit: - - if(key_state->public_key_oct) { - LIBSSH2_FREE(session, key_state->public_key_oct); - key_state->public_key_oct = NULL; - } - - if(key_state->private_key) { - _libssh2_ecdsa_free(key_state->private_key); - key_state->private_key = NULL; - } - - key_state->state = libssh2_NB_state_idle; - - return ret; -} - -#endif /*LIBSSH2_ECDSA*/ - - -#if LIBSSH2_ED25519 - -/* curve25519_sha256 - * Elliptic Curve Key Exchange - */ - -static int -curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, - size_t data_len, - unsigned char public_key[LIBSSH2_ED25519_KEY_LEN], - unsigned char private_key[LIBSSH2_ED25519_KEY_LEN], - kmdhgGPshakex_state_t *exchange_state) -{ - int ret = 0; - int rc; - int public_key_len = LIBSSH2_ED25519_KEY_LEN; - - if(data_len < 5) { - return _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT, - "Data is too short"); - } - - if(exchange_state->state == libssh2_NB_state_idle) { - - /* Setup initial values */ - exchange_state->k = _libssh2_bn_init(); - - exchange_state->state = libssh2_NB_state_created; - } - - if(exchange_state->state == libssh2_NB_state_created) { - /* parse INIT reply data */ - unsigned char *server_public_key, *server_host_key; - size_t server_public_key_len, hostkey_len; - struct string_buf buf; - - if(data_len < 5) { - ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unexpected key length"); - goto clean_exit; - } - - buf.data = data; - buf.len = data_len; - buf.dataptr = buf.data; - buf.dataptr++; /* advance past packet type */ - - if(_libssh2_get_string(&buf, &server_host_key, &hostkey_len)) { - ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unexpected key length"); - goto clean_exit; - } - - session->server_hostkey_len = (uint32_t)hostkey_len; - session->server_hostkey = LIBSSH2_ALLOC(session, - session->server_hostkey_len); - if(!session->server_hostkey) { - ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for a copy " - "of the host key"); - goto clean_exit; - } - - memcpy(session->server_hostkey, server_host_key, - session->server_hostkey_len); - -#if LIBSSH2_MD5 - { - libssh2_md5_ctx fingerprint_ctx; - - if(libssh2_md5_init(&fingerprint_ctx)) { - libssh2_md5_update(fingerprint_ctx, session->server_hostkey, - session->server_hostkey_len); - libssh2_md5_final(fingerprint_ctx, - session->server_hostkey_md5); - session->server_hostkey_md5_valid = TRUE; - } - else { - session->server_hostkey_md5_valid = FALSE; - } - } -#ifdef LIBSSH2DEBUG - { - char fingerprint[50], *fprint = fingerprint; - int i; - for(i = 0; i < 16; i++, fprint += 3) { - snprintf(fprint, 4, "%02x:", session->server_hostkey_md5[i]); - } - *(--fprint) = '\0'; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server's MD5 Fingerprint: %s", fingerprint); - } -#endif /* LIBSSH2DEBUG */ -#endif /* ! LIBSSH2_MD5 */ - - { - libssh2_sha1_ctx fingerprint_ctx; - - if(libssh2_sha1_init(&fingerprint_ctx)) { - libssh2_sha1_update(fingerprint_ctx, session->server_hostkey, - session->server_hostkey_len); - libssh2_sha1_final(fingerprint_ctx, - session->server_hostkey_sha1); - session->server_hostkey_sha1_valid = TRUE; - } - else { - session->server_hostkey_sha1_valid = FALSE; - } - } -#ifdef LIBSSH2DEBUG - { - char fingerprint[64], *fprint = fingerprint; - int i; - - for(i = 0; i < 20; i++, fprint += 3) { - snprintf(fprint, 4, "%02x:", session->server_hostkey_sha1[i]); - } - *(--fprint) = '\0'; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server's SHA1 Fingerprint: %s", fingerprint); - } -#endif /* LIBSSH2DEBUG */ - - /* SHA256 */ - { - libssh2_sha256_ctx fingerprint_ctx; - - if(libssh2_sha256_init(&fingerprint_ctx)) { - libssh2_sha256_update(fingerprint_ctx, session->server_hostkey, - session->server_hostkey_len); - libssh2_sha256_final(fingerprint_ctx, - session->server_hostkey_sha256); - session->server_hostkey_sha256_valid = TRUE; - } - else { - session->server_hostkey_sha256_valid = FALSE; - } - } -#ifdef LIBSSH2DEBUG - { - char *base64Fingerprint = NULL; - _libssh2_base64_encode(session, - (const char *) - session->server_hostkey_sha256, - SHA256_DIGEST_LENGTH, &base64Fingerprint); - if(base64Fingerprint != NULL) { - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server's SHA256 Fingerprint: %s", - base64Fingerprint); - LIBSSH2_FREE(session, base64Fingerprint); - } - } -#endif /* LIBSSH2DEBUG */ - - if(session->hostkey->init(session, session->server_hostkey, - session->server_hostkey_len, - &session->server_hostkey_abstract)) { - ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT, - "Unable to initialize hostkey importer"); - goto clean_exit; - } - - /* server public key Q_S */ - if(_libssh2_get_string(&buf, &server_public_key, - &server_public_key_len)) { - ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unexpected key length"); - goto clean_exit; - } - - if(server_public_key_len != LIBSSH2_ED25519_KEY_LEN) { - ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT, - "Unexpected curve25519 server " - "public key length"); - goto clean_exit; - } - - /* server signature */ - if(_libssh2_get_string(&buf, &exchange_state->h_sig, - &(exchange_state->h_sig_len))) { - ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT, - "Unexpected curve25519 server sig length"); - goto clean_exit; - } - - /* Compute the shared secret K */ - rc = _libssh2_curve25519_gen_k(&exchange_state->k, private_key, - server_public_key); - if(rc != 0) { - ret = _libssh2_error(session, LIBSSH2_ERROR_KEX_FAILURE, - "Unable to create ECDH shared secret"); - goto clean_exit; - } - - exchange_state->k_value_len = _libssh2_bn_bytes(exchange_state->k) + 5; - if(_libssh2_bn_bits(exchange_state->k) % 8) { - /* don't need leading 00 */ - exchange_state->k_value_len--; - } - exchange_state->k_value = - LIBSSH2_ALLOC(session, exchange_state->k_value_len); - if(!exchange_state->k_value) { - ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate buffer for K"); - goto clean_exit; - } - _libssh2_htonu32(exchange_state->k_value, - exchange_state->k_value_len - 4); - if(_libssh2_bn_bits(exchange_state->k) % 8) { - _libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 4); - } - else { - exchange_state->k_value[4] = 0; - _libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 5); - } - - /*/ verify hash */ - LIBSSH2_KEX_METHOD_EC_SHA_HASH_CREATE_VERIFY(256); - - if(rc != 0) { - ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_SIGN, - "Unable to verify hostkey signature"); - goto clean_exit; - } - - exchange_state->c = SSH_MSG_NEWKEYS; - exchange_state->state = libssh2_NB_state_sent; - } - - if(exchange_state->state == libssh2_NB_state_sent) { - rc = _libssh2_transport_send(session, &exchange_state->c, 1, NULL, 0); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc) { - ret = _libssh2_error(session, rc, - "Unable to send NEWKEYS message"); - goto clean_exit; - } - - exchange_state->state = libssh2_NB_state_sent2; - } - - if(exchange_state->state == libssh2_NB_state_sent2) { - rc = _libssh2_packet_require(session, SSH_MSG_NEWKEYS, - &exchange_state->tmp, - &exchange_state->tmp_len, 0, NULL, 0, - &exchange_state->req_state); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc) { - ret = _libssh2_error(session, rc, "Timed out waiting for NEWKEYS"); - goto clean_exit; - } - - /* The first key exchange has been performed, switch to active - crypt/comp/mac mode */ - - session->state |= LIBSSH2_STATE_NEWKEYS; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Received NEWKEYS message"); - - /* This will actually end up being just packet_type(1) for this packet - type anyway */ - LIBSSH2_FREE(session, exchange_state->tmp); - - if(!session->session_id) { - - size_t digest_length = SHA256_DIGEST_LENGTH; - session->session_id = LIBSSH2_ALLOC(session, digest_length); - if(!session->session_id) { - ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allxcocate buffer for " - "SHA digest"); - goto clean_exit; - } - memcpy(session->session_id, exchange_state->h_sig_comp, - digest_length); - session->session_id_len = digest_length; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "session_id calculated"); - } - - /* Cleanup any existing cipher */ - if(session->local.crypt->dtor) { - session->local.crypt->dtor(session, - &session->local.crypt_abstract); - } - - /* Calculate IV/Secret/Key for each direction */ - if(session->local.crypt->init) { - unsigned char *iv = NULL, *secret = NULL; - int free_iv = 0, free_secret = 0; - - LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(256, iv, - session->local.crypt-> - iv_len, "A"); - if(!iv) { - ret = -1; - goto clean_exit; - } - - LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(256, secret, - session->local.crypt-> - secret_len, "C"); - - if(!secret) { - LIBSSH2_FREE(session, iv); - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - if(session->local.crypt-> - init(session, session->local.crypt, iv, &free_iv, secret, - &free_secret, 1, &session->local.crypt_abstract)) { - LIBSSH2_FREE(session, iv); - LIBSSH2_FREE(session, secret); - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - - if(free_iv) { - _libssh2_explicit_zero(iv, session->local.crypt->iv_len); - LIBSSH2_FREE(session, iv); - } - - if(free_secret) { - _libssh2_explicit_zero(secret, - session->local.crypt->secret_len); - LIBSSH2_FREE(session, secret); - } - } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Client to Server IV and Key calculated"); - - if(session->remote.crypt->dtor) { - /* Cleanup any existing cipher */ - session->remote.crypt->dtor(session, - &session->remote.crypt_abstract); - } - - if(session->remote.crypt->init) { - unsigned char *iv = NULL, *secret = NULL; - int free_iv = 0, free_secret = 0; - - LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(256, iv, - session->remote.crypt-> - iv_len, "B"); - - if(!iv) { - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(256, secret, - session->remote.crypt-> - secret_len, "D"); - - if(!secret) { - LIBSSH2_FREE(session, iv); - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - if(session->remote.crypt-> - init(session, session->remote.crypt, iv, &free_iv, secret, - &free_secret, 0, &session->remote.crypt_abstract)) { - LIBSSH2_FREE(session, iv); - LIBSSH2_FREE(session, secret); - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - - if(free_iv) { - _libssh2_explicit_zero(iv, session->remote.crypt->iv_len); - LIBSSH2_FREE(session, iv); - } - - if(free_secret) { - _libssh2_explicit_zero(secret, - session->remote.crypt->secret_len); - LIBSSH2_FREE(session, secret); - } - } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server to Client IV and Key calculated"); - - if(session->local.mac->dtor) { - session->local.mac->dtor(session, &session->local.mac_abstract); - } - - if(session->local.mac->init) { - unsigned char *key = NULL; - int free_key = 0; - - LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(256, key, - session->local.mac-> - key_len, "E"); - - if(!key) { - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - session->local.mac->init(session, key, &free_key, - &session->local.mac_abstract); - - if(free_key) { - _libssh2_explicit_zero(key, session->local.mac->key_len); - LIBSSH2_FREE(session, key); - } - } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Client to Server HMAC Key calculated"); - - if(session->remote.mac->dtor) { - session->remote.mac->dtor(session, &session->remote.mac_abstract); - } - - if(session->remote.mac->init) { - unsigned char *key = NULL; - int free_key = 0; - - LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(256, key, - session->remote.mac-> - key_len, "F"); - - if(!key) { - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - session->remote.mac->init(session, key, &free_key, - &session->remote.mac_abstract); - - if(free_key) { - _libssh2_explicit_zero(key, session->remote.mac->key_len); - LIBSSH2_FREE(session, key); - } - } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server to Client HMAC Key calculated"); - - /* Initialize compression for each direction */ - - /* Cleanup any existing compression */ - if(session->local.comp && session->local.comp->dtor) { - session->local.comp->dtor(session, 1, - &session->local.comp_abstract); - } - - if(session->local.comp && session->local.comp->init) { - if(session->local.comp->init(session, 1, - &session->local.comp_abstract)) { - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Client to Server compression initialized"); - - if(session->remote.comp && session->remote.comp->dtor) { - session->remote.comp->dtor(session, 0, - &session->remote.comp_abstract); - } - - if(session->remote.comp && session->remote.comp->init) { - if(session->remote.comp->init(session, 0, - &session->remote.comp_abstract)) { - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server to Client compression initialized"); - } - -clean_exit: - _libssh2_bn_free(exchange_state->k); - exchange_state->k = NULL; - - if(exchange_state->k_value) { - LIBSSH2_FREE(session, exchange_state->k_value); - exchange_state->k_value = NULL; - } - - exchange_state->state = libssh2_NB_state_idle; - - return ret; -} - -/* kex_method_curve25519_key_exchange - * - * Elliptic Curve X25519 Key Exchange with SHA256 hash - * - */ - -static int -kex_method_curve25519_key_exchange -(LIBSSH2_SESSION * session, key_exchange_state_low_t * key_state) -{ - int ret = 0; - int rc = 0; - - if(key_state->state == libssh2_NB_state_idle) { - - key_state->public_key_oct = NULL; - key_state->state = libssh2_NB_state_created; - } - - if(key_state->state == libssh2_NB_state_created) { - unsigned char *s = NULL; - - rc = strcmp(session->kex->name, "curve25519-sha256@libssh.org"); - if(rc != 0) - rc = strcmp(session->kex->name, "curve25519-sha256"); - - if(rc != 0) { - ret = _libssh2_error(session, -1, - "Unknown KEX curve25519 curve type"); - goto clean_exit; - } - - rc = _libssh2_curve25519_new(session, NULL, - &key_state->curve25519_public_key, - &key_state->curve25519_private_key); - - if(rc != 0) { - ret = _libssh2_error(session, rc, - "Unable to create private key"); - goto clean_exit; - } - - key_state->request[0] = SSH2_MSG_KEX_ECDH_INIT; - s = key_state->request + 1; - _libssh2_store_str(&s, (const char *)key_state->curve25519_public_key, - LIBSSH2_ED25519_KEY_LEN); - key_state->request_len = LIBSSH2_ED25519_KEY_LEN + 5; - - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Initiating curve25519 SHA2"); - - key_state->state = libssh2_NB_state_sent; - } - - if(key_state->state == libssh2_NB_state_sent) { - rc = _libssh2_transport_send(session, key_state->request, - key_state->request_len, NULL, 0); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc) { - ret = _libssh2_error(session, rc, - "Unable to send ECDH_INIT"); - goto clean_exit; - } - - key_state->state = libssh2_NB_state_sent1; - } - - if(key_state->state == libssh2_NB_state_sent1) { - rc = _libssh2_packet_require(session, SSH2_MSG_KEX_ECDH_REPLY, - &key_state->data, &key_state->data_len, - 0, NULL, 0, &key_state->req_state); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc) { - ret = _libssh2_error(session, rc, - "Timeout waiting for ECDH_REPLY reply"); - goto clean_exit; - } - - key_state->state = libssh2_NB_state_sent2; - } - - if(key_state->state == libssh2_NB_state_sent2) { - - ret = curve25519_sha256(session, key_state->data, key_state->data_len, - key_state->curve25519_public_key, - key_state->curve25519_private_key, - &key_state->exchange_state); - - if(ret == LIBSSH2_ERROR_EAGAIN) { - return ret; - } - - LIBSSH2_FREE(session, key_state->data); - } - -clean_exit: - - if(key_state->curve25519_public_key) { - _libssh2_explicit_zero(key_state->curve25519_public_key, - LIBSSH2_ED25519_KEY_LEN); - LIBSSH2_FREE(session, key_state->curve25519_public_key); - key_state->curve25519_public_key = NULL; - } - - if(key_state->curve25519_private_key) { - _libssh2_explicit_zero(key_state->curve25519_private_key, - LIBSSH2_ED25519_KEY_LEN); - LIBSSH2_FREE(session, key_state->curve25519_private_key); - key_state->curve25519_private_key = NULL; - } - - key_state->state = libssh2_NB_state_idle; - - return ret; -} - - -#endif /*LIBSSH2_ED25519*/ - - -#define LIBSSH2_KEX_METHOD_FLAG_REQ_ENC_HOSTKEY 0x0001 -#define LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY 0x0002 - -static const LIBSSH2_KEX_METHOD kex_method_diffie_helman_group1_sha1 = { - "diffie-hellman-group1-sha1", - kex_method_diffie_hellman_group1_sha1_key_exchange, - LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, -}; - -static const LIBSSH2_KEX_METHOD kex_method_diffie_helman_group14_sha1 = { - "diffie-hellman-group14-sha1", - kex_method_diffie_hellman_group14_sha1_key_exchange, - LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, -}; - -static const LIBSSH2_KEX_METHOD kex_method_diffie_helman_group14_sha256 = { - "diffie-hellman-group14-sha256", - kex_method_diffie_hellman_group14_sha256_key_exchange, - LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, -}; - -static const LIBSSH2_KEX_METHOD -kex_method_diffie_helman_group_exchange_sha1 = { - "diffie-hellman-group-exchange-sha1", - kex_method_diffie_hellman_group_exchange_sha1_key_exchange, - LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, -}; - -static const LIBSSH2_KEX_METHOD -kex_method_diffie_helman_group_exchange_sha256 = { - "diffie-hellman-group-exchange-sha256", - kex_method_diffie_hellman_group_exchange_sha256_key_exchange, - LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, -}; - -#if LIBSSH2_ECDSA -static const LIBSSH2_KEX_METHOD -kex_method_ecdh_sha2_nistp256 = { - "ecdh-sha2-nistp256", - kex_method_ecdh_key_exchange, - LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, -}; - -static const LIBSSH2_KEX_METHOD -kex_method_ecdh_sha2_nistp384 = { - "ecdh-sha2-nistp384", - kex_method_ecdh_key_exchange, - LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, -}; - -static const LIBSSH2_KEX_METHOD -kex_method_ecdh_sha2_nistp521 = { - "ecdh-sha2-nistp521", - kex_method_ecdh_key_exchange, - LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, -}; -#endif - -#if LIBSSH2_ED25519 -static const LIBSSH2_KEX_METHOD -kex_method_ssh_curve25519_sha256_libssh = { - "curve25519-sha256@libssh.org", - kex_method_curve25519_key_exchange, - LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, -}; -static const LIBSSH2_KEX_METHOD -kex_method_ssh_curve25519_sha256 = { - "curve25519-sha256", - kex_method_curve25519_key_exchange, - LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, -}; -#endif - -static const LIBSSH2_KEX_METHOD *libssh2_kex_methods[] = { -#if LIBSSH2_ECDSA - &kex_method_ecdh_sha2_nistp256, - &kex_method_ecdh_sha2_nistp384, - &kex_method_ecdh_sha2_nistp521, -#endif -#if LIBSSH2_ED25519 - &kex_method_ssh_curve25519_sha256, - &kex_method_ssh_curve25519_sha256_libssh, -#endif - &kex_method_diffie_helman_group14_sha256, - &kex_method_diffie_helman_group_exchange_sha256, - &kex_method_diffie_helman_group_exchange_sha1, - &kex_method_diffie_helman_group14_sha1, - &kex_method_diffie_helman_group1_sha1, - NULL -}; - -typedef struct _LIBSSH2_COMMON_METHOD -{ - const char *name; -} LIBSSH2_COMMON_METHOD; - -/* kex_method_strlen - * Calculate the length of a particular method list's resulting string - * Includes SUM(strlen() of each individual method plus 1 (for coma)) - 1 - * (because the last coma isn't used) - * Another sign of bad coding practices gone mad. Pretend you don't see this. - */ -static size_t -kex_method_strlen(LIBSSH2_COMMON_METHOD ** method) -{ - size_t len = 0; - - if(!method || !*method) { - return 0; - } - - while(*method && (*method)->name) { - len += strlen((*method)->name) + 1; - method++; - } - - return len - 1; -} - - - -/* kex_method_list - * Generate formatted preference list in buf - */ -static size_t -kex_method_list(unsigned char *buf, size_t list_strlen, - LIBSSH2_COMMON_METHOD ** method) -{ - _libssh2_htonu32(buf, list_strlen); - buf += 4; - - if(!method || !*method) { - return 4; - } - - while(*method && (*method)->name) { - int mlen = strlen((*method)->name); - memcpy(buf, (*method)->name, mlen); - buf += mlen; - *(buf++) = ','; - method++; - } - - return list_strlen + 4; -} - - - -#define LIBSSH2_METHOD_PREFS_LEN(prefvar, defaultvar) \ - ((prefvar) ? strlen(prefvar) : \ - kex_method_strlen((LIBSSH2_COMMON_METHOD**)(defaultvar))) - -#define LIBSSH2_METHOD_PREFS_STR(buf, prefvarlen, prefvar, defaultvar) \ - if(prefvar) { \ - _libssh2_htonu32((buf), (prefvarlen)); \ - buf += 4; \ - memcpy((buf), (prefvar), (prefvarlen)); \ - buf += (prefvarlen); \ - } \ - else { \ - buf += kex_method_list((buf), (prefvarlen), \ - (LIBSSH2_COMMON_METHOD**)(defaultvar)); \ - } - -/* kexinit - * Send SSH_MSG_KEXINIT packet - */ -static int kexinit(LIBSSH2_SESSION * session) -{ - /* 62 = packet_type(1) + cookie(16) + first_packet_follows(1) + - reserved(4) + length longs(40) */ - size_t data_len = 62; - size_t kex_len, hostkey_len = 0; - size_t crypt_cs_len, crypt_sc_len; - size_t comp_cs_len, comp_sc_len; - size_t mac_cs_len, mac_sc_len; - size_t lang_cs_len, lang_sc_len; - unsigned char *data, *s; - int rc; - - if(session->kexinit_state == libssh2_NB_state_idle) { - kex_len = - LIBSSH2_METHOD_PREFS_LEN(session->kex_prefs, libssh2_kex_methods); - hostkey_len = - LIBSSH2_METHOD_PREFS_LEN(session->hostkey_prefs, - libssh2_hostkey_methods()); - crypt_cs_len = - LIBSSH2_METHOD_PREFS_LEN(session->local.crypt_prefs, - libssh2_crypt_methods()); - crypt_sc_len = - LIBSSH2_METHOD_PREFS_LEN(session->remote.crypt_prefs, - libssh2_crypt_methods()); - mac_cs_len = - LIBSSH2_METHOD_PREFS_LEN(session->local.mac_prefs, - _libssh2_mac_methods()); - mac_sc_len = - LIBSSH2_METHOD_PREFS_LEN(session->remote.mac_prefs, - _libssh2_mac_methods()); - comp_cs_len = - LIBSSH2_METHOD_PREFS_LEN(session->local.comp_prefs, - _libssh2_comp_methods(session)); - comp_sc_len = - LIBSSH2_METHOD_PREFS_LEN(session->remote.comp_prefs, - _libssh2_comp_methods(session)); - lang_cs_len = - LIBSSH2_METHOD_PREFS_LEN(session->local.lang_prefs, NULL); - lang_sc_len = - LIBSSH2_METHOD_PREFS_LEN(session->remote.lang_prefs, NULL); - - data_len += kex_len + hostkey_len + crypt_cs_len + crypt_sc_len + - comp_cs_len + comp_sc_len + mac_cs_len + mac_sc_len + - lang_cs_len + lang_sc_len; - - s = data = LIBSSH2_ALLOC(session, data_len); - if(!data) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory"); - } - - *(s++) = SSH_MSG_KEXINIT; - - _libssh2_random(s, 16); - s += 16; - - /* Ennumerating through these lists twice is probably (certainly?) - inefficient from a CPU standpoint, but it saves multiple - malloc/realloc calls */ - LIBSSH2_METHOD_PREFS_STR(s, kex_len, session->kex_prefs, - libssh2_kex_methods); - LIBSSH2_METHOD_PREFS_STR(s, hostkey_len, session->hostkey_prefs, - libssh2_hostkey_methods()); - LIBSSH2_METHOD_PREFS_STR(s, crypt_cs_len, session->local.crypt_prefs, - libssh2_crypt_methods()); - LIBSSH2_METHOD_PREFS_STR(s, crypt_sc_len, session->remote.crypt_prefs, - libssh2_crypt_methods()); - LIBSSH2_METHOD_PREFS_STR(s, mac_cs_len, session->local.mac_prefs, - _libssh2_mac_methods()); - LIBSSH2_METHOD_PREFS_STR(s, mac_sc_len, session->remote.mac_prefs, - _libssh2_mac_methods()); - LIBSSH2_METHOD_PREFS_STR(s, comp_cs_len, session->local.comp_prefs, - _libssh2_comp_methods(session)); - LIBSSH2_METHOD_PREFS_STR(s, comp_sc_len, session->remote.comp_prefs, - _libssh2_comp_methods(session)); - LIBSSH2_METHOD_PREFS_STR(s, lang_cs_len, session->local.lang_prefs, - NULL); - LIBSSH2_METHOD_PREFS_STR(s, lang_sc_len, session->remote.lang_prefs, - NULL); - - /* No optimistic KEX packet follows */ - /* Deal with optimistic packets - * session->flags |= KEXINIT_OPTIMISTIC - * session->flags |= KEXINIT_METHODSMATCH - */ - *(s++) = 0; - - /* Reserved == 0 */ - _libssh2_htonu32(s, 0); - -#ifdef LIBSSH2DEBUG - { - /* Funnily enough, they'll all "appear" to be '\0' terminated */ - unsigned char *p = data + 21; /* type(1) + cookie(16) + len(4) */ - - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent KEX: %s", p); - p += kex_len + 4; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent HOSTKEY: %s", p); - p += hostkey_len + 4; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent CRYPT_CS: %s", p); - p += crypt_cs_len + 4; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent CRYPT_SC: %s", p); - p += crypt_sc_len + 4; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent MAC_CS: %s", p); - p += mac_cs_len + 4; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent MAC_SC: %s", p); - p += mac_sc_len + 4; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent COMP_CS: %s", p); - p += comp_cs_len + 4; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent COMP_SC: %s", p); - p += comp_sc_len + 4; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent LANG_CS: %s", p); - p += lang_cs_len + 4; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent LANG_SC: %s", p); - p += lang_sc_len + 4; - } -#endif /* LIBSSH2DEBUG */ - - session->kexinit_state = libssh2_NB_state_created; - } - else { - data = session->kexinit_data; - data_len = session->kexinit_data_len; - /* zap the variables to ensure there is NOT a double free later */ - session->kexinit_data = NULL; - session->kexinit_data_len = 0; - } - - rc = _libssh2_transport_send(session, data, data_len, NULL, 0); - if(rc == LIBSSH2_ERROR_EAGAIN) { - session->kexinit_data = data; - session->kexinit_data_len = data_len; - return rc; - } - else if(rc) { - LIBSSH2_FREE(session, data); - session->kexinit_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, - "Unable to send KEXINIT packet to remote host"); - - } - - if(session->local.kexinit) { - LIBSSH2_FREE(session, session->local.kexinit); - } - - session->local.kexinit = data; - session->local.kexinit_len = data_len; - - session->kexinit_state = libssh2_NB_state_idle; - - return 0; -} - -/* kex_agree_instr - * Kex specific variant of strstr() - * Needle must be precede by BOL or ',', and followed by ',' or EOL - */ -static unsigned char * -kex_agree_instr(unsigned char *haystack, unsigned long haystack_len, - const unsigned char *needle, unsigned long needle_len) -{ - unsigned char *s; - - /* Haystack too short to bother trying */ - if(haystack_len < needle_len) { - return NULL; - } - - /* Needle at start of haystack */ - if((strncmp((char *) haystack, (char *) needle, needle_len) == 0) && - (needle_len == haystack_len || haystack[needle_len] == ',')) { - return haystack; - } - - s = haystack; - /* Search until we run out of comas or we run out of haystack, - whichever comes first */ - while((s = (unsigned char *) strchr((char *) s, ',')) - && ((haystack_len - (s - haystack)) > needle_len)) { - s++; - /* Needle at X position */ - if((strncmp((char *) s, (char *) needle, needle_len) == 0) && - (((s - haystack) + needle_len) == haystack_len - || s[needle_len] == ',')) { - return s; - } - } - - return NULL; -} - - - -/* kex_get_method_by_name - */ -static const LIBSSH2_COMMON_METHOD * -kex_get_method_by_name(const char *name, size_t name_len, - const LIBSSH2_COMMON_METHOD ** methodlist) -{ - while(*methodlist) { - if((strlen((*methodlist)->name) == name_len) && - (strncmp((*methodlist)->name, name, name_len) == 0)) { - return *methodlist; - } - methodlist++; - } - return NULL; -} - - - -/* kex_agree_hostkey - * Agree on a Hostkey which works with this kex - */ -static int kex_agree_hostkey(LIBSSH2_SESSION * session, - unsigned long kex_flags, - unsigned char *hostkey, unsigned long hostkey_len) -{ - const LIBSSH2_HOSTKEY_METHOD **hostkeyp = libssh2_hostkey_methods(); - unsigned char *s; - - if(session->hostkey_prefs) { - s = (unsigned char *) session->hostkey_prefs; - - while(s && *s) { - unsigned char *p = (unsigned char *) strchr((char *) s, ','); - size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s)); - if(kex_agree_instr(hostkey, hostkey_len, s, method_len)) { - const LIBSSH2_HOSTKEY_METHOD *method = - (const LIBSSH2_HOSTKEY_METHOD *) - kex_get_method_by_name((char *) s, method_len, - (const LIBSSH2_COMMON_METHOD **) - hostkeyp); - - if(!method) { - /* Invalid method -- Should never be reached */ - return -1; - } - - /* So far so good, but does it suit our purposes? (Encrypting - vs Signing) */ - if(((kex_flags & LIBSSH2_KEX_METHOD_FLAG_REQ_ENC_HOSTKEY) == - 0) || (method->encrypt)) { - /* Either this hostkey can do encryption or this kex just - doesn't require it */ - if(((kex_flags & LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY) - == 0) || (method->sig_verify)) { - /* Either this hostkey can do signing or this kex just - doesn't require it */ - session->hostkey = method; - return 0; - } - } - } - - s = p ? p + 1 : NULL; - } - return -1; - } - - while(hostkeyp && (*hostkeyp) && (*hostkeyp)->name) { - s = kex_agree_instr(hostkey, hostkey_len, - (unsigned char *) (*hostkeyp)->name, - strlen((*hostkeyp)->name)); - if(s) { - /* So far so good, but does it suit our purposes? (Encrypting vs - Signing) */ - if(((kex_flags & LIBSSH2_KEX_METHOD_FLAG_REQ_ENC_HOSTKEY) == 0) || - ((*hostkeyp)->encrypt)) { - /* Either this hostkey can do encryption or this kex just - doesn't require it */ - if(((kex_flags & LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY) == - 0) || ((*hostkeyp)->sig_verify)) { - /* Either this hostkey can do signing or this kex just - doesn't require it */ - session->hostkey = *hostkeyp; - return 0; - } - } - } - hostkeyp++; - } - - return -1; -} - - - -/* kex_agree_kex_hostkey - * Agree on a Key Exchange method and a hostkey encoding type - */ -static int kex_agree_kex_hostkey(LIBSSH2_SESSION * session, unsigned char *kex, - unsigned long kex_len, unsigned char *hostkey, - unsigned long hostkey_len) -{ - const LIBSSH2_KEX_METHOD **kexp = libssh2_kex_methods; - unsigned char *s; - - if(session->kex_prefs) { - s = (unsigned char *) session->kex_prefs; - - while(s && *s) { - unsigned char *q, *p = (unsigned char *) strchr((char *) s, ','); - size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s)); - q = kex_agree_instr(kex, kex_len, s, method_len); - if(q) { - const LIBSSH2_KEX_METHOD *method = (const LIBSSH2_KEX_METHOD *) - kex_get_method_by_name((char *) s, method_len, - (const LIBSSH2_COMMON_METHOD **) - kexp); - - if(!method) { - /* Invalid method -- Should never be reached */ - return -1; - } - - /* We've agreed on a key exchange method, - * Can we agree on a hostkey that works with this kex? - */ - if(kex_agree_hostkey(session, method->flags, hostkey, - hostkey_len) == 0) { - session->kex = method; - if(session->burn_optimistic_kexinit && (kex == q)) { - /* Server sent an optimistic packet, and client agrees - * with preference cancel burning the first KEX_INIT - * packet that comes in */ - session->burn_optimistic_kexinit = 0; - } - return 0; - } - } - - s = p ? p + 1 : NULL; - } - return -1; - } - - while(*kexp && (*kexp)->name) { - s = kex_agree_instr(kex, kex_len, - (unsigned char *) (*kexp)->name, - strlen((*kexp)->name)); - if(s) { - /* We've agreed on a key exchange method, - * Can we agree on a hostkey that works with this kex? - */ - if(kex_agree_hostkey(session, (*kexp)->flags, hostkey, - hostkey_len) == 0) { - session->kex = *kexp; - if(session->burn_optimistic_kexinit && (kex == s)) { - /* Server sent an optimistic packet, and client agrees - * with preference cancel burning the first KEX_INIT - * packet that comes in */ - session->burn_optimistic_kexinit = 0; - } - return 0; - } - } - kexp++; - } - return -1; -} - - - -/* kex_agree_crypt - * Agree on a cipher algo - */ -static int kex_agree_crypt(LIBSSH2_SESSION * session, - libssh2_endpoint_data *endpoint, - unsigned char *crypt, - unsigned long crypt_len) -{ - const LIBSSH2_CRYPT_METHOD **cryptp = libssh2_crypt_methods(); - unsigned char *s; - - (void) session; - - if(endpoint->crypt_prefs) { - s = (unsigned char *) endpoint->crypt_prefs; - - while(s && *s) { - unsigned char *p = (unsigned char *) strchr((char *) s, ','); - size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s)); - - if(kex_agree_instr(crypt, crypt_len, s, method_len)) { - const LIBSSH2_CRYPT_METHOD *method = - (const LIBSSH2_CRYPT_METHOD *) - kex_get_method_by_name((char *) s, method_len, - (const LIBSSH2_COMMON_METHOD **) - cryptp); - - if(!method) { - /* Invalid method -- Should never be reached */ - return -1; - } - - endpoint->crypt = method; - return 0; - } - - s = p ? p + 1 : NULL; - } - return -1; - } - - while(*cryptp && (*cryptp)->name) { - s = kex_agree_instr(crypt, crypt_len, - (unsigned char *) (*cryptp)->name, - strlen((*cryptp)->name)); - if(s) { - endpoint->crypt = *cryptp; - return 0; - } - cryptp++; - } - - return -1; -} - - - -/* kex_agree_mac - * Agree on a message authentication hash - */ -static int kex_agree_mac(LIBSSH2_SESSION * session, - libssh2_endpoint_data * endpoint, unsigned char *mac, - unsigned long mac_len) -{ - const LIBSSH2_MAC_METHOD **macp = _libssh2_mac_methods(); - unsigned char *s; - (void) session; - - if(endpoint->mac_prefs) { - s = (unsigned char *) endpoint->mac_prefs; - - while(s && *s) { - unsigned char *p = (unsigned char *) strchr((char *) s, ','); - size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s)); - - if(kex_agree_instr(mac, mac_len, s, method_len)) { - const LIBSSH2_MAC_METHOD *method = (const LIBSSH2_MAC_METHOD *) - kex_get_method_by_name((char *) s, method_len, - (const LIBSSH2_COMMON_METHOD **) - macp); - - if(!method) { - /* Invalid method -- Should never be reached */ - return -1; - } - - endpoint->mac = method; - return 0; - } - - s = p ? p + 1 : NULL; - } - return -1; - } - - while(*macp && (*macp)->name) { - s = kex_agree_instr(mac, mac_len, (unsigned char *) (*macp)->name, - strlen((*macp)->name)); - if(s) { - endpoint->mac = *macp; - return 0; - } - macp++; - } - - return -1; -} - - - -/* kex_agree_comp - * Agree on a compression scheme - */ -static int kex_agree_comp(LIBSSH2_SESSION *session, - libssh2_endpoint_data *endpoint, unsigned char *comp, - unsigned long comp_len) -{ - const LIBSSH2_COMP_METHOD **compp = _libssh2_comp_methods(session); - unsigned char *s; - (void) session; - - if(endpoint->comp_prefs) { - s = (unsigned char *) endpoint->comp_prefs; - - while(s && *s) { - unsigned char *p = (unsigned char *) strchr((char *) s, ','); - size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s)); - - if(kex_agree_instr(comp, comp_len, s, method_len)) { - const LIBSSH2_COMP_METHOD *method = - (const LIBSSH2_COMP_METHOD *) - kex_get_method_by_name((char *) s, method_len, - (const LIBSSH2_COMMON_METHOD **) - compp); - - if(!method) { - /* Invalid method -- Should never be reached */ - return -1; - } - - endpoint->comp = method; - return 0; - } - - s = p ? p + 1 : NULL; - } - return -1; - } - - while(*compp && (*compp)->name) { - s = kex_agree_instr(comp, comp_len, (unsigned char *) (*compp)->name, - strlen((*compp)->name)); - if(s) { - endpoint->comp = *compp; - return 0; - } - compp++; - } - - return -1; -} - - -/* TODO: When in server mode we need to turn this logic on its head - * The Client gets to make the final call on "agreed methods" - */ - -/* kex_agree_methods - * Decide which specific method to use of the methods offered by each party - */ -static int kex_agree_methods(LIBSSH2_SESSION * session, unsigned char *data, - unsigned data_len) -{ - unsigned char *kex, *hostkey, *crypt_cs, *crypt_sc, *comp_cs, *comp_sc, - *mac_cs, *mac_sc; - size_t kex_len, hostkey_len, crypt_cs_len, crypt_sc_len, comp_cs_len; - size_t comp_sc_len, mac_cs_len, mac_sc_len; - struct string_buf buf; - - if(data_len < 17) - return -1; - - buf.data = (unsigned char *)data; - buf.len = data_len; - buf.dataptr = buf.data; - buf.dataptr++; /* advance past packet type */ - - /* Skip cookie, don't worry, it's preserved in the kexinit field */ - buf.dataptr += 16; - - /* Locate each string */ - if(_libssh2_get_string(&buf, &kex, &kex_len)) - return -1; - if(_libssh2_get_string(&buf, &hostkey, &hostkey_len)) - return -1; - if(_libssh2_get_string(&buf, &crypt_cs, &crypt_cs_len)) - return -1; - if(_libssh2_get_string(&buf, &crypt_sc, &crypt_sc_len)) - return -1; - if(_libssh2_get_string(&buf, &mac_cs, &mac_cs_len)) - return -1; - if(_libssh2_get_string(&buf, &mac_sc, &mac_sc_len)) - return -1; - if(_libssh2_get_string(&buf, &comp_cs, &comp_cs_len)) - return -1; - if(_libssh2_get_string(&buf, &comp_sc, &comp_sc_len)) - return -1; - - /* If the server sent an optimistic packet, assume that it guessed wrong. - * If the guess is determined to be right (by kex_agree_kex_hostkey) - * This flag will be reset to zero so that it's not ignored */ - if(_libssh2_check_length(&buf, 1)) { - session->burn_optimistic_kexinit = *(buf.dataptr++); - } - else { - return -1; - } - - /* Next uint32 in packet is all zeros (reserved) */ - - if(kex_agree_kex_hostkey(session, kex, kex_len, hostkey, hostkey_len)) { - return -1; - } - - if(kex_agree_crypt(session, &session->local, crypt_cs, crypt_cs_len) - || kex_agree_crypt(session, &session->remote, crypt_sc, - crypt_sc_len)) { - return -1; - } - - if(kex_agree_mac(session, &session->local, mac_cs, mac_cs_len) || - kex_agree_mac(session, &session->remote, mac_sc, mac_sc_len)) { - return -1; - } - - if(kex_agree_comp(session, &session->local, comp_cs, comp_cs_len) || - kex_agree_comp(session, &session->remote, comp_sc, comp_sc_len)) { - return -1; - } - -#if 0 - if(libssh2_kex_agree_lang(session, &session->local, lang_cs, lang_cs_len) - || libssh2_kex_agree_lang(session, &session->remote, lang_sc, - lang_sc_len)) { - return -1; - } -#endif - - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on KEX method: %s", - session->kex->name); - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on HOSTKEY method: %s", - session->hostkey->name); - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on CRYPT_CS method: %s", - session->local.crypt->name); - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on CRYPT_SC method: %s", - session->remote.crypt->name); - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on MAC_CS method: %s", - session->local.mac->name); - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on MAC_SC method: %s", - session->remote.mac->name); - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on COMP_CS method: %s", - session->local.comp->name); - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on COMP_SC method: %s", - session->remote.comp->name); - - return 0; -} - - - -/* _libssh2_kex_exchange - * Exchange keys - * Returns 0 on success, non-zero on failure - * - * Returns some errors without _libssh2_error() - */ -int -_libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange, - key_exchange_state_t * key_state) -{ - int rc = 0; - int retcode; - - session->state |= LIBSSH2_STATE_KEX_ACTIVE; - - if(key_state->state == libssh2_NB_state_idle) { - /* Prevent loop in packet_add() */ - session->state |= LIBSSH2_STATE_EXCHANGING_KEYS; - - if(reexchange) { - session->kex = NULL; - - if(session->hostkey && session->hostkey->dtor) { - session->hostkey->dtor(session, - &session->server_hostkey_abstract); - } - session->hostkey = NULL; - } - - key_state->state = libssh2_NB_state_created; - } - - if(!session->kex || !session->hostkey) { - if(key_state->state == libssh2_NB_state_created) { - /* Preserve in case of failure */ - key_state->oldlocal = session->local.kexinit; - key_state->oldlocal_len = session->local.kexinit_len; - - session->local.kexinit = NULL; - - key_state->state = libssh2_NB_state_sent; - } - - if(key_state->state == libssh2_NB_state_sent) { - retcode = kexinit(session); - if(retcode == LIBSSH2_ERROR_EAGAIN) { - session->state &= ~LIBSSH2_STATE_KEX_ACTIVE; - return retcode; - } - else if(retcode) { - session->local.kexinit = key_state->oldlocal; - session->local.kexinit_len = key_state->oldlocal_len; - key_state->state = libssh2_NB_state_idle; - session->state &= ~LIBSSH2_STATE_KEX_ACTIVE; - session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS; - return -1; - } - - key_state->state = libssh2_NB_state_sent1; - } - - if(key_state->state == libssh2_NB_state_sent1) { - retcode = - _libssh2_packet_require(session, SSH_MSG_KEXINIT, - &key_state->data, - &key_state->data_len, 0, NULL, 0, - &key_state->req_state); - if(retcode == LIBSSH2_ERROR_EAGAIN) { - session->state &= ~LIBSSH2_STATE_KEX_ACTIVE; - return retcode; - } - else if(retcode) { - if(session->local.kexinit) { - LIBSSH2_FREE(session, session->local.kexinit); - } - session->local.kexinit = key_state->oldlocal; - session->local.kexinit_len = key_state->oldlocal_len; - key_state->state = libssh2_NB_state_idle; - session->state &= ~LIBSSH2_STATE_KEX_ACTIVE; - session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS; - return -1; - } - - if(session->remote.kexinit) { - LIBSSH2_FREE(session, session->remote.kexinit); - } - session->remote.kexinit = key_state->data; - session->remote.kexinit_len = key_state->data_len; - - if(kex_agree_methods(session, key_state->data, - key_state->data_len)) - rc = LIBSSH2_ERROR_KEX_FAILURE; - - key_state->state = libssh2_NB_state_sent2; - } - } - else { - key_state->state = libssh2_NB_state_sent2; - } - - if(rc == 0 && session->kex) { - if(key_state->state == libssh2_NB_state_sent2) { - retcode = session->kex->exchange_keys(session, - &key_state->key_state_low); - if(retcode == LIBSSH2_ERROR_EAGAIN) { - session->state &= ~LIBSSH2_STATE_KEX_ACTIVE; - return retcode; - } - else if(retcode) { - rc = _libssh2_error(session, - LIBSSH2_ERROR_KEY_EXCHANGE_FAILURE, - "Unrecoverable error exchanging keys"); - } - } - } - - /* Done with kexinit buffers */ - if(session->local.kexinit) { - LIBSSH2_FREE(session, session->local.kexinit); - session->local.kexinit = NULL; - } - if(session->remote.kexinit) { - LIBSSH2_FREE(session, session->remote.kexinit); - session->remote.kexinit = NULL; - } - - session->state &= ~LIBSSH2_STATE_KEX_ACTIVE; - session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS; - - key_state->state = libssh2_NB_state_idle; - - return rc; -} - - - -/* libssh2_session_method_pref - * Set preferred method - */ -LIBSSH2_API int -libssh2_session_method_pref(LIBSSH2_SESSION * session, int method_type, - const char *prefs) -{ - char **prefvar, *s, *newprefs; - int prefs_len = strlen(prefs); - const LIBSSH2_COMMON_METHOD **mlist; - - switch(method_type) { - case LIBSSH2_METHOD_KEX: - prefvar = &session->kex_prefs; - mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_kex_methods; - break; - - case LIBSSH2_METHOD_HOSTKEY: - prefvar = &session->hostkey_prefs; - mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_hostkey_methods(); - break; - - case LIBSSH2_METHOD_CRYPT_CS: - prefvar = &session->local.crypt_prefs; - mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_crypt_methods(); - break; - - case LIBSSH2_METHOD_CRYPT_SC: - prefvar = &session->remote.crypt_prefs; - mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_crypt_methods(); - break; - - case LIBSSH2_METHOD_MAC_CS: - prefvar = &session->local.mac_prefs; - mlist = (const LIBSSH2_COMMON_METHOD **) _libssh2_mac_methods(); - break; - - case LIBSSH2_METHOD_MAC_SC: - prefvar = &session->remote.mac_prefs; - mlist = (const LIBSSH2_COMMON_METHOD **) _libssh2_mac_methods(); - break; - - case LIBSSH2_METHOD_COMP_CS: - prefvar = &session->local.comp_prefs; - mlist = (const LIBSSH2_COMMON_METHOD **) - _libssh2_comp_methods(session); - break; - - case LIBSSH2_METHOD_COMP_SC: - prefvar = &session->remote.comp_prefs; - mlist = (const LIBSSH2_COMMON_METHOD **) - _libssh2_comp_methods(session); - break; - - case LIBSSH2_METHOD_LANG_CS: - prefvar = &session->local.lang_prefs; - mlist = NULL; - break; - - case LIBSSH2_METHOD_LANG_SC: - prefvar = &session->remote.lang_prefs; - mlist = NULL; - break; - - default: - return _libssh2_error(session, LIBSSH2_ERROR_INVAL, - "Invalid parameter specified for method_type"); - } - - s = newprefs = LIBSSH2_ALLOC(session, prefs_len + 1); - if(!newprefs) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Error allocated space for method preferences"); - } - memcpy(s, prefs, prefs_len + 1); - - while(s && *s && mlist) { - char *p = strchr(s, ','); - int method_len = p ? (p - s) : (int) strlen(s); - - if(!kex_get_method_by_name(s, method_len, mlist)) { - /* Strip out unsupported method */ - if(p) { - memcpy(s, p + 1, strlen(s) - method_len); - } - else { - if(s > newprefs) { - *(--s) = '\0'; - } - else { - *s = '\0'; - } - } - } - else { - s = p ? (p + 1) : NULL; - } - } - - if(!*newprefs) { - LIBSSH2_FREE(session, newprefs); - return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "The requested method(s) are not currently " - "supported"); - } - - if(*prefvar) { - LIBSSH2_FREE(session, *prefvar); - } - *prefvar = newprefs; - - return 0; -} - -/* - * libssh2_session_supported_algs() - * returns a number of returned algorithms (a positive number) on success, - * a negative number on failure - */ - -LIBSSH2_API int libssh2_session_supported_algs(LIBSSH2_SESSION* session, - int method_type, - const char ***algs) -{ - unsigned int i; - unsigned int j; - unsigned int ialg; - const LIBSSH2_COMMON_METHOD **mlist; - - /* to prevent coredumps due to dereferencing of NULL */ - if(NULL == algs) - return _libssh2_error(session, LIBSSH2_ERROR_BAD_USE, - "algs must not be NULL"); - - switch(method_type) { - case LIBSSH2_METHOD_KEX: - mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_kex_methods; - break; - - case LIBSSH2_METHOD_HOSTKEY: - mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_hostkey_methods(); - break; - - case LIBSSH2_METHOD_CRYPT_CS: - case LIBSSH2_METHOD_CRYPT_SC: - mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_crypt_methods(); - break; - - case LIBSSH2_METHOD_MAC_CS: - case LIBSSH2_METHOD_MAC_SC: - mlist = (const LIBSSH2_COMMON_METHOD **) _libssh2_mac_methods(); - break; - - case LIBSSH2_METHOD_COMP_CS: - case LIBSSH2_METHOD_COMP_SC: - mlist = (const LIBSSH2_COMMON_METHOD **) - _libssh2_comp_methods(session); - break; - - default: - return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Unknown method type"); - } /* switch */ - - /* weird situation */ - if(NULL == mlist) - return _libssh2_error(session, LIBSSH2_ERROR_INVAL, - "No algorithm found"); - - /* - mlist is looped through twice. The first time to find the number od - supported algorithms (needed to allocate the proper size of array) and - the second time to actually copy the pointers. Typically this function - will not be called often (typically at the beginning of a session) and - the number of algorithms (i.e. niumber of iterations in one loop) will - not be high (typically it will not exceed 20) for quite a long time. - - So double looping really shouldn't be an issue and it is definitely a - better solution than reallocation several times. - */ - - /* count the number of supported algorithms */ - for(i = 0, ialg = 0; NULL != mlist[i]; i++) { - /* do not count fields with NULL name */ - if(mlist[i]->name) - ialg++; - } - - /* weird situation, no algorithm found */ - if(0 == ialg) - return _libssh2_error(session, LIBSSH2_ERROR_INVAL, - "No algorithm found"); - - /* allocate buffer */ - *algs = (const char **) LIBSSH2_ALLOC(session, ialg*sizeof(const char *)); - if(NULL == *algs) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Memory allocation failed"); - } - /* Past this point *algs must be deallocated in case of an error!! */ - - /* copy non-NULL pointers only */ - for(i = 0, j = 0; NULL != mlist[i] && j < ialg; i++) { - if(NULL == mlist[i]->name) { - /* maybe a weird situation but if it occurs, do not include NULL - pointers */ - continue; - } - - /* note that [] has higher priority than * (dereferencing) */ - (*algs)[j++] = mlist[i]->name; - } - - /* correct number of pointers copied? (test the code above) */ - if(j != ialg) { - /* deallocate buffer */ - LIBSSH2_FREE(session, (void *)*algs); - *algs = NULL; - - return _libssh2_error(session, LIBSSH2_ERROR_BAD_USE, - "Internal error"); - } - - return ialg; -} diff --git a/libssh2/knownhost.c b/libssh2/knownhost.c deleted file mode 100644 index 77798fb..0000000 --- a/libssh2/knownhost.c +++ /dev/null @@ -1,1271 +0,0 @@ -/* - * Copyright (c) 2009-2019 by Daniel Stenberg - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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 "libssh2_priv.h" -#include "misc.h" - -struct known_host { - struct list_node node; - char *name; /* points to the name or the hash (allocated) */ - size_t name_len; /* needed for hashed data */ - int port; /* if non-zero, a specific port this key is for on this - host */ - int typemask; /* plain, sha1, custom, ... */ - char *salt; /* points to binary salt (allocated) */ - size_t salt_len; /* size of salt */ - char *key; /* the (allocated) associated key. This is kept base64 - encoded in memory. */ - char *key_type_name; /* the (allocated) key type name */ - size_t key_type_len; /* size of key_type_name */ - char *comment; /* the (allocated) optional comment text, may be - NULL */ - size_t comment_len; /* the size of comment */ - - /* this is the struct we expose externally */ - struct libssh2_knownhost external; -}; - -struct _LIBSSH2_KNOWNHOSTS -{ - LIBSSH2_SESSION *session; /* the session this "belongs to" */ - struct list_head head; -}; - -static void free_host(LIBSSH2_SESSION *session, struct known_host *entry) -{ - if(entry) { - if(entry->comment) - LIBSSH2_FREE(session, entry->comment); - if(entry->key_type_name) - LIBSSH2_FREE(session, entry->key_type_name); - if(entry->key) - LIBSSH2_FREE(session, entry->key); - if(entry->salt) - LIBSSH2_FREE(session, entry->salt); - if(entry->name) - LIBSSH2_FREE(session, entry->name); - LIBSSH2_FREE(session, entry); - } -} - -/* - * libssh2_knownhost_init - * - * Init a collection of known hosts. Returns the pointer to a collection. - * - */ -LIBSSH2_API LIBSSH2_KNOWNHOSTS * -libssh2_knownhost_init(LIBSSH2_SESSION *session) -{ - LIBSSH2_KNOWNHOSTS *knh = - LIBSSH2_ALLOC(session, sizeof(struct _LIBSSH2_KNOWNHOSTS)); - - if(!knh) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for known-hosts " - "collection"); - return NULL; - } - - knh->session = session; - - _libssh2_list_init(&knh->head); - - return knh; -} - -#define KNOWNHOST_MAGIC 0xdeadcafe -/* - * knownhost_to_external() - * - * Copies data from the internal to the external representation struct. - * - */ -static struct libssh2_knownhost *knownhost_to_external(struct known_host *node) -{ - struct libssh2_knownhost *ext = &node->external; - - ext->magic = KNOWNHOST_MAGIC; - ext->node = node; - ext->name = ((node->typemask & LIBSSH2_KNOWNHOST_TYPE_MASK) == - LIBSSH2_KNOWNHOST_TYPE_PLAIN)? node->name:NULL; - ext->key = node->key; - ext->typemask = node->typemask; - - return ext; -} - -static int -knownhost_add(LIBSSH2_KNOWNHOSTS *hosts, - const char *host, const char *salt, - const char *key_type_name, size_t key_type_len, - const char *key, size_t keylen, - const char *comment, size_t commentlen, - int typemask, struct libssh2_knownhost **store) -{ - struct known_host *entry; - size_t hostlen = strlen(host); - int rc; - char *ptr; - unsigned int ptrlen; - - /* make sure we have a key type set */ - if(!(typemask & LIBSSH2_KNOWNHOST_KEY_MASK)) - return _libssh2_error(hosts->session, LIBSSH2_ERROR_INVAL, - "No key type set"); - - entry = LIBSSH2_CALLOC(hosts->session, sizeof(struct known_host)); - if(!entry) - return _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for known host " - "entry"); - - entry->typemask = typemask; - - switch(entry->typemask & LIBSSH2_KNOWNHOST_TYPE_MASK) { - case LIBSSH2_KNOWNHOST_TYPE_PLAIN: - case LIBSSH2_KNOWNHOST_TYPE_CUSTOM: - entry->name = LIBSSH2_ALLOC(hosts->session, hostlen + 1); - if(!entry->name) { - rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for host name"); - goto error; - } - memcpy(entry->name, host, hostlen + 1); - entry->name_len = hostlen; - break; - case LIBSSH2_KNOWNHOST_TYPE_SHA1: - rc = libssh2_base64_decode(hosts->session, &ptr, &ptrlen, - host, hostlen); - if(rc) - goto error; - entry->name = ptr; - entry->name_len = ptrlen; - - rc = libssh2_base64_decode(hosts->session, &ptr, &ptrlen, - salt, strlen(salt)); - if(rc) - goto error; - entry->salt = ptr; - entry->salt_len = ptrlen; - break; - default: - rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Unknown host name type"); - goto error; - } - - if(typemask & LIBSSH2_KNOWNHOST_KEYENC_BASE64) { - /* the provided key is base64 encoded already */ - if(!keylen) - keylen = strlen(key); - entry->key = LIBSSH2_ALLOC(hosts->session, keylen + 1); - if(!entry->key) { - rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for key"); - goto error; - } - memcpy(entry->key, key, keylen + 1); - entry->key[keylen] = 0; /* force a terminating zero trailer */ - } - else { - /* key is raw, we base64 encode it and store it as such */ - size_t nlen = _libssh2_base64_encode(hosts->session, key, keylen, - &ptr); - if(!nlen) { - rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "base64-encoded key"); - goto error; - } - - entry->key = ptr; - } - - if(key_type_name && ((typemask & LIBSSH2_KNOWNHOST_KEY_MASK) == - LIBSSH2_KNOWNHOST_KEY_UNKNOWN)) { - entry->key_type_name = LIBSSH2_ALLOC(hosts->session, key_type_len + 1); - if(!entry->key_type_name) { - rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for key type"); - goto error; - } - memcpy(entry->key_type_name, key_type_name, key_type_len); - entry->key_type_name[key_type_len] = 0; - entry->key_type_len = key_type_len; - } - - if(comment) { - entry->comment = LIBSSH2_ALLOC(hosts->session, commentlen + 1); - if(!entry->comment) { - rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for comment"); - goto error; - } - memcpy(entry->comment, comment, commentlen + 1); - entry->comment[commentlen] = 0; /* force a terminating zero trailer */ - entry->comment_len = commentlen; - } - else { - entry->comment = NULL; - } - - /* add this new host to the big list of known hosts */ - _libssh2_list_add(&hosts->head, &entry->node); - - if(store) - *store = knownhost_to_external(entry); - - return LIBSSH2_ERROR_NONE; - error: - free_host(hosts->session, entry); - return rc; -} - -/* - * libssh2_knownhost_add - * - * Add a host and its associated key to the collection of known hosts. - * - * The 'type' argument specifies on what format the given host and keys are: - * - * plain - ascii "hostname.domain.tld" - * sha1 - SHA1( ) base64-encoded! - * custom - another hash - * - * If 'sha1' is selected as type, the salt must be provided to the salt - * argument. This too base64 encoded. - * - * The SHA-1 hash is what OpenSSH can be told to use in known_hosts files. If - * a custom type is used, salt is ignored and you must provide the host - * pre-hashed when checking for it in the libssh2_knownhost_check() function. - * - * The keylen parameter may be omitted (zero) if the key is provided as a - * NULL-terminated base64-encoded string. - */ - -LIBSSH2_API int -libssh2_knownhost_add(LIBSSH2_KNOWNHOSTS *hosts, - const char *host, const char *salt, - const char *key, size_t keylen, - int typemask, struct libssh2_knownhost **store) -{ - return knownhost_add(hosts, host, salt, NULL, 0, key, keylen, NULL, - 0, typemask, store); -} - - -/* - * libssh2_knownhost_addc - * - * Add a host and its associated key to the collection of known hosts. - * - * Takes a comment argument that may be NULL. A NULL comment indicates - * there is no comment and the entry will end directly after the key - * when written out to a file. An empty string "" comment will indicate an - * empty comment which will cause a single space to be written after the key. - * - * The 'type' argument specifies on what format the given host and keys are: - * - * plain - ascii "hostname.domain.tld" - * sha1 - SHA1( ) base64-encoded! - * custom - another hash - * - * If 'sha1' is selected as type, the salt must be provided to the salt - * argument. This too base64 encoded. - * - * The SHA-1 hash is what OpenSSH can be told to use in known_hosts files. If - * a custom type is used, salt is ignored and you must provide the host - * pre-hashed when checking for it in the libssh2_knownhost_check() function. - * - * The keylen parameter may be omitted (zero) if the key is provided as a - * NULL-terminated base64-encoded string. - */ - -LIBSSH2_API int -libssh2_knownhost_addc(LIBSSH2_KNOWNHOSTS *hosts, - const char *host, const char *salt, - const char *key, size_t keylen, - const char *comment, size_t commentlen, - int typemask, struct libssh2_knownhost **store) -{ - return knownhost_add(hosts, host, salt, NULL, 0, key, keylen, - comment, commentlen, typemask, store); -} - -/* - * knownhost_check - * - * Check a host and its associated key against the collection of known hosts. - * - * The typemask is the type/format of the given host name and key - * - * plain - ascii "hostname.domain.tld" - * sha1 - NOT SUPPORTED AS INPUT - * custom - prehashed base64 encoded. Note that this cannot use any salts. - * - * Returns: - * - * LIBSSH2_KNOWNHOST_CHECK_FAILURE - * LIBSSH2_KNOWNHOST_CHECK_NOTFOUND - * LIBSSH2_KNOWNHOST_CHECK_MATCH - * LIBSSH2_KNOWNHOST_CHECK_MISMATCH - */ -static int -knownhost_check(LIBSSH2_KNOWNHOSTS *hosts, - const char *hostp, int port, - const char *key, size_t keylen, - int typemask, - struct libssh2_knownhost **ext) -{ - struct known_host *node; - struct known_host *badkey = NULL; - int type = typemask & LIBSSH2_KNOWNHOST_TYPE_MASK; - char *keyalloc = NULL; - int rc = LIBSSH2_KNOWNHOST_CHECK_NOTFOUND; - char hostbuff[270]; /* most host names can't be longer than like 256 */ - const char *host; - int numcheck; /* number of host combos to check */ - int match = 0; - - if(type == LIBSSH2_KNOWNHOST_TYPE_SHA1) - /* we can't work with a sha1 as given input */ - return LIBSSH2_KNOWNHOST_CHECK_MISMATCH; - - /* if a port number is given, check for a '[host]:port' first before the - plain 'host' */ - if(port >= 0) { - int len = snprintf(hostbuff, sizeof(hostbuff), "[%s]:%d", hostp, port); - if(len < 0 || len >= (int)sizeof(hostbuff)) { - _libssh2_error(hosts->session, - LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "Known-host write buffer too small"); - return LIBSSH2_KNOWNHOST_CHECK_FAILURE; - } - host = hostbuff; - numcheck = 2; /* check both combos, start with this */ - } - else { - host = hostp; - numcheck = 1; /* only check this host version */ - } - - if(!(typemask & LIBSSH2_KNOWNHOST_KEYENC_BASE64)) { - /* we got a raw key input, convert it to base64 for the checks below */ - size_t nlen = _libssh2_base64_encode(hosts->session, key, keylen, - &keyalloc); - if(!nlen) { - _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for base64-encoded " - "key"); - return LIBSSH2_KNOWNHOST_CHECK_FAILURE; - } - - /* make the key point to this */ - key = keyalloc; - } - - do { - node = _libssh2_list_first(&hosts->head); - while(node) { - switch(node->typemask & LIBSSH2_KNOWNHOST_TYPE_MASK) { - case LIBSSH2_KNOWNHOST_TYPE_PLAIN: - if(type == LIBSSH2_KNOWNHOST_TYPE_PLAIN) - match = !strcmp(host, node->name); - break; - case LIBSSH2_KNOWNHOST_TYPE_CUSTOM: - if(type == LIBSSH2_KNOWNHOST_TYPE_CUSTOM) - match = !strcmp(host, node->name); - break; - case LIBSSH2_KNOWNHOST_TYPE_SHA1: - if(type == LIBSSH2_KNOWNHOST_TYPE_PLAIN) { - /* when we have the sha1 version stored, we can use a - plain input to produce a hash to compare with the - stored hash. - */ - unsigned char hash[SHA_DIGEST_LENGTH]; - libssh2_hmac_ctx ctx; - libssh2_hmac_ctx_init(ctx); - - if(SHA_DIGEST_LENGTH != node->name_len) { - /* the name hash length must be the sha1 size or - we can't match it */ - break; - } - libssh2_hmac_sha1_init(&ctx, (unsigned char *)node->salt, - node->salt_len); - libssh2_hmac_update(ctx, (unsigned char *)host, - strlen(host)); - libssh2_hmac_final(ctx, hash); - libssh2_hmac_cleanup(&ctx); - - if(!memcmp(hash, node->name, SHA_DIGEST_LENGTH)) - /* this is a node we're interested in */ - match = 1; - } - break; - default: /* unsupported type */ - break; - } - if(match) { - int host_key_type = typemask & LIBSSH2_KNOWNHOST_KEY_MASK; - int known_key_type = - node->typemask & LIBSSH2_KNOWNHOST_KEY_MASK; - /* match on key type as follows: - - never match on an unknown key type - - if key_type is set to zero, ignore it an match always - - otherwise match when both key types are equal - */ - if(host_key_type != LIBSSH2_KNOWNHOST_KEY_UNKNOWN && - (host_key_type == 0 || - host_key_type == known_key_type)) { - /* host name and key type match, now compare the keys */ - if(!strcmp(key, node->key)) { - /* they match! */ - if(ext) - *ext = knownhost_to_external(node); - badkey = NULL; - rc = LIBSSH2_KNOWNHOST_CHECK_MATCH; - break; - } - else { - /* remember the first node that had a host match but a - failed key match since we continue our search from - here */ - if(!badkey) - badkey = node; - } - } - match = 0; /* don't count this as a match anymore */ - } - node = _libssh2_list_next(&node->node); - } - host = hostp; - } while(!match && --numcheck); - - if(badkey) { - /* key mismatch */ - if(ext) - *ext = knownhost_to_external(badkey); - rc = LIBSSH2_KNOWNHOST_CHECK_MISMATCH; - } - - if(keyalloc) - LIBSSH2_FREE(hosts->session, keyalloc); - - return rc; -} - -/* - * libssh2_knownhost_check - * - * Check a host and its associated key against the collection of known hosts. - * - * The typemask is the type/format of the given host name and key - * - * plain - ascii "hostname.domain.tld" - * sha1 - NOT SUPPORTED AS INPUT - * custom - prehashed base64 encoded. Note that this cannot use any salts. - * - * Returns: - * - * LIBSSH2_KNOWNHOST_CHECK_FAILURE - * LIBSSH2_KNOWNHOST_CHECK_NOTFOUND - * LIBSSH2_KNOWNHOST_CHECK_MATCH - * LIBSSH2_KNOWNHOST_CHECK_MISMATCH - */ -LIBSSH2_API int -libssh2_knownhost_check(LIBSSH2_KNOWNHOSTS *hosts, - const char *hostp, const char *key, size_t keylen, - int typemask, - struct libssh2_knownhost **ext) -{ - return knownhost_check(hosts, hostp, -1, key, keylen, - typemask, ext); -} - -/* - * libssh2_knownhost_checkp - * - * Check a host+port and its associated key against the collection of known - * hosts. - * - * Note that if 'port' is specified as greater than zero, the check function - * will be able to check for a dedicated key for this particular host+port - * combo, and if 'port' is negative it only checks for the generic host key. - * - * The typemask is the type/format of the given host name and key - * - * plain - ascii "hostname.domain.tld" - * sha1 - NOT SUPPORTED AS INPUT - * custom - prehashed base64 encoded. Note that this cannot use any salts. - * - * Returns: - * - * LIBSSH2_KNOWNHOST_CHECK_FAILURE - * LIBSSH2_KNOWNHOST_CHECK_NOTFOUND - * LIBSSH2_KNOWNHOST_CHECK_MATCH - * LIBSSH2_KNOWNHOST_CHECK_MISMATCH - */ -LIBSSH2_API int -libssh2_knownhost_checkp(LIBSSH2_KNOWNHOSTS *hosts, - const char *hostp, int port, - const char *key, size_t keylen, - int typemask, - struct libssh2_knownhost **ext) -{ - return knownhost_check(hosts, hostp, port, key, keylen, - typemask, ext); -} - - -/* - * libssh2_knownhost_del - * - * Remove a host from the collection of known hosts. - * - */ -LIBSSH2_API int -libssh2_knownhost_del(LIBSSH2_KNOWNHOSTS *hosts, - struct libssh2_knownhost *entry) -{ - struct known_host *node; - - /* check that this was retrieved the right way or get out */ - if(!entry || (entry->magic != KNOWNHOST_MAGIC)) - return _libssh2_error(hosts->session, LIBSSH2_ERROR_INVAL, - "Invalid host information"); - - /* get the internal node pointer */ - node = entry->node; - - /* unlink from the list of all hosts */ - _libssh2_list_remove(&node->node); - - /* clear the struct now since the memory in which it is allocated is - about to be freed! */ - memset(entry, 0, sizeof(struct libssh2_knownhost)); - - /* free all resources */ - free_host(hosts->session, node); - - return 0; -} - -/* - * libssh2_knownhost_free - * - * Free an entire collection of known hosts. - * - */ -LIBSSH2_API void -libssh2_knownhost_free(LIBSSH2_KNOWNHOSTS *hosts) -{ - struct known_host *node; - struct known_host *next; - - for(node = _libssh2_list_first(&hosts->head); node; node = next) { - next = _libssh2_list_next(&node->node); - free_host(hosts->session, node); - } - LIBSSH2_FREE(hosts->session, hosts); -} - - -/* old style plain text: [name]([,][name])* - - for the sake of simplicity, we add them as separate hosts with the same - key -*/ -static int oldstyle_hostline(LIBSSH2_KNOWNHOSTS *hosts, - const char *host, size_t hostlen, - const char *key_type_name, size_t key_type_len, - const char *key, size_t keylen, int key_type, - const char *comment, size_t commentlen) -{ - int rc = 0; - size_t namelen = 0; - const char *name = host + hostlen; - - if(hostlen < 1) - return _libssh2_error(hosts->session, - LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Failed to parse known_hosts line " - "(no host names)"); - - while(name > host) { - --name; - ++namelen; - - /* when we get the the start or see a comma coming up, add the host - name to the collection */ - if((name == host) || (*(name-1) == ',')) { - - char hostbuf[256]; - - /* make sure we don't overflow the buffer */ - if(namelen >= sizeof(hostbuf)-1) - return _libssh2_error(hosts->session, - LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Failed to parse known_hosts line " - "(unexpected length)"); - - /* copy host name to the temp buffer and zero terminate */ - memcpy(hostbuf, name, namelen); - hostbuf[namelen] = 0; - - rc = knownhost_add(hosts, hostbuf, NULL, - key_type_name, key_type_len, - key, keylen, - comment, commentlen, - key_type | LIBSSH2_KNOWNHOST_TYPE_PLAIN | - LIBSSH2_KNOWNHOST_KEYENC_BASE64, NULL); - if(rc) - return rc; - - if(name > host) { - namelen = 0; - --name; /* skip comma */ - } - } - } - - return rc; -} - -/* |1|[salt]|[hash] */ -static int hashed_hostline(LIBSSH2_KNOWNHOSTS *hosts, - const char *host, size_t hostlen, - const char *key_type_name, size_t key_type_len, - const char *key, size_t keylen, int key_type, - const char *comment, size_t commentlen) -{ - const char *p; - char saltbuf[32]; - char hostbuf[256]; - - const char *salt = &host[3]; /* skip the magic marker */ - hostlen -= 3; /* deduct the marker */ - - /* this is where the salt starts, find the end of it */ - for(p = salt; *p && (*p != '|'); p++) - ; - - if(*p == '|') { - const char *hash = NULL; - size_t saltlen = p - salt; - if(saltlen >= (sizeof(saltbuf)-1)) /* weird length */ - return _libssh2_error(hosts->session, - LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Failed to parse known_hosts line " - "(unexpectedly long salt)"); - - memcpy(saltbuf, salt, saltlen); - saltbuf[saltlen] = 0; /* zero terminate */ - salt = saltbuf; /* point to the stack based buffer */ - - hash = p + 1; /* the host hash is after the separator */ - - /* now make the host point to the hash */ - host = hash; - hostlen -= saltlen + 1; /* deduct the salt and separator */ - - /* check that the lengths seem sensible */ - if(hostlen >= sizeof(hostbuf)-1) - return _libssh2_error(hosts->session, - LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Failed to parse known_hosts line " - "(unexpected length)"); - - memcpy(hostbuf, host, hostlen); - hostbuf[hostlen] = 0; - - return knownhost_add(hosts, hostbuf, salt, - key_type_name, key_type_len, - key, keylen, - comment, commentlen, - key_type | LIBSSH2_KNOWNHOST_TYPE_SHA1 | - LIBSSH2_KNOWNHOST_KEYENC_BASE64, NULL); - } - else - return 0; /* XXX: This should be an error, shouldn't it? */ -} - -/* - * hostline() - * - * Parse a single known_host line pre-split into host and key. - * - * The key part may include an optional comment which will be parsed here - * for ssh-rsa and ssh-dsa keys. Comments in other key types aren't handled. - * - * The function assumes new-lines have already been removed from the arguments. - */ -static int hostline(LIBSSH2_KNOWNHOSTS *hosts, - const char *host, size_t hostlen, - const char *key, size_t keylen) -{ - const char *comment = NULL; - const char *key_type_name = NULL; - size_t commentlen = 0; - size_t key_type_len = 0; - int key_type; - - /* make some checks that the lengths seem sensible */ - if(keylen < 20) - return _libssh2_error(hosts->session, - LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Failed to parse known_hosts line " - "(key too short)"); - - switch(key[0]) { - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - key_type = LIBSSH2_KNOWNHOST_KEY_RSA1; - - /* Note that the old-style keys (RSA1) aren't truly base64, but we - * claim it is for now since we can get away with strcmp()ing the - * entire anything anyway! We need to check and fix these to make them - * work properly. - */ - break; - - default: - key_type_name = key; - while(keylen && *key && - (*key != ' ') && (*key != '\t')) { - key++; - keylen--; - } - key_type_len = key - key_type_name; - - if(!strncmp(key_type_name, "ssh-dss", key_type_len)) - key_type = LIBSSH2_KNOWNHOST_KEY_SSHDSS; - else if(!strncmp(key_type_name, "ssh-rsa", key_type_len)) - key_type = LIBSSH2_KNOWNHOST_KEY_SSHRSA; - else if(!strncmp(key_type_name, "ecdsa-sha2-nistp256", key_type_len)) - key_type = LIBSSH2_KNOWNHOST_KEY_ECDSA_256; - else if(!strncmp(key_type_name, "ecdsa-sha2-nistp384", key_type_len)) - key_type = LIBSSH2_KNOWNHOST_KEY_ECDSA_384; - else if(!strncmp(key_type_name, "ecdsa-sha2-nistp521", key_type_len)) - key_type = LIBSSH2_KNOWNHOST_KEY_ECDSA_521; - else if(!strncmp(key_type_name, "ssh-ed25519", key_type_len)) - key_type = LIBSSH2_KNOWNHOST_KEY_ED25519; - else - key_type = LIBSSH2_KNOWNHOST_KEY_UNKNOWN; - - /* skip whitespaces */ - while((*key ==' ') || (*key == '\t')) { - key++; - keylen--; - } - - comment = key; - commentlen = keylen; - - /* move over key */ - while(commentlen && *comment && - (*comment != ' ') && (*comment != '\t')) { - comment++; - commentlen--; - } - - /* reduce key by comment length */ - keylen -= commentlen; - - /* Distinguish empty comment (a space) from no comment (no space) */ - if(commentlen == 0) - comment = NULL; - - /* skip whitespaces */ - while(commentlen && *comment && - ((*comment ==' ') || (*comment == '\t'))) { - comment++; - commentlen--; - } - break; - } - - /* Figure out host format */ - if((hostlen >2) && memcmp(host, "|1|", 3)) { - /* old style plain text: [name]([,][name])* - - for the sake of simplicity, we add them as separate hosts with the - same key - */ - return oldstyle_hostline(hosts, host, hostlen, key_type_name, - key_type_len, key, keylen, key_type, - comment, commentlen); - } - else { - /* |1|[salt]|[hash] */ - return hashed_hostline(hosts, host, hostlen, key_type_name, - key_type_len, key, keylen, key_type, - comment, commentlen); - } -} - -/* - * libssh2_knownhost_readline() - * - * Pass in a line of a file of 'type'. - * - * LIBSSH2_KNOWNHOST_FILE_OPENSSH is the only supported type. - * - * OpenSSH line format: - * - * - * - * Where the two parts can be created like: - * - * can be either - * or - * - * consists of - * [name] optionally followed by [,name] one or more times - * - * consists of - * |1||hash - * - * can be one of: - * [RSA bits] [e] [n as a decimal number] - * 'ssh-dss' [base64-encoded-key] - * 'ssh-rsa' [base64-encoded-key] - * - */ -LIBSSH2_API int -libssh2_knownhost_readline(LIBSSH2_KNOWNHOSTS *hosts, - const char *line, size_t len, int type) -{ - const char *cp; - const char *hostp; - const char *keyp; - size_t hostlen; - size_t keylen; - int rc; - - if(type != LIBSSH2_KNOWNHOST_FILE_OPENSSH) - return _libssh2_error(hosts->session, - LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Unsupported type of known-host information " - "store"); - - cp = line; - - /* skip leading whitespaces */ - while(len && ((*cp == ' ') || (*cp == '\t'))) { - cp++; - len--; - } - - if(!len || !*cp || (*cp == '#') || (*cp == '\n')) - /* comment or empty line */ - return LIBSSH2_ERROR_NONE; - - /* the host part starts here */ - hostp = cp; - - /* move over the host to the separator */ - while(len && *cp && (*cp != ' ') && (*cp != '\t')) { - cp++; - len--; - } - - hostlen = cp - hostp; - - /* the key starts after the whitespaces */ - while(len && *cp && ((*cp == ' ') || (*cp == '\t'))) { - cp++; - len--; - } - - if(!*cp || !len) /* illegal line */ - return _libssh2_error(hosts->session, - LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Failed to parse known_hosts line"); - - keyp = cp; /* the key starts here */ - keylen = len; - - /* check if the line (key) ends with a newline and if so kill it */ - while(len && *cp && (*cp != '\n')) { - cp++; - len--; - } - - /* zero terminate where the newline is */ - if(*cp == '\n') - keylen--; /* don't include this in the count */ - - /* deal with this one host+key line */ - rc = hostline(hosts, hostp, hostlen, keyp, keylen); - if(rc) - return rc; /* failed */ - - return LIBSSH2_ERROR_NONE; /* success */ -} - -/* - * libssh2_knownhost_readfile - * - * Read hosts+key pairs from a given file. - * - * Returns a negative value for error or number of successfully added hosts. - * - */ - -LIBSSH2_API int -libssh2_knownhost_readfile(LIBSSH2_KNOWNHOSTS *hosts, - const char *filename, int type) -{ - FILE *file; - int num = 0; - char buf[4092]; - - if(type != LIBSSH2_KNOWNHOST_FILE_OPENSSH) - return _libssh2_error(hosts->session, - LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Unsupported type of known-host information " - "store"); - - file = fopen(filename, FOPEN_READTEXT); - if(file) { - while(fgets(buf, sizeof(buf), file)) { - if(libssh2_knownhost_readline(hosts, buf, strlen(buf), type)) { - num = _libssh2_error(hosts->session, LIBSSH2_ERROR_KNOWN_HOSTS, - "Failed to parse known hosts file"); - break; - } - num++; - } - fclose(file); - } - else - return _libssh2_error(hosts->session, LIBSSH2_ERROR_FILE, - "Failed to open file"); - - return num; -} - -/* - * knownhost_writeline() - * - * Ask libssh2 to convert a known host to an output line for storage. - * - * Note that this function returns LIBSSH2_ERROR_BUFFER_TOO_SMALL if the given - * output buffer is too small to hold the desired output. The 'outlen' field - * will then contain the size libssh2 wanted to store, which then is the - * smallest sufficient buffer it would require. - * - */ -static int -knownhost_writeline(LIBSSH2_KNOWNHOSTS *hosts, - struct known_host *node, - char *buf, size_t buflen, - size_t *outlen, int type) -{ - size_t required_size; - - const char *key_type_name; - size_t key_type_len; - - /* we only support this single file type for now, bail out on all other - attempts */ - if(type != LIBSSH2_KNOWNHOST_FILE_OPENSSH) - return _libssh2_error(hosts->session, - LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Unsupported type of known-host information " - "store"); - - switch(node->typemask & LIBSSH2_KNOWNHOST_KEY_MASK) { - case LIBSSH2_KNOWNHOST_KEY_RSA1: - key_type_name = NULL; - key_type_len = 0; - break; - case LIBSSH2_KNOWNHOST_KEY_SSHRSA: - key_type_name = "ssh-rsa"; - key_type_len = 7; - break; - case LIBSSH2_KNOWNHOST_KEY_SSHDSS: - key_type_name = "ssh-dss"; - key_type_len = 7; - break; - case LIBSSH2_KNOWNHOST_KEY_ECDSA_256: - key_type_name = "ecdsa-sha2-nistp256"; - key_type_len = 19; - break; - case LIBSSH2_KNOWNHOST_KEY_ECDSA_384: - key_type_name = "ecdsa-sha2-nistp384"; - key_type_len = 19; - break; - case LIBSSH2_KNOWNHOST_KEY_ECDSA_521: - key_type_name = "ecdsa-sha2-nistp521"; - key_type_len = 19; - break; - case LIBSSH2_KNOWNHOST_KEY_ED25519: - key_type_name = "ssh-ed25519"; - key_type_len = 11; - break; - case LIBSSH2_KNOWNHOST_KEY_UNKNOWN: - key_type_name = node->key_type_name; - if(key_type_name) { - key_type_len = node->key_type_len; - break; - } - /* otherwise fallback to default and error */ - /* FALL-THROUGH */ - default: - return _libssh2_error(hosts->session, - LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Unsupported type of known-host entry"); - } - - /* When putting together the host line there are three aspects to consider: - - Hashed (SHA1) or unhashed hostname - - key name or no key name (RSA1) - - comment or no comment - - This means there are 2^3 different formats: - ("|1|%s|%s %s %s %s\n", salt, hashed_host, key_name, key, comment) - ("|1|%s|%s %s %s\n", salt, hashed_host, key_name, key) - ("|1|%s|%s %s %s\n", salt, hashed_host, key, comment) - ("|1|%s|%s %s\n", salt, hashed_host, key) - ("%s %s %s %s\n", host, key_name, key, comment) - ("%s %s %s\n", host, key_name, key) - ("%s %s %s\n", host, key, comment) - ("%s %s\n", host, key) - - Even if the buffer is too small, we have to set outlen to the number of - characters the complete line would have taken. We also don't write - anything to the buffer unless we are sure we can write everything to the - buffer. */ - - required_size = strlen(node->key); - - if(key_type_len) - required_size += key_type_len + 1; /* ' ' = 1 */ - if(node->comment) - required_size += node->comment_len + 1; /* ' ' = 1 */ - - if((node->typemask & LIBSSH2_KNOWNHOST_TYPE_MASK) == - LIBSSH2_KNOWNHOST_TYPE_SHA1) { - char *namealloc; - size_t name_base64_len; - char *saltalloc; - size_t salt_base64_len; - - name_base64_len = _libssh2_base64_encode(hosts->session, node->name, - node->name_len, &namealloc); - if(!name_base64_len) - return _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "base64-encoded host name"); - - salt_base64_len = _libssh2_base64_encode(hosts->session, - node->salt, node->salt_len, - &saltalloc); - if(!salt_base64_len) { - LIBSSH2_FREE(hosts->session, namealloc); - return _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "base64-encoded salt"); - } - - required_size += salt_base64_len + name_base64_len + 7; - /* |1| + | + ' ' + \n + \0 = 7 */ - - if(required_size <= buflen) { - if(node->comment && key_type_len) - snprintf(buf, buflen, "|1|%s|%s %s %s %s\n", saltalloc, - namealloc, key_type_name, node->key, node->comment); - else if(node->comment) - snprintf(buf, buflen, "|1|%s|%s %s %s\n", saltalloc, namealloc, - node->key, node->comment); - else if(key_type_len) - snprintf(buf, buflen, "|1|%s|%s %s %s\n", saltalloc, namealloc, - key_type_name, node->key); - else - snprintf(buf, buflen, "|1|%s|%s %s\n", saltalloc, namealloc, - node->key); - } - - LIBSSH2_FREE(hosts->session, namealloc); - LIBSSH2_FREE(hosts->session, saltalloc); - } - else { - required_size += node->name_len + 3; - /* ' ' + '\n' + \0 = 3 */ - - if(required_size <= buflen) { - if(node->comment && key_type_len) - snprintf(buf, buflen, "%s %s %s %s\n", node->name, - key_type_name, node->key, node->comment); - else if(node->comment) - snprintf(buf, buflen, "%s %s %s\n", node->name, node->key, - node->comment); - else if(key_type_len) - snprintf(buf, buflen, "%s %s %s\n", node->name, key_type_name, - node->key); - else - snprintf(buf, buflen, "%s %s\n", node->name, node->key); - } - } - - /* we report the full length of the data with the trailing zero excluded */ - *outlen = required_size-1; - - if(required_size <= buflen) - return LIBSSH2_ERROR_NONE; - else - return _libssh2_error(hosts->session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "Known-host write buffer too small"); -} - -/* - * libssh2_knownhost_writeline() - * - * Ask libssh2 to convert a known host to an output line for storage. - * - * Note that this function returns LIBSSH2_ERROR_BUFFER_TOO_SMALL if the given - * output buffer is too small to hold the desired output. - */ -LIBSSH2_API int -libssh2_knownhost_writeline(LIBSSH2_KNOWNHOSTS *hosts, - struct libssh2_knownhost *known, - char *buffer, size_t buflen, - size_t *outlen, /* the amount of written data */ - int type) -{ - struct known_host *node; - - if(known->magic != KNOWNHOST_MAGIC) - return _libssh2_error(hosts->session, LIBSSH2_ERROR_INVAL, - "Invalid host information"); - - node = known->node; - - return knownhost_writeline(hosts, node, buffer, buflen, outlen, type); -} - -/* - * libssh2_knownhost_writefile() - * - * Write hosts+key pairs to the given file. - */ -LIBSSH2_API int -libssh2_knownhost_writefile(LIBSSH2_KNOWNHOSTS *hosts, - const char *filename, int type) -{ - struct known_host *node; - FILE *file; - int rc = LIBSSH2_ERROR_NONE; - char buffer[4092]; - - /* we only support this single file type for now, bail out on all other - attempts */ - if(type != LIBSSH2_KNOWNHOST_FILE_OPENSSH) - return _libssh2_error(hosts->session, - LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Unsupported type of known-host information " - "store"); - - file = fopen(filename, FOPEN_WRITETEXT); - if(!file) - return _libssh2_error(hosts->session, LIBSSH2_ERROR_FILE, - "Failed to open file"); - - for(node = _libssh2_list_first(&hosts->head); - node; - node = _libssh2_list_next(&node->node)) { - size_t wrote = 0; - size_t nwrote; - rc = knownhost_writeline(hosts, node, buffer, sizeof(buffer), &wrote, - type); - if(rc) - break; - - nwrote = fwrite(buffer, 1, wrote, file); - if(nwrote != wrote) { - /* failed to write the whole thing, bail out */ - rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_FILE, - "Write failed"); - break; - } - } - fclose(file); - - return rc; -} - - -/* - * libssh2_knownhost_get() - * - * Traverse the internal list of known hosts. Pass NULL to 'prev' to get - * the first one. - * - * Returns: - * 0 if a fine host was stored in 'store' - * 1 if end of hosts - * [negative] on errors - */ -LIBSSH2_API int -libssh2_knownhost_get(LIBSSH2_KNOWNHOSTS *hosts, - struct libssh2_knownhost **ext, - struct libssh2_knownhost *oprev) -{ - struct known_host *node; - if(oprev && oprev->node) { - /* we have a starting point */ - struct known_host *prev = oprev->node; - - /* get the next node in the list */ - node = _libssh2_list_next(&prev->node); - - } - else - node = _libssh2_list_first(&hosts->head); - - if(!node) - /* no (more) node */ - return 1; - - *ext = knownhost_to_external(node); - - return 0; -} diff --git a/libssh2/libgcrypt.c b/libssh2/libgcrypt.c deleted file mode 100644 index 0aff176..0000000 --- a/libssh2/libgcrypt.c +++ /dev/null @@ -1,667 +0,0 @@ -/* Copyright (C) 2008, 2009, Simon Josefsson - * Copyright (C) 2006, 2007, The Written Word, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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 "libssh2_priv.h" - -#ifdef LIBSSH2_LIBGCRYPT /* compile only if we build with libgcrypt */ - -#include - -int -_libssh2_rsa_new(libssh2_rsa_ctx ** rsa, - const unsigned char *edata, - unsigned long elen, - const unsigned char *ndata, - unsigned long nlen, - const unsigned char *ddata, - unsigned long dlen, - const unsigned char *pdata, - unsigned long plen, - const unsigned char *qdata, - unsigned long qlen, - const unsigned char *e1data, - unsigned long e1len, - const unsigned char *e2data, - unsigned long e2len, - const unsigned char *coeffdata, unsigned long coefflen) -{ - int rc; - (void) e1data; - (void) e1len; - (void) e2data; - (void) e2len; - - if(ddata) { - rc = gcry_sexp_build - (rsa, NULL, - "(private-key(rsa(n%b)(e%b)(d%b)(q%b)(p%b)(u%b)))", - nlen, ndata, elen, edata, dlen, ddata, plen, pdata, - qlen, qdata, coefflen, coeffdata); - } - else { - rc = gcry_sexp_build(rsa, NULL, "(public-key(rsa(n%b)(e%b)))", - nlen, ndata, elen, edata); - } - if(rc) { - *rsa = NULL; - return -1; - } - - return 0; -} - -int -_libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsa, - const unsigned char *sig, - unsigned long sig_len, - const unsigned char *m, unsigned long m_len) -{ - unsigned char hash[SHA_DIGEST_LENGTH]; - gcry_sexp_t s_sig, s_hash; - int rc = -1; - - libssh2_sha1(m, m_len, hash); - - rc = gcry_sexp_build(&s_hash, NULL, - "(data (flags pkcs1) (hash sha1 %b))", - SHA_DIGEST_LENGTH, hash); - if(rc != 0) { - return -1; - } - - rc = gcry_sexp_build(&s_sig, NULL, "(sig-val(rsa(s %b)))", sig_len, sig); - if(rc != 0) { - gcry_sexp_release(s_hash); - return -1; - } - - rc = gcry_pk_verify(s_sig, s_hash, rsa); - gcry_sexp_release(s_sig); - gcry_sexp_release(s_hash); - - return (rc == 0) ? 0 : -1; -} - -int -_libssh2_dsa_new(libssh2_dsa_ctx ** dsactx, - const unsigned char *p, - unsigned long p_len, - const unsigned char *q, - unsigned long q_len, - const unsigned char *g, - unsigned long g_len, - const unsigned char *y, - unsigned long y_len, - const unsigned char *x, unsigned long x_len) -{ - int rc; - - if(x_len) { - rc = gcry_sexp_build - (dsactx, NULL, - "(private-key(dsa(p%b)(q%b)(g%b)(y%b)(x%b)))", - p_len, p, q_len, q, g_len, g, y_len, y, x_len, x); - } - else { - rc = gcry_sexp_build(dsactx, NULL, - "(public-key(dsa(p%b)(q%b)(g%b)(y%b)))", - p_len, p, q_len, q, g_len, g, y_len, y); - } - - if(rc) { - *dsactx = NULL; - return -1; - } - - return 0; -} - -int -_libssh2_rsa_new_private_frommemory(libssh2_rsa_ctx ** rsa, - LIBSSH2_SESSION * session, - const char *filedata, size_t filedata_len, - unsigned const char *passphrase) -{ - return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Unable to extract private key from memory: " - "Method unimplemented in libgcrypt backend"); -} - -int -_libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa, - LIBSSH2_SESSION * session, - const char *filename, unsigned const char *passphrase) -{ - FILE *fp; - unsigned char *data, *save_data; - unsigned int datalen; - int ret; - unsigned char *n, *e, *d, *p, *q, *e1, *e2, *coeff; - unsigned int nlen, elen, dlen, plen, qlen, e1len, e2len, coefflen; - - fp = fopen(filename, FOPEN_READTEXT); - if(!fp) { - return -1; - } - - ret = _libssh2_pem_parse(session, - "-----BEGIN RSA PRIVATE KEY-----", - "-----END RSA PRIVATE KEY-----", - passphrase, - fp, &data, &datalen); - fclose(fp); - if(ret) { - return -1; - } - - save_data = data; - - if(_libssh2_pem_decode_sequence(&data, &datalen)) { - ret = -1; - goto fail; - } -/* First read Version field (should be 0). */ - ret = _libssh2_pem_decode_integer(&data, &datalen, &n, &nlen); - if(ret != 0 || (nlen != 1 && *n != '\0')) { - ret = -1; - goto fail; - } - - ret = _libssh2_pem_decode_integer(&data, &datalen, &n, &nlen); - if(ret != 0) { - ret = -1; - goto fail; - } - - ret = _libssh2_pem_decode_integer(&data, &datalen, &e, &elen); - if(ret != 0) { - ret = -1; - goto fail; - } - - ret = _libssh2_pem_decode_integer(&data, &datalen, &d, &dlen); - if(ret != 0) { - ret = -1; - goto fail; - } - - ret = _libssh2_pem_decode_integer(&data, &datalen, &p, &plen); - if(ret != 0) { - ret = -1; - goto fail; - } - - ret = _libssh2_pem_decode_integer(&data, &datalen, &q, &qlen); - if(ret != 0) { - ret = -1; - goto fail; - } - - ret = _libssh2_pem_decode_integer(&data, &datalen, &e1, &e1len); - if(ret != 0) { - ret = -1; - goto fail; - } - - ret = _libssh2_pem_decode_integer(&data, &datalen, &e2, &e2len); - if(ret != 0) { - ret = -1; - goto fail; - } - - ret = _libssh2_pem_decode_integer(&data, &datalen, &coeff, &coefflen); - if(ret != 0) { - ret = -1; - goto fail; - } - - if(_libssh2_rsa_new(rsa, e, elen, n, nlen, d, dlen, p, plen, - q, qlen, e1, e1len, e2, e2len, coeff, coefflen)) { - ret = -1; - goto fail; - } - - ret = 0; - - fail: - LIBSSH2_FREE(session, save_data); - return ret; -} - -int -_libssh2_dsa_new_private_frommemory(libssh2_dsa_ctx ** dsa, - LIBSSH2_SESSION * session, - const char *filedata, size_t filedata_len, - unsigned const char *passphrase) -{ - return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Unable to extract private key from memory: " - "Method unimplemented in libgcrypt backend"); -} - -int -_libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa, - LIBSSH2_SESSION * session, - const char *filename, unsigned const char *passphrase) -{ - FILE *fp; - unsigned char *data, *save_data; - unsigned int datalen; - int ret; - unsigned char *p, *q, *g, *y, *x; - unsigned int plen, qlen, glen, ylen, xlen; - - fp = fopen(filename, FOPEN_READTEXT); - if(!fp) { - return -1; - } - - ret = _libssh2_pem_parse(session, - "-----BEGIN DSA PRIVATE KEY-----", - "-----END DSA PRIVATE KEY-----", - passphrase, - fp, &data, &datalen); - fclose(fp); - if(ret) { - return -1; - } - - save_data = data; - - if(_libssh2_pem_decode_sequence(&data, &datalen)) { - ret = -1; - goto fail; - } - -/* First read Version field (should be 0). */ - ret = _libssh2_pem_decode_integer(&data, &datalen, &p, &plen); - if(ret != 0 || (plen != 1 && *p != '\0')) { - ret = -1; - goto fail; - } - - ret = _libssh2_pem_decode_integer(&data, &datalen, &p, &plen); - if(ret != 0) { - ret = -1; - goto fail; - } - - ret = _libssh2_pem_decode_integer(&data, &datalen, &q, &qlen); - if(ret != 0) { - ret = -1; - goto fail; - } - - ret = _libssh2_pem_decode_integer(&data, &datalen, &g, &glen); - if(ret != 0) { - ret = -1; - goto fail; - } - - ret = _libssh2_pem_decode_integer(&data, &datalen, &y, &ylen); - if(ret != 0) { - ret = -1; - goto fail; - } - - ret = _libssh2_pem_decode_integer(&data, &datalen, &x, &xlen); - if(ret != 0) { - ret = -1; - goto fail; - } - - if(datalen != 0) { - ret = -1; - goto fail; - } - - if(_libssh2_dsa_new(dsa, p, plen, q, qlen, g, glen, y, ylen, x, xlen)) { - ret = -1; - goto fail; - } - - ret = 0; - - fail: - LIBSSH2_FREE(session, save_data); - return ret; -} - -int -_libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session, - libssh2_rsa_ctx * rsactx, - const unsigned char *hash, - size_t hash_len, - unsigned char **signature, size_t *signature_len) -{ - gcry_sexp_t sig_sexp; - gcry_sexp_t data; - int rc; - const char *tmp; - size_t size; - - if(hash_len != SHA_DIGEST_LENGTH) { - return -1; - } - - if(gcry_sexp_build(&data, NULL, - "(data (flags pkcs1) (hash sha1 %b))", - hash_len, hash)) { - return -1; - } - - rc = gcry_pk_sign(&sig_sexp, data, rsactx); - - gcry_sexp_release(data); - - if(rc != 0) { - return -1; - } - - data = gcry_sexp_find_token(sig_sexp, "s", 0); - if(!data) { - return -1; - } - - tmp = gcry_sexp_nth_data(data, 1, &size); - if(!tmp) { - gcry_sexp_release(data); - return -1; - } - - if(tmp[0] == '\0') { - tmp++; - size--; - } - - *signature = LIBSSH2_ALLOC(session, size); - if(!*signature) { - gcry_sexp_release(data); - return -1; - } - memcpy(*signature, tmp, size); - *signature_len = size; - - gcry_sexp_release(data); - - return rc; -} - -int -_libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx, - const unsigned char *hash, - unsigned long hash_len, unsigned char *sig) -{ - unsigned char zhash[SHA_DIGEST_LENGTH + 1]; - gcry_sexp_t sig_sexp; - gcry_sexp_t data; - int ret; - const char *tmp; - size_t size; - - if(hash_len != SHA_DIGEST_LENGTH) { - return -1; - } - - memcpy(zhash + 1, hash, hash_len); - zhash[0] = 0; - - if(gcry_sexp_build(&data, NULL, "(data (value %b))", - hash_len + 1, zhash)) { - return -1; - } - - ret = gcry_pk_sign(&sig_sexp, data, dsactx); - - gcry_sexp_release(data); - - if(ret != 0) { - return -1; - } - - memset(sig, 0, 40); - -/* Extract R. */ - - data = gcry_sexp_find_token(sig_sexp, "r", 0); - if(!data) - goto err; - - tmp = gcry_sexp_nth_data(data, 1, &size); - if(!tmp) - goto err; - - if(tmp[0] == '\0') { - tmp++; - size--; - } - - if(size < 1 || size > 20) - goto err; - - memcpy(sig + (20 - size), tmp, size); - - gcry_sexp_release(data); - -/* Extract S. */ - - data = gcry_sexp_find_token(sig_sexp, "s", 0); - if(!data) - goto err; - - tmp = gcry_sexp_nth_data(data, 1, &size); - if(!tmp) - goto err; - - if(tmp[0] == '\0') { - tmp++; - size--; - } - - if(size < 1 || size > 20) - goto err; - - memcpy(sig + 20 + (20 - size), tmp, size); - goto out; - - err: - ret = -1; - - out: - if(sig_sexp) { - gcry_sexp_release(sig_sexp); - } - if(data) { - gcry_sexp_release(data); - } - return ret; -} - -int -_libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx, - const unsigned char *sig, - const unsigned char *m, unsigned long m_len) -{ - unsigned char hash[SHA_DIGEST_LENGTH + 1]; - gcry_sexp_t s_sig, s_hash; - int rc = -1; - - libssh2_sha1(m, m_len, hash + 1); - hash[0] = 0; - - if(gcry_sexp_build(&s_hash, NULL, "(data(flags raw)(value %b))", - SHA_DIGEST_LENGTH + 1, hash)) { - return -1; - } - - if(gcry_sexp_build(&s_sig, NULL, "(sig-val(dsa(r %b)(s %b)))", - 20, sig, 20, sig + 20)) { - gcry_sexp_release(s_hash); - return -1; - } - - rc = gcry_pk_verify(s_sig, s_hash, dsactx); - gcry_sexp_release(s_sig); - gcry_sexp_release(s_hash); - - return (rc == 0) ? 0 : -1; -} - -int -_libssh2_cipher_init(_libssh2_cipher_ctx * h, - _libssh2_cipher_type(algo), - unsigned char *iv, unsigned char *secret, int encrypt) -{ - int ret; - int cipher = _libssh2_gcry_cipher(algo); - int mode = _libssh2_gcry_mode(algo); - int keylen = gcry_cipher_get_algo_keylen(cipher); - - (void) encrypt; - - ret = gcry_cipher_open(h, cipher, mode, 0); - if(ret) { - return -1; - } - - ret = gcry_cipher_setkey(*h, secret, keylen); - if(ret) { - gcry_cipher_close(*h); - return -1; - } - - if(mode != GCRY_CIPHER_MODE_STREAM) { - int blklen = gcry_cipher_get_algo_blklen(cipher); - if(mode == GCRY_CIPHER_MODE_CTR) - ret = gcry_cipher_setctr(*h, iv, blklen); - else - ret = gcry_cipher_setiv(*h, iv, blklen); - if(ret) { - gcry_cipher_close(*h); - return -1; - } - } - - return 0; -} - -int -_libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx, - _libssh2_cipher_type(algo), - int encrypt, unsigned char *block, size_t blklen) -{ - int cipher = _libssh2_gcry_cipher(algo); - int ret; - - if(encrypt) { - ret = gcry_cipher_encrypt(*ctx, block, blklen, block, blklen); - } - else { - ret = gcry_cipher_decrypt(*ctx, block, blklen, block, blklen); - } - return ret; -} - -int -_libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - const char *privatekeydata, - size_t privatekeydata_len, - const char *passphrase) -{ - return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Unable to extract public key from private " - "key in memory: " - "Method unimplemented in libgcrypt backend"); -} - -int -_libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - const char *privatekey, - const char *passphrase) -{ - return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Unable to extract public key from private key file: " - "Method unimplemented in libgcrypt backend"); -} - -void _libssh2_init_aes_ctr(void) -{ - /* no implementation */ -} - -void -_libssh2_dh_init(_libssh2_dh_ctx *dhctx) -{ - *dhctx = gcry_mpi_new(0); /* Random from client */ -} - -int -_libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public, - _libssh2_bn *g, _libssh2_bn *p, int group_order) -{ - /* Generate x and e */ - gcry_mpi_randomize(*dhctx, group_order * 8 - 1, GCRY_WEAK_RANDOM); - gcry_mpi_powm(public, g, *dhctx, p); - return 0; -} - -int -_libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret, - _libssh2_bn *f, _libssh2_bn *p) -{ - /* Compute the shared secret */ - gcry_mpi_powm(secret, f, *dhctx, p); - return 0; -} - -void -_libssh2_dh_dtor(_libssh2_dh_ctx *dhctx) -{ - gcry_mpi_release(*dhctx); - *dhctx = NULL; -} - -#endif /* LIBSSH2_LIBGCRYPT */ diff --git a/libssh2/mac.c b/libssh2/mac.c deleted file mode 100644 index 5ac71df..0000000 --- a/libssh2/mac.c +++ /dev/null @@ -1,414 +0,0 @@ -/* Copyright (c) 2004-2007, Sara Golemon - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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 "libssh2_priv.h" -#include "mac.h" - -#ifdef LIBSSH2_MAC_NONE -/* mac_none_MAC - * Minimalist MAC: No MAC - */ -static int -mac_none_MAC(LIBSSH2_SESSION * session, unsigned char *buf, - uint32_t seqno, const unsigned char *packet, - uint32_t packet_len, const unsigned char *addtl, - uint32_t addtl_len, void **abstract) -{ - return 0; -} - - - - -static LIBSSH2_MAC_METHOD mac_method_none = { - "none", - 0, - 0, - NULL, - mac_none_MAC, - NULL -}; -#endif /* LIBSSH2_MAC_NONE */ - -/* mac_method_common_init - * Initialize simple mac methods - */ -static int -mac_method_common_init(LIBSSH2_SESSION * session, unsigned char *key, - int *free_key, void **abstract) -{ - *abstract = key; - *free_key = 0; - (void) session; - - return 0; -} - - - -/* mac_method_common_dtor - * Cleanup simple mac methods - */ -static int -mac_method_common_dtor(LIBSSH2_SESSION * session, void **abstract) -{ - if(*abstract) { - LIBSSH2_FREE(session, *abstract); - } - *abstract = NULL; - - return 0; -} - - - -#if LIBSSH2_HMAC_SHA512 -/* mac_method_hmac_sha512_hash - * Calculate hash using full sha512 value - */ -static int -mac_method_hmac_sha2_512_hash(LIBSSH2_SESSION * session, - unsigned char *buf, uint32_t seqno, - const unsigned char *packet, - uint32_t packet_len, - const unsigned char *addtl, - uint32_t addtl_len, void **abstract) -{ - libssh2_hmac_ctx ctx; - unsigned char seqno_buf[4]; - (void) session; - - _libssh2_htonu32(seqno_buf, seqno); - - libssh2_hmac_ctx_init(ctx); - libssh2_hmac_sha512_init(&ctx, *abstract, 64); - libssh2_hmac_update(ctx, seqno_buf, 4); - libssh2_hmac_update(ctx, packet, packet_len); - if(addtl && addtl_len) { - libssh2_hmac_update(ctx, addtl, addtl_len); - } - libssh2_hmac_final(ctx, buf); - libssh2_hmac_cleanup(&ctx); - - return 0; -} - - - -static const LIBSSH2_MAC_METHOD mac_method_hmac_sha2_512 = { - "hmac-sha2-512", - 64, - 64, - mac_method_common_init, - mac_method_hmac_sha2_512_hash, - mac_method_common_dtor, -}; -#endif - - - -#if LIBSSH2_HMAC_SHA256 -/* mac_method_hmac_sha256_hash - * Calculate hash using full sha256 value - */ -static int -mac_method_hmac_sha2_256_hash(LIBSSH2_SESSION * session, - unsigned char *buf, uint32_t seqno, - const unsigned char *packet, - uint32_t packet_len, - const unsigned char *addtl, - uint32_t addtl_len, void **abstract) -{ - libssh2_hmac_ctx ctx; - unsigned char seqno_buf[4]; - (void) session; - - _libssh2_htonu32(seqno_buf, seqno); - - libssh2_hmac_ctx_init(ctx); - libssh2_hmac_sha256_init(&ctx, *abstract, 32); - libssh2_hmac_update(ctx, seqno_buf, 4); - libssh2_hmac_update(ctx, packet, packet_len); - if(addtl && addtl_len) { - libssh2_hmac_update(ctx, addtl, addtl_len); - } - libssh2_hmac_final(ctx, buf); - libssh2_hmac_cleanup(&ctx); - - return 0; -} - - - -static const LIBSSH2_MAC_METHOD mac_method_hmac_sha2_256 = { - "hmac-sha2-256", - 32, - 32, - mac_method_common_init, - mac_method_hmac_sha2_256_hash, - mac_method_common_dtor, -}; -#endif - - - - -/* mac_method_hmac_sha1_hash - * Calculate hash using full sha1 value - */ -static int -mac_method_hmac_sha1_hash(LIBSSH2_SESSION * session, - unsigned char *buf, uint32_t seqno, - const unsigned char *packet, - uint32_t packet_len, - const unsigned char *addtl, - uint32_t addtl_len, void **abstract) -{ - libssh2_hmac_ctx ctx; - unsigned char seqno_buf[4]; - (void) session; - - _libssh2_htonu32(seqno_buf, seqno); - - libssh2_hmac_ctx_init(ctx); - libssh2_hmac_sha1_init(&ctx, *abstract, 20); - libssh2_hmac_update(ctx, seqno_buf, 4); - libssh2_hmac_update(ctx, packet, packet_len); - if(addtl && addtl_len) { - libssh2_hmac_update(ctx, addtl, addtl_len); - } - libssh2_hmac_final(ctx, buf); - libssh2_hmac_cleanup(&ctx); - - return 0; -} - - - -static const LIBSSH2_MAC_METHOD mac_method_hmac_sha1 = { - "hmac-sha1", - 20, - 20, - mac_method_common_init, - mac_method_hmac_sha1_hash, - mac_method_common_dtor, -}; - -/* mac_method_hmac_sha1_96_hash - * Calculate hash using first 96 bits of sha1 value - */ -static int -mac_method_hmac_sha1_96_hash(LIBSSH2_SESSION * session, - unsigned char *buf, uint32_t seqno, - const unsigned char *packet, - uint32_t packet_len, - const unsigned char *addtl, - uint32_t addtl_len, void **abstract) -{ - unsigned char temp[SHA_DIGEST_LENGTH]; - - mac_method_hmac_sha1_hash(session, temp, seqno, packet, packet_len, - addtl, addtl_len, abstract); - memcpy(buf, (char *) temp, 96 / 8); - - return 0; -} - - - -static const LIBSSH2_MAC_METHOD mac_method_hmac_sha1_96 = { - "hmac-sha1-96", - 12, - 20, - mac_method_common_init, - mac_method_hmac_sha1_96_hash, - mac_method_common_dtor, -}; - -#if LIBSSH2_MD5 -/* mac_method_hmac_md5_hash - * Calculate hash using full md5 value - */ -static int -mac_method_hmac_md5_hash(LIBSSH2_SESSION * session, unsigned char *buf, - uint32_t seqno, - const unsigned char *packet, - uint32_t packet_len, - const unsigned char *addtl, - uint32_t addtl_len, void **abstract) -{ - libssh2_hmac_ctx ctx; - unsigned char seqno_buf[4]; - (void) session; - - _libssh2_htonu32(seqno_buf, seqno); - - libssh2_hmac_ctx_init(ctx); - libssh2_hmac_md5_init(&ctx, *abstract, 16); - libssh2_hmac_update(ctx, seqno_buf, 4); - libssh2_hmac_update(ctx, packet, packet_len); - if(addtl && addtl_len) { - libssh2_hmac_update(ctx, addtl, addtl_len); - } - libssh2_hmac_final(ctx, buf); - libssh2_hmac_cleanup(&ctx); - - return 0; -} - - - -static const LIBSSH2_MAC_METHOD mac_method_hmac_md5 = { - "hmac-md5", - 16, - 16, - mac_method_common_init, - mac_method_hmac_md5_hash, - mac_method_common_dtor, -}; - -/* mac_method_hmac_md5_96_hash - * Calculate hash using first 96 bits of md5 value - */ -static int -mac_method_hmac_md5_96_hash(LIBSSH2_SESSION * session, - unsigned char *buf, uint32_t seqno, - const unsigned char *packet, - uint32_t packet_len, - const unsigned char *addtl, - uint32_t addtl_len, void **abstract) -{ - unsigned char temp[MD5_DIGEST_LENGTH]; - mac_method_hmac_md5_hash(session, temp, seqno, packet, packet_len, - addtl, addtl_len, abstract); - memcpy(buf, (char *) temp, 96 / 8); - return 0; -} - - - -static const LIBSSH2_MAC_METHOD mac_method_hmac_md5_96 = { - "hmac-md5-96", - 12, - 16, - mac_method_common_init, - mac_method_hmac_md5_96_hash, - mac_method_common_dtor, -}; -#endif /* LIBSSH2_MD5 */ - -#if LIBSSH2_HMAC_RIPEMD -/* mac_method_hmac_ripemd160_hash - * Calculate hash using ripemd160 value - */ -static int -mac_method_hmac_ripemd160_hash(LIBSSH2_SESSION * session, - unsigned char *buf, uint32_t seqno, - const unsigned char *packet, - uint32_t packet_len, - const unsigned char *addtl, - uint32_t addtl_len, - void **abstract) -{ - libssh2_hmac_ctx ctx; - unsigned char seqno_buf[4]; - (void) session; - - _libssh2_htonu32(seqno_buf, seqno); - - libssh2_hmac_ctx_init(ctx); - libssh2_hmac_ripemd160_init(&ctx, *abstract, 20); - libssh2_hmac_update(ctx, seqno_buf, 4); - libssh2_hmac_update(ctx, packet, packet_len); - if(addtl && addtl_len) { - libssh2_hmac_update(ctx, addtl, addtl_len); - } - libssh2_hmac_final(ctx, buf); - libssh2_hmac_cleanup(&ctx); - - return 0; -} - - - -static const LIBSSH2_MAC_METHOD mac_method_hmac_ripemd160 = { - "hmac-ripemd160", - 20, - 20, - mac_method_common_init, - mac_method_hmac_ripemd160_hash, - mac_method_common_dtor, -}; - -static const LIBSSH2_MAC_METHOD mac_method_hmac_ripemd160_openssh_com = { - "hmac-ripemd160@openssh.com", - 20, - 20, - mac_method_common_init, - mac_method_hmac_ripemd160_hash, - mac_method_common_dtor, -}; -#endif /* LIBSSH2_HMAC_RIPEMD */ - -static const LIBSSH2_MAC_METHOD *mac_methods[] = { -#if LIBSSH2_HMAC_SHA256 - &mac_method_hmac_sha2_256, -#endif -#if LIBSSH2_HMAC_SHA512 - &mac_method_hmac_sha2_512, -#endif - &mac_method_hmac_sha1, - &mac_method_hmac_sha1_96, -#if LIBSSH2_MD5 - &mac_method_hmac_md5, - &mac_method_hmac_md5_96, -#endif -#if LIBSSH2_HMAC_RIPEMD - &mac_method_hmac_ripemd160, - &mac_method_hmac_ripemd160_openssh_com, -#endif /* LIBSSH2_HMAC_RIPEMD */ -#ifdef LIBSSH2_MAC_NONE - &mac_method_none, -#endif /* LIBSSH2_MAC_NONE */ - NULL -}; - -const LIBSSH2_MAC_METHOD ** -_libssh2_mac_methods(void) -{ - return mac_methods; -} diff --git a/libssh2/mbedtls.c b/libssh2/mbedtls.c deleted file mode 100644 index 128eee4..0000000 --- a/libssh2/mbedtls.c +++ /dev/null @@ -1,733 +0,0 @@ -/* Copyright (c) 2016, Art - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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 "libssh2_priv.h" - -#ifdef LIBSSH2_MBEDTLS /* compile only if we build with mbedtls */ - -/*******************************************************************/ -/* - * mbedTLS backend: Global context handles - */ - -static mbedtls_entropy_context _libssh2_mbedtls_entropy; -static mbedtls_ctr_drbg_context _libssh2_mbedtls_ctr_drbg; - -/*******************************************************************/ -/* - * mbedTLS backend: Generic functions - */ - -void -_libssh2_mbedtls_init(void) -{ - int ret; - - mbedtls_entropy_init(&_libssh2_mbedtls_entropy); - mbedtls_ctr_drbg_init(&_libssh2_mbedtls_ctr_drbg); - - ret = mbedtls_ctr_drbg_seed(&_libssh2_mbedtls_ctr_drbg, - mbedtls_entropy_func, - &_libssh2_mbedtls_entropy, NULL, 0); - if(ret != 0) - mbedtls_ctr_drbg_free(&_libssh2_mbedtls_ctr_drbg); -} - -void -_libssh2_mbedtls_free(void) -{ - mbedtls_ctr_drbg_free(&_libssh2_mbedtls_ctr_drbg); - mbedtls_entropy_free(&_libssh2_mbedtls_entropy); -} - -int -_libssh2_mbedtls_random(unsigned char *buf, int len) -{ - int ret; - ret = mbedtls_ctr_drbg_random(&_libssh2_mbedtls_ctr_drbg, buf, len); - return ret == 0 ? 0 : -1; -} - -static void -_libssh2_mbedtls_safe_free(void *buf, int len) -{ -#ifndef LIBSSH2_CLEAR_MEMORY - (void)len; -#endif - - if(!buf) - return; - -#ifdef LIBSSH2_CLEAR_MEMORY - if(len > 0) - memset(buf, 0, len); -#endif - - mbedtls_free(buf); -} - -int -_libssh2_mbedtls_cipher_init(_libssh2_cipher_ctx *ctx, - _libssh2_cipher_type(algo), - unsigned char *iv, - unsigned char *secret, - int encrypt) -{ - const mbedtls_cipher_info_t *cipher_info; - int ret, op; - - if(!ctx) - return -1; - - op = encrypt == 0 ? MBEDTLS_ENCRYPT : MBEDTLS_DECRYPT; - - cipher_info = mbedtls_cipher_info_from_type(algo); - if(!cipher_info) - return -1; - - mbedtls_cipher_init(ctx); - ret = mbedtls_cipher_setup(ctx, cipher_info); - if(!ret) - ret = mbedtls_cipher_setkey(ctx, secret, cipher_info->key_bitlen, op); - - if(!ret) - ret = mbedtls_cipher_set_iv(ctx, iv, cipher_info->iv_size); - - return ret == 0 ? 0 : -1; -} - -int -_libssh2_mbedtls_cipher_crypt(_libssh2_cipher_ctx *ctx, - _libssh2_cipher_type(algo), - int encrypt, - unsigned char *block, - size_t blocklen) -{ - int ret; - unsigned char *output; - size_t osize, olen, finish_olen; - - (void) encrypt; - (void) algo; - - osize = blocklen + mbedtls_cipher_get_block_size(ctx); - - output = (unsigned char *)mbedtls_calloc(osize, sizeof(char)); - if(output) { - ret = mbedtls_cipher_reset(ctx); - - if(!ret) - ret = mbedtls_cipher_update(ctx, block, blocklen, output, &olen); - - if(!ret) - ret = mbedtls_cipher_finish(ctx, output + olen, &finish_olen); - - if(!ret) { - olen += finish_olen; - memcpy(block, output, olen); - } - - _libssh2_mbedtls_safe_free(output, osize); - } - else - ret = -1; - - return ret == 0 ? 0 : -1; -} - -void -_libssh2_mbedtls_cipher_dtor(_libssh2_cipher_ctx *ctx) -{ - mbedtls_cipher_free(ctx); -} - - -int -_libssh2_mbedtls_hash_init(mbedtls_md_context_t *ctx, - mbedtls_md_type_t mdtype, - const unsigned char *key, unsigned long keylen) -{ - const mbedtls_md_info_t *md_info; - int ret, hmac; - - md_info = mbedtls_md_info_from_type(mdtype); - if(!md_info) - return 0; - - hmac = key == NULL ? 0 : 1; - - mbedtls_md_init(ctx); - ret = mbedtls_md_setup(ctx, md_info, hmac); - if(!ret) { - if(hmac) - ret = mbedtls_md_hmac_starts(ctx, key, keylen); - else - ret = mbedtls_md_starts(ctx); - } - - return ret == 0 ? 1 : 0; -} - -int -_libssh2_mbedtls_hash_final(mbedtls_md_context_t *ctx, unsigned char *hash) -{ - int ret; - - ret = mbedtls_md_finish(ctx, hash); - mbedtls_md_free(ctx); - - return ret == 0 ? 0 : -1; -} - -int -_libssh2_mbedtls_hash(const unsigned char *data, unsigned long datalen, - mbedtls_md_type_t mdtype, unsigned char *hash) -{ - const mbedtls_md_info_t *md_info; - int ret; - - md_info = mbedtls_md_info_from_type(mdtype); - if(!md_info) - return 0; - - ret = mbedtls_md(md_info, data, datalen, hash); - - return ret == 0 ? 0 : -1; -} - -/*******************************************************************/ -/* - * mbedTLS backend: BigNumber functions - */ - -_libssh2_bn * -_libssh2_mbedtls_bignum_init(void) -{ - _libssh2_bn *bignum; - - bignum = (_libssh2_bn *)mbedtls_calloc(1, sizeof(_libssh2_bn)); - if(bignum) { - mbedtls_mpi_init(bignum); - } - - return bignum; -} - -void -_libssh2_mbedtls_bignum_free(_libssh2_bn *bn) -{ - if(bn) { - mbedtls_mpi_free(bn); - mbedtls_free(bn); - } -} - -static int -_libssh2_mbedtls_bignum_random(_libssh2_bn *bn, int bits, int top, int bottom) -{ - size_t len; - int err; - int i; - - if(!bn || bits <= 0) - return -1; - - len = (bits + 7) >> 3; - err = mbedtls_mpi_fill_random(bn, len, mbedtls_ctr_drbg_random, - &_libssh2_mbedtls_ctr_drbg); - if(err) - return -1; - - /* Zero unused bits above the most significant bit*/ - for(i = len*8 - 1; bits <= i; --i) { - err = mbedtls_mpi_set_bit(bn, i, 0); - if(err) - return -1; - } - - /* If `top` is -1, the most significant bit of the random number can be - zero. If top is 0, the most significant bit of the random number is - set to 1, and if top is 1, the two most significant bits of the number - will be set to 1, so that the product of two such random numbers will - always have 2*bits length. - */ - for(i = 0; i <= top; ++i) { - err = mbedtls_mpi_set_bit(bn, bits-i-1, 1); - if(err) - return -1; - } - - /* make odd by setting first bit in least significant byte */ - if(bottom) { - err = mbedtls_mpi_set_bit(bn, 0, 1); - if(err) - return -1; - } - - return 0; -} - - -/*******************************************************************/ -/* - * mbedTLS backend: RSA functions - */ - -int -_libssh2_mbedtls_rsa_new(libssh2_rsa_ctx **rsa, - const unsigned char *edata, - unsigned long elen, - const unsigned char *ndata, - unsigned long nlen, - const unsigned char *ddata, - unsigned long dlen, - const unsigned char *pdata, - unsigned long plen, - const unsigned char *qdata, - unsigned long qlen, - const unsigned char *e1data, - unsigned long e1len, - const unsigned char *e2data, - unsigned long e2len, - const unsigned char *coeffdata, - unsigned long coefflen) -{ - int ret; - libssh2_rsa_ctx *ctx; - - ctx = (libssh2_rsa_ctx *) mbedtls_calloc(1, sizeof(libssh2_rsa_ctx)); - if(ctx != NULL) { - mbedtls_rsa_init(ctx, MBEDTLS_RSA_PKCS_V15, 0); - } - else - return -1; - - /* !checksrc! disable ASSIGNWITHINCONDITION 1 */ - if((ret = mbedtls_mpi_read_binary(&(ctx->E), edata, elen) ) != 0 || - (ret = mbedtls_mpi_read_binary(&(ctx->N), ndata, nlen) ) != 0) { - ret = -1; - } - - if(!ret) { - ctx->len = mbedtls_mpi_size(&(ctx->N)); - } - - if(!ret && ddata) { - /* !checksrc! disable ASSIGNWITHINCONDITION 1 */ - if((ret = mbedtls_mpi_read_binary(&(ctx->D), ddata, dlen) ) != 0 || - (ret = mbedtls_mpi_read_binary(&(ctx->P), pdata, plen) ) != 0 || - (ret = mbedtls_mpi_read_binary(&(ctx->Q), qdata, qlen) ) != 0 || - (ret = mbedtls_mpi_read_binary(&(ctx->DP), e1data, e1len) ) != 0 || - (ret = mbedtls_mpi_read_binary(&(ctx->DQ), e2data, e2len) ) != 0 || - (ret = mbedtls_mpi_read_binary(&(ctx->QP), coeffdata, coefflen) ) - != 0) { - ret = -1; - } - ret = mbedtls_rsa_check_privkey(ctx); - } - else if(!ret) { - ret = mbedtls_rsa_check_pubkey(ctx); - } - - if(ret && ctx) { - _libssh2_mbedtls_rsa_free(ctx); - ctx = NULL; - } - *rsa = ctx; - return ret; -} - -int -_libssh2_mbedtls_rsa_new_private(libssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - const char *filename, - const unsigned char *passphrase) -{ - int ret; - mbedtls_pk_context pkey; - mbedtls_rsa_context *pk_rsa; - - *rsa = (libssh2_rsa_ctx *) LIBSSH2_ALLOC(session, sizeof(libssh2_rsa_ctx)); - if(*rsa == NULL) - return -1; - - mbedtls_rsa_init(*rsa, MBEDTLS_RSA_PKCS_V15, 0); - mbedtls_pk_init(&pkey); - - ret = mbedtls_pk_parse_keyfile(&pkey, filename, (char *)passphrase); - if(ret != 0 || mbedtls_pk_get_type(&pkey) != MBEDTLS_PK_RSA) { - mbedtls_pk_free(&pkey); - mbedtls_rsa_free(*rsa); - LIBSSH2_FREE(session, *rsa); - *rsa = NULL; - return -1; - } - - pk_rsa = mbedtls_pk_rsa(pkey); - mbedtls_rsa_copy(*rsa, pk_rsa); - mbedtls_pk_free(&pkey); - - return 0; -} - -int -_libssh2_mbedtls_rsa_new_private_frommemory(libssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - const char *filedata, - size_t filedata_len, - unsigned const char *passphrase) -{ - int ret; - mbedtls_pk_context pkey; - mbedtls_rsa_context *pk_rsa; - void *filedata_nullterm; - size_t pwd_len; - - *rsa = (libssh2_rsa_ctx *) mbedtls_calloc(1, sizeof(libssh2_rsa_ctx)); - if(*rsa == NULL) - return -1; - - /* - mbedtls checks in "mbedtls/pkparse.c:1184" if "key[keylen - 1] != '\0'" - private-key from memory will fail if the last byte is not a null byte - */ - filedata_nullterm = mbedtls_calloc(filedata_len + 1, 1); - if(filedata_nullterm == NULL) { - return -1; - } - memcpy(filedata_nullterm, filedata, filedata_len); - - mbedtls_pk_init(&pkey); - - pwd_len = passphrase != NULL ? strlen((const char *)passphrase) : 0; - ret = mbedtls_pk_parse_key(&pkey, (unsigned char *)filedata_nullterm, - filedata_len + 1, - passphrase, pwd_len); - _libssh2_mbedtls_safe_free(filedata_nullterm, filedata_len); - - if(ret != 0 || mbedtls_pk_get_type(&pkey) != MBEDTLS_PK_RSA) { - mbedtls_pk_free(&pkey); - mbedtls_rsa_free(*rsa); - LIBSSH2_FREE(session, *rsa); - *rsa = NULL; - return -1; - } - - pk_rsa = mbedtls_pk_rsa(pkey); - mbedtls_rsa_copy(*rsa, pk_rsa); - mbedtls_pk_free(&pkey); - - return 0; -} - -int -_libssh2_mbedtls_rsa_sha1_verify(libssh2_rsa_ctx *rsa, - const unsigned char *sig, - unsigned long sig_len, - const unsigned char *m, - unsigned long m_len) -{ - unsigned char hash[SHA_DIGEST_LENGTH]; - int ret; - - ret = _libssh2_mbedtls_hash(m, m_len, MBEDTLS_MD_SHA1, hash); - if(ret) - return -1; /* failure */ - - ret = mbedtls_rsa_pkcs1_verify(rsa, NULL, NULL, MBEDTLS_RSA_PUBLIC, - MBEDTLS_MD_SHA1, SHA_DIGEST_LENGTH, - hash, sig); - - return (ret == 0) ? 0 : -1; -} - -int -_libssh2_mbedtls_rsa_sha1_sign(LIBSSH2_SESSION *session, - libssh2_rsa_ctx *rsa, - const unsigned char *hash, - size_t hash_len, - unsigned char **signature, - size_t *signature_len) -{ - int ret; - unsigned char *sig; - unsigned int sig_len; - - (void)hash_len; - - sig_len = rsa->len; - sig = LIBSSH2_ALLOC(session, sig_len); - if(!sig) { - return -1; - } - - ret = mbedtls_rsa_pkcs1_sign(rsa, NULL, NULL, MBEDTLS_RSA_PRIVATE, - MBEDTLS_MD_SHA1, SHA_DIGEST_LENGTH, - hash, sig); - if(ret) { - LIBSSH2_FREE(session, sig); - return -1; - } - - *signature = sig; - *signature_len = sig_len; - - return (ret == 0) ? 0 : -1; -} - -void -_libssh2_mbedtls_rsa_free(libssh2_rsa_ctx *ctx) -{ - mbedtls_rsa_free(ctx); - mbedtls_free(ctx); -} - -static unsigned char * -gen_publickey_from_rsa(LIBSSH2_SESSION *session, - mbedtls_rsa_context *rsa, - size_t *keylen) -{ - int e_bytes, n_bytes; - unsigned long len; - unsigned char *key; - unsigned char *p; - - e_bytes = mbedtls_mpi_size(&rsa->E); - n_bytes = mbedtls_mpi_size(&rsa->N); - - /* Key form is "ssh-rsa" + e + n. */ - len = 4 + 7 + 4 + e_bytes + 4 + n_bytes; - - key = LIBSSH2_ALLOC(session, len); - if(!key) { - return NULL; - } - - /* Process key encoding. */ - p = key; - - _libssh2_htonu32(p, 7); /* Key type. */ - p += 4; - memcpy(p, "ssh-rsa", 7); - p += 7; - - _libssh2_htonu32(p, e_bytes); - p += 4; - mbedtls_mpi_write_binary(&rsa->E, p, e_bytes); - - _libssh2_htonu32(p, n_bytes); - p += 4; - mbedtls_mpi_write_binary(&rsa->N, p, n_bytes); - - *keylen = (size_t)(p - key); - return key; -} - -static int -_libssh2_mbedtls_pub_priv_key(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - mbedtls_pk_context *pkey) -{ - unsigned char *key = NULL, *mth = NULL; - size_t keylen = 0, mthlen = 0; - int ret; - mbedtls_rsa_context *rsa; - - if(mbedtls_pk_get_type(pkey) != MBEDTLS_PK_RSA) { - mbedtls_pk_free(pkey); - return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Key type not supported"); - } - - /* write method */ - mthlen = 7; - mth = LIBSSH2_ALLOC(session, mthlen); - if(mth) { - memcpy(mth, "ssh-rsa", mthlen); - } - else { - ret = -1; - } - - rsa = mbedtls_pk_rsa(*pkey); - key = gen_publickey_from_rsa(session, rsa, &keylen); - if(key == NULL) { - ret = -1; - } - - /* write output */ - if(ret) { - if(mth) - LIBSSH2_FREE(session, mth); - if(key) - LIBSSH2_FREE(session, key); - } - else { - *method = mth; - *method_len = mthlen; - *pubkeydata = key; - *pubkeydata_len = keylen; - } - - return ret; -} - -int -_libssh2_mbedtls_pub_priv_keyfile(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - const char *privatekey, - const char *passphrase) -{ - mbedtls_pk_context pkey; - char buf[1024]; - int ret; - - mbedtls_pk_init(&pkey); - ret = mbedtls_pk_parse_keyfile(&pkey, privatekey, passphrase); - if(ret != 0) { - mbedtls_strerror(ret, (char *)buf, sizeof(buf)); - mbedtls_pk_free(&pkey); - return _libssh2_error(session, LIBSSH2_ERROR_FILE, buf); - } - - ret = _libssh2_mbedtls_pub_priv_key(session, method, method_len, - pubkeydata, pubkeydata_len, &pkey); - - mbedtls_pk_free(&pkey); - - return ret; -} - -int -_libssh2_mbedtls_pub_priv_keyfilememory(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - const char *privatekeydata, - size_t privatekeydata_len, - const char *passphrase) -{ - mbedtls_pk_context pkey; - char buf[1024]; - int ret; - void *privatekeydata_nullterm; - size_t pwd_len; - - /* - mbedtls checks in "mbedtls/pkparse.c:1184" if "key[keylen - 1] != '\0'" - private-key from memory will fail if the last byte is not a null byte - */ - privatekeydata_nullterm = mbedtls_calloc(privatekeydata_len + 1, 1); - if(privatekeydata_nullterm == NULL) { - return -1; - } - memcpy(privatekeydata_nullterm, privatekeydata, privatekeydata_len); - - mbedtls_pk_init(&pkey); - - pwd_len = passphrase != NULL ? strlen((const char *)passphrase) : 0; - ret = mbedtls_pk_parse_key(&pkey, - (unsigned char *)privatekeydata_nullterm, - privatekeydata_len + 1, - (const unsigned char *)passphrase, pwd_len); - _libssh2_mbedtls_safe_free(privatekeydata_nullterm, privatekeydata_len); - - if(ret != 0) { - mbedtls_strerror(ret, (char *)buf, sizeof(buf)); - mbedtls_pk_free(&pkey); - return _libssh2_error(session, LIBSSH2_ERROR_FILE, buf); - } - - ret = _libssh2_mbedtls_pub_priv_key(session, method, method_len, - pubkeydata, pubkeydata_len, &pkey); - - mbedtls_pk_free(&pkey); - - return ret; -} - -void _libssh2_init_aes_ctr(void) -{ - /* no implementation */ -} - - -/*******************************************************************/ -/* - * mbedTLS backend: Diffie-Hellman functions - */ - -void -_libssh2_dh_init(_libssh2_dh_ctx *dhctx) -{ - *dhctx = _libssh2_mbedtls_bignum_init(); /* Random from client */ -} - -int -_libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public, - _libssh2_bn *g, _libssh2_bn *p, int group_order) -{ - /* Generate x and e */ - _libssh2_mbedtls_bignum_random(*dhctx, group_order * 8 - 1, 0, -1); - mbedtls_mpi_exp_mod(public, g, *dhctx, p, NULL); - return 0; -} - -int -_libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret, - _libssh2_bn *f, _libssh2_bn *p) -{ - /* Compute the shared secret */ - mbedtls_mpi_exp_mod(secret, f, *dhctx, p, NULL); - return 0; -} - -void -_libssh2_dh_dtor(_libssh2_dh_ctx *dhctx) -{ - _libssh2_mbedtls_bignum_free(*dhctx); - *dhctx = NULL; -} - -#endif /* LIBSSH2_MBEDTLS */ diff --git a/libssh2/misc.c b/libssh2/misc.c deleted file mode 100644 index 594b2d1..0000000 --- a/libssh2/misc.c +++ /dev/null @@ -1,872 +0,0 @@ -/* Copyright (c) 2004-2007 Sara Golemon - * Copyright (c) 2009-2019 by Daniel Stenberg - * Copyright (c) 2010 Simon Josefsson - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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 "libssh2_priv.h" -#include "misc.h" -#include "blf.h" - -#ifdef HAVE_STDLIB_H -#include -#endif - -#ifdef HAVE_UNISTD_H -#include -#endif - -#ifdef HAVE_SYS_TIME_H -#include -#endif - -#if defined(HAVE_DECL_SECUREZEROMEMORY) && HAVE_DECL_SECUREZEROMEMORY -#ifdef HAVE_WINDOWS_H -#include -#endif -#endif - -#include -#include - -int _libssh2_error_flags(LIBSSH2_SESSION* session, int errcode, - const char *errmsg, int errflags) -{ - if(session->err_flags & LIBSSH2_ERR_FLAG_DUP) - LIBSSH2_FREE(session, (char *)session->err_msg); - - session->err_code = errcode; - session->err_flags = 0; - - if((errmsg != NULL) && ((errflags & LIBSSH2_ERR_FLAG_DUP) != 0)) { - size_t len = strlen(errmsg); - char *copy = LIBSSH2_ALLOC(session, len + 1); - if(copy) { - memcpy(copy, errmsg, len + 1); - session->err_flags = LIBSSH2_ERR_FLAG_DUP; - session->err_msg = copy; - } - else - /* Out of memory: this code path is very unlikely */ - session->err_msg = "former error forgotten (OOM)"; - } - else - session->err_msg = errmsg; - -#ifdef LIBSSH2DEBUG - if((errcode == LIBSSH2_ERROR_EAGAIN) && !session->api_block_mode) - /* if this is EAGAIN and we're in non-blocking mode, don't generate - a debug output for this */ - return errcode; - _libssh2_debug(session, LIBSSH2_TRACE_ERROR, "%d - %s", session->err_code, - session->err_msg); -#endif - - return errcode; -} - -int _libssh2_error(LIBSSH2_SESSION* session, int errcode, const char *errmsg) -{ - return _libssh2_error_flags(session, errcode, errmsg, 0); -} - -#ifdef WIN32 -static int wsa2errno(void) -{ - switch(WSAGetLastError()) { - case WSAEWOULDBLOCK: - return EAGAIN; - - case WSAENOTSOCK: - return EBADF; - - case WSAEINTR: - return EINTR; - - default: - /* It is most important to ensure errno does not stay at EAGAIN - * when a different error occurs so just set errno to a generic - * error */ - return EIO; - } -} -#endif - -/* _libssh2_recv - * - * Replacement for the standard recv, return -errno on failure. - */ -ssize_t -_libssh2_recv(libssh2_socket_t sock, void *buffer, size_t length, - int flags, void **abstract) -{ - ssize_t rc; - - (void) abstract; - - rc = recv(sock, buffer, length, flags); -#ifdef WIN32 - if(rc < 0) - return -wsa2errno(); -#else - if(rc < 0) { - /* Sometimes the first recv() function call sets errno to ENOENT on - Solaris and HP-UX */ - if(errno == ENOENT) - return -EAGAIN; -#ifdef EWOULDBLOCK /* For VMS and other special unixes */ - else if(errno == EWOULDBLOCK) - return -EAGAIN; -#endif - else - return -errno; - } -#endif - return rc; -} - -/* _libssh2_send - * - * Replacement for the standard send, return -errno on failure. - */ -ssize_t -_libssh2_send(libssh2_socket_t sock, const void *buffer, size_t length, - int flags, void **abstract) -{ - ssize_t rc; - - (void) abstract; - - rc = send(sock, buffer, length, flags); -#ifdef WIN32 - if(rc < 0) - return -wsa2errno(); -#else - if(rc < 0) { -#ifdef EWOULDBLOCK /* For VMS and other special unixes */ - if(errno == EWOULDBLOCK) - return -EAGAIN; -#endif - return -errno; - } -#endif - return rc; -} - -/* libssh2_ntohu32 - */ -unsigned int -_libssh2_ntohu32(const unsigned char *buf) -{ - return (((unsigned int)buf[0] << 24) - | ((unsigned int)buf[1] << 16) - | ((unsigned int)buf[2] << 8) - | ((unsigned int)buf[3])); -} - - -/* _libssh2_ntohu64 - */ -libssh2_uint64_t -_libssh2_ntohu64(const unsigned char *buf) -{ - unsigned long msl, lsl; - - msl = ((libssh2_uint64_t)buf[0] << 24) | ((libssh2_uint64_t)buf[1] << 16) - | ((libssh2_uint64_t)buf[2] << 8) | (libssh2_uint64_t)buf[3]; - lsl = ((libssh2_uint64_t)buf[4] << 24) | ((libssh2_uint64_t)buf[5] << 16) - | ((libssh2_uint64_t)buf[6] << 8) | (libssh2_uint64_t)buf[7]; - - return ((libssh2_uint64_t)msl <<32) | lsl; -} - -/* _libssh2_htonu32 - */ -void -_libssh2_htonu32(unsigned char *buf, uint32_t value) -{ - buf[0] = (value >> 24) & 0xFF; - buf[1] = (value >> 16) & 0xFF; - buf[2] = (value >> 8) & 0xFF; - buf[3] = value & 0xFF; -} - -/* _libssh2_store_u32 - */ -void _libssh2_store_u32(unsigned char **buf, uint32_t value) -{ - _libssh2_htonu32(*buf, value); - *buf += sizeof(uint32_t); -} - -/* _libssh2_store_str - */ -void _libssh2_store_str(unsigned char **buf, const char *str, size_t len) -{ - _libssh2_store_u32(buf, (uint32_t)len); - if(len) { - memcpy(*buf, str, len); - *buf += len; - } -} - -/* Base64 Conversion */ - -static const short base64_reverse_table[256] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, - -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, - -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 -}; - -/* libssh2_base64_decode - * - * Decode a base64 chunk and store it into a newly alloc'd buffer - */ -LIBSSH2_API int -libssh2_base64_decode(LIBSSH2_SESSION *session, char **data, - unsigned int *datalen, const char *src, - unsigned int src_len) -{ - unsigned char *s, *d; - short v; - int i = 0, len = 0; - - *data = LIBSSH2_ALLOC(session, (3 * src_len / 4) + 1); - d = (unsigned char *) *data; - if(!d) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for base64 decoding"); - } - - for(s = (unsigned char *) src; ((char *) s) < (src + src_len); s++) { - v = base64_reverse_table[*s]; - if(v < 0) - continue; - switch(i % 4) { - case 0: - d[len] = (unsigned char)(v << 2); - break; - case 1: - d[len++] |= v >> 4; - d[len] = (unsigned char)(v << 4); - break; - case 2: - d[len++] |= v >> 2; - d[len] = (unsigned char)(v << 6); - break; - case 3: - d[len++] |= v; - break; - } - i++; - } - if((i % 4) == 1) { - /* Invalid -- We have a byte which belongs exclusively to a partial - octet */ - LIBSSH2_FREE(session, *data); - *data = NULL; - return _libssh2_error(session, LIBSSH2_ERROR_INVAL, "Invalid base64"); - } - - *datalen = len; - return 0; -} - -/* ---- Base64 Encoding/Decoding Table --- */ -static const char table64[]= - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -/* - * _libssh2_base64_encode() - * - * Returns the length of the newly created base64 string. The third argument - * is a pointer to an allocated area holding the base64 data. If something - * went wrong, 0 is returned. - * - */ -size_t _libssh2_base64_encode(LIBSSH2_SESSION *session, - const char *inp, size_t insize, char **outptr) -{ - unsigned char ibuf[3]; - unsigned char obuf[4]; - int i; - int inputparts; - char *output; - char *base64data; - const char *indata = inp; - - *outptr = NULL; /* set to NULL in case of failure before we reach the - end */ - - if(0 == insize) - insize = strlen(indata); - - base64data = output = LIBSSH2_ALLOC(session, insize * 4 / 3 + 4); - if(NULL == output) - return 0; - - while(insize > 0) { - for(i = inputparts = 0; i < 3; i++) { - if(insize > 0) { - inputparts++; - ibuf[i] = *indata; - indata++; - insize--; - } - else - ibuf[i] = 0; - } - - obuf[0] = (unsigned char) ((ibuf[0] & 0xFC) >> 2); - obuf[1] = (unsigned char) (((ibuf[0] & 0x03) << 4) | \ - ((ibuf[1] & 0xF0) >> 4)); - obuf[2] = (unsigned char) (((ibuf[1] & 0x0F) << 2) | \ - ((ibuf[2] & 0xC0) >> 6)); - obuf[3] = (unsigned char) (ibuf[2] & 0x3F); - - switch(inputparts) { - case 1: /* only one byte read */ - snprintf(output, 5, "%c%c==", - table64[obuf[0]], - table64[obuf[1]]); - break; - case 2: /* two bytes read */ - snprintf(output, 5, "%c%c%c=", - table64[obuf[0]], - table64[obuf[1]], - table64[obuf[2]]); - break; - default: - snprintf(output, 5, "%c%c%c%c", - table64[obuf[0]], - table64[obuf[1]], - table64[obuf[2]], - table64[obuf[3]]); - break; - } - output += 4; - } - *output = 0; - *outptr = base64data; /* make it return the actual data memory */ - - return strlen(base64data); /* return the length of the new data */ -} -/* ---- End of Base64 Encoding ---- */ - -LIBSSH2_API void -libssh2_free(LIBSSH2_SESSION *session, void *ptr) -{ - LIBSSH2_FREE(session, ptr); -} - -#ifdef LIBSSH2DEBUG -#include - -LIBSSH2_API int -libssh2_trace(LIBSSH2_SESSION * session, int bitmask) -{ - session->showmask = bitmask; - return 0; -} - -LIBSSH2_API int -libssh2_trace_sethandler(LIBSSH2_SESSION *session, void *handler_context, - libssh2_trace_handler_func callback) -{ - session->tracehandler = callback; - session->tracehandler_context = handler_context; - return 0; -} - -void -_libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, ...) -{ - char buffer[1536]; - int len, msglen, buflen = sizeof(buffer); - va_list vargs; - struct timeval now; - static int firstsec; - static const char *const contexts[] = { - "Unknown", - "Transport", - "Key Ex", - "Userauth", - "Conn", - "SCP", - "SFTP", - "Failure Event", - "Publickey", - "Socket", - }; - const char *contexttext = contexts[0]; - unsigned int contextindex; - - if(!(session->showmask & context)) { - /* no such output asked for */ - return; - } - - /* Find the first matching context string for this message */ - for(contextindex = 0; contextindex < ARRAY_SIZE(contexts); - contextindex++) { - if((context & (1 << contextindex)) != 0) { - contexttext = contexts[contextindex]; - break; - } - } - - _libssh2_gettimeofday(&now, NULL); - if(!firstsec) { - firstsec = now.tv_sec; - } - now.tv_sec -= firstsec; - - len = snprintf(buffer, buflen, "[libssh2] %d.%06d %s: ", - (int)now.tv_sec, (int)now.tv_usec, contexttext); - - if(len >= buflen) - msglen = buflen - 1; - else { - buflen -= len; - msglen = len; - va_start(vargs, format); - len = vsnprintf(buffer + msglen, buflen, format, vargs); - va_end(vargs); - msglen += len < buflen ? len : buflen - 1; - } - - if(session->tracehandler) - (session->tracehandler)(session, session->tracehandler_context, buffer, - msglen); - else - fprintf(stderr, "%s\n", buffer); -} - -#else -LIBSSH2_API int -libssh2_trace(LIBSSH2_SESSION * session, int bitmask) -{ - (void) session; - (void) bitmask; - return 0; -} - -LIBSSH2_API int -libssh2_trace_sethandler(LIBSSH2_SESSION *session, void *handler_context, - libssh2_trace_handler_func callback) -{ - (void) session; - (void) handler_context; - (void) callback; - return 0; -} -#endif - -/* init the list head */ -void _libssh2_list_init(struct list_head *head) -{ - head->first = head->last = NULL; -} - -/* add a node to the list */ -void _libssh2_list_add(struct list_head *head, - struct list_node *entry) -{ - /* store a pointer to the head */ - entry->head = head; - - /* we add this entry at the "top" so it has no next */ - entry->next = NULL; - - /* make our prev point to what the head thinks is last */ - entry->prev = head->last; - - /* and make head's last be us now */ - head->last = entry; - - /* make sure our 'prev' node points to us next */ - if(entry->prev) - entry->prev->next = entry; - else - head->first = entry; -} - -/* return the "first" node in the list this head points to */ -void *_libssh2_list_first(struct list_head *head) -{ - return head->first; -} - -/* return the next node in the list */ -void *_libssh2_list_next(struct list_node *node) -{ - return node->next; -} - -/* return the prev node in the list */ -void *_libssh2_list_prev(struct list_node *node) -{ - return node->prev; -} - -/* remove this node from the list */ -void _libssh2_list_remove(struct list_node *entry) -{ - if(entry->prev) - entry->prev->next = entry->next; - else - entry->head->first = entry->next; - - if(entry->next) - entry->next->prev = entry->prev; - else - entry->head->last = entry->prev; -} - -#if 0 -/* insert a node before the given 'after' entry */ -void _libssh2_list_insert(struct list_node *after, /* insert before this */ - struct list_node *entry) -{ - /* 'after' is next to 'entry' */ - bentry->next = after; - - /* entry's prev is then made to be the prev after current has */ - entry->prev = after->prev; - - /* the node that is now before 'entry' was previously before 'after' - and must be made to point to 'entry' correctly */ - if(entry->prev) - entry->prev->next = entry; - else - /* there was no node before this, so we make sure we point the head - pointer to this node */ - after->head->first = entry; - - /* after's prev entry points back to entry */ - after->prev = entry; - - /* after's next entry is still the same as before */ - - /* entry's head is the same as after's */ - entry->head = after->head; -} - -#endif - -/* this define is defined in misc.h for the correct platforms */ -#ifdef LIBSSH2_GETTIMEOFDAY_WIN32 -/* - * gettimeofday - * Implementation according to: - * The Open Group Base Specifications Issue 6 - * IEEE Std 1003.1, 2004 Edition - */ - -/* - * THIS SOFTWARE IS NOT COPYRIGHTED - * - * This source code is offered for use in the public domain. You may - * use, modify or distribute it freely. - * - * This code is distributed in the hope that it will be useful but - * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY - * DISCLAIMED. This includes but is not limited to warranties of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Contributed by: - * Danny Smith - */ - -/* Offset between 1/1/1601 and 1/1/1970 in 100 nanosec units */ -#define _W32_FT_OFFSET (116444736000000000) - -int __cdecl _libssh2_gettimeofday(struct timeval *tp, void *tzp) -{ - union { - unsigned __int64 ns100; /*time since 1 Jan 1601 in 100ns units */ - FILETIME ft; - } _now; - (void)tzp; - if(tp) { - GetSystemTimeAsFileTime(&_now.ft); - tp->tv_usec = (long)((_now.ns100 / 10) % 1000000); - tp->tv_sec = (long)((_now.ns100 - _W32_FT_OFFSET) / 10000000); - } - /* Always return 0 as per Open Group Base Specifications Issue 6. - Do not set errno on error. */ - return 0; -} - - -#endif - -void *_libssh2_calloc(LIBSSH2_SESSION* session, size_t size) -{ - void *p = LIBSSH2_ALLOC(session, size); - if(p) { - memset(p, 0, size); - } - return p; -} - -/* XOR operation on buffers input1 and input2, result in output. - It is safe to use an input buffer as the output buffer. */ -void _libssh2_xor_data(unsigned char *output, - const unsigned char *input1, - const unsigned char *input2, - size_t length) -{ - size_t i; - - for(i = 0; i < length; i++) - *output++ = *input1++ ^ *input2++; -} - -/* Increments an AES CTR buffer to prepare it for use with the - next AES block. */ -void _libssh2_aes_ctr_increment(unsigned char *ctr, - size_t length) -{ - unsigned char *pc; - unsigned int val, carry; - - pc = ctr + length - 1; - carry = 1; - - while(pc >= ctr) { - val = (unsigned int)*pc + carry; - *pc-- = val & 0xFF; - carry = val >> 8; - } -} - -#ifdef WIN32 -static void * (__cdecl * const volatile memset_libssh)(void *, int, size_t) = - memset; -#else -static void * (* const volatile memset_libssh)(void *, int, size_t) = memset; -#endif - -void _libssh2_explicit_zero(void *buf, size_t size) -{ -#if defined(HAVE_DECL_SECUREZEROMEMORY) && HAVE_DECL_SECUREZEROMEMORY - SecureZeroMemory(buf, size); - (void)memset_libssh; /* Silence unused variable warning */ -#elif defined(HAVE_MEMSET_S) - (void)memset_s(buf, size, 0, size); - (void)memset_libssh; /* Silence unused variable warning */ -#else - memset_libssh(buf, 0, size); -#endif -} - -/* String buffer */ - -struct string_buf* _libssh2_string_buf_new(LIBSSH2_SESSION *session) -{ - struct string_buf *ret; - - ret = _libssh2_calloc(session, sizeof(*ret)); - if(ret == NULL) - return NULL; - - return ret; -} - -void _libssh2_string_buf_free(LIBSSH2_SESSION *session, struct string_buf *buf) -{ - if(buf == NULL) - return; - - if(buf->data != NULL) - LIBSSH2_FREE(session, buf->data); - - LIBSSH2_FREE(session, buf); - buf = NULL; -} - -int _libssh2_get_u32(struct string_buf *buf, uint32_t *out) -{ - if(!_libssh2_check_length(buf, 4)) { - return -1; - } - - *out = _libssh2_ntohu32(buf->dataptr); - buf->dataptr += 4; - return 0; -} - -int _libssh2_get_u64(struct string_buf *buf, libssh2_uint64_t *out) -{ - if(!_libssh2_check_length(buf, 8)) { - return -1; - } - - *out = _libssh2_ntohu64(buf->dataptr); - buf->dataptr += 8; - return 0; -} - -int _libssh2_match_string(struct string_buf *buf, const char *match) -{ - unsigned char *out; - size_t len = 0; - if(_libssh2_get_string(buf, &out, &len) || len != strlen(match) || - strncmp((char *)out, match, strlen(match)) != 0) { - return -1; - } - return 0; -} - -int _libssh2_get_string(struct string_buf *buf, unsigned char **outbuf, - size_t *outlen) -{ - uint32_t data_len; - if(_libssh2_get_u32(buf, &data_len) != 0) { - return -1; - } - if(!_libssh2_check_length(buf, data_len)) { - return -1; - } - *outbuf = buf->dataptr; - buf->dataptr += data_len; - - if(outlen) - *outlen = (size_t)data_len; - - return 0; -} - -int _libssh2_copy_string(LIBSSH2_SESSION *session, struct string_buf *buf, - unsigned char **outbuf, size_t *outlen) -{ - size_t str_len; - unsigned char *str; - - if(_libssh2_get_string(buf, &str, &str_len)) { - return -1; - } - - *outbuf = LIBSSH2_ALLOC(session, str_len); - if(*outbuf) { - memcpy(*outbuf, str, str_len); - } - else { - return -1; - } - - if(outlen) - *outlen = str_len; - - return 0; -} - -int _libssh2_get_bignum_bytes(struct string_buf *buf, unsigned char **outbuf, - size_t *outlen) -{ - uint32_t data_len; - uint32_t bn_len; - unsigned char *bnptr; - - if(_libssh2_get_u32(buf, &data_len)) { - return -1; - } - if(!_libssh2_check_length(buf, data_len)) { - return -1; - } - - bn_len = data_len; - bnptr = buf->dataptr; - - /* trim leading zeros */ - while(bn_len > 0 && *bnptr == 0x00) { - bn_len--; - bnptr++; - } - - *outbuf = bnptr; - buf->dataptr += data_len; - - if(outlen) - *outlen = (size_t)bn_len; - - return 0; -} - -/* Given the current location in buf, _libssh2_check_length ensures - callers can read the next len number of bytes out of the buffer - before reading the buffer content */ - -int _libssh2_check_length(struct string_buf *buf, size_t len) -{ - unsigned char *endp = &buf->data[buf->len]; - size_t left = endp - buf->dataptr; - return ((len <= left) && (left <= buf->len)); -} - -/* Wrappers */ - -int _libssh2_bcrypt_pbkdf(const char *pass, - size_t passlen, - const uint8_t *salt, - size_t saltlen, - uint8_t *key, - size_t keylen, - unsigned int rounds) -{ - /* defined in bcrypt_pbkdf.c */ - return bcrypt_pbkdf(pass, - passlen, - salt, - saltlen, - key, - keylen, - rounds); -} diff --git a/libssh2/module.mk b/libssh2/module.mk deleted file mode 100644 index 34a3f0e..0000000 --- a/libssh2/module.mk +++ /dev/null @@ -1,40 +0,0 @@ -####################################################################### -# -# pgAdmin III - PostgreSQL Tools -# -# Copyright (C) 2002 - 2016, The pgAdmin Development Team -# This software is released under the PostgreSQL Licence -# -# module.mk - pgadmin/libssh2 Makefile fragment -# -####################################################################### - -if BUILD_SSH_TUNNEL - -pgadmin3_SOURCES += \ - libssh2/agent.c \ - libssh2/channel.c \ - libssh2/comp.c \ - libssh2/crypt.c \ - libssh2/global.c \ - libssh2/hostkey.c \ - libssh2/keepalive.c \ - libssh2/kex.c \ - libssh2/knownhost.c \ - libssh2/libgcrypt.c \ - libssh2/mac.c \ - libssh2/misc.c \ - libssh2/openssl.c \ - libssh2/packet.c \ - libssh2/pem.c \ - libssh2/publickey.c \ - libssh2/scp.c \ - libssh2/session.c \ - libssh2/sftp.c \ - libssh2/transport.c \ - libssh2/userauth.c \ - libssh2/version.c - -EXTRA_DIST += \ - libssh2/module.mk -endif diff --git a/libssh2/openssl.c b/libssh2/openssl.c deleted file mode 100644 index 9d3b8c7..0000000 --- a/libssh2/openssl.c +++ /dev/null @@ -1,3294 +0,0 @@ -/* Copyright (C) 2009, 2010 Simon Josefsson - * Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved. - * Copyright (c) 2004-2006, Sara Golemon - * - * Author: Simon Josefsson - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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 "libssh2_priv.h" - -#ifdef LIBSSH2_OPENSSL /* compile only if we build with openssl */ - -#include -#include "misc.h" - -#ifndef EVP_MAX_BLOCK_LENGTH -#define EVP_MAX_BLOCK_LENGTH 32 -#endif - -int -read_openssh_private_key_from_memory(void **key_ctx, LIBSSH2_SESSION *session, - const char *key_type, - const char *filedata, - size_t filedata_len, - unsigned const char *passphrase); - -static unsigned char * -write_bn(unsigned char *buf, const BIGNUM *bn, int bn_bytes) -{ - unsigned char *p = buf; - - /* Left space for bn size which will be written below. */ - p += 4; - - *p = 0; - BN_bn2bin(bn, p + 1); - if(!(*(p + 1) & 0x80)) { - memmove(p, p + 1, --bn_bytes); - } - _libssh2_htonu32(p - 4, bn_bytes); /* Post write bn size. */ - - return p + bn_bytes; -} - -int -_libssh2_rsa_new(libssh2_rsa_ctx ** rsa, - const unsigned char *edata, - unsigned long elen, - const unsigned char *ndata, - unsigned long nlen, - const unsigned char *ddata, - unsigned long dlen, - const unsigned char *pdata, - unsigned long plen, - const unsigned char *qdata, - unsigned long qlen, - const unsigned char *e1data, - unsigned long e1len, - const unsigned char *e2data, - unsigned long e2len, - const unsigned char *coeffdata, unsigned long coefflen) -{ - BIGNUM * e; - BIGNUM * n; - BIGNUM * d = 0; - BIGNUM * p = 0; - BIGNUM * q = 0; - BIGNUM * dmp1 = 0; - BIGNUM * dmq1 = 0; - BIGNUM * iqmp = 0; - - e = BN_new(); - BN_bin2bn(edata, elen, e); - - n = BN_new(); - BN_bin2bn(ndata, nlen, n); - - if(ddata) { - d = BN_new(); - BN_bin2bn(ddata, dlen, d); - - p = BN_new(); - BN_bin2bn(pdata, plen, p); - - q = BN_new(); - BN_bin2bn(qdata, qlen, q); - - dmp1 = BN_new(); - BN_bin2bn(e1data, e1len, dmp1); - - dmq1 = BN_new(); - BN_bin2bn(e2data, e2len, dmq1); - - iqmp = BN_new(); - BN_bin2bn(coeffdata, coefflen, iqmp); - } - - *rsa = RSA_new(); -#ifdef HAVE_OPAQUE_STRUCTS - RSA_set0_key(*rsa, n, e, d); -#else - (*rsa)->e = e; - (*rsa)->n = n; - (*rsa)->d = d; -#endif - -#ifdef HAVE_OPAQUE_STRUCTS - RSA_set0_factors(*rsa, p, q); -#else - (*rsa)->p = p; - (*rsa)->q = q; -#endif - -#ifdef HAVE_OPAQUE_STRUCTS - RSA_set0_crt_params(*rsa, dmp1, dmq1, iqmp); -#else - (*rsa)->dmp1 = dmp1; - (*rsa)->dmq1 = dmq1; - (*rsa)->iqmp = iqmp; -#endif - return 0; -} - -int -_libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsactx, - const unsigned char *sig, - unsigned long sig_len, - const unsigned char *m, unsigned long m_len) -{ - unsigned char hash[SHA_DIGEST_LENGTH]; - int ret; - - if(_libssh2_sha1(m, m_len, hash)) - return -1; /* failure */ - ret = RSA_verify(NID_sha1, hash, SHA_DIGEST_LENGTH, - (unsigned char *) sig, sig_len, rsactx); - return (ret == 1) ? 0 : -1; -} - -#if LIBSSH2_DSA -int -_libssh2_dsa_new(libssh2_dsa_ctx ** dsactx, - const unsigned char *p, - unsigned long p_len, - const unsigned char *q, - unsigned long q_len, - const unsigned char *g, - unsigned long g_len, - const unsigned char *y, - unsigned long y_len, - const unsigned char *x, unsigned long x_len) -{ - BIGNUM * p_bn; - BIGNUM * q_bn; - BIGNUM * g_bn; - BIGNUM * pub_key; - BIGNUM * priv_key = NULL; - - p_bn = BN_new(); - BN_bin2bn(p, p_len, p_bn); - - q_bn = BN_new(); - BN_bin2bn(q, q_len, q_bn); - - g_bn = BN_new(); - BN_bin2bn(g, g_len, g_bn); - - pub_key = BN_new(); - BN_bin2bn(y, y_len, pub_key); - - if(x_len) { - priv_key = BN_new(); - BN_bin2bn(x, x_len, priv_key); - } - - *dsactx = DSA_new(); - -#ifdef HAVE_OPAQUE_STRUCTS - DSA_set0_pqg(*dsactx, p_bn, q_bn, g_bn); -#else - (*dsactx)->p = p_bn; - (*dsactx)->g = g_bn; - (*dsactx)->q = q_bn; -#endif - -#ifdef HAVE_OPAQUE_STRUCTS - DSA_set0_key(*dsactx, pub_key, priv_key); -#else - (*dsactx)->pub_key = pub_key; - (*dsactx)->priv_key = priv_key; -#endif - return 0; -} - -int -_libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx, - const unsigned char *sig, - const unsigned char *m, unsigned long m_len) -{ - unsigned char hash[SHA_DIGEST_LENGTH]; - DSA_SIG * dsasig; - BIGNUM * r; - BIGNUM * s; - int ret = -1; - - r = BN_new(); - BN_bin2bn(sig, 20, r); - s = BN_new(); - BN_bin2bn(sig + 20, 20, s); - - dsasig = DSA_SIG_new(); -#ifdef HAVE_OPAQUE_STRUCTS - DSA_SIG_set0(dsasig, r, s); -#else - dsasig->r = r; - dsasig->s = s; -#endif - if(!_libssh2_sha1(m, m_len, hash)) - /* _libssh2_sha1() succeeded */ - ret = DSA_do_verify(hash, SHA_DIGEST_LENGTH, dsasig, dsactx); - - DSA_SIG_free(dsasig); - - return (ret == 1) ? 0 : -1; -} -#endif /* LIBSSH_DSA */ - -#if LIBSSH2_ECDSA - -/* _libssh2_ecdsa_get_curve_type - * - * returns key curve type that maps to libssh2_curve_type - * - */ - -libssh2_curve_type -_libssh2_ecdsa_get_curve_type(libssh2_ecdsa_ctx *ec_ctx) -{ - const EC_GROUP *group = EC_KEY_get0_group(ec_ctx); - return EC_GROUP_get_curve_name(group); -} - -/* _libssh2_ecdsa_curve_type_from_name - * - * returns 0 for success, key curve type that maps to libssh2_curve_type - * - */ - -int -_libssh2_ecdsa_curve_type_from_name(const char *name, - libssh2_curve_type *out_type) -{ - int ret = 0; - libssh2_curve_type type; - - if(name == NULL || strlen(name) != 19) - return -1; - - if(strcmp(name, "ecdsa-sha2-nistp256") == 0) - type = LIBSSH2_EC_CURVE_NISTP256; - else if(strcmp(name, "ecdsa-sha2-nistp384") == 0) - type = LIBSSH2_EC_CURVE_NISTP384; - else if(strcmp(name, "ecdsa-sha2-nistp521") == 0) - type = LIBSSH2_EC_CURVE_NISTP521; - else { - ret = -1; - } - - if(ret == 0 && out_type) { - *out_type = type; - } - - return ret; -} - -/* _libssh2_ecdsa_curve_name_with_octal_new - * - * Creates a new public key given an octal string, length and type - * - */ - -int -_libssh2_ecdsa_curve_name_with_octal_new(libssh2_ecdsa_ctx ** ec_ctx, - const unsigned char *k, - size_t k_len, libssh2_curve_type curve) -{ - - int ret = 0; - const EC_GROUP *ec_group = NULL; - EC_KEY *ec_key = EC_KEY_new_by_curve_name(curve); - EC_POINT *point = NULL; - - if(ec_key) { - ec_group = EC_KEY_get0_group(ec_key); - point = EC_POINT_new(ec_group); - ret = EC_POINT_oct2point(ec_group, point, k, k_len, NULL); - ret = EC_KEY_set_public_key(ec_key, point); - - if(point != NULL) - EC_POINT_free(point); - - if(ec_ctx != NULL) - *ec_ctx = ec_key; - } - - return (ret == 1) ? 0 : -1; -} - -#define LIBSSH2_ECDSA_VERIFY(digest_type) \ -{ \ - unsigned char hash[SHA##digest_type##_DIGEST_LENGTH]; \ - libssh2_sha##digest_type(m, m_len, hash); \ - ret = ECDSA_do_verify(hash, SHA##digest_type##_DIGEST_LENGTH, \ - ecdsa_sig, ec_key); \ - \ -} - -int -_libssh2_ecdsa_verify(libssh2_ecdsa_ctx * ctx, - const unsigned char *r, size_t r_len, - const unsigned char *s, size_t s_len, - const unsigned char *m, size_t m_len) -{ - int ret = 0; - EC_KEY *ec_key = (EC_KEY*)ctx; - libssh2_curve_type type = _libssh2_ecdsa_get_curve_type(ec_key); - -#ifdef HAVE_OPAQUE_STRUCTS - ECDSA_SIG *ecdsa_sig = ECDSA_SIG_new(); - BIGNUM *pr = BN_new(); - BIGNUM *ps = BN_new(); - - BN_bin2bn(r, r_len, pr); - BN_bin2bn(s, s_len, ps); - ECDSA_SIG_set0(ecdsa_sig, pr, ps); - -#else - ECDSA_SIG ecdsa_sig_; - ECDSA_SIG *ecdsa_sig = &ecdsa_sig_; - ecdsa_sig_.r = BN_new(); - BN_bin2bn(r, r_len, ecdsa_sig_.r); - ecdsa_sig_.s = BN_new(); - BN_bin2bn(s, s_len, ecdsa_sig_.s); -#endif - - if(type == LIBSSH2_EC_CURVE_NISTP256) { - LIBSSH2_ECDSA_VERIFY(256); - } - else if(type == LIBSSH2_EC_CURVE_NISTP384) { - LIBSSH2_ECDSA_VERIFY(384); - } - else if(type == LIBSSH2_EC_CURVE_NISTP521) { - LIBSSH2_ECDSA_VERIFY(512); - } - -#ifdef HAVE_OPAQUE_STRUCTS - if(ecdsa_sig) - ECDSA_SIG_free(ecdsa_sig); -#else - BN_clear_free(ecdsa_sig_.s); - BN_clear_free(ecdsa_sig_.r); -#endif - - return (ret == 1) ? 0 : -1; -} - -#endif /* LIBSSH2_ECDSA */ - -int -_libssh2_cipher_init(_libssh2_cipher_ctx * h, - _libssh2_cipher_type(algo), - unsigned char *iv, unsigned char *secret, int encrypt) -{ -#ifdef HAVE_OPAQUE_STRUCTS - *h = EVP_CIPHER_CTX_new(); - return !EVP_CipherInit(*h, algo(), secret, iv, encrypt); -#else - EVP_CIPHER_CTX_init(h); - return !EVP_CipherInit(h, algo(), secret, iv, encrypt); -#endif -} - -int -_libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx, - _libssh2_cipher_type(algo), - int encrypt, unsigned char *block, size_t blocksize) -{ - unsigned char buf[EVP_MAX_BLOCK_LENGTH]; - int ret; - (void) algo; - (void) encrypt; - -#ifdef HAVE_OPAQUE_STRUCTS - ret = EVP_Cipher(*ctx, buf, block, blocksize); -#else - ret = EVP_Cipher(ctx, buf, block, blocksize); -#endif - if(ret == 1) { - memcpy(block, buf, blocksize); - } - return ret == 1 ? 0 : 1; -} - -#if LIBSSH2_AES_CTR && !defined(HAVE_EVP_AES_128_CTR) - -#include -#include - -typedef struct -{ - AES_KEY key; - EVP_CIPHER_CTX *aes_ctx; - unsigned char ctr[AES_BLOCK_SIZE]; -} aes_ctr_ctx; - -static EVP_CIPHER * aes_128_ctr_cipher = NULL; -static EVP_CIPHER * aes_192_ctr_cipher = NULL; -static EVP_CIPHER * aes_256_ctr_cipher = NULL; - -static int -aes_ctr_init(EVP_CIPHER_CTX *ctx, const unsigned char *key, - const unsigned char *iv, int enc) /* init key */ -{ - /* - * variable "c" is leaked from this scope, but is later freed - * in aes_ctr_cleanup - */ - aes_ctr_ctx *c; - const EVP_CIPHER *aes_cipher; - (void) enc; - - switch(EVP_CIPHER_CTX_key_length(ctx)) { - case 16: - aes_cipher = EVP_aes_128_ecb(); - break; - case 24: - aes_cipher = EVP_aes_192_ecb(); - break; - case 32: - aes_cipher = EVP_aes_256_ecb(); - break; - default: - return 0; - } - - c = malloc(sizeof(*c)); - if(c == NULL) - return 0; - -#ifdef HAVE_OPAQUE_STRUCTS - c->aes_ctx = EVP_CIPHER_CTX_new(); -#else - c->aes_ctx = malloc(sizeof(EVP_CIPHER_CTX)); -#endif - if(c->aes_ctx == NULL) { - free(c); - return 0; - } - - if(EVP_EncryptInit(c->aes_ctx, aes_cipher, key, NULL) != 1) { -#ifdef HAVE_OPAQUE_STRUCTS - EVP_CIPHER_CTX_free(c->aes_ctx); -#else - free(c->aes_ctx); -#endif - free(c); - return 0; - } - - EVP_CIPHER_CTX_set_padding(c->aes_ctx, 0); - - memcpy(c->ctr, iv, AES_BLOCK_SIZE); - - EVP_CIPHER_CTX_set_app_data(ctx, c); - - return 1; -} - -static int -aes_ctr_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, - const unsigned char *in, - size_t inl) /* encrypt/decrypt data */ -{ - aes_ctr_ctx *c = EVP_CIPHER_CTX_get_app_data(ctx); - unsigned char b1[AES_BLOCK_SIZE]; - int outlen = 0; - - if(inl != 16) /* libssh2 only ever encrypt one block */ - return 0; - - if(c == NULL) { - return 0; - } - -/* - To encrypt a packet P=P1||P2||...||Pn (where P1, P2, ..., Pn are each - blocks of length L), the encryptor first encrypts with - to obtain a block B1. The block B1 is then XORed with P1 to generate - the ciphertext block C1. The counter X is then incremented -*/ - - if(EVP_EncryptUpdate(c->aes_ctx, b1, &outlen, - c->ctr, AES_BLOCK_SIZE) != 1) { - return 0; - } - - _libssh2_xor_data(out, in, b1, AES_BLOCK_SIZE); - _libssh2_aes_ctr_increment(c->ctr, AES_BLOCK_SIZE); - - return 1; -} - -static int -aes_ctr_cleanup(EVP_CIPHER_CTX *ctx) /* cleanup ctx */ -{ - aes_ctr_ctx *c = EVP_CIPHER_CTX_get_app_data(ctx); - - if(c == NULL) { - return 1; - } - - if(c->aes_ctx != NULL) { -#ifdef HAVE_OPAQUE_STRUCTS - EVP_CIPHER_CTX_free(c->aes_ctx); -#else - _libssh2_cipher_dtor(c->aes_ctx); - free(c->aes_ctx); -#endif - } - - free(c); - - return 1; -} - -static const EVP_CIPHER * -make_ctr_evp (size_t keylen, EVP_CIPHER **aes_ctr_cipher, int type) -{ -#ifdef HAVE_OPAQUE_STRUCTS - *aes_ctr_cipher = EVP_CIPHER_meth_new(type, 16, keylen); - if(*aes_ctr_cipher) { - EVP_CIPHER_meth_set_iv_length(*aes_ctr_cipher, 16); - EVP_CIPHER_meth_set_init(*aes_ctr_cipher, aes_ctr_init); - EVP_CIPHER_meth_set_do_cipher(*aes_ctr_cipher, aes_ctr_do_cipher); - EVP_CIPHER_meth_set_cleanup(*aes_ctr_cipher, aes_ctr_cleanup); - } -#else - (*aes_ctr_cipher)->nid = type; - (*aes_ctr_cipher)->block_size = 16; - (*aes_ctr_cipher)->key_len = keylen; - (*aes_ctr_cipher)->iv_len = 16; - (*aes_ctr_cipher)->init = aes_ctr_init; - (*aes_ctr_cipher)->do_cipher = aes_ctr_do_cipher; - (*aes_ctr_cipher)->cleanup = aes_ctr_cleanup; -#endif - - return *aes_ctr_cipher; -} - -const EVP_CIPHER * -_libssh2_EVP_aes_128_ctr(void) -{ -#ifdef HAVE_OPAQUE_STRUCTS - return !aes_128_ctr_cipher ? - make_ctr_evp(16, &aes_128_ctr_cipher, NID_aes_128_ctr) : - aes_128_ctr_cipher; -#else - static EVP_CIPHER aes_ctr_cipher; - if(!aes_128_ctr_cipher) { - aes_128_ctr_cipher = &aes_ctr_cipher; - make_ctr_evp(16, &aes_128_ctr_cipher, 0); - } - return aes_128_ctr_cipher; -#endif -} - -const EVP_CIPHER * -_libssh2_EVP_aes_192_ctr(void) -{ -#ifdef HAVE_OPAQUE_STRUCTS - return !aes_192_ctr_cipher ? - make_ctr_evp(24, &aes_192_ctr_cipher, NID_aes_192_ctr) : - aes_192_ctr_cipher; -#else - static EVP_CIPHER aes_ctr_cipher; - if(!aes_192_ctr_cipher) { - aes_192_ctr_cipher = &aes_ctr_cipher; - make_ctr_evp(24, &aes_192_ctr_cipher, 0); - } - return aes_192_ctr_cipher; -#endif -} - -const EVP_CIPHER * -_libssh2_EVP_aes_256_ctr(void) -{ -#ifdef HAVE_OPAQUE_STRUCTS - return !aes_256_ctr_cipher ? - make_ctr_evp(32, &aes_256_ctr_cipher, NID_aes_256_ctr) : - aes_256_ctr_cipher; -#else - static EVP_CIPHER aes_ctr_cipher; - if(!aes_256_ctr_cipher) { - aes_256_ctr_cipher = &aes_ctr_cipher; - make_ctr_evp(32, &aes_256_ctr_cipher, 0); - } - return aes_256_ctr_cipher; -#endif -} - -#endif /* LIBSSH2_AES_CTR && !defined(HAVE_EVP_AES_128_CTR) */ - -void _libssh2_openssl_crypto_init(void) -{ -#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \ - !defined(LIBRESSL_VERSION_NUMBER) -#ifndef OPENSSL_NO_ENGINE - ENGINE_load_builtin_engines(); - ENGINE_register_all_complete(); -#endif -#else - OpenSSL_add_all_algorithms(); - OpenSSL_add_all_ciphers(); - OpenSSL_add_all_digests(); -#ifndef OPENSSL_NO_ENGINE - ENGINE_load_builtin_engines(); - ENGINE_register_all_complete(); -#endif -#endif -#if LIBSSH2_AES_CTR && !defined(HAVE_EVP_AES_128_CTR) - aes_128_ctr_cipher = (EVP_CIPHER *) _libssh2_EVP_aes_128_ctr(); - aes_192_ctr_cipher = (EVP_CIPHER *) _libssh2_EVP_aes_192_ctr(); - aes_256_ctr_cipher = (EVP_CIPHER *) _libssh2_EVP_aes_256_ctr(); -#endif -} - -void _libssh2_openssl_crypto_exit(void) -{ -#if LIBSSH2_AES_CTR && !defined(HAVE_EVP_AES_128_CTR) -#ifdef HAVE_OPAQUE_STRUCTS - if(aes_128_ctr_cipher) { - EVP_CIPHER_meth_free(aes_128_ctr_cipher); - } - - if(aes_192_ctr_cipher) { - EVP_CIPHER_meth_free(aes_192_ctr_cipher); - } - - if(aes_256_ctr_cipher) { - EVP_CIPHER_meth_free(aes_256_ctr_cipher); - } -#endif - - aes_128_ctr_cipher = NULL; - aes_192_ctr_cipher = NULL; - aes_256_ctr_cipher = NULL; -#endif -} - -/* TODO: Optionally call a passphrase callback specified by the - * calling program - */ -static int -passphrase_cb(char *buf, int size, int rwflag, char *passphrase) -{ - int passphrase_len = strlen(passphrase); - (void) rwflag; - - if(passphrase_len > (size - 1)) { - passphrase_len = size - 1; - } - memcpy(buf, passphrase, passphrase_len); - buf[passphrase_len] = '\0'; - - return passphrase_len; -} - -typedef void * (*pem_read_bio_func)(BIO *, void **, pem_password_cb *, - void *u); - -static int -read_private_key_from_memory(void **key_ctx, - pem_read_bio_func read_private_key, - const char *filedata, - size_t filedata_len, - unsigned const char *passphrase) -{ - BIO * bp; - - *key_ctx = NULL; - - bp = BIO_new_mem_buf((char *)filedata, filedata_len); - if(!bp) { - return -1; - } - *key_ctx = read_private_key(bp, NULL, (pem_password_cb *) passphrase_cb, - (void *) passphrase); - - BIO_free(bp); - return (*key_ctx) ? 0 : -1; -} - - - -static int -read_private_key_from_file(void **key_ctx, - pem_read_bio_func read_private_key, - const char *filename, - unsigned const char *passphrase) -{ - BIO * bp; - - *key_ctx = NULL; - - bp = BIO_new_file(filename, "r"); - if(!bp) { - return -1; - } - - *key_ctx = read_private_key(bp, NULL, (pem_password_cb *) passphrase_cb, - (void *) passphrase); - - BIO_free(bp); - return (*key_ctx) ? 0 : -1; -} - -int -_libssh2_rsa_new_private_frommemory(libssh2_rsa_ctx ** rsa, - LIBSSH2_SESSION * session, - const char *filedata, size_t filedata_len, - unsigned const char *passphrase) -{ - int rc; - - pem_read_bio_func read_rsa = - (pem_read_bio_func) &PEM_read_bio_RSAPrivateKey; - - _libssh2_init_if_needed(); - - rc = read_private_key_from_memory((void **) rsa, read_rsa, - filedata, filedata_len, passphrase); - - if(rc) { - rc = read_openssh_private_key_from_memory((void **)rsa, session, - "ssh-rsa", filedata, filedata_len, passphrase); - } - -return rc; -} - -static unsigned char * -gen_publickey_from_rsa(LIBSSH2_SESSION *session, RSA *rsa, - size_t *key_len) -{ - int e_bytes, n_bytes; - unsigned long len; - unsigned char *key; - unsigned char *p; - const BIGNUM * e; - const BIGNUM * n; -#ifdef HAVE_OPAQUE_STRUCTS - RSA_get0_key(rsa, &n, &e, NULL); -#else - e = rsa->e; - n = rsa->n; -#endif - e_bytes = BN_num_bytes(e) + 1; - n_bytes = BN_num_bytes(n) + 1; - - /* Key form is "ssh-rsa" + e + n. */ - len = 4 + 7 + 4 + e_bytes + 4 + n_bytes; - - key = LIBSSH2_ALLOC(session, len); - if(key == NULL) { - return NULL; - } - - /* Process key encoding. */ - p = key; - - _libssh2_htonu32(p, 7); /* Key type. */ - p += 4; - memcpy(p, "ssh-rsa", 7); - p += 7; - - p = write_bn(p, e, e_bytes); - p = write_bn(p, n, n_bytes); - - *key_len = (size_t)(p - key); - return key; -} - -static int -gen_publickey_from_rsa_evp(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - EVP_PKEY *pk) -{ - RSA* rsa = NULL; - unsigned char *key; - unsigned char *method_buf = NULL; - size_t key_len; - - _libssh2_debug(session, - LIBSSH2_TRACE_AUTH, - "Computing public key from RSA private key envelope"); - - rsa = EVP_PKEY_get1_RSA(pk); - if(rsa == NULL) { - /* Assume memory allocation error... what else could it be ? */ - goto __alloc_error; - } - - method_buf = LIBSSH2_ALLOC(session, 7); /* ssh-rsa. */ - if(method_buf == NULL) { - goto __alloc_error; - } - - key = gen_publickey_from_rsa(session, rsa, &key_len); - if(key == NULL) { - goto __alloc_error; - } - RSA_free(rsa); - - memcpy(method_buf, "ssh-rsa", 7); - *method = method_buf; - *method_len = 7; - *pubkeydata = key; - *pubkeydata_len = key_len; - return 0; - - __alloc_error: - if(rsa != NULL) { - RSA_free(rsa); - } - if(method_buf != NULL) { - LIBSSH2_FREE(session, method_buf); - } - - return _libssh2_error(session, - LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for private key data"); -} - -static int _libssh2_rsa_new_additional_parameters(RSA *rsa) -{ - BN_CTX *ctx = NULL; - BIGNUM *aux = NULL; - BIGNUM *dmp1 = NULL; - BIGNUM *dmq1 = NULL; - const BIGNUM *p = NULL; - const BIGNUM *q = NULL; - const BIGNUM *d = NULL; - int rc = 0; - -#ifdef HAVE_OPAQUE_STRUCTS - RSA_get0_key(rsa, NULL, NULL, &d); - RSA_get0_factors(rsa, &p, &q); -#else - d = (*rsa).d; - p = (*rsa).p; - q = (*rsa).q; -#endif - - ctx = BN_CTX_new(); - if(ctx == NULL) - return -1; - - aux = BN_new(); - if(aux == NULL) { - rc = -1; - goto out; - } - - dmp1 = BN_new(); - if(dmp1 == NULL) { - rc = -1; - goto out; - } - - dmq1 = BN_new(); - if(dmq1 == NULL) { - rc = -1; - goto out; - } - - if((BN_sub(aux, q, BN_value_one()) == 0) || - (BN_mod(dmq1, d, aux, ctx) == 0) || - (BN_sub(aux, p, BN_value_one()) == 0) || - (BN_mod(dmp1, d, aux, ctx) == 0)) { - rc = -1; - goto out; - } - -#ifdef HAVE_OPAQUE_STRUCTS - RSA_set0_crt_params(rsa, dmp1, dmq1, NULL); -#else - (*rsa).dmp1 = dmp1; - (*rsa).dmq1 = dmq1; -#endif - -out: - if(aux) - BN_clear_free(aux); - BN_CTX_free(ctx); - - if(rc != 0) { - if(dmp1) - BN_clear_free(dmp1); - if(dmq1) - BN_clear_free(dmq1); - } - - return rc; -} - -static int -gen_publickey_from_rsa_openssh_priv_data(LIBSSH2_SESSION *session, - struct string_buf *decrypted, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - libssh2_rsa_ctx **rsa_ctx) -{ - int rc = 0; - size_t nlen, elen, dlen, plen, qlen, coefflen, commentlen; - unsigned char *n, *e, *d, *p, *q, *coeff, *comment; - RSA *rsa = NULL; - - _libssh2_debug(session, - LIBSSH2_TRACE_AUTH, - "Computing RSA keys from private key data"); - - /* public key data */ - if(_libssh2_get_bignum_bytes(decrypted, &n, &nlen)) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "RSA no n"); - return -1; - } - - if(_libssh2_get_bignum_bytes(decrypted, &e, &elen)) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "RSA no e"); - return -1; - } - - /* private key data */ - if(_libssh2_get_bignum_bytes(decrypted, &d, &dlen)) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "RSA no d"); - return -1; - } - - if(_libssh2_get_bignum_bytes(decrypted, &coeff, &coefflen)) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "RSA no coeff"); - return -1; - } - - if(_libssh2_get_bignum_bytes(decrypted, &p, &plen)) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "RSA no p"); - return -1; - } - - if(_libssh2_get_bignum_bytes(decrypted, &q, &qlen)) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "RSA no q"); - return -1; - } - - if(_libssh2_get_string(decrypted, &comment, &commentlen)) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "RSA no comment"); - return -1; - } - - if((rc = _libssh2_rsa_new(&rsa, e, elen, n, nlen, d, dlen, p, plen, - q, qlen, NULL, 0, NULL, 0, - coeff, coefflen)) != 0) { - _libssh2_debug(session, - LIBSSH2_TRACE_AUTH, - "Could not create RSA private key"); - goto fail; - } - - if(rsa != NULL) - rc = _libssh2_rsa_new_additional_parameters(rsa); - - if(rsa != NULL && pubkeydata != NULL && method != NULL) { - EVP_PKEY *pk = EVP_PKEY_new(); - EVP_PKEY_set1_RSA(pk, rsa); - - rc = gen_publickey_from_rsa_evp(session, method, method_len, - pubkeydata, pubkeydata_len, - pk); - - if(pk) - EVP_PKEY_free(pk); - } - - if(rsa_ctx != NULL) - *rsa_ctx = rsa; - else - RSA_free(rsa); - - return rc; - -fail: - - if(rsa != NULL) - RSA_free(rsa); - - return _libssh2_error(session, - LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for private key data"); -} - -static int -_libssh2_rsa_new_openssh_private(libssh2_rsa_ctx ** rsa, - LIBSSH2_SESSION * session, - const char *filename, - unsigned const char *passphrase) -{ - FILE *fp; - int rc; - unsigned char *buf = NULL; - struct string_buf *decrypted = NULL; - - if(session == NULL) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Session is required"); - return -1; - } - - _libssh2_init_if_needed(); - - fp = fopen(filename, "r"); - if(!fp) { - _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Unable to open OpenSSH RSA private key file"); - return -1; - } - - rc = _libssh2_openssh_pem_parse(session, passphrase, fp, &decrypted); - fclose(fp); - if(rc) { - return rc; - } - - /* We have a new key file, now try and parse it using supported types */ - rc = _libssh2_get_string(decrypted, &buf, NULL); - - if(rc != 0 || buf == NULL) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Public key type in decrypted key data not found"); - return -1; - } - - if(strcmp("ssh-rsa", (const char *)buf) == 0) { - rc = gen_publickey_from_rsa_openssh_priv_data(session, decrypted, - NULL, 0, - NULL, 0, rsa); - } - else { - rc = -1; - } - - if(decrypted) - _libssh2_string_buf_free(session, decrypted); - - return rc; -} - -int -_libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa, - LIBSSH2_SESSION * session, - const char *filename, unsigned const char *passphrase) -{ - int rc; - - pem_read_bio_func read_rsa = - (pem_read_bio_func) &PEM_read_bio_RSAPrivateKey; - - _libssh2_init_if_needed(); - - rc = read_private_key_from_file((void **) rsa, read_rsa, - filename, passphrase); - - if(rc) { - rc = _libssh2_rsa_new_openssh_private(rsa, session, - filename, passphrase); - } - - return rc; -} - -#if LIBSSH2_DSA -int -_libssh2_dsa_new_private_frommemory(libssh2_dsa_ctx ** dsa, - LIBSSH2_SESSION * session, - const char *filedata, size_t filedata_len, - unsigned const char *passphrase) -{ - int rc; - - pem_read_bio_func read_dsa = - (pem_read_bio_func) &PEM_read_bio_DSAPrivateKey; - - _libssh2_init_if_needed(); - - rc = read_private_key_from_memory((void **)dsa, read_dsa, - filedata, filedata_len, passphrase); - - if(rc) { - rc = read_openssh_private_key_from_memory((void **)dsa, session, - "ssh-dsa", filedata, filedata_len, passphrase); - } - - return rc; -} - -static unsigned char * -gen_publickey_from_dsa(LIBSSH2_SESSION* session, DSA *dsa, - size_t *key_len) -{ - int p_bytes, q_bytes, g_bytes, k_bytes; - unsigned long len; - unsigned char *key; - unsigned char *p; - - const BIGNUM * p_bn; - const BIGNUM * q; - const BIGNUM * g; - const BIGNUM * pub_key; -#ifdef HAVE_OPAQUE_STRUCTS - DSA_get0_pqg(dsa, &p_bn, &q, &g); -#else - p_bn = dsa->p; - q = dsa->q; - g = dsa->g; -#endif - -#ifdef HAVE_OPAQUE_STRUCTS - DSA_get0_key(dsa, &pub_key, NULL); -#else - pub_key = dsa->pub_key; -#endif - p_bytes = BN_num_bytes(p_bn) + 1; - q_bytes = BN_num_bytes(q) + 1; - g_bytes = BN_num_bytes(g) + 1; - k_bytes = BN_num_bytes(pub_key) + 1; - - /* Key form is "ssh-dss" + p + q + g + pub_key. */ - len = 4 + 7 + 4 + p_bytes + 4 + q_bytes + 4 + g_bytes + 4 + k_bytes; - - key = LIBSSH2_ALLOC(session, len); - if(key == NULL) { - return NULL; - } - - /* Process key encoding. */ - p = key; - - _libssh2_htonu32(p, 7); /* Key type. */ - p += 4; - memcpy(p, "ssh-dss", 7); - p += 7; - - p = write_bn(p, p_bn, p_bytes); - p = write_bn(p, q, q_bytes); - p = write_bn(p, g, g_bytes); - p = write_bn(p, pub_key, k_bytes); - - *key_len = (size_t)(p - key); - return key; -} - -static int -gen_publickey_from_dsa_evp(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - EVP_PKEY *pk) -{ - DSA* dsa = NULL; - unsigned char *key; - unsigned char *method_buf = NULL; - size_t key_len; - - _libssh2_debug(session, - LIBSSH2_TRACE_AUTH, - "Computing public key from DSA private key envelope"); - - dsa = EVP_PKEY_get1_DSA(pk); - if(dsa == NULL) { - /* Assume memory allocation error... what else could it be ? */ - goto __alloc_error; - } - - method_buf = LIBSSH2_ALLOC(session, 7); /* ssh-dss. */ - if(method_buf == NULL) { - goto __alloc_error; - } - - key = gen_publickey_from_dsa(session, dsa, &key_len); - if(key == NULL) { - goto __alloc_error; - } - DSA_free(dsa); - - memcpy(method_buf, "ssh-dss", 7); - *method = method_buf; - *method_len = 7; - *pubkeydata = key; - *pubkeydata_len = key_len; - return 0; - - __alloc_error: - if(dsa != NULL) { - DSA_free(dsa); - } - if(method_buf != NULL) { - LIBSSH2_FREE(session, method_buf); - } - - return _libssh2_error(session, - LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for private key data"); -} - -static int -gen_publickey_from_dsa_openssh_priv_data(LIBSSH2_SESSION *session, - struct string_buf *decrypted, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - libssh2_dsa_ctx **dsa_ctx) -{ - int rc = 0; - size_t plen, qlen, glen, pub_len, priv_len; - unsigned char *p, *q, *g, *pub_key, *priv_key; - DSA *dsa = NULL; - - _libssh2_debug(session, - LIBSSH2_TRACE_AUTH, - "Computing DSA keys from private key data"); - - if(_libssh2_get_bignum_bytes(decrypted, &p, &plen)) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "DSA no p"); - return -1; - } - - if(_libssh2_get_bignum_bytes(decrypted, &q, &qlen)) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "DSA no q"); - return -1; - } - - if(_libssh2_get_bignum_bytes(decrypted, &g, &glen)) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "DSA no g"); - return -1; - } - - if(_libssh2_get_bignum_bytes(decrypted, &pub_key, &pub_len)) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "DSA no public key"); - return -1; - } - - if(_libssh2_get_bignum_bytes(decrypted, &priv_key, &priv_len)) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "DSA no private key"); - return -1; - } - - rc = _libssh2_dsa_new(&dsa, p, plen, q, qlen, g, glen, pub_key, pub_len, - priv_key, priv_len); - if(rc != 0) { - _libssh2_debug(session, - LIBSSH2_ERROR_PROTO, - "Could not create DSA private key"); - goto fail; - } - - if(dsa != NULL && pubkeydata != NULL && method != NULL) { - EVP_PKEY *pk = EVP_PKEY_new(); - EVP_PKEY_set1_DSA(pk, dsa); - - rc = gen_publickey_from_dsa_evp(session, method, method_len, - pubkeydata, pubkeydata_len, - pk); - - if(pk) - EVP_PKEY_free(pk); - } - - if(dsa_ctx != NULL) - *dsa_ctx = dsa; - else - DSA_free(dsa); - - return rc; - -fail: - - if(dsa != NULL) - DSA_free(dsa); - - return _libssh2_error(session, - LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for private key data"); -} - -static int -_libssh2_dsa_new_openssh_private(libssh2_dsa_ctx ** dsa, - LIBSSH2_SESSION * session, - const char *filename, - unsigned const char *passphrase) -{ - FILE *fp; - int rc; - unsigned char *buf = NULL; - struct string_buf *decrypted = NULL; - - if(session == NULL) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Session is required"); - return -1; - } - - _libssh2_init_if_needed(); - - fp = fopen(filename, "r"); - if(!fp) { - _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Unable to open OpenSSH DSA private key file"); - return -1; - } - - rc = _libssh2_openssh_pem_parse(session, passphrase, fp, &decrypted); - fclose(fp); - if(rc) { - return rc; - } - - /* We have a new key file, now try and parse it using supported types */ - rc = _libssh2_get_string(decrypted, &buf, NULL); - - if(rc != 0 || buf == NULL) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Public key type in decrypted key data not found"); - return -1; - } - - if(strcmp("ssh-dss", (const char *)buf) == 0) { - rc = gen_publickey_from_dsa_openssh_priv_data(session, decrypted, - NULL, 0, - NULL, 0, dsa); - } - else { - rc = -1; - } - - if(decrypted) - _libssh2_string_buf_free(session, decrypted); - - return rc; -} - -int -_libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa, - LIBSSH2_SESSION * session, - const char *filename, unsigned const char *passphrase) -{ - int rc; - - pem_read_bio_func read_dsa = - (pem_read_bio_func) &PEM_read_bio_DSAPrivateKey; - - _libssh2_init_if_needed(); - - rc = read_private_key_from_file((void **) dsa, read_dsa, - filename, passphrase); - - if(rc) { - rc = _libssh2_dsa_new_openssh_private(dsa, session, - filename, passphrase); - } - - return rc; -} - -#endif /* LIBSSH_DSA */ - -#if LIBSSH2_ECDSA - -int -_libssh2_ecdsa_new_private_frommemory(libssh2_ecdsa_ctx ** ec_ctx, - LIBSSH2_SESSION * session, - const char *filedata, size_t filedata_len, - unsigned const char *passphrase) -{ - int rc; - - pem_read_bio_func read_ec = - (pem_read_bio_func) &PEM_read_bio_ECPrivateKey; - - _libssh2_init_if_needed(); - - rc = read_private_key_from_memory((void **) ec_ctx, read_ec, - filedata, filedata_len, passphrase); - - if(rc) { - rc = read_openssh_private_key_from_memory((void **)ec_ctx, session, - "ssh-ecdsa", filedata, - filedata_len, passphrase); - } - - return rc; -} - -#endif /* LIBSSH2_ECDSA */ - - -#if LIBSSH2_ED25519 - -int -_libssh2_curve25519_new(LIBSSH2_SESSION *session, libssh2_x25519_ctx **out_ctx, - unsigned char **out_public_key, - unsigned char **out_private_key) -{ - EVP_PKEY *key = NULL; - EVP_PKEY_CTX *pctx = NULL; - PKCS8_PRIV_KEY_INFO *info = NULL; - ASN1_OCTET_STRING *oct = NULL; - X509_PUBKEY *pubkey = NULL; - libssh2_ed25519_ctx *ctx = NULL; - const unsigned char *pkcs, *priv, *pub; - int privLen, pubLen, pkcsLen; - int rc = -1; - - pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_X25519, NULL); - if(pctx == NULL) - return -1; - - EVP_PKEY_keygen_init(pctx); - EVP_PKEY_keygen(pctx, &key); - info = EVP_PKEY2PKCS8(key); - - if(info == NULL || !PKCS8_pkey_get0(NULL, &pkcs, &pkcsLen, NULL, info)) - goto cleanExit; - - oct = d2i_ASN1_OCTET_STRING(NULL, &pkcs, pkcsLen); - if(oct == NULL) { - goto cleanExit; - } - - priv = ASN1_STRING_get0_data(oct); - privLen = ASN1_STRING_length(oct); - - if(privLen != LIBSSH2_ED25519_KEY_LEN) - goto cleanExit; - - pubkey = X509_PUBKEY_new(); - if(pubkey == NULL || !X509_PUBKEY_set(&pubkey, key)) - goto cleanExit; - - if(!X509_PUBKEY_get0_param(NULL, &pub, &pubLen, NULL, pubkey)) - goto cleanExit; - - if(pubLen != LIBSSH2_ED25519_KEY_LEN) - goto cleanExit; - - if(out_private_key != NULL) { - *out_private_key = LIBSSH2_ALLOC(session, LIBSSH2_ED25519_KEY_LEN); - if(*out_private_key == NULL) - goto cleanExit; - - memcpy(*out_private_key, priv, LIBSSH2_ED25519_KEY_LEN); - } - - if(out_public_key != NULL) { - *out_public_key = LIBSSH2_ALLOC(session, LIBSSH2_ED25519_KEY_LEN); - if(*out_public_key == NULL) - goto cleanExit; - - memcpy(*out_public_key, pub, LIBSSH2_ED25519_KEY_LEN); - } - - if(out_ctx != NULL) { - ctx = EVP_PKEY_new_raw_private_key(EVP_PKEY_X25519, NULL, priv, - LIBSSH2_ED25519_KEY_LEN); - if(!ctx) - goto cleanExit; - - *out_ctx = ctx; - } - - /* success */ - rc = 0; - -cleanExit: - - if(info) - PKCS8_PRIV_KEY_INFO_free(info); - if(pctx) - EVP_PKEY_CTX_free(pctx); - if(oct) - ASN1_OCTET_STRING_free(oct); - if(pubkey) - X509_PUBKEY_free(pubkey); - if(key) - EVP_PKEY_free(key); - - return rc; -} - - -static int -gen_publickey_from_ed_evp(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - EVP_PKEY *pk) -{ - const char methodName[] = "ssh-ed25519"; - unsigned char *methodBuf = NULL; - size_t rawKeyLen = 0; - unsigned char *keyBuf = NULL; - size_t bufLen = 0; - unsigned char *bufPos = NULL; - - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Computing public key from ED private key envelope"); - - methodBuf = LIBSSH2_ALLOC(session, sizeof(methodName) - 1); - if(!methodBuf) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for private key data"); - goto fail; - } - memcpy(methodBuf, methodName, sizeof(methodName) - 1); - - if(EVP_PKEY_get_raw_public_key(pk, NULL, &rawKeyLen) != 1) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "EVP_PKEY_get_raw_public_key failed"); - goto fail; - } - - /* Key form is: type_len(4) + type(11) + pub_key_len(4) + pub_key(32). */ - bufLen = 4 + sizeof(methodName) - 1 + 4 + rawKeyLen; - bufPos = keyBuf = LIBSSH2_ALLOC(session, bufLen); - if(!keyBuf) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for private key data"); - goto fail; - } - - _libssh2_store_str(&bufPos, methodName, sizeof(methodName) - 1); - _libssh2_store_u32(&bufPos, rawKeyLen); - - if(EVP_PKEY_get_raw_public_key(pk, bufPos, &rawKeyLen) != 1) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "EVP_PKEY_get_raw_public_key failed"); - goto fail; - } - - *method = methodBuf; - *method_len = sizeof(methodName) - 1; - *pubkeydata = keyBuf; - *pubkeydata_len = bufLen; - return 0; - -fail: - if(methodBuf) - LIBSSH2_FREE(session, methodBuf); - if(keyBuf) - LIBSSH2_FREE(session, keyBuf); - return -1; -} - - -static int -gen_publickey_from_ed25519_openssh_priv_data(LIBSSH2_SESSION *session, - struct string_buf *decrypted, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - libssh2_ed25519_ctx **out_ctx) -{ - libssh2_ed25519_ctx *ctx = NULL; - unsigned char *method_buf = NULL; - unsigned char *key = NULL; - int i, ret = 0; - unsigned char *pub_key, *priv_key, *buf; - size_t key_len = 0, tmp_len = 0; - unsigned char *p; - - _libssh2_debug(session, - LIBSSH2_TRACE_AUTH, - "Computing ED25519 keys from private key data"); - - if(_libssh2_get_string(decrypted, &pub_key, &tmp_len) || - tmp_len != LIBSSH2_ED25519_KEY_LEN) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Wrong public key length"); - return -1; - } - - if(_libssh2_get_string(decrypted, &priv_key, &tmp_len) || - tmp_len != LIBSSH2_ED25519_PRIVATE_KEY_LEN) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Wrong private key length"); - ret = -1; - goto clean_exit; - } - - /* first 32 bytes of priv_key is the private key, the last 32 bytes are - the public key */ - ctx = EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, NULL, - (const unsigned char *)priv_key, - LIBSSH2_ED25519_KEY_LEN); - - /* comment */ - if(_libssh2_get_string(decrypted, &buf, &tmp_len)) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unable to read comment"); - ret = -1; - goto clean_exit; - } - - if(tmp_len > 0) { - unsigned char *comment = LIBSSH2_CALLOC(session, tmp_len + 1); - if(comment != NULL) { - memcpy(comment, buf, tmp_len); - memcpy(comment + tmp_len, "\0", 1); - - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, "Key comment: %s", - comment); - - LIBSSH2_FREE(session, comment); - } - } - - /* Padding */ - i = 1; - while(decrypted->dataptr < decrypted->data + decrypted->len) { - if(*decrypted->dataptr != i) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Wrong padding"); - ret = -1; - goto clean_exit; - } - i++; - decrypted->dataptr++; - } - - if(ret == 0) { - _libssh2_debug(session, - LIBSSH2_TRACE_AUTH, - "Computing public key from ED25519 " - "private key envelope"); - - method_buf = LIBSSH2_ALLOC(session, 11); /* ssh-ed25519. */ - if(method_buf == NULL) { - goto clean_exit; - } - - /* Key form is: type_len(4) + type(11) + pub_key_len(4) + - pub_key(32). */ - key_len = LIBSSH2_ED25519_KEY_LEN + 19; - key = LIBSSH2_CALLOC(session, key_len); - if(key == NULL) { - goto clean_exit; - } - - p = key; - - _libssh2_store_str(&p, "ssh-ed25519", 11); - _libssh2_store_str(&p, (const char *)pub_key, LIBSSH2_ED25519_KEY_LEN); - - memcpy(method_buf, "ssh-ed25519", 11); - - if(method != NULL) - *method = method_buf; - else - LIBSSH2_FREE(session, method_buf); - - if(method_len != NULL) - *method_len = 11; - - if(pubkeydata != NULL) - *pubkeydata = key; - else - LIBSSH2_FREE(session, key); - - if(pubkeydata_len != NULL) - *pubkeydata_len = key_len; - - if(out_ctx != NULL) - *out_ctx = ctx; - else if(ctx != NULL) - _libssh2_ed25519_free(ctx); - - return 0; - } - -clean_exit: - - if(ctx) - _libssh2_ed25519_free(ctx); - - if(method_buf) - LIBSSH2_FREE(session, method_buf); - - if(key) - LIBSSH2_FREE(session, key); - - return -1; -} - -int -_libssh2_ed25519_new_private(libssh2_ed25519_ctx ** ed_ctx, - LIBSSH2_SESSION * session, - const char *filename, const uint8_t *passphrase) -{ - int rc; - FILE *fp; - unsigned char *buf; - struct string_buf *decrypted = NULL; - libssh2_ed25519_ctx *ctx = NULL; - - if(session == NULL) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Session is required"); - return -1; - } - - _libssh2_init_if_needed(); - - fp = fopen(filename, "r"); - if(!fp) { - _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Unable to open ED25519 private key file"); - return -1; - } - - rc = _libssh2_openssh_pem_parse(session, passphrase, fp, &decrypted); - fclose(fp); - if(rc) { - return rc; - } - - /* We have a new key file, now try and parse it using supported types */ - rc = _libssh2_get_string(decrypted, &buf, NULL); - - if(rc != 0 || buf == NULL) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Public key type in decrypted key data not found"); - return -1; - } - - if(strcmp("ssh-ed25519", (const char *)buf) == 0) { - rc = gen_publickey_from_ed25519_openssh_priv_data(session, - decrypted, - NULL, - NULL, - NULL, - NULL, - &ctx); - } - else { - rc = -1; - } - - if(decrypted) - _libssh2_string_buf_free(session, decrypted); - - if(rc == 0) { - if(ed_ctx != NULL) - *ed_ctx = ctx; - else if(ctx != NULL) - _libssh2_ed25519_free(ctx); - } - - return rc; -} - -int -_libssh2_ed25519_new_private_frommemory(libssh2_ed25519_ctx ** ed_ctx, - LIBSSH2_SESSION * session, - const char *filedata, - size_t filedata_len, - unsigned const char *passphrase) -{ - libssh2_ed25519_ctx *ctx = NULL; - - _libssh2_init_if_needed(); - - if(read_private_key_from_memory((void **)&ctx, - (pem_read_bio_func) - &PEM_read_bio_PrivateKey, - filedata, filedata_len, passphrase) == 0) { - if(EVP_PKEY_id(ctx) != EVP_PKEY_ED25519) { - _libssh2_ed25519_free(ctx); - return _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Private key is not an ED25519 key"); - } - - *ed_ctx = ctx; - return 0; - } - - return read_openssh_private_key_from_memory((void **)ed_ctx, session, - "ssh-ed25519", - filedata, filedata_len, - passphrase); -} - -int -_libssh2_ed25519_new_public(libssh2_ed25519_ctx ** ed_ctx, - LIBSSH2_SESSION * session, - const unsigned char *raw_pub_key, - const uint8_t key_len) -{ - libssh2_ed25519_ctx *ctx = NULL; - - if(ed_ctx == NULL) - return -1; - - ctx = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL, - raw_pub_key, key_len); - if(!ctx) - return _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "could not create ED25519 public key"); - - if(ed_ctx != NULL) - *ed_ctx = ctx; - else if(ctx) - _libssh2_ed25519_free(ctx); - - return 0; -} -#endif /* LIBSSH2_ED25519 */ - - -int -_libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session, - libssh2_rsa_ctx * rsactx, - const unsigned char *hash, - size_t hash_len, - unsigned char **signature, size_t *signature_len) -{ - int ret; - unsigned char *sig; - unsigned int sig_len; - - sig_len = RSA_size(rsactx); - sig = LIBSSH2_ALLOC(session, sig_len); - - if(!sig) { - return -1; - } - - ret = RSA_sign(NID_sha1, hash, hash_len, sig, &sig_len, rsactx); - - if(!ret) { - LIBSSH2_FREE(session, sig); - return -1; - } - - *signature = sig; - *signature_len = sig_len; - - return 0; -} - -#if LIBSSH2_DSA -int -_libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx, - const unsigned char *hash, - unsigned long hash_len, unsigned char *signature) -{ - DSA_SIG *sig; - const BIGNUM * r; - const BIGNUM * s; - int r_len, s_len; - (void) hash_len; - - sig = DSA_do_sign(hash, SHA_DIGEST_LENGTH, dsactx); - if(!sig) { - return -1; - } - -#ifdef HAVE_OPAQUE_STRUCTS - DSA_SIG_get0(sig, &r, &s); -#else - r = sig->r; - s = sig->s; -#endif - r_len = BN_num_bytes(r); - if(r_len < 1 || r_len > 20) { - DSA_SIG_free(sig); - return -1; - } - s_len = BN_num_bytes(s); - if(s_len < 1 || s_len > 20) { - DSA_SIG_free(sig); - return -1; - } - - memset(signature, 0, 40); - - BN_bn2bin(r, signature + (20 - r_len)); - BN_bn2bin(s, signature + 20 + (20 - s_len)); - - DSA_SIG_free(sig); - - return 0; -} -#endif /* LIBSSH_DSA */ - -#if LIBSSH2_ECDSA - -int -_libssh2_ecdsa_sign(LIBSSH2_SESSION * session, libssh2_ecdsa_ctx * ec_ctx, - const unsigned char *hash, unsigned long hash_len, - unsigned char **signature, size_t *signature_len) -{ - int r_len, s_len; - int rc = 0; - size_t out_buffer_len = 0; - unsigned char *sp; - const BIGNUM *pr = NULL, *ps = NULL; - unsigned char *temp_buffer = NULL; - unsigned char *out_buffer = NULL; - - ECDSA_SIG *sig = ECDSA_do_sign(hash, hash_len, ec_ctx); - if(sig == NULL) - return -1; -#ifdef HAVE_OPAQUE_STRUCTS - ECDSA_SIG_get0(sig, &pr, &ps); -#else - pr = sig->r; - ps = sig->s; -#endif - - r_len = BN_num_bytes(pr) + 1; - s_len = BN_num_bytes(ps) + 1; - - temp_buffer = malloc(r_len + s_len + 8); - if(temp_buffer == NULL) { - rc = -1; - goto clean_exit; - } - - sp = temp_buffer; - sp = write_bn(sp, pr, r_len); - sp = write_bn(sp, ps, s_len); - - out_buffer_len = (size_t)(sp - temp_buffer); - - out_buffer = LIBSSH2_CALLOC(session, out_buffer_len); - if(out_buffer == NULL) { - rc = -1; - goto clean_exit; - } - - memcpy(out_buffer, temp_buffer, out_buffer_len); - - *signature = out_buffer; - *signature_len = out_buffer_len; - -clean_exit: - - if(temp_buffer != NULL) - free(temp_buffer); - - if(sig) - ECDSA_SIG_free(sig); - - return rc; -} -#endif /* LIBSSH2_ECDSA */ - -int -_libssh2_sha1_init(libssh2_sha1_ctx *ctx) -{ -#ifdef HAVE_OPAQUE_STRUCTS - *ctx = EVP_MD_CTX_new(); - - if(*ctx == NULL) - return 0; - - if(EVP_DigestInit(*ctx, EVP_get_digestbyname("sha1"))) - return 1; - - EVP_MD_CTX_free(*ctx); - *ctx = NULL; - - return 0; -#else - EVP_MD_CTX_init(ctx); - return EVP_DigestInit(ctx, EVP_get_digestbyname("sha1")); -#endif -} - -int -_libssh2_sha1(const unsigned char *message, unsigned long len, - unsigned char *out) -{ -#ifdef HAVE_OPAQUE_STRUCTS - EVP_MD_CTX * ctx = EVP_MD_CTX_new(); - - if(ctx == NULL) - return 1; /* error */ - - if(EVP_DigestInit(ctx, EVP_get_digestbyname("sha1"))) { - EVP_DigestUpdate(ctx, message, len); - EVP_DigestFinal(ctx, out, NULL); - EVP_MD_CTX_free(ctx); - return 0; /* success */ - } - EVP_MD_CTX_free(ctx); -#else - EVP_MD_CTX ctx; - - EVP_MD_CTX_init(&ctx); - if(EVP_DigestInit(&ctx, EVP_get_digestbyname("sha1"))) { - EVP_DigestUpdate(&ctx, message, len); - EVP_DigestFinal(&ctx, out, NULL); - return 0; /* success */ - } -#endif - return 1; /* error */ -} - -int -_libssh2_sha256_init(libssh2_sha256_ctx *ctx) -{ -#ifdef HAVE_OPAQUE_STRUCTS - *ctx = EVP_MD_CTX_new(); - - if(*ctx == NULL) - return 0; - - if(EVP_DigestInit(*ctx, EVP_get_digestbyname("sha256"))) - return 1; - - EVP_MD_CTX_free(*ctx); - *ctx = NULL; - - return 0; -#else - EVP_MD_CTX_init(ctx); - return EVP_DigestInit(ctx, EVP_get_digestbyname("sha256")); -#endif -} - -int -_libssh2_sha256(const unsigned char *message, unsigned long len, - unsigned char *out) -{ -#ifdef HAVE_OPAQUE_STRUCTS - EVP_MD_CTX * ctx = EVP_MD_CTX_new(); - - if(ctx == NULL) - return 1; /* error */ - - if(EVP_DigestInit(ctx, EVP_get_digestbyname("sha256"))) { - EVP_DigestUpdate(ctx, message, len); - EVP_DigestFinal(ctx, out, NULL); - EVP_MD_CTX_free(ctx); - return 0; /* success */ - } - EVP_MD_CTX_free(ctx); -#else - EVP_MD_CTX ctx; - - EVP_MD_CTX_init(&ctx); - if(EVP_DigestInit(&ctx, EVP_get_digestbyname("sha256"))) { - EVP_DigestUpdate(&ctx, message, len); - EVP_DigestFinal(&ctx, out, NULL); - return 0; /* success */ - } -#endif - return 1; /* error */ -} - -int -_libssh2_sha384_init(libssh2_sha384_ctx *ctx) -{ -#ifdef HAVE_OPAQUE_STRUCTS - *ctx = EVP_MD_CTX_new(); - - if(*ctx == NULL) - return 0; - - if(EVP_DigestInit(*ctx, EVP_get_digestbyname("sha384"))) - return 1; - - EVP_MD_CTX_free(*ctx); - *ctx = NULL; - - return 0; -#else - EVP_MD_CTX_init(ctx); - return EVP_DigestInit(ctx, EVP_get_digestbyname("sha384")); -#endif -} - -int -_libssh2_sha384(const unsigned char *message, unsigned long len, - unsigned char *out) -{ -#ifdef HAVE_OPAQUE_STRUCTS - EVP_MD_CTX * ctx = EVP_MD_CTX_new(); - - if(ctx == NULL) - return 1; /* error */ - - if(EVP_DigestInit(ctx, EVP_get_digestbyname("sha384"))) { - EVP_DigestUpdate(ctx, message, len); - EVP_DigestFinal(ctx, out, NULL); - EVP_MD_CTX_free(ctx); - return 0; /* success */ - } - EVP_MD_CTX_free(ctx); -#else - EVP_MD_CTX ctx; - - EVP_MD_CTX_init(&ctx); - if(EVP_DigestInit(&ctx, EVP_get_digestbyname("sha384"))) { - EVP_DigestUpdate(&ctx, message, len); - EVP_DigestFinal(&ctx, out, NULL); - return 0; /* success */ - } -#endif - return 1; /* error */ -} - -int -_libssh2_sha512_init(libssh2_sha512_ctx *ctx) -{ -#ifdef HAVE_OPAQUE_STRUCTS - *ctx = EVP_MD_CTX_new(); - - if(*ctx == NULL) - return 0; - - if(EVP_DigestInit(*ctx, EVP_get_digestbyname("sha512"))) - return 1; - - EVP_MD_CTX_free(*ctx); - *ctx = NULL; - - return 0; -#else - EVP_MD_CTX_init(ctx); - return EVP_DigestInit(ctx, EVP_get_digestbyname("sha512")); -#endif -} - -int -_libssh2_sha512(const unsigned char *message, unsigned long len, - unsigned char *out) -{ -#ifdef HAVE_OPAQUE_STRUCTS - EVP_MD_CTX * ctx = EVP_MD_CTX_new(); - - if(ctx == NULL) - return 1; /* error */ - - if(EVP_DigestInit(ctx, EVP_get_digestbyname("sha512"))) { - EVP_DigestUpdate(ctx, message, len); - EVP_DigestFinal(ctx, out, NULL); - EVP_MD_CTX_free(ctx); - return 0; /* success */ - } - EVP_MD_CTX_free(ctx); -#else - EVP_MD_CTX ctx; - - EVP_MD_CTX_init(&ctx); - if(EVP_DigestInit(&ctx, EVP_get_digestbyname("sha512"))) { - EVP_DigestUpdate(&ctx, message, len); - EVP_DigestFinal(&ctx, out, NULL); - return 0; /* success */ - } -#endif - return 1; /* error */ -} - -int -_libssh2_md5_init(libssh2_md5_ctx *ctx) -{ -#ifdef HAVE_OPAQUE_STRUCTS - *ctx = EVP_MD_CTX_new(); - - if(*ctx == NULL) - return 0; - - if(EVP_DigestInit(*ctx, EVP_get_digestbyname("md5"))) - return 1; - - EVP_MD_CTX_free(*ctx); - *ctx = NULL; - - return 0; -#else - EVP_MD_CTX_init(ctx); - return EVP_DigestInit(ctx, EVP_get_digestbyname("md5")); -#endif -} - -#if LIBSSH2_ECDSA - -static int -gen_publickey_from_ec_evp(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - EVP_PKEY *pk) -{ - int rc = 0; - EC_KEY *ec = NULL; - unsigned char *p; - unsigned char *method_buf = NULL; - unsigned char *key; - size_t key_len = 0; - unsigned char *octal_value = NULL; - size_t octal_len; - const EC_POINT *public_key; - const EC_GROUP *group; - BN_CTX *bn_ctx; - libssh2_curve_type type; - - _libssh2_debug(session, - LIBSSH2_TRACE_AUTH, - "Computing public key from EC private key envelope"); - - bn_ctx = BN_CTX_new(); - if(bn_ctx == NULL) - return -1; - - ec = EVP_PKEY_get1_EC_KEY(pk); - if(ec == NULL) { - rc = -1; - goto clean_exit; - } - - public_key = EC_KEY_get0_public_key(ec); - group = EC_KEY_get0_group(ec); - type = _libssh2_ecdsa_get_curve_type(ec); - - method_buf = LIBSSH2_ALLOC(session, 19); - if(method_buf == NULL) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "out of memory"); - } - - if(type == LIBSSH2_EC_CURVE_NISTP256) - memcpy(method_buf, "ecdsa-sha2-nistp256", 19); - else if(type == LIBSSH2_EC_CURVE_NISTP384) - memcpy(method_buf, "ecdsa-sha2-nistp384", 19); - else if(type == LIBSSH2_EC_CURVE_NISTP521) - memcpy(method_buf, "ecdsa-sha2-nistp521", 19); - else { - _libssh2_debug(session, - LIBSSH2_TRACE_ERROR, - "Unsupported EC private key type"); - rc = -1; - goto clean_exit; - } - - /* get length */ - octal_len = EC_POINT_point2oct(group, public_key, - POINT_CONVERSION_UNCOMPRESSED, - NULL, 0, bn_ctx); - if(octal_len > EC_MAX_POINT_LEN) { - rc = -1; - goto clean_exit; - } - - octal_value = malloc(octal_len); - if(octal_value == NULL) { - rc = -1; - goto clean_exit; - } - - /* convert to octal */ - if(EC_POINT_point2oct(group, public_key, POINT_CONVERSION_UNCOMPRESSED, - octal_value, octal_len, bn_ctx) != octal_len) { - rc = -1; - goto clean_exit; - } - - /* Key form is: type_len(4) + type(19) + domain_len(4) + domain(8) + - pub_key_len(4) + pub_key(~65). */ - key_len = 4 + 19 + 4 + 8 + 4 + octal_len; - key = LIBSSH2_ALLOC(session, key_len); - if(key == NULL) { - rc = -1; - goto clean_exit; - } - - /* Process key encoding. */ - p = key; - - /* Key type */ - _libssh2_store_str(&p, (const char *)method_buf, 19); - - /* Name domain */ - _libssh2_store_str(&p, (const char *)method_buf + 11, 8); - - /* Public key */ - _libssh2_store_str(&p, (const char *)octal_value, octal_len); - - *method = method_buf; - *method_len = 19; - *pubkeydata = key; - *pubkeydata_len = key_len; - -clean_exit: - - if(ec != NULL) - EC_KEY_free(ec); - - if(bn_ctx != NULL) { - BN_CTX_free(bn_ctx); - } - - if(octal_value != NULL) - free(octal_value); - - if(rc == 0) - return 0; - - if(method_buf != NULL) - LIBSSH2_FREE(session, method_buf); - - return -1; -} - -static int -gen_publickey_from_ecdsa_openssh_priv_data(LIBSSH2_SESSION *session, - libssh2_curve_type curve_type, - struct string_buf *decrypted, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - libssh2_ecdsa_ctx **ec_ctx) -{ - int rc = 0; - size_t curvelen, exponentlen, pointlen; - unsigned char *curve, *exponent, *point_buf; - EC_KEY *ec_key = NULL; - BIGNUM *bn_exponent; - - _libssh2_debug(session, - LIBSSH2_TRACE_AUTH, - "Computing ECDSA keys from private key data"); - - if(_libssh2_get_string(decrypted, &curve, &curvelen) || - curvelen == 0) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "ECDSA no curve"); - return -1; - } - - if(_libssh2_get_string(decrypted, &point_buf, &pointlen)) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "ECDSA no point"); - return -1; - } - - if(_libssh2_get_bignum_bytes(decrypted, &exponent, &exponentlen)) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "ECDSA no exponent"); - return -1; - } - - if((rc = _libssh2_ecdsa_curve_name_with_octal_new(&ec_key, point_buf, - pointlen, curve_type)) != 0) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "ECDSA could not create key"); - goto fail; - } - - bn_exponent = BN_new(); - if(bn_exponent == NULL) { - rc = -1; - goto fail; - } - - BN_bin2bn(exponent, exponentlen, bn_exponent); - rc = (EC_KEY_set_private_key(ec_key, bn_exponent) != 1); - - if(rc == 0 && ec_key != NULL && pubkeydata != NULL && method != NULL) { - EVP_PKEY *pk = EVP_PKEY_new(); - EVP_PKEY_set1_EC_KEY(pk, ec_key); - - rc = gen_publickey_from_ec_evp(session, method, method_len, - pubkeydata, pubkeydata_len, - pk); - - if(pk) - EVP_PKEY_free(pk); - } - - if(ec_ctx != NULL) - *ec_ctx = ec_key; - else - EC_KEY_free(ec_key); - - return rc; - -fail: - - if(ec_key != NULL) - EC_KEY_free(ec_key); - - return _libssh2_error(session, - LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for private key data"); - - -} - -static int -_libssh2_ecdsa_new_openssh_private(libssh2_ecdsa_ctx ** ec_ctx, - LIBSSH2_SESSION * session, - const char *filename, - unsigned const char *passphrase) -{ - FILE *fp; - int rc; - unsigned char *buf = NULL; - libssh2_curve_type type; - struct string_buf *decrypted = NULL; - - if(session == NULL) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Session is required"); - return -1; - } - - _libssh2_init_if_needed(); - - fp = fopen(filename, "r"); - if(!fp) { - _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Unable to open OpenSSH ECDSA private key file"); - return -1; - } - - rc = _libssh2_openssh_pem_parse(session, passphrase, fp, &decrypted); - fclose(fp); - if(rc) { - return rc; - } - - /* We have a new key file, now try and parse it using supported types */ - rc = _libssh2_get_string(decrypted, &buf, NULL); - - if(rc != 0 || buf == NULL) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Public key type in decrypted key data not found"); - return -1; - } - - rc = _libssh2_ecdsa_curve_type_from_name((const char *)buf, &type); - - if(rc == 0) { - rc = gen_publickey_from_ecdsa_openssh_priv_data(session, type, - decrypted, NULL, 0, - NULL, 0, ec_ctx); - } - else { - rc = -1; - } - - if(decrypted) - _libssh2_string_buf_free(session, decrypted); - - return rc; -} - -int -_libssh2_ecdsa_new_private(libssh2_ecdsa_ctx ** ec_ctx, - LIBSSH2_SESSION * session, - const char *filename, unsigned const char *passphrase) -{ - int rc; - - pem_read_bio_func read_ec = (pem_read_bio_func) &PEM_read_bio_ECPrivateKey; - - _libssh2_init_if_needed(); - - rc = read_private_key_from_file((void **) ec_ctx, read_ec, - filename, passphrase); - - if(rc) { - return _libssh2_ecdsa_new_openssh_private(ec_ctx, session, - filename, passphrase); - } - - return rc; -} - -/* - * _libssh2_ecdsa_create_key - * - * Creates a local private key based on input curve - * and returns octal value and octal length - * - */ - -int -_libssh2_ecdsa_create_key(LIBSSH2_SESSION *session, - _libssh2_ec_key **out_private_key, - unsigned char **out_public_key_octal, - size_t *out_public_key_octal_len, - libssh2_curve_type curve_type) -{ - int ret = 1; - size_t octal_len = 0; - unsigned char octal_value[EC_MAX_POINT_LEN]; - const EC_POINT *public_key = NULL; - EC_KEY *private_key = NULL; - const EC_GROUP *group = NULL; - - /* create key */ - BN_CTX *bn_ctx = BN_CTX_new(); - if(!bn_ctx) - return -1; - - private_key = EC_KEY_new_by_curve_name(curve_type); - group = EC_KEY_get0_group(private_key); - - EC_KEY_generate_key(private_key); - public_key = EC_KEY_get0_public_key(private_key); - - /* get length */ - octal_len = EC_POINT_point2oct(group, public_key, - POINT_CONVERSION_UNCOMPRESSED, - NULL, 0, bn_ctx); - if(octal_len > EC_MAX_POINT_LEN) { - ret = -1; - goto clean_exit; - } - - /* convert to octal */ - if(EC_POINT_point2oct(group, public_key, POINT_CONVERSION_UNCOMPRESSED, - octal_value, octal_len, bn_ctx) != octal_len) { - ret = -1; - goto clean_exit; - } - - if(out_private_key != NULL) - *out_private_key = private_key; - - if(out_public_key_octal) { - *out_public_key_octal = LIBSSH2_ALLOC(session, octal_len); - if(*out_public_key_octal == NULL) { - ret = -1; - goto clean_exit; - } - - memcpy(*out_public_key_octal, octal_value, octal_len); - } - - if(out_public_key_octal_len != NULL) - *out_public_key_octal_len = octal_len; - -clean_exit: - - if(bn_ctx) - BN_CTX_free(bn_ctx); - - return (ret == 1) ? 0 : -1; -} - -/* _libssh2_ecdh_gen_k - * - * Computes the shared secret K given a local private key, - * remote public key and length - */ - -int -_libssh2_ecdh_gen_k(_libssh2_bn **k, _libssh2_ec_key *private_key, - const unsigned char *server_public_key, size_t server_public_key_len) -{ - int ret = 0; - int rc; - size_t secret_len; - unsigned char *secret = NULL; - const EC_GROUP *private_key_group; - EC_POINT *server_public_key_point; - - BN_CTX *bn_ctx = BN_CTX_new(); - - if(!bn_ctx) - return -1; - - if(k == NULL) - return -1; - - private_key_group = EC_KEY_get0_group(private_key); - - server_public_key_point = EC_POINT_new(private_key_group); - if(server_public_key_point == NULL) - return -1; - - rc = EC_POINT_oct2point(private_key_group, server_public_key_point, - server_public_key, server_public_key_len, bn_ctx); - if(rc != 1) { - ret = -1; - goto clean_exit; - } - - secret_len = (EC_GROUP_get_degree(private_key_group) + 7) / 8; - secret = malloc(secret_len); - if(!secret) { - ret = -1; - goto clean_exit; - } - - secret_len = ECDH_compute_key(secret, secret_len, server_public_key_point, - private_key, NULL); - - if(secret_len <= 0 || secret_len > EC_MAX_POINT_LEN) { - ret = -1; - goto clean_exit; - } - - BN_bin2bn(secret, secret_len, *k); - -clean_exit: - - if(server_public_key_point != NULL) - EC_POINT_free(server_public_key_point); - - if(bn_ctx != NULL) - BN_CTX_free(bn_ctx); - - if(secret != NULL) - free(secret); - - return ret; -} - - -#endif /* LIBSSH2_ECDSA */ - -#if LIBSSH2_ED25519 - -int -_libssh2_ed25519_sign(libssh2_ed25519_ctx *ctx, LIBSSH2_SESSION *session, - uint8_t **out_sig, size_t *out_sig_len, - const uint8_t *message, size_t message_len) -{ - int rc = -1; - EVP_MD_CTX *md_ctx = EVP_MD_CTX_new(); - size_t sig_len = 0; - unsigned char *sig = NULL; - - if(md_ctx != NULL) { - if(EVP_DigestSignInit(md_ctx, NULL, NULL, NULL, ctx) != 1) - goto clean_exit; - if(EVP_DigestSign(md_ctx, NULL, &sig_len, message, message_len) != 1) - goto clean_exit; - - if(sig_len != LIBSSH2_ED25519_SIG_LEN) - goto clean_exit; - - sig = LIBSSH2_CALLOC(session, sig_len); - if(sig == NULL) - goto clean_exit; - - rc = EVP_DigestSign(md_ctx, sig, &sig_len, message, message_len); - } - - if(rc == 1) { - *out_sig = sig; - *out_sig_len = sig_len; - } - else { - *out_sig_len = 0; - *out_sig = NULL; - LIBSSH2_FREE(session, sig); - } - -clean_exit: - - if(md_ctx) - EVP_MD_CTX_free(md_ctx); - - return (rc == 1 ? 0 : -1); -} - -int -_libssh2_curve25519_gen_k(_libssh2_bn **k, - uint8_t private_key[LIBSSH2_ED25519_KEY_LEN], - uint8_t server_public_key[LIBSSH2_ED25519_KEY_LEN]) -{ - int rc = -1; - unsigned char out_shared_key[LIBSSH2_ED25519_KEY_LEN]; - EVP_PKEY *peer_key = NULL, *server_key = NULL; - EVP_PKEY_CTX *server_key_ctx = NULL; - BN_CTX *bn_ctx = NULL; - size_t out_len = 0; - - if(k == NULL || *k == NULL) - return -1; - - bn_ctx = BN_CTX_new(); - if(bn_ctx == NULL) - return -1; - - peer_key = EVP_PKEY_new_raw_public_key(EVP_PKEY_X25519, NULL, - server_public_key, - LIBSSH2_ED25519_KEY_LEN); - - server_key = EVP_PKEY_new_raw_private_key(EVP_PKEY_X25519, NULL, - private_key, - LIBSSH2_ED25519_KEY_LEN); - - if(peer_key == NULL || server_key == NULL) { - goto cleanExit; - } - - server_key_ctx = EVP_PKEY_CTX_new(server_key, NULL); - if(server_key_ctx == NULL) { - goto cleanExit; - } - - rc = EVP_PKEY_derive_init(server_key_ctx); - if(rc <= 0) goto cleanExit; - - rc = EVP_PKEY_derive_set_peer(server_key_ctx, peer_key); - if(rc <= 0) goto cleanExit; - - rc = EVP_PKEY_derive(server_key_ctx, NULL, &out_len); - if(rc <= 0) goto cleanExit; - - if(out_len != LIBSSH2_ED25519_KEY_LEN) { - rc = -1; - goto cleanExit; - } - - rc = EVP_PKEY_derive(server_key_ctx, out_shared_key, &out_len); - - if(rc == 1 && out_len == LIBSSH2_ED25519_KEY_LEN) { - BN_bin2bn(out_shared_key, LIBSSH2_ED25519_KEY_LEN, *k); - } - else { - rc = -1; - } - -cleanExit: - - if(server_key_ctx) - EVP_PKEY_CTX_free(server_key_ctx); - if(peer_key) - EVP_PKEY_free(peer_key); - if(server_key) - EVP_PKEY_free(server_key); - if(bn_ctx != NULL) - BN_CTX_free(bn_ctx); - - return (rc == 1) ? 0 : -1; -} - - -int -_libssh2_ed25519_verify(libssh2_ed25519_ctx *ctx, const uint8_t *s, - size_t s_len, const uint8_t *m, size_t m_len) -{ - int ret = -1; - - EVP_MD_CTX *md_ctx = EVP_MD_CTX_new(); - if(NULL == md_ctx) - return -1; - - ret = EVP_DigestVerifyInit(md_ctx, NULL, NULL, NULL, ctx); - if(ret != 1) - goto clean_exit; - - ret = EVP_DigestVerify(md_ctx, s, s_len, m, m_len); - - clean_exit: - - EVP_MD_CTX_free(md_ctx); - - return (ret == 1) ? 0 : -1; -} - -#endif /* LIBSSH2_ED25519 */ - -static int -_libssh2_pub_priv_openssh_keyfile(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - const char *privatekey, - const char *passphrase) -{ - FILE *fp; - unsigned char *buf = NULL; - struct string_buf *decrypted = NULL; - int rc = 0; - - if(session == NULL) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Session is required"); - return -1; - } - - _libssh2_init_if_needed(); - - fp = fopen(privatekey, "r"); - if(!fp) { - _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Unable to open private key file"); - return -1; - } - - rc = _libssh2_openssh_pem_parse(session, (const unsigned char *)passphrase, - fp, &decrypted); - fclose(fp); - if(rc) { - _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Not an OpenSSH key file"); - return rc; - } - - /* We have a new key file, now try and parse it using supported types */ - rc = _libssh2_get_string(decrypted, &buf, NULL); - - if(rc != 0 || buf == NULL) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Public key type in decrypted key data not found"); - return -1; - } - - rc = -1; - -#if LIBSSH2_ED25519 - if(strcmp("ssh-ed25519", (const char *)buf) == 0) { - rc = gen_publickey_from_ed25519_openssh_priv_data(session, decrypted, - method, method_len, - pubkeydata, - pubkeydata_len, - NULL); - } -#endif -#if LIBSSH2_RSA - if(strcmp("ssh-rsa", (const char *)buf) == 0) { - rc = gen_publickey_from_rsa_openssh_priv_data(session, decrypted, - method, method_len, - pubkeydata, - pubkeydata_len, - NULL); - } -#endif -#if LIBSSH2_DSA - if(strcmp("ssh-dss", (const char *)buf) == 0) { - rc = gen_publickey_from_dsa_openssh_priv_data(session, decrypted, - method, method_len, - pubkeydata, - pubkeydata_len, - NULL); - } -#endif -#if LIBSSH2_ECDSA - { - libssh2_curve_type type; - - if(_libssh2_ecdsa_curve_type_from_name((const char *)buf, - &type) == 0) { - rc = gen_publickey_from_ecdsa_openssh_priv_data(session, type, - decrypted, - method, method_len, - pubkeydata, - pubkeydata_len, - NULL); - } - } -#endif - - if(decrypted) - _libssh2_string_buf_free(session, decrypted); - - if(rc != 0) { - _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Unsupported OpenSSH key type"); - } - - return rc; -} - -int -_libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - const char *privatekey, - const char *passphrase) -{ - int st; - BIO* bp; - EVP_PKEY* pk; - int pktype; - int rc; - - _libssh2_debug(session, - LIBSSH2_TRACE_AUTH, - "Computing public key from private key file: %s", - privatekey); - - bp = BIO_new_file(privatekey, "r"); - if(bp == NULL) { - return _libssh2_error(session, - LIBSSH2_ERROR_FILE, - "Unable to extract public key from private key " - "file: Unable to open private key file"); - } - - BIO_reset(bp); - pk = PEM_read_bio_PrivateKey(bp, NULL, NULL, (void *)passphrase); - BIO_free(bp); - - if(pk == NULL) { - - /* Try OpenSSH format */ - rc = _libssh2_pub_priv_openssh_keyfile(session, - method, - method_len, - pubkeydata, pubkeydata_len, - privatekey, passphrase); - if(rc != 0) { - return _libssh2_error(session, - LIBSSH2_ERROR_FILE, - "Unable to extract public key " - "from private key file: " - "Wrong passphrase or invalid/unrecognized " - "private key file format"); - } - - return 0; - } - -#ifdef HAVE_OPAQUE_STRUCTS - pktype = EVP_PKEY_id(pk); -#else - pktype = pk->type; -#endif - - switch(pktype) { -#if LIBSSH2_ED25519 - case EVP_PKEY_ED25519 : - st = gen_publickey_from_ed_evp( - session, method, method_len, pubkeydata, pubkeydata_len, pk); - break; -#endif /* LIBSSH2_ED25519 */ - case EVP_PKEY_RSA : - st = gen_publickey_from_rsa_evp( - session, method, method_len, pubkeydata, pubkeydata_len, pk); - break; - -#if LIBSSH2_DSA - case EVP_PKEY_DSA : - st = gen_publickey_from_dsa_evp( - session, method, method_len, pubkeydata, pubkeydata_len, pk); - break; -#endif /* LIBSSH_DSA */ - -#if LIBSSH2_ECDSA - case EVP_PKEY_EC : - st = gen_publickey_from_ec_evp( - session, method, method_len, pubkeydata, pubkeydata_len, pk); - break; -#endif - - default : - st = _libssh2_error(session, - LIBSSH2_ERROR_FILE, - "Unable to extract public key " - "from private key file: " - "Unsupported private key file format"); - break; - } - - EVP_PKEY_free(pk); - return st; -} - -static int -_libssh2_pub_priv_openssh_keyfilememory(LIBSSH2_SESSION *session, - void **key_ctx, - const char *key_type, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - const char *privatekeydata, - size_t privatekeydata_len, - unsigned const char *passphrase) -{ - int rc; - unsigned char *buf = NULL; - struct string_buf *decrypted = NULL; - - if(key_ctx != NULL) - *key_ctx = NULL; - - if(session == NULL) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Session is required"); - return -1; - } - - if(key_type != NULL && (strlen(key_type) > 11 || strlen(key_type) < 7)) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "type is invalid"); - return -1; - } - - _libssh2_init_if_needed(); - - rc = _libssh2_openssh_pem_parse_memory(session, passphrase, - privatekeydata, - privatekeydata_len, &decrypted); - - if(rc) { - return rc; - } - - /* We have a new key file, now try and parse it using supported types */ - rc = _libssh2_get_string(decrypted, &buf, NULL); - - if(rc != 0 || buf == NULL) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Public key type in decrypted key data not found"); - return -1; - } - - rc = -1; - -#if LIBSSH2_ED25519 - if(strcmp("ssh-ed25519", (const char *)buf) == 0) { - if(key_type == NULL || strcmp("ssh-ed25519", key_type) == 0) { - rc = gen_publickey_from_ed25519_openssh_priv_data(session, - decrypted, - method, - method_len, - pubkeydata, - pubkeydata_len, - (libssh2_ed25519_ctx**)key_ctx); - } - } -#endif -#if LIBSSH2_RSA - if(strcmp("ssh-rsa", (const char *)buf) == 0) { - if(key_type == NULL || strcmp("ssh-rsa", key_type) == 0) { - rc = gen_publickey_from_rsa_openssh_priv_data(session, decrypted, - method, method_len, - pubkeydata, - pubkeydata_len, - (libssh2_rsa_ctx**)key_ctx); - } - } -#endif -#if LIBSSH2_DSA - if(strcmp("ssh-dss", (const char *)buf) == 0) { - if(key_type == NULL || strcmp("ssh-dss", key_type) == 0) { - rc = gen_publickey_from_dsa_openssh_priv_data(session, decrypted, - method, method_len, - pubkeydata, - pubkeydata_len, - (libssh2_dsa_ctx**)key_ctx); - } - } -#endif -#if LIBSSH2_ECDSA -{ - libssh2_curve_type type; - - if(_libssh2_ecdsa_curve_type_from_name((const char *)buf, &type) == 0) { - if(key_type == NULL || strcmp("ssh-ecdsa", key_type) == 0) { - rc = gen_publickey_from_ecdsa_openssh_priv_data(session, type, - decrypted, - method, method_len, - pubkeydata, - pubkeydata_len, - (libssh2_ecdsa_ctx**)key_ctx); - } - } -} -#endif - - if(decrypted) - _libssh2_string_buf_free(session, decrypted); - - return rc; -} - -int -read_openssh_private_key_from_memory(void **key_ctx, LIBSSH2_SESSION *session, - const char *key_type, - const char *filedata, - size_t filedata_len, - unsigned const char *passphrase) -{ - return _libssh2_pub_priv_openssh_keyfilememory(session, key_ctx, key_type, - NULL, NULL, NULL, NULL, - filedata, filedata_len, - passphrase); -} - -int -_libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - const char *privatekeydata, - size_t privatekeydata_len, - const char *passphrase) -{ - int st; - BIO* bp; - EVP_PKEY* pk; - int pktype; - - _libssh2_debug(session, - LIBSSH2_TRACE_AUTH, - "Computing public key from private key."); - - bp = BIO_new_mem_buf((char *)privatekeydata, privatekeydata_len); - if(!bp) { - return -1; - } - - BIO_reset(bp); - pk = PEM_read_bio_PrivateKey(bp, NULL, NULL, (void *)passphrase); - BIO_free(bp); - - if(pk == NULL) { - /* Try OpenSSH format */ - st = _libssh2_pub_priv_openssh_keyfilememory(session, NULL, NULL, - method, - method_len, - pubkeydata, - pubkeydata_len, - privatekeydata, - privatekeydata_len, - (unsigned const char *)passphrase); - if(st != 0) { - return _libssh2_error(session, - LIBSSH2_ERROR_FILE, - "Unable to extract public key " - "from private key file: " - "Wrong passphrase or invalid/unrecognized " - "private key file format"); - } - - return 0; - } - -#ifdef HAVE_OPAQUE_STRUCTS - pktype = EVP_PKEY_id(pk); -#else - pktype = pk->type; -#endif - - switch(pktype) { -#if LIBSSH2_ED25519 - case EVP_PKEY_ED25519 : - st = gen_publickey_from_ed_evp( - session, method, method_len, pubkeydata, pubkeydata_len, pk); - break; -#endif /* LIBSSH2_ED25519 */ - case EVP_PKEY_RSA : - st = gen_publickey_from_rsa_evp(session, method, method_len, - pubkeydata, pubkeydata_len, pk); - break; -#if LIBSSH2_DSA - case EVP_PKEY_DSA : - st = gen_publickey_from_dsa_evp(session, method, method_len, - pubkeydata, pubkeydata_len, pk); - break; -#endif /* LIBSSH_DSA */ -#if LIBSSH2_ECDSA - case EVP_PKEY_EC : - st = gen_publickey_from_ec_evp(session, method, method_len, - pubkeydata, pubkeydata_len, pk); - break; -#endif /* LIBSSH2_ECDSA */ - default : - st = _libssh2_error(session, - LIBSSH2_ERROR_FILE, - "Unable to extract public key " - "from private key file: " - "Unsupported private key file format"); - break; - } - - EVP_PKEY_free(pk); - return st; -} - -void -_libssh2_dh_init(_libssh2_dh_ctx *dhctx) -{ - *dhctx = BN_new(); /* Random from client */ -} - -int -_libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public, - _libssh2_bn *g, _libssh2_bn *p, int group_order, - _libssh2_bn_ctx *bnctx) -{ - /* Generate x and e */ - BN_rand(*dhctx, group_order * 8 - 1, 0, -1); - BN_mod_exp(public, g, *dhctx, p, bnctx); - return 0; -} - -int -_libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret, - _libssh2_bn *f, _libssh2_bn *p, - _libssh2_bn_ctx *bnctx) -{ - /* Compute the shared secret */ - BN_mod_exp(secret, f, *dhctx, p, bnctx); - return 0; -} - -void -_libssh2_dh_dtor(_libssh2_dh_ctx *dhctx) -{ - BN_clear_free(*dhctx); - *dhctx = NULL; -} - -#endif /* LIBSSH2_OPENSSL */ diff --git a/libssh2/os400qc3.c b/libssh2/os400qc3.c deleted file mode 100644 index bf5acda..0000000 --- a/libssh2/os400qc3.c +++ /dev/null @@ -1,2411 +0,0 @@ -/* - * Copyright (C) 2015-2016 Patrick Monnerat, D+H - * Copyright (C) 2020 Patrick Monnerat . - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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 "libssh2_priv.h" - -#ifdef LIBSSH2_OS400QC3 /* compile only if we build with OS/400 QC3 library */ - -#ifdef HAVE_STDLIB_H -#include -#endif - -#include -#include -#include -#include - -#include - - -#ifdef OS400_DEBUG -/* In debug mode, all system library errors cause an exception. */ -#define set_EC_length(ec, length) ((ec).Bytes_Provided = \ - (ec).Bytes_Available = 0) -#else -#define set_EC_length(ec, length) ((ec).Bytes_Provided = (length)) -#endif - - -/* Ensure va_list operations are not on an array. */ -typedef struct { - va_list list; -} valiststr; - - -typedef int (*loadkeyproc)(LIBSSH2_SESSION *session, - const unsigned char *data, unsigned int datalen, - const unsigned char *passphrase, void *loadkeydata); - -/* Public key extraction data. */ -typedef struct { - const char * method; - const unsigned char * data; - unsigned int length; -} loadpubkeydata; - - -/* Support for ASN.1 elements. */ - -typedef struct { - char * header; /* Pointer to header byte. */ - char * beg; /* Pointer to element data. */ - char * end; /* Pointer to 1st byte after element. */ - unsigned char class; /* ASN.1 element class. */ - unsigned char tag; /* ASN.1 element tag. */ - unsigned char constructed; /* Element is constructed. */ -} asn1Element; - -#define ASN1_INTEGER 2 -#define ASN1_BIT_STRING 3 -#define ASN1_OCTET_STRING 4 -#define ASN1_NULL 5 -#define ASN1_OBJ_ID 6 -#define ASN1_SEQ 16 - -#define ASN1_CONSTRUCTED 0x20 - -/* rsaEncryption OID: 1.2.840.113549.1.1.1 */ -static unsigned char OID_rsaEncryption[] = - {9, 40 + 2, 0x86, 0x48, 0x86, 0xF7, 0x0D, 1, 1, 1}; -static int sshrsapubkey(LIBSSH2_SESSION *session, char **sshpubkey, - asn1Element *params, asn1Element *key, - const char *method); - -#if LIBSSH2_DSA != 0 -/* dsaEncryption OID: 1.2.840.10040.4.1 */ -static unsigned char OID_dsaEncryption[] = - {7, 40 + 2, 0x86, 0x48, 0xCE, 0x38, 4, 1}; -static int sshdsapubkey(LIBSSH2_SESSION *session, char **sshpubkey, - asn1Element *params, asn1Element *key, - const char *method); -#endif - -static unsigned char OID_dhKeyAgreement[] = - {9, 40 + 2, 0x86, 0x48, 0x86, 0xF7, 0x0D, 1, 3, 1}; - - -/* PKCS#5 support. */ - -typedef struct pkcs5params pkcs5params; -struct pkcs5params { - int cipher; /* Encryption cipher. */ - int blocksize; /* Cipher block size. */ - char mode; /* Block encryption mode. */ - char padopt; /* Pad option. */ - char padchar; /* Pad character. */ - int (*kdf)(LIBSSH2_SESSION *session, char **dk, - const unsigned char *passphrase, pkcs5params *pkcs5); - int hash; /* KDF hash algorithm. */ - size_t hashlen; /* KDF hash digest length. */ - char * salt; /* Salt. */ - size_t saltlen; /* Salt length. */ - char * iv; /* Initialization vector. */ - size_t ivlen; /* Initialization vector length. */ - int itercount; /* KDF iteration count. */ - int dklen; /* Derived key length (#bytes). */ - int effkeysize; /* RC2 effective key size (#bits) or 0. */ -}; - -typedef struct pkcs5algo pkcs5algo; -struct pkcs5algo { - const unsigned char * oid; - int (*parse)(LIBSSH2_SESSION *session, pkcs5params *pkcs5, - pkcs5algo *algo, asn1Element *param); - int cipher; /* Encryption cipher. */ - size_t blocksize; /* Cipher block size. */ - char mode; /* Block encryption mode. */ - char padopt; /* Pad option. */ - char padchar; /* Pad character. */ - size_t keylen; /* Key length (#bytes). */ - int hash; /* Hash algorithm. */ - size_t hashlen; /* Hash digest length. */ - size_t saltlen; /* Salt length. */ - size_t ivlen; /* Initialisation vector length. */ - int effkeysize; /* RC2 effective key size (#bits) or 0. */ -}; - -/* id-PBES2 OID: 1.2.840.113549.1.5.13 */ -static const unsigned char OID_id_PBES2[] = { - 9, 40 + 2, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x05, 0x0D -}; -static int parse_pbes2(LIBSSH2_SESSION *session, pkcs5params *pkcs5, - pkcs5algo *algo, asn1Element *param); -static const pkcs5algo PBES2 = { - OID_id_PBES2, parse_pbes2, 0, 0, '\0', '\0', '\0', 0, - 0, 0, 0, 0, 0 -}; - -/* id-PBKDF2 OID: 1.2.840.113549.1.5.12 */ -static const unsigned char OID_id_PBKDF2[] = { - 9, 40 + 2, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x05, 0x0C -}; -static int parse_pbkdf2(LIBSSH2_SESSION *session, pkcs5params *pkcs5, - pkcs5algo *algo, asn1Element *param); -static const pkcs5algo PBKDF2 = { - OID_id_PBKDF2, parse_pbkdf2, 0, 0, '\0', '\0', '\0', - SHA_DIGEST_LENGTH, Qc3_SHA1, SHA_DIGEST_LENGTH, 8, 8, 0 -}; - -/* id-hmacWithSHA1 OID: 1.2.840.113549.2.7 */ -static const unsigned char OID_id_hmacWithSHA1[] = { - 8, 40 + 2, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x07 -}; -static int parse_hmacWithSHA1(LIBSSH2_SESSION *session, pkcs5params *pkcs5, - pkcs5algo *algo, asn1Element *param); -static const pkcs5algo hmacWithSHA1 = { - OID_id_hmacWithSHA1, parse_hmacWithSHA1, 0, 0, '\0', '\0', '\0', - SHA_DIGEST_LENGTH, Qc3_SHA1, SHA_DIGEST_LENGTH, 8, 8, 0 -}; - -/* desCBC OID: 1.3.14.3.2.7 */ -static const unsigned char OID_desCBC[] = {5, 40 + 3, 0x0E, 0x03, 0x02, 0x07}; -static int parse_iv(LIBSSH2_SESSION *session, pkcs5params *pkcs5, - pkcs5algo *algo, asn1Element *param); -static const pkcs5algo desCBC = { - OID_desCBC, parse_iv, Qc3_DES, 8, Qc3_CBC, Qc3_Pad_Counter, - '\0', 8, 0, 0, 8, 8, 0 -}; - -/* des-EDE3-CBC OID: 1.2.840.113549.3.7 */ -static const unsigned char OID_des_EDE3_CBC[] = { - 8, 40 + 2, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x03, 0x07 -}; -static const pkcs5algo des_EDE3_CBC = { - OID_des_EDE3_CBC, parse_iv, Qc3_TDES, 8, Qc3_CBC, Qc3_Pad_Counter, - '\0', 24, 0, 0, 8, 8, 0 -}; - -/* rc2CBC OID: 1.2.840.113549.3.2 */ -static const unsigned char OID_rc2CBC[] = { - 8, 40 + 2, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x03, 0x02 -}; -static int parse_rc2(LIBSSH2_SESSION *session, pkcs5params *pkcs5, - pkcs5algo *algo, asn1Element *param); -static const pkcs5algo rc2CBC = { - OID_rc2CBC, parse_rc2, Qc3_RC2, 8, Qc3_CBC, Qc3_Pad_Counter, - '\0', 0, 0, 0, 8, 0, 32 -}; - -/* pbeWithMD5AndDES-CBC OID: 1.2.840.113549.1.5.3 */ -static const unsigned char OID_pbeWithMD5AndDES_CBC[] = { - 9, 40 + 2, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x05, 0x03 -}; -static int parse_pbes1(LIBSSH2_SESSION *session, pkcs5params *pkcs5, - pkcs5algo *algo, asn1Element *param); -static const pkcs5algo pbeWithMD5AndDES_CBC = { - OID_pbeWithMD5AndDES_CBC, parse_pbes1, Qc3_DES, 8, Qc3_CBC, - Qc3_Pad_Counter, '\0', 8, Qc3_MD5, MD5_DIGEST_LENGTH, 8, 0, 0 -}; - -/* pbeWithMD5AndRC2-CBC OID: 1.2.840.113549.1.5.6 */ -static const unsigned char OID_pbeWithMD5AndRC2_CBC[] = { - 9, 40 + 2, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x05, 0x06 -}; -static const pkcs5algo pbeWithMD5AndRC2_CBC = { - OID_pbeWithMD5AndRC2_CBC, parse_pbes1, Qc3_RC2, 8, Qc3_CBC, - Qc3_Pad_Counter, '\0', 0, Qc3_MD5, MD5_DIGEST_LENGTH, 8, 0, 64 -}; - -/* pbeWithSHA1AndDES-CBC OID: 1.2.840.113549.1.5.10 */ -static const unsigned char OID_pbeWithSHA1AndDES_CBC[] = { - 9, 40 + 2, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x05, 0x0A -}; -static const pkcs5algo pbeWithSHA1AndDES_CBC = { - OID_pbeWithSHA1AndDES_CBC, parse_pbes1, Qc3_DES, 8, Qc3_CBC, - Qc3_Pad_Counter, '\0', 8, Qc3_SHA1, SHA_DIGEST_LENGTH, 8, 0, 0 -}; - -/* pbeWithSHA1AndRC2-CBC OID: 1.2.840.113549.1.5.11 */ -static const unsigned char OID_pbeWithSHA1AndRC2_CBC[] = { - 9, 40 + 2, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x05, 0x0B -}; -static const pkcs5algo pbeWithSHA1AndRC2_CBC = { - OID_pbeWithSHA1AndRC2_CBC, parse_pbes1, Qc3_RC2, 8, Qc3_CBC, - Qc3_Pad_Counter, '\0', 0, Qc3_SHA1, SHA_DIGEST_LENGTH, 8, 0, 64 -}; - -/* rc5-CBC-PAD OID: 1.2.840.113549.3.9: RC5 not implemented in Qc3. */ -/* pbeWithMD2AndDES-CBC OID: 1.2.840.113549.1.5.1: MD2 not implemented. */ -/* pbeWithMD2AndRC2-CBC OID: 1.2.840.113549.1.5.4: MD2 not implemented. */ - -static const pkcs5algo * pbestable[] = { - &pbeWithMD5AndDES_CBC, - &pbeWithMD5AndRC2_CBC, - &pbeWithSHA1AndDES_CBC, - &pbeWithSHA1AndRC2_CBC, - &PBES2, - NULL -}; - -static const pkcs5algo * pbkdf2table[] = { - &PBKDF2, - NULL -}; - -static const pkcs5algo * pbes2enctable[] = { - &desCBC, - &des_EDE3_CBC, - &rc2CBC, - NULL -}; - -static const pkcs5algo * kdf2prftable[] = { - &hmacWithSHA1, - NULL -}; - - -/* Public key extraction support. */ -static struct { - unsigned char *oid; - int (*sshpubkey)(LIBSSH2_SESSION *session, char **pubkey, - asn1Element *params, asn1Element *key, - const char *method); - const char * method; -} pka[] = { -#if LIBSSH2_RSA != 0 - { OID_rsaEncryption, sshrsapubkey, "ssh-rsa" }, -#endif -#if LIBSSH2_DSA != 0 - { OID_dsaEncryption, sshdsapubkey, "ssh-dss" }, -#endif - { NULL, NULL, NULL } -}; - -/* Define ASCII strings. */ -static const char beginencprivkeyhdr[] = - "-----BEGIN ENCRYPTED PRIVATE KEY-----"; -static const char endencprivkeyhdr[] = "-----END ENCRYPTED PRIVATE KEY-----"; -static const char beginprivkeyhdr[] = "-----BEGIN PRIVATE KEY-----"; -static const char endprivkeyhdr[] = "-----END PRIVATE KEY-----"; -static const char beginrsaprivkeyhdr[] = "-----BEGIN RSA PRIVATE KEY-----"; -static const char endrsaprivkeyhdr[] = "-----END RSA PRIVATE KEY-----"; -static const char fopenrmode[] = "r"; -static const char fopenrbmode[] = "rb"; - - -/* The rest of character literals in this module are in EBCDIC. */ -#pragma convert(37) - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static Qc3_Format_KEYD0100_T nulltoken = {""}; - -static int zero = 0; -static int rsaprivate[] = { Qc3_RSA_Private }; -static char anycsp[] = { Qc3_Any_CSP }; -static char binstring[] = { Qc3_Bin_String }; -static char berstring[] = { Qc3_BER_String }; -static char qc3clear[] = { Qc3_Clear }; - -static const Qus_EC_t ecnull = {0}; /* Error causes an exception. */ - -static asn1Element lastbytebitcount = { - (char *) &zero, NULL, (char *) &zero + 1 -}; - - -/******************************************************************* - * - * OS/400 QC3 crypto-library backend: ASN.1 support. - * - *******************************************************************/ - -static char * -getASN1Element(asn1Element *elem, char *beg, char *end) -{ - unsigned char b; - unsigned long len; - asn1Element lelem; - - /* Get a single ASN.1 element into `elem', parse ASN.1 string at `beg' - * ending at `end'. - * Returns a pointer in source string after the parsed element, or NULL - * if an error occurs. - */ - - if(beg >= end || !*beg) - return NULL; - - /* Process header byte. */ - elem->header = beg; - b = (unsigned char) *beg++; - elem->constructed = (b & 0x20) != 0; - elem->class = (b >> 6) & 3; - b &= 0x1F; - if(b == 0x1F) - return NULL; /* Long tag values not supported here. */ - elem->tag = b; - - /* Process length. */ - if(beg >= end) - return NULL; - b = (unsigned char) *beg++; - if(!(b & 0x80)) - len = b; - else if(!(b &= 0x7F)) { - /* Unspecified length. Since we have all the data, we can determine the - * effective length by skipping element until an end element is - * found. - */ - if(!elem->constructed) - return NULL; - elem->beg = beg; - while(beg < end && *beg) { - beg = getASN1Element(&lelem, beg, end); - if(!beg) - return NULL; - } - if(beg >= end) - return NULL; - elem->end = beg; - return beg + 1; - } - else if(beg + b > end) - return NULL; /* Does not fit in source. */ - else { - /* Get long length. */ - len = 0; - do { - if(len & 0xFF000000L) - return NULL; /* Lengths > 32 bits are not supported. */ - len = (len << 8) | (unsigned char) *beg++; - } while(--b); - } - if((unsigned long) (end - beg) < len) - return NULL; /* Element data does not fit in source. */ - elem->beg = beg; - elem->end = beg + len; - return elem->end; -} - -static asn1Element * -asn1_new(unsigned int type, unsigned int length) -{ - asn1Element *e; - unsigned int hdrl = 2; - unsigned int i; - unsigned char *buf; - - e = (asn1Element *) malloc(sizeof *e); - - if(e) { - if(length >= 0x80) - for(i = length; i; i >>= 8) - hdrl++; - - buf = (unsigned char *) malloc(hdrl + length); - - if(buf) { - e->header = buf; - e->beg = buf + hdrl; - e->end = e->beg + length; - e->class = (type >> 6) & 0x03; - e->tag = type & 0x1F; - e->constructed = (type >> 5) & 0x01; - e->header[0] = type; - - if(length < 0x80) - e->header[1] = length; - else { - e->header[1] = (hdrl - 2) | 0x80; - do { - e->header[--hdrl] = length; - length >>= 8; - } while(length); - } - } - else { - free((char *) e); - e = NULL; - } - } - - return e; -} - -static asn1Element * -asn1_new_from_bytes(const unsigned char *data, unsigned int length) -{ - asn1Element *e; - asn1Element te; - - getASN1Element(&te, - (unsigned char *) data, (unsigned char *) data + length); - e = asn1_new(te.tag, te.end - te.beg); - - if(e) - memcpy(e->header, data, e->end - e->header); - - return e; -} - -static void -asn1delete(asn1Element *e) -{ - if(e) { - if(e->header) - free((char *) e->header); - free((char *) e); - } -} - -static asn1Element * -asn1uint(_libssh2_bn *bn) -{ - asn1Element *e; - int bits; - int length; - unsigned char *p; - - if(!bn) - return NULL; - - bits = _libssh2_bn_bits(bn); - length = (bits + 8) >> 3; - e = asn1_new(ASN1_INTEGER, length); - - if(e) { - p = e->beg; - if(!(bits & 0x07)) - *p++ = 0; - _libssh2_bn_to_bin(bn, p); - } - - return e; -} - -static asn1Element * -asn1containerv(unsigned int type, valiststr args) -{ - valiststr va; - asn1Element *e; - asn1Element *p; - unsigned char *bp; - unsigned int length = 0; - - memcpy((char *) &va, (char *) &args, sizeof args); - while((p = va_arg(va.list, asn1Element *))) - length += p->end - p->header; - va_end(va.list); - e = asn1_new(type, length); - if(e) { - bp = e->beg; - while((p = va_arg(args.list, asn1Element *))) { - memcpy(bp, p->header, p->end - p->header); - bp += p->end - p->header; - } - } - return e; -} - -/* VARARGS1 */ -static asn1Element * -asn1container(unsigned int type, ...) -{ - valiststr va; - asn1Element *e; - - va_start(va.list, type); - e = asn1containerv(type, va); - va_end(va.list); - return e; -} - -static asn1Element * -asn1bytes(unsigned int type, const unsigned char *bytes, unsigned int length) -{ - asn1Element *e; - - e = asn1_new(type, length); - if(e && length) - memcpy(e->beg, bytes, length); - return e; -} - -static asn1Element * -rsapublickey(_libssh2_bn *e, _libssh2_bn *m) -{ - asn1Element *publicexponent; - asn1Element *modulus; - asn1Element *rsapubkey; - - /* Build a PKCS#1 RSAPublicKey. */ - - modulus = asn1uint(m); - publicexponent = asn1uint(e); - rsapubkey = asn1container(ASN1_SEQ | ASN1_CONSTRUCTED, - modulus, publicexponent, NULL); - asn1delete(modulus); - asn1delete(publicexponent); - - if(!modulus || !publicexponent) { - asn1delete(rsapubkey); - rsapubkey = NULL; - } - - return rsapubkey; -} - -static asn1Element * -rsaprivatekey(_libssh2_bn *e, _libssh2_bn *m, _libssh2_bn *d, - _libssh2_bn *p, _libssh2_bn *q, - _libssh2_bn *exp1, _libssh2_bn *exp2, _libssh2_bn *coeff) -{ - asn1Element *version; - asn1Element *modulus; - asn1Element *publicexponent; - asn1Element *privateexponent; - asn1Element *prime1; - asn1Element *prime2; - asn1Element *exponent1; - asn1Element *exponent2; - asn1Element *coefficient; - asn1Element *rsaprivkey; - - /* Build a PKCS#1 RSAPrivateKey. */ - version = asn1bytes(ASN1_INTEGER, "\0", 1); - modulus = asn1uint(m); - publicexponent = asn1uint(e); - privateexponent = asn1uint(d); - prime1 = asn1uint(p); - prime2 = asn1uint(q); - exponent1 = asn1uint(exp1); - exponent2 = asn1uint(exp2); - coefficient = asn1uint(coeff); - rsaprivkey = asn1container(ASN1_SEQ | ASN1_CONSTRUCTED, version, modulus, - publicexponent, privateexponent, prime1, prime2, - exponent1, exponent2, coefficient, NULL); - asn1delete(version); - asn1delete(modulus); - asn1delete(publicexponent); - asn1delete(privateexponent); - asn1delete(prime1); - asn1delete(prime2); - asn1delete(exponent1); - asn1delete(exponent2); - asn1delete(coefficient); - - if(!version || !modulus || !publicexponent || !privateexponent || - !prime1 || !prime2 || !exponent1 || !exponent2 || !coefficient) { - asn1delete(rsaprivkey); - rsaprivkey = NULL; - } - - return rsaprivkey; -} - -static asn1Element * -subjectpublickeyinfo(asn1Element *pubkey, const unsigned char *algo, - asn1Element *parameters) -{ - asn1Element *subjpubkey; - asn1Element *algorithm; - asn1Element *algorithmid; - asn1Element *subjpubkeyinfo; - unsigned int algosize = *algo++; - - algorithm = asn1bytes(ASN1_OBJ_ID, algo, algosize); - algorithmid = asn1container(ASN1_SEQ | ASN1_CONSTRUCTED, - algorithm, parameters, NULL); - subjpubkey = asn1container(ASN1_BIT_STRING, &lastbytebitcount, - pubkey, NULL); - subjpubkeyinfo = asn1container(ASN1_SEQ | ASN1_CONSTRUCTED, - algorithmid, subjpubkey, NULL); - asn1delete(algorithm); - asn1delete(algorithmid); - asn1delete(subjpubkey); - if(!algorithm || !algorithmid || !subjpubkey) { - asn1delete(subjpubkeyinfo); - subjpubkeyinfo = NULL; - } - return subjpubkeyinfo; -} - -static asn1Element * -rsasubjectpublickeyinfo(asn1Element *pubkey) -{ - asn1Element *parameters; - asn1Element *subjpubkeyinfo; - - parameters = asn1bytes(ASN1_NULL, NULL, 0); - subjpubkeyinfo = subjectpublickeyinfo(pubkey, - OID_rsaEncryption, parameters); - asn1delete(parameters); - if(!parameters) { - asn1delete(subjpubkeyinfo); - subjpubkeyinfo = NULL; - } - return subjpubkeyinfo; -} - -static asn1Element * -privatekeyinfo(asn1Element *privkey, const unsigned char *algo, - asn1Element *parameters) -{ - asn1Element *version; - asn1Element *privatekey; - asn1Element *algorithm; - asn1Element *privatekeyalgorithm; - asn1Element *privkeyinfo; - unsigned int algosize = *algo++; - - /* Build a PKCS#8 PrivateKeyInfo. */ - version = asn1bytes(ASN1_INTEGER, "\0", 1); - algorithm = asn1bytes(ASN1_OBJ_ID, algo, algosize); - privatekeyalgorithm = asn1container(ASN1_SEQ | ASN1_CONSTRUCTED, - algorithm, parameters, NULL); - privatekey = asn1container(ASN1_OCTET_STRING, privkey, NULL); - privkeyinfo = asn1container(ASN1_SEQ | ASN1_CONSTRUCTED, version, - privatekeyalgorithm, privatekey, NULL); - asn1delete(version); - asn1delete(algorithm); - asn1delete(privatekeyalgorithm); - if(!version || !algorithm || !privatekeyalgorithm) { - asn1delete(privkeyinfo); - privkeyinfo = NULL; - } - return privkeyinfo; -} - -static asn1Element * -rsaprivatekeyinfo(asn1Element *privkey) -{ - asn1Element *parameters; - asn1Element *privkeyinfo; - - parameters = asn1bytes(ASN1_NULL, NULL, 0); - privkeyinfo = privatekeyinfo(privkey, OID_rsaEncryption, parameters); - asn1delete(parameters); - if(!parameters) { - asn1delete(privkeyinfo); - privkeyinfo = NULL; - } - return privkeyinfo; -} - -/******************************************************************* - * - * OS/400 QC3 crypto-library backend: big numbers support. - * - *******************************************************************/ - - -_libssh2_bn * -_libssh2_bn_init(void) -{ - _libssh2_bn *bignum; - - bignum = (_libssh2_bn *) malloc(sizeof *bignum); - if(bignum) { - bignum->bignum = NULL; - bignum->length = 0; - } - - return bignum; -} - -void -_libssh2_bn_free(_libssh2_bn *bn) -{ - if(bn) { - if(bn->bignum) { -#ifdef LIBSSH2_CLEAR_MEMORY - if(bn->length) - memset((char *) bn->bignum, 0, bn->length); -#endif - free(bn->bignum); - } - - free((char *) bn); - } -} - -static int -_libssh2_bn_resize(_libssh2_bn *bn, size_t newlen) -{ - unsigned char *bignum; - - if(!bn) - return -1; - if(newlen == bn->length) - return 0; - - if(!bn->bignum) - bignum = (unsigned char *) malloc(newlen); - else { -#ifdef LIBSSH2_CLEAR_MEMORY - if(newlen < bn->length) - memset((char *) bn->bignum + newlen, 0, bn->length - newlen); -#endif - if(!newlen) { - free((char *) bn->bignum); - bn->bignum = NULL; - bn->length = 0; - return 0; - } - bignum = (unsigned char *) realloc((char *) bn->bignum, newlen); - } - - if(!bignum) - return -1; - - if(newlen > bn->length) - memset((char *) bignum + bn->length, 0, newlen - bn->length); - - bn->bignum = bignum; - bn->length = newlen; - return 0; -} - -unsigned long -_libssh2_bn_bits(_libssh2_bn *bn) -{ - unsigned int i; - unsigned char b; - - if(bn && bn->bignum) { - for(i = bn->length; i--;) - b = bn->bignum[i]; - if(b) { - i *= 8; - do { - i++; - } while(b >>= 1); - return i; - } - } - - return 0; -} - -int -_libssh2_bn_from_bin(_libssh2_bn *bn, int len, const unsigned char *val) -{ - int i; - - if(!bn || (len && !val)) - return -1; - - for(; len && !*val; len--) - val++; - - if(_libssh2_bn_resize(bn, len)) - return -1; - - for(i = len; i--;) - bn->bignum[i] = *val++; - - return 0; -} - -int -_libssh2_bn_set_word(_libssh2_bn *bn, unsigned long val) -{ - val = htonl(val); - return _libssh2_bn_from_bin(bn, sizeof val, (unsigned char *) &val); -} - -int -_libssh2_bn_to_bin(_libssh2_bn *bn, unsigned char *val) -{ - int i; - - if(!bn || !val) - return -1; - - for(i = bn->length; i--;) - *val++ = bn->bignum[i]; - - return 0; -} - -static int -_libssh2_bn_from_bn(_libssh2_bn *to, _libssh2_bn *from) -{ - int i; - - if(!to || !from) - return -1; - - if(_libssh2_bn_resize(to, from->length)) - return -1; - - for(i = to->length; i--;) - to->bignum[i] = from->bignum[i]; - - return 0; -} - -void -_libssh2_random(unsigned char *buf, int len) -{ - Qc3GenPRNs(buf, len, - Qc3PRN_TYPE_NORMAL, Qc3PRN_NO_PARITY, (char *) &ecnull); -} - - -/******************************************************************* - * - * OS/400 QC3 crypto-library backend: crypto context support. - * - *******************************************************************/ - -static _libssh2_os400qc3_crypto_ctx * -libssh2_init_crypto_ctx(_libssh2_os400qc3_crypto_ctx *ctx) -{ - if(!ctx) - ctx = (_libssh2_os400qc3_crypto_ctx *) malloc(sizeof *ctx); - - if(ctx) { - memset((char *) ctx, 0, sizeof *ctx); - ctx->hash.Final_Op_Flag = Qc3_Continue; - } - - return ctx; -} - -static int -null_token(const char *token) -{ - return !memcmp(token, nulltoken.Key_Context_Token, - sizeof nulltoken.Key_Context_Token); -} - -void -_libssh2_os400qc3_crypto_dtor(_libssh2_os400qc3_crypto_ctx *x) -{ - if(!x) - return; - if(!null_token(x->hash.Alg_Context_Token)) { - Qc3DestroyAlgorithmContext(x->hash.Alg_Context_Token, - (char *) &ecnull); - memset(x->hash.Alg_Context_Token, 0, sizeof x->hash.Alg_Context_Token); - } - if(!null_token(x->key.Key_Context_Token)) { - Qc3DestroyKeyContext(x->key.Key_Context_Token, (char *) &ecnull); - memset(x->key.Key_Context_Token, 0, sizeof x->key.Key_Context_Token); - } - if(x->kek) { - _libssh2_os400qc3_crypto_dtor(x->kek); - free((char *) x->kek); - x->kek = NULL; - } -} - -/******************************************************************* - * - * OS/400 QC3 crypto-library backend: hash algorithms support. - * - *******************************************************************/ - -int -libssh2_os400qc3_hash_init(Qc3_Format_ALGD0100_T *x, unsigned int algorithm) -{ - Qc3_Format_ALGD0500_T algd; - Qus_EC_t errcode; - - if(!x) - return 0; - - memset((char *) x, 0, sizeof *x); - x->Final_Op_Flag = Qc3_Continue; - algd.Hash_Alg = algorithm; - set_EC_length(errcode, sizeof errcode); - Qc3CreateAlgorithmContext((char *) &algd, Qc3_Alg_Hash, - x->Alg_Context_Token, &errcode); - return errcode.Bytes_Available? 0: 1; -} - -void -libssh2_os400qc3_hash_update(Qc3_Format_ALGD0100_T *ctx, - const unsigned char *data, int len) -{ - char dummy[64]; - - ctx->Final_Op_Flag = Qc3_Continue; - Qc3CalculateHash((char *) data, &len, Qc3_Data, (char *) ctx, - Qc3_Alg_Token, anycsp, NULL, dummy, (char *) &ecnull); -} - -void -libssh2_os400qc3_hash_final(Qc3_Format_ALGD0100_T *ctx, unsigned char *out) -{ - char data; - - ctx->Final_Op_Flag = Qc3_Final; - Qc3CalculateHash(&data, &zero, Qc3_Data, (char *) ctx, Qc3_Alg_Token, - anycsp, NULL, (char *) out, (char *) &ecnull); - Qc3DestroyAlgorithmContext(ctx->Alg_Context_Token, (char *) &ecnull); - memset(ctx->Alg_Context_Token, 0, sizeof ctx->Alg_Context_Token); -} - -int -libssh2_os400qc3_hash(const unsigned char *message, unsigned long len, - unsigned char *out, unsigned int algo) -{ - Qc3_Format_ALGD0100_T ctx; - - if(!libssh2_os400qc3_hash_init(&ctx, algo)) - return 1; - - libssh2_os400qc3_hash_update(&ctx, message, len); - libssh2_os400qc3_hash_final(&ctx, out); - return 0; -} - -void -libssh2_os400qc3_hmac_init(_libssh2_os400qc3_crypto_ctx *ctx, - int algo, size_t minkeylen, void *key, int keylen) -{ - if(keylen < minkeylen) { - char *lkey = alloca(minkeylen); - - /* Pad key with zeroes if too short. */ - if(!lkey) - return; - memcpy(lkey, (char *) key, keylen); - memset(lkey + keylen, 0, minkeylen - keylen); - key = (void *) lkey; - keylen = minkeylen; - } - libssh2_os400qc3_hash_init(&ctx->hash, algo); - Qc3CreateKeyContext((char *) key, &keylen, binstring, &algo, qc3clear, - NULL, NULL, ctx->key.Key_Context_Token, - (char *) &ecnull); -} - -void -libssh2_os400qc3_hmac_update(_libssh2_os400qc3_crypto_ctx *ctx, - unsigned char *data, int len) -{ - char dummy[64]; - - ctx->hash.Final_Op_Flag = Qc3_Continue; - Qc3CalculateHMAC((char *) data, &len, Qc3_Data, (char *) &ctx->hash, - Qc3_Alg_Token, ctx->key.Key_Context_Token, Qc3_Key_Token, - anycsp, NULL, dummy, (char *) &ecnull); -} - -void -libssh2_os400qc3_hmac_final(_libssh2_os400qc3_crypto_ctx *ctx, - unsigned char *out) -{ - char data; - - ctx->hash.Final_Op_Flag = Qc3_Final; - Qc3CalculateHMAC((char *) data, &zero, Qc3_Data, (char *) &ctx->hash, - Qc3_Alg_Token, ctx->key.Key_Context_Token, Qc3_Key_Token, - anycsp, NULL, (char *) out, (char *) &ecnull); -} - - -/******************************************************************* - * - * OS/400 QC3 crypto-library backend: cipher algorithms support. - * - *******************************************************************/ - -int -_libssh2_cipher_init(_libssh2_cipher_ctx *h, _libssh2_cipher_type(algo), - unsigned char *iv, unsigned char *secret, int encrypt) -{ - Qc3_Format_ALGD0200_T algd; - Qus_EC_t errcode; - - (void) encrypt; - - if(!h) - return -1; - - libssh2_init_crypto_ctx(h); - algd.Block_Cipher_Alg = algo.algo; - algd.Block_Length = algo.size; - algd.Mode = algo.mode; - algd.Pad_Option = Qc3_No_Pad; - algd.Pad_Character = 0; - algd.Reserved = 0; - algd.MAC_Length = 0; - algd.Effective_Key_Size = 0; - memset(algd.Init_Vector, 0, sizeof algd.Init_Vector); - if(algo.mode != Qc3_ECB && algo.size) - memcpy(algd.Init_Vector, iv, algo.size); - set_EC_length(errcode, sizeof errcode); - Qc3CreateAlgorithmContext((char *) &algd, algo.fmt, - h->hash.Alg_Context_Token, &errcode); - if(errcode.Bytes_Available) - return -1; - Qc3CreateKeyContext((char *) secret, &algo.keylen, binstring, - &algo.algo, qc3clear, NULL, NULL, - h->key.Key_Context_Token, (char *) &errcode); - if(errcode.Bytes_Available) { - _libssh2_os400qc3_crypto_dtor(h); - return -1; - } - - return 0; -} - -int -_libssh2_cipher_crypt(_libssh2_cipher_ctx *ctx, - _libssh2_cipher_type(algo), - int encrypt, unsigned char *block, size_t blocksize) -{ - Qus_EC_t errcode; - int outlen; - int blksize = blocksize; - - (void) algo; - - set_EC_length(errcode, sizeof errcode); - if(encrypt) - Qc3EncryptData((char *) block, &blksize, Qc3_Data, - ctx->hash.Alg_Context_Token, Qc3_Alg_Token, - ctx->key.Key_Context_Token, Qc3_Key_Token, anycsp, NULL, - (char *) block, &blksize, &outlen, (char *) &errcode); - else - Qc3DecryptData((char *) block, &blksize, - ctx->hash.Alg_Context_Token, Qc3_Alg_Token, - ctx->key.Key_Context_Token, Qc3_Key_Token, anycsp, NULL, - (char *) block, &blksize, &outlen, (char *) &errcode); - - return errcode.Bytes_Available? -1: 0; -} - - -/******************************************************************* - * - * OS/400 QC3 crypto-library backend: RSA support. - * - *******************************************************************/ - -int -_libssh2_rsa_new(libssh2_rsa_ctx **rsa, - const unsigned char *edata, unsigned long elen, - const unsigned char *ndata, unsigned long nlen, - const unsigned char *ddata, unsigned long dlen, - const unsigned char *pdata, unsigned long plen, - const unsigned char *qdata, unsigned long qlen, - const unsigned char *e1data, unsigned long e1len, - const unsigned char *e2data, unsigned long e2len, - const unsigned char *coeffdata, unsigned long coefflen) -{ - libssh2_rsa_ctx *ctx; - _libssh2_bn *e = _libssh2_bn_init_from_bin(); - _libssh2_bn *n = _libssh2_bn_init_from_bin(); - _libssh2_bn *d = NULL; - _libssh2_bn *p = NULL; - _libssh2_bn *q = NULL; - _libssh2_bn *e1 = NULL; - _libssh2_bn *e2 = NULL; - _libssh2_bn *coeff = NULL; - asn1Element *key = NULL; - asn1Element *structkey = NULL; - Qc3_Format_ALGD0400_T algd; - Qus_EC_t errcode; - int keytype; - int ret = 0; - int i; - - ctx = libssh2_init_crypto_ctx(NULL); - if(!ctx) - ret = -1; - if(!ret) { - _libssh2_bn_from_bin(e, elen, edata); - _libssh2_bn_from_bin(n, nlen, ndata); - if(!e || !n) - ret = -1; - } - if(!ret && ddata) { - /* Private key. */ - d = _libssh2_bn_init_from_bin(); - _libssh2_bn_from_bin(d, dlen, ddata); - p = _libssh2_bn_init_from_bin(); - _libssh2_bn_from_bin(p, plen, pdata); - q = _libssh2_bn_init_from_bin(); - _libssh2_bn_from_bin(q, qlen, qdata); - e1 = _libssh2_bn_init_from_bin(); - _libssh2_bn_from_bin(e1, e1len, e1data); - e2 = _libssh2_bn_init_from_bin(); - _libssh2_bn_from_bin(e2, e2len, e2data); - coeff = _libssh2_bn_init_from_bin(); - _libssh2_bn_from_bin(coeff, coefflen, coeffdata); - if(!d || !p || !q ||!e1 || !e2 || !coeff) - ret = -1; - - if(!ret) { - /* Build a PKCS#8 private key. */ - key = rsaprivatekey(e, n, d, p, q, e1, e2, coeff); - structkey = rsaprivatekeyinfo(key); - } - keytype = Qc3_RSA_Private; - } - else if(!ret) { - key = rsapublickey(e, n); - structkey = rsasubjectpublickeyinfo(key); - keytype = Qc3_RSA_Public; - } - if(!key || !structkey) - ret = -1; - - set_EC_length(errcode, sizeof errcode); - - if(!ret) { - /* Create the algorithm context. */ - algd.Public_Key_Alg = Qc3_RSA; - algd.PKA_Block_Format = Qc3_PKCS1_01; - memset(algd.Reserved, 0, sizeof algd.Reserved); - algd.Signing_Hash_Alg = Qc3_SHA1; - Qc3CreateAlgorithmContext((char *) &algd, Qc3_Alg_Public_Key, - ctx->hash.Alg_Context_Token, &errcode); - if(errcode.Bytes_Available) - ret = -1; - ctx->hash.Final_Op_Flag = Qc3_Continue; - } - - /* Create the key context. */ - if(!ret) { - i = structkey->end - structkey->header; - Qc3CreateKeyContext(structkey->header, &i, berstring, &keytype, - qc3clear, NULL, NULL, ctx->key.Key_Context_Token, - (char *) &errcode); - if(errcode.Bytes_Available) - ret = -1; - } - - _libssh2_bn_free(e); - _libssh2_bn_free(n); - _libssh2_bn_free(d); - _libssh2_bn_free(p); - _libssh2_bn_free(q); - _libssh2_bn_free(e1); - _libssh2_bn_free(e2); - _libssh2_bn_free(coeff); - asn1delete(key); - asn1delete(structkey); - if(ret && ctx) { - _libssh2_rsa_free(ctx); - ctx = NULL; - } - *rsa = ctx; - return ret; -} - - -/******************************************************************* - * - * OS/400 QC3 crypto-library backend: Diffie-Hellman support. - * - *******************************************************************/ - -void -_libssh2_os400qc3_dh_init(_libssh2_dh_ctx *dhctx) -{ - memset((char *) dhctx, 0, sizeof *dhctx); -} - -int -_libssh2_os400qc3_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public, - _libssh2_bn *g, _libssh2_bn *p, int group_order) -{ - asn1Element *prime; - asn1Element *base; - asn1Element *dhparameter; - asn1Element *dhkeyagreement; - asn1Element *pkcs3; - int pkcs3len; - char *pubkey; - int pubkeysize; - int pubkeylen; - Qus_EC_t errcode; - - (void) group_order; - - /* Build the PKCS#3 structure. */ - - base = asn1uint(g); - prime = asn1uint(p); - dhparameter = asn1container(ASN1_SEQ | ASN1_CONSTRUCTED, - prime, base, NULL); - asn1delete(base); - asn1delete(prime); - dhkeyagreement = asn1bytes(ASN1_OBJ_ID, - OID_dhKeyAgreement + 1, OID_dhKeyAgreement[0]); - pkcs3 = asn1container(ASN1_SEQ | ASN1_CONSTRUCTED, - dhkeyagreement, dhparameter, NULL); - asn1delete(dhkeyagreement); - asn1delete(dhparameter); - if(!base || !prime || !dhparameter || - !dhkeyagreement || !dhparameter || !pkcs3) { - asn1delete(pkcs3); - return -1; - } - pkcs3len = pkcs3->end - pkcs3->header; - pubkeysize = (_libssh2_bn_bits(p) + 7) >> 3; - pubkey = alloca(pubkeysize); - set_EC_length(errcode, sizeof errcode); - Qc3GenDHKeyPair((char *) pkcs3->header, &pkcs3len, anycsp, NULL, - dhctx->token, pubkey, &pubkeysize, &pubkeylen, &errcode); - asn1delete(pkcs3); - if(errcode.Bytes_Available) - return -1; - return _libssh2_bn_from_bin(public, pubkeylen, (unsigned char *) pubkey); -} - -int -_libssh2_os400qc3_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret, - _libssh2_bn *f, _libssh2_bn *p) -{ - char *pubkey; - int pubkeysize; - char *secretbuf; - int secretbufsize; - int secretbuflen; - Qus_EC_t errcode; - - pubkeysize = (_libssh2_bn_bits(f) + 7) >> 3; - pubkey = alloca(pubkeysize); - _libssh2_bn_to_bin(f, pubkey); - secretbufsize = (_libssh2_bn_bits(p) + 7) >> 3; - secretbuf = alloca(pubkeysize); - set_EC_length(errcode, sizeof errcode); - Qc3CalculateDHSecretKey(dhctx->token, pubkey, &pubkeysize, - secretbuf, &secretbufsize, &secretbuflen, - &errcode); - if(errcode.Bytes_Available) - return -1; - return _libssh2_bn_from_bin(secret, - secretbuflen, (unsigned char *) secretbuf); -} - -void -_libssh2_os400qc3_dh_dtor(_libssh2_dh_ctx *dhctx) -{ - if(!null_token(dhctx->token)) { - Qc3DestroyAlgorithmContext(dhctx->token, (char *) &ecnull); - memset((char *) dhctx, 0, sizeof *dhctx); - } -} - - -/******************************************************************* - * - * OS/400 QC3 crypto-library backend: PKCS#5 supplement. - * - *******************************************************************/ - -static int -oidcmp(const asn1Element *e, const unsigned char *oid) -{ - int i = e->end - e->beg - *oid++; - - if(*e->header != ASN1_OBJ_ID) - return -2; - if(!i) - i = memcmp(e->beg, oid, oid[-1]); - return i; -} - -static int -asn1getword(asn1Element *e, unsigned long *v) -{ - unsigned long a; - const unsigned char *cp; - - if(*e->header != ASN1_INTEGER) - return -1; - for(cp = e->beg; cp < e->end && !*cp; cp++) - ; - if(e->end - cp > sizeof a) - return -1; - for(a = 0; cp < e->end; cp++) - a = (a << 8) | *cp; - *v = a; - return 0; -} - -static int -pbkdf1(LIBSSH2_SESSION *session, char **dk, const unsigned char *passphrase, - pkcs5params *pkcs5) -{ - int i; - Qc3_Format_ALGD0100_T hctx; - int len = pkcs5->saltlen; - char *data = (char *) pkcs5->salt; - - *dk = NULL; - if(pkcs5->dklen > pkcs5->hashlen) - return -1; - - /* Allocate the derived key buffer. */ - *dk = LIBSSH2_ALLOC(session, pkcs5->hashlen); - if(!*dk) - return -1; - - /* Initial hash. */ - libssh2_os400qc3_hash_init(&hctx, pkcs5->hash); - libssh2_os400qc3_hash_update(&hctx, passphrase, strlen(passphrase)); - hctx.Final_Op_Flag = Qc3_Final; - Qc3CalculateHash((char *) pkcs5->salt, &len, Qc3_Data, (char *) &hctx, - Qc3_Alg_Token, anycsp, NULL, *dk, (char *) &ecnull); - - /* Iterate. */ - len = pkcs5->hashlen; - for(i = 1; i < pkcs5->itercount; i++) - Qc3CalculateHash((char *) *dk, &len, Qc3_Data, (char *) &hctx, - Qc3_Alg_Token, anycsp, NULL, *dk, (char *) &ecnull); - - /* Special stuff for PBES1: split derived key into 8-byte key and 8-byte - initialization vector. */ - pkcs5->dklen = 8; - pkcs5->ivlen = 8; - pkcs5->iv = *dk + 8; - - /* Clean-up and exit. */ - Qc3DestroyAlgorithmContext(hctx.Alg_Context_Token, (char *) &ecnull); - return 0; -} - -static int -pbkdf2(LIBSSH2_SESSION *session, char **dk, const unsigned char *passphrase, - pkcs5params *pkcs5) -{ - size_t i; - size_t k; - int j; - int l; - uint32_t ni; - unsigned long long t; - char *mac; - char *buf; - _libssh2_os400qc3_crypto_ctx hctx; - - *dk = NULL; - t = ((unsigned long long) pkcs5->dklen + pkcs5->hashlen - 1) / - pkcs5->hashlen; - if(t > 0xFFFFFFFF) - return -1; - mac = alloca(pkcs5->hashlen); - if(!mac) - return -1; - - /* Allocate the derived key buffer. */ - l = t; - buf = LIBSSH2_ALLOC(session, l * pkcs5->hashlen); - if(!buf) - return -1; - *dk = buf; - - /* Create an HMAC context for our computations. */ - libssh2_os400qc3_hmac_init(&hctx, pkcs5->hash, pkcs5->hashlen, - (void *) passphrase, strlen(passphrase)); - - /* Process each hLen-size blocks. */ - for(i = 1; i <= l; i++) { - ni = htonl(i); - libssh2_os400qc3_hmac_update(&hctx, pkcs5->salt, pkcs5->saltlen); - libssh2_os400qc3_hmac_update(&hctx, (char *) &ni, sizeof ni); - libssh2_os400qc3_hmac_final(&hctx, mac); - memcpy(buf, mac, pkcs5->hashlen); - for(j = 1; j < pkcs5->itercount; j++) { - libssh2_os400qc3_hmac_update(&hctx, mac, pkcs5->hashlen); - libssh2_os400qc3_hmac_final(&hctx, mac); - for(k = 0; k < pkcs5->hashlen; k++) - buf[k] ^= mac[k]; - } - buf += pkcs5->hashlen; - } - - /* Computation done. Release HMAC context. */ - _libssh2_os400qc3_crypto_dtor(&hctx); - return 0; -} - -static int -parse_pkcs5_algorithm(LIBSSH2_SESSION *session, pkcs5params *pkcs5, - asn1Element *algid, pkcs5algo **algotable) -{ - asn1Element oid; - asn1Element param; - char *cp; - - cp = getASN1Element(&oid, algid->beg, algid->end); - if(!cp || *oid.header != ASN1_OBJ_ID) - return -1; - param.header = NULL; - if(cp < algid->end) - cp = getASN1Element(¶m, cp, algid->end); - if(cp != algid->end) - return -1; - for(; *algotable; algotable++) - if(!oidcmp(&oid, (*algotable)->oid)) - return (*(*algotable)->parse)(session, pkcs5, *algotable, - param.header? ¶m: NULL); - return -1; -} - -static int -parse_pbes2(LIBSSH2_SESSION *session, pkcs5params *pkcs5, - pkcs5algo *algo, asn1Element *param) -{ - asn1Element keyDerivationFunc; - asn1Element encryptionScheme; - char *cp; - - if(!param || *param->header != (ASN1_SEQ | ASN1_CONSTRUCTED)) - return -1; - cp = getASN1Element(&keyDerivationFunc, param->beg, param->end); - if(!cp || *keyDerivationFunc.header != (ASN1_SEQ | ASN1_CONSTRUCTED)) - return -1; - if(getASN1Element(&encryptionScheme, cp, param->end) != param->end || - *encryptionScheme.header != (ASN1_SEQ | ASN1_CONSTRUCTED)) - return -1; - if(parse_pkcs5_algorithm(session, pkcs5, &encryptionScheme, pbes2enctable)) - return -1; - if(parse_pkcs5_algorithm(session, pkcs5, &keyDerivationFunc, pbkdf2table)) - return -1; - return 0; -} - -static int -parse_pbkdf2(LIBSSH2_SESSION *session, pkcs5params *pkcs5, - pkcs5algo *algo, asn1Element *param) -{ - asn1Element salt; - asn1Element iterationCount; - asn1Element keyLength; - asn1Element prf; - unsigned long itercount; - char *cp; - - if(!param || *param->header != (ASN1_SEQ | ASN1_CONSTRUCTED)) - return -1; - cp = getASN1Element(&salt, param->beg, param->end); - /* otherSource not supported. */ - if(!cp || *salt.header != ASN1_OCTET_STRING) - return -1; - cp = getASN1Element(&iterationCount, cp, param->end); - if(!cp || *iterationCount.header != ASN1_INTEGER) - return -1; - keyLength.header = prf.header = NULL; - if(cp < param->end) { - cp = getASN1Element(&prf, cp, param->end); - if(!cp) - return -1; - if(*prf.header == ASN1_INTEGER) { - keyLength = prf; - prf.header = NULL; - if(cp < param->end) - cp = getASN1Element(&prf, cp, param->end); - } - if(cp != param->end) - return -1; - } - pkcs5->hash = algo->hash; - pkcs5->hashlen = algo->hashlen; - if(prf.header) { - if(*prf.header != (ASN1_SEQ | ASN1_CONSTRUCTED)) - return -1; - if(parse_pkcs5_algorithm(session, pkcs5, &prf, kdf2prftable)) - return -1; - } - pkcs5->saltlen = salt.end - salt.beg; - pkcs5->salt = salt.beg; - if(asn1getword(&iterationCount, &itercount) || - !itercount || itercount > 100000) - return -1; - pkcs5->itercount = itercount; - pkcs5->kdf = pbkdf2; - return 0; -} - -static int -parse_hmacWithSHA1(LIBSSH2_SESSION *session, pkcs5params *pkcs5, - pkcs5algo *algo, asn1Element *param) -{ - if(!param || *param->header != ASN1_NULL) - return -1; - pkcs5->hash = algo->hash; - pkcs5->hashlen = algo->hashlen; - return 0; -} - -static int -parse_iv(LIBSSH2_SESSION *session, pkcs5params *pkcs5, - pkcs5algo *algo, asn1Element *param) -{ - if(!param || *param->header != ASN1_OCTET_STRING || - param->end - param->beg != algo->ivlen) - return -1; - pkcs5->cipher = algo->cipher; - pkcs5->blocksize = algo->blocksize; - pkcs5->mode = algo->mode; - pkcs5->padopt = algo->padopt; - pkcs5->padchar = algo->padchar; - pkcs5->dklen = algo->keylen; - pkcs5->ivlen = algo->ivlen; - pkcs5->iv = param->beg; - return 0; -} - -static int -parse_rc2(LIBSSH2_SESSION *session, pkcs5params *pkcs5, - pkcs5algo *algo, asn1Element *param) -{ - asn1Element iv; - unsigned long effkeysize; - char *cp; - - if(!param || *param->header != (ASN1_SEQ | ASN1_CONSTRUCTED)) - return -1; - cp = getASN1Element(&iv, param->beg, param->end); - if(!cp) - return -1; - effkeysize = algo->effkeysize; - if(*iv.header == ASN1_INTEGER) { - if(asn1getword(&iv, &effkeysize) || effkeysize > 1024) - return -1; - - cp = getASN1Element(&iv, cp, param->end); - if(effkeysize < 256) - switch(effkeysize) { - case 160: - effkeysize = 40; - case 120: - effkeysize = 64; - case 58: - effkeysize = 128; - break; - default: - return -1; - } - } - if(effkeysize > 1024 || cp != param->end || - *iv.header != ASN1_OCTET_STRING || iv.end - iv.beg != algo->ivlen) - return -1; - pkcs5->cipher = algo->cipher; - pkcs5->blocksize = algo->blocksize; - pkcs5->mode = algo->mode; - pkcs5->padopt = algo->padopt; - pkcs5->padchar = algo->padchar; - pkcs5->ivlen = algo->ivlen; - pkcs5->iv = iv.beg; - pkcs5->effkeysize = effkeysize; - pkcs5->dklen = (effkeysize + 8 - 1) / 8; - return 0; -} - -static int -parse_pbes1(LIBSSH2_SESSION *session, pkcs5params *pkcs5, - pkcs5algo *algo, asn1Element *param) -{ - asn1Element salt; - asn1Element iterationCount; - unsigned long itercount; - char *cp; - - if(!param || *param->header != (ASN1_SEQ | ASN1_CONSTRUCTED)) - return -1; - - cp = getASN1Element(&salt, param->beg, param->end); - if(!cp || *salt.header != ASN1_OCTET_STRING || - salt.end - salt.beg != algo->saltlen) - return -1; - if(getASN1Element(&iterationCount, cp, param->end) != param->end || - *iterationCount.header != ASN1_INTEGER) - return -1; - if(asn1getword(&iterationCount, &itercount) || - !itercount || itercount > 100000) - return -1; - pkcs5->cipher = algo->cipher; - pkcs5->blocksize = algo->blocksize; - pkcs5->mode = algo->mode; - pkcs5->padopt = algo->padopt; - pkcs5->padchar = algo->padchar; - pkcs5->hash = algo->hash; - pkcs5->hashlen = algo->hashlen; - pkcs5->dklen = 16; - pkcs5->saltlen = algo->saltlen; - pkcs5->effkeysize = algo->effkeysize; - pkcs5->salt = salt.beg; - pkcs5->kdf = pbkdf1; - pkcs5->itercount = itercount; - return 0; -} - -static int -pkcs8kek(LIBSSH2_SESSION *session, _libssh2_os400qc3_crypto_ctx **ctx, - const unsigned char *data, unsigned int datalen, - const unsigned char *passphrase, asn1Element *privkeyinfo) -{ - asn1Element encprivkeyinfo; - asn1Element pkcs5alg; - pkcs5params pkcs5; - size_t pplen; - char *cp; - unsigned long t; - int i; - char *dk = NULL; - Qc3_Format_ALGD0200_T algd; - Qus_EC_t errcode; - - /* Determine if the PKCS#8 data is encrypted and, if so, set-up a - key encryption key and algorithm in context. - Return 1 if encrypted, 0, if not, -1 if error. */ - - *ctx = NULL; - privkeyinfo->beg = (char *) data; - privkeyinfo->end = privkeyinfo->beg + datalen; - - /* If no passphrase is given, it cannot be an encrypted key. */ - if(!passphrase || !*passphrase) - return 0; - - /* Parse PKCS#8 data, checking if ASN.1 format is PrivateKeyInfo or - EncryptedPrivateKeyInfo. */ - if(getASN1Element(&encprivkeyinfo, privkeyinfo->beg, privkeyinfo->end) != - (char *) data + datalen || - *encprivkeyinfo.header != (ASN1_SEQ | ASN1_CONSTRUCTED)) - return -1; - cp = getASN1Element(&pkcs5alg, encprivkeyinfo.beg, encprivkeyinfo.end); - if(!cp) - return -1; - - switch(*pkcs5alg.header) { - case ASN1_INTEGER: /* Version. */ - return 0; /* This is a PrivateKeyInfo --> not encrypted. */ - case ASN1_SEQ | ASN1_CONSTRUCTED: /* AlgorithIdentifier. */ - break; /* This is an EncryptedPrivateKeyInfo --> encrypted. */ - default: - return -1; /* Unrecognized: error. */ - } - - /* Get the encrypted key data. */ - if(getASN1Element(privkeyinfo, cp, encprivkeyinfo.end) != - encprivkeyinfo.end || *privkeyinfo->header != ASN1_OCTET_STRING) - return -1; - - /* PKCS#5: parse the PBES AlgorithmIdentifier and recursively get all - encryption parameters. */ - memset((char *) &pkcs5, 0, sizeof pkcs5); - if(parse_pkcs5_algorithm(session, &pkcs5, &pkcs5alg, pbestable)) - return -1; - - /* Compute the derived key. */ - if((*pkcs5.kdf)(session, &dk, passphrase, &pkcs5)) - return -1; - - /* Prepare the algorithm descriptor. */ - memset((char *) &algd, 0, sizeof algd); - algd.Block_Cipher_Alg = pkcs5.cipher; - algd.Block_Length = pkcs5.blocksize; - algd.Mode = pkcs5.mode; - algd.Pad_Option = pkcs5.padopt; - algd.Pad_Character = pkcs5.padchar; - algd.Effective_Key_Size = pkcs5.effkeysize; - memcpy(algd.Init_Vector, pkcs5.iv, pkcs5.ivlen); - - /* Create the key and algorithm context tokens. */ - *ctx = libssh2_init_crypto_ctx(NULL); - if(!*ctx) { - LIBSSH2_FREE(session, dk); - return -1; - } - libssh2_init_crypto_ctx(*ctx); - set_EC_length(errcode, sizeof errcode); - Qc3CreateKeyContext(dk, &pkcs5.dklen, binstring, &algd.Block_Cipher_Alg, - qc3clear, NULL, NULL, (*ctx)->key.Key_Context_Token, - (char *) &errcode); - LIBSSH2_FREE(session, dk); - if(errcode.Bytes_Available) { - free((char *) *ctx); - *ctx = NULL; - return -1; - } - - Qc3CreateAlgorithmContext((char *) &algd, Qc3_Alg_Block_Cipher, - (*ctx)->hash.Alg_Context_Token, &errcode); - if(errcode.Bytes_Available) { - Qc3DestroyKeyContext((*ctx)->key.Key_Context_Token, (char *) &ecnull); - free((char *) *ctx); - *ctx = NULL; - return -1; - } - return 1; /* Tell it's encrypted. */ -} - -static int -rsapkcs8privkey(LIBSSH2_SESSION *session, - const unsigned char *data, unsigned int datalen, - const unsigned char *passphrase, void *loadkeydata) -{ - libssh2_rsa_ctx *ctx = (libssh2_rsa_ctx *) loadkeydata; - char keyform = Qc3_Clear; - char *kek = NULL; - char *kea = NULL; - _libssh2_os400qc3_crypto_ctx *kekctx; - asn1Element pki; - int pkilen; - Qus_EC_t errcode; - - switch(pkcs8kek(session, &kekctx, data, datalen, passphrase, &pki)) { - case 1: - keyform = Qc3_Encrypted; - kek = kekctx->key.Key_Context_Token; - kea = kekctx->hash.Alg_Context_Token; - case 0: - break; - default: - return -1; - } - - set_EC_length(errcode, sizeof errcode); - pkilen = pki.end - pki.beg; - Qc3CreateKeyContext((unsigned char *) pki.beg, &pkilen, berstring, - rsaprivate, &keyform, kek, kea, - ctx->key.Key_Context_Token, (char *) &errcode); - if(errcode.Bytes_Available) { - if(kekctx) - _libssh2_os400qc3_crypto_dtor(kekctx); - return -1; - } - ctx->kek = kekctx; - return 0; -} - -static char * -storewithlength(char *p, const char *data, int length) -{ - _libssh2_htonu32(p, length); - if(length) - memcpy(p + 4, data, length); - return p + 4 + length; -} - -static int -sshrsapubkey(LIBSSH2_SESSION *session, char **sshpubkey, - asn1Element *params, asn1Element *key, const char *method) -{ - int methlen = strlen(method); - asn1Element keyseq; - asn1Element m; - asn1Element e; - int len; - char *cp; - - if(getASN1Element(&keyseq, key->beg + 1, key->end) != key->end || - *keyseq.header != (ASN1_SEQ | ASN1_CONSTRUCTED)) - return -1; - if(!getASN1Element(&m, keyseq.beg, keyseq.end) || - *m.header != ASN1_INTEGER) - return -1; - if(getASN1Element(&e, m.end, keyseq.end) != keyseq.end || - *e.header != ASN1_INTEGER) - return -1; - len = 4 + methlen + 4 + (e.end - e.beg) + 4 + (m.end - m.beg); - cp = LIBSSH2_ALLOC(session, len); - if(!cp) - return -1; - *sshpubkey = cp; - cp = storewithlength(cp, method, methlen); - cp = storewithlength(cp, e.beg, e.end - e.beg); - cp = storewithlength(cp, m.beg, m.end - m.beg); - return len; -} - -static int -rsapkcs8pubkey(LIBSSH2_SESSION *session, - const unsigned char *data, unsigned int datalen, - const unsigned char *passphrase, void *loadkeydata) -{ - loadpubkeydata *p = (loadpubkeydata *) loadkeydata; - char *buf; - int len; - char *cp; - int i; - char keyform = Qc3_Clear; - char *kek = NULL; - char *kea = NULL; - _libssh2_os400qc3_crypto_ctx *kekctx; - asn1Element subjpubkeyinfo; - asn1Element algorithmid; - asn1Element algorithm; - asn1Element subjpubkey; - asn1Element parameters; - asn1Element pki; - int pkilen; - Qus_EC_t errcode; - - buf = alloca(datalen); - if(!buf) - return -1; - - switch(pkcs8kek(session, &kekctx, data, datalen, passphrase, &pki)) { - case 1: - keyform = Qc3_Encrypted; - kek = kekctx->key.Key_Context_Token; - kea = kekctx->hash.Alg_Context_Token; - case 0: - break; - default: - return -1; - } - - set_EC_length(errcode, sizeof errcode); - pkilen = pki.end - pki.beg; - Qc3ExtractPublicKey(pki.beg, &pkilen, berstring, &keyform, - kek, kea, buf, (int *) &datalen, &len, &errcode); - _libssh2_os400qc3_crypto_dtor(kekctx); - if(errcode.Bytes_Available) - return -1; - /* Get the algorithm OID and key data from SubjectPublicKeyInfo. */ - if(getASN1Element(&subjpubkeyinfo, buf, buf + len) != buf + len || - *subjpubkeyinfo.header != (ASN1_SEQ | ASN1_CONSTRUCTED)) - return -1; - cp = getASN1Element(&algorithmid, subjpubkeyinfo.beg, subjpubkeyinfo.end); - if(!cp || *algorithmid.header != (ASN1_SEQ | ASN1_CONSTRUCTED)) - return -1; - if(!getASN1Element(&algorithm, algorithmid.beg, algorithmid.end) || - *algorithm.header != ASN1_OBJ_ID) - return -1; - if(getASN1Element(&subjpubkey, cp, subjpubkeyinfo.end) != - subjpubkeyinfo.end || *subjpubkey.header != ASN1_BIT_STRING) - return -1; - /* Check for supported algorithm. */ - for(i = 0; pka[i].oid; i++) - if(!oidcmp(&algorithm, pka[i].oid)) { - len = (*pka[i].sshpubkey)(session, &p->data, &algorithmid, - &subjpubkey, pka[i].method); - if(len < 0) - return -1; - p->length = len; - p->method = pka[i].method; - return 0; - } - return -1; /* Algorithm not supported. */ -} - -static int -pkcs1topkcs8(LIBSSH2_SESSION *session, - const unsigned char **data8, unsigned int *datalen8, - const unsigned char *data1, unsigned int datalen1) -{ - asn1Element *prvk; - asn1Element *pkcs8; - unsigned char *data; - - *data8 = NULL; - *datalen8 = 0; - if(datalen1 < 2) - return -1; - prvk = asn1_new_from_bytes(data1, datalen1); - if(!prvk) - return -1; - pkcs8 = rsaprivatekeyinfo(prvk); - asn1delete(prvk); - if(!prvk) { - asn1delete(pkcs8); - pkcs8 = NULL; - } - if(!pkcs8) - return -1; - data = (unsigned char *) LIBSSH2_ALLOC(session, - pkcs8->end - pkcs8->header); - if(!data) { - asn1delete(pkcs8); - return -1; - } - *data8 = data; - *datalen8 = pkcs8->end - pkcs8->header; - memcpy((char *) data, (char *) pkcs8->header, *datalen8); - asn1delete(pkcs8); - return 0; -} - -static int -rsapkcs1privkey(LIBSSH2_SESSION *session, - const unsigned char *data, unsigned int datalen, - const unsigned char *passphrase, void *loadkeydata) -{ - const unsigned char *data8; - unsigned int datalen8; - int ret; - - if(pkcs1topkcs8(session, &data8, &datalen8, data, datalen)) - return -1; - ret = rsapkcs8privkey(session, data8, datalen8, passphrase, loadkeydata); - LIBSSH2_FREE(session, (char *) data8); - return ret; -} - -static int -rsapkcs1pubkey(LIBSSH2_SESSION *session, - const unsigned char *data, unsigned int datalen, - const unsigned char *passphrase, void *loadkeydata) -{ - const unsigned char *data8; - unsigned int datalen8; - int ret; - - if(pkcs1topkcs8(session, &data8, &datalen8, data, datalen)) - return -1; - ret = rsapkcs8pubkey(session, data8, datalen8, passphrase, loadkeydata); - LIBSSH2_FREE(session, (char *) data8); - return ret; -} - -static int -try_pem_load(LIBSSH2_SESSION *session, FILE *fp, - const unsigned char *passphrase, - const char *header, const char *trailer, - loadkeyproc proc, void *loadkeydata) -{ - unsigned char *data = NULL; - unsigned int datalen = 0; - int c; - int ret; - - fseek(fp, 0L, SEEK_SET); - for(;;) { - ret = _libssh2_pem_parse(session, header, trailer, - passphrase, - fp, &data, &datalen); - - if(!ret) { - ret = (*proc)(session, data, datalen, passphrase, loadkeydata); - if(!ret) - return 0; - } - - if(data) { - LIBSSH2_FREE(session, data); - data = NULL; - } - c = getc(fp); - - if(c == EOF) - break; - - ungetc(c, fp); - } - - return -1; -} - -static int -load_rsa_private_file(LIBSSH2_SESSION *session, const char *filename, - unsigned const char *passphrase, - loadkeyproc proc1, loadkeyproc proc8, void *loadkeydata) -{ - FILE *fp = fopen(filename, fopenrmode); - unsigned char *data = NULL; - size_t datalen = 0; - int ret; - long filesize; - - if(!fp) - return -1; - - /* Try with "ENCRYPTED PRIVATE KEY" PEM armor. - --> PKCS#8 EncryptedPrivateKeyInfo */ - ret = try_pem_load(session, fp, passphrase, beginencprivkeyhdr, - endencprivkeyhdr, proc8, loadkeydata); - - /* Try with "PRIVATE KEY" PEM armor. - --> PKCS#8 PrivateKeyInfo or EncryptedPrivateKeyInfo */ - if(ret) - ret = try_pem_load(session, fp, passphrase, beginprivkeyhdr, - endprivkeyhdr, proc8, loadkeydata); - - /* Try with "RSA PRIVATE KEY" PEM armor. - --> PKCS#1 RSAPrivateKey */ - if(ret) - ret = try_pem_load(session, fp, passphrase, beginrsaprivkeyhdr, - endrsaprivkeyhdr, proc1, loadkeydata); - fclose(fp); - - if(ret) { - /* Try DER encoding. */ - fp = fopen(filename, fopenrbmode); - fseek(fp, 0L, SEEK_END); - filesize = ftell(fp); - - if(filesize <= 32768) { /* Limit to a reasonable size. */ - datalen = filesize; - data = (unsigned char *) alloca(datalen); - if(data) { - fseek(fp, 0L, SEEK_SET); - fread(data, datalen, 1, fp); - - /* Try as PKCS#8 DER data. - --> PKCS#8 PrivateKeyInfo or EncryptedPrivateKeyInfo */ - ret = (*proc8)(session, data, datalen, passphrase, - loadkeydata); - - /* Try as PKCS#1 DER data. - --> PKCS#1 RSAPrivateKey */ - if(ret) - ret = (*proc1)(session, data, datalen, passphrase, - loadkeydata); - } - } - fclose(fp); - } - - return ret; -} - -int -_libssh2_rsa_new_private(libssh2_rsa_ctx **rsa, LIBSSH2_SESSION *session, - const char *filename, unsigned const char *passphrase) -{ - libssh2_rsa_ctx *ctx = libssh2_init_crypto_ctx(NULL); - int ret; - Qc3_Format_ALGD0400_T algd; - Qus_EC_t errcode; - - if(!ctx) - return -1; - ret = load_rsa_private_file(session, filename, passphrase, - rsapkcs1privkey, rsapkcs8privkey, - (void *) ctx); - if(!ret) { - /* Create the algorithm context. */ - algd.Public_Key_Alg = Qc3_RSA; - algd.PKA_Block_Format = Qc3_PKCS1_01; - memset(algd.Reserved, 0, sizeof algd.Reserved); - algd.Signing_Hash_Alg = Qc3_SHA1; - set_EC_length(errcode, sizeof errcode); - Qc3CreateAlgorithmContext((char *) &algd, Qc3_Alg_Public_Key, - ctx->hash.Alg_Context_Token, &errcode); - if(errcode.Bytes_Available) - ret = -1; - } - if(ret) { - _libssh2_os400qc3_crypto_dtor(ctx); - ctx = NULL; - } - *rsa = ctx; - return ret; -} - -int -_libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session, - unsigned char **method, size_t *method_len, - unsigned char **pubkeydata, size_t *pubkeydata_len, - const char *privatekey, const char *passphrase) - -{ - loadpubkeydata p; - int ret; - - *method = NULL; - *method_len = 0; - *pubkeydata = NULL; - *pubkeydata_len = 0; - - ret = load_rsa_private_file(session, privatekey, passphrase, - rsapkcs1pubkey, rsapkcs8pubkey, (void *) &p); - if(!ret) { - *method_len = strlen(p.method); - *method = LIBSSH2_ALLOC(session, *method_len); - if(*method) - memcpy((char *) *method, p.method, *method_len); - else - ret = -1; - } - - if(ret) { - if(*method) - LIBSSH2_FREE(session, *method); - if(p.data) - LIBSSH2_FREE(session, (void *) p.data); - *method = NULL; - *method_len = 0; - } - else { - *pubkeydata = (unsigned char *) p.data; - *pubkeydata_len = p.length; - } - - return ret; -} - -int -_libssh2_rsa_new_private_frommemory(libssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - const char *filedata, - size_t filedata_len, - unsigned const char *passphrase) -{ - libssh2_rsa_ctx *ctx = libssh2_init_crypto_ctx(NULL); - unsigned char *data = NULL; - unsigned int datalen = 0; - int ret; - Qc3_Format_ALGD0400_T algd; - Qus_EC_t errcode; - - if(!ctx) - return -1; - - /* Try with "ENCRYPTED PRIVATE KEY" PEM armor. - --> PKCS#8 EncryptedPrivateKeyInfo */ - ret = _libssh2_pem_parse_memory(session, - beginencprivkeyhdr, endencprivkeyhdr, - filedata, filedata_len, &data, &datalen); - - /* Try with "PRIVATE KEY" PEM armor. - --> PKCS#8 PrivateKeyInfo or EncryptedPrivateKeyInfo */ - if(ret) - ret = _libssh2_pem_parse_memory(session, - beginprivkeyhdr, endprivkeyhdr, - filedata, filedata_len, - &data, &datalen); - - if(!ret) { - /* Process PKCS#8. */ - ret = rsapkcs8privkey(session, - data, datalen, passphrase, (void *) &ctx); - } - else { - /* Try with "RSA PRIVATE KEY" PEM armor. - --> PKCS#1 RSAPrivateKey */ - ret = _libssh2_pem_parse_memory(session, - beginrsaprivkeyhdr, endrsaprivkeyhdr, - filedata, filedata_len, - &data, &datalen); - if(!ret) - ret = rsapkcs1privkey(session, - data, datalen, passphrase, (void *) &ctx); - } - - if(ret) { - /* Try as PKCS#8 DER data. - --> PKCS#8 PrivateKeyInfo or EncryptedPrivateKeyInfo */ - ret = rsapkcs8privkey(session, filedata, filedata_len, - passphrase, (void *) &ctx); - - /* Try as PKCS#1 DER data. - --> PKCS#1 RSAPrivateKey */ - if(ret) - ret = rsapkcs1privkey(session, filedata, filedata_len, - passphrase, (void *) &ctx); - } - - if(data) - LIBSSH2_FREE(session, data); - - if(!ret) { - /* Create the algorithm context. */ - algd.Public_Key_Alg = Qc3_RSA; - algd.PKA_Block_Format = Qc3_PKCS1_01; - memset(algd.Reserved, 0, sizeof algd.Reserved); - algd.Signing_Hash_Alg = Qc3_SHA1; - set_EC_length(errcode, sizeof errcode); - Qc3CreateAlgorithmContext((char *) &algd, Qc3_Alg_Public_Key, - ctx->hash.Alg_Context_Token, &errcode); - if(errcode.Bytes_Available) - ret = -1; - } - - if(ret) { - _libssh2_os400qc3_crypto_dtor(ctx); - ctx = NULL; - } - - *rsa = ctx; - return ret; -} - -int -_libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session, - unsigned char **method, size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - const char *privatekeydata, - size_t privatekeydata_len, - const char *passphrase) -{ - loadpubkeydata p; - unsigned char *data = NULL; - unsigned int datalen = 0; - const char *meth; - int ret; - - *method = NULL; - *method_len = 0; - *pubkeydata = NULL; - *pubkeydata_len = 0; - - /* Try with "ENCRYPTED PRIVATE KEY" PEM armor. - --> PKCS#8 EncryptedPrivateKeyInfo */ - ret = _libssh2_pem_parse_memory(session, - beginencprivkeyhdr, endencprivkeyhdr, - privatekeydata, privatekeydata_len, - &data, &datalen); - - /* Try with "PRIVATE KEY" PEM armor. - --> PKCS#8 PrivateKeyInfo or EncryptedPrivateKeyInfo */ - if(ret) - ret = _libssh2_pem_parse_memory(session, - beginprivkeyhdr, endprivkeyhdr, - privatekeydata, privatekeydata_len, - &data, &datalen); - - if(!ret) { - /* Process PKCS#8. */ - ret = rsapkcs8pubkey(session, - data, datalen, passphrase, (void *) &p); - } - else { - /* Try with "RSA PRIVATE KEY" PEM armor. - --> PKCS#1 RSAPrivateKey */ - ret = _libssh2_pem_parse_memory(session, - beginrsaprivkeyhdr, endrsaprivkeyhdr, - privatekeydata, privatekeydata_len, - &data, &datalen); - if(!ret) - ret = rsapkcs1pubkey(session, - data, datalen, passphrase, (void *) &p); - } - - if(ret) { - /* Try as PKCS#8 DER data. - --> PKCS#8 PrivateKeyInfo or EncryptedPrivateKeyInfo */ - ret = rsapkcs8pubkey(session, privatekeydata, privatekeydata_len, - passphrase, (void *) &p); - - /* Try as PKCS#1 DER data. - --> PKCS#1 RSAPrivateKey */ - if(ret) - ret = rsapkcs1pubkey(session, privatekeydata, privatekeydata_len, - passphrase, (void *) &p); - } - - if(data) - LIBSSH2_FREE(session, data); - - if(!ret) { - *method_len = strlen(p.method); - *method = LIBSSH2_ALLOC(session, *method_len); - if(*method) - memcpy((char *) *method, p.method, *method_len); - else - ret = -1; - } - if(ret) { - if(*method) - LIBSSH2_FREE(session, *method); - if(p.data) - LIBSSH2_FREE(session, (void *) p.data); - *method = NULL; - *method_len = 0; - } - else { - *pubkeydata = (unsigned char *) p.data; - *pubkeydata_len = p.length; - } - - return ret; -} - -int -_libssh2_rsa_sha1_verify(libssh2_rsa_ctx *rsa, - const unsigned char *sig, unsigned long sig_len, - const unsigned char *m, unsigned long m_len) -{ - Qus_EC_t errcode; - int slen = sig_len; - int mlen = m_len; - - set_EC_length(errcode, sizeof errcode); - Qc3VerifySignature((char *) sig, &slen, (char *) m, &mlen, Qc3_Data, - rsa->hash.Alg_Context_Token, Qc3_Alg_Token, - rsa->key.Key_Context_Token, Qc3_Key_Token, anycsp, - NULL, (char *) &errcode); - return errcode.Bytes_Available? -1: 0; -} - -int -_libssh2_os400qc3_rsa_sha1_signv(LIBSSH2_SESSION *session, - unsigned char **signature, - size_t *signature_len, - int veccount, - const struct iovec vector[], - libssh2_rsa_ctx *ctx) -{ - Qus_EC_t errcode; - int siglen; - unsigned char *sig; - char sigbuf[8192]; - int sigbufsize = sizeof sigbuf; - - ctx->hash.Final_Op_Flag = Qc3_Final; - set_EC_length(errcode, sizeof errcode); - Qc3CalculateSignature((char *) vector, &veccount, Qc3_Array, - (char *) &ctx->hash, Qc3_Alg_Token, - (char *) &ctx->key, Qc3_Key_Token, - anycsp, NULL, sigbuf, &sigbufsize, &siglen, - (char *) &errcode); - ctx->hash.Final_Op_Flag = Qc3_Continue; - if(errcode.Bytes_Available) - return -1; - sig = LIBSSH2_ALLOC(session, siglen); - if(!sig) - return -1; - memcpy((char *) sig, sigbuf, siglen); - *signature = sig; - *signature_len = siglen; - return 0; -} - -#endif /* LIBSSH2_OS400QC3 */ - -/* vim: set expandtab ts=4 sw=4: */ diff --git a/libssh2/packet.c b/libssh2/packet.c deleted file mode 100644 index 9897f77..0000000 --- a/libssh2/packet.c +++ /dev/null @@ -1,1336 +0,0 @@ -/* Copyright (c) 2004-2007, Sara Golemon - * Copyright (c) 2005,2006 Mikhail Gusarov - * Copyright (c) 2009-2014 by Daniel Stenberg - * Copyright (c) 2010 Simon Josefsson - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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 "libssh2_priv.h" -#include -#include - -#ifdef HAVE_UNISTD_H -#include -#endif - -#ifdef HAVE_SYS_TIME_H -#include -#endif - -#ifdef HAVE_INTTYPES_H -#include -#endif - -/* Needed for struct iovec on some platforms */ -#ifdef HAVE_SYS_UIO_H -#include -#endif - -#include - -#include "transport.h" -#include "channel.h" -#include "packet.h" - -/* - * libssh2_packet_queue_listener - * - * Queue a connection request for a listener - */ -static inline int -packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data, - unsigned long datalen, - packet_queue_listener_state_t *listen_state) -{ - /* - * Look for a matching listener - */ - /* 17 = packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */ - unsigned long packet_len = 17 + (sizeof(FwdNotReq) - 1); - unsigned char *p; - LIBSSH2_LISTENER *listn = _libssh2_list_first(&session->listeners); - char failure_code = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED; - int rc; - - if(listen_state->state == libssh2_NB_state_idle) { - unsigned long offset = (sizeof("forwarded-tcpip") - 1) + 5; - size_t temp_len = 0; - struct string_buf buf; - buf.data = data; - buf.dataptr = buf.data; - buf.len = datalen; - - if(datalen < offset) { - return _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, - "Unexpected packet size"); - } - - buf.dataptr += offset; - - if(_libssh2_get_u32(&buf, &(listen_state->sender_channel))) { - return _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "Data too short extracting channel"); - } - if(_libssh2_get_u32(&buf, &(listen_state->initial_window_size))) { - return _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "Data too short extracting window size"); - } - if(_libssh2_get_u32(&buf, &(listen_state->packet_size))) { - return _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "Data too short extracting packet"); - } - if(_libssh2_get_string(&buf, &(listen_state->host), &temp_len)) { - return _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "Data too short extracting host"); - } - listen_state->host_len = (uint32_t)temp_len; - - if(_libssh2_get_u32(&buf, &(listen_state->port))) { - return _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "Data too short extracting port"); - } - if(_libssh2_get_string(&buf, &(listen_state->shost), &temp_len)) { - return _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "Data too short extracting shost"); - } - listen_state->shost_len = (uint32_t)temp_len; - - if(_libssh2_get_u32(&buf, &(listen_state->sport))) { - return _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "Data too short extracting sport"); - } - - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Remote received connection from %s:%ld to %s:%ld", - listen_state->shost, listen_state->sport, - listen_state->host, listen_state->port); - - listen_state->state = libssh2_NB_state_allocated; - } - - if(listen_state->state != libssh2_NB_state_sent) { - while(listn) { - if((listn->port == (int) listen_state->port) && - (strlen(listn->host) == listen_state->host_len) && - (memcmp (listn->host, listen_state->host, - listen_state->host_len) == 0)) { - /* This is our listener */ - LIBSSH2_CHANNEL *channel = NULL; - listen_state->channel = NULL; - - if(listen_state->state == libssh2_NB_state_allocated) { - if(listn->queue_maxsize && - (listn->queue_maxsize <= listn->queue_size)) { - /* Queue is full */ - failure_code = SSH_OPEN_RESOURCE_SHORTAGE; - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Listener queue full, ignoring"); - listen_state->state = libssh2_NB_state_sent; - break; - } - - channel = LIBSSH2_CALLOC(session, sizeof(LIBSSH2_CHANNEL)); - if(!channel) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate a channel for " - "new connection"); - failure_code = SSH_OPEN_RESOURCE_SHORTAGE; - listen_state->state = libssh2_NB_state_sent; - break; - } - listen_state->channel = channel; - - channel->session = session; - channel->channel_type_len = sizeof("forwarded-tcpip") - 1; - channel->channel_type = LIBSSH2_ALLOC(session, - channel-> - channel_type_len + - 1); - if(!channel->channel_type) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate a channel for new" - " connection"); - LIBSSH2_FREE(session, channel); - failure_code = SSH_OPEN_RESOURCE_SHORTAGE; - listen_state->state = libssh2_NB_state_sent; - break; - } - memcpy(channel->channel_type, "forwarded-tcpip", - channel->channel_type_len + 1); - - channel->remote.id = listen_state->sender_channel; - channel->remote.window_size_initial = - LIBSSH2_CHANNEL_WINDOW_DEFAULT; - channel->remote.window_size = - LIBSSH2_CHANNEL_WINDOW_DEFAULT; - channel->remote.packet_size = - LIBSSH2_CHANNEL_PACKET_DEFAULT; - - channel->local.id = _libssh2_channel_nextid(session); - channel->local.window_size_initial = - listen_state->initial_window_size; - channel->local.window_size = - listen_state->initial_window_size; - channel->local.packet_size = listen_state->packet_size; - - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Connection queued: channel %lu/%lu " - "win %lu/%lu packet %lu/%lu", - channel->local.id, channel->remote.id, - channel->local.window_size, - channel->remote.window_size, - channel->local.packet_size, - channel->remote.packet_size); - - p = listen_state->packet; - *(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION; - _libssh2_store_u32(&p, channel->remote.id); - _libssh2_store_u32(&p, channel->local.id); - _libssh2_store_u32(&p, - channel->remote.window_size_initial); - _libssh2_store_u32(&p, channel->remote.packet_size); - - listen_state->state = libssh2_NB_state_created; - } - - if(listen_state->state == libssh2_NB_state_created) { - rc = _libssh2_transport_send(session, listen_state->packet, - 17, NULL, 0); - if(rc == LIBSSH2_ERROR_EAGAIN) - return rc; - else if(rc) { - listen_state->state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, - "Unable to send channel " - "open confirmation"); - } - - /* Link the channel into the end of the queue list */ - if(listen_state->channel) { - _libssh2_list_add(&listn->queue, - &listen_state->channel->node); - listn->queue_size++; - } - - listen_state->state = libssh2_NB_state_idle; - return 0; - } - } - - listn = _libssh2_list_next(&listn->node); - } - - listen_state->state = libssh2_NB_state_sent; - } - - /* We're not listening to you */ - p = listen_state->packet; - *(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE; - _libssh2_store_u32(&p, listen_state->sender_channel); - _libssh2_store_u32(&p, failure_code); - _libssh2_store_str(&p, FwdNotReq, sizeof(FwdNotReq) - 1); - _libssh2_htonu32(p, 0); - - rc = _libssh2_transport_send(session, listen_state->packet, - packet_len, NULL, 0); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc) { - listen_state->state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, "Unable to send open failure"); - - } - listen_state->state = libssh2_NB_state_idle; - return 0; -} - -/* - * packet_x11_open - * - * Accept a forwarded X11 connection - */ -static inline int -packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data, - unsigned long datalen, - packet_x11_open_state_t *x11open_state) -{ - int failure_code = SSH_OPEN_CONNECT_FAILED; - /* 17 = packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */ - unsigned long packet_len = 17 + (sizeof(X11FwdUnAvil) - 1); - unsigned char *p; - LIBSSH2_CHANNEL *channel = x11open_state->channel; - int rc; - - if(x11open_state->state == libssh2_NB_state_idle) { - - unsigned long offset = (sizeof("x11") - 1) + 5; - size_t temp_len = 0; - struct string_buf buf; - buf.data = data; - buf.dataptr = buf.data; - buf.len = datalen; - - if(datalen < offset) { - _libssh2_error(session, LIBSSH2_ERROR_INVAL, - "unexpected data length"); - failure_code = SSH_OPEN_CONNECT_FAILED; - goto x11_exit; - } - - buf.dataptr += offset; - - if(_libssh2_get_u32(&buf, &(x11open_state->sender_channel))) { - _libssh2_error(session, LIBSSH2_ERROR_INVAL, - "unexpected sender channel size"); - failure_code = SSH_OPEN_CONNECT_FAILED; - goto x11_exit; - } - if(_libssh2_get_u32(&buf, &(x11open_state->initial_window_size))) { - _libssh2_error(session, LIBSSH2_ERROR_INVAL, - "unexpected window size"); - failure_code = SSH_OPEN_CONNECT_FAILED; - goto x11_exit; - } - if(_libssh2_get_u32(&buf, &(x11open_state->packet_size))) { - _libssh2_error(session, LIBSSH2_ERROR_INVAL, - "unexpected window size"); - failure_code = SSH_OPEN_CONNECT_FAILED; - goto x11_exit; - } - if(_libssh2_get_string(&buf, &(x11open_state->shost), &temp_len)) { - _libssh2_error(session, LIBSSH2_ERROR_INVAL, - "unexpected host size"); - failure_code = SSH_OPEN_CONNECT_FAILED; - goto x11_exit; - } - x11open_state->shost_len = (uint32_t)temp_len; - - if(_libssh2_get_u32(&buf, &(x11open_state->sport))) { - _libssh2_error(session, LIBSSH2_ERROR_INVAL, - "unexpected port size"); - failure_code = SSH_OPEN_CONNECT_FAILED; - goto x11_exit; - } - - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "X11 Connection Received from %s:%ld on channel %lu", - x11open_state->shost, x11open_state->sport, - x11open_state->sender_channel); - - x11open_state->state = libssh2_NB_state_allocated; - } - - if(session->x11) { - if(x11open_state->state == libssh2_NB_state_allocated) { - channel = LIBSSH2_CALLOC(session, sizeof(LIBSSH2_CHANNEL)); - if(!channel) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "allocate a channel for new connection"); - failure_code = SSH_OPEN_RESOURCE_SHORTAGE; - goto x11_exit; - } - - channel->session = session; - channel->channel_type_len = sizeof("x11") - 1; - channel->channel_type = LIBSSH2_ALLOC(session, - channel->channel_type_len + - 1); - if(!channel->channel_type) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "allocate a channel for new connection"); - LIBSSH2_FREE(session, channel); - failure_code = SSH_OPEN_RESOURCE_SHORTAGE; - goto x11_exit; - } - memcpy(channel->channel_type, "x11", - channel->channel_type_len + 1); - - channel->remote.id = x11open_state->sender_channel; - channel->remote.window_size_initial = - LIBSSH2_CHANNEL_WINDOW_DEFAULT; - channel->remote.window_size = LIBSSH2_CHANNEL_WINDOW_DEFAULT; - channel->remote.packet_size = LIBSSH2_CHANNEL_PACKET_DEFAULT; - - channel->local.id = _libssh2_channel_nextid(session); - channel->local.window_size_initial = - x11open_state->initial_window_size; - channel->local.window_size = x11open_state->initial_window_size; - channel->local.packet_size = x11open_state->packet_size; - - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "X11 Connection established: channel %lu/%lu " - "win %lu/%lu packet %lu/%lu", - channel->local.id, channel->remote.id, - channel->local.window_size, - channel->remote.window_size, - channel->local.packet_size, - channel->remote.packet_size); - p = x11open_state->packet; - *(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION; - _libssh2_store_u32(&p, channel->remote.id); - _libssh2_store_u32(&p, channel->local.id); - _libssh2_store_u32(&p, channel->remote.window_size_initial); - _libssh2_store_u32(&p, channel->remote.packet_size); - - x11open_state->state = libssh2_NB_state_created; - } - - if(x11open_state->state == libssh2_NB_state_created) { - rc = _libssh2_transport_send(session, x11open_state->packet, 17, - NULL, 0); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc) { - x11open_state->state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send channel open " - "confirmation"); - } - - /* Link the channel into the session */ - _libssh2_list_add(&session->channels, &channel->node); - - /* - * Pass control to the callback, they may turn right around and - * free the channel, or actually use it - */ - LIBSSH2_X11_OPEN(channel, (char *)x11open_state->shost, - x11open_state->sport); - - x11open_state->state = libssh2_NB_state_idle; - return 0; - } - } - else - failure_code = SSH_OPEN_RESOURCE_SHORTAGE; - /* fall-trough */ - x11_exit: - p = x11open_state->packet; - *(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE; - _libssh2_store_u32(&p, x11open_state->sender_channel); - _libssh2_store_u32(&p, failure_code); - _libssh2_store_str(&p, X11FwdUnAvil, sizeof(X11FwdUnAvil) - 1); - _libssh2_htonu32(p, 0); - - rc = _libssh2_transport_send(session, x11open_state->packet, packet_len, - NULL, 0); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc) { - x11open_state->state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, "Unable to send open failure"); - } - x11open_state->state = libssh2_NB_state_idle; - return 0; -} - -/* - * _libssh2_packet_add - * - * Create a new packet and attach it to the brigade. Called from the transport - * layer when it has received a packet. - * - * The input pointer 'data' is pointing to allocated data that this function - * is asked to deal with so on failure OR success, it must be freed fine. - * The only exception is when the return code is LIBSSH2_ERROR_EAGAIN. - * - * This function will always be called with 'datalen' greater than zero. - */ -int -_libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, - size_t datalen, int macstate) -{ - int rc = 0; - unsigned char *message = NULL; - unsigned char *language = NULL; - size_t message_len = 0; - size_t language_len = 0; - LIBSSH2_CHANNEL *channelp = NULL; - size_t data_head = 0; - unsigned char msg = data[0]; - - switch(session->packAdd_state) { - case libssh2_NB_state_idle: - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "Packet type %d received, length=%d", - (int) msg, (int) datalen); - - if((macstate == LIBSSH2_MAC_INVALID) && - (!session->macerror || - LIBSSH2_MACERROR(session, (char *) data, datalen))) { - /* Bad MAC input, but no callback set or non-zero return from the - callback */ - - LIBSSH2_FREE(session, data); - return _libssh2_error(session, LIBSSH2_ERROR_INVALID_MAC, - "Invalid MAC received"); - } - session->packAdd_state = libssh2_NB_state_allocated; - break; - case libssh2_NB_state_jump1: - goto libssh2_packet_add_jump_point1; - case libssh2_NB_state_jump2: - goto libssh2_packet_add_jump_point2; - case libssh2_NB_state_jump3: - goto libssh2_packet_add_jump_point3; - case libssh2_NB_state_jump4: - goto libssh2_packet_add_jump_point4; - case libssh2_NB_state_jump5: - goto libssh2_packet_add_jump_point5; - default: /* nothing to do */ - break; - } - - if(session->packAdd_state == libssh2_NB_state_allocated) { - /* A couple exceptions to the packet adding rule: */ - switch(msg) { - - /* - byte SSH_MSG_DISCONNECT - uint32 reason code - string description in ISO-10646 UTF-8 encoding [RFC3629] - string language tag [RFC3066] - */ - - case SSH_MSG_DISCONNECT: - if(datalen >= 5) { - uint32_t reason = 0; - struct string_buf buf; - buf.data = (unsigned char *)data; - buf.dataptr = buf.data; - buf.len = datalen; - buf.dataptr++; /* advance past type */ - - _libssh2_get_u32(&buf, &reason); - _libssh2_get_string(&buf, &message, &message_len); - _libssh2_get_string(&buf, &language, &language_len); - - if(session->ssh_msg_disconnect) { - LIBSSH2_DISCONNECT(session, reason, (const char *)message, - message_len, (const char *)language, - language_len); - } - - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "Disconnect(%d): %s(%s)", reason, - message, language); - } - - LIBSSH2_FREE(session, data); - session->socket_state = LIBSSH2_SOCKET_DISCONNECTED; - session->packAdd_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_DISCONNECT, - "socket disconnect"); - /* - byte SSH_MSG_IGNORE - string data - */ - - case SSH_MSG_IGNORE: - if(datalen >= 2) { - if(session->ssh_msg_ignore) { - LIBSSH2_IGNORE(session, (char *) data + 1, datalen - 1); - } - } - else if(session->ssh_msg_ignore) { - LIBSSH2_IGNORE(session, "", 0); - } - LIBSSH2_FREE(session, data); - session->packAdd_state = libssh2_NB_state_idle; - return 0; - - /* - byte SSH_MSG_DEBUG - boolean always_display - string message in ISO-10646 UTF-8 encoding [RFC3629] - string language tag [RFC3066] - */ - - case SSH_MSG_DEBUG: - if(datalen >= 2) { - int always_display = data[1]; - - if(datalen >= 6) { - struct string_buf buf; - buf.data = (unsigned char *)data; - buf.dataptr = buf.data; - buf.len = datalen; - buf.dataptr += 2; /* advance past type & always display */ - - _libssh2_get_string(&buf, &message, &message_len); - _libssh2_get_string(&buf, &language, &language_len); - } - - if(session->ssh_msg_debug) { - LIBSSH2_DEBUG(session, always_display, - (const char *)message, - message_len, (const char *)language, - language_len); - } - } - - /* - * _libssh2_debug will actually truncate this for us so - * that it's not an inordinate about of data - */ - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "Debug Packet: %s", message); - LIBSSH2_FREE(session, data); - session->packAdd_state = libssh2_NB_state_idle; - return 0; - - /* - byte SSH_MSG_GLOBAL_REQUEST - string request name in US-ASCII only - boolean want reply - .... request-specific data follows - */ - - case SSH_MSG_GLOBAL_REQUEST: - if(datalen >= 5) { - uint32_t len = 0; - unsigned char want_reply = 0; - len = _libssh2_ntohu32(data + 1); - if((len <= (UINT_MAX - 6)) && (datalen >= (6 + len))) { - want_reply = data[5 + len]; - _libssh2_debug(session, - LIBSSH2_TRACE_CONN, - "Received global request type %.*s (wr %X)", - len, data + 5, want_reply); - } - - - if(want_reply) { - static const unsigned char packet = - SSH_MSG_REQUEST_FAILURE; - libssh2_packet_add_jump_point5: - session->packAdd_state = libssh2_NB_state_jump5; - rc = _libssh2_transport_send(session, &packet, 1, NULL, 0); - if(rc == LIBSSH2_ERROR_EAGAIN) - return rc; - } - } - LIBSSH2_FREE(session, data); - session->packAdd_state = libssh2_NB_state_idle; - return 0; - - /* - byte SSH_MSG_CHANNEL_EXTENDED_DATA - uint32 recipient channel - uint32 data_type_code - string data - */ - - case SSH_MSG_CHANNEL_EXTENDED_DATA: - /* streamid(4) */ - data_head += 4; - - /* fall-through */ - - /* - byte SSH_MSG_CHANNEL_DATA - uint32 recipient channel - string data - */ - - case SSH_MSG_CHANNEL_DATA: - /* packet_type(1) + channelno(4) + datalen(4) */ - data_head += 9; - - if(datalen >= data_head) - channelp = - _libssh2_channel_locate(session, - _libssh2_ntohu32(data + 1)); - - if(!channelp) { - _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_UNKNOWN, - "Packet received for unknown channel"); - LIBSSH2_FREE(session, data); - session->packAdd_state = libssh2_NB_state_idle; - return 0; - } -#ifdef LIBSSH2DEBUG - { - uint32_t stream_id = 0; - if(msg == SSH_MSG_CHANNEL_EXTENDED_DATA) - stream_id = _libssh2_ntohu32(data + 5); - - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "%d bytes packet_add() for %lu/%lu/%lu", - (int) (datalen - data_head), - channelp->local.id, - channelp->remote.id, - stream_id); - } -#endif - if((channelp->remote.extended_data_ignore_mode == - LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE) && - (msg == SSH_MSG_CHANNEL_EXTENDED_DATA)) { - /* Pretend we didn't receive this */ - LIBSSH2_FREE(session, data); - - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Ignoring extended data and refunding %d bytes", - (int) (datalen - 13)); - if(channelp->read_avail + datalen - data_head >= - channelp->remote.window_size) - datalen = channelp->remote.window_size - - channelp->read_avail + data_head; - - channelp->remote.window_size -= datalen - data_head; - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "shrinking window size by %lu bytes to %lu, " - "read_avail %lu", - datalen - data_head, - channelp->remote.window_size, - channelp->read_avail); - - session->packAdd_channelp = channelp; - - /* Adjust the window based on the block we just freed */ - libssh2_packet_add_jump_point1: - session->packAdd_state = libssh2_NB_state_jump1; - rc = _libssh2_channel_receive_window_adjust(session-> - packAdd_channelp, - datalen - 13, - 1, NULL); - if(rc == LIBSSH2_ERROR_EAGAIN) - return rc; - - session->packAdd_state = libssh2_NB_state_idle; - return 0; - } - - /* - * REMEMBER! remote means remote as source of data, - * NOT remote window! - */ - if(channelp->remote.packet_size < (datalen - data_head)) { - /* - * Spec says we MAY ignore bytes sent beyond - * packet_size - */ - _libssh2_error(session, - LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED, - "Packet contains more data than we offered" - " to receive, truncating"); - datalen = channelp->remote.packet_size + data_head; - } - if(channelp->remote.window_size <= channelp->read_avail) { - /* - * Spec says we MAY ignore bytes sent beyond - * window_size - */ - _libssh2_error(session, - LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED, - "The current receive window is full," - " data ignored"); - LIBSSH2_FREE(session, data); - session->packAdd_state = libssh2_NB_state_idle; - return 0; - } - /* Reset EOF status */ - channelp->remote.eof = 0; - - if(channelp->read_avail + datalen - data_head > - channelp->remote.window_size) { - _libssh2_error(session, - LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED, - "Remote sent more data than current " - "window allows, truncating"); - datalen = channelp->remote.window_size - - channelp->read_avail + data_head; - } - - /* Update the read_avail counter. The window size will be - * updated once the data is actually read from the queue - * from an upper layer */ - channelp->read_avail += datalen - data_head; - - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "increasing read_avail by %lu bytes to %lu/%lu", - (long)(datalen - data_head), - (long)channelp->read_avail, - (long)channelp->remote.window_size); - - break; - - /* - byte SSH_MSG_CHANNEL_EOF - uint32 recipient channel - */ - - case SSH_MSG_CHANNEL_EOF: - if(datalen >= 5) - channelp = - _libssh2_channel_locate(session, - _libssh2_ntohu32(data + 1)); - if(!channelp) - /* We may have freed already, just quietly ignore this... */ - ; - else { - _libssh2_debug(session, - LIBSSH2_TRACE_CONN, - "EOF received for channel %lu/%lu", - channelp->local.id, - channelp->remote.id); - channelp->remote.eof = 1; - } - LIBSSH2_FREE(session, data); - session->packAdd_state = libssh2_NB_state_idle; - return 0; - - /* - byte SSH_MSG_CHANNEL_REQUEST - uint32 recipient channel - string request type in US-ASCII characters only - boolean want reply - .... type-specific data follows - */ - - case SSH_MSG_CHANNEL_REQUEST: - if(datalen >= 9) { - uint32_t channel = _libssh2_ntohu32(data + 1); - uint32_t len = _libssh2_ntohu32(data + 5); - unsigned char want_reply = 1; - - if((len + 9) < datalen) - want_reply = data[len + 9]; - - _libssh2_debug(session, - LIBSSH2_TRACE_CONN, - "Channel %d received request type %.*s (wr %X)", - channel, len, data + 9, want_reply); - - if(len == sizeof("exit-status") - 1 - && (sizeof("exit-status") - 1 + 9) <= datalen - && !memcmp("exit-status", data + 9, - sizeof("exit-status") - 1)) { - - /* we've got "exit-status" packet. Set the session value */ - if(datalen >= 20) - channelp = - _libssh2_channel_locate(session, channel); - - if(channelp && (sizeof("exit-status") + 13) <= datalen) { - channelp->exit_status = - _libssh2_ntohu32(data + 9 + sizeof("exit-status")); - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Exit status %lu received for " - "channel %lu/%lu", - channelp->exit_status, - channelp->local.id, - channelp->remote.id); - } - - } - else if(len == sizeof("exit-signal") - 1 - && (sizeof("exit-signal") - 1 + 9) <= datalen - && !memcmp("exit-signal", data + 9, - sizeof("exit-signal") - 1)) { - /* command terminated due to signal */ - if(datalen >= 20) - channelp = _libssh2_channel_locate(session, channel); - - if(channelp && (sizeof("exit-signal") + 13) <= datalen) { - /* set signal name (without SIG prefix) */ - uint32_t namelen = - _libssh2_ntohu32(data + 9 + sizeof("exit-signal")); - - if(namelen <= UINT_MAX - 1) { - channelp->exit_signal = - LIBSSH2_ALLOC(session, namelen + 1); - } - else { - channelp->exit_signal = NULL; - } - - if(!channelp->exit_signal) - rc = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "memory for signal name"); - else if((sizeof("exit-signal") + 13 + namelen <= - datalen)) { - memcpy(channelp->exit_signal, - data + 13 + sizeof("exit-signal"), namelen); - channelp->exit_signal[namelen] = '\0'; - /* TODO: save error message and language tag */ - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Exit signal %s received for " - "channel %lu/%lu", - channelp->exit_signal, - channelp->local.id, - channelp->remote.id); - } - } - } - - - if(want_reply) { - unsigned char packet[5]; - libssh2_packet_add_jump_point4: - session->packAdd_state = libssh2_NB_state_jump4; - packet[0] = SSH_MSG_CHANNEL_FAILURE; - memcpy(&packet[1], data + 1, 4); - rc = _libssh2_transport_send(session, packet, 5, NULL, 0); - if(rc == LIBSSH2_ERROR_EAGAIN) - return rc; - } - } - LIBSSH2_FREE(session, data); - session->packAdd_state = libssh2_NB_state_idle; - return rc; - - /* - byte SSH_MSG_CHANNEL_CLOSE - uint32 recipient channel - */ - - case SSH_MSG_CHANNEL_CLOSE: - if(datalen >= 5) - channelp = - _libssh2_channel_locate(session, - _libssh2_ntohu32(data + 1)); - if(!channelp) { - /* We may have freed already, just quietly ignore this... */ - LIBSSH2_FREE(session, data); - session->packAdd_state = libssh2_NB_state_idle; - return 0; - } - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Close received for channel %lu/%lu", - channelp->local.id, - channelp->remote.id); - - channelp->remote.close = 1; - channelp->remote.eof = 1; - - LIBSSH2_FREE(session, data); - session->packAdd_state = libssh2_NB_state_idle; - return 0; - - /* - byte SSH_MSG_CHANNEL_OPEN - string "session" - uint32 sender channel - uint32 initial window size - uint32 maximum packet size - */ - - case SSH_MSG_CHANNEL_OPEN: - if(datalen < 17) - ; - else if((datalen >= (sizeof("forwarded-tcpip") + 4)) && - ((sizeof("forwarded-tcpip") - 1) == - _libssh2_ntohu32(data + 1)) - && - (memcmp(data + 5, "forwarded-tcpip", - sizeof("forwarded-tcpip") - 1) == 0)) { - - /* init the state struct */ - memset(&session->packAdd_Qlstn_state, 0, - sizeof(session->packAdd_Qlstn_state)); - - libssh2_packet_add_jump_point2: - session->packAdd_state = libssh2_NB_state_jump2; - rc = packet_queue_listener(session, data, datalen, - &session->packAdd_Qlstn_state); - } - else if((datalen >= (sizeof("x11") + 4)) && - ((sizeof("x11") - 1) == _libssh2_ntohu32(data + 1)) && - (memcmp(data + 5, "x11", sizeof("x11") - 1) == 0)) { - - /* init the state struct */ - memset(&session->packAdd_x11open_state, 0, - sizeof(session->packAdd_x11open_state)); - - libssh2_packet_add_jump_point3: - session->packAdd_state = libssh2_NB_state_jump3; - rc = packet_x11_open(session, data, datalen, - &session->packAdd_x11open_state); - } - if(rc == LIBSSH2_ERROR_EAGAIN) - return rc; - - LIBSSH2_FREE(session, data); - session->packAdd_state = libssh2_NB_state_idle; - return rc; - - /* - byte SSH_MSG_CHANNEL_WINDOW_ADJUST - uint32 recipient channel - uint32 bytes to add - */ - case SSH_MSG_CHANNEL_WINDOW_ADJUST: - if(datalen < 9) - ; - else { - uint32_t bytestoadd = _libssh2_ntohu32(data + 5); - channelp = - _libssh2_channel_locate(session, - _libssh2_ntohu32(data + 1)); - if(channelp) { - channelp->local.window_size += bytestoadd; - - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Window adjust for channel %lu/%lu, " - "adding %lu bytes, new window_size=%lu", - channelp->local.id, - channelp->remote.id, - bytestoadd, - channelp->local.window_size); - } - } - LIBSSH2_FREE(session, data); - session->packAdd_state = libssh2_NB_state_idle; - return 0; - default: - break; - } - - session->packAdd_state = libssh2_NB_state_sent; - } - - if(session->packAdd_state == libssh2_NB_state_sent) { - LIBSSH2_PACKET *packetp = - LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PACKET)); - if(!packetp) { - _libssh2_debug(session, LIBSSH2_ERROR_ALLOC, - "memory for packet"); - LIBSSH2_FREE(session, data); - session->packAdd_state = libssh2_NB_state_idle; - return LIBSSH2_ERROR_ALLOC; - } - packetp->data = data; - packetp->data_len = datalen; - packetp->data_head = data_head; - - _libssh2_list_add(&session->packets, &packetp->node); - - session->packAdd_state = libssh2_NB_state_sent1; - } - - if((msg == SSH_MSG_KEXINIT && - !(session->state & LIBSSH2_STATE_EXCHANGING_KEYS)) || - (session->packAdd_state == libssh2_NB_state_sent2)) { - if(session->packAdd_state == libssh2_NB_state_sent1) { - /* - * Remote wants new keys - * Well, it's already in the brigade, - * let's just call back into ourselves - */ - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Renegotiating Keys"); - - session->packAdd_state = libssh2_NB_state_sent2; - } - - /* - * The KEXINIT message has been added to the queue. The packAdd and - * readPack states need to be reset because _libssh2_kex_exchange - * (eventually) calls upon _libssh2_transport_read to read the rest of - * the key exchange conversation. - */ - session->readPack_state = libssh2_NB_state_idle; - session->packet.total_num = 0; - session->packAdd_state = libssh2_NB_state_idle; - session->fullpacket_state = libssh2_NB_state_idle; - - memset(&session->startup_key_state, 0, sizeof(key_exchange_state_t)); - - /* - * If there was a key reexchange failure, let's just hope we didn't - * send NEWKEYS yet, otherwise remote will drop us like a rock - */ - rc = _libssh2_kex_exchange(session, 1, &session->startup_key_state); - if(rc == LIBSSH2_ERROR_EAGAIN) - return rc; - } - - session->packAdd_state = libssh2_NB_state_idle; - return 0; -} - -/* - * _libssh2_packet_ask - * - * Scan the brigade for a matching packet type, optionally poll the socket for - * a packet first - */ -int -_libssh2_packet_ask(LIBSSH2_SESSION * session, unsigned char packet_type, - unsigned char **data, size_t *data_len, - int match_ofs, const unsigned char *match_buf, - size_t match_len) -{ - LIBSSH2_PACKET *packet = _libssh2_list_first(&session->packets); - - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "Looking for packet of type: %d", (int) packet_type); - - while(packet) { - if(packet->data[0] == packet_type - && (packet->data_len >= (match_ofs + match_len)) - && (!match_buf || - (memcmp(packet->data + match_ofs, match_buf, - match_len) == 0))) { - *data = packet->data; - *data_len = packet->data_len; - - /* unlink struct from session->packets */ - _libssh2_list_remove(&packet->node); - - LIBSSH2_FREE(session, packet); - - return 0; - } - packet = _libssh2_list_next(&packet->node); - } - return -1; -} - -/* - * libssh2_packet_askv - * - * Scan for any of a list of packet types in the brigade, optionally poll the - * socket for a packet first - */ -int -_libssh2_packet_askv(LIBSSH2_SESSION * session, - const unsigned char *packet_types, - unsigned char **data, size_t *data_len, - int match_ofs, - const unsigned char *match_buf, - size_t match_len) -{ - int i, packet_types_len = strlen((char *) packet_types); - - for(i = 0; i < packet_types_len; i++) { - if(0 == _libssh2_packet_ask(session, packet_types[i], data, - data_len, match_ofs, - match_buf, match_len)) { - return 0; - } - } - - return -1; -} - -/* - * _libssh2_packet_require - * - * Loops _libssh2_transport_read() until the packet requested is available - * SSH_DISCONNECT or a SOCKET_DISCONNECTED will cause a bailout - * - * Returns negative on error - * Returns 0 when it has taken care of the requested packet. - */ -int -_libssh2_packet_require(LIBSSH2_SESSION * session, unsigned char packet_type, - unsigned char **data, size_t *data_len, - int match_ofs, - const unsigned char *match_buf, - size_t match_len, - packet_require_state_t *state) -{ - if(state->start == 0) { - if(_libssh2_packet_ask(session, packet_type, data, data_len, - match_ofs, match_buf, - match_len) == 0) { - /* A packet was available in the packet brigade */ - return 0; - } - - state->start = time(NULL); - } - - while(session->socket_state == LIBSSH2_SOCKET_CONNECTED) { - int ret = _libssh2_transport_read(session); - if(ret == LIBSSH2_ERROR_EAGAIN) - return ret; - else if(ret < 0) { - state->start = 0; - /* an error which is not just because of blocking */ - return ret; - } - else if(ret == packet_type) { - /* Be lazy, let packet_ask pull it out of the brigade */ - ret = _libssh2_packet_ask(session, packet_type, data, data_len, - match_ofs, match_buf, match_len); - state->start = 0; - return ret; - } - else if(ret == 0) { - /* nothing available, wait until data arrives or we time out */ - long left = LIBSSH2_READ_TIMEOUT - (long)(time(NULL) - - state->start); - - if(left <= 0) { - state->start = 0; - return LIBSSH2_ERROR_TIMEOUT; - } - return -1; /* no packet available yet */ - } - } - - /* Only reached if the socket died */ - return LIBSSH2_ERROR_SOCKET_DISCONNECT; -} - -/* - * _libssh2_packet_burn - * - * Loops _libssh2_transport_read() until any packet is available and promptly - * discards it. - * Used during KEX exchange to discard badly guessed KEX_INIT packets - */ -int -_libssh2_packet_burn(LIBSSH2_SESSION * session, - libssh2_nonblocking_states * state) -{ - unsigned char *data; - size_t data_len; - unsigned char i, all_packets[255]; - int ret; - - if(*state == libssh2_NB_state_idle) { - for(i = 1; i < 255; i++) { - all_packets[i - 1] = i; - } - all_packets[254] = 0; - - if(_libssh2_packet_askv(session, all_packets, &data, &data_len, 0, - NULL, 0) == 0) { - i = data[0]; - /* A packet was available in the packet brigade, burn it */ - LIBSSH2_FREE(session, data); - return i; - } - - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "Blocking until packet becomes available to burn"); - *state = libssh2_NB_state_created; - } - - while(session->socket_state == LIBSSH2_SOCKET_CONNECTED) { - ret = _libssh2_transport_read(session); - if(ret == LIBSSH2_ERROR_EAGAIN) { - return ret; - } - else if(ret < 0) { - *state = libssh2_NB_state_idle; - return ret; - } - else if(ret == 0) { - /* FIXME: this might busyloop */ - continue; - } - - /* Be lazy, let packet_ask pull it out of the brigade */ - if(0 == - _libssh2_packet_ask(session, (unsigned char)ret, - &data, &data_len, 0, NULL, 0)) { - /* Smoke 'em if you got 'em */ - LIBSSH2_FREE(session, data); - *state = libssh2_NB_state_idle; - return ret; - } - } - - /* Only reached if the socket died */ - return LIBSSH2_ERROR_SOCKET_DISCONNECT; -} - -/* - * _libssh2_packet_requirev - * - * Loops _libssh2_transport_read() until one of a list of packet types - * requested is available. SSH_DISCONNECT or a SOCKET_DISCONNECTED will cause - * a bailout. packet_types is a null terminated list of packet_type numbers - */ - -int -_libssh2_packet_requirev(LIBSSH2_SESSION *session, - const unsigned char *packet_types, - unsigned char **data, size_t *data_len, - int match_ofs, - const unsigned char *match_buf, size_t match_len, - packet_requirev_state_t * state) -{ - if(_libssh2_packet_askv(session, packet_types, data, data_len, match_ofs, - match_buf, match_len) == 0) { - /* One of the packets listed was available in the packet brigade */ - state->start = 0; - return 0; - } - - if(state->start == 0) { - state->start = time(NULL); - } - - while(session->socket_state != LIBSSH2_SOCKET_DISCONNECTED) { - int ret = _libssh2_transport_read(session); - if((ret < 0) && (ret != LIBSSH2_ERROR_EAGAIN)) { - state->start = 0; - return ret; - } - if(ret <= 0) { - long left = LIBSSH2_READ_TIMEOUT - - (long)(time(NULL) - state->start); - - if(left <= 0) { - state->start = 0; - return LIBSSH2_ERROR_TIMEOUT; - } - else if(ret == LIBSSH2_ERROR_EAGAIN) { - return ret; - } - } - - if(strchr((char *) packet_types, ret)) { - /* Be lazy, let packet_ask pull it out of the brigade */ - return _libssh2_packet_askv(session, packet_types, data, - data_len, match_ofs, match_buf, - match_len); - } - } - - /* Only reached if the socket died */ - state->start = 0; - return LIBSSH2_ERROR_SOCKET_DISCONNECT; -} - diff --git a/libssh2/pem.c b/libssh2/pem.c deleted file mode 100644 index 53f58c2..0000000 --- a/libssh2/pem.c +++ /dev/null @@ -1,902 +0,0 @@ -/* Copyright (C) 2007 The Written Word, Inc. - * Copyright (C) 2008, Simon Josefsson - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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 "libssh2_priv.h" - -static int -readline(char *line, int line_size, FILE * fp) -{ - size_t len; - - if(!line) { - return -1; - } - if(!fgets(line, line_size, fp)) { - return -1; - } - - if(*line) { - len = strlen(line); - if(len > 0 && line[len - 1] == '\n') { - line[len - 1] = '\0'; - } - } - - if(*line) { - len = strlen(line); - if(len > 0 && line[len - 1] == '\r') { - line[len - 1] = '\0'; - } - } - - return 0; -} - -static int -readline_memory(char *line, size_t line_size, - const char *filedata, size_t filedata_len, - size_t *filedata_offset) -{ - size_t off, len; - - off = *filedata_offset; - - for(len = 0; off + len < filedata_len && len < line_size - 1; len++) { - if(filedata[off + len] == '\n' || - filedata[off + len] == '\r') { - break; - } - } - - if(len) { - memcpy(line, filedata + off, len); - *filedata_offset += len; - } - - line[len] = '\0'; - *filedata_offset += 1; - - return 0; -} - -#define LINE_SIZE 128 - -static const char *crypt_annotation = "Proc-Type: 4,ENCRYPTED"; - -static unsigned char hex_decode(char digit) -{ - return (digit >= 'A') ? 0xA + (digit - 'A') : (digit - '0'); -} - -int -_libssh2_pem_parse(LIBSSH2_SESSION * session, - const char *headerbegin, - const char *headerend, - const unsigned char *passphrase, - FILE * fp, unsigned char **data, unsigned int *datalen) -{ - char line[LINE_SIZE]; - unsigned char iv[LINE_SIZE]; - char *b64data = NULL; - unsigned int b64datalen = 0; - int ret; - const LIBSSH2_CRYPT_METHOD *method = NULL; - - do { - *line = '\0'; - - if(readline(line, LINE_SIZE, fp)) { - return -1; - } - } - while(strcmp(line, headerbegin) != 0); - - if(readline(line, LINE_SIZE, fp)) { - return -1; - } - - if(passphrase && - memcmp(line, crypt_annotation, strlen(crypt_annotation)) == 0) { - const LIBSSH2_CRYPT_METHOD **all_methods, *cur_method; - int i; - - if(readline(line, LINE_SIZE, fp)) { - ret = -1; - goto out; - } - - all_methods = libssh2_crypt_methods(); - while((cur_method = *all_methods++)) { - if(*cur_method->pem_annotation && - memcmp(line, cur_method->pem_annotation, - strlen(cur_method->pem_annotation)) == 0) { - method = cur_method; - memcpy(iv, line + strlen(method->pem_annotation) + 1, - 2*method->iv_len); - } - } - - /* None of the available crypt methods were able to decrypt the key */ - if(method == NULL) - return -1; - - /* Decode IV from hex */ - for(i = 0; i < method->iv_len; ++i) { - iv[i] = hex_decode(iv[2*i]) << 4; - iv[i] |= hex_decode(iv[2*i + 1]); - } - - /* skip to the next line */ - if(readline(line, LINE_SIZE, fp)) { - ret = -1; - goto out; - } - } - - do { - if(*line) { - char *tmp; - size_t linelen; - - linelen = strlen(line); - tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen); - if(!tmp) { - ret = -1; - goto out; - } - memcpy(tmp + b64datalen, line, linelen); - b64data = tmp; - b64datalen += linelen; - } - - *line = '\0'; - - if(readline(line, LINE_SIZE, fp)) { - ret = -1; - goto out; - } - } while(strcmp(line, headerend) != 0); - - if(!b64data) { - return -1; - } - - if(libssh2_base64_decode(session, (char **) data, datalen, - b64data, b64datalen)) { - ret = -1; - goto out; - } - - if(method) { - /* Set up decryption */ - int free_iv = 0, free_secret = 0, len_decrypted = 0, padding = 0; - int blocksize = method->blocksize; - void *abstract; - unsigned char secret[2*MD5_DIGEST_LENGTH]; - libssh2_md5_ctx fingerprint_ctx; - - /* Perform key derivation (PBKDF1/MD5) */ - if(!libssh2_md5_init(&fingerprint_ctx)) { - ret = -1; - goto out; - } - libssh2_md5_update(fingerprint_ctx, passphrase, - strlen((char *)passphrase)); - libssh2_md5_update(fingerprint_ctx, iv, 8); - libssh2_md5_final(fingerprint_ctx, secret); - if(method->secret_len > MD5_DIGEST_LENGTH) { - if(!libssh2_md5_init(&fingerprint_ctx)) { - ret = -1; - goto out; - } - libssh2_md5_update(fingerprint_ctx, secret, MD5_DIGEST_LENGTH); - libssh2_md5_update(fingerprint_ctx, passphrase, - strlen((char *)passphrase)); - libssh2_md5_update(fingerprint_ctx, iv, 8); - libssh2_md5_final(fingerprint_ctx, secret + MD5_DIGEST_LENGTH); - } - - /* Initialize the decryption */ - if(method->init(session, method, iv, &free_iv, secret, - &free_secret, 0, &abstract)) { - _libssh2_explicit_zero((char *)secret, sizeof(secret)); - LIBSSH2_FREE(session, data); - ret = -1; - goto out; - } - - if(free_secret) { - _libssh2_explicit_zero((char *)secret, sizeof(secret)); - } - - /* Do the actual decryption */ - if((*datalen % blocksize) != 0) { - _libssh2_explicit_zero((char *)secret, sizeof(secret)); - method->dtor(session, &abstract); - _libssh2_explicit_zero(*data, *datalen); - LIBSSH2_FREE(session, *data); - ret = -1; - goto out; - } - - while(len_decrypted <= (int)*datalen - blocksize) { - if(method->crypt(session, *data + len_decrypted, blocksize, - &abstract)) { - ret = LIBSSH2_ERROR_DECRYPT; - _libssh2_explicit_zero((char *)secret, sizeof(secret)); - method->dtor(session, &abstract); - _libssh2_explicit_zero(*data, *datalen); - LIBSSH2_FREE(session, *data); - goto out; - } - - len_decrypted += blocksize; - } - - /* Account for padding */ - padding = (*data)[*datalen - 1]; - memset(&(*data)[*datalen-padding], 0, padding); - *datalen -= padding; - - /* Clean up */ - _libssh2_explicit_zero((char *)secret, sizeof(secret)); - method->dtor(session, &abstract); - } - - ret = 0; - out: - if(b64data) { - _libssh2_explicit_zero(b64data, b64datalen); - LIBSSH2_FREE(session, b64data); - } - return ret; -} - -int -_libssh2_pem_parse_memory(LIBSSH2_SESSION * session, - const char *headerbegin, - const char *headerend, - const char *filedata, size_t filedata_len, - unsigned char **data, unsigned int *datalen) -{ - char line[LINE_SIZE]; - char *b64data = NULL; - unsigned int b64datalen = 0; - size_t off = 0; - int ret; - - do { - *line = '\0'; - - if(readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) { - return -1; - } - } - while(strcmp(line, headerbegin) != 0); - - *line = '\0'; - - do { - if(*line) { - char *tmp; - size_t linelen; - - linelen = strlen(line); - tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen); - if(!tmp) { - ret = -1; - goto out; - } - memcpy(tmp + b64datalen, line, linelen); - b64data = tmp; - b64datalen += linelen; - } - - *line = '\0'; - - if(readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) { - ret = -1; - goto out; - } - } while(strcmp(line, headerend) != 0); - - if(!b64data) { - return -1; - } - - if(libssh2_base64_decode(session, (char **) data, datalen, - b64data, b64datalen)) { - ret = -1; - goto out; - } - - ret = 0; - out: - if(b64data) { - _libssh2_explicit_zero(b64data, b64datalen); - LIBSSH2_FREE(session, b64data); - } - return ret; -} - -/* OpenSSH formatted keys */ -#define AUTH_MAGIC "openssh-key-v1" -#define OPENSSH_HEADER_BEGIN "-----BEGIN OPENSSH PRIVATE KEY-----" -#define OPENSSH_HEADER_END "-----END OPENSSH PRIVATE KEY-----" - -static int -_libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session, - const unsigned char *passphrase, - const char *b64data, size_t b64datalen, - struct string_buf **decrypted_buf) -{ - const LIBSSH2_CRYPT_METHOD *method = NULL; - struct string_buf decoded, decrypted, kdf_buf; - unsigned char *ciphername = NULL; - unsigned char *kdfname = NULL; - unsigned char *kdf = NULL; - unsigned char *buf = NULL; - unsigned char *salt = NULL; - uint32_t nkeys, check1, check2; - uint32_t rounds = 0; - unsigned char *key = NULL; - unsigned char *key_part = NULL; - unsigned char *iv_part = NULL; - unsigned char *f = NULL; - unsigned int f_len = 0; - int ret = 0, keylen = 0, ivlen = 0, total_len = 0; - size_t kdf_len = 0, tmp_len = 0, salt_len = 0; - - if(decrypted_buf) - *decrypted_buf = NULL; - - /* decode file */ - if(libssh2_base64_decode(session, (char **)&f, &f_len, - b64data, b64datalen)) { - ret = -1; - goto out; - } - - /* Parse the file */ - decoded.data = (unsigned char *)f; - decoded.dataptr = (unsigned char *)f; - decoded.len = f_len; - - if(decoded.len < strlen(AUTH_MAGIC)) { - ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, "key too short"); - goto out; - } - - if(strncmp((char *) decoded.dataptr, AUTH_MAGIC, - strlen(AUTH_MAGIC)) != 0) { - ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "key auth magic mismatch"); - goto out; - } - - decoded.dataptr += strlen(AUTH_MAGIC) + 1; - - if(_libssh2_get_string(&decoded, &ciphername, &tmp_len) || - tmp_len == 0) { - ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "ciphername is missing"); - goto out; - } - - if(_libssh2_get_string(&decoded, &kdfname, &tmp_len) || - tmp_len == 0) { - ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "kdfname is missing"); - goto out; - } - - if(_libssh2_get_string(&decoded, &kdf, &kdf_len)) { - ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "kdf is missing"); - goto out; - } - else { - kdf_buf.data = kdf; - kdf_buf.dataptr = kdf; - kdf_buf.len = kdf_len; - } - - if((passphrase == NULL || strlen((const char *)passphrase) == 0) && - strcmp((const char *)ciphername, "none") != 0) { - /* passphrase required */ - ret = LIBSSH2_ERROR_KEYFILE_AUTH_FAILED; - goto out; - } - - if(strcmp((const char *)kdfname, "none") != 0 && - strcmp((const char *)kdfname, "bcrypt") != 0) { - ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "unknown cipher"); - goto out; - } - - if(!strcmp((const char *)kdfname, "none") && - strcmp((const char *)ciphername, "none") != 0) { - ret =_libssh2_error(session, LIBSSH2_ERROR_PROTO, - "invalid format"); - goto out; - } - - if(_libssh2_get_u32(&decoded, &nkeys) != 0 || nkeys != 1) { - ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Multiple keys are unsupported"); - goto out; - } - - /* unencrypted public key */ - - if(_libssh2_get_string(&decoded, &buf, &tmp_len) || tmp_len == 0) { - ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Invalid private key; " - "expect embedded public key"); - goto out; - } - - if(_libssh2_get_string(&decoded, &buf, &tmp_len) || tmp_len == 0) { - ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Private key data not found"); - goto out; - } - - /* decode encrypted private key */ - decrypted.data = decrypted.dataptr = buf; - decrypted.len = tmp_len; - - if(ciphername && strcmp((const char *)ciphername, "none") != 0) { - const LIBSSH2_CRYPT_METHOD **all_methods, *cur_method; - - all_methods = libssh2_crypt_methods(); - while((cur_method = *all_methods++)) { - if(*cur_method->name && - memcmp(ciphername, cur_method->name, - strlen(cur_method->name)) == 0) { - method = cur_method; - } - } - - /* None of the available crypt methods were able to decrypt the key */ - - if(method == NULL) { - ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "No supported cipher found"); - goto out; - } - } - - if(method) { - int free_iv = 0, free_secret = 0, len_decrypted = 0; - int blocksize; - void *abstract = NULL; - - keylen = method->secret_len; - ivlen = method->iv_len; - total_len = keylen + ivlen; - - key = LIBSSH2_CALLOC(session, total_len); - if(key == NULL) { - ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Could not alloc key"); - goto out; - } - - if(strcmp((const char *)kdfname, "bcrypt") == 0 && - passphrase != NULL) { - if((_libssh2_get_string(&kdf_buf, &salt, &salt_len)) || - (_libssh2_get_u32(&kdf_buf, &rounds) != 0) ) { - ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "kdf contains unexpected values"); - LIBSSH2_FREE(session, key); - goto out; - } - - if(_libssh2_bcrypt_pbkdf((const char *)passphrase, - strlen((const char *)passphrase), - salt, salt_len, key, - keylen + ivlen, rounds) < 0) { - ret = _libssh2_error(session, LIBSSH2_ERROR_DECRYPT, - "invalid format"); - LIBSSH2_FREE(session, key); - goto out; - } - } - else { - ret = _libssh2_error(session, LIBSSH2_ERROR_KEYFILE_AUTH_FAILED, - "bcrypted without passphrase"); - LIBSSH2_FREE(session, key); - goto out; - } - - /* Set up decryption */ - blocksize = method->blocksize; - - key_part = LIBSSH2_CALLOC(session, keylen); - if(key_part == NULL) { - ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Could not alloc key part"); - goto out; - } - - iv_part = LIBSSH2_CALLOC(session, ivlen); - if(iv_part == NULL) { - ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Could not alloc iv part"); - goto out; - } - - memcpy(key_part, key, keylen); - memcpy(iv_part, key + keylen, ivlen); - - /* Initialize the decryption */ - if(method->init(session, method, iv_part, &free_iv, key_part, - &free_secret, 0, &abstract)) { - ret = LIBSSH2_ERROR_DECRYPT; - goto out; - } - - /* Do the actual decryption */ - if((decrypted.len % blocksize) != 0) { - method->dtor(session, &abstract); - ret = LIBSSH2_ERROR_DECRYPT; - goto out; - } - - while((size_t)len_decrypted <= decrypted.len - blocksize) { - if(method->crypt(session, decrypted.data + len_decrypted, - blocksize, - &abstract)) { - ret = LIBSSH2_ERROR_DECRYPT; - method->dtor(session, &abstract); - goto out; - } - - len_decrypted += blocksize; - } - - /* No padding */ - - method->dtor(session, &abstract); - } - - /* Check random bytes match */ - - if(_libssh2_get_u32(&decrypted, &check1) != 0 || - _libssh2_get_u32(&decrypted, &check2) != 0 || - check1 != check2) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Private key unpack failed (correct password?)"); - ret = LIBSSH2_ERROR_KEYFILE_AUTH_FAILED; - goto out; - } - - if(decrypted_buf != NULL) { - /* copy data to out-going buffer */ - struct string_buf *out_buf = _libssh2_string_buf_new(session); - if(!out_buf) { - ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "decrypted struct"); - goto out; - } - - out_buf->data = LIBSSH2_CALLOC(session, decrypted.len); - if(out_buf->data == NULL) { - ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "decrypted struct"); - _libssh2_string_buf_free(session, out_buf); - goto out; - } - memcpy(out_buf->data, decrypted.data, decrypted.len); - out_buf->dataptr = out_buf->data + - (decrypted.dataptr - decrypted.data); - out_buf->len = decrypted.len; - - *decrypted_buf = out_buf; - } - -out: - - /* Clean up */ - if(key) { - _libssh2_explicit_zero(key, total_len); - LIBSSH2_FREE(session, key); - } - if(key_part) { - _libssh2_explicit_zero(key_part, keylen); - LIBSSH2_FREE(session, key_part); - } - if(iv_part) { - _libssh2_explicit_zero(iv_part, ivlen); - LIBSSH2_FREE(session, iv_part); - } - if(f) { - _libssh2_explicit_zero(f, f_len); - LIBSSH2_FREE(session, f); - } - - return ret; -} - -int -_libssh2_openssh_pem_parse(LIBSSH2_SESSION * session, - const unsigned char *passphrase, - FILE * fp, struct string_buf **decrypted_buf) -{ - char line[LINE_SIZE]; - char *b64data = NULL; - unsigned int b64datalen = 0; - int ret = 0; - - /* read file */ - - do { - *line = '\0'; - - if(readline(line, LINE_SIZE, fp)) { - return -1; - } - } - while(strcmp(line, OPENSSH_HEADER_BEGIN) != 0); - - if(readline(line, LINE_SIZE, fp)) { - return -1; - } - - do { - if(*line) { - char *tmp; - size_t linelen; - - linelen = strlen(line); - tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen); - if(!tmp) { - ret = -1; - goto out; - } - memcpy(tmp + b64datalen, line, linelen); - b64data = tmp; - b64datalen += linelen; - } - - *line = '\0'; - - if(readline(line, LINE_SIZE, fp)) { - ret = -1; - goto out; - } - } while(strcmp(line, OPENSSH_HEADER_END) != 0); - - if(!b64data) { - return -1; - } - - ret = _libssh2_openssh_pem_parse_data(session, - passphrase, - (const char *)b64data, - (size_t)b64datalen, - decrypted_buf); - - if(b64data) { - _libssh2_explicit_zero(b64data, b64datalen); - LIBSSH2_FREE(session, b64data); - } - -out: - - return ret; -} - -int -_libssh2_openssh_pem_parse_memory(LIBSSH2_SESSION * session, - const unsigned char *passphrase, - const char *filedata, size_t filedata_len, - struct string_buf **decrypted_buf) -{ - char line[LINE_SIZE]; - char *b64data = NULL; - unsigned int b64datalen = 0; - size_t off = 0; - int ret; - - if(filedata == NULL || filedata_len <= 0) { - return -1; - } - - do { - - *line = '\0'; - - if(off >= filedata_len) { - return -1; - } - - if(readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) { - return -1; - } - } - while(strcmp(line, OPENSSH_HEADER_BEGIN) != 0); - - *line = '\0'; - - do { - if (*line) { - char *tmp; - size_t linelen; - - linelen = strlen(line); - tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen); - if(!tmp) { - ret = -1; - goto out; - } - memcpy(tmp + b64datalen, line, linelen); - b64data = tmp; - b64datalen += linelen; - } - - *line = '\0'; - - if(off >= filedata_len) { - ret = -1; - goto out; - } - - if(readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) { - ret = -1; - goto out; - } - } while(strcmp(line, OPENSSH_HEADER_END) != 0); - - if(!b64data) { - return -1; - } - - ret = _libssh2_openssh_pem_parse_data(session, passphrase, b64data, - b64datalen, decrypted_buf); - -out: - if(b64data) { - _libssh2_explicit_zero(b64data, b64datalen); - LIBSSH2_FREE(session, b64data); - } - return ret; - -} - -static int -read_asn1_length(const unsigned char *data, - unsigned int datalen, unsigned int *len) -{ - unsigned int lenlen; - int nextpos; - - if(datalen < 1) { - return -1; - } - *len = data[0]; - - if(*len >= 0x80) { - lenlen = *len & 0x7F; - *len = data[1]; - if(1 + lenlen > datalen) { - return -1; - } - if(lenlen > 1) { - *len <<= 8; - *len |= data[2]; - } - } - else { - lenlen = 0; - } - - nextpos = 1 + lenlen; - if(lenlen > 2 || 1 + lenlen + *len > datalen) { - return -1; - } - - return nextpos; -} - -int -_libssh2_pem_decode_sequence(unsigned char **data, unsigned int *datalen) -{ - unsigned int len; - int lenlen; - - if(*datalen < 1) { - return -1; - } - - if((*data)[0] != '\x30') { - return -1; - } - - (*data)++; - (*datalen)--; - - lenlen = read_asn1_length(*data, *datalen, &len); - if(lenlen < 0 || lenlen + len != *datalen) { - return -1; - } - - *data += lenlen; - *datalen -= lenlen; - - return 0; -} - -int -_libssh2_pem_decode_integer(unsigned char **data, unsigned int *datalen, - unsigned char **i, unsigned int *ilen) -{ - unsigned int len; - int lenlen; - - if(*datalen < 1) { - return -1; - } - - if((*data)[0] != '\x02') { - return -1; - } - - (*data)++; - (*datalen)--; - - lenlen = read_asn1_length(*data, *datalen, &len); - if(lenlen < 0 || lenlen + len > *datalen) { - return -1; - } - - *data += lenlen; - *datalen -= lenlen; - - *i = *data; - *ilen = len; - - *data += len; - *datalen -= len; - - return 0; -} diff --git a/libssh2/publickey.c b/libssh2/publickey.c deleted file mode 100644 index f26c632..0000000 --- a/libssh2/publickey.c +++ /dev/null @@ -1,1278 +0,0 @@ -/* Copyright (c) 2004-2007, Sara Golemon - * Copyright (c) 2010-2014 by Daniel Stenberg - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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 "libssh2_priv.h" -#include "libssh2_publickey.h" -#include "channel.h" -#include "session.h" - -#define LIBSSH2_PUBLICKEY_VERSION 2 - -/* Numericised response codes -- Not IETF, just local representation */ -#define LIBSSH2_PUBLICKEY_RESPONSE_STATUS 0 -#define LIBSSH2_PUBLICKEY_RESPONSE_VERSION 1 -#define LIBSSH2_PUBLICKEY_RESPONSE_PUBLICKEY 2 - -typedef struct _LIBSSH2_PUBLICKEY_CODE_LIST -{ - int code; - const char *name; - int name_len; -} LIBSSH2_PUBLICKEY_CODE_LIST; - -static const LIBSSH2_PUBLICKEY_CODE_LIST publickey_response_codes[] = -{ - {LIBSSH2_PUBLICKEY_RESPONSE_STATUS, "status", sizeof("status") - 1}, - {LIBSSH2_PUBLICKEY_RESPONSE_VERSION, "version", sizeof("version") - 1}, - {LIBSSH2_PUBLICKEY_RESPONSE_PUBLICKEY, "publickey", - sizeof("publickey") - 1}, - {0, NULL, 0} -}; - -/* PUBLICKEY status codes -- IETF defined */ -#define LIBSSH2_PUBLICKEY_SUCCESS 0 -#define LIBSSH2_PUBLICKEY_ACCESS_DENIED 1 -#define LIBSSH2_PUBLICKEY_STORAGE_EXCEEDED 2 -#define LIBSSH2_PUBLICKEY_VERSION_NOT_SUPPORTED 3 -#define LIBSSH2_PUBLICKEY_KEY_NOT_FOUND 4 -#define LIBSSH2_PUBLICKEY_KEY_NOT_SUPPORTED 5 -#define LIBSSH2_PUBLICKEY_KEY_ALREADY_PRESENT 6 -#define LIBSSH2_PUBLICKEY_GENERAL_FAILURE 7 -#define LIBSSH2_PUBLICKEY_REQUEST_NOT_SUPPORTED 8 - -#define LIBSSH2_PUBLICKEY_STATUS_CODE_MAX 8 - -static const LIBSSH2_PUBLICKEY_CODE_LIST publickey_status_codes[] = { - {LIBSSH2_PUBLICKEY_SUCCESS, "success", sizeof("success") - 1}, - {LIBSSH2_PUBLICKEY_ACCESS_DENIED, "access denied", - sizeof("access denied") - 1}, - {LIBSSH2_PUBLICKEY_STORAGE_EXCEEDED, "storage exceeded", - sizeof("storage exceeded") - 1}, - {LIBSSH2_PUBLICKEY_VERSION_NOT_SUPPORTED, "version not supported", - sizeof("version not supported") - 1}, - {LIBSSH2_PUBLICKEY_KEY_NOT_FOUND, "key not found", - sizeof("key not found") - 1}, - {LIBSSH2_PUBLICKEY_KEY_NOT_SUPPORTED, "key not supported", - sizeof("key not supported") - 1}, - {LIBSSH2_PUBLICKEY_KEY_ALREADY_PRESENT, "key already present", - sizeof("key already present") - 1}, - {LIBSSH2_PUBLICKEY_GENERAL_FAILURE, "general failure", - sizeof("general failure") - 1}, - {LIBSSH2_PUBLICKEY_REQUEST_NOT_SUPPORTED, "request not supported", - sizeof("request not supported") - 1}, - {0, NULL, 0} -}; - -/* - * publickey_status_error - * - * Format an error message from a status code - */ -static void -publickey_status_error(const LIBSSH2_PUBLICKEY *pkey, - LIBSSH2_SESSION *session, int status) -{ - const char *msg; - - /* GENERAL_FAILURE got remapped between version 1 and 2 */ - if(status == 6 && pkey && pkey->version == 1) { - status = 7; - } - - if(status < 0 || status > LIBSSH2_PUBLICKEY_STATUS_CODE_MAX) { - msg = "unknown"; - } - else { - msg = publickey_status_codes[status].name; - } - - _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, msg); -} - -/* - * publickey_packet_receive - * - * Read a packet from the subsystem - */ -static int -publickey_packet_receive(LIBSSH2_PUBLICKEY * pkey, - unsigned char **data, size_t *data_len) -{ - LIBSSH2_CHANNEL *channel = pkey->channel; - LIBSSH2_SESSION *session = channel->session; - unsigned char buffer[4]; - int rc; - *data = NULL; /* default to nothing returned */ - *data_len = 0; - - if(pkey->receive_state == libssh2_NB_state_idle) { - rc = _libssh2_channel_read(channel, 0, (char *) buffer, 4); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc != 4) { - return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, - "Invalid response from publickey subsystem"); - } - - pkey->receive_packet_len = _libssh2_ntohu32(buffer); - pkey->receive_packet = - LIBSSH2_ALLOC(session, pkey->receive_packet_len); - if(!pkey->receive_packet) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate publickey response " - "buffer"); - } - - pkey->receive_state = libssh2_NB_state_sent; - } - - if(pkey->receive_state == libssh2_NB_state_sent) { - rc = _libssh2_channel_read(channel, 0, (char *) pkey->receive_packet, - pkey->receive_packet_len); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc != (int)pkey->receive_packet_len) { - LIBSSH2_FREE(session, pkey->receive_packet); - pkey->receive_packet = NULL; - pkey->receive_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, - "Timeout waiting for publickey subsystem " - "response packet"); - } - - *data = pkey->receive_packet; - *data_len = pkey->receive_packet_len; - } - - pkey->receive_state = libssh2_NB_state_idle; - - return 0; -} - -/* publickey_response_id - * - * Translate a string response name to a numeric code - * Data will be incremented by 4 + response_len on success only - */ -static int -publickey_response_id(unsigned char **pdata, size_t data_len) -{ - size_t response_len; - unsigned char *data = *pdata; - const LIBSSH2_PUBLICKEY_CODE_LIST *codes = publickey_response_codes; - - if(data_len < 4) { - /* Malformed response */ - return -1; - } - response_len = _libssh2_ntohu32(data); - data += 4; - data_len -= 4; - if(data_len < response_len) { - /* Malformed response */ - return -1; - } - - while(codes->name) { - if((unsigned long)codes->name_len == response_len && - strncmp(codes->name, (char *) data, response_len) == 0) { - *pdata = data + response_len; - return codes->code; - } - codes++; - } - - return -1; -} - -/* publickey_response_success - * - * Generic helper routine to wait for success response and nothing else - */ -static int -publickey_response_success(LIBSSH2_PUBLICKEY * pkey) -{ - LIBSSH2_SESSION *session = pkey->channel->session; - unsigned char *data, *s; - size_t data_len; - int response; - - while(1) { - int rc = publickey_packet_receive(pkey, &data, &data_len); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc) { - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, - "Timeout waiting for response from " - "publickey subsystem"); - } - - if(data_len < 4) { - return _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "Publickey response too small"); - } - - s = data; - response = publickey_response_id(&s, data_len); - - switch(response) { - case LIBSSH2_PUBLICKEY_RESPONSE_STATUS: - /* Error, or processing complete */ - { - unsigned long status = 0; - - if(data_len < 8) { - return _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "Publickey response too small"); - } - - status = _libssh2_ntohu32(s); - - LIBSSH2_FREE(session, data); - - if(status == LIBSSH2_PUBLICKEY_SUCCESS) - return 0; - - publickey_status_error(pkey, session, status); - return -1; - } - default: - LIBSSH2_FREE(session, data); - if(response < 0) { - return _libssh2_error(session, - LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, - "Invalid publickey subsystem response"); - } - /* Unknown/Unexpected */ - _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, - "Unexpected publickey subsystem response"); - data = NULL; - } - } - /* never reached, but include `return` to silence compiler warnings */ - return -1; -} - -/* ***************** - * Publickey API * - ***************** */ - -/* - * publickey_init - * - * Startup the publickey subsystem - */ -static LIBSSH2_PUBLICKEY *publickey_init(LIBSSH2_SESSION *session) -{ - int response; - int rc; - - if(session->pkeyInit_state == libssh2_NB_state_idle) { - session->pkeyInit_data = NULL; - session->pkeyInit_pkey = NULL; - session->pkeyInit_channel = NULL; - - _libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, - "Initializing publickey subsystem"); - - session->pkeyInit_state = libssh2_NB_state_allocated; - } - - if(session->pkeyInit_state == libssh2_NB_state_allocated) { - - session->pkeyInit_channel = - _libssh2_channel_open(session, "session", - sizeof("session") - 1, - LIBSSH2_CHANNEL_WINDOW_DEFAULT, - LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, - 0); - if(!session->pkeyInit_channel) { - if(libssh2_session_last_errno(session) == LIBSSH2_ERROR_EAGAIN) - /* The error state is already set, so leave it */ - return NULL; - _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, - "Unable to startup channel"); - goto err_exit; - } - - session->pkeyInit_state = libssh2_NB_state_sent; - } - - if(session->pkeyInit_state == libssh2_NB_state_sent) { - rc = _libssh2_channel_process_startup(session->pkeyInit_channel, - "subsystem", - sizeof("subsystem") - 1, - "publickey", - sizeof("publickey") - 1); - if(rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block starting publickey subsystem"); - return NULL; - } - else if(rc) { - _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, - "Unable to request publickey subsystem"); - goto err_exit; - } - - session->pkeyInit_state = libssh2_NB_state_sent1; - } - - if(session->pkeyInit_state == libssh2_NB_state_sent1) { - unsigned char *s; - rc = _libssh2_channel_extended_data(session->pkeyInit_channel, - LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE); - if(rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block starting publickey subsystem"); - return NULL; - } - - session->pkeyInit_pkey = - LIBSSH2_CALLOC(session, sizeof(LIBSSH2_PUBLICKEY)); - if(!session->pkeyInit_pkey) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate a new publickey structure"); - goto err_exit; - } - session->pkeyInit_pkey->channel = session->pkeyInit_channel; - session->pkeyInit_pkey->version = 0; - - s = session->pkeyInit_buffer; - _libssh2_htonu32(s, 4 + (sizeof("version") - 1) + 4); - s += 4; - _libssh2_htonu32(s, sizeof("version") - 1); - s += 4; - memcpy(s, "version", sizeof("version") - 1); - s += sizeof("version") - 1; - _libssh2_htonu32(s, LIBSSH2_PUBLICKEY_VERSION); - - session->pkeyInit_buffer_sent = 0; - - _libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, - "Sending publickey advertising version %d support", - (int) LIBSSH2_PUBLICKEY_VERSION); - - session->pkeyInit_state = libssh2_NB_state_sent2; - } - - if(session->pkeyInit_state == libssh2_NB_state_sent2) { - rc = _libssh2_channel_write(session->pkeyInit_channel, 0, - session->pkeyInit_buffer, - 19 - session->pkeyInit_buffer_sent); - if(rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block sending publickey version packet"); - return NULL; - } - else if(rc < 0) { - _libssh2_error(session, rc, - "Unable to send publickey version packet"); - goto err_exit; - } - session->pkeyInit_buffer_sent += rc; - if(session->pkeyInit_buffer_sent < 19) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Need to be called again to complete this"); - return NULL; - } - - session->pkeyInit_state = libssh2_NB_state_sent3; - } - - if(session->pkeyInit_state == libssh2_NB_state_sent3) { - while(1) { - unsigned char *s; - rc = publickey_packet_receive(session->pkeyInit_pkey, - &session->pkeyInit_data, - &session->pkeyInit_data_len); - if(rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block waiting for response from " - "publickey subsystem"); - return NULL; - } - else if(rc) { - _libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, - "Timeout waiting for response from " - "publickey subsystem"); - goto err_exit; - } - - s = session->pkeyInit_data; - if((response = - publickey_response_id(&s, session->pkeyInit_data_len)) < 0) { - _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, - "Invalid publickey subsystem response code"); - goto err_exit; - } - - if(session->pkeyInit_data_len < 4) { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "Public key init data too small"); - goto err_exit; - } - - switch(response) { - case LIBSSH2_PUBLICKEY_RESPONSE_STATUS: - /* Error */ - { - unsigned long status, descr_len, lang_len; - - if(session->pkeyInit_data_len >= 8) { - status = _libssh2_ntohu32(s); - s += 4; - descr_len = _libssh2_ntohu32(s); - s += 4; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "Public key init data too small"); - goto err_exit; - } - - if(s + descr_len + 4 <= - session->pkeyInit_data + session->pkeyInit_data_len) { - /* description starts here */ - s += descr_len; - lang_len = _libssh2_ntohu32(s); - s += 4; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "Public key init data too small"); - goto err_exit; - } - - if(s + lang_len <= - session->pkeyInit_data + session->pkeyInit_data_len) { - /* lang starts here */ - s += lang_len; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "Public key init data too small"); - goto err_exit; - } - - if(s > - session->pkeyInit_data + session->pkeyInit_data_len) { - _libssh2_error(session, - LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, - "Malformed publickey subsystem packet"); - goto err_exit; - } - - publickey_status_error(NULL, session, status); - - goto err_exit; - } - - case LIBSSH2_PUBLICKEY_RESPONSE_VERSION: - /* What we want */ - session->pkeyInit_pkey->version = _libssh2_ntohu32(s); - if(session->pkeyInit_pkey->version > - LIBSSH2_PUBLICKEY_VERSION) { - _libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, - "Truncate remote publickey version " - "from %lu", - session->pkeyInit_pkey->version); - session->pkeyInit_pkey->version = - LIBSSH2_PUBLICKEY_VERSION; - } - _libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, - "Enabling publickey subsystem version %lu", - session->pkeyInit_pkey->version); - LIBSSH2_FREE(session, session->pkeyInit_data); - session->pkeyInit_data = NULL; - session->pkeyInit_state = libssh2_NB_state_idle; - return session->pkeyInit_pkey; - - default: - /* Unknown/Unexpected */ - _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, - "Unexpected publickey subsystem response, " - "ignoring"); - LIBSSH2_FREE(session, session->pkeyInit_data); - session->pkeyInit_data = NULL; - } - } - } - - /* Never reached except by direct goto */ - err_exit: - session->pkeyInit_state = libssh2_NB_state_sent4; - if(session->pkeyInit_channel) { - rc = _libssh2_channel_close(session->pkeyInit_channel); - if(rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block closing channel"); - return NULL; - } - } - if(session->pkeyInit_pkey) { - LIBSSH2_FREE(session, session->pkeyInit_pkey); - session->pkeyInit_pkey = NULL; - } - if(session->pkeyInit_data) { - LIBSSH2_FREE(session, session->pkeyInit_data); - session->pkeyInit_data = NULL; - } - session->pkeyInit_state = libssh2_NB_state_idle; - return NULL; -} - -/* - * libssh2_publickey_init - * - * Startup the publickey subsystem - */ -LIBSSH2_API LIBSSH2_PUBLICKEY * -libssh2_publickey_init(LIBSSH2_SESSION *session) -{ - LIBSSH2_PUBLICKEY *ptr; - - BLOCK_ADJUST_ERRNO(ptr, session, - publickey_init(session)); - return ptr; -} - - - -/* - * libssh2_publickey_add_ex - * - * Add a new public key entry - */ -LIBSSH2_API int -libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY *pkey, const unsigned char *name, - unsigned long name_len, const unsigned char *blob, - unsigned long blob_len, char overwrite, - unsigned long num_attrs, - const libssh2_publickey_attribute attrs[]) -{ - LIBSSH2_CHANNEL *channel; - LIBSSH2_SESSION *session; - /* 19 = packet_len(4) + add_len(4) + "add"(3) + name_len(4) + {name} - blob_len(4) + {blob} */ - unsigned long i, packet_len = 19 + name_len + blob_len; - unsigned char *comment = NULL; - unsigned long comment_len = 0; - int rc; - - if(!pkey) - return LIBSSH2_ERROR_BAD_USE; - - channel = pkey->channel; - session = channel->session; - - if(pkey->add_state == libssh2_NB_state_idle) { - pkey->add_packet = NULL; - - _libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, "Adding %s publickey", - name); - - if(pkey->version == 1) { - for(i = 0; i < num_attrs; i++) { - /* Search for a comment attribute */ - if(attrs[i].name_len == (sizeof("comment") - 1) && - strncmp(attrs[i].name, "comment", - sizeof("comment") - 1) == 0) { - comment = (unsigned char *) attrs[i].value; - comment_len = attrs[i].value_len; - break; - } - } - packet_len += 4 + comment_len; - } - else { - packet_len += 5; /* overwrite(1) + attribute_count(4) */ - for(i = 0; i < num_attrs; i++) { - packet_len += 9 + attrs[i].name_len + attrs[i].value_len; - /* name_len(4) + value_len(4) + mandatory(1) */ - } - } - - pkey->add_packet = LIBSSH2_ALLOC(session, packet_len); - if(!pkey->add_packet) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "publickey \"add\" packet"); - } - - pkey->add_s = pkey->add_packet; - _libssh2_htonu32(pkey->add_s, packet_len - 4); - pkey->add_s += 4; - _libssh2_htonu32(pkey->add_s, sizeof("add") - 1); - pkey->add_s += 4; - memcpy(pkey->add_s, "add", sizeof("add") - 1); - pkey->add_s += sizeof("add") - 1; - if(pkey->version == 1) { - _libssh2_htonu32(pkey->add_s, comment_len); - pkey->add_s += 4; - if(comment) { - memcpy(pkey->add_s, comment, comment_len); - pkey->add_s += comment_len; - } - - _libssh2_htonu32(pkey->add_s, name_len); - pkey->add_s += 4; - memcpy(pkey->add_s, name, name_len); - pkey->add_s += name_len; - _libssh2_htonu32(pkey->add_s, blob_len); - pkey->add_s += 4; - memcpy(pkey->add_s, blob, blob_len); - pkey->add_s += blob_len; - } - else { - /* Version == 2 */ - - _libssh2_htonu32(pkey->add_s, name_len); - pkey->add_s += 4; - memcpy(pkey->add_s, name, name_len); - pkey->add_s += name_len; - _libssh2_htonu32(pkey->add_s, blob_len); - pkey->add_s += 4; - memcpy(pkey->add_s, blob, blob_len); - pkey->add_s += blob_len; - *(pkey->add_s++) = overwrite ? 0x01 : 0; - _libssh2_htonu32(pkey->add_s, num_attrs); - pkey->add_s += 4; - for(i = 0; i < num_attrs; i++) { - _libssh2_htonu32(pkey->add_s, attrs[i].name_len); - pkey->add_s += 4; - memcpy(pkey->add_s, attrs[i].name, attrs[i].name_len); - pkey->add_s += attrs[i].name_len; - _libssh2_htonu32(pkey->add_s, attrs[i].value_len); - pkey->add_s += 4; - memcpy(pkey->add_s, attrs[i].value, attrs[i].value_len); - pkey->add_s += attrs[i].value_len; - *(pkey->add_s++) = attrs[i].mandatory ? 0x01 : 0; - } - } - - _libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, - "Sending publickey \"add\" packet: " - "type=%s blob_len=%ld num_attrs=%ld", - name, blob_len, num_attrs); - - pkey->add_state = libssh2_NB_state_created; - } - - if(pkey->add_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, pkey->add_packet, - (pkey->add_s - pkey->add_packet)); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if((pkey->add_s - pkey->add_packet) != rc) { - LIBSSH2_FREE(session, pkey->add_packet); - pkey->add_packet = NULL; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send publickey add packet"); - } - LIBSSH2_FREE(session, pkey->add_packet); - pkey->add_packet = NULL; - - pkey->add_state = libssh2_NB_state_sent; - } - - rc = publickey_response_success(pkey); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - - pkey->add_state = libssh2_NB_state_idle; - - return rc; -} - -/* libssh2_publickey_remove_ex - * Remove an existing publickey so that authentication can no longer be - * performed using it - */ -LIBSSH2_API int -libssh2_publickey_remove_ex(LIBSSH2_PUBLICKEY * pkey, - const unsigned char *name, unsigned long name_len, - const unsigned char *blob, unsigned long blob_len) -{ - LIBSSH2_CHANNEL *channel; - LIBSSH2_SESSION *session; - /* 22 = packet_len(4) + remove_len(4) + "remove"(6) + name_len(4) + {name} - + blob_len(4) + {blob} */ - unsigned long packet_len = 22 + name_len + blob_len; - int rc; - - if(!pkey) - return LIBSSH2_ERROR_BAD_USE; - - channel = pkey->channel; - session = channel->session; - - if(pkey->remove_state == libssh2_NB_state_idle) { - pkey->remove_packet = NULL; - - pkey->remove_packet = LIBSSH2_ALLOC(session, packet_len); - if(!pkey->remove_packet) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "publickey \"remove\" packet"); - } - - pkey->remove_s = pkey->remove_packet; - _libssh2_htonu32(pkey->remove_s, packet_len - 4); - pkey->remove_s += 4; - _libssh2_htonu32(pkey->remove_s, sizeof("remove") - 1); - pkey->remove_s += 4; - memcpy(pkey->remove_s, "remove", sizeof("remove") - 1); - pkey->remove_s += sizeof("remove") - 1; - _libssh2_htonu32(pkey->remove_s, name_len); - pkey->remove_s += 4; - memcpy(pkey->remove_s, name, name_len); - pkey->remove_s += name_len; - _libssh2_htonu32(pkey->remove_s, blob_len); - pkey->remove_s += 4; - memcpy(pkey->remove_s, blob, blob_len); - pkey->remove_s += blob_len; - - _libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, - "Sending publickey \"remove\" packet: " - "type=%s blob_len=%ld", - name, blob_len); - - pkey->remove_state = libssh2_NB_state_created; - } - - if(pkey->remove_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, pkey->remove_packet, - (pkey->remove_s - pkey->remove_packet)); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if((pkey->remove_s - pkey->remove_packet) != rc) { - LIBSSH2_FREE(session, pkey->remove_packet); - pkey->remove_packet = NULL; - pkey->remove_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send publickey remove packet"); - } - LIBSSH2_FREE(session, pkey->remove_packet); - pkey->remove_packet = NULL; - - pkey->remove_state = libssh2_NB_state_sent; - } - - rc = publickey_response_success(pkey); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - - pkey->remove_state = libssh2_NB_state_idle; - - return rc; -} - -/* libssh2_publickey_list_fetch - * Fetch a list of supported public key from a server - */ -LIBSSH2_API int -libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY * pkey, unsigned long *num_keys, - libssh2_publickey_list ** pkey_list) -{ - LIBSSH2_CHANNEL *channel; - LIBSSH2_SESSION *session; - libssh2_publickey_list *list = NULL; - unsigned long buffer_len = 12, keys = 0, max_keys = 0, i; - /* 12 = packet_len(4) + list_len(4) + "list"(4) */ - int response; - int rc; - - if(!pkey) - return LIBSSH2_ERROR_BAD_USE; - - channel = pkey->channel; - session = channel->session; - - if(pkey->listFetch_state == libssh2_NB_state_idle) { - pkey->listFetch_data = NULL; - - pkey->listFetch_s = pkey->listFetch_buffer; - _libssh2_htonu32(pkey->listFetch_s, buffer_len - 4); - pkey->listFetch_s += 4; - _libssh2_htonu32(pkey->listFetch_s, sizeof("list") - 1); - pkey->listFetch_s += 4; - memcpy(pkey->listFetch_s, "list", sizeof("list") - 1); - pkey->listFetch_s += sizeof("list") - 1; - - _libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, - "Sending publickey \"list\" packet"); - - pkey->listFetch_state = libssh2_NB_state_created; - } - - if(pkey->listFetch_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, - pkey->listFetch_buffer, - (pkey->listFetch_s - - pkey->listFetch_buffer)); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if((pkey->listFetch_s - pkey->listFetch_buffer) != rc) { - pkey->listFetch_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send publickey list packet"); - } - - pkey->listFetch_state = libssh2_NB_state_sent; - } - - while(1) { - rc = publickey_packet_receive(pkey, &pkey->listFetch_data, - &pkey->listFetch_data_len); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc) { - _libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, - "Timeout waiting for response from " - "publickey subsystem"); - goto err_exit; - } - - pkey->listFetch_s = pkey->listFetch_data; - if((response = - publickey_response_id(&pkey->listFetch_s, - pkey->listFetch_data_len)) < 0) { - _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, - "Invalid publickey subsystem response code"); - goto err_exit; - } - - switch(response) { - case LIBSSH2_PUBLICKEY_RESPONSE_STATUS: - /* Error, or processing complete */ - { - unsigned long status, descr_len, lang_len; - - if(pkey->listFetch_s + 8 <= - pkey->listFetch_data + pkey->listFetch_data_len) { - status = _libssh2_ntohu32(pkey->listFetch_s); - pkey->listFetch_s += 4; - descr_len = _libssh2_ntohu32(pkey->listFetch_s); - pkey->listFetch_s += 4; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "ListFetch data too short"); - goto err_exit; - } - - if(pkey->listFetch_s + descr_len + 4 <= - pkey->listFetch_data + pkey->listFetch_data_len) { - /* description starts at pkey->listFetch_s */ - pkey->listFetch_s += descr_len; - lang_len = _libssh2_ntohu32(pkey->listFetch_s); - pkey->listFetch_s += 4; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "ListFetch data too short"); - goto err_exit; - } - - if(pkey->listFetch_s + lang_len <= - pkey->listFetch_data + pkey->listFetch_data_len) { - /* lang starts at pkey->listFetch_s */ - pkey->listFetch_s += lang_len; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "ListFetch data too short"); - goto err_exit; - } - - if(pkey->listFetch_s > - pkey->listFetch_data + pkey->listFetch_data_len) { - _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, - "Malformed publickey subsystem packet"); - goto err_exit; - } - - if(status == LIBSSH2_PUBLICKEY_SUCCESS) { - LIBSSH2_FREE(session, pkey->listFetch_data); - pkey->listFetch_data = NULL; - *pkey_list = list; - *num_keys = keys; - pkey->listFetch_state = libssh2_NB_state_idle; - return 0; - } - - publickey_status_error(pkey, session, status); - goto err_exit; - } - case LIBSSH2_PUBLICKEY_RESPONSE_PUBLICKEY: - /* What we want */ - if(keys >= max_keys) { - libssh2_publickey_list *newlist; - /* Grow the key list if necessary */ - max_keys += 8; - newlist = - LIBSSH2_REALLOC(session, list, - (max_keys + - 1) * sizeof(libssh2_publickey_list)); - if(!newlist) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "publickey list"); - goto err_exit; - } - list = newlist; - } - if(pkey->version == 1) { - unsigned long comment_len; - - if(pkey->listFetch_s + 4 <= - pkey->listFetch_data + pkey->listFetch_data_len) { - comment_len = _libssh2_ntohu32(pkey->listFetch_s); - pkey->listFetch_s += 4; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "ListFetch data too short"); - goto err_exit; - } - - if(comment_len) { - list[keys].num_attrs = 1; - list[keys].attrs = - LIBSSH2_ALLOC(session, - sizeof(libssh2_publickey_attribute)); - if(!list[keys].attrs) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "publickey attributes"); - goto err_exit; - } - list[keys].attrs[0].name = "comment"; - list[keys].attrs[0].name_len = sizeof("comment") - 1; - list[keys].attrs[0].value = (char *) pkey->listFetch_s; - list[keys].attrs[0].value_len = comment_len; - list[keys].attrs[0].mandatory = 0; - - pkey->listFetch_s += comment_len; - } - else { - list[keys].num_attrs = 0; - list[keys].attrs = NULL; - } - - if(pkey->listFetch_s + 4 <= - pkey->listFetch_data + pkey->listFetch_data_len) { - list[keys].name_len = _libssh2_ntohu32(pkey->listFetch_s); - pkey->listFetch_s += 4; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "ListFetch data too short"); - goto err_exit; - } - - if(pkey->listFetch_s + list[keys].name_len <= - pkey->listFetch_data + pkey->listFetch_data_len) { - list[keys].name = pkey->listFetch_s; - pkey->listFetch_s += list[keys].name_len; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "ListFetch data too short"); - goto err_exit; - } - - if(pkey->listFetch_s + 4 <= - pkey->listFetch_data + pkey->listFetch_data_len) { - list[keys].blob_len = _libssh2_ntohu32(pkey->listFetch_s); - pkey->listFetch_s += 4; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "ListFetch data too short"); - goto err_exit; - } - - if(pkey->listFetch_s + list[keys].blob_len <= - pkey->listFetch_data + pkey->listFetch_data_len) { - list[keys].blob = pkey->listFetch_s; - pkey->listFetch_s += list[keys].blob_len; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "ListFetch data too short"); - goto err_exit; - } - } - else { - /* Version == 2 */ - - if(pkey->listFetch_s + 4 <= - pkey->listFetch_data + pkey->listFetch_data_len) { - list[keys].name_len = _libssh2_ntohu32(pkey->listFetch_s); - pkey->listFetch_s += 4; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "ListFetch data too short"); - goto err_exit; - } - - if(pkey->listFetch_s + list[keys].name_len <= - pkey->listFetch_data + pkey->listFetch_data_len) { - list[keys].name = pkey->listFetch_s; - pkey->listFetch_s += list[keys].name_len; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "ListFetch data too short"); - goto err_exit; - } - - if(pkey->listFetch_s + 4 <= - pkey->listFetch_data + pkey->listFetch_data_len) { - list[keys].blob_len = _libssh2_ntohu32(pkey->listFetch_s); - pkey->listFetch_s += 4; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "ListFetch data too short"); - goto err_exit; - } - - if(pkey->listFetch_s + list[keys].blob_len <= - pkey->listFetch_data + pkey->listFetch_data_len) { - list[keys].blob = pkey->listFetch_s; - pkey->listFetch_s += list[keys].blob_len; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "ListFetch data too short"); - goto err_exit; - } - - if(pkey->listFetch_s + 4 <= - pkey->listFetch_data + pkey->listFetch_data_len) { - list[keys].num_attrs = _libssh2_ntohu32(pkey->listFetch_s); - pkey->listFetch_s += 4; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "ListFetch data too short"); - goto err_exit; - } - - if(list[keys].num_attrs) { - list[keys].attrs = - LIBSSH2_ALLOC(session, - list[keys].num_attrs * - sizeof(libssh2_publickey_attribute)); - if(!list[keys].attrs) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "publickey attributes"); - goto err_exit; - } - for(i = 0; i < list[keys].num_attrs; i++) { - if(pkey->listFetch_s + 4 <= - pkey->listFetch_data + pkey->listFetch_data_len) { - list[keys].attrs[i].name_len = - _libssh2_ntohu32(pkey->listFetch_s); - pkey->listFetch_s += 4; - } - else { - _libssh2_error(session, - LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "ListFetch data too short"); - goto err_exit; - } - - if(pkey->listFetch_s + list[keys].attrs[i].name_len <= - pkey->listFetch_data + pkey->listFetch_data_len) { - list[keys].attrs[i].name = - (char *) pkey->listFetch_s; - pkey->listFetch_s += list[keys].attrs[i].name_len; - } - else { - _libssh2_error(session, - LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "ListFetch data too short"); - goto err_exit; - } - - if(pkey->listFetch_s + 4 <= - pkey->listFetch_data + pkey->listFetch_data_len) { - list[keys].attrs[i].value_len = - _libssh2_ntohu32(pkey->listFetch_s); - pkey->listFetch_s += 4; - } - else { - _libssh2_error(session, - LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "ListFetch data too short"); - goto err_exit; - } - - if(pkey->listFetch_s + - list[keys].attrs[i].value_len <= - pkey->listFetch_data + pkey->listFetch_data_len) { - list[keys].attrs[i].value = - (char *) pkey->listFetch_s; - pkey->listFetch_s += list[keys].attrs[i].value_len; - } - else { - _libssh2_error(session, - LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "ListFetch data too short"); - goto err_exit; - } - - /* actually an ignored value */ - list[keys].attrs[i].mandatory = 0; - } - } - else { - list[keys].attrs = NULL; - } - } - /* To be FREEd in libssh2_publickey_list_free() */ - list[keys].packet = pkey->listFetch_data; - keys++; - - list[keys].packet = NULL; /* Terminate the list */ - pkey->listFetch_data = NULL; - break; - default: - /* Unknown/Unexpected */ - _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, - "Unexpected publickey subsystem response"); - LIBSSH2_FREE(session, pkey->listFetch_data); - pkey->listFetch_data = NULL; - } - } - - /* Only reached via explicit goto */ - err_exit: - if(pkey->listFetch_data) { - LIBSSH2_FREE(session, pkey->listFetch_data); - pkey->listFetch_data = NULL; - } - if(list) { - libssh2_publickey_list_free(pkey, list); - } - pkey->listFetch_state = libssh2_NB_state_idle; - return -1; -} - -/* libssh2_publickey_list_free - * Free a previously fetched list of public keys - */ -LIBSSH2_API void -libssh2_publickey_list_free(LIBSSH2_PUBLICKEY * pkey, - libssh2_publickey_list * pkey_list) -{ - LIBSSH2_SESSION *session; - libssh2_publickey_list *p = pkey_list; - - if(!pkey || !p) - return; - - session = pkey->channel->session; - - while(p->packet) { - if(p->attrs) { - LIBSSH2_FREE(session, p->attrs); - } - LIBSSH2_FREE(session, p->packet); - p++; - } - - LIBSSH2_FREE(session, pkey_list); -} - -/* libssh2_publickey_shutdown - * Shutdown the publickey subsystem - */ -LIBSSH2_API int -libssh2_publickey_shutdown(LIBSSH2_PUBLICKEY *pkey) -{ - LIBSSH2_SESSION *session; - int rc; - - if(!pkey) - return LIBSSH2_ERROR_BAD_USE; - - session = pkey->channel->session; - - /* - * Make sure all memory used in the state variables are free - */ - if(pkey->receive_packet) { - LIBSSH2_FREE(session, pkey->receive_packet); - pkey->receive_packet = NULL; - } - if(pkey->add_packet) { - LIBSSH2_FREE(session, pkey->add_packet); - pkey->add_packet = NULL; - } - if(pkey->remove_packet) { - LIBSSH2_FREE(session, pkey->remove_packet); - pkey->remove_packet = NULL; - } - if(pkey->listFetch_data) { - LIBSSH2_FREE(session, pkey->listFetch_data); - pkey->listFetch_data = NULL; - } - - rc = _libssh2_channel_free(pkey->channel); - if(rc == LIBSSH2_ERROR_EAGAIN) - return rc; - - LIBSSH2_FREE(session, pkey); - return 0; -} diff --git a/libssh2/scp.c b/libssh2/scp.c deleted file mode 100644 index a9d2db5..0000000 --- a/libssh2/scp.c +++ /dev/null @@ -1,1145 +0,0 @@ -/* Copyright (c) 2009-2019 by Daniel Stenberg - * Copyright (c) 2004-2008, Sara Golemon - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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 "libssh2_priv.h" -#include -#include - -#include "channel.h" -#include "session.h" - - -/* Max. length of a quoted string after libssh2_shell_quotearg() processing */ -#define _libssh2_shell_quotedsize(s) (3 * strlen(s) + 2) - -/* - This function quotes a string in a way suitable to be used with a - shell, e.g. the file name - one two - becomes - 'one two' - - The resulting output string is crafted in a way that makes it usable - with the two most common shell types: Bourne Shell derived shells - (sh, ksh, ksh93, bash, zsh) and C-Shell derivates (csh, tcsh). - - The following special cases are handled: - o If the string contains an apostrophy itself, the apostrophy - character is written in quotation marks, e.g. "'". - The shell cannot handle the syntax 'doesn\'t', so we close the - current argument word, add the apostrophe in quotation marks "", - and open a new argument word instead (_ indicate the input - string characters): - _____ _ _ - 'doesn' "'" 't' - - Sequences of apostrophes are combined in one pair of quotation marks: - a'''b - becomes - _ ___ _ - 'a'"'''"'b' - - o If the string contains an exclamation mark (!), the C-Shell - interprets it as an event number. Using \! (not within quotation - marks or single quotation marks) is a mechanism understood by - both Bourne Shell and C-Shell. - - If a quotation was already started, the argument word is closed - first: - a!b - - become - _ _ _ - 'a'\!'b' - - The result buffer must be large enough for the expanded result. A - bad case regarding expansion is alternating characters and - apostrophes: - - a'b'c'd' (length 8) gets converted to - 'a'"'"'b'"'"'c'"'"'d'"'" (length 24) - - This is the worst case. - - Maximum length of the result: - 1 + 6 * (length(input) + 1) / 2) + 1 - - => 3 * length(input) + 2 - - Explanation: - o leading apostrophe - o one character / apostrophe pair (two characters) can get - represented as 6 characters: a' -> a'"'"' - o String terminator (+1) - - A result buffer three times the size of the input buffer + 2 - characters should be safe. - - References: - o csh-compatible quotation (special handling for '!' etc.), see - http://www.grymoire.com/Unix/Csh.html#toc-uh-10 - - Return value: - Length of the resulting string (not counting the terminating '\0'), - or 0 in case of errors, e.g. result buffer too small - - Note: this function could possible be used elsewhere within libssh2, but - until then it is kept static and in this source file. -*/ - -static unsigned -shell_quotearg(const char *path, unsigned char *buf, - unsigned bufsize) -{ - const char *src; - unsigned char *dst, *endp; - - /* - * Processing States: - * UQSTRING: unquoted string: ... -- used for quoting exclamation - * marks. This is the initial state - * SQSTRING: single-quoted-string: '... -- any character may follow - * QSTRING: quoted string: "... -- only apostrophes may follow - */ - enum { UQSTRING, SQSTRING, QSTRING } state = UQSTRING; - - endp = &buf[bufsize]; - src = path; - dst = buf; - while(*src && dst < endp - 1) { - - switch(*src) { - /* - * Special handling for apostrophe. - * An apostrophe is always written in quotation marks, e.g. - * ' -> "'". - */ - - case '\'': - switch(state) { - case UQSTRING: /* Unquoted string */ - if(dst + 1 >= endp) - return 0; - *dst++ = '"'; - break; - case QSTRING: /* Continue quoted string */ - break; - case SQSTRING: /* Close single quoted string */ - if(dst + 2 >= endp) - return 0; - *dst++ = '\''; - *dst++ = '"'; - break; - default: - break; - } - state = QSTRING; - break; - - /* - * Special handling for exclamation marks. CSH interprets - * exclamation marks even when quoted with apostrophes. We convert - * it to the plain string \!, because both Bourne Shell and CSH - * interpret that as a verbatim exclamation mark. - */ - - case '!': - switch(state) { - case UQSTRING: - if(dst + 1 >= endp) - return 0; - *dst++ = '\\'; - break; - case QSTRING: - if(dst + 2 >= endp) - return 0; - *dst++ = '"'; /* Closing quotation mark */ - *dst++ = '\\'; - break; - case SQSTRING: /* Close single quoted string */ - if(dst + 2 >= endp) - return 0; - *dst++ = '\''; - *dst++ = '\\'; - break; - default: - break; - } - state = UQSTRING; - break; - - /* - * Ordinary character: prefer single-quoted string - */ - - default: - switch(state) { - case UQSTRING: - if(dst + 1 >= endp) - return 0; - *dst++ = '\''; - break; - case QSTRING: - if(dst + 2 >= endp) - return 0; - *dst++ = '"'; /* Closing quotation mark */ - *dst++ = '\''; - break; - case SQSTRING: /* Continue single quoted string */ - break; - default: - break; - } - state = SQSTRING; /* Start single-quoted string */ - break; - } - - if(dst + 1 >= endp) - return 0; - *dst++ = *src++; - } - - switch(state) { - case UQSTRING: - break; - case QSTRING: /* Close quoted string */ - if(dst + 1 >= endp) - return 0; - *dst++ = '"'; - break; - case SQSTRING: /* Close single quoted string */ - if(dst + 1 >= endp) - return 0; - *dst++ = '\''; - break; - default: - break; - } - - if(dst + 1 >= endp) - return 0; - *dst = '\0'; - - /* The result cannot be larger than 3 * strlen(path) + 2 */ - /* assert((dst - buf) <= (3 * (src - path) + 2)); */ - - return dst - buf; -} - -/* - * scp_recv - * - * Open a channel and request a remote file via SCP - * - */ -static LIBSSH2_CHANNEL * -scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) -{ - int cmd_len; - int rc; - int tmp_err_code; - const char *tmp_err_msg; - - if(session->scpRecv_state == libssh2_NB_state_idle) { - session->scpRecv_mode = 0; - session->scpRecv_size = 0; - session->scpRecv_mtime = 0; - session->scpRecv_atime = 0; - - session->scpRecv_command_len = - _libssh2_shell_quotedsize(path) + sizeof("scp -f ") + (sb?1:0); - - session->scpRecv_command = - LIBSSH2_ALLOC(session, session->scpRecv_command_len); - - if(!session->scpRecv_command) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate a command buffer for " - "SCP session"); - return NULL; - } - - snprintf((char *)session->scpRecv_command, - session->scpRecv_command_len, - "scp -%sf ", sb?"p":""); - - cmd_len = strlen((char *)session->scpRecv_command); - cmd_len += shell_quotearg(path, - &session->scpRecv_command[cmd_len], - session->scpRecv_command_len - cmd_len); - - /* the command to exec should _not_ be NUL-terminated */ - session->scpRecv_command_len = cmd_len; - - _libssh2_debug(session, LIBSSH2_TRACE_SCP, - "Opening channel for SCP receive"); - - session->scpRecv_state = libssh2_NB_state_created; - } - - if(session->scpRecv_state == libssh2_NB_state_created) { - /* Allocate a channel */ - session->scpRecv_channel = - _libssh2_channel_open(session, "session", - sizeof("session") - 1, - LIBSSH2_CHANNEL_WINDOW_DEFAULT, - LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, - 0); - if(!session->scpRecv_channel) { - if(libssh2_session_last_errno(session) != - LIBSSH2_ERROR_EAGAIN) { - LIBSSH2_FREE(session, session->scpRecv_command); - session->scpRecv_command = NULL; - session->scpRecv_state = libssh2_NB_state_idle; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block starting up channel"); - } - return NULL; - } - - session->scpRecv_state = libssh2_NB_state_sent; - } - - if(session->scpRecv_state == libssh2_NB_state_sent) { - /* Request SCP for the desired file */ - rc = _libssh2_channel_process_startup(session->scpRecv_channel, "exec", - sizeof("exec") - 1, - (char *)session->scpRecv_command, - session->scpRecv_command_len); - if(rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block requesting SCP startup"); - return NULL; - } - else if(rc) { - LIBSSH2_FREE(session, session->scpRecv_command); - session->scpRecv_command = NULL; - goto scp_recv_error; - } - LIBSSH2_FREE(session, session->scpRecv_command); - session->scpRecv_command = NULL; - - _libssh2_debug(session, LIBSSH2_TRACE_SCP, "Sending initial wakeup"); - /* SCP ACK */ - session->scpRecv_response[0] = '\0'; - - session->scpRecv_state = libssh2_NB_state_sent1; - } - - if(session->scpRecv_state == libssh2_NB_state_sent1) { - rc = _libssh2_channel_write(session->scpRecv_channel, 0, - session->scpRecv_response, 1); - if(rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block sending initial wakeup"); - return NULL; - } - else if(rc != 1) { - goto scp_recv_error; - } - - /* Parse SCP response */ - session->scpRecv_response_len = 0; - - session->scpRecv_state = libssh2_NB_state_sent2; - } - - if((session->scpRecv_state == libssh2_NB_state_sent2) - || (session->scpRecv_state == libssh2_NB_state_sent3)) { - while(sb && (session->scpRecv_response_len < - LIBSSH2_SCP_RESPONSE_BUFLEN)) { - unsigned char *s, *p; - - if(session->scpRecv_state == libssh2_NB_state_sent2) { - rc = _libssh2_channel_read(session->scpRecv_channel, 0, - (char *) session-> - scpRecv_response + - session->scpRecv_response_len, 1); - if(rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block waiting for SCP response"); - return NULL; - } - else if(rc < 0) { - /* error, give up */ - _libssh2_error(session, rc, "Failed reading SCP response"); - goto scp_recv_error; - } - else if(rc == 0) - goto scp_recv_empty_channel; - - session->scpRecv_response_len++; - - if(session->scpRecv_response[0] != 'T') { - size_t err_len; - char *err_msg; - - /* there can be - 01 for warnings - 02 for errors - - The following string MUST be newline terminated - */ - err_len = - _libssh2_channel_packet_data_len(session-> - scpRecv_channel, 0); - err_msg = LIBSSH2_ALLOC(session, err_len + 1); - if(!err_msg) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Failed to get memory "); - goto scp_recv_error; - } - - /* Read the remote error message */ - (void)_libssh2_channel_read(session->scpRecv_channel, 0, - err_msg, err_len); - /* If it failed for any reason, we ignore it anyway. */ - - /* zero terminate the error */ - err_msg[err_len] = 0; - - _libssh2_debug(session, LIBSSH2_TRACE_SCP, - "got %02x %s", session->scpRecv_response[0], - err_msg); - - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Failed to recv file"); - - LIBSSH2_FREE(session, err_msg); - goto scp_recv_error; - } - - if((session->scpRecv_response_len > 1) && - ((session-> - scpRecv_response[session->scpRecv_response_len - 1] < - '0') - || (session-> - scpRecv_response[session->scpRecv_response_len - 1] > - '9')) - && (session-> - scpRecv_response[session->scpRecv_response_len - 1] != - ' ') - && (session-> - scpRecv_response[session->scpRecv_response_len - 1] != - '\r') - && (session-> - scpRecv_response[session->scpRecv_response_len - 1] != - '\n')) { - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Invalid data in SCP response"); - goto scp_recv_error; - } - - if((session->scpRecv_response_len < 9) - || (session-> - scpRecv_response[session->scpRecv_response_len - 1] != - '\n')) { - if(session->scpRecv_response_len == - LIBSSH2_SCP_RESPONSE_BUFLEN) { - /* You had your chance */ - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Unterminated response from " - "SCP server"); - goto scp_recv_error; - } - /* Way too short to be an SCP response, or not done yet, - short circuit */ - continue; - } - - /* We're guaranteed not to go under response_len == 0 by the - logic above */ - while((session-> - scpRecv_response[session->scpRecv_response_len - 1] == - '\r') - || (session-> - scpRecv_response[session->scpRecv_response_len - - 1] == '\n')) - session->scpRecv_response_len--; - session->scpRecv_response[session->scpRecv_response_len] = - '\0'; - - if(session->scpRecv_response_len < 8) { - /* EOL came too soon */ - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Invalid response from SCP server, " - "too short"); - goto scp_recv_error; - } - - s = session->scpRecv_response + 1; - - p = (unsigned char *) strchr((char *) s, ' '); - if(!p || ((p - s) <= 0)) { - /* No spaces or space in the wrong spot */ - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Invalid response from SCP server, " - "malformed mtime"); - goto scp_recv_error; - } - - *(p++) = '\0'; - /* Make sure we don't get fooled by leftover values */ - session->scpRecv_mtime = strtol((char *) s, NULL, 10); - - s = (unsigned char *) strchr((char *) p, ' '); - if(!s || ((s - p) <= 0)) { - /* No spaces or space in the wrong spot */ - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Invalid response from SCP server, " - "malformed mtime.usec"); - goto scp_recv_error; - } - - /* Ignore mtime.usec */ - s++; - p = (unsigned char *) strchr((char *) s, ' '); - if(!p || ((p - s) <= 0)) { - /* No spaces or space in the wrong spot */ - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Invalid response from SCP server, " - "too short or malformed"); - goto scp_recv_error; - } - - *p = '\0'; - /* Make sure we don't get fooled by leftover values */ - session->scpRecv_atime = strtol((char *) s, NULL, 10); - - /* SCP ACK */ - session->scpRecv_response[0] = '\0'; - - session->scpRecv_state = libssh2_NB_state_sent3; - } - - if(session->scpRecv_state == libssh2_NB_state_sent3) { - rc = _libssh2_channel_write(session->scpRecv_channel, 0, - session->scpRecv_response, 1); - if(rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block waiting to send SCP ACK"); - return NULL; - } - else if(rc != 1) { - goto scp_recv_error; - } - - _libssh2_debug(session, LIBSSH2_TRACE_SCP, - "mtime = %ld, atime = %ld", - session->scpRecv_mtime, session->scpRecv_atime); - - /* We *should* check that atime.usec is valid, but why let - that stop use? */ - break; - } - } - - session->scpRecv_state = libssh2_NB_state_sent4; - } - - if(session->scpRecv_state == libssh2_NB_state_sent4) { - session->scpRecv_response_len = 0; - - session->scpRecv_state = libssh2_NB_state_sent5; - } - - if((session->scpRecv_state == libssh2_NB_state_sent5) - || (session->scpRecv_state == libssh2_NB_state_sent6)) { - while(session->scpRecv_response_len < LIBSSH2_SCP_RESPONSE_BUFLEN) { - char *s, *p, *e = NULL; - - if(session->scpRecv_state == libssh2_NB_state_sent5) { - rc = _libssh2_channel_read(session->scpRecv_channel, 0, - (char *) session-> - scpRecv_response + - session->scpRecv_response_len, 1); - if(rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block waiting for SCP response"); - return NULL; - } - else if(rc < 0) { - /* error, bail out*/ - _libssh2_error(session, rc, "Failed reading SCP response"); - goto scp_recv_error; - } - else if(rc == 0) - goto scp_recv_empty_channel; - - session->scpRecv_response_len++; - - if(session->scpRecv_response[0] != 'C') { - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Invalid response from SCP server"); - goto scp_recv_error; - } - - if((session->scpRecv_response_len > 1) && - (session-> - scpRecv_response[session->scpRecv_response_len - 1] != - '\r') - && (session-> - scpRecv_response[session->scpRecv_response_len - 1] != - '\n') - && - (session-> - scpRecv_response[session->scpRecv_response_len - 1] - < 32)) { - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Invalid data in SCP response"); - goto scp_recv_error; - } - - if((session->scpRecv_response_len < 7) - || (session-> - scpRecv_response[session->scpRecv_response_len - 1] != - '\n')) { - if(session->scpRecv_response_len == - LIBSSH2_SCP_RESPONSE_BUFLEN) { - /* You had your chance */ - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Unterminated response " - "from SCP server"); - goto scp_recv_error; - } - /* Way too short to be an SCP response, or not done yet, - short circuit */ - continue; - } - - /* We're guaranteed not to go under response_len == 0 by the - logic above */ - while((session-> - scpRecv_response[session->scpRecv_response_len - 1] == - '\r') - || (session-> - scpRecv_response[session->scpRecv_response_len - - 1] == '\n')) { - session->scpRecv_response_len--; - } - session->scpRecv_response[session->scpRecv_response_len] = - '\0'; - - if(session->scpRecv_response_len < 6) { - /* EOL came too soon */ - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Invalid response from SCP server, " - "too short"); - goto scp_recv_error; - } - - s = (char *) session->scpRecv_response + 1; - - p = strchr(s, ' '); - if(!p || ((p - s) <= 0)) { - /* No spaces or space in the wrong spot */ - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Invalid response from SCP server, " - "malformed mode"); - goto scp_recv_error; - } - - *(p++) = '\0'; - /* Make sure we don't get fooled by leftover values */ - - session->scpRecv_mode = strtol(s, &e, 8); - if(e && *e) { - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Invalid response from SCP server, " - "invalid mode"); - goto scp_recv_error; - } - - s = strchr(p, ' '); - if(!s || ((s - p) <= 0)) { - /* No spaces or space in the wrong spot */ - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Invalid response from SCP server, " - "too short or malformed"); - goto scp_recv_error; - } - - *s = '\0'; - /* Make sure we don't get fooled by leftover values */ - session->scpRecv_size = scpsize_strtol(p, &e, 10); - if(e && *e) { - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Invalid response from SCP server, " - "invalid size"); - goto scp_recv_error; - } - - /* SCP ACK */ - session->scpRecv_response[0] = '\0'; - - session->scpRecv_state = libssh2_NB_state_sent6; - } - - if(session->scpRecv_state == libssh2_NB_state_sent6) { - rc = _libssh2_channel_write(session->scpRecv_channel, 0, - session->scpRecv_response, 1); - if(rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block sending SCP ACK"); - return NULL; - } - else if(rc != 1) { - goto scp_recv_error; - } - _libssh2_debug(session, LIBSSH2_TRACE_SCP, - "mode = 0%lo size = %ld", session->scpRecv_mode, - session->scpRecv_size); - - /* We *should* check that basename is valid, but why let that - stop us? */ - break; - } - } - - session->scpRecv_state = libssh2_NB_state_sent7; - } - - if(sb) { - memset(sb, 0, sizeof(libssh2_struct_stat)); - - sb->st_mtime = session->scpRecv_mtime; - sb->st_atime = session->scpRecv_atime; - sb->st_size = session->scpRecv_size; - sb->st_mode = (unsigned short)session->scpRecv_mode; - } - - session->scpRecv_state = libssh2_NB_state_idle; - return session->scpRecv_channel; - - scp_recv_empty_channel: - /* the code only jumps here as a result of a zero read from channel_read() - so we check EOF status to avoid getting stuck in a loop */ - if(libssh2_channel_eof(session->scpRecv_channel)) - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Unexpected channel close"); - else - return session->scpRecv_channel; - /* fall-through */ - scp_recv_error: - tmp_err_code = session->err_code; - tmp_err_msg = session->err_msg; - while(libssh2_channel_free(session->scpRecv_channel) == - LIBSSH2_ERROR_EAGAIN); - session->err_code = tmp_err_code; - session->err_msg = tmp_err_msg; - session->scpRecv_channel = NULL; - session->scpRecv_state = libssh2_NB_state_idle; - return NULL; -} - -/* - * libssh2_scp_recv - * - * DEPRECATED - * - * Open a channel and request a remote file via SCP. This receives files - * larger than 2 GB, but is unable to report the proper size on platforms - * where the st_size member of struct stat is limited to 2 GB (e.g. windows). - * - */ -LIBSSH2_API LIBSSH2_CHANNEL * -libssh2_scp_recv(LIBSSH2_SESSION *session, const char *path, struct stat * sb) -{ - LIBSSH2_CHANNEL *ptr; - - /* scp_recv uses libssh2_struct_stat, so pass one if the caller gave us a - struct to populate... */ - libssh2_struct_stat sb_intl; - libssh2_struct_stat *sb_ptr; - memset(&sb_intl, 0, sizeof(sb_intl)); - sb_ptr = sb ? &sb_intl : NULL; - - BLOCK_ADJUST_ERRNO(ptr, session, scp_recv(session, path, sb_ptr)); - - /* ...and populate the caller's with as much info as fits. */ - if(sb) { - memset(sb, 0, sizeof(struct stat)); - - sb->st_mtime = sb_intl.st_mtime; - sb->st_atime = sb_intl.st_atime; - sb->st_size = (off_t)sb_intl.st_size; - sb->st_mode = sb_intl.st_mode; - } - - return ptr; -} - -/* - * libssh2_scp_recv2 - * - * Open a channel and request a remote file via SCP. This supports files > 2GB - * on platforms that support it. - * - */ -LIBSSH2_API LIBSSH2_CHANNEL * -libssh2_scp_recv2(LIBSSH2_SESSION *session, const char *path, - libssh2_struct_stat *sb) -{ - LIBSSH2_CHANNEL *ptr; - BLOCK_ADJUST_ERRNO(ptr, session, scp_recv(session, path, sb)); - return ptr; -} - -/* - * scp_send() - * - * Send a file using SCP - * - */ -static LIBSSH2_CHANNEL * -scp_send(LIBSSH2_SESSION * session, const char *path, int mode, - libssh2_int64_t size, time_t mtime, time_t atime) -{ - int cmd_len; - int rc; - int tmp_err_code; - const char *tmp_err_msg; - - if(session->scpSend_state == libssh2_NB_state_idle) { - session->scpSend_command_len = - _libssh2_shell_quotedsize(path) + sizeof("scp -t ") + - ((mtime || atime)?1:0); - - session->scpSend_command = - LIBSSH2_ALLOC(session, session->scpSend_command_len); - - if(!session->scpSend_command) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate a command buffer for " - "SCP session"); - return NULL; - } - - snprintf((char *)session->scpSend_command, - session->scpSend_command_len, - "scp -%st ", (mtime || atime)?"p":""); - - cmd_len = strlen((char *)session->scpSend_command); - cmd_len += shell_quotearg(path, - &session->scpSend_command[cmd_len], - session->scpSend_command_len - cmd_len); - - /* the command to exec should _not_ be NUL-terminated */ - session->scpSend_command_len = cmd_len; - - _libssh2_debug(session, LIBSSH2_TRACE_SCP, - "Opening channel for SCP send"); - /* Allocate a channel */ - - session->scpSend_state = libssh2_NB_state_created; - } - - if(session->scpSend_state == libssh2_NB_state_created) { - session->scpSend_channel = - _libssh2_channel_open(session, "session", sizeof("session") - 1, - LIBSSH2_CHANNEL_WINDOW_DEFAULT, - LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0); - if(!session->scpSend_channel) { - if(libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN) { - /* previous call set libssh2_session_last_error(), pass it - through */ - LIBSSH2_FREE(session, session->scpSend_command); - session->scpSend_command = NULL; - session->scpSend_state = libssh2_NB_state_idle; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block starting up channel"); - } - return NULL; - } - - session->scpSend_state = libssh2_NB_state_sent; - } - - if(session->scpSend_state == libssh2_NB_state_sent) { - /* Request SCP for the desired file */ - rc = _libssh2_channel_process_startup(session->scpSend_channel, "exec", - sizeof("exec") - 1, - (char *)session->scpSend_command, - session->scpSend_command_len); - if(rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block requesting SCP startup"); - return NULL; - } - else if(rc) { - /* previous call set libssh2_session_last_error(), pass it - through */ - LIBSSH2_FREE(session, session->scpSend_command); - session->scpSend_command = NULL; - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Unknown error while getting error string"); - goto scp_send_error; - } - LIBSSH2_FREE(session, session->scpSend_command); - session->scpSend_command = NULL; - - session->scpSend_state = libssh2_NB_state_sent1; - } - - if(session->scpSend_state == libssh2_NB_state_sent1) { - /* Wait for ACK */ - rc = _libssh2_channel_read(session->scpSend_channel, 0, - (char *) session->scpSend_response, 1); - if(rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block waiting for response from remote"); - return NULL; - } - else if(rc < 0) { - _libssh2_error(session, rc, "SCP failure"); - goto scp_send_error; - } - else if(!rc) - /* remain in the same state */ - goto scp_send_empty_channel; - else if(session->scpSend_response[0] != 0) { - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Invalid ACK response from remote"); - goto scp_send_error; - } - if(mtime || atime) { - /* Send mtime and atime to be used for file */ - session->scpSend_response_len = - snprintf((char *) session->scpSend_response, - LIBSSH2_SCP_RESPONSE_BUFLEN, "T%ld 0 %ld 0\n", - (long)mtime, (long)atime); - _libssh2_debug(session, LIBSSH2_TRACE_SCP, "Sent %s", - session->scpSend_response); - } - - session->scpSend_state = libssh2_NB_state_sent2; - } - - /* Send mtime and atime to be used for file */ - if(mtime || atime) { - if(session->scpSend_state == libssh2_NB_state_sent2) { - rc = _libssh2_channel_write(session->scpSend_channel, 0, - session->scpSend_response, - session->scpSend_response_len); - if(rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block sending time data for SCP file"); - return NULL; - } - else if(rc != (int)session->scpSend_response_len) { - _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send time data for SCP file"); - goto scp_send_error; - } - - session->scpSend_state = libssh2_NB_state_sent3; - } - - if(session->scpSend_state == libssh2_NB_state_sent3) { - /* Wait for ACK */ - rc = _libssh2_channel_read(session->scpSend_channel, 0, - (char *) session->scpSend_response, 1); - if(rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block waiting for response"); - return NULL; - } - else if(rc < 0) { - _libssh2_error(session, rc, "SCP failure"); - goto scp_send_error; - } - else if(!rc) - /* remain in the same state */ - goto scp_send_empty_channel; - else if(session->scpSend_response[0] != 0) { - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Invalid SCP ACK response"); - goto scp_send_error; - } - - session->scpSend_state = libssh2_NB_state_sent4; - } - } - else { - if(session->scpSend_state == libssh2_NB_state_sent2) { - session->scpSend_state = libssh2_NB_state_sent4; - } - } - - if(session->scpSend_state == libssh2_NB_state_sent4) { - /* Send mode, size, and basename */ - const char *base = strrchr(path, '/'); - if(base) - base++; - else - base = path; - - session->scpSend_response_len = - snprintf((char *) session->scpSend_response, - LIBSSH2_SCP_RESPONSE_BUFLEN, "C0%o %" - LIBSSH2_INT64_T_FORMAT " %s\n", mode, - size, base); - _libssh2_debug(session, LIBSSH2_TRACE_SCP, "Sent %s", - session->scpSend_response); - - session->scpSend_state = libssh2_NB_state_sent5; - } - - if(session->scpSend_state == libssh2_NB_state_sent5) { - rc = _libssh2_channel_write(session->scpSend_channel, 0, - session->scpSend_response, - session->scpSend_response_len); - if(rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block send core file data for SCP file"); - return NULL; - } - else if(rc != (int)session->scpSend_response_len) { - _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send core file data for SCP file"); - goto scp_send_error; - } - - session->scpSend_state = libssh2_NB_state_sent6; - } - - if(session->scpSend_state == libssh2_NB_state_sent6) { - /* Wait for ACK */ - rc = _libssh2_channel_read(session->scpSend_channel, 0, - (char *) session->scpSend_response, 1); - if(rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block waiting for response"); - return NULL; - } - else if(rc < 0) { - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Invalid ACK response from remote"); - goto scp_send_error; - } - else if(rc == 0) - goto scp_send_empty_channel; - - else if(session->scpSend_response[0] != 0) { - size_t err_len; - char *err_msg; - - err_len = - _libssh2_channel_packet_data_len(session->scpSend_channel, 0); - err_msg = LIBSSH2_ALLOC(session, err_len + 1); - if(!err_msg) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "failed to get memory"); - goto scp_send_error; - } - - /* Read the remote error message */ - rc = _libssh2_channel_read(session->scpSend_channel, 0, - err_msg, err_len); - if(rc > 0) { - err_msg[err_len] = 0; - _libssh2_debug(session, LIBSSH2_TRACE_SCP, - "got %02x %s", session->scpSend_response[0], - err_msg); - } - LIBSSH2_FREE(session, err_msg); - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "failed to send file"); - goto scp_send_error; - } - } - - session->scpSend_state = libssh2_NB_state_idle; - return session->scpSend_channel; - - scp_send_empty_channel: - /* the code only jumps here as a result of a zero read from channel_read() - so we check EOF status to avoid getting stuck in a loop */ - if(libssh2_channel_eof(session->scpSend_channel)) { - _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, - "Unexpected channel close"); - } - else - return session->scpSend_channel; - /* fall-through */ - scp_send_error: - tmp_err_code = session->err_code; - tmp_err_msg = session->err_msg; - while(libssh2_channel_free(session->scpSend_channel) == - LIBSSH2_ERROR_EAGAIN); - session->err_code = tmp_err_code; - session->err_msg = tmp_err_msg; - session->scpSend_channel = NULL; - session->scpSend_state = libssh2_NB_state_idle; - return NULL; -} - -/* - * libssh2_scp_send_ex - * - * Send a file using SCP. Old API. - */ -LIBSSH2_API LIBSSH2_CHANNEL * -libssh2_scp_send_ex(LIBSSH2_SESSION *session, const char *path, int mode, - size_t size, long mtime, long atime) -{ - LIBSSH2_CHANNEL *ptr; - BLOCK_ADJUST_ERRNO(ptr, session, - scp_send(session, path, mode, size, - (time_t)mtime, (time_t)atime)); - return ptr; -} - -/* - * libssh2_scp_send64 - * - * Send a file using SCP - */ -LIBSSH2_API LIBSSH2_CHANNEL * -libssh2_scp_send64(LIBSSH2_SESSION *session, const char *path, int mode, - libssh2_int64_t size, time_t mtime, time_t atime) -{ - LIBSSH2_CHANNEL *ptr; - BLOCK_ADJUST_ERRNO(ptr, session, - scp_send(session, path, mode, size, mtime, atime)); - return ptr; -} diff --git a/libssh2/session.c b/libssh2/session.c deleted file mode 100644 index 256eb99..0000000 --- a/libssh2/session.c +++ /dev/null @@ -1,1832 +0,0 @@ -/* Copyright (c) 2004-2007 Sara Golemon - * Copyright (c) 2009-2015 by Daniel Stenberg - * Copyright (c) 2010 Simon Josefsson - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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 "libssh2_priv.h" -#include -#ifdef HAVE_UNISTD_H -#include -#endif -#include -#include - -#ifdef HAVE_GETTIMEOFDAY -#include -#endif -#ifdef HAVE_ALLOCA_H -#include -#endif - -#include "transport.h" -#include "session.h" -#include "channel.h" -#include "mac.h" -#include "misc.h" - -/* libssh2_default_alloc - */ -static -LIBSSH2_ALLOC_FUNC(libssh2_default_alloc) -{ - (void) abstract; - return malloc(count); -} - -/* libssh2_default_free - */ -static -LIBSSH2_FREE_FUNC(libssh2_default_free) -{ - (void) abstract; - free(ptr); -} - -/* libssh2_default_realloc - */ -static -LIBSSH2_REALLOC_FUNC(libssh2_default_realloc) -{ - (void) abstract; - return realloc(ptr, count); -} - -/* - * banner_receive - * - * Wait for a hello from the remote host - * Allocate a buffer and store the banner in session->remote.banner - * Returns: 0 on success, LIBSSH2_ERROR_EAGAIN if read would block, negative - * on failure - */ -static int -banner_receive(LIBSSH2_SESSION * session) -{ - int ret; - int banner_len; - - if(session->banner_TxRx_state == libssh2_NB_state_idle) { - banner_len = 0; - - session->banner_TxRx_state = libssh2_NB_state_created; - } - else { - banner_len = session->banner_TxRx_total_send; - } - - while((banner_len < (int) sizeof(session->banner_TxRx_banner)) && - ((banner_len == 0) - || (session->banner_TxRx_banner[banner_len - 1] != '\n'))) { - char c = '\0'; - - /* no incoming block yet! */ - session->socket_block_directions &= ~LIBSSH2_SESSION_BLOCK_INBOUND; - - ret = LIBSSH2_RECV(session, &c, 1, - LIBSSH2_SOCKET_RECV_FLAGS(session)); - if(ret < 0) { - if(session->api_block_mode || (ret != -EAGAIN)) - /* ignore EAGAIN when non-blocking */ - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, - "Error recving %d bytes: %d", 1, -ret); - } - else - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, - "Recved %d bytes banner", ret); - - if(ret < 0) { - if(ret == -EAGAIN) { - session->socket_block_directions = - LIBSSH2_SESSION_BLOCK_INBOUND; - session->banner_TxRx_total_send = banner_len; - return LIBSSH2_ERROR_EAGAIN; - } - - /* Some kinda error */ - session->banner_TxRx_state = libssh2_NB_state_idle; - session->banner_TxRx_total_send = 0; - return LIBSSH2_ERROR_SOCKET_RECV; - } - - if(ret == 0) { - session->socket_state = LIBSSH2_SOCKET_DISCONNECTED; - return LIBSSH2_ERROR_SOCKET_DISCONNECT; - } - - if(c == '\0') { - /* NULLs are not allowed in SSH banners */ - session->banner_TxRx_state = libssh2_NB_state_idle; - session->banner_TxRx_total_send = 0; - return LIBSSH2_ERROR_BANNER_RECV; - } - - session->banner_TxRx_banner[banner_len++] = c; - } - - while(banner_len && - ((session->banner_TxRx_banner[banner_len - 1] == '\n') || - (session->banner_TxRx_banner[banner_len - 1] == '\r'))) { - banner_len--; - } - - /* From this point on, we are done here */ - session->banner_TxRx_state = libssh2_NB_state_idle; - session->banner_TxRx_total_send = 0; - - if(!banner_len) - return LIBSSH2_ERROR_BANNER_RECV; - - if(session->remote.banner) - LIBSSH2_FREE(session, session->remote.banner); - - session->remote.banner = LIBSSH2_ALLOC(session, banner_len + 1); - if(!session->remote.banner) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Error allocating space for remote banner"); - } - memcpy(session->remote.banner, session->banner_TxRx_banner, banner_len); - session->remote.banner[banner_len] = '\0'; - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Received Banner: %s", - session->remote.banner); - return LIBSSH2_ERROR_NONE; -} - -/* - * banner_send - * - * Send the default banner, or the one set via libssh2_setopt_string - * - * Returns LIBSSH2_ERROR_EAGAIN if it would block - and if it does so, you - * should call this function again as soon as it is likely that more data can - * be sent, and this function should then be called with the same argument set - * (same data pointer and same data_len) until zero or failure is returned. - */ -static int -banner_send(LIBSSH2_SESSION * session) -{ - char *banner = (char *) LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF; - int banner_len = sizeof(LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF) - 1; - ssize_t ret; -#ifdef LIBSSH2DEBUG - char banner_dup[256]; -#endif - - if(session->banner_TxRx_state == libssh2_NB_state_idle) { - if(session->local.banner) { - /* setopt_string will have given us our \r\n characters */ - banner_len = strlen((char *) session->local.banner); - banner = (char *) session->local.banner; - } -#ifdef LIBSSH2DEBUG - /* Hack and slash to avoid sending CRLF in debug output */ - if(banner_len < 256) { - memcpy(banner_dup, banner, banner_len - 2); - banner_dup[banner_len - 2] = '\0'; - } - else { - memcpy(banner_dup, banner, 255); - banner[255] = '\0'; - } - - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Sending Banner: %s", - banner_dup); -#endif - - session->banner_TxRx_state = libssh2_NB_state_created; - } - - /* no outgoing block yet! */ - session->socket_block_directions &= ~LIBSSH2_SESSION_BLOCK_OUTBOUND; - - ret = LIBSSH2_SEND(session, - banner + session->banner_TxRx_total_send, - banner_len - session->banner_TxRx_total_send, - LIBSSH2_SOCKET_SEND_FLAGS(session)); - if(ret < 0) - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, - "Error sending %d bytes: %d", - banner_len - session->banner_TxRx_total_send, -ret); - else - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, - "Sent %d/%d bytes at %p+%d", ret, - banner_len - session->banner_TxRx_total_send, - banner, session->banner_TxRx_total_send); - - if(ret != (banner_len - session->banner_TxRx_total_send)) { - if(ret >= 0 || ret == -EAGAIN) { - /* the whole packet could not be sent, save the what was */ - session->socket_block_directions = - LIBSSH2_SESSION_BLOCK_OUTBOUND; - if(ret > 0) - session->banner_TxRx_total_send += ret; - return LIBSSH2_ERROR_EAGAIN; - } - session->banner_TxRx_state = libssh2_NB_state_idle; - session->banner_TxRx_total_send = 0; - return LIBSSH2_ERROR_SOCKET_RECV; - } - - /* Set the state back to idle */ - session->banner_TxRx_state = libssh2_NB_state_idle; - session->banner_TxRx_total_send = 0; - - return 0; -} - -/* - * session_nonblock() sets the given socket to either blocking or - * non-blocking mode based on the 'nonblock' boolean argument. This function - * is copied from the libcurl sources with permission. - */ -static int -session_nonblock(libssh2_socket_t sockfd, /* operate on this */ - int nonblock /* TRUE or FALSE */ ) -{ -#undef SETBLOCK -#define SETBLOCK 0 -#ifdef HAVE_O_NONBLOCK - /* most recent unix versions */ - int flags; - - flags = fcntl(sockfd, F_GETFL, 0); - if(nonblock) - return fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); - else - return fcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK)); -#undef SETBLOCK -#define SETBLOCK 1 -#endif - -#if defined(HAVE_FIONBIO) && (SETBLOCK == 0) - /* older unix versions and VMS*/ - int flags; - - flags = nonblock; - return ioctl(sockfd, FIONBIO, &flags); -#undef SETBLOCK -#define SETBLOCK 2 -#endif - -#if defined(HAVE_IOCTLSOCKET) && (SETBLOCK == 0) - /* Windows? */ - unsigned long flags; - flags = nonblock; - - return ioctlsocket(sockfd, FIONBIO, &flags); -#undef SETBLOCK -#define SETBLOCK 3 -#endif - -#if defined(HAVE_IOCTLSOCKET_CASE) && (SETBLOCK == 0) - /* presumably for Amiga */ - return IoctlSocket(sockfd, FIONBIO, (long) nonblock); -#undef SETBLOCK -#define SETBLOCK 4 -#endif - -#if defined(HAVE_SO_NONBLOCK) && (SETBLOCK == 0) - /* BeOS */ - long b = nonblock ? 1 : 0; - return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b)); -#undef SETBLOCK -#define SETBLOCK 5 -#endif - -#ifdef HAVE_DISABLED_NONBLOCKING - return 0; /* returns success */ -#undef SETBLOCK -#define SETBLOCK 6 -#endif - -#if(SETBLOCK == 0) -#error "no non-blocking method was found/used/set" -#endif -} - -/* - * get_socket_nonblocking() - * - * gets the given blocking or non-blocking state of the socket. - */ -static int -get_socket_nonblocking(int sockfd) -{ /* operate on this */ -#undef GETBLOCK -#define GETBLOCK 0 -#ifdef HAVE_O_NONBLOCK - /* most recent unix versions */ - int flags = fcntl(sockfd, F_GETFL, 0); - - if(flags == -1) { - /* Assume blocking on error */ - return 1; - } - return (flags & O_NONBLOCK); -#undef GETBLOCK -#define GETBLOCK 1 -#endif - -#if defined(WSAEWOULDBLOCK) && (GETBLOCK == 0) - /* Windows? */ - unsigned int option_value; - socklen_t option_len = sizeof(option_value); - - if(getsockopt - (sockfd, SOL_SOCKET, SO_ERROR, (void *) &option_value, &option_len)) { - /* Assume blocking on error */ - return 1; - } - return (int) option_value; -#undef GETBLOCK -#define GETBLOCK 2 -#endif - -#if defined(HAVE_SO_NONBLOCK) && (GETBLOCK == 0) - /* BeOS */ - long b; - if(getsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b))) { - /* Assume blocking on error */ - return 1; - } - return (int) b; -#undef GETBLOCK -#define GETBLOCK 5 -#endif - -#if defined(SO_STATE) && defined(__VMS) && (GETBLOCK == 0) - - /* VMS TCP/IP Services */ - - size_t sockstat = 0; - int callstat = 0; - size_t size = sizeof(int); - - callstat = getsockopt(sockfd, SOL_SOCKET, SO_STATE, - (char *)&sockstat, &size); - if(callstat == -1) return 0; - if((sockstat&SS_NBIO) != 0) return 1; - return 0; - -#undef GETBLOCK -#define GETBLOCK 6 -#endif - -#ifdef HAVE_DISABLED_NONBLOCKING - return 1; /* returns blocking */ -#undef GETBLOCK -#define GETBLOCK 7 -#endif - -#if(GETBLOCK == 0) -#error "no non-blocking method was found/used/get" -#endif -} - -/* libssh2_session_banner_set - * Set the local banner to use in the server handshake. - */ -LIBSSH2_API int -libssh2_session_banner_set(LIBSSH2_SESSION * session, const char *banner) -{ - size_t banner_len = banner ? strlen(banner) : 0; - - if(session->local.banner) { - LIBSSH2_FREE(session, session->local.banner); - session->local.banner = NULL; - } - - if(!banner_len) - return 0; - - session->local.banner = LIBSSH2_ALLOC(session, banner_len + 3); - if(!session->local.banner) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for local banner"); - } - - memcpy(session->local.banner, banner, banner_len); - - /* first zero terminate like this so that the debug output is nice */ - session->local.banner[banner_len] = '\0'; - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Setting local Banner: %s", - session->local.banner); - session->local.banner[banner_len++] = '\r'; - session->local.banner[banner_len++] = '\n'; - session->local.banner[banner_len] = '\0'; - - return 0; -} - -/* libssh2_banner_set - * Set the local banner. DEPRECATED VERSION - */ -LIBSSH2_API int -libssh2_banner_set(LIBSSH2_SESSION * session, const char *banner) -{ - return libssh2_session_banner_set(session, banner); -} - -/* - * libssh2_session_init_ex - * - * Allocate and initialize a libssh2 session structure. Allows for malloc - * callbacks in case the calling program has its own memory manager It's - * allowable (but unadvisable) to define some but not all of the malloc - * callbacks An additional pointer value may be optionally passed to be sent - * to the callbacks (so they know who's asking) - */ -LIBSSH2_API LIBSSH2_SESSION * -libssh2_session_init_ex(LIBSSH2_ALLOC_FUNC((*my_alloc)), - LIBSSH2_FREE_FUNC((*my_free)), - LIBSSH2_REALLOC_FUNC((*my_realloc)), void *abstract) -{ - LIBSSH2_ALLOC_FUNC((*local_alloc)) = libssh2_default_alloc; - LIBSSH2_FREE_FUNC((*local_free)) = libssh2_default_free; - LIBSSH2_REALLOC_FUNC((*local_realloc)) = libssh2_default_realloc; - LIBSSH2_SESSION *session; - - if(my_alloc) { - local_alloc = my_alloc; - } - if(my_free) { - local_free = my_free; - } - if(my_realloc) { - local_realloc = my_realloc; - } - - session = local_alloc(sizeof(LIBSSH2_SESSION), &abstract); - if(session) { - memset(session, 0, sizeof(LIBSSH2_SESSION)); - session->alloc = local_alloc; - session->free = local_free; - session->realloc = local_realloc; - session->send = _libssh2_send; - session->recv = _libssh2_recv; - session->abstract = abstract; - session->api_timeout = 0; /* timeout-free API by default */ - session->api_block_mode = 1; /* blocking API by default */ - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "New session resource allocated"); - _libssh2_init_if_needed(); - } - return session; -} - -/* - * libssh2_session_callback_set - * - * Set (or reset) a callback function - * Returns the prior address - * - * ALERT: this function relies on that we can typecast function pointers - * to void pointers, which isn't allowed in ISO C! - */ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wpedantic" -LIBSSH2_API void * -libssh2_session_callback_set(LIBSSH2_SESSION * session, - int cbtype, void *callback) -{ - void *oldcb; - - switch(cbtype) { - case LIBSSH2_CALLBACK_IGNORE: - oldcb = session->ssh_msg_ignore; - session->ssh_msg_ignore = callback; - return oldcb; - - case LIBSSH2_CALLBACK_DEBUG: - oldcb = session->ssh_msg_debug; - session->ssh_msg_debug = callback; - return oldcb; - - case LIBSSH2_CALLBACK_DISCONNECT: - oldcb = session->ssh_msg_disconnect; - session->ssh_msg_disconnect = callback; - return oldcb; - - case LIBSSH2_CALLBACK_MACERROR: - oldcb = session->macerror; - session->macerror = callback; - return oldcb; - - case LIBSSH2_CALLBACK_X11: - oldcb = session->x11; - session->x11 = callback; - return oldcb; - - case LIBSSH2_CALLBACK_SEND: - oldcb = session->send; - session->send = callback; - return oldcb; - - case LIBSSH2_CALLBACK_RECV: - oldcb = session->recv; - session->recv = callback; - return oldcb; - } - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Setting Callback %d", - cbtype); - - return NULL; -} -#pragma GCC diagnostic pop - -/* - * _libssh2_wait_socket() - * - * Utility function that waits for action on the socket. Returns 0 when ready - * to run again or error on timeout. - */ -int _libssh2_wait_socket(LIBSSH2_SESSION *session, time_t start_time) -{ - int rc; - int seconds_to_next; - int dir; - int has_timeout; - long ms_to_next = 0; - long elapsed_ms; - - /* since libssh2 often sets EAGAIN internally before this function is - called, we can decrease some amount of confusion in user programs by - resetting the error code in this function to reduce the risk of EAGAIN - being stored as error when a blocking function has returned */ - session->err_code = LIBSSH2_ERROR_NONE; - - rc = libssh2_keepalive_send(session, &seconds_to_next); - if(rc) - return rc; - - ms_to_next = seconds_to_next * 1000; - - /* figure out what to wait for */ - dir = libssh2_session_block_directions(session); - - if(!dir) { - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, - "Nothing to wait for in wait_socket"); - /* To avoid that we hang below just because there's nothing set to - wait for, we timeout on 1 second to also avoid busy-looping - during this condition */ - ms_to_next = 1000; - } - - if(session->api_timeout > 0 && - (seconds_to_next == 0 || - ms_to_next > session->api_timeout)) { - time_t now = time(NULL); - elapsed_ms = (long)(1000*difftime(now, start_time)); - if(elapsed_ms > session->api_timeout) { - return _libssh2_error(session, LIBSSH2_ERROR_TIMEOUT, - "API timeout expired"); - } - ms_to_next = (session->api_timeout - elapsed_ms); - has_timeout = 1; - } - else if(ms_to_next > 0) { - has_timeout = 1; - } - else - has_timeout = 0; - -#ifdef HAVE_POLL - { - struct pollfd sockets[1]; - - sockets[0].fd = session->socket_fd; - sockets[0].events = 0; - sockets[0].revents = 0; - - if(dir & LIBSSH2_SESSION_BLOCK_INBOUND) - sockets[0].events |= POLLIN; - - if(dir & LIBSSH2_SESSION_BLOCK_OUTBOUND) - sockets[0].events |= POLLOUT; - - rc = poll(sockets, 1, has_timeout?ms_to_next: -1); - } -#else - { - fd_set rfd; - fd_set wfd; - fd_set *writefd = NULL; - fd_set *readfd = NULL; - struct timeval tv; - - tv.tv_sec = ms_to_next / 1000; - tv.tv_usec = (ms_to_next - tv.tv_sec*1000) * 1000; - - if(dir & LIBSSH2_SESSION_BLOCK_INBOUND) { - FD_ZERO(&rfd); - FD_SET(session->socket_fd, &rfd); - readfd = &rfd; - } - - if(dir & LIBSSH2_SESSION_BLOCK_OUTBOUND) { - FD_ZERO(&wfd); - FD_SET(session->socket_fd, &wfd); - writefd = &wfd; - } - - rc = select(session->socket_fd + 1, readfd, writefd, NULL, - has_timeout ? &tv : NULL); - } -#endif - if(rc == 0) { - return _libssh2_error(session, LIBSSH2_ERROR_TIMEOUT, - "Timed out waiting on socket"); - } - if(rc < 0) { - return _libssh2_error(session, LIBSSH2_ERROR_TIMEOUT, - "Error waiting on socket"); - } - - return 0; /* ready to try again */ -} - -static int -session_startup(LIBSSH2_SESSION *session, libssh2_socket_t sock) -{ - int rc; - - if(session->startup_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "session_startup for socket %d", sock); - if(LIBSSH2_INVALID_SOCKET == sock) { - /* Did we forget something? */ - return _libssh2_error(session, LIBSSH2_ERROR_BAD_SOCKET, - "Bad socket provided"); - } - session->socket_fd = sock; - - session->socket_prev_blockstate = - !get_socket_nonblocking(session->socket_fd); - - if(session->socket_prev_blockstate) { - /* If in blocking state change to non-blocking */ - rc = session_nonblock(session->socket_fd, 1); - if(rc) { - return _libssh2_error(session, rc, - "Failed changing socket's " - "blocking state to non-blocking"); - } - } - - session->startup_state = libssh2_NB_state_created; - } - - if(session->startup_state == libssh2_NB_state_created) { - rc = banner_send(session); - if(rc == LIBSSH2_ERROR_EAGAIN) - return rc; - else if(rc) { - return _libssh2_error(session, rc, - "Failed sending banner"); - } - session->startup_state = libssh2_NB_state_sent; - session->banner_TxRx_state = libssh2_NB_state_idle; - } - - if(session->startup_state == libssh2_NB_state_sent) { - do { - rc = banner_receive(session); - if(rc == LIBSSH2_ERROR_EAGAIN) - return rc; - else if(rc) - return _libssh2_error(session, rc, - "Failed getting banner"); - } while(strncmp("SSH-", (char *)session->remote.banner, 4)); - - session->startup_state = libssh2_NB_state_sent1; - } - - if(session->startup_state == libssh2_NB_state_sent1) { - rc = _libssh2_kex_exchange(session, 0, &session->startup_key_state); - if(rc == LIBSSH2_ERROR_EAGAIN) - return rc; - else if(rc) - return _libssh2_error(session, rc, - "Unable to exchange encryption keys"); - - session->startup_state = libssh2_NB_state_sent2; - } - - if(session->startup_state == libssh2_NB_state_sent2) { - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "Requesting userauth service"); - - /* Request the userauth service */ - session->startup_service[0] = SSH_MSG_SERVICE_REQUEST; - _libssh2_htonu32(session->startup_service + 1, - sizeof("ssh-userauth") - 1); - memcpy(session->startup_service + 5, "ssh-userauth", - sizeof("ssh-userauth") - 1); - - session->startup_state = libssh2_NB_state_sent3; - } - - if(session->startup_state == libssh2_NB_state_sent3) { - rc = _libssh2_transport_send(session, session->startup_service, - sizeof("ssh-userauth") + 5 - 1, - NULL, 0); - if(rc == LIBSSH2_ERROR_EAGAIN) - return rc; - else if(rc) { - return _libssh2_error(session, rc, - "Unable to ask for ssh-userauth service"); - } - - session->startup_state = libssh2_NB_state_sent4; - } - - if(session->startup_state == libssh2_NB_state_sent4) { - rc = _libssh2_packet_require(session, SSH_MSG_SERVICE_ACCEPT, - &session->startup_data, - &session->startup_data_len, 0, NULL, 0, - &session->startup_req_state); - if(rc) - return rc; - - if(session->startup_data_len < 5) { - return _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unexpected packet length"); - } - - session->startup_service_length = - _libssh2_ntohu32(session->startup_data + 1); - - - if((session->startup_service_length != (sizeof("ssh-userauth") - 1)) - || strncmp("ssh-userauth", (char *) session->startup_data + 5, - session->startup_service_length)) { - LIBSSH2_FREE(session, session->startup_data); - session->startup_data = NULL; - return _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Invalid response received from server"); - } - LIBSSH2_FREE(session, session->startup_data); - session->startup_data = NULL; - - session->startup_state = libssh2_NB_state_idle; - - return 0; - } - - /* just for safety return some error */ - return LIBSSH2_ERROR_INVAL; -} - -/* - * libssh2_session_handshake() - * - * session: LIBSSH2_SESSION struct allocated and owned by the calling program - * sock: *must* be populated with an opened and connected socket. - * - * Returns: 0 on success, or non-zero on failure - */ -LIBSSH2_API int -libssh2_session_handshake(LIBSSH2_SESSION *session, libssh2_socket_t sock) -{ - int rc; - - BLOCK_ADJUST(rc, session, session_startup(session, sock) ); - - return rc; -} - -/* - * libssh2_session_startup() - * - * DEPRECATED. Use libssh2_session_handshake() instead! This function is not - * portable enough. - * - * session: LIBSSH2_SESSION struct allocated and owned by the calling program - * sock: *must* be populated with an opened and connected socket. - * - * Returns: 0 on success, or non-zero on failure - */ -LIBSSH2_API int -libssh2_session_startup(LIBSSH2_SESSION *session, int sock) -{ - return libssh2_session_handshake(session, (libssh2_socket_t) sock); -} - -/* - * libssh2_session_free - * - * Frees the memory allocated to the session - * Also closes and frees any channels attached to this session - */ -static int -session_free(LIBSSH2_SESSION *session) -{ - int rc; - LIBSSH2_PACKET *pkg; - LIBSSH2_CHANNEL *ch; - LIBSSH2_LISTENER *l; - int packets_left = 0; - - if(session->free_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "Freeing session resource", - session->remote.banner); - - session->free_state = libssh2_NB_state_created; - } - - if(session->free_state == libssh2_NB_state_created) { - while((ch = _libssh2_list_first(&session->channels))) { - - rc = _libssh2_channel_free(ch); - if(rc == LIBSSH2_ERROR_EAGAIN) - return rc; - } - - session->free_state = libssh2_NB_state_sent; - } - - if(session->free_state == libssh2_NB_state_sent) { - while((l = _libssh2_list_first(&session->listeners))) { - rc = _libssh2_channel_forward_cancel(l); - if(rc == LIBSSH2_ERROR_EAGAIN) - return rc; - } - - session->free_state = libssh2_NB_state_sent1; - } - - if(session->state & LIBSSH2_STATE_NEWKEYS) { - /* hostkey */ - if(session->hostkey && session->hostkey->dtor) { - session->hostkey->dtor(session, &session->server_hostkey_abstract); - } - - /* Client to Server */ - /* crypt */ - if(session->local.crypt && session->local.crypt->dtor) { - session->local.crypt->dtor(session, - &session->local.crypt_abstract); - } - /* comp */ - if(session->local.comp && session->local.comp->dtor) { - session->local.comp->dtor(session, 1, - &session->local.comp_abstract); - } - /* mac */ - if(session->local.mac && session->local.mac->dtor) { - session->local.mac->dtor(session, &session->local.mac_abstract); - } - - /* Server to Client */ - /* crypt */ - if(session->remote.crypt && session->remote.crypt->dtor) { - session->remote.crypt->dtor(session, - &session->remote.crypt_abstract); - } - /* comp */ - if(session->remote.comp && session->remote.comp->dtor) { - session->remote.comp->dtor(session, 0, - &session->remote.comp_abstract); - } - /* mac */ - if(session->remote.mac && session->remote.mac->dtor) { - session->remote.mac->dtor(session, &session->remote.mac_abstract); - } - - /* session_id */ - if(session->session_id) { - LIBSSH2_FREE(session, session->session_id); - } - } - - /* Free banner(s) */ - if(session->remote.banner) { - LIBSSH2_FREE(session, session->remote.banner); - } - if(session->local.banner) { - LIBSSH2_FREE(session, session->local.banner); - } - - /* Free preference(s) */ - if(session->kex_prefs) { - LIBSSH2_FREE(session, session->kex_prefs); - } - if(session->hostkey_prefs) { - LIBSSH2_FREE(session, session->hostkey_prefs); - } - - if(session->local.kexinit) { - LIBSSH2_FREE(session, session->local.kexinit); - } - if(session->local.crypt_prefs) { - LIBSSH2_FREE(session, session->local.crypt_prefs); - } - if(session->local.mac_prefs) { - LIBSSH2_FREE(session, session->local.mac_prefs); - } - if(session->local.comp_prefs) { - LIBSSH2_FREE(session, session->local.comp_prefs); - } - if(session->local.lang_prefs) { - LIBSSH2_FREE(session, session->local.lang_prefs); - } - - if(session->remote.kexinit) { - LIBSSH2_FREE(session, session->remote.kexinit); - } - if(session->remote.crypt_prefs) { - LIBSSH2_FREE(session, session->remote.crypt_prefs); - } - if(session->remote.mac_prefs) { - LIBSSH2_FREE(session, session->remote.mac_prefs); - } - if(session->remote.comp_prefs) { - LIBSSH2_FREE(session, session->remote.comp_prefs); - } - if(session->remote.lang_prefs) { - LIBSSH2_FREE(session, session->remote.lang_prefs); - } - - /* - * Make sure all memory used in the state variables are free - */ - if(session->kexinit_data) { - LIBSSH2_FREE(session, session->kexinit_data); - } - if(session->startup_data) { - LIBSSH2_FREE(session, session->startup_data); - } - if(session->userauth_list_data) { - LIBSSH2_FREE(session, session->userauth_list_data); - } - if(session->userauth_pswd_data) { - LIBSSH2_FREE(session, session->userauth_pswd_data); - } - if(session->userauth_pswd_newpw) { - LIBSSH2_FREE(session, session->userauth_pswd_newpw); - } - if(session->userauth_host_packet) { - LIBSSH2_FREE(session, session->userauth_host_packet); - } - if(session->userauth_host_method) { - LIBSSH2_FREE(session, session->userauth_host_method); - } - if(session->userauth_host_data) { - LIBSSH2_FREE(session, session->userauth_host_data); - } - if(session->userauth_pblc_data) { - LIBSSH2_FREE(session, session->userauth_pblc_data); - } - if(session->userauth_pblc_packet) { - LIBSSH2_FREE(session, session->userauth_pblc_packet); - } - if(session->userauth_pblc_method) { - LIBSSH2_FREE(session, session->userauth_pblc_method); - } - if(session->userauth_kybd_data) { - LIBSSH2_FREE(session, session->userauth_kybd_data); - } - if(session->userauth_kybd_packet) { - LIBSSH2_FREE(session, session->userauth_kybd_packet); - } - if(session->userauth_kybd_auth_instruction) { - LIBSSH2_FREE(session, session->userauth_kybd_auth_instruction); - } - if(session->open_packet) { - LIBSSH2_FREE(session, session->open_packet); - } - if(session->open_data) { - LIBSSH2_FREE(session, session->open_data); - } - if(session->direct_message) { - LIBSSH2_FREE(session, session->direct_message); - } - if(session->fwdLstn_packet) { - LIBSSH2_FREE(session, session->fwdLstn_packet); - } - if(session->pkeyInit_data) { - LIBSSH2_FREE(session, session->pkeyInit_data); - } - if(session->scpRecv_command) { - LIBSSH2_FREE(session, session->scpRecv_command); - } - if(session->scpSend_command) { - LIBSSH2_FREE(session, session->scpSend_command); - } - if(session->sftpInit_sftp) { - LIBSSH2_FREE(session, session->sftpInit_sftp); - } - - /* Free payload buffer */ - if(session->packet.total_num) { - LIBSSH2_FREE(session, session->packet.payload); - } - - /* Cleanup all remaining packets */ - while((pkg = _libssh2_list_first(&session->packets))) { - packets_left++; - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "packet left with id %d", pkg->data[0]); - /* unlink the node */ - _libssh2_list_remove(&pkg->node); - - /* free */ - LIBSSH2_FREE(session, pkg->data); - LIBSSH2_FREE(session, pkg); - } - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "Extra packets left %d", packets_left); - - if(session->socket_prev_blockstate) { - /* if the socket was previously blocking, put it back so */ - rc = session_nonblock(session->socket_fd, 0); - if(rc) { - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "unable to reset socket's blocking state"); - } - } - - if(session->server_hostkey) { - LIBSSH2_FREE(session, session->server_hostkey); - } - - /* error string */ - if(session->err_msg && - ((session->err_flags & LIBSSH2_ERR_FLAG_DUP) != 0)) { - LIBSSH2_FREE(session, (char *)session->err_msg); - } - - LIBSSH2_FREE(session, session); - - return 0; -} - -/* - * libssh2_session_free - * - * Frees the memory allocated to the session - * Also closes and frees any channels attached to this session - */ -LIBSSH2_API int -libssh2_session_free(LIBSSH2_SESSION * session) -{ - int rc; - - BLOCK_ADJUST(rc, session, session_free(session) ); - - return rc; -} - -/* - * libssh2_session_disconnect_ex - */ -static int -session_disconnect(LIBSSH2_SESSION *session, int reason, - const char *description, - const char *lang) -{ - unsigned char *s; - unsigned long descr_len = 0, lang_len = 0; - int rc; - - if(session->disconnect_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "Disconnecting: reason=%d, desc=%s, lang=%s", reason, - description, lang); - if(description) - descr_len = strlen(description); - - if(lang) - lang_len = strlen(lang); - - if(descr_len > 256) - return _libssh2_error(session, LIBSSH2_ERROR_INVAL, - "too long description"); - - /* 13 = packet_type(1) + reason code(4) + descr_len(4) + lang_len(4) */ - session->disconnect_data_len = descr_len + lang_len + 13; - - s = session->disconnect_data; - - *(s++) = SSH_MSG_DISCONNECT; - _libssh2_store_u32(&s, reason); - _libssh2_store_str(&s, description, descr_len); - /* store length only, lang is sent separately */ - _libssh2_store_u32(&s, lang_len); - - session->disconnect_state = libssh2_NB_state_created; - } - - rc = _libssh2_transport_send(session, session->disconnect_data, - session->disconnect_data_len, - (unsigned char *)lang, lang_len); - if(rc == LIBSSH2_ERROR_EAGAIN) - return rc; - - session->disconnect_state = libssh2_NB_state_idle; - - return 0; -} - -/* - * libssh2_session_disconnect_ex - */ -LIBSSH2_API int -libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, int reason, - const char *desc, const char *lang) -{ - int rc; - session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS; - BLOCK_ADJUST(rc, session, - session_disconnect(session, reason, desc, lang)); - - return rc; -} - -/* libssh2_session_methods - * - * Return the currently active methods for method_type - * - * NOTE: Currently lang_cs and lang_sc are ALWAYS set to empty string - * regardless of actual negotiation Strings should NOT be freed - */ -LIBSSH2_API const char * -libssh2_session_methods(LIBSSH2_SESSION * session, int method_type) -{ - /* All methods have char *name as their first element */ - const LIBSSH2_KEX_METHOD *method = NULL; - - switch(method_type) { - case LIBSSH2_METHOD_KEX: - method = session->kex; - break; - - case LIBSSH2_METHOD_HOSTKEY: - method = (LIBSSH2_KEX_METHOD *) session->hostkey; - break; - - case LIBSSH2_METHOD_CRYPT_CS: - method = (LIBSSH2_KEX_METHOD *) session->local.crypt; - break; - - case LIBSSH2_METHOD_CRYPT_SC: - method = (LIBSSH2_KEX_METHOD *) session->remote.crypt; - break; - - case LIBSSH2_METHOD_MAC_CS: - method = (LIBSSH2_KEX_METHOD *) session->local.mac; - break; - - case LIBSSH2_METHOD_MAC_SC: - method = (LIBSSH2_KEX_METHOD *) session->remote.mac; - break; - - case LIBSSH2_METHOD_COMP_CS: - method = (LIBSSH2_KEX_METHOD *) session->local.comp; - break; - - case LIBSSH2_METHOD_COMP_SC: - method = (LIBSSH2_KEX_METHOD *) session->remote.comp; - break; - - case LIBSSH2_METHOD_LANG_CS: - return ""; - - case LIBSSH2_METHOD_LANG_SC: - return ""; - - default: - _libssh2_error(session, LIBSSH2_ERROR_INVAL, - "Invalid parameter specified for method_type"); - return NULL; - } - - if(!method) { - _libssh2_error(session, LIBSSH2_ERROR_METHOD_NONE, - "No method negotiated"); - return NULL; - } - - return method->name; -} - -/* libssh2_session_abstract - * Retrieve a pointer to the abstract property - */ -LIBSSH2_API void ** -libssh2_session_abstract(LIBSSH2_SESSION * session) -{ - return &session->abstract; -} - -/* libssh2_session_last_error - * - * Returns error code and populates an error string into errmsg If want_buf is - * non-zero then the string placed into errmsg must be freed by the calling - * program. Otherwise it is assumed to be owned by libssh2 - */ -LIBSSH2_API int -libssh2_session_last_error(LIBSSH2_SESSION * session, char **errmsg, - int *errmsg_len, int want_buf) -{ - size_t msglen = 0; - - /* No error to report */ - if(!session->err_code) { - if(errmsg) { - if(want_buf) { - *errmsg = LIBSSH2_ALLOC(session, 1); - if(*errmsg) { - **errmsg = 0; - } - } - else { - *errmsg = (char *) ""; - } - } - if(errmsg_len) { - *errmsg_len = 0; - } - return 0; - } - - if(errmsg) { - const char *error = session->err_msg ? session->err_msg : ""; - - msglen = strlen(error); - - if(want_buf) { - /* Make a copy so the calling program can own it */ - *errmsg = LIBSSH2_ALLOC(session, msglen + 1); - if(*errmsg) { - memcpy(*errmsg, error, msglen); - (*errmsg)[msglen] = 0; - } - } - else - *errmsg = (char *)error; - } - - if(errmsg_len) { - *errmsg_len = msglen; - } - - return session->err_code; -} - -/* libssh2_session_last_errno - * - * Returns error code - */ -LIBSSH2_API int -libssh2_session_last_errno(LIBSSH2_SESSION * session) -{ - return session->err_code; -} - -/* libssh2_session_set_last_error - * - * Sets the internal error code for the session. - * - * This function is available specifically to be used by high level - * language wrappers (i.e. Python or Perl) that may extend the library - * features while still relying on its error reporting mechanism. - */ -LIBSSH2_API int -libssh2_session_set_last_error(LIBSSH2_SESSION* session, - int errcode, - const char *errmsg) -{ - return _libssh2_error_flags(session, errcode, errmsg, - LIBSSH2_ERR_FLAG_DUP); -} - -/* Libssh2_session_flag - * - * Set/Get session flags - * - * Return error code. - */ -LIBSSH2_API int -libssh2_session_flag(LIBSSH2_SESSION * session, int flag, int value) -{ - switch(flag) { - case LIBSSH2_FLAG_SIGPIPE: - session->flag.sigpipe = value; - break; - case LIBSSH2_FLAG_COMPRESS: - session->flag.compress = value; - break; - default: - /* unknown flag */ - return LIBSSH2_ERROR_INVAL; - } - - return LIBSSH2_ERROR_NONE; -} - -/* _libssh2_session_set_blocking - * - * Set a session's blocking mode on or off, return the previous status when - * this function is called. Note this function does not alter the state of the - * actual socket involved. - */ -int -_libssh2_session_set_blocking(LIBSSH2_SESSION *session, int blocking) -{ - int bl = session->api_block_mode; - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Setting blocking mode %s", blocking?"ON":"OFF"); - session->api_block_mode = blocking; - - return bl; -} - -/* libssh2_session_set_blocking - * - * Set a channel's blocking mode on or off, similar to a socket's - * fcntl(fd, F_SETFL, O_NONBLOCK); type command - */ -LIBSSH2_API void -libssh2_session_set_blocking(LIBSSH2_SESSION * session, int blocking) -{ - (void) _libssh2_session_set_blocking(session, blocking); -} - -/* libssh2_session_get_blocking - * - * Returns a session's blocking mode on or off - */ -LIBSSH2_API int -libssh2_session_get_blocking(LIBSSH2_SESSION * session) -{ - return session->api_block_mode; -} - - -/* libssh2_session_set_timeout - * - * Set a session's timeout (in msec) for blocking mode, - * or 0 to disable timeouts. - */ -LIBSSH2_API void -libssh2_session_set_timeout(LIBSSH2_SESSION * session, long timeout) -{ - session->api_timeout = timeout; -} - -/* libssh2_session_get_timeout - * - * Returns a session's timeout, or 0 if disabled - */ -LIBSSH2_API long -libssh2_session_get_timeout(LIBSSH2_SESSION * session) -{ - return session->api_timeout; -} - -/* - * libssh2_poll_channel_read - * - * Returns 0 if no data is waiting on channel, - * non-0 if data is available - */ -LIBSSH2_API int -libssh2_poll_channel_read(LIBSSH2_CHANNEL *channel, int extended) -{ - LIBSSH2_SESSION *session; - LIBSSH2_PACKET *packet; - - if(!channel) - return LIBSSH2_ERROR_BAD_USE; - - session = channel->session; - packet = _libssh2_list_first(&session->packets); - - while(packet) { - if(packet->data_len < 5) { - return _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "Packet too small"); - } - - if(channel->local.id == _libssh2_ntohu32(packet->data + 1)) { - if(extended == 1 && - (packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA - || packet->data[0] == SSH_MSG_CHANNEL_DATA)) { - return 1; - } - else if(extended == 0 && - packet->data[0] == SSH_MSG_CHANNEL_DATA) { - return 1; - } - /* else - no data of any type is ready to be read */ - } - packet = _libssh2_list_next(&packet->node); - } - - return 0; -} - -/* - * poll_channel_write - * - * Returns 0 if writing to channel would block, - * non-0 if data can be written without blocking - */ -static inline int -poll_channel_write(LIBSSH2_CHANNEL * channel) -{ - return channel->local.window_size ? 1 : 0; -} - -/* poll_listener_queued - * - * Returns 0 if no connections are waiting to be accepted - * non-0 if one or more connections are available - */ -static inline int -poll_listener_queued(LIBSSH2_LISTENER * listener) -{ - return _libssh2_list_first(&listener->queue) ? 1 : 0; -} - -/* - * libssh2_poll - * - * Poll sockets, channels, and listeners for activity - */ -LIBSSH2_API int -libssh2_poll(LIBSSH2_POLLFD * fds, unsigned int nfds, long timeout) -{ - long timeout_remaining; - unsigned int i, active_fds; -#ifdef HAVE_POLL - LIBSSH2_SESSION *session = NULL; -#ifdef HAVE_ALLOCA - struct pollfd *sockets = alloca(sizeof(struct pollfd) * nfds); -#else - struct pollfd sockets[256]; - - if(nfds > 256) - /* systems without alloca use a fixed-size array, this can be fixed if - we really want to, at least if the compiler is a C99 capable one */ - return -1; -#endif - /* Setup sockets for polling */ - for(i = 0; i < nfds; i++) { - fds[i].revents = 0; - switch(fds[i].type) { - case LIBSSH2_POLLFD_SOCKET: - sockets[i].fd = fds[i].fd.socket; - sockets[i].events = fds[i].events; - sockets[i].revents = 0; - break; - - case LIBSSH2_POLLFD_CHANNEL: - sockets[i].fd = fds[i].fd.channel->session->socket_fd; - sockets[i].events = POLLIN; - sockets[i].revents = 0; - if(!session) - session = fds[i].fd.channel->session; - break; - - case LIBSSH2_POLLFD_LISTENER: - sockets[i].fd = fds[i].fd.listener->session->socket_fd; - sockets[i].events = POLLIN; - sockets[i].revents = 0; - if(!session) - session = fds[i].fd.listener->session; - break; - - default: - if(session) - _libssh2_error(session, LIBSSH2_ERROR_INVALID_POLL_TYPE, - "Invalid descriptor passed to libssh2_poll()"); - return -1; - } - } -#elif defined(HAVE_SELECT) - LIBSSH2_SESSION *session = NULL; - libssh2_socket_t maxfd = 0; - fd_set rfds, wfds; - struct timeval tv; - - FD_ZERO(&rfds); - FD_ZERO(&wfds); - for(i = 0; i < nfds; i++) { - fds[i].revents = 0; - switch(fds[i].type) { - case LIBSSH2_POLLFD_SOCKET: - if(fds[i].events & LIBSSH2_POLLFD_POLLIN) { - FD_SET(fds[i].fd.socket, &rfds); - if(fds[i].fd.socket > maxfd) - maxfd = fds[i].fd.socket; - } - if(fds[i].events & LIBSSH2_POLLFD_POLLOUT) { - FD_SET(fds[i].fd.socket, &wfds); - if(fds[i].fd.socket > maxfd) - maxfd = fds[i].fd.socket; - } - break; - - case LIBSSH2_POLLFD_CHANNEL: - FD_SET(fds[i].fd.channel->session->socket_fd, &rfds); - if(fds[i].fd.channel->session->socket_fd > maxfd) - maxfd = fds[i].fd.channel->session->socket_fd; - if(!session) - session = fds[i].fd.channel->session; - break; - - case LIBSSH2_POLLFD_LISTENER: - FD_SET(fds[i].fd.listener->session->socket_fd, &rfds); - if(fds[i].fd.listener->session->socket_fd > maxfd) - maxfd = fds[i].fd.listener->session->socket_fd; - if(!session) - session = fds[i].fd.listener->session; - break; - - default: - if(session) - _libssh2_error(session, LIBSSH2_ERROR_INVALID_POLL_TYPE, - "Invalid descriptor passed to libssh2_poll()"); - return -1; - } - } -#else - /* No select() or poll() - * no sockets structure to setup - */ - - timeout = 0; -#endif /* HAVE_POLL or HAVE_SELECT */ - - timeout_remaining = timeout; - do { -#if defined(HAVE_POLL) || defined(HAVE_SELECT) - int sysret; -#endif - - active_fds = 0; - - for(i = 0; i < nfds; i++) { - if(fds[i].events != fds[i].revents) { - switch(fds[i].type) { - case LIBSSH2_POLLFD_CHANNEL: - if((fds[i].events & LIBSSH2_POLLFD_POLLIN) && - /* Want to be ready for read */ - ((fds[i].revents & LIBSSH2_POLLFD_POLLIN) == 0)) { - /* Not yet known to be ready for read */ - fds[i].revents |= - libssh2_poll_channel_read(fds[i].fd.channel, - 0) ? - LIBSSH2_POLLFD_POLLIN : 0; - } - if((fds[i].events & LIBSSH2_POLLFD_POLLEXT) && - /* Want to be ready for extended read */ - ((fds[i].revents & LIBSSH2_POLLFD_POLLEXT) == 0)) { - /* Not yet known to be ready for extended read */ - fds[i].revents |= - libssh2_poll_channel_read(fds[i].fd.channel, - 1) ? - LIBSSH2_POLLFD_POLLEXT : 0; - } - if((fds[i].events & LIBSSH2_POLLFD_POLLOUT) && - /* Want to be ready for write */ - ((fds[i].revents & LIBSSH2_POLLFD_POLLOUT) == 0)) { - /* Not yet known to be ready for write */ - fds[i].revents |= - poll_channel_write(fds[i].fd. channel) ? - LIBSSH2_POLLFD_POLLOUT : 0; - } - if(fds[i].fd.channel->remote.close - || fds[i].fd.channel->local.close) { - fds[i].revents |= LIBSSH2_POLLFD_CHANNEL_CLOSED; - } - if(fds[i].fd.channel->session->socket_state == - LIBSSH2_SOCKET_DISCONNECTED) { - fds[i].revents |= - LIBSSH2_POLLFD_CHANNEL_CLOSED | - LIBSSH2_POLLFD_SESSION_CLOSED; - } - break; - - case LIBSSH2_POLLFD_LISTENER: - if((fds[i].events & LIBSSH2_POLLFD_POLLIN) && - /* Want a connection */ - ((fds[i].revents & LIBSSH2_POLLFD_POLLIN) == 0)) { - /* No connections known of yet */ - fds[i].revents |= - poll_listener_queued(fds[i].fd. listener) ? - LIBSSH2_POLLFD_POLLIN : 0; - } - if(fds[i].fd.listener->session->socket_state == - LIBSSH2_SOCKET_DISCONNECTED) { - fds[i].revents |= - LIBSSH2_POLLFD_LISTENER_CLOSED | - LIBSSH2_POLLFD_SESSION_CLOSED; - } - break; - } - } - if(fds[i].revents) { - active_fds++; - } - } - - if(active_fds) { - /* Don't block on the sockets if we have channels/listeners which - are ready */ - timeout_remaining = 0; - } -#ifdef HAVE_POLL - -#ifdef HAVE_LIBSSH2_GETTIMEOFDAY - { - struct timeval tv_begin, tv_end; - - _libssh2_gettimeofday((struct timeval *) &tv_begin, NULL); - sysret = poll(sockets, nfds, timeout_remaining); - _libssh2_gettimeofday((struct timeval *) &tv_end, NULL); - timeout_remaining -= (tv_end.tv_sec - tv_begin.tv_sec) * 1000; - timeout_remaining -= (tv_end.tv_usec - tv_begin.tv_usec) / 1000; - } -#else - /* If the platform doesn't support gettimeofday, - * then just make the call non-blocking and walk away - */ - sysret = poll(sockets, nfds, timeout_remaining); - timeout_remaining = 0; -#endif /* HAVE_GETTIMEOFDAY */ - - if(sysret > 0) { - for(i = 0; i < nfds; i++) { - switch(fds[i].type) { - case LIBSSH2_POLLFD_SOCKET: - fds[i].revents = sockets[i].revents; - sockets[i].revents = 0; /* In case we loop again, be - nice */ - if(fds[i].revents) { - active_fds++; - } - break; - case LIBSSH2_POLLFD_CHANNEL: - if(sockets[i].events & POLLIN) { - /* Spin session until no data available */ - while(_libssh2_transport_read(fds[i].fd. - channel->session) - > 0); - } - if(sockets[i].revents & POLLHUP) { - fds[i].revents |= - LIBSSH2_POLLFD_CHANNEL_CLOSED | - LIBSSH2_POLLFD_SESSION_CLOSED; - } - sockets[i].revents = 0; - break; - case LIBSSH2_POLLFD_LISTENER: - if(sockets[i].events & POLLIN) { - /* Spin session until no data available */ - while(_libssh2_transport_read(fds[i].fd. - listener->session) - > 0); - } - if(sockets[i].revents & POLLHUP) { - fds[i].revents |= - LIBSSH2_POLLFD_LISTENER_CLOSED | - LIBSSH2_POLLFD_SESSION_CLOSED; - } - sockets[i].revents = 0; - break; - } - } - } -#elif defined(HAVE_SELECT) - tv.tv_sec = timeout_remaining / 1000; - tv.tv_usec = (timeout_remaining % 1000) * 1000; -#ifdef HAVE_LIBSSH2_GETTIMEOFDAY - { - struct timeval tv_begin, tv_end; - - _libssh2_gettimeofday((struct timeval *) &tv_begin, NULL); - sysret = select(maxfd + 1, &rfds, &wfds, NULL, &tv); - _libssh2_gettimeofday((struct timeval *) &tv_end, NULL); - - timeout_remaining -= (tv_end.tv_sec - tv_begin.tv_sec) * 1000; - timeout_remaining -= (tv_end.tv_usec - tv_begin.tv_usec) / 1000; - } -#else - /* If the platform doesn't support gettimeofday, - * then just make the call non-blocking and walk away - */ - sysret = select(maxfd + 1, &rfds, &wfds, NULL, &tv); - timeout_remaining = 0; -#endif - - if(sysret > 0) { - for(i = 0; i < nfds; i++) { - switch(fds[i].type) { - case LIBSSH2_POLLFD_SOCKET: - if(FD_ISSET(fds[i].fd.socket, &rfds)) { - fds[i].revents |= LIBSSH2_POLLFD_POLLIN; - } - if(FD_ISSET(fds[i].fd.socket, &wfds)) { - fds[i].revents |= LIBSSH2_POLLFD_POLLOUT; - } - if(fds[i].revents) { - active_fds++; - } - break; - - case LIBSSH2_POLLFD_CHANNEL: - if(FD_ISSET(fds[i].fd.channel->session->socket_fd, - &rfds)) { - /* Spin session until no data available */ - while(_libssh2_transport_read(fds[i].fd. - channel->session) - > 0); - } - break; - - case LIBSSH2_POLLFD_LISTENER: - if(FD_ISSET - (fds[i].fd.listener->session->socket_fd, &rfds)) { - /* Spin session until no data available */ - while(_libssh2_transport_read(fds[i].fd. - listener->session) - > 0); - } - break; - } - } - } -#endif /* else no select() or poll() -- timeout (and by extension - * timeout_remaining) will be equal to 0 */ - } while((timeout_remaining > 0) && !active_fds); - - return active_fds; -} - -/* - * libssh2_session_block_directions - * - * Get blocked direction when a function returns LIBSSH2_ERROR_EAGAIN - * Returns LIBSSH2_SOCKET_BLOCK_INBOUND if recv() blocked - * or LIBSSH2_SOCKET_BLOCK_OUTBOUND if send() blocked - */ -LIBSSH2_API int -libssh2_session_block_directions(LIBSSH2_SESSION *session) -{ - return session->socket_block_directions; -} - -/* libssh2_session_banner_get - * Get the remote banner (server ID string) - */ - -LIBSSH2_API const char * -libssh2_session_banner_get(LIBSSH2_SESSION *session) -{ - /* to avoid a coredump when session is NULL */ - if(NULL == session) - return NULL; - - if(NULL == session->remote.banner) - return NULL; - - return (const char *) session->remote.banner; -} diff --git a/libssh2/sftp.c b/libssh2/sftp.c deleted file mode 100644 index ac7ee01..0000000 --- a/libssh2/sftp.c +++ /dev/null @@ -1,3755 +0,0 @@ -/* Copyright (c) 2004-2008, Sara Golemon - * Copyright (c) 2007 Eli Fant - * Copyright (c) 2009-2019 by Daniel Stenberg - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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 "libssh2_priv.h" -#include "libssh2_sftp.h" -#include "channel.h" -#include "session.h" -#include "sftp.h" - -/* Note: Version 6 was documented at the time of writing - * However it was marked as "DO NOT IMPLEMENT" due to pending changes - * - * This release of libssh2 implements Version 5 with automatic downgrade - * based on server's declaration - */ - -/* SFTP packet types */ -#define SSH_FXP_INIT 1 -#define SSH_FXP_VERSION 2 -#define SSH_FXP_OPEN 3 -#define SSH_FXP_CLOSE 4 -#define SSH_FXP_READ 5 -#define SSH_FXP_WRITE 6 -#define SSH_FXP_LSTAT 7 -#define SSH_FXP_FSTAT 8 -#define SSH_FXP_SETSTAT 9 -#define SSH_FXP_FSETSTAT 10 -#define SSH_FXP_OPENDIR 11 -#define SSH_FXP_READDIR 12 -#define SSH_FXP_REMOVE 13 -#define SSH_FXP_MKDIR 14 -#define SSH_FXP_RMDIR 15 -#define SSH_FXP_REALPATH 16 -#define SSH_FXP_STAT 17 -#define SSH_FXP_RENAME 18 -#define SSH_FXP_READLINK 19 -#define SSH_FXP_SYMLINK 20 -#define SSH_FXP_STATUS 101 -#define SSH_FXP_HANDLE 102 -#define SSH_FXP_DATA 103 -#define SSH_FXP_NAME 104 -#define SSH_FXP_ATTRS 105 -#define SSH_FXP_EXTENDED 200 -#define SSH_FXP_EXTENDED_REPLY 201 - -/* S_IFREG */ -#define LIBSSH2_SFTP_ATTR_PFILETYPE_FILE 0100000 -/* S_IFDIR */ -#define LIBSSH2_SFTP_ATTR_PFILETYPE_DIR 0040000 - -#define SSH_FXE_STATVFS_ST_RDONLY 0x00000001 -#define SSH_FXE_STATVFS_ST_NOSUID 0x00000002 - -/* This is the maximum packet length to accept, as larger than this indicate - some kind of server problem. */ -#define LIBSSH2_SFTP_PACKET_MAXLEN (256 * 1024) - -static int sftp_packet_ask(LIBSSH2_SFTP *sftp, unsigned char packet_type, - uint32_t request_id, unsigned char **data, - size_t *data_len); -static void sftp_packet_flush(LIBSSH2_SFTP *sftp); - -/* sftp_attrsize - * Size that attr with this flagset will occupy when turned into a bin struct - */ -static int sftp_attrsize(unsigned long flags) -{ - return (4 + /* flags(4) */ - ((flags & LIBSSH2_SFTP_ATTR_SIZE) ? 8 : 0) + - ((flags & LIBSSH2_SFTP_ATTR_UIDGID) ? 8 : 0) + - ((flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) ? 4 : 0) + - ((flags & LIBSSH2_SFTP_ATTR_ACMODTIME) ? 8 : 0)); - /* atime + mtime as u32 */ -} - -/* _libssh2_store_u64 - */ -static void _libssh2_store_u64(unsigned char **ptr, libssh2_uint64_t value) -{ - uint32_t msl = (uint32_t)(value >> 32); - unsigned char *buf = *ptr; - - buf[0] = (unsigned char)((msl >> 24) & 0xFF); - buf[1] = (unsigned char)((msl >> 16) & 0xFF); - buf[2] = (unsigned char)((msl >> 8) & 0xFF); - buf[3] = (unsigned char)( msl & 0xFF); - - buf[4] = (unsigned char)((value >> 24) & 0xFF); - buf[5] = (unsigned char)((value >> 16) & 0xFF); - buf[6] = (unsigned char)((value >> 8) & 0xFF); - buf[7] = (unsigned char)( value & 0xFF); - - *ptr += 8; -} - -/* - * Search list of zombied FXP_READ request IDs. - * - * Returns NULL if ID not in list. - */ -static struct sftp_zombie_requests * -find_zombie_request(LIBSSH2_SFTP *sftp, uint32_t request_id) -{ - struct sftp_zombie_requests *zombie = - _libssh2_list_first(&sftp->zombie_requests); - - while(zombie) { - if(zombie->request_id == request_id) - break; - else - zombie = _libssh2_list_next(&zombie->node); - } - - return zombie; -} - -static void -remove_zombie_request(LIBSSH2_SFTP *sftp, uint32_t request_id) -{ - LIBSSH2_SESSION *session = sftp->channel->session; - - struct sftp_zombie_requests *zombie = find_zombie_request(sftp, - request_id); - if(zombie) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Removing request ID %ld from the list of " - "zombie requests", - request_id); - - _libssh2_list_remove(&zombie->node); - LIBSSH2_FREE(session, zombie); - } -} - -static int -add_zombie_request(LIBSSH2_SFTP *sftp, uint32_t request_id) -{ - LIBSSH2_SESSION *session = sftp->channel->session; - - struct sftp_zombie_requests *zombie; - - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Marking request ID %ld as a zombie request", request_id); - - zombie = LIBSSH2_ALLOC(sftp->channel->session, - sizeof(struct sftp_zombie_requests)); - if(!zombie) - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "malloc fail for zombie request ID"); - else { - zombie->request_id = request_id; - _libssh2_list_add(&sftp->zombie_requests, &zombie->node); - return LIBSSH2_ERROR_NONE; - } -} - -/* - * sftp_packet_add - * - * Add a packet to the SFTP packet brigade - */ -static int -sftp_packet_add(LIBSSH2_SFTP *sftp, unsigned char *data, - size_t data_len) -{ - LIBSSH2_SESSION *session = sftp->channel->session; - LIBSSH2_SFTP_PACKET *packet; - uint32_t request_id; - - if(data_len < 5) { - return LIBSSH2_ERROR_OUT_OF_BOUNDARY; - } - - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Received packet type %d (len %d)", - (int) data[0], data_len); - - /* - * Experience shows that if we mess up EAGAIN handling somewhere or - * otherwise get out of sync with the channel, this is where we first get - * a wrong byte and if so we need to bail out at once to aid tracking the - * problem better. - */ - - switch(data[0]) { - case SSH_FXP_INIT: - case SSH_FXP_VERSION: - case SSH_FXP_OPEN: - case SSH_FXP_CLOSE: - case SSH_FXP_READ: - case SSH_FXP_WRITE: - case SSH_FXP_LSTAT: - case SSH_FXP_FSTAT: - case SSH_FXP_SETSTAT: - case SSH_FXP_FSETSTAT: - case SSH_FXP_OPENDIR: - case SSH_FXP_READDIR: - case SSH_FXP_REMOVE: - case SSH_FXP_MKDIR: - case SSH_FXP_RMDIR: - case SSH_FXP_REALPATH: - case SSH_FXP_STAT: - case SSH_FXP_RENAME: - case SSH_FXP_READLINK: - case SSH_FXP_SYMLINK: - case SSH_FXP_STATUS: - case SSH_FXP_HANDLE: - case SSH_FXP_DATA: - case SSH_FXP_NAME: - case SSH_FXP_ATTRS: - case SSH_FXP_EXTENDED: - case SSH_FXP_EXTENDED_REPLY: - break; - default: - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "Out of sync with the world"); - } - - request_id = _libssh2_ntohu32(&data[1]); - - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Received packet id %d", - request_id); - - /* Don't add the packet if it answers a request we've given up on. */ - if((data[0] == SSH_FXP_STATUS || data[0] == SSH_FXP_DATA) - && find_zombie_request(sftp, request_id)) { - - /* If we get here, the file ended before the response arrived. We - are no longer interested in the request so we discard it */ - - LIBSSH2_FREE(session, data); - - remove_zombie_request(sftp, request_id); - return LIBSSH2_ERROR_NONE; - } - - packet = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_SFTP_PACKET)); - if(!packet) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate datablock for SFTP packet"); - } - - packet->data = data; - packet->data_len = data_len; - packet->request_id = request_id; - - _libssh2_list_add(&sftp->packets, &packet->node); - - return LIBSSH2_ERROR_NONE; -} - -/* - * sftp_packet_read - * - * Frame an SFTP packet off the channel - */ -static int -sftp_packet_read(LIBSSH2_SFTP *sftp) -{ - LIBSSH2_CHANNEL *channel = sftp->channel; - LIBSSH2_SESSION *session = channel->session; - unsigned char *packet = NULL; - ssize_t rc; - unsigned long recv_window; - int packet_type; - - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "recv packet"); - - switch(sftp->packet_state) { - case libssh2_NB_state_sent: /* EAGAIN from window adjusting */ - sftp->packet_state = libssh2_NB_state_idle; - - packet = sftp->partial_packet; - goto window_adjust; - - case libssh2_NB_state_sent1: /* EAGAIN from channel read */ - sftp->packet_state = libssh2_NB_state_idle; - - packet = sftp->partial_packet; - - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "partial read cont, len: %lu", sftp->partial_len); - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "partial read cont, already recvd: %lu", - sftp->partial_received); - /* fall-through */ - default: - if(!packet) { - /* only do this if there's not already a packet buffer allocated - to use */ - - /* each packet starts with a 32 bit length field */ - rc = _libssh2_channel_read(channel, 0, - (char *)&sftp->partial_size[ - sftp->partial_size_len], - 4 - sftp->partial_size_len); - if(rc == LIBSSH2_ERROR_EAGAIN) - return rc; - else if(rc < 0) - return _libssh2_error(session, rc, "channel read"); - - sftp->partial_size_len += rc; - - if(4 != sftp->partial_size_len) - /* we got a short read for the length part */ - return LIBSSH2_ERROR_EAGAIN; - - sftp->partial_len = _libssh2_ntohu32(sftp->partial_size); - /* make sure we don't proceed if the packet size is unreasonably - large */ - if(sftp->partial_len > LIBSSH2_SFTP_PACKET_MAXLEN) { - libssh2_channel_flush(channel); - sftp->partial_size_len = 0; - return _libssh2_error(session, - LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED, - "SFTP packet too large"); - } - - if(sftp->partial_len == 0) - return _libssh2_error(session, - LIBSSH2_ERROR_ALLOC, - "Unable to allocate empty SFTP packet"); - - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Data begin - Packet Length: %lu", - sftp->partial_len); - packet = LIBSSH2_ALLOC(session, sftp->partial_len); - if(!packet) - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate SFTP packet"); - sftp->partial_size_len = 0; - sftp->partial_received = 0; /* how much of the packet already - received */ - sftp->partial_packet = packet; - - window_adjust: - recv_window = libssh2_channel_window_read_ex(channel, NULL, NULL); - - if(sftp->partial_len > recv_window) { - /* ask for twice the data amount we need at once */ - rc = _libssh2_channel_receive_window_adjust(channel, - sftp->partial_len - * 2, - 1, NULL); - /* store the state so that we continue with the correct - operation at next invoke */ - sftp->packet_state = (rc == LIBSSH2_ERROR_EAGAIN)? - libssh2_NB_state_sent: - libssh2_NB_state_idle; - - if(rc == LIBSSH2_ERROR_EAGAIN) - return rc; - } - } - - /* Read as much of the packet as we can */ - while(sftp->partial_len > sftp->partial_received) { - rc = _libssh2_channel_read(channel, 0, - (char *)&packet[sftp->partial_received], - sftp->partial_len - - sftp->partial_received); - - if(rc == LIBSSH2_ERROR_EAGAIN) { - /* - * We received EAGAIN, save what we have and return EAGAIN to - * the caller. Set 'partial_packet' so that this function - * knows how to continue on the next invoke. - */ - sftp->packet_state = libssh2_NB_state_sent1; - return rc; - } - else if(rc < 0) { - LIBSSH2_FREE(session, packet); - sftp->partial_packet = NULL; - return _libssh2_error(session, rc, - "Error waiting for SFTP packet"); - } - sftp->partial_received += rc; - } - - sftp->partial_packet = NULL; - - /* sftp_packet_add takes ownership of the packet and might free it - so we take a copy of the packet type before we call it. */ - packet_type = packet[0]; - rc = sftp_packet_add(sftp, packet, sftp->partial_len); - if(rc) { - LIBSSH2_FREE(session, packet); - return rc; - } - else { - return packet_type; - } - } - /* WON'T REACH */ -} -/* - * sftp_packetlist_flush - * - * Remove all pending packets in the packet_list and the corresponding one(s) - * in the SFTP packet brigade. - */ -static void sftp_packetlist_flush(LIBSSH2_SFTP_HANDLE *handle) -{ - struct sftp_pipeline_chunk *chunk; - LIBSSH2_SFTP *sftp = handle->sftp; - LIBSSH2_SESSION *session = sftp->channel->session; - - /* remove pending packets, if any */ - chunk = _libssh2_list_first(&handle->packet_list); - while(chunk) { - unsigned char *data; - size_t data_len; - int rc; - struct sftp_pipeline_chunk *next = _libssh2_list_next(&chunk->node); - - rc = sftp_packet_ask(sftp, SSH_FXP_STATUS, - chunk->request_id, &data, &data_len); - if(rc) - rc = sftp_packet_ask(sftp, SSH_FXP_DATA, - chunk->request_id, &data, &data_len); - - if(!rc) - /* we found a packet, free it */ - LIBSSH2_FREE(session, data); - else if(chunk->sent) - /* there was no incoming packet for this request, mark this - request as a zombie if it ever sent the request */ - add_zombie_request(sftp, chunk->request_id); - - _libssh2_list_remove(&chunk->node); - LIBSSH2_FREE(session, chunk); - chunk = next; - } -} - - -/* - * sftp_packet_ask() - * - * Checks if there's a matching SFTP packet available. - */ -static int -sftp_packet_ask(LIBSSH2_SFTP *sftp, unsigned char packet_type, - uint32_t request_id, unsigned char **data, - size_t *data_len) -{ - LIBSSH2_SESSION *session = sftp->channel->session; - LIBSSH2_SFTP_PACKET *packet = _libssh2_list_first(&sftp->packets); - - if(!packet) - return -1; - - /* Special consideration when getting VERSION packet */ - - while(packet) { - if((packet->data[0] == packet_type) && - ((packet_type == SSH_FXP_VERSION) || - (packet->request_id == request_id))) { - - /* Match! Fetch the data */ - *data = packet->data; - *data_len = packet->data_len; - - /* unlink and free this struct */ - _libssh2_list_remove(&packet->node); - LIBSSH2_FREE(session, packet); - - return 0; - } - /* check next struct in the list */ - packet = _libssh2_list_next(&packet->node); - } - return -1; -} - -/* sftp_packet_require - * A la libssh2_packet_require - */ -static int -sftp_packet_require(LIBSSH2_SFTP *sftp, unsigned char packet_type, - uint32_t request_id, unsigned char **data, - size_t *data_len, size_t required_size) -{ - LIBSSH2_SESSION *session = sftp->channel->session; - int rc; - - if(data == NULL || data_len == NULL || required_size == 0) { - return LIBSSH2_ERROR_BAD_USE; - } - - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Requiring packet %d id %ld", - (int) packet_type, request_id); - - if(sftp_packet_ask(sftp, packet_type, request_id, data, data_len) == 0) { - /* The right packet was available in the packet brigade */ - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Got %d", - (int) packet_type); - - if (*data_len < required_size) { - return LIBSSH2_ERROR_BUFFER_TOO_SMALL; - } - - return LIBSSH2_ERROR_NONE; - } - - while(session->socket_state == LIBSSH2_SOCKET_CONNECTED) { - rc = sftp_packet_read(sftp); - if(rc < 0) - return rc; - - /* data was read, check the queue again */ - if(!sftp_packet_ask(sftp, packet_type, request_id, data, data_len)) { - /* The right packet was available in the packet brigade */ - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Got %d", - (int) packet_type); - - if (*data_len < required_size) { - return LIBSSH2_ERROR_BUFFER_TOO_SMALL; - } - - return LIBSSH2_ERROR_NONE; - } - } - - /* Only reached if the socket died */ - return LIBSSH2_ERROR_SOCKET_DISCONNECT; -} - -/* sftp_packet_requirev - * Require one of N possible responses - */ -static int -sftp_packet_requirev(LIBSSH2_SFTP *sftp, int num_valid_responses, - const unsigned char *valid_responses, - uint32_t request_id, unsigned char **data, - size_t *data_len, size_t required_size) -{ - int i; - int rc; - - if(data == NULL || data_len == NULL || required_size == 0) { - return LIBSSH2_ERROR_BAD_USE; - } - - /* If no timeout is active, start a new one */ - if(sftp->requirev_start == 0) - sftp->requirev_start = time(NULL); - - while(sftp->channel->session->socket_state == LIBSSH2_SOCKET_CONNECTED) { - for(i = 0; i < num_valid_responses; i++) { - if(sftp_packet_ask(sftp, valid_responses[i], request_id, - data, data_len) == 0) { - /* - * Set to zero before all returns to say - * the timeout is not active - */ - sftp->requirev_start = 0; - - if (*data_len < required_size) { - return LIBSSH2_ERROR_BUFFER_TOO_SMALL; - } - - return LIBSSH2_ERROR_NONE; - } - } - - rc = sftp_packet_read(sftp); - if((rc < 0) && (rc != LIBSSH2_ERROR_EAGAIN)) { - sftp->requirev_start = 0; - return rc; - } - else if(rc <= 0) { - /* prevent busy-looping */ - long left = - LIBSSH2_READ_TIMEOUT - - (long)(time(NULL) - sftp->requirev_start); - - if(left <= 0) { - sftp->requirev_start = 0; - return LIBSSH2_ERROR_TIMEOUT; - } - else if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - } - } - - sftp->requirev_start = 0; - - /* Only reached if the socket died */ - return LIBSSH2_ERROR_SOCKET_DISCONNECT; -} - -/* sftp_attr2bin - * Populate attributes into an SFTP block - */ -static ssize_t -sftp_attr2bin(unsigned char *p, const LIBSSH2_SFTP_ATTRIBUTES * attrs) -{ - unsigned char *s = p; - uint32_t flag_mask = - LIBSSH2_SFTP_ATTR_SIZE | LIBSSH2_SFTP_ATTR_UIDGID | - LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME; - - /* TODO: When we add SFTP4+ functionality flag_mask can get additional - bits */ - - if(!attrs) { - _libssh2_htonu32(s, 0); - return 4; - } - - _libssh2_store_u32(&s, attrs->flags & flag_mask); - - if(attrs->flags & LIBSSH2_SFTP_ATTR_SIZE) { - _libssh2_store_u64(&s, attrs->filesize); - } - - if(attrs->flags & LIBSSH2_SFTP_ATTR_UIDGID) { - _libssh2_store_u32(&s, attrs->uid); - _libssh2_store_u32(&s, attrs->gid); - } - - if(attrs->flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) { - _libssh2_store_u32(&s, attrs->permissions); - } - - if(attrs->flags & LIBSSH2_SFTP_ATTR_ACMODTIME) { - _libssh2_store_u32(&s, attrs->atime); - _libssh2_store_u32(&s, attrs->mtime); - } - - return (s - p); -} - -/* sftp_bin2attr - */ -static int -sftp_bin2attr(LIBSSH2_SFTP_ATTRIBUTES *attrs, const unsigned char *p, - size_t data_len) -{ - struct string_buf buf; - uint32_t flags = 0; - buf.data = (unsigned char *)p; - buf.dataptr = buf.data; - buf.len = data_len; - - if(_libssh2_get_u32(&buf, &flags) != 0) { - return LIBSSH2_ERROR_BUFFER_TOO_SMALL; - } - attrs->flags = flags; - - if(attrs->flags & LIBSSH2_SFTP_ATTR_SIZE) { - if(_libssh2_get_u64(&buf, &(attrs->filesize)) != 0) { - return LIBSSH2_ERROR_BUFFER_TOO_SMALL; - } - } - - if(attrs->flags & LIBSSH2_SFTP_ATTR_UIDGID) { - uint32_t uid = 0; - uint32_t gid = 0; - if(_libssh2_get_u32(&buf, &uid) != 0 || - _libssh2_get_u32(&buf, &gid) != 0) { - return LIBSSH2_ERROR_BUFFER_TOO_SMALL; - } - attrs->uid = uid; - attrs->gid = gid; - } - - if(attrs->flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) { - uint32_t permissions; - if(_libssh2_get_u32(&buf, &permissions) != 0) { - return LIBSSH2_ERROR_BUFFER_TOO_SMALL; - } - attrs->permissions = permissions; - } - - if(attrs->flags & LIBSSH2_SFTP_ATTR_ACMODTIME) { - uint32_t atime; - uint32_t mtime; - if(_libssh2_get_u32(&buf, &atime) != 0 || - _libssh2_get_u32(&buf, &mtime) != 0) { - return LIBSSH2_ERROR_BUFFER_TOO_SMALL; - } - attrs->atime = atime; - attrs->mtime = mtime; - } - - return (buf.dataptr - buf.data); -} - -/* ************ - * SFTP API * - ************ */ - -LIBSSH2_CHANNEL_CLOSE_FUNC(libssh2_sftp_dtor); - -/* libssh2_sftp_dtor - * Shutdown an SFTP stream when the channel closes - */ -LIBSSH2_CHANNEL_CLOSE_FUNC(libssh2_sftp_dtor) -{ - LIBSSH2_SFTP *sftp = (LIBSSH2_SFTP *) (*channel_abstract); - - (void) session_abstract; - (void) channel; - - /* Free the partial packet storage for sftp_packet_read */ - if(sftp->partial_packet) { - LIBSSH2_FREE(session, sftp->partial_packet); - } - - /* Free the packet storage for _libssh2_sftp_packet_readdir */ - if(sftp->readdir_packet) { - LIBSSH2_FREE(session, sftp->readdir_packet); - } - - LIBSSH2_FREE(session, sftp); -} - -/* - * sftp_init - * - * Startup an SFTP session - */ -static LIBSSH2_SFTP *sftp_init(LIBSSH2_SESSION *session) -{ - unsigned char *data; - size_t data_len; - ssize_t rc; - LIBSSH2_SFTP *sftp_handle; - struct string_buf buf; - unsigned char *endp; - - if(session->sftpInit_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Initializing SFTP subsystem"); - - /* - * The 'sftpInit_sftp' and 'sftpInit_channel' struct fields within the - * session struct are only to be used during the setup phase. As soon - * as the SFTP session is created they are cleared and can thus be - * re-used again to allow any amount of SFTP handles per sessions. - * - * Note that you MUST NOT try to call libssh2_sftp_init() again to get - * another handle until the previous call has finished and either - * successfully made a handle or failed and returned error (not - * including *EAGAIN). - */ - - assert(session->sftpInit_sftp == NULL); - session->sftpInit_sftp = NULL; - session->sftpInit_state = libssh2_NB_state_created; - } - - sftp_handle = session->sftpInit_sftp; - - if(session->sftpInit_state == libssh2_NB_state_created) { - session->sftpInit_channel = - _libssh2_channel_open(session, "session", sizeof("session") - 1, - LIBSSH2_CHANNEL_WINDOW_DEFAULT, - LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0); - if(!session->sftpInit_channel) { - if(libssh2_session_last_errno(session) == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block starting up channel"); - } - else { - _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, - "Unable to startup channel"); - session->sftpInit_state = libssh2_NB_state_idle; - } - return NULL; - } - - session->sftpInit_state = libssh2_NB_state_sent; - } - - if(session->sftpInit_state == libssh2_NB_state_sent) { - int ret = _libssh2_channel_process_startup(session->sftpInit_channel, - "subsystem", - sizeof("subsystem") - 1, - "sftp", - strlen("sftp")); - if(ret == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block to request SFTP subsystem"); - return NULL; - } - else if(ret) { - _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, - "Unable to request SFTP subsystem"); - goto sftp_init_error; - } - - session->sftpInit_state = libssh2_NB_state_sent1; - } - - if(session->sftpInit_state == libssh2_NB_state_sent1) { - rc = _libssh2_channel_extended_data(session->sftpInit_channel, - LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE); - if(rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block requesting handle extended data"); - return NULL; - } - - sftp_handle = - session->sftpInit_sftp = - LIBSSH2_CALLOC(session, sizeof(LIBSSH2_SFTP)); - if(!sftp_handle) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate a new SFTP structure"); - goto sftp_init_error; - } - sftp_handle->channel = session->sftpInit_channel; - sftp_handle->request_id = 0; - - _libssh2_htonu32(session->sftpInit_buffer, 5); - session->sftpInit_buffer[4] = SSH_FXP_INIT; - _libssh2_htonu32(session->sftpInit_buffer + 5, LIBSSH2_SFTP_VERSION); - session->sftpInit_sent = 0; /* nothing's sent yet */ - - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Sending FXP_INIT packet advertising " - "version %d support", - (int) LIBSSH2_SFTP_VERSION); - - session->sftpInit_state = libssh2_NB_state_sent2; - } - - if(session->sftpInit_state == libssh2_NB_state_sent2) { - /* sent off what's left of the init buffer to send */ - rc = _libssh2_channel_write(session->sftpInit_channel, 0, - session->sftpInit_buffer + - session->sftpInit_sent, - 9 - session->sftpInit_sent); - if(rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block sending SSH_FXP_INIT"); - return NULL; - } - else if(rc < 0) { - _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send SSH_FXP_INIT"); - goto sftp_init_error; - } - else { - /* add up the number of bytes sent */ - session->sftpInit_sent += rc; - - if(session->sftpInit_sent == 9) - /* move on */ - session->sftpInit_state = libssh2_NB_state_sent3; - - /* if less than 9, we remain in this state to send more later on */ - } - } - - rc = sftp_packet_require(sftp_handle, SSH_FXP_VERSION, - 0, &data, &data_len, 5); - if(rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block receiving SSH_FXP_VERSION"); - return NULL; - } - else if(rc == LIBSSH2_ERROR_BUFFER_TOO_SMALL) { - if(data_len > 0) { - LIBSSH2_FREE(session, data); - } - _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "Invalid SSH_FXP_VERSION response"); - goto sftp_init_error; - } - else if(rc) { - _libssh2_error(session, rc, - "Timeout waiting for response from SFTP subsystem"); - goto sftp_init_error; - } - - buf.data = data; - buf.dataptr = buf.data + 1; - buf.len = data_len; - endp = &buf.data[data_len]; - - if(_libssh2_get_u32(&buf, &(sftp_handle->version)) != 0) { - LIBSSH2_FREE(session, data); - rc = LIBSSH2_ERROR_BUFFER_TOO_SMALL; - goto sftp_init_error; - } - - if(sftp_handle->version > LIBSSH2_SFTP_VERSION) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Truncating remote SFTP version from %lu", - sftp_handle->version); - sftp_handle->version = LIBSSH2_SFTP_VERSION; - } - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Enabling SFTP version %lu compatibility", - sftp_handle->version); - while(buf.dataptr < endp) { - unsigned char *extname, *extdata; - - if(_libssh2_get_string(&buf, &extname, NULL)) { - LIBSSH2_FREE(session, data); - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "Data too short when extracting extname"); - goto sftp_init_error; - } - - if(_libssh2_get_string(&buf, &extdata, NULL)) { - LIBSSH2_FREE(session, data); - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "Data too short when extracting extdata"); - goto sftp_init_error; - } - } - LIBSSH2_FREE(session, data); - - /* Make sure that when the channel gets closed, the SFTP service is shut - down too */ - sftp_handle->channel->abstract = sftp_handle; - sftp_handle->channel->close_cb = libssh2_sftp_dtor; - - session->sftpInit_state = libssh2_NB_state_idle; - - /* clear the sftp and channel pointers in this session struct now */ - session->sftpInit_sftp = NULL; - session->sftpInit_channel = NULL; - - _libssh2_list_init(&sftp_handle->sftp_handles); - - return sftp_handle; - - sftp_init_error: - while(_libssh2_channel_free(session->sftpInit_channel) == - LIBSSH2_ERROR_EAGAIN); - session->sftpInit_channel = NULL; - if(session->sftpInit_sftp) { - LIBSSH2_FREE(session, session->sftpInit_sftp); - session->sftpInit_sftp = NULL; - } - session->sftpInit_state = libssh2_NB_state_idle; - return NULL; -} - -/* - * libssh2_sftp_init - * - * Startup an SFTP session - */ -LIBSSH2_API LIBSSH2_SFTP *libssh2_sftp_init(LIBSSH2_SESSION *session) -{ - LIBSSH2_SFTP *ptr; - - if(!session) - return NULL; - - if(!(session->state & LIBSSH2_STATE_AUTHENTICATED)) { - _libssh2_error(session, LIBSSH2_ERROR_INVAL, - "session not authenticated yet"); - return NULL; - } - - BLOCK_ADJUST_ERRNO(ptr, session, sftp_init(session)); - return ptr; -} - -/* - * sftp_shutdown - * - * Shuts down the SFTP subsystem - */ -static int -sftp_shutdown(LIBSSH2_SFTP *sftp) -{ - int rc; - LIBSSH2_SESSION *session = sftp->channel->session; - /* - * Make sure all memory used in the state variables are free - */ - if(sftp->partial_packet) { - LIBSSH2_FREE(session, sftp->partial_packet); - sftp->partial_packet = NULL; - } - if(sftp->open_packet) { - LIBSSH2_FREE(session, sftp->open_packet); - sftp->open_packet = NULL; - } - if(sftp->readdir_packet) { - LIBSSH2_FREE(session, sftp->readdir_packet); - sftp->readdir_packet = NULL; - } - if(sftp->fstat_packet) { - LIBSSH2_FREE(session, sftp->fstat_packet); - sftp->fstat_packet = NULL; - } - if(sftp->unlink_packet) { - LIBSSH2_FREE(session, sftp->unlink_packet); - sftp->unlink_packet = NULL; - } - if(sftp->rename_packet) { - LIBSSH2_FREE(session, sftp->rename_packet); - sftp->rename_packet = NULL; - } - if(sftp->fstatvfs_packet) { - LIBSSH2_FREE(session, sftp->fstatvfs_packet); - sftp->fstatvfs_packet = NULL; - } - if(sftp->statvfs_packet) { - LIBSSH2_FREE(session, sftp->statvfs_packet); - sftp->statvfs_packet = NULL; - } - if(sftp->mkdir_packet) { - LIBSSH2_FREE(session, sftp->mkdir_packet); - sftp->mkdir_packet = NULL; - } - if(sftp->rmdir_packet) { - LIBSSH2_FREE(session, sftp->rmdir_packet); - sftp->rmdir_packet = NULL; - } - if(sftp->stat_packet) { - LIBSSH2_FREE(session, sftp->stat_packet); - sftp->stat_packet = NULL; - } - if(sftp->symlink_packet) { - LIBSSH2_FREE(session, sftp->symlink_packet); - sftp->symlink_packet = NULL; - } - if(sftp->fsync_packet) { - LIBSSH2_FREE(session, sftp->fsync_packet); - sftp->fsync_packet = NULL; - } - - sftp_packet_flush(sftp); - - /* TODO: We should consider walking over the sftp_handles list and kill - * any remaining sftp handles ... */ - - rc = _libssh2_channel_free(sftp->channel); - - return rc; -} - -/* libssh2_sftp_shutdown - * Shutsdown the SFTP subsystem - */ -LIBSSH2_API int -libssh2_sftp_shutdown(LIBSSH2_SFTP *sftp) -{ - int rc; - if(!sftp) - return LIBSSH2_ERROR_BAD_USE; - BLOCK_ADJUST(rc, sftp->channel->session, sftp_shutdown(sftp)); - return rc; -} - -/* ******************************* - * SFTP File and Directory Ops * - ******************************* */ - -/* sftp_open - */ -static LIBSSH2_SFTP_HANDLE * -sftp_open(LIBSSH2_SFTP *sftp, const char *filename, - size_t filename_len, uint32_t flags, long mode, - int open_type) -{ - LIBSSH2_CHANNEL *channel = sftp->channel; - LIBSSH2_SESSION *session = channel->session; - LIBSSH2_SFTP_HANDLE *fp; - LIBSSH2_SFTP_ATTRIBUTES attrs = { - LIBSSH2_SFTP_ATTR_PERMISSIONS, 0, 0, 0, 0, 0, 0 - }; - unsigned char *s; - ssize_t rc; - int open_file = (open_type == LIBSSH2_SFTP_OPENFILE)?1:0; - - if(sftp->open_state == libssh2_NB_state_idle) { - /* packet_len(4) + packet_type(1) + request_id(4) + filename_len(4) + - flags(4) */ - sftp->open_packet_len = filename_len + 13 + - (open_file? (4 + - sftp_attrsize(LIBSSH2_SFTP_ATTR_PERMISSIONS)) : 0); - - /* surprise! this starts out with nothing sent */ - sftp->open_packet_sent = 0; - s = sftp->open_packet = LIBSSH2_ALLOC(session, sftp->open_packet_len); - if(!sftp->open_packet) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for FXP_OPEN or " - "FXP_OPENDIR packet"); - return NULL; - } - /* Filetype in SFTP 3 and earlier */ - attrs.permissions = mode | - (open_file ? LIBSSH2_SFTP_ATTR_PFILETYPE_FILE : - LIBSSH2_SFTP_ATTR_PFILETYPE_DIR); - - _libssh2_store_u32(&s, sftp->open_packet_len - 4); - *(s++) = open_file? SSH_FXP_OPEN : SSH_FXP_OPENDIR; - sftp->open_request_id = sftp->request_id++; - _libssh2_store_u32(&s, sftp->open_request_id); - _libssh2_store_str(&s, filename, filename_len); - - if(open_file) { - _libssh2_store_u32(&s, flags); - s += sftp_attr2bin(s, &attrs); - } - - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Sending %s open request", - open_file? "file" : "directory"); - - sftp->open_state = libssh2_NB_state_created; - } - - if(sftp->open_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, sftp->open_packet+ - sftp->open_packet_sent, - sftp->open_packet_len - - sftp->open_packet_sent); - if(rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block sending FXP_OPEN or " - "FXP_OPENDIR command"); - return NULL; - } - else if(rc < 0) { - _libssh2_error(session, rc, "Unable to send FXP_OPEN*"); - LIBSSH2_FREE(session, sftp->open_packet); - sftp->open_packet = NULL; - sftp->open_state = libssh2_NB_state_idle; - return NULL; - } - - /* bump the sent counter and remain in this state until the whole - data is off */ - sftp->open_packet_sent += rc; - - if(sftp->open_packet_len == sftp->open_packet_sent) { - LIBSSH2_FREE(session, sftp->open_packet); - sftp->open_packet = NULL; - - sftp->open_state = libssh2_NB_state_sent; - } - } - - if(sftp->open_state == libssh2_NB_state_sent) { - size_t data_len; - unsigned char *data; - static const unsigned char fopen_responses[2] = - { SSH_FXP_HANDLE, SSH_FXP_STATUS }; - rc = sftp_packet_requirev(sftp, 2, fopen_responses, - sftp->open_request_id, &data, - &data_len, 1); - if(rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block waiting for status message"); - return NULL; - } - else if(rc == LIBSSH2_ERROR_BUFFER_TOO_SMALL) { - if(data_len > 0) { - LIBSSH2_FREE(session, data); - } - _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "Response too small"); - return NULL; - } - sftp->open_state = libssh2_NB_state_idle; - if(rc) { - _libssh2_error(session, rc, "Timeout waiting for status message"); - return NULL; - } - - /* OPEN can basically get STATUS or HANDLE back, where HANDLE implies - a fine response while STATUS means error. It seems though that at - times we get an SSH_FX_OK back in a STATUS, followed the "real" - HANDLE so we need to properly deal with that. */ - if(data[0] == SSH_FXP_STATUS) { - int badness = 1; - - if(data_len < 9) { - _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "Too small FXP_STATUS"); - LIBSSH2_FREE(session, data); - return NULL; - } - - sftp->last_errno = _libssh2_ntohu32(data + 5); - - if(LIBSSH2_FX_OK == sftp->last_errno) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "got HANDLE FXOK!"); - - LIBSSH2_FREE(session, data); - - /* silly situation, but check for a HANDLE */ - rc = sftp_packet_require(sftp, SSH_FXP_HANDLE, - sftp->open_request_id, &data, - &data_len, 10); - if(rc == LIBSSH2_ERROR_EAGAIN) { - /* go back to sent state and wait for something else */ - sftp->open_state = libssh2_NB_state_sent; - return NULL; - } - else if(rc == LIBSSH2_ERROR_BUFFER_TOO_SMALL) { - if(data_len > 0) { - LIBSSH2_FREE(session, data); - } - _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "Too small FXP_HANDLE"); - return NULL; - } - else if(!rc) - /* we got the handle so this is not a bad situation */ - badness = 0; - } - - if(badness) { - _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "Failed opening remote file"); - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "got FXP_STATUS %d", - sftp->last_errno); - LIBSSH2_FREE(session, data); - return NULL; - } - } - - if(data_len < 10) { - _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "Too small FXP_HANDLE"); - LIBSSH2_FREE(session, data); - return NULL; - } - - fp = LIBSSH2_CALLOC(session, sizeof(LIBSSH2_SFTP_HANDLE)); - if(!fp) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate new SFTP handle structure"); - LIBSSH2_FREE(session, data); - return NULL; - } - fp->handle_type = open_file ? LIBSSH2_SFTP_HANDLE_FILE : - LIBSSH2_SFTP_HANDLE_DIR; - - fp->handle_len = _libssh2_ntohu32(data + 5); - if(fp->handle_len > SFTP_HANDLE_MAXLEN) - /* SFTP doesn't allow handles longer than 256 characters */ - fp->handle_len = SFTP_HANDLE_MAXLEN; - - if(fp->handle_len > (data_len - 9)) - /* do not reach beyond the end of the data we got */ - fp->handle_len = data_len - 9; - - memcpy(fp->handle, data + 9, fp->handle_len); - - LIBSSH2_FREE(session, data); - - /* add this file handle to the list kept in the sftp session */ - _libssh2_list_add(&sftp->sftp_handles, &fp->node); - - fp->sftp = sftp; /* point to the parent struct */ - - fp->u.file.offset = 0; - fp->u.file.offset_sent = 0; - - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Open command successful"); - return fp; - } - return NULL; -} - -/* libssh2_sftp_open_ex - */ -LIBSSH2_API LIBSSH2_SFTP_HANDLE * -libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, const char *filename, - unsigned int filename_len, unsigned long flags, long mode, - int open_type) -{ - LIBSSH2_SFTP_HANDLE *hnd; - - if(!sftp) - return NULL; - - BLOCK_ADJUST_ERRNO(hnd, sftp->channel->session, - sftp_open(sftp, filename, filename_len, flags, mode, - open_type)); - return hnd; -} - -/* - * sftp_read - * - * Read from an SFTP file handle - * - */ -static ssize_t sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer, - size_t buffer_size) -{ - LIBSSH2_SFTP *sftp = handle->sftp; - LIBSSH2_CHANNEL *channel = sftp->channel; - LIBSSH2_SESSION *session = channel->session; - size_t count = 0; - struct sftp_pipeline_chunk *chunk; - struct sftp_pipeline_chunk *next; - ssize_t rc; - struct _libssh2_sftp_handle_file_data *filep = - &handle->u.file; - size_t bytes_in_buffer = 0; - char *sliding_bufferp = buffer; - - /* This function can be interrupted in three different places where it - might need to wait for data from the network. It returns EAGAIN to - allow non-blocking clients to do other work but these client are - expected to call this function again (possibly many times) to finish - the operation. - - The tricky part is that if we previously aborted a sftp_read due to - EAGAIN, we must continue at the same spot to continue the previously - interrupted operation. This is done using a state machine to record - what phase of execution we were at. The state is stored in - sftp->read_state. - - libssh2_NB_state_idle: The first phase is where we prepare multiple - FXP_READ packets to do optimistic read-ahead. We send off as many as - possible in the second phase without waiting for a response to each - one; this is the key to fast reads. But we may have to adjust the - channel window size to do this which may interrupt this function while - waiting. The state machine saves the phase as libssh2_NB_state_idle so - it returns here on the next call. - - libssh2_NB_state_sent: The second phase is where we send the FXP_READ - packets. Writing them to the channel can be interrupted with EAGAIN - but the state machine ensures we skip the first phase on the next call - and resume sending. - - libssh2_NB_state_sent2: In the third phase (indicated by ) we read the - data from the responses that have arrived so far. Reading can be - interrupted with EAGAIN but the state machine ensures we skip the first - and second phases on the next call and resume sending. - */ - - switch(sftp->read_state) { - case libssh2_NB_state_idle: - - /* Some data may already have been read from the server in the - previous call but didn't fit in the buffer at the time. If so, we - return that now as we can't risk being interrupted later with data - partially written to the buffer. */ - if(filep->data_left) { - size_t copy = MIN(buffer_size, filep->data_left); - - memcpy(buffer, &filep->data[ filep->data_len - filep->data_left], - copy); - - filep->data_left -= copy; - filep->offset += copy; - - if(!filep->data_left) { - LIBSSH2_FREE(session, filep->data); - filep->data = NULL; - } - - return copy; - } - - if(filep->eof) { - return 0; - } - else { - /* We allow a number of bytes being requested at any given time - without having been acked - until we reach EOF. */ - - /* Number of bytes asked for that haven't been acked yet */ - size_t already = (size_t)(filep->offset_sent - filep->offset); - - size_t max_read_ahead = buffer_size*4; - unsigned long recv_window; - - if(max_read_ahead > LIBSSH2_CHANNEL_WINDOW_DEFAULT*4) - max_read_ahead = LIBSSH2_CHANNEL_WINDOW_DEFAULT*4; - - /* if the buffer_size passed in now is smaller than what has - already been sent, we risk getting count become a very large - number */ - if(max_read_ahead > already) - count = max_read_ahead - already; - - /* 'count' is how much more data to ask for, and 'already' is how - much data that already has been asked for but not yet returned. - Specifically, 'count' means how much data that have or will be - asked for by the nodes that are already added to the linked - list. Some of those read requests may not actually have been - sent off successfully yet. - - If 'already' is very large it should be perfectly fine to have - count set to 0 as then we don't have to ask for more data - (right now). - - buffer_size*4 is just picked more or less out of the air. The - idea is that when reading SFTP from a remote server, we send - away multiple read requests guessing that the client will read - more than only this 'buffer_size' amount of memory. So we ask - for maximum buffer_size*4 amount of data so that we can return - them very fast in subsequent calls. - */ - - recv_window = libssh2_channel_window_read_ex(sftp->channel, - NULL, NULL); - if(max_read_ahead > recv_window) { - /* more data will be asked for than what the window currently - allows, expand it! */ - - rc = _libssh2_channel_receive_window_adjust(sftp->channel, - max_read_ahead*8, - 1, NULL); - /* if this returns EAGAIN, we will get back to this function - at next call */ - assert(rc != LIBSSH2_ERROR_EAGAIN || !filep->data_left); - assert(rc != LIBSSH2_ERROR_EAGAIN || !filep->eof); - if(rc) - return rc; - } - } - - while(count > 0) { - unsigned char *s; - - /* 25 = packet_len(4) + packet_type(1) + request_id(4) + - handle_len(4) + offset(8) + count(4) */ - uint32_t packet_len = (uint32_t)handle->handle_len + 25; - uint32_t request_id; - - uint32_t size = count; - if(size < buffer_size) - size = buffer_size; - if(size > MAX_SFTP_READ_SIZE) - size = MAX_SFTP_READ_SIZE; - - chunk = LIBSSH2_ALLOC(session, packet_len + - sizeof(struct sftp_pipeline_chunk)); - if(!chunk) - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "malloc fail for FXP_WRITE"); - - chunk->offset = filep->offset_sent; - chunk->len = size; - chunk->lefttosend = packet_len; - chunk->sent = 0; - - s = chunk->packet; - - _libssh2_store_u32(&s, packet_len - 4); - *s++ = SSH_FXP_READ; - request_id = sftp->request_id++; - chunk->request_id = request_id; - _libssh2_store_u32(&s, request_id); - _libssh2_store_str(&s, handle->handle, handle->handle_len); - _libssh2_store_u64(&s, filep->offset_sent); - filep->offset_sent += size; /* advance offset at once */ - _libssh2_store_u32(&s, size); - - /* add this new entry LAST in the list */ - _libssh2_list_add(&handle->packet_list, &chunk->node); - count -= MIN(size, count); /* deduct the size we used, as we might - * have to create more packets */ - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "read request id %d sent (offset: %d, size: %d)", - request_id, (int)chunk->offset, (int)chunk->len); - } - /* FALL-THROUGH */ - case libssh2_NB_state_sent: - - sftp->read_state = libssh2_NB_state_idle; - - /* move through the READ packets that haven't been sent and send as - many as possible - remember that we don't block */ - chunk = _libssh2_list_first(&handle->packet_list); - - while(chunk) { - if(chunk->lefttosend) { - - rc = _libssh2_channel_write(channel, 0, - &chunk->packet[chunk->sent], - chunk->lefttosend); - if(rc < 0) { - sftp->read_state = libssh2_NB_state_sent; - return rc; - } - - /* remember where to continue sending the next time */ - chunk->lefttosend -= rc; - chunk->sent += rc; - - if(chunk->lefttosend) { - /* We still have data left to send for this chunk. - * If there is at least one completely sent chunk, - * we can get out of this loop and start reading. */ - if(chunk != _libssh2_list_first(&handle->packet_list)) { - break; - } - else { - continue; - } - } - } - - /* move on to the next chunk with data to send */ - chunk = _libssh2_list_next(&chunk->node); - } - /* FALL-THROUGH */ - - case libssh2_NB_state_sent2: - - sftp->read_state = libssh2_NB_state_idle; - - /* - * Count all ACKed packets and act on the contents of them. - */ - chunk = _libssh2_list_first(&handle->packet_list); - - while(chunk) { - unsigned char *data; - size_t data_len; - uint32_t rc32; - static const unsigned char read_responses[2] = { - SSH_FXP_DATA, SSH_FXP_STATUS - }; - - if(chunk->lefttosend) { - /* if the chunk still has data left to send, we shouldn't wait - for an ACK for it just yet */ - if(bytes_in_buffer > 0) { - return bytes_in_buffer; - } - else { - /* we should never reach this point */ - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "sftp_read() internal error"); - } - } - - rc = sftp_packet_requirev(sftp, 2, read_responses, - chunk->request_id, &data, &data_len, 9); - if(rc == LIBSSH2_ERROR_EAGAIN && bytes_in_buffer != 0) { - /* do not return EAGAIN if we have already - * written data into the buffer */ - return bytes_in_buffer; - } - - if(rc == LIBSSH2_ERROR_BUFFER_TOO_SMALL) { - if(data_len > 0) { - LIBSSH2_FREE(session, data); - } - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "Response too small"); - } - else if(rc < 0) { - sftp->read_state = libssh2_NB_state_sent2; - return rc; - } - - /* - * We get DATA or STATUS back. STATUS can be error, or it is - * FX_EOF when we reach the end of the file. - */ - - switch(data[0]) { - case SSH_FXP_STATUS: - /* remove the chunk we just processed */ - - _libssh2_list_remove(&chunk->node); - LIBSSH2_FREE(session, chunk); - - /* we must remove all outstanding READ requests, as either we - got an error or we're at end of file */ - sftp_packetlist_flush(handle); - - rc32 = _libssh2_ntohu32(data + 5); - LIBSSH2_FREE(session, data); - - if(rc32 == LIBSSH2_FX_EOF) { - filep->eof = TRUE; - return bytes_in_buffer; - } - else { - sftp->last_errno = rc32; - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP READ error"); - } - break; - - case SSH_FXP_DATA: - if(chunk->offset != filep->offset) { - /* This could happen if the server returns less bytes than - requested, which shouldn't happen for normal files. See: - https://tools.ietf.org/html/draft-ietf-secsh-filexfer-02 - #section-6.4 - */ - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "Read Packet At Unexpected Offset"); - } - - rc32 = _libssh2_ntohu32(data + 5); - if(rc32 > (data_len - 9)) - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP Protocol badness"); - - if(rc32 > chunk->len) { - /* A chunk larger than we requested was returned to us. - This is a protocol violation and we don't know how to - deal with it. Bail out! */ - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "FXP_READ response too big"); - } - - if(rc32 != chunk->len) { - /* a short read does not imply end of file, but we must - adjust the offset_sent since it was advanced with a - full chunk->len before */ - filep->offset_sent -= (chunk->len - rc32); - } - - if((bytes_in_buffer + rc32) > buffer_size) { - /* figure out the overlap amount */ - filep->data_left = (bytes_in_buffer + rc32) - buffer_size; - - /* getting the full packet would overflow the buffer, so - only get the correct amount and keep the remainder */ - rc32 = (uint32_t)buffer_size - bytes_in_buffer; - - /* store data to keep for next call */ - filep->data = data; - filep->data_len = data_len; - } - else - filep->data_len = 0; - - /* copy the received data from the received FXP_DATA packet to - the buffer at the correct index */ - memcpy(sliding_bufferp, data + 9, rc32); - filep->offset += rc32; - bytes_in_buffer += rc32; - sliding_bufferp += rc32; - - if(filep->data_len == 0) - /* free the allocated data if not stored to keep */ - LIBSSH2_FREE(session, data); - - /* remove the chunk we just processed keeping track of the - * next one in case we need it */ - next = _libssh2_list_next(&chunk->node); - _libssh2_list_remove(&chunk->node); - LIBSSH2_FREE(session, chunk); - - /* check if we have space left in the buffer - * and either continue to the next chunk or stop - */ - if(bytes_in_buffer < buffer_size) { - chunk = next; - } - else { - chunk = NULL; - } - - break; - default: - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP Protocol badness: unrecognised " - "read request response"); - } - } - - if(bytes_in_buffer > 0) - return bytes_in_buffer; - - break; - - default: - assert(!"State machine error; unrecognised read state"); - } - - /* we should never reach this point */ - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "sftp_read() internal error"); -} - -/* libssh2_sftp_read - * Read from an SFTP file handle - */ -LIBSSH2_API ssize_t -libssh2_sftp_read(LIBSSH2_SFTP_HANDLE *hnd, char *buffer, - size_t buffer_maxlen) -{ - ssize_t rc; - if(!hnd) - return LIBSSH2_ERROR_BAD_USE; - BLOCK_ADJUST(rc, hnd->sftp->channel->session, - sftp_read(hnd, buffer, buffer_maxlen)); - return rc; -} - -/* sftp_readdir - * Read from an SFTP directory handle - */ -static ssize_t sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer, - size_t buffer_maxlen, char *longentry, - size_t longentry_maxlen, - LIBSSH2_SFTP_ATTRIBUTES *attrs) -{ - LIBSSH2_SFTP *sftp = handle->sftp; - LIBSSH2_CHANNEL *channel = sftp->channel; - LIBSSH2_SESSION *session = channel->session; - size_t data_len; - uint32_t num_names; - /* 13 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) */ - uint32_t packet_len = handle->handle_len + 13; - unsigned char *s, *data; - static const unsigned char read_responses[2] = { - SSH_FXP_NAME, SSH_FXP_STATUS }; - ssize_t retcode; - - if(sftp->readdir_state == libssh2_NB_state_idle) { - if(handle->u.dir.names_left) { - /* - * A prior request returned more than one directory entry, - * feed it back from the buffer - */ - LIBSSH2_SFTP_ATTRIBUTES attrs_dummy; - size_t real_longentry_len; - size_t real_filename_len; - size_t filename_len; - size_t longentry_len; - size_t names_packet_len = handle->u.dir.names_packet_len; - int attr_len = 0; - - if(names_packet_len >= 4) { - s = (unsigned char *) handle->u.dir.next_name; - real_filename_len = _libssh2_ntohu32(s); - s += 4; - names_packet_len -= 4; - } - else { - filename_len = (size_t)LIBSSH2_ERROR_BUFFER_TOO_SMALL; - goto end; - } - - filename_len = real_filename_len; - if(filename_len >= buffer_maxlen) { - filename_len = (size_t)LIBSSH2_ERROR_BUFFER_TOO_SMALL; - goto end; - } - - if(buffer_maxlen >= filename_len && names_packet_len >= - filename_len) { - memcpy(buffer, s, filename_len); - buffer[filename_len] = '\0'; /* zero terminate */ - s += real_filename_len; - names_packet_len -= real_filename_len; - } - else { - filename_len = (size_t)LIBSSH2_ERROR_BUFFER_TOO_SMALL; - goto end; - } - - if(names_packet_len >= 4) { - real_longentry_len = _libssh2_ntohu32(s); - s += 4; - names_packet_len -= 4; - } - else { - filename_len = (size_t)LIBSSH2_ERROR_BUFFER_TOO_SMALL; - goto end; - } - - if(longentry && (longentry_maxlen>1)) { - longentry_len = real_longentry_len; - - if(longentry_len >= longentry_maxlen || - longentry_len > names_packet_len) { - filename_len = (size_t)LIBSSH2_ERROR_BUFFER_TOO_SMALL; - goto end; - } - - memcpy(longentry, s, longentry_len); - longentry[longentry_len] = '\0'; /* zero terminate */ - } - - if(real_longentry_len <= names_packet_len) { - s += real_longentry_len; - names_packet_len -= real_longentry_len; - } - else { - filename_len = (size_t)LIBSSH2_ERROR_BUFFER_TOO_SMALL; - goto end; - } - - if(attrs) - memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES)); - - attr_len = sftp_bin2attr(attrs ? attrs : &attrs_dummy, s, - names_packet_len); - - if(attr_len >= 0) { - s += attr_len; - names_packet_len -= attr_len; - } - else { - filename_len = (size_t)LIBSSH2_ERROR_BUFFER_TOO_SMALL; - goto end; - } - - handle->u.dir.next_name = (char *) s; - handle->u.dir.names_packet_len = names_packet_len; - end: - - if((--handle->u.dir.names_left) == 0) - LIBSSH2_FREE(session, handle->u.dir.names_packet); - - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "libssh2_sftp_readdir_ex() return %d", - filename_len); - return (ssize_t)filename_len; - } - - /* Request another entry(entries?) */ - - s = sftp->readdir_packet = LIBSSH2_ALLOC(session, packet_len); - if(!sftp->readdir_packet) - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "FXP_READDIR packet"); - - _libssh2_store_u32(&s, packet_len - 4); - *(s++) = SSH_FXP_READDIR; - sftp->readdir_request_id = sftp->request_id++; - _libssh2_store_u32(&s, sftp->readdir_request_id); - _libssh2_store_str(&s, handle->handle, handle->handle_len); - - sftp->readdir_state = libssh2_NB_state_created; - } - - if(sftp->readdir_state == libssh2_NB_state_created) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Reading entries from directory handle"); - retcode = _libssh2_channel_write(channel, 0, sftp->readdir_packet, - packet_len); - if(retcode == LIBSSH2_ERROR_EAGAIN) { - return retcode; - } - else if((ssize_t)packet_len != retcode) { - LIBSSH2_FREE(session, sftp->readdir_packet); - sftp->readdir_packet = NULL; - sftp->readdir_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "_libssh2_channel_write() failed"); - } - - LIBSSH2_FREE(session, sftp->readdir_packet); - sftp->readdir_packet = NULL; - - sftp->readdir_state = libssh2_NB_state_sent; - } - - retcode = sftp_packet_requirev(sftp, 2, read_responses, - sftp->readdir_request_id, &data, - &data_len, 9); - if(retcode == LIBSSH2_ERROR_EAGAIN) - return retcode; - else if(retcode == LIBSSH2_ERROR_BUFFER_TOO_SMALL) { - if(data_len > 0) { - LIBSSH2_FREE(session, data); - } - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "Status message too short"); - } - else if(retcode) { - sftp->readdir_state = libssh2_NB_state_idle; - return _libssh2_error(session, retcode, - "Timeout waiting for status message"); - } - - if(data[0] == SSH_FXP_STATUS) { - retcode = _libssh2_ntohu32(data + 5); - LIBSSH2_FREE(session, data); - if(retcode == LIBSSH2_FX_EOF) { - sftp->readdir_state = libssh2_NB_state_idle; - return 0; - } - else { - sftp->last_errno = retcode; - sftp->readdir_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP Protocol Error"); - } - } - - sftp->readdir_state = libssh2_NB_state_idle; - - num_names = _libssh2_ntohu32(data + 5); - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "%lu entries returned", - num_names); - if(!num_names) { - LIBSSH2_FREE(session, data); - return 0; - } - - handle->u.dir.names_left = num_names; - handle->u.dir.names_packet = data; - handle->u.dir.next_name = (char *) data + 9; - handle->u.dir.names_packet_len = data_len - 9; - - /* use the name popping mechanism from the start of the function */ - return sftp_readdir(handle, buffer, buffer_maxlen, longentry, - longentry_maxlen, attrs); -} - -/* libssh2_sftp_readdir_ex - * Read from an SFTP directory handle - */ -LIBSSH2_API int -libssh2_sftp_readdir_ex(LIBSSH2_SFTP_HANDLE *hnd, char *buffer, - size_t buffer_maxlen, char *longentry, - size_t longentry_maxlen, - LIBSSH2_SFTP_ATTRIBUTES *attrs) -{ - int rc; - if(!hnd) - return LIBSSH2_ERROR_BAD_USE; - BLOCK_ADJUST(rc, hnd->sftp->channel->session, - sftp_readdir(hnd, buffer, buffer_maxlen, longentry, - longentry_maxlen, attrs)); - return rc; -} - -/* - * sftp_write - * - * Write data to an SFTP handle. Returns the number of bytes written, or - * a negative error code. - * - * We recommend sending very large data buffers to this function! - * - * Concept: - * - * - Detect how much of the given buffer that was already sent in a previous - * call by inspecting the linked list of outgoing chunks. Make sure to skip - * passed the data that has already been taken care of. - * - * - Split all (new) outgoing data in chunks no larger than N. - * - * - Each N bytes chunk gets created as a separate SFTP packet. - * - * - Add all created outgoing packets to the linked list. - * - * - Walk through the list and send the chunks that haven't been sent, - * as many as possible until EAGAIN. Some of the chunks may have been put - * in the list in a previous invoke. - * - * - For all the chunks in the list that have been completely sent off, check - * for ACKs. If a chunk has been ACKed, it is removed from the linked - * list and the "acked" counter gets increased with that data amount. - * - * - Return TOTAL bytes acked so far. - * - * Caveats: - * - be careful: we must not return a higher number than what was given! - * - * TODO: - * Introduce an option that disables this sort of "speculative" ahead writing - * as there's a risk that it will do harm to some app. - */ - -static ssize_t sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *buffer, - size_t count) -{ - LIBSSH2_SFTP *sftp = handle->sftp; - LIBSSH2_CHANNEL *channel = sftp->channel; - LIBSSH2_SESSION *session = channel->session; - size_t data_len; - uint32_t retcode; - uint32_t packet_len; - unsigned char *s, *data; - ssize_t rc; - struct sftp_pipeline_chunk *chunk; - struct sftp_pipeline_chunk *next; - size_t acked = 0; - size_t org_count = count; - size_t already; - - switch(sftp->write_state) { - default: - case libssh2_NB_state_idle: - - /* Number of bytes sent off that haven't been acked and therefore we - will get passed in here again. - - Also, add up the number of bytes that actually already have been - acked but we haven't been able to return as such yet, so we will - get that data as well passed in here again. - */ - already = (size_t) (handle->u.file.offset_sent - - handle->u.file.offset)+ - handle->u.file.acked; - - if(count >= already) { - /* skip the part already made into packets */ - buffer += already; - count -= already; - } - else - /* there is more data already fine than what we got in this call */ - count = 0; - - sftp->write_state = libssh2_NB_state_idle; - while(count) { - /* TODO: Possibly this should have some logic to prevent a very - very small fraction to be left but lets ignore that for now */ - uint32_t size = MIN(MAX_SFTP_OUTGOING_SIZE, count); - uint32_t request_id; - - /* 25 = packet_len(4) + packet_type(1) + request_id(4) + - handle_len(4) + offset(8) + count(4) */ - packet_len = handle->handle_len + size + 25; - - chunk = LIBSSH2_ALLOC(session, packet_len + - sizeof(struct sftp_pipeline_chunk)); - if(!chunk) - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "malloc fail for FXP_WRITE"); - - chunk->len = size; - chunk->sent = 0; - chunk->lefttosend = packet_len; - - s = chunk->packet; - _libssh2_store_u32(&s, packet_len - 4); - - *(s++) = SSH_FXP_WRITE; - request_id = sftp->request_id++; - chunk->request_id = request_id; - _libssh2_store_u32(&s, request_id); - _libssh2_store_str(&s, handle->handle, handle->handle_len); - _libssh2_store_u64(&s, handle->u.file.offset_sent); - handle->u.file.offset_sent += size; /* advance offset at once */ - _libssh2_store_str(&s, buffer, size); - - /* add this new entry LAST in the list */ - _libssh2_list_add(&handle->packet_list, &chunk->node); - - buffer += size; - count -= size; /* deduct the size we used, as we might have - to create more packets */ - } - - /* move through the WRITE packets that haven't been sent and send as - many as possible - remember that we don't block */ - chunk = _libssh2_list_first(&handle->packet_list); - - while(chunk) { - if(chunk->lefttosend) { - rc = _libssh2_channel_write(channel, 0, - &chunk->packet[chunk->sent], - chunk->lefttosend); - if(rc < 0) - /* remain in idle state */ - return rc; - - /* remember where to continue sending the next time */ - chunk->lefttosend -= rc; - chunk->sent += rc; - - if(chunk->lefttosend) - /* data left to send, get out of loop */ - break; - } - - /* move on to the next chunk with data to send */ - chunk = _libssh2_list_next(&chunk->node); - } - - /* fall-through */ - case libssh2_NB_state_sent: - - sftp->write_state = libssh2_NB_state_idle; - /* - * Count all ACKed packets - */ - chunk = _libssh2_list_first(&handle->packet_list); - - while(chunk) { - if(chunk->lefttosend) - /* if the chunk still has data left to send, we shouldn't wait - for an ACK for it just yet */ - break; - - else if(acked) - /* if we have sent data that is acked, we must return that - info before we call a function that might return EAGAIN */ - break; - - /* we check the packets in order */ - rc = sftp_packet_require(sftp, SSH_FXP_STATUS, - chunk->request_id, &data, &data_len, 9); - if(rc == LIBSSH2_ERROR_BUFFER_TOO_SMALL) { - if(data_len > 0) { - LIBSSH2_FREE(session, data); - } - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "FXP write packet too short"); - } - else if(rc < 0) { - if(rc == LIBSSH2_ERROR_EAGAIN) - sftp->write_state = libssh2_NB_state_sent; - return rc; - } - - retcode = _libssh2_ntohu32(data + 5); - LIBSSH2_FREE(session, data); - - sftp->last_errno = retcode; - if(retcode == LIBSSH2_FX_OK) { - acked += chunk->len; /* number of payload data that was acked - here */ - - /* we increase the offset value for all acks */ - handle->u.file.offset += chunk->len; - - next = _libssh2_list_next(&chunk->node); - - _libssh2_list_remove(&chunk->node); /* remove from list */ - LIBSSH2_FREE(session, chunk); /* free memory */ - - chunk = next; - } - else { - /* flush all pending packets from the outgoing list */ - sftp_packetlist_flush(handle); - - /* since we return error now, the application will not get any - outstanding data acked, so we need to rewind the offset to - where the application knows it has reached with acked - data */ - handle->u.file.offset -= handle->u.file.acked; - - /* then reset the offset_sent to be the same as the offset */ - handle->u.file.offset_sent = handle->u.file.offset; - - /* clear the acked counter since we can have no pending data to - ack after an error */ - handle->u.file.acked = 0; - - /* the server returned an error for that written chunk, - propagate this back to our parent function */ - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "FXP write failed"); - } - } - break; - } - - /* if there were acked data in a previous call that wasn't returned then, - add that up and try to return it all now. This can happen if the app - first sends a huge buffer of data, and then in a second call it sends a - smaller one. */ - acked += handle->u.file.acked; - - if(acked) { - ssize_t ret = MIN(acked, org_count); - /* we got data acked so return that amount, but no more than what - was asked to get sent! */ - - /* store the remainder. 'ret' is always equal to or less than 'acked' - here */ - handle->u.file.acked = acked - ret; - - return ret; - } - - else - return 0; /* nothing was acked, and no EAGAIN was received! */ -} - -/* libssh2_sftp_write - * Write data to a file handle - */ -LIBSSH2_API ssize_t -libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *hnd, const char *buffer, - size_t count) -{ - ssize_t rc; - if(!hnd) - return LIBSSH2_ERROR_BAD_USE; - BLOCK_ADJUST(rc, hnd->sftp->channel->session, - sftp_write(hnd, buffer, count)); - return rc; - -} - -static int sftp_fsync(LIBSSH2_SFTP_HANDLE *handle) -{ - LIBSSH2_SFTP *sftp = handle->sftp; - LIBSSH2_CHANNEL *channel = sftp->channel; - LIBSSH2_SESSION *session = channel->session; - /* 34 = packet_len(4) + packet_type(1) + request_id(4) + - string_len(4) + strlen("fsync@openssh.com")(17) + handle_len(4) */ - uint32_t packet_len = handle->handle_len + 34; - size_t data_len; - unsigned char *packet, *s, *data; - ssize_t rc; - uint32_t retcode; - - if(sftp->fsync_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Issuing fsync command"); - s = packet = LIBSSH2_ALLOC(session, packet_len); - if(!packet) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for FXP_EXTENDED " - "packet"); - } - - _libssh2_store_u32(&s, packet_len - 4); - *(s++) = SSH_FXP_EXTENDED; - sftp->fsync_request_id = sftp->request_id++; - _libssh2_store_u32(&s, sftp->fsync_request_id); - _libssh2_store_str(&s, "fsync@openssh.com", 17); - _libssh2_store_str(&s, handle->handle, handle->handle_len); - - sftp->fsync_state = libssh2_NB_state_created; - } - else { - packet = sftp->fsync_packet; - } - - if(sftp->fsync_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, packet, packet_len); - if(rc == LIBSSH2_ERROR_EAGAIN || - (0 <= rc && rc < (ssize_t)packet_len)) { - sftp->fsync_packet = packet; - return LIBSSH2_ERROR_EAGAIN; - } - - LIBSSH2_FREE(session, packet); - sftp->fsync_packet = NULL; - - if(rc < 0) { - sftp->fsync_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "_libssh2_channel_write() failed"); - } - sftp->fsync_state = libssh2_NB_state_sent; - } - - rc = sftp_packet_require(sftp, SSH_FXP_STATUS, - sftp->fsync_request_id, &data, &data_len, 9); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc == LIBSSH2_ERROR_BUFFER_TOO_SMALL) { - if(data_len > 0) { - LIBSSH2_FREE(session, data); - } - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP fsync packet too short"); - } - else if(rc) { - sftp->fsync_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, - "Error waiting for FXP EXTENDED REPLY"); - } - - sftp->fsync_state = libssh2_NB_state_idle; - - retcode = _libssh2_ntohu32(data + 5); - LIBSSH2_FREE(session, data); - - if(retcode != LIBSSH2_FX_OK) { - sftp->last_errno = retcode; - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "fsync failed"); - } - - return 0; -} - -/* libssh2_sftp_fsync - * Commit data on the handle to disk. - */ -LIBSSH2_API int -libssh2_sftp_fsync(LIBSSH2_SFTP_HANDLE *hnd) -{ - int rc; - if(!hnd) - return LIBSSH2_ERROR_BAD_USE; - BLOCK_ADJUST(rc, hnd->sftp->channel->session, - sftp_fsync(hnd)); - return rc; -} - - -/* - * sftp_fstat - * - * Get or Set stat on a file - */ -static int sftp_fstat(LIBSSH2_SFTP_HANDLE *handle, - LIBSSH2_SFTP_ATTRIBUTES *attrs, int setstat) -{ - LIBSSH2_SFTP *sftp = handle->sftp; - LIBSSH2_CHANNEL *channel = sftp->channel; - LIBSSH2_SESSION *session = channel->session; - size_t data_len; - /* 13 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) */ - uint32_t packet_len = - handle->handle_len + 13 + (setstat ? sftp_attrsize(attrs->flags) : 0); - unsigned char *s, *data; - static const unsigned char fstat_responses[2] = - { SSH_FXP_ATTRS, SSH_FXP_STATUS }; - ssize_t rc; - - if(sftp->fstat_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Issuing %s command", - setstat ? "set-stat" : "stat"); - s = sftp->fstat_packet = LIBSSH2_ALLOC(session, packet_len); - if(!sftp->fstat_packet) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "FSTAT/FSETSTAT packet"); - } - - _libssh2_store_u32(&s, packet_len - 4); - *(s++) = setstat ? SSH_FXP_FSETSTAT : SSH_FXP_FSTAT; - sftp->fstat_request_id = sftp->request_id++; - _libssh2_store_u32(&s, sftp->fstat_request_id); - _libssh2_store_str(&s, handle->handle, handle->handle_len); - - if(setstat) { - s += sftp_attr2bin(s, attrs); - } - - sftp->fstat_state = libssh2_NB_state_created; - } - - if(sftp->fstat_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, sftp->fstat_packet, - packet_len); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if((ssize_t)packet_len != rc) { - LIBSSH2_FREE(session, sftp->fstat_packet); - sftp->fstat_packet = NULL; - sftp->fstat_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - (setstat ? "Unable to send FXP_FSETSTAT" - : "Unable to send FXP_FSTAT command")); - } - LIBSSH2_FREE(session, sftp->fstat_packet); - sftp->fstat_packet = NULL; - - sftp->fstat_state = libssh2_NB_state_sent; - } - - rc = sftp_packet_requirev(sftp, 2, fstat_responses, - sftp->fstat_request_id, &data, - &data_len, 9); - if(rc == LIBSSH2_ERROR_EAGAIN) - return rc; - else if(rc == LIBSSH2_ERROR_BUFFER_TOO_SMALL) { - if(data_len > 0) { - LIBSSH2_FREE(session, data); - } - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP fstat packet too short"); - } - else if(rc) { - sftp->fstat_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, - "Timeout waiting for status message"); - } - - sftp->fstat_state = libssh2_NB_state_idle; - - if(data[0] == SSH_FXP_STATUS) { - uint32_t retcode; - - retcode = _libssh2_ntohu32(data + 5); - LIBSSH2_FREE(session, data); - if(retcode == LIBSSH2_FX_OK) { - return 0; - } - else { - sftp->last_errno = retcode; - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP Protocol Error"); - } - } - - if(sftp_bin2attr(attrs, data + 5, data_len - 5) < 0) { - LIBSSH2_FREE(session, data); - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "Attributes too short in SFTP fstat"); - } - - LIBSSH2_FREE(session, data); - - return 0; -} - -/* libssh2_sftp_fstat_ex - * Get or Set stat on a file - */ -LIBSSH2_API int -libssh2_sftp_fstat_ex(LIBSSH2_SFTP_HANDLE *hnd, - LIBSSH2_SFTP_ATTRIBUTES *attrs, int setstat) -{ - int rc; - if(!hnd || !attrs) - return LIBSSH2_ERROR_BAD_USE; - BLOCK_ADJUST(rc, hnd->sftp->channel->session, - sftp_fstat(hnd, attrs, setstat)); - return rc; -} - - -/* libssh2_sftp_seek64 - * Set the read/write pointer to an arbitrary position within the file - */ -LIBSSH2_API void -libssh2_sftp_seek64(LIBSSH2_SFTP_HANDLE *handle, libssh2_uint64_t offset) -{ - if(!handle) - return; - if(handle->u.file.offset == offset && handle->u.file.offset_sent == offset) - return; - - handle->u.file.offset = handle->u.file.offset_sent = offset; - /* discard all pending requests and currently read data */ - sftp_packetlist_flush(handle); - - /* free the left received buffered data */ - if(handle->u.file.data_left) { - LIBSSH2_FREE(handle->sftp->channel->session, handle->u.file.data); - handle->u.file.data_left = handle->u.file.data_len = 0; - handle->u.file.data = NULL; - } - - /* reset EOF to False */ - handle->u.file.eof = FALSE; -} - -/* libssh2_sftp_seek - * Set the read/write pointer to an arbitrary position within the file - */ -LIBSSH2_API void -libssh2_sftp_seek(LIBSSH2_SFTP_HANDLE *handle, size_t offset) -{ - libssh2_sftp_seek64(handle, (libssh2_uint64_t)offset); -} - -/* libssh2_sftp_tell - * Return the current read/write pointer's offset - */ -LIBSSH2_API size_t -libssh2_sftp_tell(LIBSSH2_SFTP_HANDLE *handle) -{ - if(!handle) - return 0; /* no handle, no size */ - - /* NOTE: this may very well truncate the size if it is larger than what - size_t can hold, so libssh2_sftp_tell64() is really the function you - should use */ - return (size_t)(handle->u.file.offset); -} - -/* libssh2_sftp_tell64 - * Return the current read/write pointer's offset - */ -LIBSSH2_API libssh2_uint64_t -libssh2_sftp_tell64(LIBSSH2_SFTP_HANDLE *handle) -{ - if(!handle) - return 0; /* no handle, no size */ - - return handle->u.file.offset; -} - -/* - * Flush all remaining incoming SFTP packets and zombies. - */ -static void sftp_packet_flush(LIBSSH2_SFTP *sftp) -{ - LIBSSH2_CHANNEL *channel = sftp->channel; - LIBSSH2_SESSION *session = channel->session; - LIBSSH2_SFTP_PACKET *packet = _libssh2_list_first(&sftp->packets); - struct sftp_zombie_requests *zombie = - _libssh2_list_first(&sftp->zombie_requests); - - while(packet) { - LIBSSH2_SFTP_PACKET *next; - - /* check next struct in the list */ - next = _libssh2_list_next(&packet->node); - _libssh2_list_remove(&packet->node); - LIBSSH2_FREE(session, packet->data); - LIBSSH2_FREE(session, packet); - - packet = next; - } - - while(zombie) { - /* figure out the next node */ - struct sftp_zombie_requests *next = _libssh2_list_next(&zombie->node); - /* unlink the current one */ - _libssh2_list_remove(&zombie->node); - /* free the memory */ - LIBSSH2_FREE(session, zombie); - zombie = next; - } - -} - -/* sftp_close_handle - * - * Close a file or directory handle. - * Also frees handle resource and unlinks it from the SFTP structure. - * The handle is no longer usable after return of this function, unless - * the return value is LIBSSH2_ERROR_EAGAIN in which case this function - * should be called again. - */ -static int -sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle) -{ - LIBSSH2_SFTP *sftp = handle->sftp; - LIBSSH2_CHANNEL *channel = sftp->channel; - LIBSSH2_SESSION *session = channel->session; - size_t data_len; - /* 13 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) */ - uint32_t packet_len = handle->handle_len + 13; - unsigned char *s, *data = NULL; - int rc = 0; - - if(handle->close_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Closing handle"); - s = handle->close_packet = LIBSSH2_ALLOC(session, packet_len); - if(!handle->close_packet) { - handle->close_state = libssh2_NB_state_idle; - rc = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for FXP_CLOSE " - "packet"); - } - else { - - _libssh2_store_u32(&s, packet_len - 4); - *(s++) = SSH_FXP_CLOSE; - handle->close_request_id = sftp->request_id++; - _libssh2_store_u32(&s, handle->close_request_id); - _libssh2_store_str(&s, handle->handle, handle->handle_len); - handle->close_state = libssh2_NB_state_created; - } - } - - if(handle->close_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, handle->close_packet, - packet_len); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if((ssize_t)packet_len != rc) { - handle->close_state = libssh2_NB_state_idle; - rc = _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send FXP_CLOSE command"); - } - else - handle->close_state = libssh2_NB_state_sent; - - LIBSSH2_FREE(session, handle->close_packet); - handle->close_packet = NULL; - } - - if(handle->close_state == libssh2_NB_state_sent) { - rc = sftp_packet_require(sftp, SSH_FXP_STATUS, - handle->close_request_id, &data, - &data_len, 9); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc == LIBSSH2_ERROR_BUFFER_TOO_SMALL) { - if(data_len > 0) { - LIBSSH2_FREE(session, data); - } - data = NULL; - _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "Packet too short in FXP_CLOSE command"); - } - else if(rc) { - _libssh2_error(session, rc, - "Error waiting for status message"); - } - - handle->close_state = libssh2_NB_state_sent1; - } - - if(!data) { - /* if it reaches this point with data unset, something unwanted - happened for which we should have set an error code */ - assert(rc); - - } - else { - int retcode = _libssh2_ntohu32(data + 5); - LIBSSH2_FREE(session, data); - - if(retcode != LIBSSH2_FX_OK) { - sftp->last_errno = retcode; - handle->close_state = libssh2_NB_state_idle; - rc = _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP Protocol Error"); - } - } - - /* remove this handle from the parent's list */ - _libssh2_list_remove(&handle->node); - - if(handle->handle_type == LIBSSH2_SFTP_HANDLE_DIR) { - if(handle->u.dir.names_left) - LIBSSH2_FREE(session, handle->u.dir.names_packet); - } - else if(handle->handle_type == LIBSSH2_SFTP_HANDLE_FILE) { - if(handle->u.file.data) - LIBSSH2_FREE(session, handle->u.file.data); - } - - sftp_packetlist_flush(handle); - sftp->read_state = libssh2_NB_state_idle; - - handle->close_state = libssh2_NB_state_idle; - - LIBSSH2_FREE(session, handle); - - return rc; -} - -/* libssh2_sftp_close_handle - * - * Close a file or directory handle - * Also frees handle resource and unlinks it from the SFTP structure - */ -LIBSSH2_API int -libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE *hnd) -{ - int rc; - if(!hnd) - return LIBSSH2_ERROR_BAD_USE; - BLOCK_ADJUST(rc, hnd->sftp->channel->session, sftp_close_handle(hnd)); - return rc; -} - -/* sftp_unlink - * Delete a file from the remote server - */ -static int sftp_unlink(LIBSSH2_SFTP *sftp, const char *filename, - size_t filename_len) -{ - LIBSSH2_CHANNEL *channel = sftp->channel; - LIBSSH2_SESSION *session = channel->session; - size_t data_len; - int retcode; - /* 13 = packet_len(4) + packet_type(1) + request_id(4) + filename_len(4) */ - uint32_t packet_len = filename_len + 13; - unsigned char *s, *data; - int rc; - - if(sftp->unlink_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Unlinking %s", filename); - s = sftp->unlink_packet = LIBSSH2_ALLOC(session, packet_len); - if(!sftp->unlink_packet) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for FXP_REMOVE " - "packet"); - } - - _libssh2_store_u32(&s, packet_len - 4); - *(s++) = SSH_FXP_REMOVE; - sftp->unlink_request_id = sftp->request_id++; - _libssh2_store_u32(&s, sftp->unlink_request_id); - _libssh2_store_str(&s, filename, filename_len); - sftp->unlink_state = libssh2_NB_state_created; - } - - if(sftp->unlink_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, sftp->unlink_packet, - packet_len); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if((ssize_t)packet_len != rc) { - LIBSSH2_FREE(session, sftp->unlink_packet); - sftp->unlink_packet = NULL; - sftp->unlink_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send FXP_REMOVE command"); - } - LIBSSH2_FREE(session, sftp->unlink_packet); - sftp->unlink_packet = NULL; - - sftp->unlink_state = libssh2_NB_state_sent; - } - - rc = sftp_packet_require(sftp, SSH_FXP_STATUS, - sftp->unlink_request_id, &data, - &data_len, 9); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc == LIBSSH2_ERROR_BUFFER_TOO_SMALL) { - if(data_len > 0) { - LIBSSH2_FREE(session, data); - } - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP unlink packet too short"); - } - else if(rc) { - sftp->unlink_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, - "Error waiting for FXP STATUS"); - } - - sftp->unlink_state = libssh2_NB_state_idle; - - retcode = _libssh2_ntohu32(data + 5); - LIBSSH2_FREE(session, data); - - if(retcode == LIBSSH2_FX_OK) { - return 0; - } - else { - sftp->last_errno = retcode; - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP Protocol Error"); - } -} - -/* libssh2_sftp_unlink_ex - * Delete a file from the remote server - */ -LIBSSH2_API int -libssh2_sftp_unlink_ex(LIBSSH2_SFTP *sftp, const char *filename, - unsigned int filename_len) -{ - int rc; - if(!sftp) - return LIBSSH2_ERROR_BAD_USE; - BLOCK_ADJUST(rc, sftp->channel->session, - sftp_unlink(sftp, filename, filename_len)); - return rc; -} - -/* - * sftp_rename - * - * Rename a file on the remote server - */ -static int sftp_rename(LIBSSH2_SFTP *sftp, const char *source_filename, - unsigned int source_filename_len, - const char *dest_filename, - unsigned int dest_filename_len, long flags) -{ - LIBSSH2_CHANNEL *channel = sftp->channel; - LIBSSH2_SESSION *session = channel->session; - size_t data_len; - int retcode; - uint32_t packet_len = - source_filename_len + dest_filename_len + 17 + (sftp->version >= - 5 ? 4 : 0); - /* packet_len(4) + packet_type(1) + request_id(4) + - source_filename_len(4) + dest_filename_len(4) + flags(4){SFTP5+) */ - unsigned char *data; - ssize_t rc; - - if(sftp->version < 2) { - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "Server does not support RENAME"); - } - - if(sftp->rename_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Renaming %s to %s", - source_filename, dest_filename); - sftp->rename_s = sftp->rename_packet = - LIBSSH2_ALLOC(session, packet_len); - if(!sftp->rename_packet) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for FXP_RENAME " - "packet"); - } - - _libssh2_store_u32(&sftp->rename_s, packet_len - 4); - *(sftp->rename_s++) = SSH_FXP_RENAME; - sftp->rename_request_id = sftp->request_id++; - _libssh2_store_u32(&sftp->rename_s, sftp->rename_request_id); - _libssh2_store_str(&sftp->rename_s, source_filename, - source_filename_len); - _libssh2_store_str(&sftp->rename_s, dest_filename, dest_filename_len); - - if(sftp->version >= 5) - _libssh2_store_u32(&sftp->rename_s, flags); - - sftp->rename_state = libssh2_NB_state_created; - } - - if(sftp->rename_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, sftp->rename_packet, - sftp->rename_s - sftp->rename_packet); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if((ssize_t)packet_len != rc) { - LIBSSH2_FREE(session, sftp->rename_packet); - sftp->rename_packet = NULL; - sftp->rename_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send FXP_RENAME command"); - } - LIBSSH2_FREE(session, sftp->rename_packet); - sftp->rename_packet = NULL; - - sftp->rename_state = libssh2_NB_state_sent; - } - - rc = sftp_packet_require(sftp, SSH_FXP_STATUS, - sftp->rename_request_id, &data, - &data_len, 9); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc == LIBSSH2_ERROR_BUFFER_TOO_SMALL) { - if(data_len > 0) { - LIBSSH2_FREE(session, data); - } - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP rename packet too short"); - } - else if(rc) { - sftp->rename_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, - "Error waiting for FXP STATUS"); - } - - sftp->rename_state = libssh2_NB_state_idle; - - retcode = _libssh2_ntohu32(data + 5); - LIBSSH2_FREE(session, data); - - sftp->last_errno = retcode; - - /* now convert the SFTP error code to libssh2 return code or error - message */ - switch(retcode) { - case LIBSSH2_FX_OK: - retcode = LIBSSH2_ERROR_NONE; - break; - - case LIBSSH2_FX_FILE_ALREADY_EXISTS: - retcode = _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "File already exists and " - "SSH_FXP_RENAME_OVERWRITE not specified"); - break; - - case LIBSSH2_FX_OP_UNSUPPORTED: - retcode = _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "Operation Not Supported"); - break; - - default: - retcode = _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP Protocol Error"); - break; - } - - return retcode; -} - -/* libssh2_sftp_rename_ex - * Rename a file on the remote server - */ -LIBSSH2_API int -libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp, const char *source_filename, - unsigned int source_filename_len, - const char *dest_filename, - unsigned int dest_filename_len, long flags) -{ - int rc; - if(!sftp) - return LIBSSH2_ERROR_BAD_USE; - BLOCK_ADJUST(rc, sftp->channel->session, - sftp_rename(sftp, source_filename, source_filename_len, - dest_filename, dest_filename_len, flags)); - return rc; -} - -/* - * sftp_fstatvfs - * - * Get file system statistics - */ -static int sftp_fstatvfs(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP_STATVFS *st) -{ - LIBSSH2_SFTP *sftp = handle->sftp; - LIBSSH2_CHANNEL *channel = sftp->channel; - LIBSSH2_SESSION *session = channel->session; - size_t data_len; - /* 17 = packet_len(4) + packet_type(1) + request_id(4) + ext_len(4) - + handle_len (4) */ - /* 20 = strlen ("fstatvfs@openssh.com") */ - uint32_t packet_len = handle->handle_len + 20 + 17; - unsigned char *packet, *s, *data; - ssize_t rc; - unsigned int flag; - static const unsigned char responses[2] = - { SSH_FXP_EXTENDED_REPLY, SSH_FXP_STATUS }; - - if(sftp->fstatvfs_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Getting file system statistics"); - s = packet = LIBSSH2_ALLOC(session, packet_len); - if(!packet) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for FXP_EXTENDED " - "packet"); - } - - _libssh2_store_u32(&s, packet_len - 4); - *(s++) = SSH_FXP_EXTENDED; - sftp->fstatvfs_request_id = sftp->request_id++; - _libssh2_store_u32(&s, sftp->fstatvfs_request_id); - _libssh2_store_str(&s, "fstatvfs@openssh.com", 20); - _libssh2_store_str(&s, handle->handle, handle->handle_len); - - sftp->fstatvfs_state = libssh2_NB_state_created; - } - else { - packet = sftp->fstatvfs_packet; - } - - if(sftp->fstatvfs_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, packet, packet_len); - if(rc == LIBSSH2_ERROR_EAGAIN || - (0 <= rc && rc < (ssize_t)packet_len)) { - sftp->fstatvfs_packet = packet; - return LIBSSH2_ERROR_EAGAIN; - } - - LIBSSH2_FREE(session, packet); - sftp->fstatvfs_packet = NULL; - - if(rc < 0) { - sftp->fstatvfs_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "_libssh2_channel_write() failed"); - } - sftp->fstatvfs_state = libssh2_NB_state_sent; - } - - rc = sftp_packet_requirev(sftp, 2, responses, sftp->fstatvfs_request_id, - &data, &data_len, 9); - - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc == LIBSSH2_ERROR_BUFFER_TOO_SMALL) { - if(data_len > 0) { - LIBSSH2_FREE(session, data); - } - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP rename packet too short"); - } - else if(rc) { - sftp->fstatvfs_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, - "Error waiting for FXP EXTENDED REPLY"); - } - - if(data[0] == SSH_FXP_STATUS) { - int retcode = _libssh2_ntohu32(data + 5); - sftp->fstatvfs_state = libssh2_NB_state_idle; - LIBSSH2_FREE(session, data); - sftp->last_errno = retcode; - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP Protocol Error"); - } - - if(data_len < 93) { - LIBSSH2_FREE(session, data); - sftp->fstatvfs_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP Protocol Error: short response"); - } - - sftp->fstatvfs_state = libssh2_NB_state_idle; - - st->f_bsize = _libssh2_ntohu64(data + 5); - st->f_frsize = _libssh2_ntohu64(data + 13); - st->f_blocks = _libssh2_ntohu64(data + 21); - st->f_bfree = _libssh2_ntohu64(data + 29); - st->f_bavail = _libssh2_ntohu64(data + 37); - st->f_files = _libssh2_ntohu64(data + 45); - st->f_ffree = _libssh2_ntohu64(data + 53); - st->f_favail = _libssh2_ntohu64(data + 61); - st->f_fsid = _libssh2_ntohu64(data + 69); - flag = (unsigned int)_libssh2_ntohu64(data + 77); - st->f_namemax = _libssh2_ntohu64(data + 85); - - st->f_flag = (flag & SSH_FXE_STATVFS_ST_RDONLY) - ? LIBSSH2_SFTP_ST_RDONLY : 0; - st->f_flag |= (flag & SSH_FXE_STATVFS_ST_NOSUID) - ? LIBSSH2_SFTP_ST_NOSUID : 0; - - LIBSSH2_FREE(session, data); - return 0; -} - -/* libssh2_sftp_fstatvfs - * Get filesystem space and inode utilization (requires fstatvfs@openssh.com - * support on the server) - */ -LIBSSH2_API int -libssh2_sftp_fstatvfs(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP_STATVFS *st) -{ - int rc; - if(!handle || !st) - return LIBSSH2_ERROR_BAD_USE; - BLOCK_ADJUST(rc, handle->sftp->channel->session, - sftp_fstatvfs(handle, st)); - return rc; -} - -/* - * sftp_statvfs - * - * Get file system statistics - */ -static int sftp_statvfs(LIBSSH2_SFTP *sftp, const char *path, - unsigned int path_len, LIBSSH2_SFTP_STATVFS *st) -{ - LIBSSH2_CHANNEL *channel = sftp->channel; - LIBSSH2_SESSION *session = channel->session; - size_t data_len; - /* 17 = packet_len(4) + packet_type(1) + request_id(4) + ext_len(4) - + path_len (4) */ - /* 19 = strlen ("statvfs@openssh.com") */ - uint32_t packet_len = path_len + 19 + 17; - unsigned char *packet, *s, *data; - ssize_t rc; - unsigned int flag; - static const unsigned char responses[2] = - { SSH_FXP_EXTENDED_REPLY, SSH_FXP_STATUS }; - - if(sftp->statvfs_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Getting file system statistics of %s", path); - s = packet = LIBSSH2_ALLOC(session, packet_len); - if(!packet) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for FXP_EXTENDED " - "packet"); - } - - _libssh2_store_u32(&s, packet_len - 4); - *(s++) = SSH_FXP_EXTENDED; - sftp->statvfs_request_id = sftp->request_id++; - _libssh2_store_u32(&s, sftp->statvfs_request_id); - _libssh2_store_str(&s, "statvfs@openssh.com", 19); - _libssh2_store_str(&s, path, path_len); - - sftp->statvfs_state = libssh2_NB_state_created; - } - else { - packet = sftp->statvfs_packet; - } - - if(sftp->statvfs_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, packet, packet_len); - if(rc == LIBSSH2_ERROR_EAGAIN || - (0 <= rc && rc < (ssize_t)packet_len)) { - sftp->statvfs_packet = packet; - return LIBSSH2_ERROR_EAGAIN; - } - - LIBSSH2_FREE(session, packet); - sftp->statvfs_packet = NULL; - - if(rc < 0) { - sftp->statvfs_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "_libssh2_channel_write() failed"); - } - sftp->statvfs_state = libssh2_NB_state_sent; - } - - rc = sftp_packet_requirev(sftp, 2, responses, sftp->statvfs_request_id, - &data, &data_len, 9); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc == LIBSSH2_ERROR_BUFFER_TOO_SMALL) { - if(data_len > 0) { - LIBSSH2_FREE(session, data); - } - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP fstat packet too short"); - } - else if(rc) { - sftp->statvfs_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, - "Error waiting for FXP EXTENDED REPLY"); - } - - if(data[0] == SSH_FXP_STATUS) { - int retcode = _libssh2_ntohu32(data + 5); - sftp->statvfs_state = libssh2_NB_state_idle; - LIBSSH2_FREE(session, data); - sftp->last_errno = retcode; - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP Protocol Error"); - } - - if(data_len < 93) { - LIBSSH2_FREE(session, data); - sftp->statvfs_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP Protocol Error: short response"); - } - - sftp->statvfs_state = libssh2_NB_state_idle; - - st->f_bsize = _libssh2_ntohu64(data + 5); - st->f_frsize = _libssh2_ntohu64(data + 13); - st->f_blocks = _libssh2_ntohu64(data + 21); - st->f_bfree = _libssh2_ntohu64(data + 29); - st->f_bavail = _libssh2_ntohu64(data + 37); - st->f_files = _libssh2_ntohu64(data + 45); - st->f_ffree = _libssh2_ntohu64(data + 53); - st->f_favail = _libssh2_ntohu64(data + 61); - st->f_fsid = _libssh2_ntohu64(data + 69); - flag = (unsigned int)_libssh2_ntohu64(data + 77); - st->f_namemax = _libssh2_ntohu64(data + 85); - - st->f_flag = (flag & SSH_FXE_STATVFS_ST_RDONLY) - ? LIBSSH2_SFTP_ST_RDONLY : 0; - st->f_flag |= (flag & SSH_FXE_STATVFS_ST_NOSUID) - ? LIBSSH2_SFTP_ST_NOSUID : 0; - - LIBSSH2_FREE(session, data); - return 0; -} - -/* libssh2_sftp_statvfs_ex - * Get filesystem space and inode utilization (requires statvfs@openssh.com - * support on the server) - */ -LIBSSH2_API int -libssh2_sftp_statvfs(LIBSSH2_SFTP *sftp, const char *path, - size_t path_len, LIBSSH2_SFTP_STATVFS *st) -{ - int rc; - if(!sftp || !st) - return LIBSSH2_ERROR_BAD_USE; - BLOCK_ADJUST(rc, sftp->channel->session, sftp_statvfs(sftp, path, path_len, - st)); - return rc; -} - - -/* - * sftp_mkdir - * - * Create an SFTP directory - */ -static int sftp_mkdir(LIBSSH2_SFTP *sftp, const char *path, - unsigned int path_len, long mode) -{ - LIBSSH2_CHANNEL *channel = sftp->channel; - LIBSSH2_SESSION *session = channel->session; - LIBSSH2_SFTP_ATTRIBUTES attrs = { - 0, 0, 0, 0, 0, 0, 0 - }; - size_t data_len; - int retcode; - ssize_t packet_len; - unsigned char *packet, *s, *data; - int rc; - - if(mode != LIBSSH2_SFTP_DEFAULT_MODE) { - /* Filetype in SFTP 3 and earlier */ - attrs.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS; - attrs.permissions = mode | LIBSSH2_SFTP_ATTR_PFILETYPE_DIR; - } - - /* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */ - packet_len = path_len + 13 + sftp_attrsize(attrs.flags); - - if(sftp->mkdir_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Creating directory %s with mode 0%lo", path, mode); - s = packet = LIBSSH2_ALLOC(session, packet_len); - if(!packet) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for FXP_MKDIR " - "packet"); - } - - _libssh2_store_u32(&s, packet_len - 4); - *(s++) = SSH_FXP_MKDIR; - sftp->mkdir_request_id = sftp->request_id++; - _libssh2_store_u32(&s, sftp->mkdir_request_id); - _libssh2_store_str(&s, path, path_len); - - s += sftp_attr2bin(s, &attrs); - - sftp->mkdir_state = libssh2_NB_state_created; - } - else { - packet = sftp->mkdir_packet; - } - - if(sftp->mkdir_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, packet, packet_len); - if(rc == LIBSSH2_ERROR_EAGAIN) { - sftp->mkdir_packet = packet; - return rc; - } - if(packet_len != rc) { - LIBSSH2_FREE(session, packet); - sftp->mkdir_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "_libssh2_channel_write() failed"); - } - LIBSSH2_FREE(session, packet); - sftp->mkdir_state = libssh2_NB_state_sent; - sftp->mkdir_packet = NULL; - } - - rc = sftp_packet_require(sftp, SSH_FXP_STATUS, sftp->mkdir_request_id, - &data, &data_len, 9); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc == LIBSSH2_ERROR_BUFFER_TOO_SMALL) { - if(data_len > 0) { - LIBSSH2_FREE(session, data); - } - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP mkdir packet too short"); - } - else if(rc) { - sftp->mkdir_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, - "Error waiting for FXP STATUS"); - } - - sftp->mkdir_state = libssh2_NB_state_idle; - - retcode = _libssh2_ntohu32(data + 5); - LIBSSH2_FREE(session, data); - - if(retcode == LIBSSH2_FX_OK) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "OK!"); - return 0; - } - else { - sftp->last_errno = retcode; - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP Protocol Error"); - } -} - -/* - * libssh2_sftp_mkdir_ex - * - * Create an SFTP directory - */ -LIBSSH2_API int -libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, const char *path, - unsigned int path_len, long mode) -{ - int rc; - if(!sftp) - return LIBSSH2_ERROR_BAD_USE; - BLOCK_ADJUST(rc, sftp->channel->session, - sftp_mkdir(sftp, path, path_len, mode)); - return rc; -} - -/* sftp_rmdir - * Remove a directory - */ -static int sftp_rmdir(LIBSSH2_SFTP *sftp, const char *path, - unsigned int path_len) -{ - LIBSSH2_CHANNEL *channel = sftp->channel; - LIBSSH2_SESSION *session = channel->session; - size_t data_len; - int retcode; - /* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */ - ssize_t packet_len = path_len + 13; - unsigned char *s, *data; - int rc; - - if(sftp->rmdir_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Removing directory: %s", - path); - s = sftp->rmdir_packet = LIBSSH2_ALLOC(session, packet_len); - if(!sftp->rmdir_packet) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for FXP_RMDIR " - "packet"); - } - - _libssh2_store_u32(&s, packet_len - 4); - *(s++) = SSH_FXP_RMDIR; - sftp->rmdir_request_id = sftp->request_id++; - _libssh2_store_u32(&s, sftp->rmdir_request_id); - _libssh2_store_str(&s, path, path_len); - - sftp->rmdir_state = libssh2_NB_state_created; - } - - if(sftp->rmdir_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, sftp->rmdir_packet, - packet_len); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(packet_len != rc) { - LIBSSH2_FREE(session, sftp->rmdir_packet); - sftp->rmdir_packet = NULL; - sftp->rmdir_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send FXP_RMDIR command"); - } - LIBSSH2_FREE(session, sftp->rmdir_packet); - sftp->rmdir_packet = NULL; - - sftp->rmdir_state = libssh2_NB_state_sent; - } - - rc = sftp_packet_require(sftp, SSH_FXP_STATUS, - sftp->rmdir_request_id, &data, &data_len, 9); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc == LIBSSH2_ERROR_BUFFER_TOO_SMALL) { - if(data_len > 0) { - LIBSSH2_FREE(session, data); - } - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP rmdir packet too short"); - } - else if(rc) { - sftp->rmdir_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, - "Error waiting for FXP STATUS"); - } - - sftp->rmdir_state = libssh2_NB_state_idle; - - retcode = _libssh2_ntohu32(data + 5); - LIBSSH2_FREE(session, data); - - if(retcode == LIBSSH2_FX_OK) { - return 0; - } - else { - sftp->last_errno = retcode; - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP Protocol Error"); - } -} - -/* libssh2_sftp_rmdir_ex - * Remove a directory - */ -LIBSSH2_API int -libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp, const char *path, - unsigned int path_len) -{ - int rc; - if(!sftp) - return LIBSSH2_ERROR_BAD_USE; - BLOCK_ADJUST(rc, sftp->channel->session, - sftp_rmdir(sftp, path, path_len)); - return rc; -} - -/* sftp_stat - * Stat a file or symbolic link - */ -static int sftp_stat(LIBSSH2_SFTP *sftp, const char *path, - unsigned int path_len, int stat_type, - LIBSSH2_SFTP_ATTRIBUTES * attrs) -{ - LIBSSH2_CHANNEL *channel = sftp->channel; - LIBSSH2_SESSION *session = channel->session; - size_t data_len; - /* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */ - ssize_t packet_len = - path_len + 13 + - ((stat_type == - LIBSSH2_SFTP_SETSTAT) ? sftp_attrsize(attrs->flags) : 0); - unsigned char *s, *data; - static const unsigned char stat_responses[2] = - { SSH_FXP_ATTRS, SSH_FXP_STATUS }; - int rc; - - if(sftp->stat_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "%s %s", - (stat_type == LIBSSH2_SFTP_SETSTAT) ? "Set-statting" : - (stat_type == - LIBSSH2_SFTP_LSTAT ? "LStatting" : "Statting"), path); - s = sftp->stat_packet = LIBSSH2_ALLOC(session, packet_len); - if(!sftp->stat_packet) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for FXP_*STAT " - "packet"); - } - - _libssh2_store_u32(&s, packet_len - 4); - - switch(stat_type) { - case LIBSSH2_SFTP_SETSTAT: - *(s++) = SSH_FXP_SETSTAT; - break; - - case LIBSSH2_SFTP_LSTAT: - *(s++) = SSH_FXP_LSTAT; - break; - - case LIBSSH2_SFTP_STAT: - default: - *(s++) = SSH_FXP_STAT; - } - sftp->stat_request_id = sftp->request_id++; - _libssh2_store_u32(&s, sftp->stat_request_id); - _libssh2_store_str(&s, path, path_len); - - if(stat_type == LIBSSH2_SFTP_SETSTAT) - s += sftp_attr2bin(s, attrs); - - sftp->stat_state = libssh2_NB_state_created; - } - - if(sftp->stat_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, sftp->stat_packet, packet_len); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(packet_len != rc) { - LIBSSH2_FREE(session, sftp->stat_packet); - sftp->stat_packet = NULL; - sftp->stat_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send STAT/LSTAT/SETSTAT command"); - } - LIBSSH2_FREE(session, sftp->stat_packet); - sftp->stat_packet = NULL; - - sftp->stat_state = libssh2_NB_state_sent; - } - - rc = sftp_packet_requirev(sftp, 2, stat_responses, - sftp->stat_request_id, &data, &data_len, 9); - if(rc == LIBSSH2_ERROR_EAGAIN) - return rc; - else if(rc == LIBSSH2_ERROR_BUFFER_TOO_SMALL) { - if(data_len > 0) { - LIBSSH2_FREE(session, data); - } - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP stat packet too short"); - } - else if(rc) { - sftp->stat_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, - "Timeout waiting for status message"); - } - - sftp->stat_state = libssh2_NB_state_idle; - - if(data[0] == SSH_FXP_STATUS) { - int retcode; - - retcode = _libssh2_ntohu32(data + 5); - LIBSSH2_FREE(session, data); - if(retcode == LIBSSH2_FX_OK) { - memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES)); - return 0; - } - else { - sftp->last_errno = retcode; - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP Protocol Error"); - } - } - - memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES)); - if(sftp_bin2attr(attrs, data + 5, data_len - 5) < 0) { - LIBSSH2_FREE(session, data); - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "Attributes too short in SFTP fstat"); - } - - LIBSSH2_FREE(session, data); - - return 0; -} - -/* libssh2_sftp_stat_ex - * Stat a file or symbolic link - */ -LIBSSH2_API int -libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp, const char *path, - unsigned int path_len, int stat_type, - LIBSSH2_SFTP_ATTRIBUTES *attrs) -{ - int rc; - if(!sftp) - return LIBSSH2_ERROR_BAD_USE; - BLOCK_ADJUST(rc, sftp->channel->session, - sftp_stat(sftp, path, path_len, stat_type, attrs)); - return rc; -} - -/* sftp_symlink - * Read or set a symlink - */ -static int sftp_symlink(LIBSSH2_SFTP *sftp, const char *path, - unsigned int path_len, char *target, - unsigned int target_len, int link_type) -{ - LIBSSH2_CHANNEL *channel = sftp->channel; - LIBSSH2_SESSION *session = channel->session; - size_t data_len, link_len; - /* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */ - ssize_t packet_len = - path_len + 13 + - ((link_type == LIBSSH2_SFTP_SYMLINK) ? (4 + target_len) : 0); - unsigned char *s, *data; - static const unsigned char link_responses[2] = - { SSH_FXP_NAME, SSH_FXP_STATUS }; - int retcode; - - if((sftp->version < 3) && (link_type != LIBSSH2_SFTP_REALPATH)) { - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "Server does not support SYMLINK or READLINK"); - } - - if(sftp->symlink_state == libssh2_NB_state_idle) { - s = sftp->symlink_packet = LIBSSH2_ALLOC(session, packet_len); - if(!sftp->symlink_packet) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "SYMLINK/READLINK/REALPATH packet"); - } - - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "%s %s on %s", - (link_type == - LIBSSH2_SFTP_SYMLINK) ? "Creating" : "Reading", - (link_type == - LIBSSH2_SFTP_REALPATH) ? "realpath" : "symlink", path); - - _libssh2_store_u32(&s, packet_len - 4); - - switch(link_type) { - case LIBSSH2_SFTP_REALPATH: - *(s++) = SSH_FXP_REALPATH; - break; - - case LIBSSH2_SFTP_SYMLINK: - *(s++) = SSH_FXP_SYMLINK; - break; - - case LIBSSH2_SFTP_READLINK: - default: - *(s++) = SSH_FXP_READLINK; - } - sftp->symlink_request_id = sftp->request_id++; - _libssh2_store_u32(&s, sftp->symlink_request_id); - _libssh2_store_str(&s, path, path_len); - - if(link_type == LIBSSH2_SFTP_SYMLINK) - _libssh2_store_str(&s, target, target_len); - - sftp->symlink_state = libssh2_NB_state_created; - } - - if(sftp->symlink_state == libssh2_NB_state_created) { - ssize_t rc = _libssh2_channel_write(channel, 0, sftp->symlink_packet, - packet_len); - if(rc == LIBSSH2_ERROR_EAGAIN) - return rc; - else if(packet_len != rc) { - LIBSSH2_FREE(session, sftp->symlink_packet); - sftp->symlink_packet = NULL; - sftp->symlink_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send SYMLINK/READLINK command"); - } - LIBSSH2_FREE(session, sftp->symlink_packet); - sftp->symlink_packet = NULL; - - sftp->symlink_state = libssh2_NB_state_sent; - } - - retcode = sftp_packet_requirev(sftp, 2, link_responses, - sftp->symlink_request_id, &data, - &data_len, 9); - if(retcode == LIBSSH2_ERROR_EAGAIN) - return retcode; - else if(retcode == LIBSSH2_ERROR_BUFFER_TOO_SMALL) { - if(data_len > 0) { - LIBSSH2_FREE(session, data); - } - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP symlink packet too short"); - } - else if(retcode) { - sftp->symlink_state = libssh2_NB_state_idle; - return _libssh2_error(session, retcode, - "Error waiting for status message"); - } - - sftp->symlink_state = libssh2_NB_state_idle; - - if(data[0] == SSH_FXP_STATUS) { - retcode = _libssh2_ntohu32(data + 5); - LIBSSH2_FREE(session, data); - if(retcode == LIBSSH2_FX_OK) - return LIBSSH2_ERROR_NONE; - else { - sftp->last_errno = retcode; - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP Protocol Error"); - } - } - - if(_libssh2_ntohu32(data + 5) < 1) { - LIBSSH2_FREE(session, data); - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "Invalid READLINK/REALPATH response, " - "no name entries"); - } - - if(data_len < 13) { - if(data_len > 0) { - LIBSSH2_FREE(session, data); - } - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP stat packet too short"); - } - - /* this reads a u32 and stores it into a signed 32bit value */ - link_len = _libssh2_ntohu32(data + 9); - if(link_len < target_len) { - memcpy(target, data + 13, link_len); - target[link_len] = 0; - retcode = (int)link_len; - } - else - retcode = LIBSSH2_ERROR_BUFFER_TOO_SMALL; - LIBSSH2_FREE(session, data); - - return retcode; -} - -/* libssh2_sftp_symlink_ex - * Read or set a symlink - */ -LIBSSH2_API int -libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, const char *path, - unsigned int path_len, char *target, - unsigned int target_len, int link_type) -{ - int rc; - if(!sftp) - return LIBSSH2_ERROR_BAD_USE; - BLOCK_ADJUST(rc, sftp->channel->session, - sftp_symlink(sftp, path, path_len, target, target_len, - link_type)); - return rc; -} - -/* libssh2_sftp_last_error - * Returns the last error code reported by SFTP - */ -LIBSSH2_API unsigned long -libssh2_sftp_last_error(LIBSSH2_SFTP *sftp) -{ - if(!sftp) - return 0; - - return sftp->last_errno; -} - -/* libssh2_sftp_get_channel - * Return the channel of sftp, then caller can control the channel's behavior. - */ -LIBSSH2_API LIBSSH2_CHANNEL * -libssh2_sftp_get_channel(LIBSSH2_SFTP *sftp) -{ - if(!sftp) - return NULL; - - return sftp->channel; -} diff --git a/libssh2/transport.c b/libssh2/transport.c deleted file mode 100644 index 11e5614..0000000 --- a/libssh2/transport.c +++ /dev/null @@ -1,917 +0,0 @@ -/* Copyright (C) 2007 The Written Word, Inc. All rights reserved. - * Copyright (C) 2009-2010 by Daniel Stenberg - * Author: Daniel Stenberg - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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. - * - * This file handles reading and writing to the SECSH transport layer. RFC4253. - */ - -#include "libssh2_priv.h" -#include -#include -#include -#ifdef LIBSSH2DEBUG -#include -#endif - -#include - -#include "transport.h" -#include "mac.h" - -#define MAX_BLOCKSIZE 32 /* MUST fit biggest crypto block size we use/get */ -#define MAX_MACSIZE 64 /* MUST fit biggest MAC length we support */ - -#ifdef LIBSSH2DEBUG -#define UNPRINTABLE_CHAR '.' -static void -debugdump(LIBSSH2_SESSION * session, - const char *desc, const unsigned char *ptr, size_t size) -{ - size_t i; - size_t c; - unsigned int width = 0x10; - char buffer[256]; /* Must be enough for width*4 + about 30 or so */ - size_t used; - static const char *hex_chars = "0123456789ABCDEF"; - - if(!(session->showmask & LIBSSH2_TRACE_TRANS)) { - /* not asked for, bail out */ - return; - } - - used = snprintf(buffer, sizeof(buffer), "=> %s (%d bytes)\n", - desc, (int) size); - if(session->tracehandler) - (session->tracehandler)(session, session->tracehandler_context, - buffer, used); - else - fprintf(stderr, "%s", buffer); - - for(i = 0; i < size; i += width) { - - used = snprintf(buffer, sizeof(buffer), "%04lx: ", (long)i); - - /* hex not disabled, show it */ - for(c = 0; c < width; c++) { - if(i + c < size) { - buffer[used++] = hex_chars[(ptr[i + c] >> 4) & 0xF]; - buffer[used++] = hex_chars[ptr[i + c] & 0xF]; - } - else { - buffer[used++] = ' '; - buffer[used++] = ' '; - } - - buffer[used++] = ' '; - if((width/2) - 1 == c) - buffer[used++] = ' '; - } - - buffer[used++] = ':'; - buffer[used++] = ' '; - - for(c = 0; (c < width) && (i + c < size); c++) { - buffer[used++] = isprint(ptr[i + c]) ? - ptr[i + c] : UNPRINTABLE_CHAR; - } - buffer[used++] = '\n'; - buffer[used] = 0; - - if(session->tracehandler) - (session->tracehandler)(session, session->tracehandler_context, - buffer, used); - else - fprintf(stderr, "%s", buffer); - } -} -#else -#define debugdump(a,x,y,z) -#endif - - -/* decrypt() decrypts 'len' bytes from 'source' to 'dest'. - * - * returns 0 on success and negative on failure - */ - -static int -decrypt(LIBSSH2_SESSION * session, unsigned char *source, - unsigned char *dest, int len) -{ - struct transportpacket *p = &session->packet; - int blocksize = session->remote.crypt->blocksize; - - /* if we get called with a len that isn't an even number of blocksizes - we risk losing those extra bytes */ - assert((len % blocksize) == 0); - - while(len >= blocksize) { - if(session->remote.crypt->crypt(session, source, blocksize, - &session->remote.crypt_abstract)) { - LIBSSH2_FREE(session, p->payload); - return LIBSSH2_ERROR_DECRYPT; - } - - /* if the crypt() function would write to a given address it - wouldn't have to memcpy() and we could avoid this memcpy() - too */ - memcpy(dest, source, blocksize); - - len -= blocksize; /* less bytes left */ - dest += blocksize; /* advance write pointer */ - source += blocksize; /* advance read pointer */ - } - return LIBSSH2_ERROR_NONE; /* all is fine */ -} - -/* - * fullpacket() gets called when a full packet has been received and properly - * collected. - */ -static int -fullpacket(LIBSSH2_SESSION * session, int encrypted /* 1 or 0 */ ) -{ - unsigned char macbuf[MAX_MACSIZE]; - struct transportpacket *p = &session->packet; - int rc; - int compressed; - - if(session->fullpacket_state == libssh2_NB_state_idle) { - session->fullpacket_macstate = LIBSSH2_MAC_CONFIRMED; - session->fullpacket_payload_len = p->packet_length - 1; - - if(encrypted) { - - /* Calculate MAC hash */ - session->remote.mac->hash(session, macbuf, /* store hash here */ - session->remote.seqno, - p->init, 5, - p->payload, - session->fullpacket_payload_len, - &session->remote.mac_abstract); - - /* Compare the calculated hash with the MAC we just read from - * the network. The read one is at the very end of the payload - * buffer. Note that 'payload_len' here is the packet_length - * field which includes the padding but not the MAC. - */ - if(memcmp(macbuf, p->payload + session->fullpacket_payload_len, - session->remote.mac->mac_len)) { - session->fullpacket_macstate = LIBSSH2_MAC_INVALID; - } - } - - session->remote.seqno++; - - /* ignore the padding */ - session->fullpacket_payload_len -= p->padding_length; - - /* Check for and deal with decompression */ - compressed = - session->local.comp != NULL && - session->local.comp->compress && - ((session->state & LIBSSH2_STATE_AUTHENTICATED) || - session->local.comp->use_in_auth); - - if(compressed && session->remote.comp_abstract) { - /* - * The buffer for the decompression (remote.comp_abstract) is - * initialised in time when it is needed so as long it is NULL we - * cannot decompress. - */ - - unsigned char *data; - size_t data_len; - rc = session->remote.comp->decomp(session, - &data, &data_len, - LIBSSH2_PACKET_MAXDECOMP, - p->payload, - session->fullpacket_payload_len, - &session->remote.comp_abstract); - LIBSSH2_FREE(session, p->payload); - if(rc) - return rc; - - p->payload = data; - session->fullpacket_payload_len = data_len; - } - - session->fullpacket_packet_type = p->payload[0]; - - debugdump(session, "libssh2_transport_read() plain", - p->payload, session->fullpacket_payload_len); - - session->fullpacket_state = libssh2_NB_state_created; - } - - if(session->fullpacket_state == libssh2_NB_state_created) { - rc = _libssh2_packet_add(session, p->payload, - session->fullpacket_payload_len, - session->fullpacket_macstate); - if(rc == LIBSSH2_ERROR_EAGAIN) - return rc; - if(rc) { - session->fullpacket_state = libssh2_NB_state_idle; - return rc; - } - } - - session->fullpacket_state = libssh2_NB_state_idle; - - return session->fullpacket_packet_type; -} - - -/* - * _libssh2_transport_read - * - * Collect a packet into the input queue. - * - * Returns packet type added to input queue (0 if nothing added), or a - * negative error number. - */ - -/* - * This function reads the binary stream as specified in chapter 6 of RFC4253 - * "The Secure Shell (SSH) Transport Layer Protocol" - * - * DOES NOT call _libssh2_error() for ANY error case. - */ -int _libssh2_transport_read(LIBSSH2_SESSION * session) -{ - int rc; - struct transportpacket *p = &session->packet; - int remainbuf; - int remainpack; - int numbytes; - int numdecrypt; - unsigned char block[MAX_BLOCKSIZE]; - int blocksize; - int encrypted = 1; - - /* default clear the bit */ - session->socket_block_directions &= ~LIBSSH2_SESSION_BLOCK_INBOUND; - - /* - * All channels, systems, subsystems, etc eventually make it down here - * when looking for more incoming data. If a key exchange is going on - * (LIBSSH2_STATE_EXCHANGING_KEYS bit is set) then the remote end will - * ONLY send key exchange related traffic. In non-blocking mode, there is - * a chance to break out of the kex_exchange function with an EAGAIN - * status, and never come back to it. If LIBSSH2_STATE_EXCHANGING_KEYS is - * active, then we must redirect to the key exchange. However, if - * kex_exchange is active (as in it is the one that calls this execution - * of packet_read, then don't redirect, as that would be an infinite loop! - */ - - if(session->state & LIBSSH2_STATE_EXCHANGING_KEYS && - !(session->state & LIBSSH2_STATE_KEX_ACTIVE)) { - - /* Whoever wants a packet won't get anything until the key re-exchange - * is done! - */ - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Redirecting into the" - " key re-exchange from _libssh2_transport_read"); - rc = _libssh2_kex_exchange(session, 1, &session->startup_key_state); - if(rc) - return rc; - } - - /* - * =============================== NOTE =============================== - * I know this is very ugly and not a really good use of "goto", but - * this case statement would be even uglier to do it any other way - */ - if(session->readPack_state == libssh2_NB_state_jump1) { - session->readPack_state = libssh2_NB_state_idle; - encrypted = session->readPack_encrypted; - goto libssh2_transport_read_point1; - } - - do { - if(session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) { - return LIBSSH2_ERROR_NONE; - } - - if(session->state & LIBSSH2_STATE_NEWKEYS) { - blocksize = session->remote.crypt->blocksize; - } - else { - encrypted = 0; /* not encrypted */ - blocksize = 5; /* not strictly true, but we can use 5 here to - make the checks below work fine still */ - } - - /* read/use a whole big chunk into a temporary area stored in - the LIBSSH2_SESSION struct. We will decrypt data from that - buffer into the packet buffer so this temp one doesn't have - to be able to keep a whole SSH packet, just be large enough - so that we can read big chunks from the network layer. */ - - /* how much data there is remaining in the buffer to deal with - before we should read more from the network */ - remainbuf = p->writeidx - p->readidx; - - /* if remainbuf turns negative we have a bad internal error */ - assert(remainbuf >= 0); - - if(remainbuf < blocksize) { - /* If we have less than a blocksize left, it is too - little data to deal with, read more */ - ssize_t nread; - - /* move any remainder to the start of the buffer so - that we can do a full refill */ - if(remainbuf) { - memmove(p->buf, &p->buf[p->readidx], remainbuf); - p->readidx = 0; - p->writeidx = remainbuf; - } - else { - /* nothing to move, just zero the indexes */ - p->readidx = p->writeidx = 0; - } - - /* now read a big chunk from the network into the temp buffer */ - nread = - LIBSSH2_RECV(session, &p->buf[remainbuf], - PACKETBUFSIZE - remainbuf, - LIBSSH2_SOCKET_RECV_FLAGS(session)); - if(nread <= 0) { - /* check if this is due to EAGAIN and return the special - return code if so, error out normally otherwise */ - if((nread < 0) && (nread == -EAGAIN)) { - session->socket_block_directions |= - LIBSSH2_SESSION_BLOCK_INBOUND; - return LIBSSH2_ERROR_EAGAIN; - } - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, - "Error recving %d bytes (got %d)", - PACKETBUFSIZE - remainbuf, -nread); - return LIBSSH2_ERROR_SOCKET_RECV; - } - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, - "Recved %d/%d bytes to %p+%d", nread, - PACKETBUFSIZE - remainbuf, p->buf, remainbuf); - - debugdump(session, "libssh2_transport_read() raw", - &p->buf[remainbuf], nread); - /* advance write pointer */ - p->writeidx += nread; - - /* update remainbuf counter */ - remainbuf = p->writeidx - p->readidx; - } - - /* how much data to deal with from the buffer */ - numbytes = remainbuf; - - if(!p->total_num) { - size_t total_num; - - /* No payload package area allocated yet. To know the - size of this payload, we need to decrypt the first - blocksize data. */ - - if(numbytes < blocksize) { - /* we can't act on anything less than blocksize, but this - check is only done for the initial block since once we have - got the start of a block we can in fact deal with fractions - */ - session->socket_block_directions |= - LIBSSH2_SESSION_BLOCK_INBOUND; - return LIBSSH2_ERROR_EAGAIN; - } - - if(encrypted) { - rc = decrypt(session, &p->buf[p->readidx], block, blocksize); - if(rc != LIBSSH2_ERROR_NONE) { - return rc; - } - /* save the first 5 bytes of the decrypted package, to be - used in the hash calculation later down. */ - memcpy(p->init, block, 5); - } - else { - /* the data is plain, just copy it verbatim to - the working block buffer */ - memcpy(block, &p->buf[p->readidx], blocksize); - } - - /* advance the read pointer */ - p->readidx += blocksize; - - /* we now have the initial blocksize bytes decrypted, - * and we can extract packet and padding length from it - */ - p->packet_length = _libssh2_ntohu32(block); - if(p->packet_length < 1) { - return LIBSSH2_ERROR_DECRYPT; - } - else if(p->packet_length > LIBSSH2_PACKET_MAXPAYLOAD) { - return LIBSSH2_ERROR_OUT_OF_BOUNDARY; - } - - p->padding_length = block[4]; - if(p->padding_length > p->packet_length - 1) { - return LIBSSH2_ERROR_DECRYPT; - } - - - /* total_num is the number of bytes following the initial - (5 bytes) packet length and padding length fields */ - total_num = - p->packet_length - 1 + - (encrypted ? session->remote.mac->mac_len : 0); - - /* RFC4253 section 6.1 Maximum Packet Length says: - * - * "All implementations MUST be able to process - * packets with uncompressed payload length of 32768 - * bytes or less and total packet size of 35000 bytes - * or less (including length, padding length, payload, - * padding, and MAC.)." - */ - if(total_num > LIBSSH2_PACKET_MAXPAYLOAD || total_num == 0) { - return LIBSSH2_ERROR_OUT_OF_BOUNDARY; - } - - /* Get a packet handle put data into. We get one to - hold all data, including padding and MAC. */ - p->payload = LIBSSH2_ALLOC(session, total_num); - if(!p->payload) { - return LIBSSH2_ERROR_ALLOC; - } - p->total_num = total_num; - /* init write pointer to start of payload buffer */ - p->wptr = p->payload; - - if(blocksize > 5) { - /* copy the data from index 5 to the end of - the blocksize from the temporary buffer to - the start of the decrypted buffer */ - if(blocksize - 5 <= (int) total_num) { - memcpy(p->wptr, &block[5], blocksize - 5); - p->wptr += blocksize - 5; /* advance write pointer */ - } - else { - return LIBSSH2_ERROR_OUT_OF_BOUNDARY; - } - } - - /* init the data_num field to the number of bytes of - the package read so far */ - p->data_num = p->wptr - p->payload; - - /* we already dealt with a blocksize worth of data */ - numbytes -= blocksize; - } - - /* how much there is left to add to the current payload - package */ - remainpack = p->total_num - p->data_num; - - if(numbytes > remainpack) { - /* if we have more data in the buffer than what is going into this - particular packet, we limit this round to this packet only */ - numbytes = remainpack; - } - - if(encrypted) { - /* At the end of the incoming stream, there is a MAC, - and we don't want to decrypt that since we need it - "raw". We MUST however decrypt the padding data - since it is used for the hash later on. */ - int skip = session->remote.mac->mac_len; - - /* if what we have plus numbytes is bigger than the - total minus the skip margin, we should lower the - amount to decrypt even more */ - if((p->data_num + numbytes) > (p->total_num - skip)) { - numdecrypt = (p->total_num - skip) - p->data_num; - } - else { - int frac; - numdecrypt = numbytes; - frac = numdecrypt % blocksize; - if(frac) { - /* not an aligned amount of blocks, - align it */ - numdecrypt -= frac; - /* and make it no unencrypted data - after it */ - numbytes = 0; - } - } - } - else { - /* unencrypted data should not be decrypted at all */ - numdecrypt = 0; - } - - /* if there are bytes to decrypt, do that */ - if(numdecrypt > 0) { - /* now decrypt the lot */ - rc = decrypt(session, &p->buf[p->readidx], p->wptr, numdecrypt); - if(rc != LIBSSH2_ERROR_NONE) { - p->total_num = 0; /* no packet buffer available */ - return rc; - } - - /* advance the read pointer */ - p->readidx += numdecrypt; - /* advance write pointer */ - p->wptr += numdecrypt; - /* increase data_num */ - p->data_num += numdecrypt; - - /* bytes left to take care of without decryption */ - numbytes -= numdecrypt; - } - - /* if there are bytes to copy that aren't decrypted, simply - copy them as-is to the target buffer */ - if(numbytes > 0) { - - if(numbytes <= (int)(p->total_num - (p->wptr - p->payload))) { - memcpy(p->wptr, &p->buf[p->readidx], numbytes); - } - else { - return LIBSSH2_ERROR_OUT_OF_BOUNDARY; - } - - /* advance the read pointer */ - p->readidx += numbytes; - /* advance write pointer */ - p->wptr += numbytes; - /* increase data_num */ - p->data_num += numbytes; - } - - /* now check how much data there's left to read to finish the - current packet */ - remainpack = p->total_num - p->data_num; - - if(!remainpack) { - /* we have a full packet */ - libssh2_transport_read_point1: - rc = fullpacket(session, encrypted); - if(rc == LIBSSH2_ERROR_EAGAIN) { - - if(session->packAdd_state != libssh2_NB_state_idle) { - /* fullpacket only returns LIBSSH2_ERROR_EAGAIN if - * libssh2_packet_add returns LIBSSH2_ERROR_EAGAIN. If - * that returns LIBSSH2_ERROR_EAGAIN but the packAdd_state - * is idle, then the packet has been added to the brigade, - * but some immediate action that was taken based on the - * packet type (such as key re-exchange) is not yet - * complete. Clear the way for a new packet to be read - * in. - */ - session->readPack_encrypted = encrypted; - session->readPack_state = libssh2_NB_state_jump1; - } - - return rc; - } - - p->total_num = 0; /* no packet buffer available */ - - return rc; - } - } while(1); /* loop */ - - return LIBSSH2_ERROR_SOCKET_RECV; /* we never reach this point */ -} - -static int -send_existing(LIBSSH2_SESSION *session, const unsigned char *data, - size_t data_len, ssize_t *ret) -{ - ssize_t rc; - ssize_t length; - struct transportpacket *p = &session->packet; - - if(!p->olen) { - *ret = 0; - return LIBSSH2_ERROR_NONE; - } - - /* send as much as possible of the existing packet */ - if((data != p->odata) || (data_len != p->olen)) { - /* When we are about to complete the sending of a packet, it is vital - that the caller doesn't try to send a new/different packet since - we don't add this one up until the previous one has been sent. To - make the caller really notice his/hers flaw, we return error for - this case */ - return LIBSSH2_ERROR_BAD_USE; - } - - *ret = 1; /* set to make our parent return */ - - /* number of bytes left to send */ - length = p->ototal_num - p->osent; - - rc = LIBSSH2_SEND(session, &p->outbuf[p->osent], length, - LIBSSH2_SOCKET_SEND_FLAGS(session)); - if(rc < 0) - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, - "Error sending %d bytes: %d", length, -rc); - else { - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, - "Sent %d/%d bytes at %p+%d", rc, length, p->outbuf, - p->osent); - debugdump(session, "libssh2_transport_write send()", - &p->outbuf[p->osent], rc); - } - - if(rc == length) { - /* the remainder of the package was sent */ - p->ototal_num = 0; - p->olen = 0; - /* we leave *ret set so that the parent returns as we MUST return back - a send success now, so that we don't risk sending EAGAIN later - which then would confuse the parent function */ - return LIBSSH2_ERROR_NONE; - - } - else if(rc < 0) { - /* nothing was sent */ - if(rc != -EAGAIN) - /* send failure! */ - return LIBSSH2_ERROR_SOCKET_SEND; - - session->socket_block_directions |= LIBSSH2_SESSION_BLOCK_OUTBOUND; - return LIBSSH2_ERROR_EAGAIN; - } - - p->osent += rc; /* we sent away this much data */ - - return rc < length ? LIBSSH2_ERROR_EAGAIN : LIBSSH2_ERROR_NONE; -} - -/* - * libssh2_transport_send - * - * Send a packet, encrypting it and adding a MAC code if necessary - * Returns 0 on success, non-zero on failure. - * - * The data is provided as _two_ data areas that are combined by this - * function. The 'data' part is sent immediately before 'data2'. 'data2' may - * be set to NULL to only use a single part. - * - * Returns LIBSSH2_ERROR_EAGAIN if it would block or if the whole packet was - * not sent yet. If it does so, the caller should call this function again as - * soon as it is likely that more data can be sent, and this function MUST - * then be called with the same argument set (same data pointer and same - * data_len) until ERROR_NONE or failure is returned. - * - * This function DOES NOT call _libssh2_error() on any errors. - */ -int _libssh2_transport_send(LIBSSH2_SESSION *session, - const unsigned char *data, size_t data_len, - const unsigned char *data2, size_t data2_len) -{ - int blocksize = - (session->state & LIBSSH2_STATE_NEWKEYS) ? - session->local.crypt->blocksize : 8; - int padding_length; - size_t packet_length; - int total_length; -#ifdef RANDOM_PADDING - int rand_max; - int seed = data[0]; /* FIXME: make this random */ -#endif - struct transportpacket *p = &session->packet; - int encrypted; - int compressed; - ssize_t ret; - int rc; - const unsigned char *orgdata = data; - size_t orgdata_len = data_len; - - /* - * If the last read operation was interrupted in the middle of a key - * exchange, we must complete that key exchange before continuing to write - * further data. - * - * See the similar block in _libssh2_transport_read for more details. - */ - if(session->state & LIBSSH2_STATE_EXCHANGING_KEYS && - !(session->state & LIBSSH2_STATE_KEX_ACTIVE)) { - /* Don't write any new packets if we're still in the middle of a key - * exchange. */ - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Redirecting into the" - " key re-exchange from _libssh2_transport_send"); - rc = _libssh2_kex_exchange(session, 1, &session->startup_key_state); - if(rc) - return rc; - } - - debugdump(session, "libssh2_transport_write plain", data, data_len); - if(data2) - debugdump(session, "libssh2_transport_write plain2", data2, data2_len); - - /* FIRST, check if we have a pending write to complete. send_existing - only sanity-check data and data_len and not data2 and data2_len!! */ - rc = send_existing(session, data, data_len, &ret); - if(rc) - return rc; - - session->socket_block_directions &= ~LIBSSH2_SESSION_BLOCK_OUTBOUND; - - if(ret) - /* set by send_existing if data was sent */ - return rc; - - encrypted = (session->state & LIBSSH2_STATE_NEWKEYS) ? 1 : 0; - - compressed = - session->local.comp != NULL && - session->local.comp->compress && - ((session->state & LIBSSH2_STATE_AUTHENTICATED) || - session->local.comp->use_in_auth); - - if(encrypted && compressed && session->local.comp_abstract) { - /* the idea here is that these function must fail if the output gets - larger than what fits in the assigned buffer so thus they don't - check the input size as we don't know how much it compresses */ - size_t dest_len = MAX_SSH_PACKET_LEN-5-256; - size_t dest2_len = dest_len; - - /* compress directly to the target buffer */ - rc = session->local.comp->comp(session, - &p->outbuf[5], &dest_len, - data, data_len, - &session->local.comp_abstract); - if(rc) - return rc; /* compression failure */ - - if(data2 && data2_len) { - /* compress directly to the target buffer right after where the - previous call put data */ - dest2_len -= dest_len; - - rc = session->local.comp->comp(session, - &p->outbuf[5 + dest_len], - &dest2_len, - data2, data2_len, - &session->local.comp_abstract); - } - else - dest2_len = 0; - if(rc) - return rc; /* compression failure */ - - data_len = dest_len + dest2_len; /* use the combined length */ - } - else { - if((data_len + data2_len) >= (MAX_SSH_PACKET_LEN-0x100)) - /* too large packet, return error for this until we make this - function split it up and send multiple SSH packets */ - return LIBSSH2_ERROR_INVAL; - - /* copy the payload data */ - memcpy(&p->outbuf[5], data, data_len); - if(data2 && data2_len) - memcpy(&p->outbuf[5 + data_len], data2, data2_len); - data_len += data2_len; /* use the combined length */ - } - - - /* RFC4253 says: Note that the length of the concatenation of - 'packet_length', 'padding_length', 'payload', and 'random padding' - MUST be a multiple of the cipher block size or 8, whichever is - larger. */ - - /* Plain math: (4 + 1 + packet_length + padding_length) % blocksize == 0 */ - - packet_length = data_len + 1 + 4; /* 1 is for padding_length field - 4 for the packet_length field */ - - /* at this point we have it all except the padding */ - - /* first figure out our minimum padding amount to make it an even - block size */ - padding_length = blocksize - (packet_length % blocksize); - - /* if the padding becomes too small we add another blocksize worth - of it (taken from the original libssh2 where it didn't have any - real explanation) */ - if(padding_length < 4) { - padding_length += blocksize; - } -#ifdef RANDOM_PADDING - /* FIXME: we can add padding here, but that also makes the packets - bigger etc */ - - /* now we can add 'blocksize' to the padding_length N number of times - (to "help thwart traffic analysis") but it must be less than 255 in - total */ - rand_max = (255 - padding_length) / blocksize + 1; - padding_length += blocksize * (seed % rand_max); -#endif - - packet_length += padding_length; - - /* append the MAC length to the total_length size */ - total_length = - packet_length + (encrypted ? session->local.mac->mac_len : 0); - - /* store packet_length, which is the size of the whole packet except - the MAC and the packet_length field itself */ - _libssh2_htonu32(p->outbuf, packet_length - 4); - /* store padding_length */ - p->outbuf[4] = (unsigned char)padding_length; - - /* fill the padding area with random junk */ - _libssh2_random(p->outbuf + 5 + data_len, padding_length); - - if(encrypted) { - size_t i; - - /* Calculate MAC hash. Put the output at index packet_length, - since that size includes the whole packet. The MAC is - calculated on the entire unencrypted packet, including all - fields except the MAC field itself. */ - session->local.mac->hash(session, p->outbuf + packet_length, - session->local.seqno, p->outbuf, - packet_length, NULL, 0, - &session->local.mac_abstract); - - /* Encrypt the whole packet data, one block size at a time. - The MAC field is not encrypted. */ - for(i = 0; i < packet_length; i += session->local.crypt->blocksize) { - unsigned char *ptr = &p->outbuf[i]; - if(session->local.crypt->crypt(session, ptr, - session->local.crypt->blocksize, - &session->local.crypt_abstract)) - return LIBSSH2_ERROR_ENCRYPT; /* encryption failure */ - } - } - - session->local.seqno++; - - ret = LIBSSH2_SEND(session, p->outbuf, total_length, - LIBSSH2_SOCKET_SEND_FLAGS(session)); - if(ret < 0) - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, - "Error sending %d bytes: %d", total_length, -ret); - else { - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, "Sent %d/%d bytes at %p", - ret, total_length, p->outbuf); - debugdump(session, "libssh2_transport_write send()", p->outbuf, ret); - } - - if(ret != total_length) { - if(ret >= 0 || ret == -EAGAIN) { - /* the whole packet could not be sent, save the rest */ - session->socket_block_directions |= LIBSSH2_SESSION_BLOCK_OUTBOUND; - p->odata = orgdata; - p->olen = orgdata_len; - p->osent = ret <= 0 ? 0 : ret; - p->ototal_num = total_length; - return LIBSSH2_ERROR_EAGAIN; - } - return LIBSSH2_ERROR_SOCKET_SEND; - } - - /* the whole thing got sent away */ - p->odata = NULL; - p->olen = 0; - - return LIBSSH2_ERROR_NONE; /* all is good */ -} diff --git a/libssh2/userauth.c b/libssh2/userauth.c deleted file mode 100644 index d5dbaa4..0000000 --- a/libssh2/userauth.c +++ /dev/null @@ -1,2110 +0,0 @@ -/* Copyright (c) 2004-2007, Sara Golemon - * Copyright (c) 2005 Mikhail Gusarov - * Copyright (c) 2009-2014 by Daniel Stenberg - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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 "libssh2_priv.h" - -#include -#include - -#include - -/* Needed for struct iovec on some platforms */ -#ifdef HAVE_SYS_UIO_H -#include -#endif - -#include "transport.h" -#include "session.h" -#include "userauth.h" - -/* libssh2_userauth_list - * - * List authentication methods - * Will yield successful login if "none" happens to be allowable for this user - * Not a common configuration for any SSH server though - * username should be NULL, or a null terminated string - */ -static char *userauth_list(LIBSSH2_SESSION *session, const char *username, - unsigned int username_len) -{ - static const unsigned char reply_codes[3] = - { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 }; - /* packet_type(1) + username_len(4) + service_len(4) + - service(14)"ssh-connection" + method_len(4) = 27 */ - unsigned long methods_len; - unsigned char *s; - int rc; - - if(session->userauth_list_state == libssh2_NB_state_idle) { - /* Zero the whole thing out */ - memset(&session->userauth_list_packet_requirev_state, 0, - sizeof(session->userauth_list_packet_requirev_state)); - - session->userauth_list_data_len = username_len + 27; - - s = session->userauth_list_data = - LIBSSH2_ALLOC(session, session->userauth_list_data_len); - if(!session->userauth_list_data) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for userauth_list"); - return NULL; - } - - *(s++) = SSH_MSG_USERAUTH_REQUEST; - _libssh2_store_str(&s, username, username_len); - _libssh2_store_str(&s, "ssh-connection", 14); - _libssh2_store_u32(&s, 4); /* send "none" separately */ - - session->userauth_list_state = libssh2_NB_state_created; - } - - if(session->userauth_list_state == libssh2_NB_state_created) { - rc = _libssh2_transport_send(session, session->userauth_list_data, - session->userauth_list_data_len, - (unsigned char *)"none", 4); - if(rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block requesting userauth list"); - return NULL; - } - /* now free the packet that was sent */ - LIBSSH2_FREE(session, session->userauth_list_data); - session->userauth_list_data = NULL; - - if(rc) { - _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send userauth-none request"); - session->userauth_list_state = libssh2_NB_state_idle; - return NULL; - } - - session->userauth_list_state = libssh2_NB_state_sent; - } - - if(session->userauth_list_state == libssh2_NB_state_sent) { - rc = _libssh2_packet_requirev(session, reply_codes, - &session->userauth_list_data, - &session->userauth_list_data_len, 0, - NULL, 0, - &session->userauth_list_packet_requirev_state); - if(rc == LIBSSH2_ERROR_EAGAIN) { - _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block requesting userauth list"); - return NULL; - } - else if(rc || (session->userauth_list_data_len < 1)) { - _libssh2_error(session, rc, "Failed getting response"); - session->userauth_list_state = libssh2_NB_state_idle; - return NULL; - } - - if(session->userauth_list_data[0] == SSH_MSG_USERAUTH_SUCCESS) { - /* Wow, who'dve thought... */ - _libssh2_error(session, LIBSSH2_ERROR_NONE, "No error"); - LIBSSH2_FREE(session, session->userauth_list_data); - session->userauth_list_data = NULL; - session->state |= LIBSSH2_STATE_AUTHENTICATED; - session->userauth_list_state = libssh2_NB_state_idle; - return NULL; - } - - if(session->userauth_list_data_len < 5) { - LIBSSH2_FREE(session, session->userauth_list_data); - session->userauth_list_data = NULL; - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unexpected packet size"); - return NULL; - } - - methods_len = _libssh2_ntohu32(session->userauth_list_data + 1); - if(methods_len >= session->userauth_list_data_len - 5) { - _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, - "Unexpected userauth list size"); - return NULL; - } - - /* Do note that the memory areas overlap! */ - memmove(session->userauth_list_data, session->userauth_list_data + 5, - methods_len); - session->userauth_list_data[methods_len] = '\0'; - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Permitted auth methods: %s", - session->userauth_list_data); - } - - session->userauth_list_state = libssh2_NB_state_idle; - return (char *) session->userauth_list_data; -} - -/* libssh2_userauth_list - * - * List authentication methods - * Will yield successful login if "none" happens to be allowable for this user - * Not a common configuration for any SSH server though - * username should be NULL, or a null terminated string - */ -LIBSSH2_API char * -libssh2_userauth_list(LIBSSH2_SESSION * session, const char *user, - unsigned int user_len) -{ - char *ptr; - BLOCK_ADJUST_ERRNO(ptr, session, - userauth_list(session, user, user_len)); - return ptr; -} - -/* - * libssh2_userauth_authenticated - * - * Returns: 0 if not yet authenticated - * 1 if already authenticated - */ -LIBSSH2_API int -libssh2_userauth_authenticated(LIBSSH2_SESSION * session) -{ - return (session->state & LIBSSH2_STATE_AUTHENTICATED)?1:0; -} - - - -/* userauth_password - * Plain ol' login - */ -static int -userauth_password(LIBSSH2_SESSION *session, - const char *username, unsigned int username_len, - const unsigned char *password, unsigned int password_len, - LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb))) -{ - unsigned char *s; - static const unsigned char reply_codes[4] = - { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, - SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, 0 - }; - int rc; - - if(session->userauth_pswd_state == libssh2_NB_state_idle) { - /* Zero the whole thing out */ - memset(&session->userauth_pswd_packet_requirev_state, 0, - sizeof(session->userauth_pswd_packet_requirev_state)); - - /* - * 40 = packet_type(1) + username_len(4) + service_len(4) + - * service(14)"ssh-connection" + method_len(4) + method(8)"password" + - * chgpwdbool(1) + password_len(4) */ - session->userauth_pswd_data_len = username_len + 40; - - session->userauth_pswd_data0 = - (unsigned char) ~SSH_MSG_USERAUTH_PASSWD_CHANGEREQ; - - /* TODO: remove this alloc with a fixed buffer in the session - struct */ - s = session->userauth_pswd_data = - LIBSSH2_ALLOC(session, session->userauth_pswd_data_len); - if(!session->userauth_pswd_data) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "userauth-password request"); - } - - *(s++) = SSH_MSG_USERAUTH_REQUEST; - _libssh2_store_str(&s, username, username_len); - _libssh2_store_str(&s, "ssh-connection", sizeof("ssh-connection") - 1); - _libssh2_store_str(&s, "password", sizeof("password") - 1); - *s++ = '\0'; - _libssh2_store_u32(&s, password_len); - /* 'password' is sent separately */ - - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Attempting to login using password authentication"); - - session->userauth_pswd_state = libssh2_NB_state_created; - } - - if(session->userauth_pswd_state == libssh2_NB_state_created) { - rc = _libssh2_transport_send(session, session->userauth_pswd_data, - session->userauth_pswd_data_len, - password, password_len); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block writing password request"); - } - - /* now free the sent packet */ - LIBSSH2_FREE(session, session->userauth_pswd_data); - session->userauth_pswd_data = NULL; - - if(rc) { - session->userauth_pswd_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send userauth-password request"); - } - - session->userauth_pswd_state = libssh2_NB_state_sent; - } - - password_response: - - if((session->userauth_pswd_state == libssh2_NB_state_sent) - || (session->userauth_pswd_state == libssh2_NB_state_sent1) - || (session->userauth_pswd_state == libssh2_NB_state_sent2)) { - if(session->userauth_pswd_state == libssh2_NB_state_sent) { - rc = _libssh2_packet_requirev(session, reply_codes, - &session->userauth_pswd_data, - &session->userauth_pswd_data_len, - 0, NULL, 0, - &session-> - userauth_pswd_packet_requirev_state); - - if(rc) { - if(rc != LIBSSH2_ERROR_EAGAIN) - session->userauth_pswd_state = libssh2_NB_state_idle; - - return _libssh2_error(session, rc, - "Waiting for password response"); - } - else if(session->userauth_pswd_data_len < 1) { - session->userauth_pswd_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unexpected packet size"); - } - - if(session->userauth_pswd_data[0] == SSH_MSG_USERAUTH_SUCCESS) { - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Password authentication successful"); - LIBSSH2_FREE(session, session->userauth_pswd_data); - session->userauth_pswd_data = NULL; - session->state |= LIBSSH2_STATE_AUTHENTICATED; - session->userauth_pswd_state = libssh2_NB_state_idle; - return 0; - } - else if(session->userauth_pswd_data[0] == - SSH_MSG_USERAUTH_FAILURE) { - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Password authentication failed"); - LIBSSH2_FREE(session, session->userauth_pswd_data); - session->userauth_pswd_data = NULL; - session->userauth_pswd_state = libssh2_NB_state_idle; - return _libssh2_error(session, - LIBSSH2_ERROR_AUTHENTICATION_FAILED, - "Authentication failed " - "(username/password)"); - } - - session->userauth_pswd_newpw = NULL; - session->userauth_pswd_newpw_len = 0; - - session->userauth_pswd_state = libssh2_NB_state_sent1; - } - - if(session->userauth_pswd_data_len < 1) { - session->userauth_pswd_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unexpected packet size"); - } - - if((session->userauth_pswd_data[0] == - SSH_MSG_USERAUTH_PASSWD_CHANGEREQ) - || (session->userauth_pswd_data0 == - SSH_MSG_USERAUTH_PASSWD_CHANGEREQ)) { - session->userauth_pswd_data0 = SSH_MSG_USERAUTH_PASSWD_CHANGEREQ; - - if((session->userauth_pswd_state == libssh2_NB_state_sent1) || - (session->userauth_pswd_state == libssh2_NB_state_sent2)) { - if(session->userauth_pswd_state == libssh2_NB_state_sent1) { - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Password change required"); - LIBSSH2_FREE(session, session->userauth_pswd_data); - session->userauth_pswd_data = NULL; - } - if(passwd_change_cb) { - if(session->userauth_pswd_state == - libssh2_NB_state_sent1) { - passwd_change_cb(session, - &session->userauth_pswd_newpw, - &session->userauth_pswd_newpw_len, - &session->abstract); - if(!session->userauth_pswd_newpw) { - return _libssh2_error(session, - LIBSSH2_ERROR_PASSWORD_EXPIRED, - "Password expired, and " - "callback failed"); - } - - /* basic data_len + newpw_len(4) */ - if(username_len + password_len + 44 <= UINT_MAX) { - session->userauth_pswd_data_len = - username_len + password_len + 44; - s = session->userauth_pswd_data = - LIBSSH2_ALLOC(session, - session->userauth_pswd_data_len); - } - else { - s = session->userauth_pswd_data = NULL; - session->userauth_pswd_data_len = 0; - } - - if(!session->userauth_pswd_data) { - LIBSSH2_FREE(session, - session->userauth_pswd_newpw); - session->userauth_pswd_newpw = NULL; - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory " - "for userauth password " - "change request"); - } - - *(s++) = SSH_MSG_USERAUTH_REQUEST; - _libssh2_store_str(&s, username, username_len); - _libssh2_store_str(&s, "ssh-connection", - sizeof("ssh-connection") - 1); - _libssh2_store_str(&s, "password", - sizeof("password") - 1); - *s++ = 0x01; - _libssh2_store_str(&s, (char *)password, password_len); - _libssh2_store_u32(&s, - session->userauth_pswd_newpw_len); - /* send session->userauth_pswd_newpw separately */ - - session->userauth_pswd_state = libssh2_NB_state_sent2; - } - - if(session->userauth_pswd_state == - libssh2_NB_state_sent2) { - rc = _libssh2_transport_send(session, - session->userauth_pswd_data, - session->userauth_pswd_data_len, - (unsigned char *) - session->userauth_pswd_newpw, - session->userauth_pswd_newpw_len); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return _libssh2_error(session, - LIBSSH2_ERROR_EAGAIN, - "Would block waiting"); - } - - /* free the allocated packets again */ - LIBSSH2_FREE(session, session->userauth_pswd_data); - session->userauth_pswd_data = NULL; - LIBSSH2_FREE(session, session->userauth_pswd_newpw); - session->userauth_pswd_newpw = NULL; - - if(rc) { - return _libssh2_error(session, - LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send userauth " - "password-change request"); - } - - /* - * Ugliest use of goto ever. Blame it on the - * askN => requirev migration. - */ - session->userauth_pswd_state = libssh2_NB_state_sent; - goto password_response; - } - } - } - else { - session->userauth_pswd_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_PASSWORD_EXPIRED, - "Password Expired, and no callback " - "specified"); - } - } - } - - /* FAILURE */ - LIBSSH2_FREE(session, session->userauth_pswd_data); - session->userauth_pswd_data = NULL; - session->userauth_pswd_state = libssh2_NB_state_idle; - - return _libssh2_error(session, LIBSSH2_ERROR_AUTHENTICATION_FAILED, - "Authentication failed"); -} - -/* - * libssh2_userauth_password_ex - * - * Plain ol' login - */ - -LIBSSH2_API int -libssh2_userauth_password_ex(LIBSSH2_SESSION *session, const char *username, - unsigned int username_len, const char *password, - unsigned int password_len, - LIBSSH2_PASSWD_CHANGEREQ_FUNC - ((*passwd_change_cb))) -{ - int rc; - BLOCK_ADJUST(rc, session, - userauth_password(session, username, username_len, - (unsigned char *)password, password_len, - passwd_change_cb)); - return rc; -} - -static int -memory_read_publickey(LIBSSH2_SESSION * session, unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - const char *pubkeyfiledata, - size_t pubkeyfiledata_len) -{ - unsigned char *pubkey = NULL, *sp1, *sp2, *tmp; - size_t pubkey_len = pubkeyfiledata_len; - unsigned int tmp_len; - - if(pubkeyfiledata_len <= 1) { - return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Invalid data in public key file"); - } - - pubkey = LIBSSH2_ALLOC(session, pubkeyfiledata_len); - if(!pubkey) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for public key data"); - } - - memcpy(pubkey, pubkeyfiledata, pubkeyfiledata_len); - - /* - * Remove trailing whitespace - */ - while(pubkey_len && isspace(pubkey[pubkey_len - 1])) - pubkey_len--; - - if(!pubkey_len) { - LIBSSH2_FREE(session, pubkey); - return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Missing public key data"); - } - - sp1 = memchr(pubkey, ' ', pubkey_len); - if(sp1 == NULL) { - LIBSSH2_FREE(session, pubkey); - return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Invalid public key data"); - } - - sp1++; - - sp2 = memchr(sp1, ' ', pubkey_len - (sp1 - pubkey)); - if(sp2 == NULL) { - /* Assume that the id string is missing, but that it's okay */ - sp2 = pubkey + pubkey_len; - } - - if(libssh2_base64_decode(session, (char **) &tmp, &tmp_len, - (char *) sp1, sp2 - sp1)) { - LIBSSH2_FREE(session, pubkey); - return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Invalid key data, not base64 encoded"); - } - - /* Wasting some bytes here (okay, more than some), but since it's likely - * to be freed soon anyway, we'll just avoid the extra free/alloc and call - * it a wash - */ - *method = pubkey; - *method_len = sp1 - pubkey - 1; - - *pubkeydata = tmp; - *pubkeydata_len = tmp_len; - - return 0; -} - -/* - * file_read_publickey - * - * Read a public key from an id_???.pub style file - * - * Returns an allocated string containing the decoded key in *pubkeydata - * on success. - * Returns an allocated string containing the key method (e.g. "ssh-dss") - * in method on success. - */ -static int -file_read_publickey(LIBSSH2_SESSION * session, unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - const char *pubkeyfile) -{ - FILE *fd; - char c; - unsigned char *pubkey = NULL, *sp1, *sp2, *tmp; - size_t pubkey_len = 0, sp_len; - unsigned int tmp_len; - - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, "Loading public key file: %s", - pubkeyfile); - /* Read Public Key */ - fd = fopen(pubkeyfile, FOPEN_READTEXT); - if(!fd) { - return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Unable to open public key file"); - } - while(!feof(fd) && 1 == fread(&c, 1, 1, fd) && c != '\r' && c != '\n') { - pubkey_len++; - } - rewind(fd); - - if(pubkey_len <= 1) { - fclose(fd); - return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Invalid data in public key file"); - } - - pubkey = LIBSSH2_ALLOC(session, pubkey_len); - if(!pubkey) { - fclose(fd); - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for public key data"); - } - if(fread(pubkey, 1, pubkey_len, fd) != pubkey_len) { - LIBSSH2_FREE(session, pubkey); - fclose(fd); - return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Unable to read public key from file"); - } - fclose(fd); - /* - * Remove trailing whitespace - */ - while(pubkey_len && isspace(pubkey[pubkey_len - 1])) { - pubkey_len--; - } - - if(!pubkey_len) { - LIBSSH2_FREE(session, pubkey); - return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Missing public key data"); - } - - sp1 = memchr(pubkey, ' ', pubkey_len); - if(sp1 == NULL) { - LIBSSH2_FREE(session, pubkey); - return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Invalid public key data"); - } - - sp1++; - - sp_len = sp1 > pubkey ? (sp1 - pubkey) : 0; - sp2 = memchr(sp1, ' ', pubkey_len - sp_len); - if(sp2 == NULL) { - /* Assume that the id string is missing, but that it's okay */ - sp2 = pubkey + pubkey_len; - } - - if(libssh2_base64_decode(session, (char **) &tmp, &tmp_len, - (char *) sp1, sp2 - sp1)) { - LIBSSH2_FREE(session, pubkey); - return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Invalid key data, not base64 encoded"); - } - - /* Wasting some bytes here (okay, more than some), but since it's likely - * to be freed soon anyway, we'll just avoid the extra free/alloc and call - * it a wash */ - *method = pubkey; - *method_len = sp1 - pubkey - 1; - - *pubkeydata = tmp; - *pubkeydata_len = tmp_len; - - return 0; -} - -static int -memory_read_privatekey(LIBSSH2_SESSION * session, - const LIBSSH2_HOSTKEY_METHOD ** hostkey_method, - void **hostkey_abstract, - const unsigned char *method, int method_len, - const char *privkeyfiledata, size_t privkeyfiledata_len, - const char *passphrase) -{ - const LIBSSH2_HOSTKEY_METHOD **hostkey_methods_avail = - libssh2_hostkey_methods(); - - *hostkey_method = NULL; - *hostkey_abstract = NULL; - while(*hostkey_methods_avail && (*hostkey_methods_avail)->name) { - if((*hostkey_methods_avail)->initPEMFromMemory - && strncmp((*hostkey_methods_avail)->name, (const char *) method, - method_len) == 0) { - *hostkey_method = *hostkey_methods_avail; - break; - } - hostkey_methods_avail++; - } - if(!*hostkey_method) { - return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NONE, - "No handler for specified private key"); - } - - if((*hostkey_method)-> - initPEMFromMemory(session, privkeyfiledata, privkeyfiledata_len, - (unsigned char *) passphrase, - hostkey_abstract)) { - return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Unable to initialize private key from file"); - } - - return 0; -} - -/* libssh2_file_read_privatekey - * Read a PEM encoded private key from an id_??? style file - */ -static int -file_read_privatekey(LIBSSH2_SESSION * session, - const LIBSSH2_HOSTKEY_METHOD ** hostkey_method, - void **hostkey_abstract, - const unsigned char *method, int method_len, - const char *privkeyfile, const char *passphrase) -{ - const LIBSSH2_HOSTKEY_METHOD **hostkey_methods_avail = - libssh2_hostkey_methods(); - - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, "Loading private key file: %s", - privkeyfile); - *hostkey_method = NULL; - *hostkey_abstract = NULL; - while(*hostkey_methods_avail && (*hostkey_methods_avail)->name) { - if((*hostkey_methods_avail)->initPEM - && strncmp((*hostkey_methods_avail)->name, (const char *) method, - method_len) == 0) { - *hostkey_method = *hostkey_methods_avail; - break; - } - hostkey_methods_avail++; - } - if(!*hostkey_method) { - return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NONE, - "No handler for specified private key"); - } - - if((*hostkey_method)-> - initPEM(session, privkeyfile, (unsigned char *) passphrase, - hostkey_abstract)) { - return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Unable to initialize private key from file"); - } - - return 0; -} - -struct privkey_file { - const char *filename; - const char *passphrase; -}; - -static int -sign_frommemory(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, - const unsigned char *data, size_t data_len, void **abstract) -{ - struct privkey_file *pk_file = (struct privkey_file *) (*abstract); - const LIBSSH2_HOSTKEY_METHOD *privkeyobj; - void *hostkey_abstract; - struct iovec datavec; - int rc; - - rc = memory_read_privatekey(session, &privkeyobj, &hostkey_abstract, - session->userauth_pblc_method, - session->userauth_pblc_method_len, - pk_file->filename, - strlen(pk_file->filename), - pk_file->passphrase); - if(rc) - return rc; - - libssh2_prepare_iovec(&datavec, 1); - datavec.iov_base = (void *)data; - datavec.iov_len = data_len; - - if(privkeyobj->signv(session, sig, sig_len, 1, &datavec, - &hostkey_abstract)) { - if(privkeyobj->dtor) { - privkeyobj->dtor(session, &hostkey_abstract); - } - return -1; - } - - if(privkeyobj->dtor) { - privkeyobj->dtor(session, &hostkey_abstract); - } - return 0; -} - -static int -sign_fromfile(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, - const unsigned char *data, size_t data_len, void **abstract) -{ - struct privkey_file *privkey_file = (struct privkey_file *) (*abstract); - const LIBSSH2_HOSTKEY_METHOD *privkeyobj; - void *hostkey_abstract; - struct iovec datavec; - int rc; - - rc = file_read_privatekey(session, &privkeyobj, &hostkey_abstract, - session->userauth_pblc_method, - session->userauth_pblc_method_len, - privkey_file->filename, - privkey_file->passphrase); - if(rc) - return rc; - - libssh2_prepare_iovec(&datavec, 1); - datavec.iov_base = (void *)data; - datavec.iov_len = data_len; - - if(privkeyobj->signv(session, sig, sig_len, 1, &datavec, - &hostkey_abstract)) { - if(privkeyobj->dtor) { - privkeyobj->dtor(session, &hostkey_abstract); - } - return -1; - } - - if(privkeyobj->dtor) { - privkeyobj->dtor(session, &hostkey_abstract); - } - return 0; -} - - - -/* userauth_hostbased_fromfile - * Authenticate using a keypair found in the named files - */ -static int -userauth_hostbased_fromfile(LIBSSH2_SESSION *session, - const char *username, size_t username_len, - const char *publickey, const char *privatekey, - const char *passphrase, const char *hostname, - size_t hostname_len, - const char *local_username, - size_t local_username_len) -{ - int rc; - -#if !LIBSSH2_RSA - return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "RSA is not supported by crypto backend"); -#endif - - if(session->userauth_host_state == libssh2_NB_state_idle) { - const LIBSSH2_HOSTKEY_METHOD *privkeyobj; - unsigned char *pubkeydata = NULL; - unsigned char *sig = NULL; - size_t pubkeydata_len = 0; - size_t sig_len = 0; - void *abstract; - unsigned char buf[5]; - struct iovec datavec[4]; - - /* Zero the whole thing out */ - memset(&session->userauth_host_packet_requirev_state, 0, - sizeof(session->userauth_host_packet_requirev_state)); - - if(publickey) { - rc = file_read_publickey(session, &session->userauth_host_method, - &session->userauth_host_method_len, - &pubkeydata, &pubkeydata_len, publickey); - if(rc) - /* Note: file_read_publickey() calls _libssh2_error() */ - return rc; - } - else { - /* Compute public key from private key. */ - rc = _libssh2_pub_priv_keyfile(session, - &session->userauth_host_method, - &session->userauth_host_method_len, - &pubkeydata, &pubkeydata_len, - privatekey, passphrase); - if(rc) - /* libssh2_pub_priv_keyfile calls _libssh2_error() */ - return rc; - } - - /* - * 52 = packet_type(1) + username_len(4) + servicename_len(4) + - * service_name(14)"ssh-connection" + authmethod_len(4) + - * authmethod(9)"hostbased" + method_len(4) + pubkeydata_len(4) + - * hostname_len(4) + local_username_len(4) - */ - session->userauth_host_packet_len = - username_len + session->userauth_host_method_len + hostname_len + - local_username_len + pubkeydata_len + 52; - - /* - * Preallocate space for an overall length, method name again, - * and the signature, which won't be any larger than the size of - * the publickeydata itself - */ - session->userauth_host_s = session->userauth_host_packet = - LIBSSH2_ALLOC(session, - session->userauth_host_packet_len + 4 + - (4 + session->userauth_host_method_len) + - (4 + pubkeydata_len)); - if(!session->userauth_host_packet) { - LIBSSH2_FREE(session, session->userauth_host_method); - session->userauth_host_method = NULL; - LIBSSH2_FREE(session, pubkeydata); - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Out of memory"); - } - - *(session->userauth_host_s++) = SSH_MSG_USERAUTH_REQUEST; - _libssh2_store_str(&session->userauth_host_s, username, username_len); - _libssh2_store_str(&session->userauth_host_s, "ssh-connection", 14); - _libssh2_store_str(&session->userauth_host_s, "hostbased", 9); - _libssh2_store_str(&session->userauth_host_s, - (const char *)session->userauth_host_method, - session->userauth_host_method_len); - _libssh2_store_str(&session->userauth_host_s, (const char *)pubkeydata, - pubkeydata_len); - LIBSSH2_FREE(session, pubkeydata); - _libssh2_store_str(&session->userauth_host_s, hostname, hostname_len); - _libssh2_store_str(&session->userauth_host_s, local_username, - local_username_len); - - rc = file_read_privatekey(session, &privkeyobj, &abstract, - session->userauth_host_method, - session->userauth_host_method_len, - privatekey, passphrase); - if(rc) { - /* Note: file_read_privatekey() calls _libssh2_error() */ - LIBSSH2_FREE(session, session->userauth_host_method); - session->userauth_host_method = NULL; - LIBSSH2_FREE(session, session->userauth_host_packet); - session->userauth_host_packet = NULL; - return rc; - } - - _libssh2_htonu32(buf, session->session_id_len); - libssh2_prepare_iovec(datavec, 4); - datavec[0].iov_base = (void *)buf; - datavec[0].iov_len = 4; - datavec[1].iov_base = (void *)session->session_id; - datavec[1].iov_len = session->session_id_len; - datavec[2].iov_base = (void *)session->userauth_host_packet; - datavec[2].iov_len = session->userauth_host_packet_len; - - if(privkeyobj && privkeyobj->signv && - privkeyobj->signv(session, &sig, &sig_len, 3, - datavec, &abstract)) { - LIBSSH2_FREE(session, session->userauth_host_method); - session->userauth_host_method = NULL; - LIBSSH2_FREE(session, session->userauth_host_packet); - session->userauth_host_packet = NULL; - if(privkeyobj->dtor) { - privkeyobj->dtor(session, &abstract); - } - return -1; - } - - if(privkeyobj && privkeyobj->dtor) { - privkeyobj->dtor(session, &abstract); - } - - if(sig_len > pubkeydata_len) { - unsigned char *newpacket; - /* Should *NEVER* happen, but...well.. better safe than sorry */ - newpacket = LIBSSH2_REALLOC(session, session->userauth_host_packet, - session->userauth_host_packet_len + 4 + - (4 + session->userauth_host_method_len) - + (4 + sig_len)); /* PK sigblob */ - if(!newpacket) { - LIBSSH2_FREE(session, sig); - LIBSSH2_FREE(session, session->userauth_host_packet); - session->userauth_host_packet = NULL; - LIBSSH2_FREE(session, session->userauth_host_method); - session->userauth_host_method = NULL; - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Failed allocating additional space for " - "userauth-hostbased packet"); - } - session->userauth_host_packet = newpacket; - } - - session->userauth_host_s = - session->userauth_host_packet + session->userauth_host_packet_len; - - _libssh2_store_u32(&session->userauth_host_s, - 4 + session->userauth_host_method_len + - 4 + sig_len); - _libssh2_store_str(&session->userauth_host_s, - (const char *)session->userauth_host_method, - session->userauth_host_method_len); - LIBSSH2_FREE(session, session->userauth_host_method); - session->userauth_host_method = NULL; - - _libssh2_store_str(&session->userauth_host_s, (const char *)sig, - sig_len); - LIBSSH2_FREE(session, sig); - - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Attempting hostbased authentication"); - - session->userauth_host_state = libssh2_NB_state_created; - } - - if(session->userauth_host_state == libssh2_NB_state_created) { - rc = _libssh2_transport_send(session, session->userauth_host_packet, - session->userauth_host_s - - session->userauth_host_packet, - NULL, 0); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block"); - } - else if(rc) { - LIBSSH2_FREE(session, session->userauth_host_packet); - session->userauth_host_packet = NULL; - session->userauth_host_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send userauth-hostbased request"); - } - LIBSSH2_FREE(session, session->userauth_host_packet); - session->userauth_host_packet = NULL; - - session->userauth_host_state = libssh2_NB_state_sent; - } - - if(session->userauth_host_state == libssh2_NB_state_sent) { - static const unsigned char reply_codes[3] = - { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 }; - size_t data_len; - rc = _libssh2_packet_requirev(session, reply_codes, - &session->userauth_host_data, - &data_len, 0, NULL, 0, - &session-> - userauth_host_packet_requirev_state); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block"); - } - - session->userauth_host_state = libssh2_NB_state_idle; - if(rc || data_len < 1) { - return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, - "Auth failed"); - } - - if(session->userauth_host_data[0] == SSH_MSG_USERAUTH_SUCCESS) { - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Hostbased authentication successful"); - /* We are us and we've proved it. */ - LIBSSH2_FREE(session, session->userauth_host_data); - session->userauth_host_data = NULL; - session->state |= LIBSSH2_STATE_AUTHENTICATED; - return 0; - } - } - - /* This public key is not allowed for this user on this server */ - LIBSSH2_FREE(session, session->userauth_host_data); - session->userauth_host_data = NULL; - return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, - "Invalid signature for supplied public key, or bad " - "username/public key combination"); -} - -/* libssh2_userauth_hostbased_fromfile_ex - * Authenticate using a keypair found in the named files - */ -LIBSSH2_API int -libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session, - const char *user, - unsigned int user_len, - const char *publickey, - const char *privatekey, - const char *passphrase, - const char *host, - unsigned int host_len, - const char *localuser, - unsigned int localuser_len) -{ - int rc; - BLOCK_ADJUST(rc, session, - userauth_hostbased_fromfile(session, user, user_len, - publickey, privatekey, - passphrase, host, host_len, - localuser, localuser_len)); - return rc; -} - - - -int -_libssh2_userauth_publickey(LIBSSH2_SESSION *session, - const char *username, - unsigned int username_len, - const unsigned char *pubkeydata, - unsigned long pubkeydata_len, - LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC - ((*sign_callback)), - void *abstract) -{ - unsigned char reply_codes[4] = - { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, - SSH_MSG_USERAUTH_PK_OK, 0 - }; - int rc; - unsigned char *s; - - if(session->userauth_pblc_state == libssh2_NB_state_idle) { - - /* - * The call to _libssh2_ntohu32 later relies on pubkeydata having at - * least 4 valid bytes containing the length of the method name. - */ - if(pubkeydata_len < 4) - return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, - "Invalid public key, too short"); - - /* Zero the whole thing out */ - memset(&session->userauth_pblc_packet_requirev_state, 0, - sizeof(session->userauth_pblc_packet_requirev_state)); - - /* - * As an optimisation, userauth_publickey_fromfile reuses a - * previously allocated copy of the method name to avoid an extra - * allocation/free. - * For other uses, we allocate and populate it here. - */ - if(!session->userauth_pblc_method) { - session->userauth_pblc_method_len = _libssh2_ntohu32(pubkeydata); - - if(session->userauth_pblc_method_len > pubkeydata_len - 4) - /* the method length simply cannot be longer than the entire - passed in data, so we use this to detect crazy input - data */ - return _libssh2_error(session, - LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, - "Invalid public key"); - - session->userauth_pblc_method = - LIBSSH2_ALLOC(session, session->userauth_pblc_method_len); - if(!session->userauth_pblc_method) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory " - "for public key data"); - } - memcpy(session->userauth_pblc_method, pubkeydata + 4, - session->userauth_pblc_method_len); - } - /* - * The length of the method name read from plaintext prefix in the - * file must match length embedded in the key. - * TODO: The data should match too but we don't check that. Should we? - */ - else if(session->userauth_pblc_method_len != - _libssh2_ntohu32(pubkeydata)) - return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, - "Invalid public key"); - - /* - * 45 = packet_type(1) + username_len(4) + servicename_len(4) + - * service_name(14)"ssh-connection" + authmethod_len(4) + - * authmethod(9)"publickey" + sig_included(1)'\0' + algmethod_len(4) + - * publickey_len(4) - */ - session->userauth_pblc_packet_len = - username_len + session->userauth_pblc_method_len + pubkeydata_len + - 45; - - /* - * Preallocate space for an overall length, method name again, and the - * signature, which won't be any larger than the size of the - * publickeydata itself. - * - * Note that the 'pubkeydata_len' extra bytes allocated here will not - * be used in this first send, but will be used in the later one where - * this same allocation is re-used. - */ - s = session->userauth_pblc_packet = - LIBSSH2_ALLOC(session, - session->userauth_pblc_packet_len + 4 + - (4 + session->userauth_pblc_method_len) - + (4 + pubkeydata_len)); - if(!session->userauth_pblc_packet) { - LIBSSH2_FREE(session, session->userauth_pblc_method); - session->userauth_pblc_method = NULL; - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Out of memory"); - } - - *s++ = SSH_MSG_USERAUTH_REQUEST; - _libssh2_store_str(&s, username, username_len); - _libssh2_store_str(&s, "ssh-connection", 14); - _libssh2_store_str(&s, "publickey", 9); - - session->userauth_pblc_b = s; - /* Not sending signature with *this* packet */ - *s++ = 0; - - _libssh2_store_str(&s, (const char *)session->userauth_pblc_method, - session->userauth_pblc_method_len); - _libssh2_store_str(&s, (const char *)pubkeydata, pubkeydata_len); - - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Attempting publickey authentication"); - - session->userauth_pblc_state = libssh2_NB_state_created; - } - - if(session->userauth_pblc_state == libssh2_NB_state_created) { - rc = _libssh2_transport_send(session, session->userauth_pblc_packet, - session->userauth_pblc_packet_len, - NULL, 0); - if(rc == LIBSSH2_ERROR_EAGAIN) - return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block"); - else if(rc) { - LIBSSH2_FREE(session, session->userauth_pblc_packet); - session->userauth_pblc_packet = NULL; - LIBSSH2_FREE(session, session->userauth_pblc_method); - session->userauth_pblc_method = NULL; - session->userauth_pblc_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send userauth-publickey request"); - } - - session->userauth_pblc_state = libssh2_NB_state_sent; - } - - if(session->userauth_pblc_state == libssh2_NB_state_sent) { - rc = _libssh2_packet_requirev(session, reply_codes, - &session->userauth_pblc_data, - &session->userauth_pblc_data_len, 0, - NULL, 0, - &session-> - userauth_pblc_packet_requirev_state); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block"); - } - else if(rc || (session->userauth_pblc_data_len < 1)) { - LIBSSH2_FREE(session, session->userauth_pblc_packet); - session->userauth_pblc_packet = NULL; - LIBSSH2_FREE(session, session->userauth_pblc_method); - session->userauth_pblc_method = NULL; - session->userauth_pblc_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, - "Waiting for USERAUTH response"); - } - - if(session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_SUCCESS) { - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Pubkey authentication prematurely successful"); - /* - * God help any SSH server that allows an UNVERIFIED - * public key to validate the user - */ - LIBSSH2_FREE(session, session->userauth_pblc_data); - session->userauth_pblc_data = NULL; - LIBSSH2_FREE(session, session->userauth_pblc_packet); - session->userauth_pblc_packet = NULL; - LIBSSH2_FREE(session, session->userauth_pblc_method); - session->userauth_pblc_method = NULL; - session->state |= LIBSSH2_STATE_AUTHENTICATED; - session->userauth_pblc_state = libssh2_NB_state_idle; - return 0; - } - - if(session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_FAILURE) { - /* This public key is not allowed for this user on this server */ - LIBSSH2_FREE(session, session->userauth_pblc_data); - session->userauth_pblc_data = NULL; - LIBSSH2_FREE(session, session->userauth_pblc_packet); - session->userauth_pblc_packet = NULL; - LIBSSH2_FREE(session, session->userauth_pblc_method); - session->userauth_pblc_method = NULL; - session->userauth_pblc_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_AUTHENTICATION_FAILED, - "Username/PublicKey combination invalid"); - } - - /* Semi-Success! */ - LIBSSH2_FREE(session, session->userauth_pblc_data); - session->userauth_pblc_data = NULL; - - *session->userauth_pblc_b = 0x01; - session->userauth_pblc_state = libssh2_NB_state_sent1; - } - - if(session->userauth_pblc_state == libssh2_NB_state_sent1) { - unsigned char *buf; - unsigned char *sig; - size_t sig_len; - - s = buf = LIBSSH2_ALLOC(session, 4 + session->session_id_len - + session->userauth_pblc_packet_len); - if(!buf) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "userauth-publickey signed data"); - } - - _libssh2_store_str(&s, (const char *)session->session_id, - session->session_id_len); - - memcpy(s, session->userauth_pblc_packet, - session->userauth_pblc_packet_len); - s += session->userauth_pblc_packet_len; - - rc = sign_callback(session, &sig, &sig_len, buf, s - buf, abstract); - LIBSSH2_FREE(session, buf); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block"); - } - else if(rc) { - LIBSSH2_FREE(session, session->userauth_pblc_method); - session->userauth_pblc_method = NULL; - LIBSSH2_FREE(session, session->userauth_pblc_packet); - session->userauth_pblc_packet = NULL; - session->userauth_pblc_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, - "Callback returned error"); - } - - /* - * If this function was restarted, pubkeydata_len might still be 0 - * which will cause an unnecessary but harmless realloc here. - */ - if(sig_len > pubkeydata_len) { - unsigned char *newpacket; - /* Should *NEVER* happen, but...well.. better safe than sorry */ - newpacket = LIBSSH2_REALLOC(session, - session->userauth_pblc_packet, - session->userauth_pblc_packet_len + 4 + - (4 + session->userauth_pblc_method_len) - + (4 + sig_len)); /* PK sigblob */ - if(!newpacket) { - LIBSSH2_FREE(session, sig); - LIBSSH2_FREE(session, session->userauth_pblc_packet); - session->userauth_pblc_packet = NULL; - LIBSSH2_FREE(session, session->userauth_pblc_method); - session->userauth_pblc_method = NULL; - session->userauth_pblc_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Failed allocating additional space for " - "userauth-publickey packet"); - } - session->userauth_pblc_packet = newpacket; - } - - s = session->userauth_pblc_packet + session->userauth_pblc_packet_len; - session->userauth_pblc_b = NULL; - - _libssh2_store_u32(&s, - 4 + session->userauth_pblc_method_len + 4 + - sig_len); - _libssh2_store_str(&s, (const char *)session->userauth_pblc_method, - session->userauth_pblc_method_len); - - LIBSSH2_FREE(session, session->userauth_pblc_method); - session->userauth_pblc_method = NULL; - - _libssh2_store_str(&s, (const char *)sig, sig_len); - LIBSSH2_FREE(session, sig); - - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Attempting publickey authentication -- phase 2"); - - session->userauth_pblc_s = s; - session->userauth_pblc_state = libssh2_NB_state_sent2; - } - - if(session->userauth_pblc_state == libssh2_NB_state_sent2) { - rc = _libssh2_transport_send(session, session->userauth_pblc_packet, - session->userauth_pblc_s - - session->userauth_pblc_packet, - NULL, 0); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block"); - } - else if(rc) { - LIBSSH2_FREE(session, session->userauth_pblc_packet); - session->userauth_pblc_packet = NULL; - session->userauth_pblc_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send userauth-publickey request"); - } - LIBSSH2_FREE(session, session->userauth_pblc_packet); - session->userauth_pblc_packet = NULL; - - session->userauth_pblc_state = libssh2_NB_state_sent3; - } - - /* PK_OK is no longer valid */ - reply_codes[2] = 0; - - rc = _libssh2_packet_requirev(session, reply_codes, - &session->userauth_pblc_data, - &session->userauth_pblc_data_len, 0, NULL, 0, - &session->userauth_pblc_packet_requirev_state); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block requesting userauth list"); - } - else if(rc || session->userauth_pblc_data_len < 1) { - session->userauth_pblc_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, - "Waiting for publickey USERAUTH response"); - } - - if(session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_SUCCESS) { - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Publickey authentication successful"); - /* We are us and we've proved it. */ - LIBSSH2_FREE(session, session->userauth_pblc_data); - session->userauth_pblc_data = NULL; - session->state |= LIBSSH2_STATE_AUTHENTICATED; - session->userauth_pblc_state = libssh2_NB_state_idle; - return 0; - } - - /* This public key is not allowed for this user on this server */ - LIBSSH2_FREE(session, session->userauth_pblc_data); - session->userauth_pblc_data = NULL; - session->userauth_pblc_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, - "Invalid signature for supplied public key, or bad " - "username/public key combination"); -} - - /* - * userauth_publickey_frommemory - * Authenticate using a keypair from memory - */ -static int -userauth_publickey_frommemory(LIBSSH2_SESSION *session, - const char *username, - size_t username_len, - const char *publickeydata, - size_t publickeydata_len, - const char *privatekeydata, - size_t privatekeydata_len, - const char *passphrase) -{ - unsigned char *pubkeydata = NULL; - size_t pubkeydata_len = 0; - struct privkey_file privkey_file; - void *abstract = &privkey_file; - int rc; - -#if !LIBSSH2_RSA - return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "RSA is not supported by crypto backend"); -#endif - - privkey_file.filename = privatekeydata; - privkey_file.passphrase = passphrase; - - if(session->userauth_pblc_state == libssh2_NB_state_idle) { - if(publickeydata_len && publickeydata) { - rc = memory_read_publickey(session, &session->userauth_pblc_method, - &session->userauth_pblc_method_len, - &pubkeydata, &pubkeydata_len, - publickeydata, publickeydata_len); - if(rc) - return rc; - } - else if(privatekeydata_len && privatekeydata) { - /* Compute public key from private key. */ - if(_libssh2_pub_priv_keyfilememory(session, - &session->userauth_pblc_method, - &session->userauth_pblc_method_len, - &pubkeydata, &pubkeydata_len, - privatekeydata, privatekeydata_len, - passphrase)) - return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Unable to extract public key " - "from private key."); - } - else { - return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Invalid data in public and private key."); - } - } - - rc = _libssh2_userauth_publickey(session, username, username_len, - pubkeydata, pubkeydata_len, - sign_frommemory, &abstract); - if(pubkeydata) - LIBSSH2_FREE(session, pubkeydata); - - return rc; -} - -/* - * userauth_publickey_fromfile - * Authenticate using a keypair found in the named files - */ -static int -userauth_publickey_fromfile(LIBSSH2_SESSION *session, - const char *username, - size_t username_len, - const char *publickey, - const char *privatekey, - const char *passphrase) -{ - unsigned char *pubkeydata = NULL; - size_t pubkeydata_len = 0; - struct privkey_file privkey_file; - void *abstract = &privkey_file; - int rc; - -#if !LIBSSH2_RSA - return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "RSA is not supported by crypto backend"); -#endif - - privkey_file.filename = privatekey; - privkey_file.passphrase = passphrase; - - if(session->userauth_pblc_state == libssh2_NB_state_idle) { - if(publickey) { - rc = file_read_publickey(session, &session->userauth_pblc_method, - &session->userauth_pblc_method_len, - &pubkeydata, &pubkeydata_len, publickey); - if(rc) - return rc; - } - else { - /* Compute public key from private key. */ - rc = _libssh2_pub_priv_keyfile(session, - &session->userauth_pblc_method, - &session->userauth_pblc_method_len, - &pubkeydata, &pubkeydata_len, - privatekey, passphrase); - - /* _libssh2_pub_priv_keyfile calls _libssh2_error() */ - if(rc) - return rc; - } - } - - rc = _libssh2_userauth_publickey(session, username, username_len, - pubkeydata, pubkeydata_len, - sign_fromfile, &abstract); - if(pubkeydata) - LIBSSH2_FREE(session, pubkeydata); - - return rc; -} - -/* libssh2_userauth_publickey_frommemory - * Authenticate using a keypair from memory - */ -LIBSSH2_API int -libssh2_userauth_publickey_frommemory(LIBSSH2_SESSION *session, - const char *user, - size_t user_len, - const char *publickeyfiledata, - size_t publickeyfiledata_len, - const char *privatekeyfiledata, - size_t privatekeyfiledata_len, - const char *passphrase) -{ - int rc; - - if(NULL == passphrase) - /* if given a NULL pointer, make it point to a zero-length - string to save us from having to check this all over */ - passphrase = ""; - - BLOCK_ADJUST(rc, session, - userauth_publickey_frommemory(session, user, user_len, - publickeyfiledata, - publickeyfiledata_len, - privatekeyfiledata, - privatekeyfiledata_len, - passphrase)); - return rc; -} - -/* libssh2_userauth_publickey_fromfile_ex - * Authenticate using a keypair found in the named files - */ -LIBSSH2_API int -libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, - const char *user, - unsigned int user_len, - const char *publickey, - const char *privatekey, - const char *passphrase) -{ - int rc; - - if(NULL == passphrase) - /* if given a NULL pointer, make it point to a zero-length - string to save us from having to check this all over */ - passphrase = ""; - - BLOCK_ADJUST(rc, session, - userauth_publickey_fromfile(session, user, user_len, - publickey, privatekey, - passphrase)); - return rc; -} - -/* libssh2_userauth_publickey_ex - * Authenticate using an external callback function - */ -LIBSSH2_API int -libssh2_userauth_publickey(LIBSSH2_SESSION *session, - const char *user, - const unsigned char *pubkeydata, - size_t pubkeydata_len, - LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC - ((*sign_callback)), - void **abstract) -{ - int rc; - - if(!session) - return LIBSSH2_ERROR_BAD_USE; - - BLOCK_ADJUST(rc, session, - _libssh2_userauth_publickey(session, user, strlen(user), - pubkeydata, pubkeydata_len, - sign_callback, abstract)); - return rc; -} - - - -/* - * userauth_keyboard_interactive - * - * Authenticate using a challenge-response authentication - */ -static int -userauth_keyboard_interactive(LIBSSH2_SESSION * session, - const char *username, - unsigned int username_len, - LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC - ((*response_callback))) -{ - unsigned char *s; - int rc; - - static const unsigned char reply_codes[4] = { - SSH_MSG_USERAUTH_SUCCESS, - SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_INFO_REQUEST, 0 - }; - unsigned int language_tag_len; - unsigned int i; - - if(session->userauth_kybd_state == libssh2_NB_state_idle) { - session->userauth_kybd_auth_name = NULL; - session->userauth_kybd_auth_instruction = NULL; - session->userauth_kybd_num_prompts = 0; - session->userauth_kybd_auth_failure = 1; - session->userauth_kybd_prompts = NULL; - session->userauth_kybd_responses = NULL; - - /* Zero the whole thing out */ - memset(&session->userauth_kybd_packet_requirev_state, 0, - sizeof(session->userauth_kybd_packet_requirev_state)); - - session->userauth_kybd_packet_len = - 1 /* byte SSH_MSG_USERAUTH_REQUEST */ - + 4 + username_len /* string user name (ISO-10646 UTF-8, as - defined in [RFC-3629]) */ - + 4 + 14 /* string service name (US-ASCII) */ - + 4 + 20 /* string "keyboard-interactive" (US-ASCII) */ - + 4 + 0 /* string language tag (as defined in - [RFC-3066]) */ - + 4 + 0 /* string submethods (ISO-10646 UTF-8) */ - ; - - session->userauth_kybd_data = s = - LIBSSH2_ALLOC(session, session->userauth_kybd_packet_len); - if(!s) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "keyboard-interactive authentication"); - } - - *s++ = SSH_MSG_USERAUTH_REQUEST; - - /* user name */ - _libssh2_store_str(&s, username, username_len); - - /* service name */ - _libssh2_store_str(&s, "ssh-connection", sizeof("ssh-connection") - 1); - - /* "keyboard-interactive" */ - _libssh2_store_str(&s, "keyboard-interactive", - sizeof("keyboard-interactive") - 1); - /* language tag */ - _libssh2_store_u32(&s, 0); - - /* submethods */ - _libssh2_store_u32(&s, 0); - - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Attempting keyboard-interactive authentication"); - - session->userauth_kybd_state = libssh2_NB_state_created; - } - - if(session->userauth_kybd_state == libssh2_NB_state_created) { - rc = _libssh2_transport_send(session, session->userauth_kybd_data, - session->userauth_kybd_packet_len, - NULL, 0); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block"); - } - else if(rc) { - LIBSSH2_FREE(session, session->userauth_kybd_data); - session->userauth_kybd_data = NULL; - session->userauth_kybd_state = libssh2_NB_state_idle; - return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send keyboard-interactive" - " request"); - } - LIBSSH2_FREE(session, session->userauth_kybd_data); - session->userauth_kybd_data = NULL; - - session->userauth_kybd_state = libssh2_NB_state_sent; - } - - for(;;) { - if(session->userauth_kybd_state == libssh2_NB_state_sent) { - rc = _libssh2_packet_requirev(session, reply_codes, - &session->userauth_kybd_data, - &session->userauth_kybd_data_len, - 0, NULL, 0, - &session-> - userauth_kybd_packet_requirev_state); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block"); - } - else if(rc || session->userauth_kybd_data_len < 1) { - session->userauth_kybd_state = libssh2_NB_state_idle; - return _libssh2_error(session, - LIBSSH2_ERROR_AUTHENTICATION_FAILED, - "Waiting for keyboard " - "USERAUTH response"); - } - - if(session->userauth_kybd_data[0] == SSH_MSG_USERAUTH_SUCCESS) { - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Keyboard-interactive " - "authentication successful"); - LIBSSH2_FREE(session, session->userauth_kybd_data); - session->userauth_kybd_data = NULL; - session->state |= LIBSSH2_STATE_AUTHENTICATED; - session->userauth_kybd_state = libssh2_NB_state_idle; - return 0; - } - - if(session->userauth_kybd_data[0] == SSH_MSG_USERAUTH_FAILURE) { - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Keyboard-interactive authentication failed"); - LIBSSH2_FREE(session, session->userauth_kybd_data); - session->userauth_kybd_data = NULL; - session->userauth_kybd_state = libssh2_NB_state_idle; - return _libssh2_error(session, - LIBSSH2_ERROR_AUTHENTICATION_FAILED, - "Authentication failed " - "(keyboard-interactive)"); - } - - /* server requested PAM-like conversation */ - s = session->userauth_kybd_data + 1; - - if(session->userauth_kybd_data_len >= 5) { - /* string name (ISO-10646 UTF-8) */ - session->userauth_kybd_auth_name_len = _libssh2_ntohu32(s); - s += 4; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "userauth keyboard data buffer too small" - "to get length"); - goto cleanup; - } - - if(session->userauth_kybd_auth_name_len) { - session->userauth_kybd_auth_name = - LIBSSH2_ALLOC(session, - session->userauth_kybd_auth_name_len); - if(!session->userauth_kybd_auth_name) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "keyboard-interactive 'name' " - "request field"); - goto cleanup; - } - if(s + session->userauth_list_data_len <= - session->userauth_kybd_data + - session->userauth_kybd_data_len) { - memcpy(session->userauth_kybd_auth_name, s, - session->userauth_kybd_auth_name_len); - s += session->userauth_kybd_auth_name_len; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "userauth keyboard data buffer too small" - "for auth name"); - goto cleanup; - } - } - - if(s + 4 <= session->userauth_kybd_data + - session->userauth_kybd_data_len) { - /* string instruction (ISO-10646 UTF-8) */ - session->userauth_kybd_auth_instruction_len = - _libssh2_ntohu32(s); - s += 4; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "userauth keyboard data buffer too small" - "for auth instruction length"); - goto cleanup; - } - - if(session->userauth_kybd_auth_instruction_len) { - session->userauth_kybd_auth_instruction = - LIBSSH2_ALLOC(session, - session->userauth_kybd_auth_instruction_len); - if(!session->userauth_kybd_auth_instruction) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "keyboard-interactive 'instruction' " - "request field"); - goto cleanup; - } - if(s + session->userauth_kybd_auth_instruction_len <= - session->userauth_kybd_data + - session->userauth_kybd_data_len) { - memcpy(session->userauth_kybd_auth_instruction, s, - session->userauth_kybd_auth_instruction_len); - s += session->userauth_kybd_auth_instruction_len; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "userauth keyboard data buffer too small" - "for auth instruction"); - goto cleanup; - } - } - - if(s + 4 <= session->userauth_kybd_data + - session->userauth_kybd_data_len) { - /* string language tag (as defined in [RFC-3066]) */ - language_tag_len = _libssh2_ntohu32(s); - s += 4; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "userauth keyboard data buffer too small" - "for auth language tag length"); - goto cleanup; - } - - if(s + language_tag_len <= session->userauth_kybd_data + - session->userauth_kybd_data_len) { - /* ignoring this field as deprecated */ - s += language_tag_len; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "userauth keyboard data buffer too small" - "for auth language tag"); - goto cleanup; - } - - if(s + 4 <= session->userauth_kybd_data + - session->userauth_kybd_data_len) { - /* int num-prompts */ - session->userauth_kybd_num_prompts = _libssh2_ntohu32(s); - s += 4; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "userauth keyboard data buffer too small" - "for auth num keyboard prompts"); - goto cleanup; - } - - if(session->userauth_kybd_num_prompts > 100) { - _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, - "Too many replies for " - "keyboard-interactive prompts"); - goto cleanup; - } - - if(session->userauth_kybd_num_prompts) { - session->userauth_kybd_prompts = - LIBSSH2_CALLOC(session, - sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) * - session->userauth_kybd_num_prompts); - if(!session->userauth_kybd_prompts) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "keyboard-interactive prompts array"); - goto cleanup; - } - - session->userauth_kybd_responses = - LIBSSH2_CALLOC(session, - sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) * - session->userauth_kybd_num_prompts); - if(!session->userauth_kybd_responses) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "keyboard-interactive responses array"); - goto cleanup; - } - - for(i = 0; i < session->userauth_kybd_num_prompts; i++) { - if(s + 4 <= session->userauth_kybd_data + - session->userauth_kybd_data_len) { - /* string prompt[1] (ISO-10646 UTF-8) */ - session->userauth_kybd_prompts[i].length = - _libssh2_ntohu32(s); - s += 4; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "userauth keyboard data buffer too " - "small for auth keyboard " - "prompt length"); - goto cleanup; - } - - session->userauth_kybd_prompts[i].text = - LIBSSH2_CALLOC(session, - session->userauth_kybd_prompts[i]. - length); - if(!session->userauth_kybd_prompts[i].text) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "keyboard-interactive prompt message"); - goto cleanup; - } - - if(s + session->userauth_kybd_prompts[i].length <= - session->userauth_kybd_data + - session->userauth_kybd_data_len) { - memcpy(session->userauth_kybd_prompts[i].text, s, - session->userauth_kybd_prompts[i].length); - s += session->userauth_kybd_prompts[i].length; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "userauth keyboard data buffer too " - "small for auth keyboard prompt"); - goto cleanup; - } - if(s < session->userauth_kybd_data + - session->userauth_kybd_data_len) { - /* boolean echo[1] */ - session->userauth_kybd_prompts[i].echo = *s++; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "userauth keyboard data buffer too " - "small for auth keyboard prompt echo"); - goto cleanup; - } - } - } - - response_callback(session->userauth_kybd_auth_name, - session->userauth_kybd_auth_name_len, - session->userauth_kybd_auth_instruction, - session->userauth_kybd_auth_instruction_len, - session->userauth_kybd_num_prompts, - session->userauth_kybd_prompts, - session->userauth_kybd_responses, - &session->abstract); - - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Keyboard-interactive response callback function" - " invoked"); - - session->userauth_kybd_packet_len = - 1 /* byte SSH_MSG_USERAUTH_INFO_RESPONSE */ - + 4 /* int num-responses */ - ; - - for(i = 0; i < session->userauth_kybd_num_prompts; i++) { - /* string response[1] (ISO-10646 UTF-8) */ - if(session->userauth_kybd_responses[i].length <= - (SIZE_MAX - 4 - session->userauth_kybd_packet_len) ) { - session->userauth_kybd_packet_len += - 4 + session->userauth_kybd_responses[i].length; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for keyboard-" - "interactive response packet"); - goto cleanup; - } - } - - /* A new userauth_kybd_data area is to be allocated, free the - former one. */ - LIBSSH2_FREE(session, session->userauth_kybd_data); - - session->userauth_kybd_data = s = - LIBSSH2_ALLOC(session, session->userauth_kybd_packet_len); - if(!s) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for keyboard-" - "interactive response packet"); - goto cleanup; - } - - *s = SSH_MSG_USERAUTH_INFO_RESPONSE; - s++; - _libssh2_store_u32(&s, session->userauth_kybd_num_prompts); - - for(i = 0; i < session->userauth_kybd_num_prompts; i++) { - _libssh2_store_str(&s, - session->userauth_kybd_responses[i].text, - session->userauth_kybd_responses[i].length); - } - - session->userauth_kybd_state = libssh2_NB_state_sent1; - } - - if(session->userauth_kybd_state == libssh2_NB_state_sent1) { - rc = _libssh2_transport_send(session, session->userauth_kybd_data, - session->userauth_kybd_packet_len, - NULL, 0); - if(rc == LIBSSH2_ERROR_EAGAIN) - return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, - "Would block"); - if(rc) { - _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, - "Unable to send userauth-keyboard-interactive" - " request"); - goto cleanup; - } - - session->userauth_kybd_auth_failure = 0; - } - - cleanup: - /* - * It's safe to clean all the data here, because unallocated pointers - * are filled by zeroes - */ - - LIBSSH2_FREE(session, session->userauth_kybd_data); - session->userauth_kybd_data = NULL; - - if(session->userauth_kybd_prompts) { - for(i = 0; i < session->userauth_kybd_num_prompts; i++) { - LIBSSH2_FREE(session, session->userauth_kybd_prompts[i].text); - session->userauth_kybd_prompts[i].text = NULL; - } - } - - if(session->userauth_kybd_responses) { - for(i = 0; i < session->userauth_kybd_num_prompts; i++) { - LIBSSH2_FREE(session, - session->userauth_kybd_responses[i].text); - session->userauth_kybd_responses[i].text = NULL; - } - } - - if(session->userauth_kybd_prompts) { - LIBSSH2_FREE(session, session->userauth_kybd_prompts); - session->userauth_kybd_prompts = NULL; - } - if(session->userauth_kybd_responses) { - LIBSSH2_FREE(session, session->userauth_kybd_responses); - session->userauth_kybd_responses = NULL; - } - if(session->userauth_kybd_auth_name) { - LIBSSH2_FREE(session, session->userauth_kybd_auth_name); - session->userauth_kybd_auth_name = NULL; - } - if(session->userauth_kybd_auth_instruction) { - LIBSSH2_FREE(session, session->userauth_kybd_auth_instruction); - session->userauth_kybd_auth_instruction = NULL; - } - - if(session->userauth_kybd_auth_failure) { - session->userauth_kybd_state = libssh2_NB_state_idle; - return -1; - } - - session->userauth_kybd_state = libssh2_NB_state_sent; - } -} - -/* - * libssh2_userauth_keyboard_interactive_ex - * - * Authenticate using a challenge-response authentication - */ -LIBSSH2_API int -libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION *session, - const char *user, - unsigned int user_len, - LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC - ((*response_callback))) -{ - int rc; - BLOCK_ADJUST(rc, session, - userauth_keyboard_interactive(session, user, user_len, - response_callback)); - return rc; -} diff --git a/libssh2/version.c b/libssh2/version.c deleted file mode 100644 index 408f83a..0000000 --- a/libssh2/version.c +++ /dev/null @@ -1,54 +0,0 @@ -/* Copyright (C) 2009 Daniel Stenberg. All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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 "libssh2_priv.h" - -/* - libssh2_version() can be used like this: - - if (!libssh2_version(LIBSSH2_VERSION_NUM)) { - fprintf (stderr, "Runtime libssh2 version too old!\n"); - exit(1); - } -*/ -LIBSSH2_API -const char *libssh2_version(int req_version_num) -{ - if(req_version_num <= LIBSSH2_VERSION_NUM) - return LIBSSH2_VERSION; - return NULL; /* this is not a suitable library! */ -} diff --git a/libssh2/wincng.c b/libssh2/wincng.c deleted file mode 100644 index 04a4f81..0000000 --- a/libssh2/wincng.c +++ /dev/null @@ -1,2166 +0,0 @@ -/* - * Copyright (C) 2013-2015 Marc Hoersken - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 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. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "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 COPYRIGHT OWNER OR - * CONTRIBUTORS 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 "libssh2_priv.h" - -#ifdef LIBSSH2_WINCNG /* compile only if we build with wincng */ - -/* required for cross-compilation against the w64 mingw-runtime package */ -#if defined(_WIN32_WINNT) && (_WIN32_WINNT < 0x0600) -#undef _WIN32_WINNT -#endif -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0600 -#endif - -/* specify the required libraries for dependencies using MSVC */ -#ifdef _MSC_VER -#pragma comment(lib, "bcrypt.lib") -#ifdef HAVE_LIBCRYPT32 -#pragma comment(lib, "crypt32.lib") -#endif -#endif - -#include -#include -#include -#include "misc.h" - -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef HAVE_LIBCRYPT32 -#include -#endif - -#define PEM_RSA_HEADER "-----BEGIN RSA PRIVATE KEY-----" -#define PEM_RSA_FOOTER "-----END RSA PRIVATE KEY-----" -#define PEM_DSA_HEADER "-----BEGIN DSA PRIVATE KEY-----" -#define PEM_DSA_FOOTER "-----END DSA PRIVATE KEY-----" - - -/*******************************************************************/ -/* - * Windows CNG backend: Missing definitions (for MinGW[-w64]) - */ -#ifndef BCRYPT_SUCCESS -#define BCRYPT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) -#endif - -#ifndef BCRYPT_RNG_ALGORITHM -#define BCRYPT_RNG_ALGORITHM L"RNG" -#endif - -#ifndef BCRYPT_MD5_ALGORITHM -#define BCRYPT_MD5_ALGORITHM L"MD5" -#endif - -#ifndef BCRYPT_SHA1_ALGORITHM -#define BCRYPT_SHA1_ALGORITHM L"SHA1" -#endif - -#ifndef BCRYPT_SHA256_ALGORITHM -#define BCRYPT_SHA256_ALGORITHM L"SHA256" -#endif - -#ifndef BCRYPT_SHA512_ALGORITHM -#define BCRYPT_SHA512_ALGORITHM L"SHA512" -#endif - -#ifndef BCRYPT_RSA_ALGORITHM -#define BCRYPT_RSA_ALGORITHM L"RSA" -#endif - -#ifndef BCRYPT_DSA_ALGORITHM -#define BCRYPT_DSA_ALGORITHM L"DSA" -#endif - -#ifndef BCRYPT_AES_ALGORITHM -#define BCRYPT_AES_ALGORITHM L"AES" -#endif - -#ifndef BCRYPT_RC4_ALGORITHM -#define BCRYPT_RC4_ALGORITHM L"RC4" -#endif - -#ifndef BCRYPT_3DES_ALGORITHM -#define BCRYPT_3DES_ALGORITHM L"3DES" -#endif - -#ifndef BCRYPT_ALG_HANDLE_HMAC_FLAG -#define BCRYPT_ALG_HANDLE_HMAC_FLAG 0x00000008 -#endif - -#ifndef BCRYPT_DSA_PUBLIC_BLOB -#define BCRYPT_DSA_PUBLIC_BLOB L"DSAPUBLICBLOB" -#endif - -#ifndef BCRYPT_DSA_PUBLIC_MAGIC -#define BCRYPT_DSA_PUBLIC_MAGIC 0x42505344 /* DSPB */ -#endif - -#ifndef BCRYPT_DSA_PRIVATE_BLOB -#define BCRYPT_DSA_PRIVATE_BLOB L"DSAPRIVATEBLOB" -#endif - -#ifndef BCRYPT_DSA_PRIVATE_MAGIC -#define BCRYPT_DSA_PRIVATE_MAGIC 0x56505344 /* DSPV */ -#endif - -#ifndef BCRYPT_RSAPUBLIC_BLOB -#define BCRYPT_RSAPUBLIC_BLOB L"RSAPUBLICBLOB" -#endif - -#ifndef BCRYPT_RSAPUBLIC_MAGIC -#define BCRYPT_RSAPUBLIC_MAGIC 0x31415352 /* RSA1 */ -#endif - -#ifndef BCRYPT_RSAFULLPRIVATE_BLOB -#define BCRYPT_RSAFULLPRIVATE_BLOB L"RSAFULLPRIVATEBLOB" -#endif - -#ifndef BCRYPT_RSAFULLPRIVATE_MAGIC -#define BCRYPT_RSAFULLPRIVATE_MAGIC 0x33415352 /* RSA3 */ -#endif - -#ifndef BCRYPT_KEY_DATA_BLOB -#define BCRYPT_KEY_DATA_BLOB L"KeyDataBlob" -#endif - -#ifndef BCRYPT_MESSAGE_BLOCK_LENGTH -#define BCRYPT_MESSAGE_BLOCK_LENGTH L"MessageBlockLength" -#endif - -#ifndef BCRYPT_NO_KEY_VALIDATION -#define BCRYPT_NO_KEY_VALIDATION 0x00000008 -#endif - -#ifndef BCRYPT_BLOCK_PADDING -#define BCRYPT_BLOCK_PADDING 0x00000001 -#endif - -#ifndef BCRYPT_PAD_NONE -#define BCRYPT_PAD_NONE 0x00000001 -#endif - -#ifndef BCRYPT_PAD_PKCS1 -#define BCRYPT_PAD_PKCS1 0x00000002 -#endif - -#ifndef BCRYPT_PAD_OAEP -#define BCRYPT_PAD_OAEP 0x00000004 -#endif - -#ifndef BCRYPT_PAD_PSS -#define BCRYPT_PAD_PSS 0x00000008 -#endif - -#ifndef CRYPT_STRING_ANY -#define CRYPT_STRING_ANY 0x00000007 -#endif - -#ifndef LEGACY_RSAPRIVATE_BLOB -#define LEGACY_RSAPRIVATE_BLOB L"CAPIPRIVATEBLOB" -#endif - -#ifndef PKCS_RSA_PRIVATE_KEY -#define PKCS_RSA_PRIVATE_KEY (LPCSTR)43 -#endif - - -/*******************************************************************/ -/* - * Windows CNG backend: Generic functions - */ - -struct _libssh2_wincng_ctx _libssh2_wincng; - -void -_libssh2_wincng_init(void) -{ - int ret; - - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgRNG, - BCRYPT_RNG_ALGORITHM, NULL, 0); - - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashMD5, - BCRYPT_MD5_ALGORITHM, NULL, 0); - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashSHA1, - BCRYPT_SHA1_ALGORITHM, NULL, 0); - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashSHA256, - BCRYPT_SHA256_ALGORITHM, NULL, 0); - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashSHA512, - BCRYPT_SHA512_ALGORITHM, NULL, 0); - - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacMD5, - BCRYPT_MD5_ALGORITHM, NULL, - BCRYPT_ALG_HANDLE_HMAC_FLAG); - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacSHA1, - BCRYPT_SHA1_ALGORITHM, NULL, - BCRYPT_ALG_HANDLE_HMAC_FLAG); - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacSHA256, - BCRYPT_SHA256_ALGORITHM, NULL, - BCRYPT_ALG_HANDLE_HMAC_FLAG); - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacSHA512, - BCRYPT_SHA512_ALGORITHM, NULL, - BCRYPT_ALG_HANDLE_HMAC_FLAG); - - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgRSA, - BCRYPT_RSA_ALGORITHM, NULL, 0); - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgDSA, - BCRYPT_DSA_ALGORITHM, NULL, 0); - - ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgAES_CBC, - BCRYPT_AES_ALGORITHM, NULL, 0); - if(BCRYPT_SUCCESS(ret)) { - ret = BCryptSetProperty(_libssh2_wincng.hAlgAES_CBC, - BCRYPT_CHAINING_MODE, - (PBYTE)BCRYPT_CHAIN_MODE_CBC, - sizeof(BCRYPT_CHAIN_MODE_CBC), 0); - if(!BCRYPT_SUCCESS(ret)) { - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgAES_CBC, 0); - } - } - - ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgAES_ECB, - BCRYPT_AES_ALGORITHM, NULL, 0); - if(BCRYPT_SUCCESS(ret)) { - ret = BCryptSetProperty(_libssh2_wincng.hAlgAES_ECB, - BCRYPT_CHAINING_MODE, - (PBYTE)BCRYPT_CHAIN_MODE_ECB, - sizeof(BCRYPT_CHAIN_MODE_ECB), 0); - if(!BCRYPT_SUCCESS(ret)) { - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgAES_ECB, 0); - } - } - - ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgRC4_NA, - BCRYPT_RC4_ALGORITHM, NULL, 0); - if(BCRYPT_SUCCESS(ret)) { - ret = BCryptSetProperty(_libssh2_wincng.hAlgRC4_NA, - BCRYPT_CHAINING_MODE, - (PBYTE)BCRYPT_CHAIN_MODE_NA, - sizeof(BCRYPT_CHAIN_MODE_NA), 0); - if(!BCRYPT_SUCCESS(ret)) { - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgRC4_NA, 0); - } - } - - ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlg3DES_CBC, - BCRYPT_3DES_ALGORITHM, NULL, 0); - if(BCRYPT_SUCCESS(ret)) { - ret = BCryptSetProperty(_libssh2_wincng.hAlg3DES_CBC, - BCRYPT_CHAINING_MODE, - (PBYTE)BCRYPT_CHAIN_MODE_CBC, - sizeof(BCRYPT_CHAIN_MODE_CBC), 0); - if(!BCRYPT_SUCCESS(ret)) { - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlg3DES_CBC, - 0); - } - } -} - -void -_libssh2_wincng_free(void) -{ - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgRNG, 0); - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHashMD5, 0); - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHashSHA1, 0); - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHashSHA256, 0); - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHashSHA512, 0); - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHmacMD5, 0); - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHmacSHA1, 0); - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHmacSHA256, 0); - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHmacSHA512, 0); - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgRSA, 0); - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgDSA, 0); - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgAES_CBC, 0); - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgRC4_NA, 0); - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlg3DES_CBC, 0); - - memset(&_libssh2_wincng, 0, sizeof(_libssh2_wincng)); -} - -int -_libssh2_wincng_random(void *buf, int len) -{ - int ret; - - ret = BCryptGenRandom(_libssh2_wincng.hAlgRNG, buf, len, 0); - - return BCRYPT_SUCCESS(ret) ? 0 : -1; -} - -static void -_libssh2_wincng_safe_free(void *buf, int len) -{ -#ifndef LIBSSH2_CLEAR_MEMORY - (void)len; -#endif - - if(!buf) - return; - -#ifdef LIBSSH2_CLEAR_MEMORY - if(len > 0) - SecureZeroMemory(buf, len); -#endif - - free(buf); -} - - -/*******************************************************************/ -/* - * Windows CNG backend: Hash functions - */ - -int -_libssh2_wincng_hash_init(_libssh2_wincng_hash_ctx *ctx, - BCRYPT_ALG_HANDLE hAlg, unsigned long hashlen, - unsigned char *key, unsigned long keylen) -{ - BCRYPT_HASH_HANDLE hHash; - unsigned char *pbHashObject; - unsigned long dwHashObject, dwHash, cbData; - int ret; - - ret = BCryptGetProperty(hAlg, BCRYPT_HASH_LENGTH, - (unsigned char *)&dwHash, - sizeof(dwHash), - &cbData, 0); - if((!BCRYPT_SUCCESS(ret)) || dwHash != hashlen) { - return -1; - } - - ret = BCryptGetProperty(hAlg, BCRYPT_OBJECT_LENGTH, - (unsigned char *)&dwHashObject, - sizeof(dwHashObject), - &cbData, 0); - if(!BCRYPT_SUCCESS(ret)) { - return -1; - } - - pbHashObject = malloc(dwHashObject); - if(!pbHashObject) { - return -1; - } - - - ret = BCryptCreateHash(hAlg, &hHash, - pbHashObject, dwHashObject, - key, keylen, 0); - if(!BCRYPT_SUCCESS(ret)) { - _libssh2_wincng_safe_free(pbHashObject, dwHashObject); - return -1; - } - - - ctx->hHash = hHash; - ctx->pbHashObject = pbHashObject; - ctx->dwHashObject = dwHashObject; - ctx->cbHash = dwHash; - - return 0; -} - -int -_libssh2_wincng_hash_update(_libssh2_wincng_hash_ctx *ctx, - const unsigned char *data, unsigned long datalen) -{ - int ret; - - ret = BCryptHashData(ctx->hHash, (unsigned char *)data, datalen, 0); - - return BCRYPT_SUCCESS(ret) ? 0 : -1; -} - -int -_libssh2_wincng_hash_final(_libssh2_wincng_hash_ctx *ctx, - unsigned char *hash) -{ - int ret; - - ret = BCryptFinishHash(ctx->hHash, hash, ctx->cbHash, 0); - - BCryptDestroyHash(ctx->hHash); - ctx->hHash = NULL; - - _libssh2_wincng_safe_free(ctx->pbHashObject, ctx->dwHashObject); - ctx->pbHashObject = NULL; - ctx->dwHashObject = 0; - - return BCRYPT_SUCCESS(ret) ? 0 : -1; -} - -int -_libssh2_wincng_hash(unsigned char *data, unsigned long datalen, - BCRYPT_ALG_HANDLE hAlg, - unsigned char *hash, unsigned long hashlen) -{ - _libssh2_wincng_hash_ctx ctx; - int ret; - - ret = _libssh2_wincng_hash_init(&ctx, hAlg, hashlen, NULL, 0); - if(!ret) { - ret = _libssh2_wincng_hash_update(&ctx, data, datalen); - ret |= _libssh2_wincng_hash_final(&ctx, hash); - } - - return ret; -} - - -/*******************************************************************/ -/* - * Windows CNG backend: HMAC functions - */ - -int -_libssh2_wincng_hmac_final(_libssh2_wincng_hash_ctx *ctx, - unsigned char *hash) -{ - int ret; - - ret = BCryptFinishHash(ctx->hHash, hash, ctx->cbHash, 0); - - return BCRYPT_SUCCESS(ret) ? 0 : -1; -} - -void -_libssh2_wincng_hmac_cleanup(_libssh2_wincng_hash_ctx *ctx) -{ - BCryptDestroyHash(ctx->hHash); - ctx->hHash = NULL; - - _libssh2_wincng_safe_free(ctx->pbHashObject, ctx->dwHashObject); - ctx->pbHashObject = NULL; - ctx->dwHashObject = 0; -} - - -/*******************************************************************/ -/* - * Windows CNG backend: Key functions - */ - -int -_libssh2_wincng_key_sha1_verify(_libssh2_wincng_key_ctx *ctx, - const unsigned char *sig, - unsigned long sig_len, - const unsigned char *m, - unsigned long m_len, - unsigned long flags) -{ - BCRYPT_PKCS1_PADDING_INFO paddingInfoPKCS1; - void *pPaddingInfo; - unsigned char *data, *hash; - unsigned long datalen, hashlen; - int ret; - - datalen = m_len; - data = malloc(datalen); - if(!data) { - return -1; - } - - hashlen = SHA_DIGEST_LENGTH; - hash = malloc(hashlen); - if(!hash) { - free(data); - return -1; - } - - memcpy(data, m, datalen); - - ret = _libssh2_wincng_hash(data, datalen, - _libssh2_wincng.hAlgHashSHA1, - hash, hashlen); - - _libssh2_wincng_safe_free(data, datalen); - - if(ret) { - _libssh2_wincng_safe_free(hash, hashlen); - return -1; - } - - datalen = sig_len; - data = malloc(datalen); - if(!data) { - _libssh2_wincng_safe_free(hash, hashlen); - return -1; - } - - if(flags & BCRYPT_PAD_PKCS1) { - paddingInfoPKCS1.pszAlgId = BCRYPT_SHA1_ALGORITHM; - pPaddingInfo = &paddingInfoPKCS1; - } - else - pPaddingInfo = NULL; - - memcpy(data, sig, datalen); - - ret = BCryptVerifySignature(ctx->hKey, pPaddingInfo, - hash, hashlen, data, datalen, flags); - - _libssh2_wincng_safe_free(hash, hashlen); - _libssh2_wincng_safe_free(data, datalen); - - return BCRYPT_SUCCESS(ret) ? 0 : -1; -} - -#ifdef HAVE_LIBCRYPT32 -static int -_libssh2_wincng_load_pem(LIBSSH2_SESSION *session, - const char *filename, - const char *passphrase, - const char *headerbegin, - const char *headerend, - unsigned char **data, - unsigned int *datalen) -{ - FILE *fp; - int ret; - - fp = fopen(filename, FOPEN_READTEXT); - if(!fp) { - return -1; - } - - ret = _libssh2_pem_parse(session, headerbegin, headerend, - passphrase, - fp, data, datalen); - - fclose(fp); - - return ret; -} - -static int -_libssh2_wincng_load_private(LIBSSH2_SESSION *session, - const char *filename, - const char *passphrase, - unsigned char **ppbEncoded, - unsigned long *pcbEncoded, - int tryLoadRSA, int tryLoadDSA) -{ - unsigned char *data = NULL; - unsigned int datalen = 0; - int ret = -1; - - if(ret && tryLoadRSA) { - ret = _libssh2_wincng_load_pem(session, filename, passphrase, - PEM_RSA_HEADER, PEM_RSA_FOOTER, - &data, &datalen); - } - - if(ret && tryLoadDSA) { - ret = _libssh2_wincng_load_pem(session, filename, passphrase, - PEM_DSA_HEADER, PEM_DSA_FOOTER, - &data, &datalen); - } - - if(!ret) { - *ppbEncoded = data; - *pcbEncoded = datalen; - } - - return ret; -} - -static int -_libssh2_wincng_load_private_memory(LIBSSH2_SESSION *session, - const char *privatekeydata, - size_t privatekeydata_len, - const char *passphrase, - unsigned char **ppbEncoded, - unsigned long *pcbEncoded, - int tryLoadRSA, int tryLoadDSA) -{ - unsigned char *data = NULL; - unsigned int datalen = 0; - int ret = -1; - - (void)passphrase; - - if(ret && tryLoadRSA) { - ret = _libssh2_pem_parse_memory(session, - PEM_RSA_HEADER, PEM_RSA_FOOTER, - privatekeydata, privatekeydata_len, - &data, &datalen); - } - - if(ret && tryLoadDSA) { - ret = _libssh2_pem_parse_memory(session, - PEM_DSA_HEADER, PEM_DSA_FOOTER, - privatekeydata, privatekeydata_len, - &data, &datalen); - } - - if(!ret) { - *ppbEncoded = data; - *pcbEncoded = datalen; - } - - return ret; -} - -static int -_libssh2_wincng_asn_decode(unsigned char *pbEncoded, - unsigned long cbEncoded, - LPCSTR lpszStructType, - unsigned char **ppbDecoded, - unsigned long *pcbDecoded) -{ - unsigned char *pbDecoded = NULL; - unsigned long cbDecoded = 0; - int ret; - - ret = CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, - lpszStructType, - pbEncoded, cbEncoded, 0, NULL, - NULL, &cbDecoded); - if(!ret) { - return -1; - } - - pbDecoded = malloc(cbDecoded); - if(!pbDecoded) { - return -1; - } - - ret = CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, - lpszStructType, - pbEncoded, cbEncoded, 0, NULL, - pbDecoded, &cbDecoded); - if(!ret) { - _libssh2_wincng_safe_free(pbDecoded, cbDecoded); - return -1; - } - - - *ppbDecoded = pbDecoded; - *pcbDecoded = cbDecoded; - - return 0; -} - -static int -_libssh2_wincng_bn_ltob(unsigned char *pbInput, - unsigned long cbInput, - unsigned char **ppbOutput, - unsigned long *pcbOutput) -{ - unsigned char *pbOutput; - unsigned long cbOutput, index, offset, length; - - if(cbInput < 1) { - return 0; - } - - offset = 0; - length = cbInput - 1; - cbOutput = cbInput; - if(pbInput[length] & (1 << 7)) { - offset++; - cbOutput += offset; - } - - pbOutput = (unsigned char *)malloc(cbOutput); - if(!pbOutput) { - return -1; - } - - pbOutput[0] = 0; - for(index = 0; ((index + offset) < cbOutput) - && (index < cbInput); index++) { - pbOutput[index + offset] = pbInput[length - index]; - } - - - *ppbOutput = pbOutput; - *pcbOutput = cbOutput; - - return 0; -} - -static int -_libssh2_wincng_asn_decode_bn(unsigned char *pbEncoded, - unsigned long cbEncoded, - unsigned char **ppbDecoded, - unsigned long *pcbDecoded) -{ - unsigned char *pbDecoded = NULL, *pbInteger; - unsigned long cbDecoded = 0, cbInteger; - int ret; - - ret = _libssh2_wincng_asn_decode(pbEncoded, cbEncoded, - X509_MULTI_BYTE_UINT, - &pbInteger, &cbInteger); - if(!ret) { - ret = _libssh2_wincng_bn_ltob(((PCRYPT_DATA_BLOB)pbInteger)->pbData, - ((PCRYPT_DATA_BLOB)pbInteger)->cbData, - &pbDecoded, &cbDecoded); - if(!ret) { - *ppbDecoded = pbDecoded; - *pcbDecoded = cbDecoded; - } - _libssh2_wincng_safe_free(pbInteger, cbInteger); - } - - return ret; -} - -static int -_libssh2_wincng_asn_decode_bns(unsigned char *pbEncoded, - unsigned long cbEncoded, - unsigned char ***prpbDecoded, - unsigned long **prcbDecoded, - unsigned long *pcbCount) -{ - PCRYPT_DER_BLOB pBlob; - unsigned char *pbDecoded, **rpbDecoded; - unsigned long cbDecoded, *rcbDecoded, index, length; - int ret; - - ret = _libssh2_wincng_asn_decode(pbEncoded, cbEncoded, - X509_SEQUENCE_OF_ANY, - &pbDecoded, &cbDecoded); - if(!ret) { - length = ((PCRYPT_DATA_BLOB)pbDecoded)->cbData; - - rpbDecoded = malloc(sizeof(PBYTE) * length); - if(rpbDecoded) { - rcbDecoded = malloc(sizeof(DWORD) * length); - if(rcbDecoded) { - for(index = 0; index < length; index++) { - pBlob = &((PCRYPT_DER_BLOB) - ((PCRYPT_DATA_BLOB)pbDecoded)->pbData)[index]; - ret = _libssh2_wincng_asn_decode_bn(pBlob->pbData, - pBlob->cbData, - &rpbDecoded[index], - &rcbDecoded[index]); - if(ret) - break; - } - - if(!ret) { - *prpbDecoded = rpbDecoded; - *prcbDecoded = rcbDecoded; - *pcbCount = length; - } - else { - for(length = 0; length < index; length++) { - _libssh2_wincng_safe_free(rpbDecoded[length], - rcbDecoded[length]); - rpbDecoded[length] = NULL; - rcbDecoded[length] = 0; - } - free(rpbDecoded); - free(rcbDecoded); - } - } - else { - free(rpbDecoded); - ret = -1; - } - } - else { - ret = -1; - } - - _libssh2_wincng_safe_free(pbDecoded, cbDecoded); - } - - return ret; -} -#endif /* HAVE_LIBCRYPT32 */ - -static unsigned long -_libssh2_wincng_bn_size(const unsigned char *bignum, - unsigned long length) -{ - unsigned long offset; - - if(!bignum) - return 0; - - length--; - - offset = 0; - while(!(*(bignum + offset)) && (offset < length)) - offset++; - - length++; - - return length - offset; -} - - -/*******************************************************************/ -/* - * Windows CNG backend: RSA functions - */ - -int -_libssh2_wincng_rsa_new(libssh2_rsa_ctx **rsa, - const unsigned char *edata, - unsigned long elen, - const unsigned char *ndata, - unsigned long nlen, - const unsigned char *ddata, - unsigned long dlen, - const unsigned char *pdata, - unsigned long plen, - const unsigned char *qdata, - unsigned long qlen, - const unsigned char *e1data, - unsigned long e1len, - const unsigned char *e2data, - unsigned long e2len, - const unsigned char *coeffdata, - unsigned long coefflen) -{ - BCRYPT_KEY_HANDLE hKey; - BCRYPT_RSAKEY_BLOB *rsakey; - LPCWSTR lpszBlobType; - unsigned char *key; - unsigned long keylen, offset, mlen, p1len = 0, p2len = 0; - int ret; - - mlen = max(_libssh2_wincng_bn_size(ndata, nlen), - _libssh2_wincng_bn_size(ddata, dlen)); - offset = sizeof(BCRYPT_RSAKEY_BLOB); - keylen = offset + elen + mlen; - if(ddata && dlen > 0) { - p1len = max(_libssh2_wincng_bn_size(pdata, plen), - _libssh2_wincng_bn_size(e1data, e1len)); - p2len = max(_libssh2_wincng_bn_size(qdata, qlen), - _libssh2_wincng_bn_size(e2data, e2len)); - keylen += p1len * 3 + p2len * 2 + mlen; - } - - key = malloc(keylen); - if(!key) { - return -1; - } - - memset(key, 0, keylen); - - - /* https://msdn.microsoft.com/library/windows/desktop/aa375531.aspx */ - rsakey = (BCRYPT_RSAKEY_BLOB *)key; - rsakey->BitLength = mlen * 8; - rsakey->cbPublicExp = elen; - rsakey->cbModulus = mlen; - - memcpy(key + offset, edata, elen); - offset += elen; - - if(nlen < mlen) - memcpy(key + offset + mlen - nlen, ndata, nlen); - else - memcpy(key + offset, ndata + nlen - mlen, mlen); - - if(ddata && dlen > 0) { - offset += mlen; - - if(plen < p1len) - memcpy(key + offset + p1len - plen, pdata, plen); - else - memcpy(key + offset, pdata + plen - p1len, p1len); - offset += p1len; - - if(qlen < p2len) - memcpy(key + offset + p2len - qlen, qdata, qlen); - else - memcpy(key + offset, qdata + qlen - p2len, p2len); - offset += p2len; - - if(e1len < p1len) - memcpy(key + offset + p1len - e1len, e1data, e1len); - else - memcpy(key + offset, e1data + e1len - p1len, p1len); - offset += p1len; - - if(e2len < p2len) - memcpy(key + offset + p2len - e2len, e2data, e2len); - else - memcpy(key + offset, e2data + e2len - p2len, p2len); - offset += p2len; - - if(coefflen < p1len) - memcpy(key + offset + p1len - coefflen, coeffdata, coefflen); - else - memcpy(key + offset, coeffdata + coefflen - p1len, p1len); - offset += p1len; - - if(dlen < mlen) - memcpy(key + offset + mlen - dlen, ddata, dlen); - else - memcpy(key + offset, ddata + dlen - mlen, mlen); - - lpszBlobType = BCRYPT_RSAFULLPRIVATE_BLOB; - rsakey->Magic = BCRYPT_RSAFULLPRIVATE_MAGIC; - rsakey->cbPrime1 = p1len; - rsakey->cbPrime2 = p2len; - } - else { - lpszBlobType = BCRYPT_RSAPUBLIC_BLOB; - rsakey->Magic = BCRYPT_RSAPUBLIC_MAGIC; - rsakey->cbPrime1 = 0; - rsakey->cbPrime2 = 0; - } - - - ret = BCryptImportKeyPair(_libssh2_wincng.hAlgRSA, NULL, lpszBlobType, - &hKey, key, keylen, 0); - if(!BCRYPT_SUCCESS(ret)) { - _libssh2_wincng_safe_free(key, keylen); - return -1; - } - - - *rsa = malloc(sizeof(libssh2_rsa_ctx)); - if(!(*rsa)) { - BCryptDestroyKey(hKey); - _libssh2_wincng_safe_free(key, keylen); - return -1; - } - - (*rsa)->hKey = hKey; - (*rsa)->pbKeyObject = key; - (*rsa)->cbKeyObject = keylen; - - return 0; -} - -#ifdef HAVE_LIBCRYPT32 -static int -_libssh2_wincng_rsa_new_private_parse(libssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - unsigned char *pbEncoded, - unsigned long cbEncoded) -{ - BCRYPT_KEY_HANDLE hKey; - unsigned char *pbStructInfo; - unsigned long cbStructInfo; - int ret; - - (void)session; - - ret = _libssh2_wincng_asn_decode(pbEncoded, cbEncoded, - PKCS_RSA_PRIVATE_KEY, - &pbStructInfo, &cbStructInfo); - - _libssh2_wincng_safe_free(pbEncoded, cbEncoded); - - if(ret) { - return -1; - } - - - ret = BCryptImportKeyPair(_libssh2_wincng.hAlgRSA, NULL, - LEGACY_RSAPRIVATE_BLOB, &hKey, - pbStructInfo, cbStructInfo, 0); - if(!BCRYPT_SUCCESS(ret)) { - _libssh2_wincng_safe_free(pbStructInfo, cbStructInfo); - return -1; - } - - - *rsa = malloc(sizeof(libssh2_rsa_ctx)); - if(!(*rsa)) { - BCryptDestroyKey(hKey); - _libssh2_wincng_safe_free(pbStructInfo, cbStructInfo); - return -1; - } - - (*rsa)->hKey = hKey; - (*rsa)->pbKeyObject = pbStructInfo; - (*rsa)->cbKeyObject = cbStructInfo; - - return 0; -} -#endif /* HAVE_LIBCRYPT32 */ - -int -_libssh2_wincng_rsa_new_private(libssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - const char *filename, - const unsigned char *passphrase) -{ -#ifdef HAVE_LIBCRYPT32 - unsigned char *pbEncoded; - unsigned long cbEncoded; - int ret; - - (void)session; - - ret = _libssh2_wincng_load_private(session, filename, - (const char *)passphrase, - &pbEncoded, &cbEncoded, 1, 0); - if(ret) { - return -1; - } - - return _libssh2_wincng_rsa_new_private_parse(rsa, session, - pbEncoded, cbEncoded); -#else - (void)rsa; - (void)filename; - (void)passphrase; - - return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Unable to load RSA key from private key file: " - "Method unsupported in Windows CNG backend"); -#endif /* HAVE_LIBCRYPT32 */ -} - -int -_libssh2_wincng_rsa_new_private_frommemory(libssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - const char *filedata, - size_t filedata_len, - unsigned const char *passphrase) -{ -#ifdef HAVE_LIBCRYPT32 - unsigned char *pbEncoded; - unsigned long cbEncoded; - int ret; - - (void)session; - - ret = _libssh2_wincng_load_private_memory(session, filedata, filedata_len, - (const char *)passphrase, - &pbEncoded, &cbEncoded, 1, 0); - if(ret) { - return -1; - } - - return _libssh2_wincng_rsa_new_private_parse(rsa, session, - pbEncoded, cbEncoded); -#else - (void)rsa; - (void)filedata; - (void)filedata_len; - (void)passphrase; - - return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Unable to extract private key from memory: " - "Method unsupported in Windows CNG backend"); -#endif /* HAVE_LIBCRYPT32 */ -} - -int -_libssh2_wincng_rsa_sha1_verify(libssh2_rsa_ctx *rsa, - const unsigned char *sig, - unsigned long sig_len, - const unsigned char *m, - unsigned long m_len) -{ - return _libssh2_wincng_key_sha1_verify(rsa, sig, sig_len, m, m_len, - BCRYPT_PAD_PKCS1); -} - -int -_libssh2_wincng_rsa_sha1_sign(LIBSSH2_SESSION *session, - libssh2_rsa_ctx *rsa, - const unsigned char *hash, - size_t hash_len, - unsigned char **signature, - size_t *signature_len) -{ - BCRYPT_PKCS1_PADDING_INFO paddingInfo; - unsigned char *data, *sig; - unsigned long cbData, datalen, siglen; - int ret; - - datalen = (unsigned long)hash_len; - data = malloc(datalen); - if(!data) { - return -1; - } - - paddingInfo.pszAlgId = BCRYPT_SHA1_ALGORITHM; - - memcpy(data, hash, datalen); - - ret = BCryptSignHash(rsa->hKey, &paddingInfo, - data, datalen, NULL, 0, - &cbData, BCRYPT_PAD_PKCS1); - if(BCRYPT_SUCCESS(ret)) { - siglen = cbData; - sig = LIBSSH2_ALLOC(session, siglen); - if(sig) { - ret = BCryptSignHash(rsa->hKey, &paddingInfo, - data, datalen, sig, siglen, - &cbData, BCRYPT_PAD_PKCS1); - if(BCRYPT_SUCCESS(ret)) { - *signature_len = siglen; - *signature = sig; - } - else { - LIBSSH2_FREE(session, sig); - } - } - else - ret = STATUS_NO_MEMORY; - } - - _libssh2_wincng_safe_free(data, datalen); - - return BCRYPT_SUCCESS(ret) ? 0 : -1; -} - -void -_libssh2_wincng_rsa_free(libssh2_rsa_ctx *rsa) -{ - if(!rsa) - return; - - BCryptDestroyKey(rsa->hKey); - rsa->hKey = NULL; - - _libssh2_wincng_safe_free(rsa->pbKeyObject, rsa->cbKeyObject); - _libssh2_wincng_safe_free(rsa, sizeof(libssh2_rsa_ctx)); -} - - -/*******************************************************************/ -/* - * Windows CNG backend: DSA functions - */ - -#if LIBSSH2_DSA -int -_libssh2_wincng_dsa_new(libssh2_dsa_ctx **dsa, - const unsigned char *pdata, - unsigned long plen, - const unsigned char *qdata, - unsigned long qlen, - const unsigned char *gdata, - unsigned long glen, - const unsigned char *ydata, - unsigned long ylen, - const unsigned char *xdata, - unsigned long xlen) -{ - BCRYPT_KEY_HANDLE hKey; - BCRYPT_DSA_KEY_BLOB *dsakey; - LPCWSTR lpszBlobType; - unsigned char *key; - unsigned long keylen, offset, length; - int ret; - - length = max(max(_libssh2_wincng_bn_size(pdata, plen), - _libssh2_wincng_bn_size(gdata, glen)), - _libssh2_wincng_bn_size(ydata, ylen)); - offset = sizeof(BCRYPT_DSA_KEY_BLOB); - keylen = offset + length * 3; - if(xdata && xlen > 0) - keylen += 20; - - key = malloc(keylen); - if(!key) { - return -1; - } - - memset(key, 0, keylen); - - - /* https://msdn.microsoft.com/library/windows/desktop/aa833126.aspx */ - dsakey = (BCRYPT_DSA_KEY_BLOB *)key; - dsakey->cbKey = length; - - memset(dsakey->Count, -1, sizeof(dsakey->Count)); - memset(dsakey->Seed, -1, sizeof(dsakey->Seed)); - - if(qlen < 20) - memcpy(dsakey->q + 20 - qlen, qdata, qlen); - else - memcpy(dsakey->q, qdata + qlen - 20, 20); - - if(plen < length) - memcpy(key + offset + length - plen, pdata, plen); - else - memcpy(key + offset, pdata + plen - length, length); - offset += length; - - if(glen < length) - memcpy(key + offset + length - glen, gdata, glen); - else - memcpy(key + offset, gdata + glen - length, length); - offset += length; - - if(ylen < length) - memcpy(key + offset + length - ylen, ydata, ylen); - else - memcpy(key + offset, ydata + ylen - length, length); - - if(xdata && xlen > 0) { - offset += length; - - if(xlen < 20) - memcpy(key + offset + 20 - xlen, xdata, xlen); - else - memcpy(key + offset, xdata + xlen - 20, 20); - - lpszBlobType = BCRYPT_DSA_PRIVATE_BLOB; - dsakey->dwMagic = BCRYPT_DSA_PRIVATE_MAGIC; - } - else { - lpszBlobType = BCRYPT_DSA_PUBLIC_BLOB; - dsakey->dwMagic = BCRYPT_DSA_PUBLIC_MAGIC; - } - - - ret = BCryptImportKeyPair(_libssh2_wincng.hAlgDSA, NULL, lpszBlobType, - &hKey, key, keylen, 0); - if(!BCRYPT_SUCCESS(ret)) { - _libssh2_wincng_safe_free(key, keylen); - return -1; - } - - - *dsa = malloc(sizeof(libssh2_dsa_ctx)); - if(!(*dsa)) { - BCryptDestroyKey(hKey); - _libssh2_wincng_safe_free(key, keylen); - return -1; - } - - (*dsa)->hKey = hKey; - (*dsa)->pbKeyObject = key; - (*dsa)->cbKeyObject = keylen; - - return 0; -} - -#ifdef HAVE_LIBCRYPT32 -static int -_libssh2_wincng_dsa_new_private_parse(libssh2_dsa_ctx **dsa, - LIBSSH2_SESSION *session, - unsigned char *pbEncoded, - unsigned long cbEncoded) -{ - unsigned char **rpbDecoded; - unsigned long *rcbDecoded, index, length; - int ret; - - (void)session; - - ret = _libssh2_wincng_asn_decode_bns(pbEncoded, cbEncoded, - &rpbDecoded, &rcbDecoded, &length); - - _libssh2_wincng_safe_free(pbEncoded, cbEncoded); - - if(ret) { - return -1; - } - - - if(length == 6) { - ret = _libssh2_wincng_dsa_new(dsa, - rpbDecoded[1], rcbDecoded[1], - rpbDecoded[2], rcbDecoded[2], - rpbDecoded[3], rcbDecoded[3], - rpbDecoded[4], rcbDecoded[4], - rpbDecoded[5], rcbDecoded[5]); - } - else { - ret = -1; - } - - for(index = 0; index < length; index++) { - _libssh2_wincng_safe_free(rpbDecoded[index], rcbDecoded[index]); - rpbDecoded[index] = NULL; - rcbDecoded[index] = 0; - } - - free(rpbDecoded); - free(rcbDecoded); - - return ret; -} -#endif /* HAVE_LIBCRYPT32 */ - -int -_libssh2_wincng_dsa_new_private(libssh2_dsa_ctx **dsa, - LIBSSH2_SESSION *session, - const char *filename, - const unsigned char *passphrase) -{ -#ifdef HAVE_LIBCRYPT32 - unsigned char *pbEncoded; - unsigned long cbEncoded; - int ret; - - ret = _libssh2_wincng_load_private(session, filename, - (const char *)passphrase, - &pbEncoded, &cbEncoded, 0, 1); - if(ret) { - return -1; - } - - return _libssh2_wincng_dsa_new_private_parse(dsa, session, - pbEncoded, cbEncoded); -#else - (void)dsa; - (void)filename; - (void)passphrase; - - return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Unable to load DSA key from private key file: " - "Method unsupported in Windows CNG backend"); -#endif /* HAVE_LIBCRYPT32 */ -} - -int -_libssh2_wincng_dsa_new_private_frommemory(libssh2_dsa_ctx **dsa, - LIBSSH2_SESSION *session, - const char *filedata, - size_t filedata_len, - unsigned const char *passphrase) -{ -#ifdef HAVE_LIBCRYPT32 - unsigned char *pbEncoded; - unsigned long cbEncoded; - int ret; - - ret = _libssh2_wincng_load_private_memory(session, filedata, filedata_len, - (const char *)passphrase, - &pbEncoded, &cbEncoded, 0, 1); - if(ret) { - return -1; - } - - return _libssh2_wincng_dsa_new_private_parse(dsa, session, - pbEncoded, cbEncoded); -#else - (void)dsa; - (void)filedata; - (void)filedata_len; - (void)passphrase; - - return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Unable to extract private key from memory: " - "Method unsupported in Windows CNG backend"); -#endif /* HAVE_LIBCRYPT32 */ -} - -int -_libssh2_wincng_dsa_sha1_verify(libssh2_dsa_ctx *dsa, - const unsigned char *sig_fixed, - const unsigned char *m, - unsigned long m_len) -{ - return _libssh2_wincng_key_sha1_verify(dsa, sig_fixed, 40, m, m_len, 0); -} - -int -_libssh2_wincng_dsa_sha1_sign(libssh2_dsa_ctx *dsa, - const unsigned char *hash, - unsigned long hash_len, - unsigned char *sig_fixed) -{ - unsigned char *data, *sig; - unsigned long cbData, datalen, siglen; - int ret; - - datalen = hash_len; - data = malloc(datalen); - if(!data) { - return -1; - } - - memcpy(data, hash, datalen); - - ret = BCryptSignHash(dsa->hKey, NULL, data, datalen, - NULL, 0, &cbData, 0); - if(BCRYPT_SUCCESS(ret)) { - siglen = cbData; - if(siglen == 40) { - sig = malloc(siglen); - if(sig) { - ret = BCryptSignHash(dsa->hKey, NULL, data, datalen, - sig, siglen, &cbData, 0); - if(BCRYPT_SUCCESS(ret)) { - memcpy(sig_fixed, sig, siglen); - } - - _libssh2_wincng_safe_free(sig, siglen); - } - else - ret = STATUS_NO_MEMORY; - } - else - ret = STATUS_NO_MEMORY; - } - - _libssh2_wincng_safe_free(data, datalen); - - return BCRYPT_SUCCESS(ret) ? 0 : -1; -} - -void -_libssh2_wincng_dsa_free(libssh2_dsa_ctx *dsa) -{ - if(!dsa) - return; - - BCryptDestroyKey(dsa->hKey); - dsa->hKey = NULL; - - _libssh2_wincng_safe_free(dsa->pbKeyObject, dsa->cbKeyObject); - _libssh2_wincng_safe_free(dsa, sizeof(libssh2_dsa_ctx)); -} -#endif - - -/*******************************************************************/ -/* - * Windows CNG backend: Key functions - */ - -#ifdef HAVE_LIBCRYPT32 -static unsigned long -_libssh2_wincng_pub_priv_write(unsigned char *key, - unsigned long offset, - const unsigned char *bignum, - const unsigned long length) -{ - _libssh2_htonu32(key + offset, length); - offset += 4; - - memcpy(key + offset, bignum, length); - offset += length; - - return offset; -} - -static int -_libssh2_wincng_pub_priv_keyfile_parse(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - unsigned char *pbEncoded, - unsigned long cbEncoded) -{ - unsigned char **rpbDecoded; - unsigned long *rcbDecoded; - unsigned char *key = NULL, *mth = NULL; - unsigned long keylen = 0, mthlen = 0; - unsigned long index, offset, length; - int ret; - - ret = _libssh2_wincng_asn_decode_bns(pbEncoded, cbEncoded, - &rpbDecoded, &rcbDecoded, &length); - - _libssh2_wincng_safe_free(pbEncoded, cbEncoded); - - if(ret) { - return -1; - } - - - if(length == 9) { /* private RSA key */ - mthlen = 7; - mth = LIBSSH2_ALLOC(session, mthlen); - if(mth) { - memcpy(mth, "ssh-rsa", mthlen); - } - else { - ret = -1; - } - - - keylen = 4 + mthlen + 4 + rcbDecoded[2] + 4 + rcbDecoded[1]; - key = LIBSSH2_ALLOC(session, keylen); - if(key) { - offset = _libssh2_wincng_pub_priv_write(key, 0, mth, mthlen); - - offset = _libssh2_wincng_pub_priv_write(key, offset, - rpbDecoded[2], - rcbDecoded[2]); - - _libssh2_wincng_pub_priv_write(key, offset, - rpbDecoded[1], - rcbDecoded[1]); - } - else { - ret = -1; - } - - } - else if(length == 6) { /* private DSA key */ - mthlen = 7; - mth = LIBSSH2_ALLOC(session, mthlen); - if(mth) { - memcpy(mth, "ssh-dss", mthlen); - } - else { - ret = -1; - } - - keylen = 4 + mthlen + 4 + rcbDecoded[1] + 4 + rcbDecoded[2] - + 4 + rcbDecoded[3] + 4 + rcbDecoded[4]; - key = LIBSSH2_ALLOC(session, keylen); - if(key) { - offset = _libssh2_wincng_pub_priv_write(key, 0, mth, mthlen); - - offset = _libssh2_wincng_pub_priv_write(key, offset, - rpbDecoded[1], - rcbDecoded[1]); - - offset = _libssh2_wincng_pub_priv_write(key, offset, - rpbDecoded[2], - rcbDecoded[2]); - - offset = _libssh2_wincng_pub_priv_write(key, offset, - rpbDecoded[3], - rcbDecoded[3]); - - _libssh2_wincng_pub_priv_write(key, offset, - rpbDecoded[4], - rcbDecoded[4]); - } - else { - ret = -1; - } - - } - else { - ret = -1; - } - - - for(index = 0; index < length; index++) { - _libssh2_wincng_safe_free(rpbDecoded[index], rcbDecoded[index]); - rpbDecoded[index] = NULL; - rcbDecoded[index] = 0; - } - - free(rpbDecoded); - free(rcbDecoded); - - - if(ret) { - if(mth) - LIBSSH2_FREE(session, mth); - if(key) - LIBSSH2_FREE(session, key); - } - else { - *method = mth; - *method_len = mthlen; - *pubkeydata = key; - *pubkeydata_len = keylen; - } - - return ret; -} -#endif /* HAVE_LIBCRYPT32 */ - -int -_libssh2_wincng_pub_priv_keyfile(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - const char *privatekey, - const char *passphrase) -{ -#ifdef HAVE_LIBCRYPT32 - unsigned char *pbEncoded; - unsigned long cbEncoded; - int ret; - - ret = _libssh2_wincng_load_private(session, privatekey, passphrase, - &pbEncoded, &cbEncoded, 1, 1); - if(ret) { - return -1; - } - - return _libssh2_wincng_pub_priv_keyfile_parse(session, method, method_len, - pubkeydata, pubkeydata_len, - pbEncoded, cbEncoded); -#else - (void)method; - (void)method_len; - (void)pubkeydata; - (void)pubkeydata_len; - (void)privatekey; - (void)passphrase; - - return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Unable to load public key from private key file: " - "Method unsupported in Windows CNG backend"); -#endif /* HAVE_LIBCRYPT32 */ -} - -int -_libssh2_wincng_pub_priv_keyfilememory(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - const char *privatekeydata, - size_t privatekeydata_len, - const char *passphrase) -{ -#ifdef HAVE_LIBCRYPT32 - unsigned char *pbEncoded; - unsigned long cbEncoded; - int ret; - - ret = _libssh2_wincng_load_private_memory(session, privatekeydata, - privatekeydata_len, passphrase, - &pbEncoded, &cbEncoded, 1, 1); - if(ret) { - return -1; - } - - return _libssh2_wincng_pub_priv_keyfile_parse(session, method, method_len, - pubkeydata, pubkeydata_len, - pbEncoded, cbEncoded); -#else - (void)method; - (void)method_len; - (void)pubkeydata_len; - (void)pubkeydata; - (void)privatekeydata; - (void)privatekeydata_len; - (void)passphrase; - - return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Unable to extract public key from private key in memory: " - "Method unsupported in Windows CNG backend"); -#endif /* HAVE_LIBCRYPT32 */ -} - -/*******************************************************************/ -/* - * Windows CNG backend: Cipher functions - */ - -int -_libssh2_wincng_cipher_init(_libssh2_cipher_ctx *ctx, - _libssh2_cipher_type(type), - unsigned char *iv, - unsigned char *secret, - int encrypt) -{ - BCRYPT_KEY_HANDLE hKey; - BCRYPT_KEY_DATA_BLOB_HEADER *header; - unsigned char *pbKeyObject, *pbIV, *key, *pbCtr, *pbIVCopy; - unsigned long dwKeyObject, dwIV, dwCtrLength, dwBlockLength, - cbData, keylen; - int ret; - - (void)encrypt; - - ret = BCryptGetProperty(*type.phAlg, BCRYPT_OBJECT_LENGTH, - (unsigned char *)&dwKeyObject, - sizeof(dwKeyObject), - &cbData, 0); - if(!BCRYPT_SUCCESS(ret)) { - return -1; - } - - ret = BCryptGetProperty(*type.phAlg, BCRYPT_BLOCK_LENGTH, - (unsigned char *)&dwBlockLength, - sizeof(dwBlockLength), - &cbData, 0); - if(!BCRYPT_SUCCESS(ret)) { - return -1; - } - - pbKeyObject = malloc(dwKeyObject); - if(!pbKeyObject) { - return -1; - } - - - keylen = sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) + type.dwKeyLength; - key = malloc(keylen); - if(!key) { - free(pbKeyObject); - return -1; - } - - - header = (BCRYPT_KEY_DATA_BLOB_HEADER *)key; - header->dwMagic = BCRYPT_KEY_DATA_BLOB_MAGIC; - header->dwVersion = BCRYPT_KEY_DATA_BLOB_VERSION1; - header->cbKeyData = type.dwKeyLength; - - memcpy(key + sizeof(BCRYPT_KEY_DATA_BLOB_HEADER), - secret, type.dwKeyLength); - - ret = BCryptImportKey(*type.phAlg, NULL, BCRYPT_KEY_DATA_BLOB, &hKey, - pbKeyObject, dwKeyObject, key, keylen, 0); - - _libssh2_wincng_safe_free(key, keylen); - - if(!BCRYPT_SUCCESS(ret)) { - _libssh2_wincng_safe_free(pbKeyObject, dwKeyObject); - return -1; - } - - pbIV = NULL; - pbCtr = NULL; - dwIV = 0; - dwCtrLength = 0; - - if(type.useIV || type.ctrMode) { - pbIVCopy = malloc(dwBlockLength); - if(!pbIVCopy) { - BCryptDestroyKey(hKey); - _libssh2_wincng_safe_free(pbKeyObject, dwKeyObject); - return -1; - } - memcpy(pbIVCopy, iv, dwBlockLength); - - if(type.ctrMode) { - pbCtr = pbIVCopy; - dwCtrLength = dwBlockLength; - } - else if(type.useIV) { - pbIV = pbIVCopy; - dwIV = dwBlockLength; - } - } - - ctx->hKey = hKey; - ctx->pbKeyObject = pbKeyObject; - ctx->pbIV = pbIV; - ctx->pbCtr = pbCtr; - ctx->dwKeyObject = dwKeyObject; - ctx->dwIV = dwIV; - ctx->dwBlockLength = dwBlockLength; - ctx->dwCtrLength = dwCtrLength; - - return 0; -} -int -_libssh2_wincng_cipher_crypt(_libssh2_cipher_ctx *ctx, - _libssh2_cipher_type(type), - int encrypt, - unsigned char *block, - size_t blocklen) -{ - unsigned char *pbOutput, *pbInput; - unsigned long cbOutput, cbInput; - int ret; - - (void)type; - - cbInput = (unsigned long)blocklen; - - if(type.ctrMode) { - pbInput = ctx->pbCtr; - } - else { - pbInput = block; - } - - if(encrypt || type.ctrMode) { - ret = BCryptEncrypt(ctx->hKey, pbInput, cbInput, NULL, - ctx->pbIV, ctx->dwIV, NULL, 0, &cbOutput, 0); - } - else { - ret = BCryptDecrypt(ctx->hKey, pbInput, cbInput, NULL, - ctx->pbIV, ctx->dwIV, NULL, 0, &cbOutput, 0); - } - if(BCRYPT_SUCCESS(ret)) { - pbOutput = malloc(cbOutput); - if(pbOutput) { - if(encrypt || type.ctrMode) { - ret = BCryptEncrypt(ctx->hKey, pbInput, cbInput, NULL, - ctx->pbIV, ctx->dwIV, - pbOutput, cbOutput, &cbOutput, 0); - } - else { - ret = BCryptDecrypt(ctx->hKey, pbInput, cbInput, NULL, - ctx->pbIV, ctx->dwIV, - pbOutput, cbOutput, &cbOutput, 0); - } - if(BCRYPT_SUCCESS(ret)) { - if(type.ctrMode) { - _libssh2_xor_data(block, block, pbOutput, blocklen); - _libssh2_aes_ctr_increment(ctx->pbCtr, ctx->dwCtrLength); - } - else { - memcpy(block, pbOutput, cbOutput); - } - } - - _libssh2_wincng_safe_free(pbOutput, cbOutput); - } - else - ret = STATUS_NO_MEMORY; - } - - return BCRYPT_SUCCESS(ret) ? 0 : -1; -} - -void -_libssh2_wincng_cipher_dtor(_libssh2_cipher_ctx *ctx) -{ - BCryptDestroyKey(ctx->hKey); - ctx->hKey = NULL; - - _libssh2_wincng_safe_free(ctx->pbKeyObject, ctx->dwKeyObject); - ctx->pbKeyObject = NULL; - ctx->dwKeyObject = 0; - - _libssh2_wincng_safe_free(ctx->pbIV, ctx->dwBlockLength); - ctx->pbIV = NULL; - ctx->dwBlockLength = 0; - - _libssh2_wincng_safe_free(ctx->pbCtr, ctx->dwCtrLength); - ctx->pbCtr = NULL; - ctx->dwCtrLength = 0; -} - - -/*******************************************************************/ -/* - * Windows CNG backend: BigNumber functions - */ - -_libssh2_bn * -_libssh2_wincng_bignum_init(void) -{ - _libssh2_bn *bignum; - - bignum = (_libssh2_bn *)malloc(sizeof(_libssh2_bn)); - if(bignum) { - bignum->bignum = NULL; - bignum->length = 0; - } - - return bignum; -} - -static int -_libssh2_wincng_bignum_resize(_libssh2_bn *bn, unsigned long length) -{ - unsigned char *bignum; - - if(!bn) - return -1; - - if(length == bn->length) - return 0; - -#ifdef LIBSSH2_CLEAR_MEMORY - if(bn->bignum && bn->length > 0 && length < bn->length) { - SecureZeroMemory(bn->bignum + length, bn->length - length); - } -#endif - - bignum = realloc(bn->bignum, length); - if(!bignum) - return -1; - - bn->bignum = bignum; - bn->length = length; - - return 0; -} - -static int -_libssh2_wincng_bignum_rand(_libssh2_bn *rnd, int bits, int top, int bottom) -{ - unsigned char *bignum; - unsigned long length; - - if(!rnd) - return -1; - - length = (unsigned long) (ceil(((double)bits) / 8.0) * - sizeof(unsigned char)); - if(_libssh2_wincng_bignum_resize(rnd, length)) - return -1; - - bignum = rnd->bignum; - - if(_libssh2_wincng_random(bignum, length)) - return -1; - - /* calculate significant bits in most significant byte */ - bits %= 8; - - /* fill most significant byte with zero padding */ - bignum[0] &= (1 << (8 - bits)) - 1; - - /* set some special last bits in most significant byte */ - if(top == 0) - bignum[0] |= (1 << (7 - bits)); - else if(top == 1) - bignum[0] |= (3 << (6 - bits)); - - /* make odd by setting first bit in least significant byte */ - if(bottom) - bignum[length - 1] |= 1; - - return 0; -} - -static int -_libssh2_wincng_bignum_mod_exp(_libssh2_bn *r, - _libssh2_bn *a, - _libssh2_bn *p, - _libssh2_bn *m) -{ - BCRYPT_KEY_HANDLE hKey; - BCRYPT_RSAKEY_BLOB *rsakey; - unsigned char *key, *bignum; - unsigned long keylen, offset, length; - int ret; - - if(!r || !a || !p || !m) - return -1; - - offset = sizeof(BCRYPT_RSAKEY_BLOB); - keylen = offset + p->length + m->length; - - key = malloc(keylen); - if(!key) - return -1; - - - /* https://msdn.microsoft.com/library/windows/desktop/aa375531.aspx */ - rsakey = (BCRYPT_RSAKEY_BLOB *)key; - rsakey->Magic = BCRYPT_RSAPUBLIC_MAGIC; - rsakey->BitLength = m->length * 8; - rsakey->cbPublicExp = p->length; - rsakey->cbModulus = m->length; - rsakey->cbPrime1 = 0; - rsakey->cbPrime2 = 0; - - memcpy(key + offset, p->bignum, p->length); - offset += p->length; - - memcpy(key + offset, m->bignum, m->length); - - ret = BCryptImportKeyPair(_libssh2_wincng.hAlgRSA, NULL, - BCRYPT_RSAPUBLIC_BLOB, &hKey, key, keylen, 0); - if(BCRYPT_SUCCESS(ret)) { - ret = BCryptEncrypt(hKey, a->bignum, a->length, NULL, NULL, 0, - NULL, 0, &length, BCRYPT_PAD_NONE); - if(BCRYPT_SUCCESS(ret)) { - if(!_libssh2_wincng_bignum_resize(r, length)) { - length = max(a->length, length); - bignum = malloc(length); - if(bignum) { - offset = length - a->length; - memset(bignum, 0, offset); - memcpy(bignum + offset, a->bignum, a->length); - - ret = BCryptEncrypt(hKey, bignum, length, NULL, NULL, 0, - r->bignum, r->length, &offset, - BCRYPT_PAD_NONE); - - _libssh2_wincng_safe_free(bignum, length); - - if(BCRYPT_SUCCESS(ret)) { - _libssh2_wincng_bignum_resize(r, offset); - } - } - else - ret = STATUS_NO_MEMORY; - } - else - ret = STATUS_NO_MEMORY; - } - - BCryptDestroyKey(hKey); - } - - _libssh2_wincng_safe_free(key, keylen); - - return BCRYPT_SUCCESS(ret) ? 0 : -1; -} - -int -_libssh2_wincng_bignum_set_word(_libssh2_bn *bn, unsigned long word) -{ - unsigned long offset, number, bits, length; - - if(!bn) - return -1; - - bits = 0; - number = word; - while(number >>= 1) - bits++; - bits++; - - length = (unsigned long) (ceil(((double)bits) / 8.0) * - sizeof(unsigned char)); - if(_libssh2_wincng_bignum_resize(bn, length)) - return -1; - - for(offset = 0; offset < length; offset++) - bn->bignum[offset] = (word >> (offset * 8)) & 0xff; - - return 0; -} - -unsigned long -_libssh2_wincng_bignum_bits(const _libssh2_bn *bn) -{ - unsigned char number; - unsigned long offset, length, bits; - - if(!bn || !bn->bignum || !bn->length) - return 0; - - offset = 0; - length = bn->length - 1; - while(!bn->bignum[offset] && offset < length) - offset++; - - bits = (length - offset) * 8; - number = bn->bignum[offset]; - while(number >>= 1) - bits++; - bits++; - - return bits; -} - -void -_libssh2_wincng_bignum_from_bin(_libssh2_bn *bn, unsigned long len, - const unsigned char *bin) -{ - unsigned char *bignum; - unsigned long offset, length, bits; - - if(!bn || !bin || !len) - return; - - if(_libssh2_wincng_bignum_resize(bn, len)) - return; - - memcpy(bn->bignum, bin, len); - - bits = _libssh2_wincng_bignum_bits(bn); - length = (unsigned long) (ceil(((double)bits) / 8.0) * - sizeof(unsigned char)); - - offset = bn->length - length; - if(offset > 0) { - memmove(bn->bignum, bn->bignum + offset, length); - -#ifdef LIBSSH2_CLEAR_MEMORY - SecureZeroMemory(bn->bignum + length, offset); -#endif - - bignum = realloc(bn->bignum, length); - if(bignum) { - bn->bignum = bignum; - bn->length = length; - } - } -} - -void -_libssh2_wincng_bignum_to_bin(const _libssh2_bn *bn, unsigned char *bin) -{ - if(bin && bn && bn->bignum && bn->length > 0) { - memcpy(bin, bn->bignum, bn->length); - } -} - -void -_libssh2_wincng_bignum_free(_libssh2_bn *bn) -{ - if(bn) { - if(bn->bignum) { - _libssh2_wincng_safe_free(bn->bignum, bn->length); - bn->bignum = NULL; - } - bn->length = 0; - _libssh2_wincng_safe_free(bn, sizeof(_libssh2_bn)); - } -} - - -/* - * Windows CNG backend: Diffie-Hellman support. - */ - -void -_libssh2_dh_init(_libssh2_dh_ctx *dhctx) -{ - *dhctx = _libssh2_wincng_bignum_init(); /* Random from client */ -} - -int -_libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public, - _libssh2_bn *g, _libssh2_bn *p, int group_order) -{ - /* Generate x and e */ - if(_libssh2_wincng_bignum_rand(*dhctx, group_order * 8 - 1, 0, -1)) - return -1; - if(_libssh2_wincng_bignum_mod_exp(public, g, *dhctx, p)) - return -1; - return 0; -} - -int -_libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret, - _libssh2_bn *f, _libssh2_bn *p) -{ - /* Compute the shared secret */ - return _libssh2_wincng_bignum_mod_exp(secret, f, *dhctx, p); -} - -void -_libssh2_dh_dtor(_libssh2_dh_ctx *dhctx) -{ - _libssh2_wincng_bignum_free(*dhctx); - *dhctx = NULL; -} - -#endif /* LIBSSH2_WINCNG */