Compare commits

...

37 Commits

Author SHA1 Message Date
Sara Golemon
ace0c8f00b Bump for release 2006-06-22 18:50:26 +00:00
Sara Golemon
adee5e5653 Don't wait for KEX_INIT prior to sending our own packet.
Watch out for bad KEX_INIT guesses and burn packets if necessary.
2006-06-22 18:45:29 +00:00
Sara Golemon
5f85317efa Swap ordering of packet_add/packet-inspection to avoid inspect after free. Fix OpenSSL detection using pkg-config. 2006-05-26 22:36:48 +00:00
Sara Golemon
09b93e4bb6 Map Win32 errno values 2006-04-17 02:49:44 +00:00
Sara Golemon
19cad102f4 autoconf already handles -g for us 2006-04-07 20:44:26 +00:00
Sara Golemon
4d7726c551 Plug leaks caused by not using OpenSSL's EVP interface correctly 2006-04-06 21:50:37 +00:00
Sara Golemon
37307a8778 Map win32 error codes 2006-04-05 05:36:53 +00:00
Sara Golemon
fbcdff2161 Allow socket_fd == 0 in libssh2_session_startup() 2006-03-08 19:10:53 +00:00
Sara Golemon
c45992da55 Bump copyright year 2006-03-02 01:10:52 +00:00
Sara Golemon
2207b99afb Bump version number 2006-03-02 01:10:06 +00:00
Sara Golemon
1d7522bc06 BugFix#1436593: Apply build options for HPUX targets 2006-02-23 23:14:35 +00:00
Mikhail Gusarov
a4e61c265b Fixed errorneous flushing packets for unrelated channels when one is closed
(thanks to Alexander Holyapin)
2006-02-20 08:39:54 +00:00
Sara Golemon
502a48afa1 Fix make install on MacOSX 2006-01-06 17:34:03 +00:00
Sara Golemon
efc3841fd2 Add terminating NULL to readlin/realpath results 2005-11-17 23:20:32 +00:00
Sara Golemon
f9d65b0984 Fix miscellaneous bugs in src/channel.c and src/packet.c
Courtessy David Robins
2005-11-02 00:26:24 +00:00
Sara Golemon
edcdf43264 Prep for release 2005-11-01 23:11:50 +00:00
Mikhail Gusarov
722470994a Added missing '#ifdef __cplusplus extern "C" {}' stanza 2005-10-04 04:25:24 +00:00
Sara Golemon
14f00247a8 Explicitly include sha.h and md5.h from openssl 2005-08-25 20:50:37 +00:00
Sara Golemon
78048973c5 Fix x11_req. Multiple packet_len issues and error handling logic. (Simon Hart) 2005-08-10 21:37:44 +00:00
Sara Golemon
e15f5d97a0 Add publickey subsystem support 2005-07-21 20:28:07 +00:00
Sara Golemon
01de39e585 Fix generation of 'e' portion of Diffie-Hellman keyset. 2005-07-11 15:56:09 +00:00
Sara Golemon
6cc50263e2 Fix rename op -- Take 2 2005-07-06 17:50:53 +00:00
Sara Golemon
beca3742a2 Correct ancient typos in error messages 2005-07-06 16:27:54 +00:00
Sara Golemon
d6cfa7c6b9 bump for release -- 0.11 2005-07-05 01:42:11 +00:00
Sara Golemon
ae17fbcd2c BFN 2005-07-05 01:38:41 +00:00
Mikhail Gusarov
0c53895bc0 libssh2_poll_channel_read made external 2005-06-24 11:22:10 +00:00
Mikhail Gusarov
dc446eff08 Debug output slightly fixed 2005-06-24 11:18:20 +00:00
Mikhail Gusarov
aa6e9c6eca Added libssh2_channel_wait_close() 2005-06-24 11:17:50 +00:00
Mikhail Gusarov
2e097c7760 Memory leak liquidated - free the SSH_MSG_CHANNEL_REQUEST packet data
after processing 'exit-status' message
2005-06-23 08:22:04 +00:00
Mikhail Gusarov
77bd3c1215 'exit-status' information packet handling added 2005-06-23 05:55:01 +00:00
Mikhail Gusarov
0e5eb4d9c5 Added extern "C" declaration for C++ compatibility 2005-06-20 05:17:51 +00:00
Mikhail Gusarov
8ee79a5118 Fixed keyboard-interactive authentication, debug output added 2005-06-18 12:18:07 +00:00
Mikhail Gusarov
0ad861d74c libssh2_userauth_list should return char*, not the const char* 2005-06-18 11:30:31 +00:00
Mikhail Gusarov
b6d13ebe8a Strictening function prototypes: char* -> const char* where applicable 2005-06-18 10:41:59 +00:00
Sara Golemon
06e1136ea0 Don't send flags for rename op if the sftp version is too low 2005-06-17 17:18:25 +00:00
Sara Golemon
2a6c49a73a Add abstract pointer to keyboard-interactive callback 2005-06-16 17:14:31 +00:00
Sara Golemon
da653774aa Add keyboard interactive authentication.
Implementation contributed by Mikhail Gusarov.
2005-06-11 19:18:06 +00:00
24 changed files with 1542 additions and 158 deletions

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org> /* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, * Redistribution and use in source and binary forms,

View File

@@ -7,7 +7,7 @@ incldir = @prefix@/include
distdir = @top_srcdir@/dist distdir = @top_srcdir@/dist
CC = @CC@ CC = @CC@
CFLAGS = -c @CFLAGS@ -Iinclude/ -Wall -g CFLAGS = -c @CFLAGS@ -Iinclude/ -Wall
LIBS = -lssh2 -Lsrc/ LIBS = -lssh2 -Lsrc/
INSTALL = @INSTALL@ INSTALL = @INSTALL@
VERSION=@PACKAGE_VERSION@ VERSION=@PACKAGE_VERSION@
@@ -18,9 +18,10 @@ all:
(cd $$dir && $(MAKE) all) \ (cd $$dir && $(MAKE) all) \
|| case "$(MFLAGS)" in *k*) fail=yes;; *) exit 1;; esac; \ || case "$(MFLAGS)" in *k*) fail=yes;; *) exit 1;; esac; \
done && test -z "$$fail" done && test -z "$$fail"
sample:
$(CC) -o ssh2_sample.o ssh2_sample.c $(CFLAGS) $(CC) -o ssh2_sample.o ssh2_sample.c $(CFLAGS)
$(CC) -o ssh2_sample ssh2_sample.o $(LIBS) $(CC) -o ssh2_sample ssh2_sample.o $(LIBS)
install: install: all
$(top_srcdir)/mkinstalldirs $(DESTDIR)$(incldir) $(top_srcdir)/mkinstalldirs $(DESTDIR)$(incldir)
$(top_srcdir)/mkinstalldirs $(DESTDIR)$(libdir) $(top_srcdir)/mkinstalldirs $(DESTDIR)$(libdir)
@for dir in ${subdirs}; do \ @for dir in ${subdirs}; do \
@@ -29,6 +30,7 @@ install:
done && test -z "$$fail" done && test -z "$$fail"
$(INSTALL) -m 644 include/libssh2.h $(DESTDIR)$(incldir)/ $(INSTALL) -m 644 include/libssh2.h $(DESTDIR)$(incldir)/
$(INSTALL) -m 644 include/libssh2_sftp.h $(DESTDIR)$(incldir)/ $(INSTALL) -m 644 include/libssh2_sftp.h $(DESTDIR)$(incldir)/
$(INSTALL) -m 644 include/libssh2_publickey.h $(DESTDIR)$(incldir)/
clean: clean:
@for dir in ${subdirs}; do \ @for dir in ${subdirs}; do \
(cd $$dir && $(MAKE) clean) \ (cd $$dir && $(MAKE) clean) \
@@ -46,7 +48,7 @@ dist:
$(DISTLIB)/mkinstalldirs $(DISTLIB)/install-sh $(DISTLIB)/config.sub $(DISTLIB)/config.guess \ $(DISTLIB)/mkinstalldirs $(DISTLIB)/install-sh $(DISTLIB)/config.sub $(DISTLIB)/config.guess \
$(DISTLIB)/src/*.c $(DISTLIB)/src/Makefile.in \ $(DISTLIB)/src/*.c $(DISTLIB)/src/Makefile.in \
$(DISTLIB)/include/libssh2.h $(DISTLIB)/include/libssh2_priv.h $(DISTLIB)/include/libssh2_sftp.h \ $(DISTLIB)/include/libssh2.h $(DISTLIB)/include/libssh2_priv.h $(DISTLIB)/include/libssh2_sftp.h \
$(DISTLIB)/include/libssh2_config.h.in \ $(DISTLIB)/include/libssh2_publickey.h $(DISTLIB)/include/libssh2_config.h.in \
$(DISTLIB)/win32/config.mk $(DISTLIB)/win32/libssh2_config.h $(DISTLIB)/win32/rules.mk \ $(DISTLIB)/win32/config.mk $(DISTLIB)/win32/libssh2_config.h $(DISTLIB)/win32/rules.mk \
$(DISTLIB)/win32/libssh2.dsp $(DISTLIB)/win32/libssh2.dsw $(DISTLIB)/win32/ssh2_sample.dsp $(DISTLIB)/win32/libssh2.dsp $(DISTLIB)/win32/libssh2.dsw $(DISTLIB)/win32/ssh2_sample.dsp
rm -f $(DISTLIB) rm -f $(DISTLIB)
@@ -59,6 +61,7 @@ dist_nmake:
$(DISTLIB)/NMakefile $(DISTLIB)/ssh2_sample.c $(DISTLIB)/src/*.c \ $(DISTLIB)/NMakefile $(DISTLIB)/ssh2_sample.c $(DISTLIB)/src/*.c \
$(DISTLIB)/LICENSE $(DISTLIB)/README $(DISTLIB)/TODO $(DISTLIB)/INSTALL \ $(DISTLIB)/LICENSE $(DISTLIB)/README $(DISTLIB)/TODO $(DISTLIB)/INSTALL \
$(DISTLIB)/include/libssh2.h $(DISTLIB)/include/libssh2_priv.h $(DISTLIB)/include/libssh2_sftp.h \ $(DISTLIB)/include/libssh2.h $(DISTLIB)/include/libssh2_priv.h $(DISTLIB)/include/libssh2_sftp.h \
$(DISTLIB)/include/libssh2_publickey.h \
$(DISTLIB)/win32/config.mk $(DISTLIB)/win32/libssh2_config.h $(DISTLIB)/win32/rules.mk $(DISTLIB)/win32/config.mk $(DISTLIB)/win32/libssh2_config.h $(DISTLIB)/win32/rules.mk
rm -f $(DISTLIB) rm -f $(DISTLIB)

55
README
View File

@@ -1,13 +1,68 @@
libssh2 - SSH2 library libssh2 - SSH2 library
====================== ======================
Version 0.14
------------
Plug leaks in EVP cipher init/shutdown. (Selcuk Gueney)
Allow socket_fd == 0 in libssh2_session_startup(). (puudeli)
Swap ordering of packet_add/packet-inspection to avoid inspect after free. (Selcuk)
Swap KEX_INIT ordering, send our KEX_INIT first.
Add check for oportunistic KEX_INIT packets. Burn bad guess if necessary.
Fix OpenSSL detection using pkg-config. (Dan Casey)
Version 0.13
------------
Fixed channel not being marked closed when CHANNEL_CLOSE package cannot be sent. (David Robins)
Fixed payload packet allocation bug when invalid packet length received. (David Robins)
Fixed `make install' target for MacOSX.
Add terminating NULL character to readlink()/realpath() results.
BugFix#1436593: Apply build options for HPUX targets.
Version 0.12
------------
Added support for publickey subsytem (not the same as publickey auth).
Fix x11_req. Multiple packet_len issues and error handling logic.
(Thanks Simon Hart)
Fix generation of 'e' portion of Diffie-Hellman keyset.
Use appropriate order for BN_rand() rather than fixed group1-specific value.
Re-fixed libssh2_sftp_rename_ex()
Transport had right packet_len, but sftp layer still had extra 4 bytes.
Fixed build with newer OpenSSL headers.
Added extern "C" declarations to libssh2_sftp.h for C++ compatability.
Version 0.11 Version 0.11
------------ ------------
Added libssh2_chnnale_get_exit_status() -- Mikhail
Added libssh2_channel_wait_closed() -- Mikhail
Added libssh2_userauth_keyboard_interactive_ex() -- Mikhail
Added libssh2_channel_receive_window_adjust() to be able to increase the size of the receive window. Added libssh2_channel_receive_window_adjust() to be able to increase the size of the receive window.
Added queueing for small window_adjust packets to avoid unnecessary packet conversation. Added queueing for small window_adjust packets to avoid unnecessary packet conversation.
Fixed libssh2_sftp_rename_ex() to only send flags parameter if version >= 5 negotiated
(not currently possible, but will be and might as well keep the API consistent).
Version 0.10 Version 0.10
------------ ------------

View File

@@ -1,8 +1,11 @@
# AC_PREREQ(2.57) # AC_PREREQ(2.57)
AC_INIT(libssh2,0.10,sarag@libssh2.org) AC_INIT(libssh2,0.14,sarag@libssh2.org)
AC_CONFIG_SRCDIR([src]) AC_CONFIG_SRCDIR([src])
AC_CONFIG_HEADER([include/libssh2_config.h]) AC_CONFIG_HEADER([include/libssh2_config.h])
# Default to the same as CC
LDCC="\$(CC)"
# Check for the OS. # Check for the OS.
AC_CANONICAL_HOST AC_CANONICAL_HOST
case "$host" in case "$host" in
@@ -16,6 +19,11 @@ case "$host" in
SHLIB_LDFLAGS="-dynamiclib -flat_namespace" SHLIB_LDFLAGS="-dynamiclib -flat_namespace"
CFLAGS="$CFLAGS -DLIBSSH2_DARWIN" CFLAGS="$CFLAGS -DLIBSSH2_DARWIN"
;; ;;
*hpux*)
SHLIB_SUFFIX_NAME="sl"
SHLIB_LDFLAGS="-b +vnocompatwarnings -L/lib/pa20_64"
LDCC="ld"
;;
*) *)
SHLIB_SUFFIX_NAME="so" SHLIB_SUFFIX_NAME="so"
SHLIB_LDFLAGS="-shared" SHLIB_LDFLAGS="-shared"
@@ -31,6 +39,7 @@ AC_CHECK_LIB(m, ceil, [ SHLIB_LDFLAGS="$SHLIB_LDFLAGS -lm" ])
AC_SUBST(SHLIB_SUFFIX_NAME) AC_SUBST(SHLIB_SUFFIX_NAME)
AC_SUBST(SHLIB_LDFLAGS) AC_SUBST(SHLIB_LDFLAGS)
AC_SUBST(LDCC)
AC_SUBST(LIBS) AC_SUBST(LIBS)
AC_PROG_CC AC_PROG_CC
@@ -55,15 +64,18 @@ if test "$LIBSSH2_OPENSSL_DIR" = "no" || test "$LIBSSH2_OPENSSL_DIR" = "yes"; th
fi fi
found_openssl=no found_openssl=no
pkgcfg_openssl=no
unset OPENSSL_INCDIR unset OPENSSL_INCDIR
unset OPENSSL_LIBDIR unset OPENSSL_INCLINE
unset OPENSSL_LIBLINE
AC_MSG_CHECKING([for OpenSSL]) AC_MSG_CHECKING([for OpenSSL])
# Explicit path given, use it rather than pkg-config # Explicit path given, use it rather than pkg-config
if test ! -z "$LIBSSH2_OPENSSL_DIR"; then if test ! -z "$LIBSSH2_OPENSSL_DIR"; then
found_openssl=yes found_openssl=yes
OPENSSL_LIBDIR=$LIBSSH2_OPENSSL_DIR/lib OPENSSL_LIBLINE="-L$LIBSSH2_OPENSSL_DIR/lib -lcrypto"
OPENSSL_INCLINE="-I$LIBSSH2_OPENSSL_DIR/include"
OPENSSL_INCDIR=$LIBSSH2_OPENSSL_DIR/include OPENSSL_INCDIR=$LIBSSH2_OPENSSL_DIR/include
AC_MSG_RESULT([Using explicit path $LIBSSH2_OPENSSL_DIR]) AC_MSG_RESULT([Using explicit path $LIBSSH2_OPENSSL_DIR])
fi fi
@@ -71,8 +83,9 @@ fi
# If pkg-config is found try using it # If pkg-config is found try using it
if test "$found_openssl" = "no" && test -x "$PKG_CONFIG" && $PKG_CONFIG --exists openssl; then if test "$found_openssl" = "no" && test -x "$PKG_CONFIG" && $PKG_CONFIG --exists openssl; then
found_openssl=yes found_openssl=yes
OPENSSL_LIBDIR=`$PKG_CONFIG --libs openssl` pkgcfg_openssl=yes
OPENSSL_INCDIR=`$PKG_CONFIG --variable=includedir openssl` OPENSSL_LIBLINE=`$PKG_CONFIG --libs openssl`
OPENSSL_INCLINE=`$PKG_CONFIG --variable=includedir openssl`
AC_MSG_RESULT([Using paths from pkg-config]) AC_MSG_RESULT([Using paths from pkg-config])
fi fi
@@ -82,39 +95,43 @@ if test "$found_openssl" = "no"; then
for i in $OPENSSL_SEARCH_PATH; do for i in $OPENSSL_SEARCH_PATH; do
if test -r $i/include/openssl/evp.h; then if test -r $i/include/openssl/evp.h; then
OPENSSL_INCLINE="-I$i/include"
OPENSSL_INCDIR=$i/include OPENSSL_INCDIR=$i/include
fi fi
if test -r $i/include/openssl/hmac.h; then if test -r $i/include/openssl/hmac.h; then
OPENSSL_INCLINE="-I$i/include"
OPENSSL_INCDIR=$i/include OPENSSL_INCDIR=$i/include
fi fi
if test -r $i/lib/libcrypto.a -o -r $i/lib/libcrypto.$SHLIB_SUFFIX_NAME; then if test -r $i/lib/libcrypto.a -o -r $i/lib/libcrypto.$SHLIB_SUFFIX_NAME; then
OPENSSL_LIBDIR=$i/lib OPENSSL_LIBLINE="-L$i/lib -lcrypto"
fi fi
test -n "$OPENSSL_INCDIR" && test -n "$OPENSSL_LIBDIR" && break test -n "$OPENSSL_INCLINE" && test -n "$OPENSSL_LIBLINE" && break
done done
if test -z "$OPENSSL_INCDIR"; then if test -z "$OPENSSL_INCLINE"; then
AC_MSG_ERROR([Cannot find OpenSSL's <evp.h> or <hmac.h>]) AC_MSG_ERROR([Cannot find OpenSSL's <evp.h> or <hmac.h>])
fi fi
if test -z "$OPENSSL_LIBDIR"; then if test -z "$OPENSSL_LIBLINE"; then
AC_MSG_ERROR([Cannot find OpenSSL's libcrypto]) AC_MSG_ERROR([Cannot find OpenSSL's libcrypto])
fi fi
AC_MSG_RESULT([$OPENSSL_INCDIR $OPENSSL_LIBDIR]) AC_MSG_RESULT([$OPENSSL_INCLINE $OPENSSL_LIBLINE])
fi fi
# #
# Confirm required OpenSSL libs # Confirm required OpenSSL libs
# #
if test ! -r $OPENSSL_INCDIR/openssl/bn.h || test ! -r $OPENSSL_INCDIR/openssl/evp.h || \ if test ! "$pkgcfg_openssl" = "yes"; then
test ! -r $OPENSSL_INCDIR/openssl/hmac.h || test ! -r $OPENSSL_INCDIR/openssl/pem.h || \ if test ! -r $OPENSSL_INCDIR/openssl/bn.h || test ! -r $OPENSSL_INCDIR/openssl/evp.h || \
test ! -r $OPENSSL_INCDIR/openssl/sha.h; then test ! -r $OPENSSL_INCDIR/openssl/hmac.h || test ! -r $OPENSSL_INCDIR/openssl/pem.h || \
AC_MSG_ERROR([Missing one or more of <openssl/bn.h>, <openssl/evp.h>, <openssl/hmac.h>, <openssl/pem.h>, <openssl/sha.h>]) test ! -r $OPENSSL_INCDIR/openssl/sha.h; then
AC_MSG_ERROR([Missing one or more of <openssl/bn.h>, <openssl/evp.h>, <openssl/hmac.h>, <openssl/pem.h>, <openssl/sha.h>])
fi
fi fi
CFLAGS="$CFLAGS -I$OPENSSL_INCDIR" CFLAGS="$CFLAGS $OPENSSL_INCLINE"
LDFLAGS="$LDFLAGS -L$OPENSSL_LIBDIR -lcrypto" LDFLAGS="$LDFLAGS $OPENSSL_LIBLINE"
# #
# zlib # zlib
@@ -191,6 +208,9 @@ AC_ARG_ENABLE(debug-scp,
AC_ARG_ENABLE(debug-sftp, AC_ARG_ENABLE(debug-sftp,
AC_HELP_STRING([--enable-debug-sftp],[Output sftp subsystem debugging info to stderr]), AC_HELP_STRING([--enable-debug-sftp],[Output sftp subsystem debugging info to stderr]),
[AC_DEFINE(LIBSSH2_DEBUG_SFTP, 1, [Output sftp subsystem debugging info to stderr])]) [AC_DEFINE(LIBSSH2_DEBUG_SFTP, 1, [Output sftp subsystem debugging info to stderr])])
AC_ARG_ENABLE(debug-publickey,
AC_HELP_STRING([--enable-debug-publickey],[Output publickey subsystem debugging info to stderr]),
[AC_DEFINE(LIBSSH2_DEBUG_PUBLICKEY, 1, [Output publickey subsystem debugging info to stderr])])
AC_ARG_ENABLE(debug-errors, AC_ARG_ENABLE(debug-errors,
AC_HELP_STRING([--enable-debug-errors],[Output failure events to stderr]), AC_HELP_STRING([--enable-debug-errors],[Output failure events to stderr]),
[AC_DEFINE(LIBSSH2_DEBUG_ERRORS, 1, [Output failure events to stderr])]) [AC_DEFINE(LIBSSH2_DEBUG_ERRORS, 1, [Output failure events to stderr])])
@@ -203,6 +223,7 @@ AC_ARG_ENABLE(debug-all,
AC_DEFINE(LIBSSH2_DEBUG_CONNECTION, 1, [Output connection layer debugging info to stderr]) AC_DEFINE(LIBSSH2_DEBUG_CONNECTION, 1, [Output connection layer debugging info to stderr])
AC_DEFINE(LIBSSH2_DEBUG_SCP, 1, [Output scp subsystem debugging info to stderr]) AC_DEFINE(LIBSSH2_DEBUG_SCP, 1, [Output scp subsystem debugging info to stderr])
AC_DEFINE(LIBSSH2_DEBUG_SFTP, 1, [Output sftp subsystem debugging info to stderr]) AC_DEFINE(LIBSSH2_DEBUG_SFTP, 1, [Output sftp subsystem debugging info to stderr])
AC_DEFINE(LIBSSH2_DEBUG_PUBLICKEY, 1, [Output publickey subsystem debugging info to stderr])
AC_DEFINE(LIBSSH2_DEBUG_ERRORS, 1, [Output failure events to stderr]) AC_DEFINE(LIBSSH2_DEBUG_ERRORS, 1, [Output failure events to stderr])
]) ])

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org> /* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, * Redistribution and use in source and binary forms,
@@ -38,6 +38,10 @@
#ifndef LIBSSH2_H #ifndef LIBSSH2_H
#define LIBSSH2_H 1 #define LIBSSH2_H 1
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h> #include <stddef.h>
#include <string.h> #include <string.h>
#include <sys/stat.h> #include <sys/stat.h>
@@ -67,8 +71,8 @@ typedef unsigned long long libssh2_uint64_t;
typedef long long libssh2_int64_t; typedef long long libssh2_int64_t;
#endif #endif
#define LIBSSH2_VERSION "0.10" #define LIBSSH2_VERSION "0.14"
#define LIBSSH2_APINO 200503281457 #define LIBSSH2_APINO 200507211326
/* Part of every banner, user specified or not */ /* Part of every banner, user specified or not */
#define LIBSSH2_SSH_BANNER "SSH-2.0-libssh2_" LIBSSH2_VERSION #define LIBSSH2_SSH_BANNER "SSH-2.0-libssh2_" LIBSSH2_VERSION
@@ -107,6 +111,22 @@ typedef long long libssh2_int64_t;
#define LIBSSH2_REALLOC_FUNC(name) void *name(void *ptr, 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) #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;
/* '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 */ /* 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_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_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)
@@ -233,6 +253,7 @@ typedef struct _LIBSSH2_POLLFD {
#define LIBSSH2_ERROR_METHOD_NOT_SUPPORTED -33 #define LIBSSH2_ERROR_METHOD_NOT_SUPPORTED -33
#define LIBSSH2_ERROR_INVAL -34 #define LIBSSH2_ERROR_INVAL -34
#define LIBSSH2_ERROR_INVALID_POLL_TYPE -35 #define LIBSSH2_ERROR_INVALID_POLL_TYPE -35
#define LIBSSH2_ERROR_PUBLICKEY_PROTOCOL -36
/* Session API */ /* 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); 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);
@@ -240,40 +261,51 @@ LIBSSH2_API LIBSSH2_SESSION *libssh2_session_init_ex(LIBSSH2_ALLOC_FUNC((*my_all
LIBSSH2_API void **libssh2_session_abstract(LIBSSH2_SESSION *session); 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 void *libssh2_session_callback_set(LIBSSH2_SESSION *session, int cbtype, void *callback);
LIBSSH2_API int libssh2_banner_set(LIBSSH2_SESSION *session, char *banner); LIBSSH2_API int libssh2_banner_set(LIBSSH2_SESSION *session, const char *banner);
LIBSSH2_API int libssh2_session_startup(LIBSSH2_SESSION *session, int socket); LIBSSH2_API int libssh2_session_startup(LIBSSH2_SESSION *session, int socket);
LIBSSH2_API int libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, int reason, char *description, char *lang); 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), "") #define libssh2_session_disconnect(session, description) libssh2_session_disconnect_ex((session), SSH_DISCONNECT_BY_APPLICATION, (description), "")
LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session); LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session);
LIBSSH2_API char *libssh2_hostkey_hash(LIBSSH2_SESSION *session, int hash_type); LIBSSH2_API const char *libssh2_hostkey_hash(LIBSSH2_SESSION *session, int hash_type);
LIBSSH2_API int libssh2_session_method_pref(LIBSSH2_SESSION *session, int method_type, char *prefs); LIBSSH2_API int libssh2_session_method_pref(LIBSSH2_SESSION *session, int method_type, const char *prefs);
LIBSSH2_API char *libssh2_session_methods(LIBSSH2_SESSION *session, int method_type); 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_error(LIBSSH2_SESSION *session, char **errmsg, int *errmsg_len, int want_buf);
LIBSSH2_API int libssh2_session_flag(LIBSSH2_SESSION *session, int flag, int value); LIBSSH2_API int libssh2_session_flag(LIBSSH2_SESSION *session, int flag, int value);
/* Userauth API */ /* Userauth API */
LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, char *username, int username_len); LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, const char *username, int username_len);
LIBSSH2_API int libssh2_userauth_authenticated(LIBSSH2_SESSION *session); LIBSSH2_API int libssh2_userauth_authenticated(LIBSSH2_SESSION *session);
LIBSSH2_API int libssh2_userauth_password_ex(LIBSSH2_SESSION *session, char *username, int username_len, char *password, int password_len, LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb))); LIBSSH2_API int libssh2_userauth_password_ex(LIBSSH2_SESSION *session, const char *username, int username_len, const char *password, int password_len, LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb)));
#define libssh2_userauth_password(session, username, password) libssh2_userauth_password_ex((session), (username), strlen(username), (password), strlen(password), NULL) #define libssh2_userauth_password(session, username, password) libssh2_userauth_password_ex((session), (username), strlen(username), (password), strlen(password), NULL)
LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, char *username, int username_len, LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, const char *username, int username_len,
char *publickey, char *privatekey, const char *publickey, const char *privatekey,
char *passphrase); const char *passphrase);
#define libssh2_userauth_publickey_fromfile(session, username, publickey, privatekey, passphrase) \ #define libssh2_userauth_publickey_fromfile(session, username, publickey, privatekey, passphrase) \
libssh2_userauth_publickey_fromfile_ex((session), (username), strlen(username), (publickey), (privatekey), (passphrase)) libssh2_userauth_publickey_fromfile_ex((session), (username), strlen(username), (publickey), (privatekey), (passphrase))
LIBSSH2_API int libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session, char *username, int username_len, LIBSSH2_API int libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session, const char *username, int username_len,
char *publickey, char *privatekey, const char *publickey, const char *privatekey,
char *passphrase, const char *passphrase,
char *hostname, int hostname_len, const char *hostname, int hostname_len,
char *local_username, int local_username_len); const char *local_username, int local_username_len);
#define libssh2_userauth_hostbased_fromfile(session, username, publickey, privatekey, passphrase, hostname) \ #define libssh2_userauth_hostbased_fromfile(session, username, publickey, privatekey, passphrase, hostname) \
libssh2_userauth_hostbased_fromfile_ex((session), (username), strlen(username), (publickey), (privatekey), (passphrase), (hostname), strlen(hostname), (username), strlen(username)) libssh2_userauth_hostbased_fromfile_ex((session), (username), strlen(username), (publickey), (privatekey), (passphrase), (hostname), strlen(hostname), (username), strlen(username))
/*
* 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 invokation.
*/
LIBSSH2_API int libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION* session, const char *username, 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), strlen(username), (response_callback))
LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds, long timeout); LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds, long timeout);
/* Channel API */ /* Channel API */
@@ -288,7 +320,7 @@ LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds, long timeou
#define SSH_EXTENDED_DATA_STDERR 1 #define SSH_EXTENDED_DATA_STDERR 1
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_open_ex(LIBSSH2_SESSION *session, char *channel_type, int channel_type_len, int window_size, int packet_size, char *message, int message_len); LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_open_ex(LIBSSH2_SESSION *session, const char *channel_type, int channel_type_len, int window_size, int packet_size, const char *message, 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) #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, char *host, int port, char *shost, int sport); LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *session, char *host, int port, char *shost, int sport);
@@ -310,7 +342,7 @@ LIBSSH2_API int libssh2_channel_request_pty_ex(LIBSSH2_CHANNEL *channel, char *t
LIBSSH2_API int libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL *channel, int single_connection, char *auth_proto, char *auth_cookie, int screen_number); LIBSSH2_API int libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL *channel, int single_connection, char *auth_proto, 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)) #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, char *request, int request_len, char *message, int message_len); LIBSSH2_API int libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, const char *request, int request_len, const char *message, int message_len);
#define libssh2_channel_shell(channel) libssh2_channel_process_startup((channel), "shell", sizeof("shell") - 1, NULL, 0) #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), strlen(command)) #define libssh2_channel_exec(channel, command) libssh2_channel_process_startup((channel), "exec", sizeof("exec") - 1, (command), strlen(command))
#define libssh2_channel_subsystem(channel, subsystem) libssh2_channel_process_startup((channel), "subsystem", sizeof("subsystem") - 1, (subsystem), strlen(subsystem)) #define libssh2_channel_subsystem(channel, subsystem) libssh2_channel_process_startup((channel), "subsystem", sizeof("subsystem") - 1, (subsystem), strlen(subsystem))
@@ -319,6 +351,8 @@ LIBSSH2_API int libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id,
#define libssh2_channel_read(channel, buf, buflen) libssh2_channel_read_ex((channel), 0, (buf), (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)) #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); 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) #define libssh2_channel_window_read(channel) libssh2_channel_window_read_ex((channel), NULL, NULL)
@@ -345,16 +379,22 @@ LIBSSH2_API void libssh2_channel_handle_extended_data(LIBSSH2_CHANNEL *channel,
LIBSSH2_API int libssh2_channel_flush_ex(LIBSSH2_CHANNEL *channel, int streamid); 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(channel) libssh2_channel_flush_ex((channel), 0)
#define libssh2_channel_flush_stderr(channel) libssh2_channel_flush_ex((channel), SSH_EXTENDED_DATA_STDERR) #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_send_eof(LIBSSH2_CHANNEL *channel); LIBSSH2_API int libssh2_channel_send_eof(LIBSSH2_CHANNEL *channel);
LIBSSH2_API int libssh2_channel_eof(LIBSSH2_CHANNEL *channel); LIBSSH2_API int libssh2_channel_eof(LIBSSH2_CHANNEL *channel);
LIBSSH2_API int libssh2_channel_close(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_API int libssh2_channel_free(LIBSSH2_CHANNEL *channel);
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, char *path, struct stat *sb); LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, const char *path, struct stat *sb);
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, char *path, int mode, size_t size, long mtime, long atime); LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, const char *path, int mode, size_t size, long mtime, long atime);
#define libssh2_scp_send(session, path, mode, size) libssh2_scp_send_ex((session), (path), (mode), (size), 0, 0) #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, int *dest_len, char *src, int src_len); LIBSSH2_API int libssh2_base64_decode(LIBSSH2_SESSION *session, char **dest, int *dest_len, char *src, int src_len);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* LIBSSH2_H */ #endif /* LIBSSH2_H */

View File

@@ -63,6 +63,9 @@
/* Output Key Exchange debugging info to stderr */ /* Output Key Exchange debugging info to stderr */
#undef LIBSSH2_DEBUG_KEX #undef LIBSSH2_DEBUG_KEX
/* Output publickey subsystem debugging info to stderr */
#undef LIBSSH2_DEBUG_PUBLICKEY
/* Output scp subsystem debugging info to stderr */ /* Output scp subsystem debugging info to stderr */
#undef LIBSSH2_DEBUG_SCP #undef LIBSSH2_DEBUG_SCP

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org> /* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, * Redistribution and use in source and binary forms,
@@ -46,9 +46,19 @@
#include <sys/socket.h> #include <sys/socket.h>
#endif #endif
#include <openssl/evp.h> #include <openssl/evp.h>
#ifndef OPENSSL_NO_SHA
#include <openssl/sha.h>
#endif
#ifndef OPENSSL_NO_MD5
#include <openssl/md5.h>
#endif
#ifdef __hpux
# define inline
#endif
#define LIBSSH2_ALLOC(session, count) session->alloc((count), &(session)->abstract) #define LIBSSH2_ALLOC(session, count) session->alloc((count), &(session)->abstract)
#define LIBSSH2_REALLOC(session, ptr, count) session->realloc((ptr), (count), &(session)->abstract) #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_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_IGNORE(session, data, datalen) session->ssh_msg_ignore((session), (data), (datalen), &(session)->abstract)
@@ -112,6 +122,9 @@ struct _LIBSSH2_CHANNEL {
int blocking; int blocking;
/* channel's program exit status */
int exit_status;
libssh2_channel_data local, remote; libssh2_channel_data local, remote;
unsigned long adjust_queue; /* Amount of bytes to be refunded to receive window (but not yet sent) */ unsigned long adjust_queue; /* Amount of bytes to be refunded to receive window (but not yet sent) */
@@ -186,6 +199,7 @@ struct _LIBSSH2_SESSION {
/* Agreed Key Exchange Method */ /* Agreed Key Exchange Method */
LIBSSH2_KEX_METHOD *kex; LIBSSH2_KEX_METHOD *kex;
int burn_optimistic_kexinit:1;
unsigned char *session_id; unsigned char *session_id;
unsigned long session_id_len; unsigned long session_id_len;
@@ -264,7 +278,7 @@ struct _LIBSSH2_HOSTKEY_METHOD {
unsigned long hash_len; unsigned long hash_len;
int (*init)(LIBSSH2_SESSION *session, unsigned char *hostkey_data, unsigned long hostkey_data_len, void **abstract); int (*init)(LIBSSH2_SESSION *session, unsigned char *hostkey_data, unsigned long hostkey_data_len, void **abstract);
int (*initPEM)(LIBSSH2_SESSION *session, unsigned char *privkeyfile, unsigned char *passphrase, void **abstract); int (*initPEM)(LIBSSH2_SESSION *session, unsigned const char *privkeyfile, unsigned const char *passphrase, void **abstract);
int (*sig_verify)(LIBSSH2_SESSION *session, const unsigned char *sig, unsigned long sig_len, const unsigned char *m, unsigned long m_len, void **abstract); int (*sig_verify)(LIBSSH2_SESSION *session, const unsigned char *sig, unsigned long sig_len, const unsigned char *m, unsigned long m_len, void **abstract);
int (*sign)(LIBSSH2_SESSION *session, unsigned char **signature, unsigned long *signature_len, const unsigned char *data, unsigned long data_len, void **abstract); int (*sign)(LIBSSH2_SESSION *session, unsigned char **signature, unsigned long *signature_len, const unsigned char *data, unsigned long data_len, void **abstract);
int (*signv)(LIBSSH2_SESSION *session, unsigned char **signature, unsigned long *signature_len, unsigned long veccount, const struct iovec datavec[], void **abstract); int (*signv)(LIBSSH2_SESSION *session, unsigned char **signature, unsigned long *signature_len, unsigned long veccount, const struct iovec datavec[], void **abstract);
@@ -329,6 +343,7 @@ struct _LIBSSH2_MAC_METHOD {
#define LIBSSH2_DBG_SCP 5 #define LIBSSH2_DBG_SCP 5
#define LIBSSH2_DBG_SFTP 6 #define LIBSSH2_DBG_SFTP 6
#define LIBSSH2_DBG_ERROR 7 #define LIBSSH2_DBG_ERROR 7
#define LIBSSH2_DBG_PUBLICKEY 8
void _libssh2_debug(LIBSSH2_SESSION *session, int context, const char *format, ...); void _libssh2_debug(LIBSSH2_SESSION *session, int context, const char *format, ...);
@@ -407,6 +422,9 @@ void _libssh2_debug(LIBSSH2_SESSION *session, int context, const char *format, .
#define SSH_MSG_USERAUTH_PK_OK 60 #define SSH_MSG_USERAUTH_PK_OK 60
/* "password" method */ /* "password" method */
#define SSH_MSG_USERAUTH_PASSWD_CHANGEREQ 60 #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 */ /* Channels */
#define SSH_MSG_GLOBAL_REQUEST 80 #define SSH_MSG_GLOBAL_REQUEST 80
@@ -445,6 +463,7 @@ int libssh2_packet_require_ex(LIBSSH2_SESSION *session, unsigned char packet_typ
int libssh2_packet_requirev_ex(LIBSSH2_SESSION *session, unsigned char *packet_types, unsigned char **data, unsigned long *data_len, unsigned long match_ofs, const unsigned char *match_buf, unsigned long match_len); int libssh2_packet_requirev_ex(LIBSSH2_SESSION *session, unsigned char *packet_types, unsigned char **data, unsigned long *data_len, unsigned long match_ofs, const unsigned char *match_buf, unsigned long match_len);
#define libssh2_packet_requirev(session, packet_types, data, data_len) \ #define libssh2_packet_requirev(session, packet_types, data, data_len) \
libssh2_packet_requirev_ex((session), (packet_types), (data), (data_len), 0, NULL, 0) libssh2_packet_requirev_ex((session), (packet_types), (data), (data_len), 0, NULL, 0)
int libssh2_packet_burn(LIBSSH2_SESSION *session);
int libssh2_packet_write(LIBSSH2_SESSION *session, unsigned char *data, unsigned long data_len); int libssh2_packet_write(LIBSSH2_SESSION *session, unsigned char *data, unsigned long data_len);
int libssh2_kex_exchange(LIBSSH2_SESSION *session, int reexchange); int libssh2_kex_exchange(LIBSSH2_SESSION *session, int reexchange);
unsigned long libssh2_channel_nextid(LIBSSH2_SESSION *session); unsigned long libssh2_channel_nextid(LIBSSH2_SESSION *session);

101
include/libssh2_publickey.h Normal file
View File

@@ -0,0 +1,101 @@
/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
* 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
typedef struct _LIBSSH2_PUBLICKEY LIBSSH2_PUBLICKEY;
typedef struct _libssh2_publickey_attribute {
char *name;
unsigned long name_len;
char *value;
unsigned long value_len;
char mandatory;
} libssh2_publickey_attribute;
typedef struct _libssh2_publickey_list {
unsigned char *packet; /* For freeing */
unsigned char *name;
unsigned long name_len;
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, 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 void libssh2_publickey_shutdown(LIBSSH2_PUBLICKEY *pkey);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* ndef: LIBSSH2_PUBLICKEY_H */

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org> /* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, * Redistribution and use in source and binary forms,
@@ -38,6 +38,10 @@
#ifndef LIBSSH2_SFTP_H #ifndef LIBSSH2_SFTP_H
#define LIBSSH2_SFTP_H 1 #define LIBSSH2_SFTP_H 1
#ifdef __cplusplus
extern "C" {
#endif
/* Note: Version 6 was documented at the time of writing /* Note: Version 6 was documented at the time of writing
* However it was marked as "DO NOT IMPLEMENT" due to pending changes * However it was marked as "DO NOT IMPLEMENT" due to pending changes
* *
@@ -187,4 +191,8 @@ LIBSSH2_API int libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, const char *path, in
#define libssh2_sftp_readlink(sftp, path, target, maxlen) libssh2_sftp_symlink_ex((sftp), (path), strlen(path), (target), (maxlen), LIBSSH2_SFTP_READLINK) #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) #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 */ #endif /* LIBSSH2_SFTP_H */

View File

@@ -1,4 +1,4 @@
OBJECTS = channel.o comp.o crypt.o hostkey.o kex.o mac.o misc.o packet.o scp.o session.o sftp.o userauth.o OBJECTS = channel.o comp.o crypt.o hostkey.o kex.o mac.o misc.o packet.o publickey.o scp.o session.o sftp.o userauth.o
top_srcdir = @top_srcdir@ top_srcdir = @top_srcdir@
prefix = @prefix@ prefix = @prefix@
@@ -7,8 +7,10 @@ libdir = @exec_prefix@/lib
incldir = @prefix@/include incldir = @prefix@/include
CC = @CC@ CC = @CC@
CFLAGS = -c @CFLAGS@ -Wall -g -I../include/ -fPIC LDCC = @LDCC@
CFLAGS = -c @CFLAGS@ -Wall -I../include/ -fPIC
LDFLAGS = @LDFLAGS@ LDFLAGS = @LDFLAGS@
SHLIB_LDFLAGS = @SHLIB_LDFLAGS@
LIBS = @LIBS@ LIBS = @LIBS@
INSTALL = @INSTALL@ INSTALL = @INSTALL@
@@ -36,6 +38,9 @@ misc.o: misc.c
packet.o: packet.c packet.o: packet.c
$(CC) -o packet.o packet.c $(CFLAGS) $(LIBS) $(CC) -o packet.o packet.c $(CFLAGS) $(LIBS)
publickey.o: publickey.c
$(CC) -o publickey.o publickey.c $(CFLAGS) $(LIBS)
scp.o: scp.c scp.o: scp.c
$(CC) -o scp.o scp.c $(CFLAGS) $(LIBS) $(CC) -o scp.o scp.c $(CFLAGS) $(LIBS)
@@ -51,7 +56,7 @@ userauth.o: userauth.c
all: libssh2.@SHLIB_SUFFIX_NAME@ all: libssh2.@SHLIB_SUFFIX_NAME@
libssh2.@SHLIB_SUFFIX_NAME@: $(OBJECTS) libssh2.@SHLIB_SUFFIX_NAME@: $(OBJECTS)
$(CC) -o libssh2.@SHLIB_SUFFIX_NAME@ $(SHLIB_LDFLAGS) $(OBJECTS) $(LIBS) $(LDFLAGS) @SHLIB_LDFLAGS@ $(LDCC) -o libssh2.@SHLIB_SUFFIX_NAME@ $(SHLIB_LDFLAGS) $(OBJECTS) $(LIBS) $(LDFLAGS)
libssh2.a: $(OBJECTS) libssh2.a: $(OBJECTS)
rm -f libssh2.a rm -f libssh2.a
ar q libssh2.a $(OBJECTS) ar q libssh2.a $(OBJECTS)

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org> /* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, * Redistribution and use in source and binary forms,
@@ -99,14 +99,14 @@ LIBSSH2_CHANNEL *libssh2_channel_locate(LIBSSH2_SESSION *session, unsigned long
} \ } \
(channel)->next = NULL; \ (channel)->next = NULL; \
(session)->channels.tail = (channel); \ (session)->channels.tail = (channel); \
(channel)->session = (session); \ (channel)->session = (session); \
} }
/* {{{ libssh2_channel_open_session /* {{{ libssh2_channel_open_session
* Establish a generic session channel * Establish a generic session channel
*/ */
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_open_ex(LIBSSH2_SESSION *session, char *channel_type, int channel_type_len, int window_size, int packet_size, LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_open_ex(LIBSSH2_SESSION *session, const char *channel_type, int channel_type_len, int window_size, int packet_size,
char *message, int message_len) const char *message, int message_len)
{ {
unsigned char reply_codes[3] = { SSH_MSG_CHANNEL_OPEN_CONFIRMATION, SSH_MSG_CHANNEL_OPEN_FAILURE, 0 }; unsigned char reply_codes[3] = { SSH_MSG_CHANNEL_OPEN_CONFIRMATION, SSH_MSG_CHANNEL_OPEN_FAILURE, 0 };
LIBSSH2_CHANNEL *channel = NULL; LIBSSH2_CHANNEL *channel = NULL;
@@ -598,8 +598,8 @@ LIBSSH2_API int libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL *channel, int single_
unsigned long data_len; unsigned long data_len;
unsigned long proto_len = auth_proto ? strlen(auth_proto) : (sizeof("MIT-MAGIC-COOKIE-1") - 1); unsigned long proto_len = auth_proto ? strlen(auth_proto) : (sizeof("MIT-MAGIC-COOKIE-1") - 1);
unsigned long cookie_len = auth_cookie ? strlen(auth_cookie) : LIBSSH2_X11_RANDOM_COOKIE_LEN; unsigned long cookie_len = auth_cookie ? strlen(auth_cookie) : LIBSSH2_X11_RANDOM_COOKIE_LEN;
unsigned long packet_len = proto_len + cookie_len + 41; /* packet_type(1) + channel(4) + x11_req_len(4) + "x11-req"(7) + want_reply(1) + unsigned long packet_len = proto_len + cookie_len + 30; /* packet_type(1) + channel(4) + x11_req_len(4) + "x11-req"(7) + want_reply(1) +
single_cnx(4) + proto_len(4) + cookie_len(4) + screen_num(4) */ single_cnx(1) + proto_len(4) + cookie_len(4) + screen_num(4) */
#ifdef LIBSSH2_DEBUG_CONNECTION #ifdef LIBSSH2_DEBUG_CONNECTION
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Requesting x11-req for channel %lu/%lu: single=%d proto=%s cookie=%s screen=%d", _libssh2_debug(session, LIBSSH2_DBG_CONN, "Requesting x11-req for channel %lu/%lu: single=%d proto=%s cookie=%s screen=%d",
@@ -626,7 +626,7 @@ LIBSSH2_API int libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL *channel, int single_
memcpy(s, auth_proto ? auth_proto : "MIT-MAGIC-COOKIE-1", proto_len); memcpy(s, auth_proto ? auth_proto : "MIT-MAGIC-COOKIE-1", proto_len);
s += proto_len; s += proto_len;
libssh2_htonu32(s, cookie_len); libssh2_htonu32(s, cookie_len); s += 4;
if (auth_cookie) { if (auth_cookie) {
memcpy(s, auth_cookie, cookie_len); memcpy(s, auth_cookie, cookie_len);
} else { } else {
@@ -643,14 +643,19 @@ LIBSSH2_API int libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL *channel, int single_
libssh2_htonu32(s, screen_number); s += 4; libssh2_htonu32(s, screen_number); s += 4;
if (libssh2_packet_write(session, packet, packet_len)) { if (libssh2_packet_write(session, packet, packet_len)) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send pty-request packet", 0); libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send x11-req packet", 0);
LIBSSH2_FREE(session, packet); LIBSSH2_FREE(session, packet);
return -1; return -1;
} }
LIBSSH2_FREE(session, packet); LIBSSH2_FREE(session, packet);
libssh2_htonu32(local_channel, channel->local.id); libssh2_htonu32(local_channel, channel->local.id);
if (libssh2_packet_requirev_ex(session, reply_codes, &data, &data_len, 1, local_channel, 4)) { if (libssh2_packet_requirev_ex(session, reply_codes, &data, &data_len, 1, local_channel, 4)) {
return -1;
}
if (data[0] == SSH_MSG_CHANNEL_SUCCESS) {
LIBSSH2_FREE(session, data); LIBSSH2_FREE(session, data);
return 0; return 0;
} }
@@ -664,7 +669,7 @@ LIBSSH2_API int libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL *channel, int single_
/* {{{ libssh2_channel_process_startup /* {{{ libssh2_channel_process_startup
* Primitive for libssh2_channel_(shell|exec|subsystem) * Primitive for libssh2_channel_(shell|exec|subsystem)
*/ */
LIBSSH2_API int libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, char *request, int request_len, char *message, int message_len) LIBSSH2_API int libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, const char *request, int request_len, const char *message, int message_len)
{ {
LIBSSH2_SESSION *session = channel->session; LIBSSH2_SESSION *session = channel->session;
unsigned char *s, *packet, *data, reply_codes[3] = { SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 }, local_channel[4]; unsigned char *s, *packet, *data, reply_codes[3] = { SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 }, local_channel[4];
@@ -787,6 +792,16 @@ LIBSSH2_API int libssh2_channel_flush_ex(LIBSSH2_CHANNEL *channel, int streamid)
} }
/* }}} */ /* }}} */
/* {{{ libssh2_channel_get_exit_status
* Return the channel's program exit status
*/
LIBSSH2_API int libssh2_channel_get_exit_status(LIBSSH2_CHANNEL* channel)
{
return channel->exit_status;
}
/* }}} */
/* {{{ libssh2_channel_receive_window_adjust /* {{{ libssh2_channel_receive_window_adjust
* Adjust the receive window for a channel by adjustment bytes * 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 * If the amount to be adjusted is less than LIBSSH2_CHANNEL_MINADJUST and force is 0
@@ -1089,6 +1104,7 @@ LIBSSH2_API int libssh2_channel_close(LIBSSH2_CHANNEL *channel)
if (channel->close_cb) { if (channel->close_cb) {
LIBSSH2_CHANNEL_CLOSE(session, channel); LIBSSH2_CHANNEL_CLOSE(session, channel);
} }
channel->local.close = 1;
packet[0] = SSH_MSG_CHANNEL_CLOSE; packet[0] = SSH_MSG_CHANNEL_CLOSE;
libssh2_htonu32(packet + 1, channel->remote.id); libssh2_htonu32(packet + 1, channel->remote.id);
@@ -1096,7 +1112,6 @@ LIBSSH2_API int libssh2_channel_close(LIBSSH2_CHANNEL *channel)
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send close-channel request", 0); libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send close-channel request", 0);
return -1; return -1;
} }
channel->local.close = 1;
/* TODO: Wait up to a timeout value for a CHANNEL_CLOSE to come back, to avoid the problem alluded to in channel_nextid */ /* TODO: Wait up to a timeout value for a CHANNEL_CLOSE to come back, to avoid the problem alluded to in channel_nextid */
@@ -1104,6 +1119,35 @@ LIBSSH2_API int libssh2_channel_close(LIBSSH2_CHANNEL *channel)
} }
/* }}} */ /* }}} */
/* {{{ libssh2_channel_wait_closed
* Awaiting channel close after EOF
*/
LIBSSH2_API int libssh2_channel_wait_closed(LIBSSH2_CHANNEL *channel)
{
LIBSSH2_SESSION* session = channel->session;
if (!libssh2_channel_eof(channel)) {
libssh2_error(session, LIBSSH2_ERROR_INVAL, "libssh2_channel_wait_closed() invoked when channel is not in EOF state", 0);
return -1;
}
#ifdef LIBSSH2_DEBUG_CONNECTION
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Awaiting close of channel %lu/%lu", channel->local.id, channel->remote.id);
#endif
/* while channel is not closed, read more
* packets from the network.
* Either or channel will be closed
* or network timeout will occur
*/
while (!channel->remote.close && libssh2_packet_read(session, 1) > 0)
;
return 1;
}
/* }}} */
/* {{{ libssh2_channel_free /* {{{ libssh2_channel_free
* Make sure a channel is closed, then remove the channel from the session and free its resource(s) * Make sure a channel is closed, then remove the channel from the session and free its resource(s)
*/ */

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org> /* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, * Redistribution and use in source and binary forms,

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org> /* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, * Redistribution and use in source and binary forms,

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org> /* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, * Redistribution and use in source and binary forms,
@@ -109,7 +109,7 @@ static int libssh2_hostkey_method_ssh_rsadsa_passphrase_cb(char *buf, int size,
/* {{{ libssh2_hostkey_method_ssh_rsa_initPEM /* {{{ libssh2_hostkey_method_ssh_rsa_initPEM
* Load a Private Key from a PEM file * Load a Private Key from a PEM file
*/ */
static int libssh2_hostkey_method_ssh_rsa_initPEM(LIBSSH2_SESSION *session, unsigned char *privkeyfile, unsigned char *passphrase, void **abstract) static int libssh2_hostkey_method_ssh_rsa_initPEM(LIBSSH2_SESSION *session, unsigned const char *privkeyfile, unsigned const char *passphrase, void **abstract)
{ {
RSA *rsactx; RSA *rsactx;
FILE *fp; FILE *fp;
@@ -131,7 +131,7 @@ static int libssh2_hostkey_method_ssh_rsa_initPEM(LIBSSH2_SESSION *session, unsi
*/ */
OpenSSL_add_all_ciphers(); OpenSSL_add_all_ciphers();
} }
rsactx = PEM_read_RSAPrivateKey(fp, NULL, (void*)libssh2_hostkey_method_ssh_rsadsa_passphrase_cb, passphrase); rsactx = PEM_read_RSAPrivateKey(fp, NULL, (void*)libssh2_hostkey_method_ssh_rsadsa_passphrase_cb, (void*)passphrase);
if (!rsactx) { if (!rsactx) {
fclose(fp); fclose(fp);
return -1; return -1;
@@ -323,7 +323,7 @@ static int libssh2_hostkey_method_ssh_dss_init(LIBSSH2_SESSION *session, unsigne
/* {{{ libssh2_hostkey_method_ssh_dss_initPEM /* {{{ libssh2_hostkey_method_ssh_dss_initPEM
* Load a Private Key from a PEM file * Load a Private Key from a PEM file
*/ */
static int libssh2_hostkey_method_ssh_dss_initPEM(LIBSSH2_SESSION *session, unsigned char *privkeyfile, unsigned char *passphrase, void **abstract) static int libssh2_hostkey_method_ssh_dss_initPEM(LIBSSH2_SESSION *session, unsigned const char *privkeyfile, unsigned const char *passphrase, void **abstract)
{ {
DSA *dsactx; DSA *dsactx;
FILE *fp; FILE *fp;
@@ -345,7 +345,7 @@ static int libssh2_hostkey_method_ssh_dss_initPEM(LIBSSH2_SESSION *session, unsi
*/ */
OpenSSL_add_all_ciphers(); OpenSSL_add_all_ciphers();
} }
dsactx = PEM_read_DSAPrivateKey(fp, NULL, (void*)libssh2_hostkey_method_ssh_rsadsa_passphrase_cb, passphrase); dsactx = PEM_read_DSAPrivateKey(fp, NULL, (void*)libssh2_hostkey_method_ssh_rsadsa_passphrase_cb, (void*)passphrase);
if (!dsactx) { if (!dsactx) {
fclose(fp); fclose(fp);
return -1; return -1;
@@ -523,7 +523,7 @@ LIBSSH2_HOSTKEY_METHOD **libssh2_hostkey_methods(void)
* Length of buffer is determined by hash type * Length of buffer is determined by hash type
* i.e. MD5 == 16, SHA1 == 20 * i.e. MD5 == 16, SHA1 == 20
*/ */
LIBSSH2_API char *libssh2_hostkey_hash(LIBSSH2_SESSION *session, int hash_type) LIBSSH2_API const char *libssh2_hostkey_hash(LIBSSH2_SESSION *session, int hash_type)
{ {
switch (hash_type) { switch (hash_type) {
#ifndef OPENSSL_NO_MD5 #ifndef OPENSSL_NO_MD5

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org> /* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, * Redistribution and use in source and binary forms,
@@ -68,7 +68,7 @@
/* {{{ libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange /* {{{ libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange
* Diffie Hellman Key Exchange, Group Agnostic * Diffie Hellman Key Exchange, Group Agnostic
*/ */
static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *session, BIGNUM *g, BIGNUM *p, static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *session, BIGNUM *g, BIGNUM *p, int group_order,
unsigned char packet_type_init, unsigned char packet_type_reply, unsigned char packet_type_init, unsigned char packet_type_reply,
unsigned char *midhash, unsigned long midhash_len) unsigned char *midhash, unsigned long midhash_len)
{ {
@@ -85,7 +85,7 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
SHA_CTX exchange_hash; SHA_CTX exchange_hash;
/* Generate x and e */ /* Generate x and e */
BN_rand(x, 128, 0, -1); BN_rand(x, group_order, 0, -1);
BN_mod_exp(e, g, x, p, ctx); BN_mod_exp(e, g, x, p, ctx);
/* Send KEX init */ /* Send KEX init */
@@ -118,6 +118,26 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
goto clean_exit; goto clean_exit;
} }
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;
#ifdef LIBSSH2_DEBUG_KEX
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Waiting for badly guessed KEX packet (to be ignored)");
#endif
burn_type = libssh2_packet_burn(session);
if (burn_type <= 0) {
/* Failed to receive a packet */
ret = -1;
goto clean_exit;
}
session->burn_optimistic_kexinit = 0;
#ifdef LIBSSH2_DEBUG_KEX
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Burnt packet of type: %02x", (unsigned int)burn_type);
#endif
}
/* Wait for KEX reply */ /* Wait for KEX reply */
if (libssh2_packet_require(session, packet_type_reply, &s_packet, &s_packet_len)) { if (libssh2_packet_require(session, packet_type_reply, &s_packet, &s_packet_len)) {
libssh2_error(session, LIBSSH2_ERROR_TIMEOUT, "Timed out waiting for KEX reply", 0); libssh2_error(session, LIBSSH2_ERROR_TIMEOUT, "Timed out waiting for KEX reply", 0);
@@ -314,6 +334,7 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
/* Calculate IV/Secret/Key for each direction */ /* Calculate IV/Secret/Key for each direction */
if (session->local.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) { if (session->local.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) {
if (session->local.crypt_abstract) { if (session->local.crypt_abstract) {
EVP_CIPHER_CTX_cleanup(session->local.crypt_abstract);
LIBSSH2_FREE(session, session->local.crypt_abstract); LIBSSH2_FREE(session, session->local.crypt_abstract);
session->local.crypt_abstract = NULL; session->local.crypt_abstract = NULL;
} }
@@ -342,6 +363,7 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
ret = -1; ret = -1;
goto clean_exit; goto clean_exit;
} }
EVP_CIPHER_CTX_init(ctx);
EVP_CipherInit(ctx, cipher, secret, iv, 1); EVP_CipherInit(ctx, cipher, secret, iv, 1);
session->local.crypt_abstract = ctx; session->local.crypt_abstract = ctx;
free_iv = 1; free_iv = 1;
@@ -366,6 +388,7 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
if (session->remote.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) { if (session->remote.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) {
if (session->remote.crypt_abstract) { if (session->remote.crypt_abstract) {
EVP_CIPHER_CTX_cleanup(session->remote.crypt_abstract);
LIBSSH2_FREE(session, session->remote.crypt_abstract); LIBSSH2_FREE(session, session->remote.crypt_abstract);
session->remote.crypt_abstract = NULL; session->remote.crypt_abstract = NULL;
} }
@@ -394,6 +417,7 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
ret = -1; ret = -1;
goto clean_exit; goto clean_exit;
} }
EVP_CIPHER_CTX_init(ctx);
EVP_CipherInit(ctx, cipher, secret, iv, 0); EVP_CipherInit(ctx, cipher, secret, iv, 0);
session->remote.crypt_abstract = ctx; session->remote.crypt_abstract = ctx;
free_iv = 1; free_iv = 1;
@@ -518,7 +542,7 @@ static int libssh2_kex_method_diffie_hellman_group1_sha1_key_exchange(LIBSSH2_SE
#ifdef LIBSSH2_DEBUG_KEX #ifdef LIBSSH2_DEBUG_KEX
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Initiating Diffie-Hellman Group1 Key Exchange"); _libssh2_debug(session, LIBSSH2_DBG_KEX, "Initiating Diffie-Hellman Group1 Key Exchange");
#endif #endif
ret = libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(session, g, p, SSH_MSG_KEXDH_INIT, SSH_MSG_KEXDH_REPLY, NULL, 0); ret = libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(session, g, p, 128, SSH_MSG_KEXDH_INIT, SSH_MSG_KEXDH_REPLY, NULL, 0);
BN_clear_free(p); BN_clear_free(p);
BN_clear_free(g); BN_clear_free(g);
@@ -577,7 +601,7 @@ static int libssh2_kex_method_diffie_hellman_group14_sha1_key_exchange(LIBSSH2_S
#ifdef LIBSSH2_DEBUG_KEX #ifdef LIBSSH2_DEBUG_KEX
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Initiating Diffie-Hellman Group14 Key Exchange"); _libssh2_debug(session, LIBSSH2_DBG_KEX, "Initiating Diffie-Hellman Group14 Key Exchange");
#endif #endif
ret = libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(session, g, p, SSH_MSG_KEXDH_INIT, SSH_MSG_KEXDH_REPLY, NULL, 0); ret = libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(session, g, p, 256, SSH_MSG_KEXDH_INIT, SSH_MSG_KEXDH_REPLY, NULL, 0);
BN_clear_free(p); BN_clear_free(p);
BN_clear_free(g); BN_clear_free(g);
@@ -593,7 +617,7 @@ static int libssh2_kex_method_diffie_hellman_group14_sha1_key_exchange(LIBSSH2_S
static int libssh2_kex_method_diffie_hellman_group_exchange_sha1_key_exchange(LIBSSH2_SESSION *session) static int libssh2_kex_method_diffie_hellman_group_exchange_sha1_key_exchange(LIBSSH2_SESSION *session)
{ {
unsigned char request[13], *s, *data; unsigned char request[13], *s, *data;
unsigned long data_len, len, request_len; unsigned long data_len, p_len, g_len, request_len;
BIGNUM *p = BN_new(); BIGNUM *p = BN_new();
BIGNUM *g = BN_new(); BIGNUM *g = BN_new();
int ret; int ret;
@@ -630,13 +654,13 @@ static int libssh2_kex_method_diffie_hellman_group_exchange_sha1_key_exchange(LI
} }
s = data + 1; s = data + 1;
len = libssh2_ntohu32(s); s += 4; p_len = libssh2_ntohu32(s); s += 4;
BN_bin2bn(s, len, p); s += len; BN_bin2bn(s, p_len, p); s += p_len;
len = libssh2_ntohu32(s); s += 4; g_len = libssh2_ntohu32(s); s += 4;
BN_bin2bn(s, len, g); s += len; BN_bin2bn(s, g_len, g); s += g_len;
ret = libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(session, g, p, SSH_MSG_KEX_DH_GEX_INIT, SSH_MSG_KEX_DH_GEX_REPLY, data + 1, data_len - 1); ret = libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(session, g, p, p_len, SSH_MSG_KEX_DH_GEX_INIT, SSH_MSG_KEX_DH_GEX_REPLY, data + 1, data_len - 1);
LIBSSH2_FREE(session, data); LIBSSH2_FREE(session, data);
@@ -963,9 +987,9 @@ static int libssh2_kex_agree_kex_hostkey(LIBSSH2_SESSION *session, unsigned char
s = session->kex_prefs; s = session->kex_prefs;
while (s && *s) { while (s && *s) {
unsigned char *p = strchr(s, ','); unsigned char *q, *p = strchr(s, ',');
int method_len = (p ? (p - s) : strlen(s)); int method_len = (p ? (p - s) : strlen(s));
if (libssh2_kex_agree_instr(kex, kex_len, s, method_len)) { if ((q = libssh2_kex_agree_instr(kex, kex_len, s, method_len))) {
LIBSSH2_KEX_METHOD *method = (LIBSSH2_KEX_METHOD*)libssh2_get_method_by_name(s, method_len, (LIBSSH2_COMMON_METHOD**)kexp); LIBSSH2_KEX_METHOD *method = (LIBSSH2_KEX_METHOD*)libssh2_get_method_by_name(s, method_len, (LIBSSH2_COMMON_METHOD**)kexp);
if (!method) { if (!method) {
@@ -978,6 +1002,12 @@ static int libssh2_kex_agree_kex_hostkey(LIBSSH2_SESSION *session, unsigned char
*/ */
if (libssh2_kex_agree_hostkey(session, method->flags, hostkey, hostkey_len) == 0) { if (libssh2_kex_agree_hostkey(session, method->flags, hostkey, hostkey_len) == 0) {
session->kex = method; 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; return 0;
} }
} }
@@ -995,6 +1025,12 @@ static int libssh2_kex_agree_kex_hostkey(LIBSSH2_SESSION *session, unsigned char
*/ */
if (libssh2_kex_agree_hostkey(session, (*kexp)->flags, hostkey, hostkey_len) == 0) { if (libssh2_kex_agree_hostkey(session, (*kexp)->flags, hostkey, hostkey_len) == 0) {
session->kex = *kexp; 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; return 0;
} }
} }
@@ -1170,6 +1206,12 @@ static int libssh2_kex_agree_methods(LIBSSH2_SESSION *session, unsigned char *da
lang_cs_len = libssh2_ntohu32(s); lang_cs = s + 4; s += 4 + lang_cs_len; lang_cs_len = libssh2_ntohu32(s); lang_cs = s + 4; s += 4 + lang_cs_len;
lang_sc_len = libssh2_ntohu32(s); lang_sc = s + 4; s += 4 + lang_sc_len; lang_sc_len = libssh2_ntohu32(s); lang_sc = s + 4; s += 4 + lang_sc_len;
/* If the server sent an optimistic packet, assume that it guessed wrong.
* If the guess is determined to be right (by libssh2_kex_agree_kex_hostkey)
* This flag will be reset to zero so that it's not ignored */
session->burn_optimistic_kexinit = *(s++);
/* Next uint32 in packet is all zeros (reserved) */
if (libssh2_kex_agree_kex_hostkey(session, kex, kex_len, hostkey, hostkey_len)) { if (libssh2_kex_agree_kex_hostkey(session, kex, kex_len, hostkey, hostkey_len)) {
return -1; return -1;
} }
@@ -1244,7 +1286,23 @@ int libssh2_kex_exchange(LIBSSH2_SESSION *session, int reexchange) /* session->f
} }
if (!session->kex || !session->hostkey) { if (!session->kex || !session->hostkey) {
/* Preserve in case of failure */
unsigned char *oldlocal = session->local.kexinit;
unsigned long oldlocal_len = session->local.kexinit_len;
session->local.kexinit = NULL;
if (libssh2_kexinit(session)) {
session->local.kexinit = oldlocal;
session->local.kexinit_len = oldlocal_len;
return -1;
}
if (libssh2_packet_require(session, SSH_MSG_KEXINIT, &data, &data_len)) { if (libssh2_packet_require(session, SSH_MSG_KEXINIT, &data, &data_len)) {
if (session->local.kexinit) {
LIBSSH2_FREE(session, session->local.kexinit);
}
session->local.kexinit = oldlocal;
session->local.kexinit_len = oldlocal_len;
return -1; return -1;
} }
@@ -1254,10 +1312,6 @@ int libssh2_kex_exchange(LIBSSH2_SESSION *session, int reexchange) /* session->f
session->remote.kexinit = data; session->remote.kexinit = data;
session->remote.kexinit_len = data_len; session->remote.kexinit_len = data_len;
if (libssh2_kexinit(session)) {
return -1;
}
if (libssh2_kex_agree_methods(session, data, data_len)) { if (libssh2_kex_agree_methods(session, data, data_len)) {
return -1; return -1;
} }
@@ -1287,7 +1341,7 @@ int libssh2_kex_exchange(LIBSSH2_SESSION *session, int reexchange) /* session->f
/* {{{ libssh2_session_method_pref /* {{{ libssh2_session_method_pref
* Set preferred method * Set preferred method
*/ */
LIBSSH2_API int libssh2_session_method_pref(LIBSSH2_SESSION *session, int method_type, char *prefs) LIBSSH2_API int libssh2_session_method_pref(LIBSSH2_SESSION *session, int method_type, const char *prefs)
{ {
char **prefvar, *s, *newprefs; char **prefvar, *s, *newprefs;
int prefs_len = strlen(prefs); int prefs_len = strlen(prefs);

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org> /* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, * Redistribution and use in source and binary forms,

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org> /* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, * Redistribution and use in source and binary forms,
@@ -179,9 +179,18 @@ void _libssh2_debug(LIBSSH2_SESSION *session, int context, const char *format, .
char buffer[1536]; char buffer[1536];
int len; int len;
va_list vargs; va_list vargs;
char *contexts[8] = { "Unknown", "Transport", "Key Exhange", "Userauth", "Connection", "scp", "SFTP", "Failure Event" }; char *contexts[9] = { "Unknown",
"Transport",
"Key Exhange",
"Userauth",
"Connection",
"scp",
"SFTP Subsystem",
"Failure Event",
"Publickey Subsystem",
};
if (context < 1 || context > 6) { if (context < 1 || context > 8) {
context = 0; context = 0;
} }

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org> /* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, * Redistribution and use in source and binary forms,
@@ -497,6 +497,26 @@ static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, siz
return 0; return 0;
} }
break; break;
case SSH_MSG_CHANNEL_REQUEST:
{
if (libssh2_ntohu32(data+5) == sizeof("exit-status") - 1
&& !memcmp("exit-status", data + 9, sizeof("exit-status") - 1)) {
/* we've got "exit-status" packet. Set the session value */
LIBSSH2_CHANNEL *channel = libssh2_channel_locate(session, libssh2_ntohu32(data+1));
if (channel) {
channel->exit_status = libssh2_ntohu32(data + 9 + sizeof("exit-status"));
#ifdef LIBSSH2_DEBUG_CONNECTION
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Exit status %lu received for channel %lu/%lu", channel->exit_status, channel->local.id, channel->remote.id);
#endif
}
LIBSSH2_FREE(session, data);
return 0;
}
}
break;
case SSH_MSG_CHANNEL_CLOSE: case SSH_MSG_CHANNEL_CLOSE:
{ {
LIBSSH2_CHANNEL *channel = libssh2_channel_locate(session, libssh2_ntohu32(data + 1)); LIBSSH2_CHANNEL *channel = libssh2_channel_locate(session, libssh2_ntohu32(data + 1));
@@ -620,9 +640,9 @@ static int libssh2_blocking_read(LIBSSH2_SESSION *session, unsigned char *buf, s
#ifdef WIN32 #ifdef WIN32
switch (WSAGetLastError()) { switch (WSAGetLastError()) {
case WSAEWOULDBLOCK: errno = EAGAIN; break; case WSAEWOULDBLOCK: errno = EAGAIN; break;
case WSAENOTSOCK: errno = EBADF; break;
case WSAENOTCONN: case WSAENOTCONN:
case WSAENOTSOCK: case WSAECONNABORTED: errno = ENOTCONN; break;
case WSAECONNABORTED: errno = EBADF; break;
case WSAEINTR: errno = EINTR; break; case WSAEINTR: errno = EINTR; break;
} }
#endif #endif
@@ -660,7 +680,7 @@ static int libssh2_blocking_read(LIBSSH2_SESSION *session, unsigned char *buf, s
if (errno == EINTR) { if (errno == EINTR) {
continue; continue;
} }
if ((errno == EBADF) || (errno == EIO)) { if ((errno == EBADF) || (errno == EIO) || (errno == ENOTCONN)) {
session->socket_state = LIBSSH2_SOCKET_DISCONNECTED; session->socket_state = LIBSSH2_SOCKET_DISCONNECTED;
} }
return -1; return -1;
@@ -842,9 +862,9 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
} }
} }
packet_type = payload[0];
libssh2_packet_add(session, payload, payload_len, macstate); libssh2_packet_add(session, payload, payload_len, macstate);
packet_type = payload[0];
} else { /* No cipher active */ } else { /* No cipher active */
unsigned char *payload; unsigned char *payload;
unsigned char buf[24]; unsigned char buf[24];
@@ -873,6 +893,10 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
payload_len = packet_length - padding_length - 1; /* padding_length(1) */ payload_len = packet_length - padding_length - 1; /* padding_length(1) */
payload = LIBSSH2_ALLOC(session, payload_len); payload = LIBSSH2_ALLOC(session, payload_len);
if (!payload) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for copy of plaintext data", 0);
return -1;
}
if (libssh2_blocking_read(session, payload, payload_len) < payload_len) { if (libssh2_blocking_read(session, payload, payload_len) < payload_len) {
return (session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) ? 0 : -1; return (session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) ? 0 : -1;
@@ -887,11 +911,11 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
break; break;
} }
packet_type = payload[0];
/* MACs don't exist in non-encrypted mode */ /* MACs don't exist in non-encrypted mode */
libssh2_packet_add(session, payload, payload_len, LIBSSH2_MAC_CONFIRMED); libssh2_packet_add(session, payload, payload_len, LIBSSH2_MAC_CONFIRMED);
session->remote.seqno++; session->remote.seqno++;
packet_type = payload[0];
} }
return packet_type; return packet_type;
} }
@@ -916,7 +940,7 @@ int libssh2_packet_ask_ex(LIBSSH2_SESSION *session, unsigned char packet_type, u
while (packet) { while (packet) {
if (packet->data[0] == packet_type && if (packet->data[0] == packet_type &&
(packet->data_len >= (match_ofs + match_len)) && (packet->data_len >= (match_ofs + match_len)) &&
(!match_buf || (strncmp(packet->data + match_ofs, match_buf, match_len) == 0))) { (!match_buf || (memcmp(packet->data + match_ofs, match_buf, match_len) == 0))) {
*data = packet->data; *data = packet->data;
*data_len = packet->data_len; *data_len = packet->data_len;
@@ -993,6 +1017,48 @@ int libssh2_packet_require_ex(LIBSSH2_SESSION *session, unsigned char packet_typ
} }
/* }}} */ /* }}} */
/* {{{ libssh2_packet_burn
* Loops libssh2_packet_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)
{
unsigned char *data;
unsigned long data_len;
char all_packets[255];
int i;
for(i = 1; i < 256; i++) all_packets[i - 1] = i;
if (libssh2_packet_askv_ex(session, all_packets, &data, &data_len, 0, NULL, 0, 0) == 0) {
i = data[0];
/* A packet was available in the packet brigade, burn it */
LIBSSH2_FREE(session, data);
return i;
}
#ifdef LIBSSH2_DEBUG_TRANSPORT
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Blocking until packet becomes available to burn");
#endif
while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
int ret = libssh2_packet_read(session, 1);
if (ret < 0) {
return -1;
}
if (ret == 0) continue;
/* Be lazy, let packet_ask pull it out of the brigade */
if (0 == libssh2_packet_ask_ex(session, ret, &data, &data_len, 0, NULL, 0, 0)) {
/* Smoke 'em if you got 'em */
LIBSSH2_FREE(session, data);
return ret;
}
}
/* Only reached if the socket died */
return -1;
}
/* }}} */
/* {{{ libssh2_packet_requirev /* {{{ libssh2_packet_requirev
* Loops libssh2_packet_read() until one of a list of packet types requested is available * Loops libssh2_packet_read() until one of a list of packet types requested is available
* SSH_DISCONNECT or a SOCKET_DISCONNECTED will cause a bailout * SSH_DISCONNECT or a SOCKET_DISCONNECTED will cause a bailout

728
src/publickey.c Normal file
View File

@@ -0,0 +1,728 @@
/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
* 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"
struct _LIBSSH2_PUBLICKEY {
LIBSSH2_CHANNEL *channel;
unsigned long version;
};
#define LIBSSH2_PUBLICKEY_VERSION 2
/* Numericised response codes -- Not IETF standard, just a 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;
char *name;
int name_len;
} LIBSSH2_PUBLICKEY_CODE_LIST;
static LIBSSH2_PUBLICKEY_CODE_LIST libssh2_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 LIBSSH2_PUBLICKEY_CODE_LIST libssh2_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 }
};
/* {{{ libssh2_publickey_status_error
* Format an error message from a status code
*/
#define LIBSSH2_PUBLICKEY_STATUS_TEXT_START "Publickey Subsystem Error: \""
#define LIBSSH2_PUBLICKEY_STATUS_TEXT_MID "\" Server Resports: \""
#define LIBSSH2_PUBLICKEY_STATUS_TEXT_END "\""
static void libssh2_publickey_status_error(LIBSSH2_PUBLICKEY *pkey, LIBSSH2_SESSION *session, int status, unsigned char *message, int message_len)
{
char *status_text;
int status_text_len;
char *m, *s;
int m_len;
/* 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) {
status_text = "unknown";
status_text_len = sizeof("unknown") - 1;
} else {
status_text = libssh2_publickey_status_codes[status].name;
status_text_len = libssh2_publickey_status_codes[status].name_len;
}
m_len = (sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_START) - 1) + status_text_len +
(sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_MID) - 1) + message_len +
(sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_END) - 1);
m = LIBSSH2_ALLOC(session, m_len + 1);
if (!m) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for status message", 0);
return;
}
s = m;
memcpy(s, LIBSSH2_PUBLICKEY_STATUS_TEXT_START, sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_START) - 1);
s += sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_START) - 1;
memcpy(s, status_text, status_text_len); s += status_text_len;
memcpy(s, LIBSSH2_PUBLICKEY_STATUS_TEXT_MID, sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_MID) - 1);
s += sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_MID) - 1;
memcpy(s, message, message_len); s += message_len;
memcpy(s, LIBSSH2_PUBLICKEY_STATUS_TEXT_END, sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_END) - 1);
s += sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_END);
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, m, 1);
}
/* }}} */
/* {{{ libssh2_publickey_packet_receive
* Read a packet from the subsystem
*/
static int libssh2_publickey_packet_receive(LIBSSH2_PUBLICKEY *pkey, unsigned char **data, unsigned long *data_len)
{
LIBSSH2_CHANNEL *channel = pkey->channel;
LIBSSH2_SESSION *session = channel->session;
unsigned char buffer[4];
unsigned long packet_len;
unsigned char *packet;
if (libssh2_channel_read(channel, buffer, 4) != 4) {
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Invalid response from publickey subsystem", 0);
return -1;
}
packet_len = libssh2_ntohu32(buffer);
packet = LIBSSH2_ALLOC(session, packet_len);
if (!packet) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate publickey response buffer", 0);
return -1;
}
if (libssh2_channel_read(channel, packet, packet_len) != packet_len) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for publickey subsystem response packet", 0);
LIBSSH2_FREE(session, packet);
return -1;
}
*data = packet;
*data_len = packet_len;
return 0;
}
/* }}} */
/* {{{ libssh2_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 libssh2_publickey_response_id(unsigned char **pdata, int data_len)
{
unsigned long response_len;
unsigned char *data = *pdata;
LIBSSH2_PUBLICKEY_CODE_LIST *codes = libssh2_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 (codes->name_len == response_len &&
strncmp(codes->name, data, response_len) == 0) {
*pdata = data + response_len;
return codes->code;
}
codes++;
}
return -1;
}
/* }}} */
/* {{{ libssh2_publickey_response_success
* Generic helper routine to wait for success response and nothing else
*/
static int libssh2_publickey_response_success(LIBSSH2_PUBLICKEY *pkey)
{
LIBSSH2_SESSION *session = pkey->channel->session;
unsigned char *data, *s;
unsigned long data_len, response;
while (1) {
if (libssh2_publickey_packet_receive(pkey, &data, &data_len)) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for response from publickey subsystem", 0);
return -1;
}
s = data;
if ((response = libssh2_publickey_response_id(&s, data_len)) < 0) {
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Invalid publickey subsystem response code", 0);
LIBSSH2_FREE(session, data);
return -1;
}
switch (response) {
case LIBSSH2_PUBLICKEY_RESPONSE_STATUS:
/* Error, or processing complete */
{
unsigned long status, descr_len, lang_len;
unsigned char *descr, *lang;
status = libssh2_ntohu32(s); s += 4;
descr_len = libssh2_ntohu32(s); s += 4;
descr = s; s += descr_len;
lang_len = libssh2_ntohu32(s); s += 4;
lang = s; s += lang_len;
if (s > data + data_len) {
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Malformed publickey subsystem packet", 0);
LIBSSH2_FREE(session, data);
return -1;
}
if (status == LIBSSH2_PUBLICKEY_SUCCESS) {
LIBSSH2_FREE(session, data);
return 0;
}
libssh2_publickey_status_error(pkey, session, status, descr, descr_len);
LIBSSH2_FREE(session, data);
return -1;
}
default:
/* Unknown/Unexpected */
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Unexpected publickey subsystem response, ignoring", 0);
LIBSSH2_FREE(session, data);
data = NULL;
}
}
/* never reached, but include `return` to silence compiler warnings */
return -1;
}
/* }}} */
/* *****************
* Publickey API *
***************** */
/* {{{ libssh2_publickey_init
* Startup the publickey subsystem
*/
LIBSSH2_API LIBSSH2_PUBLICKEY *libssh2_publickey_init(LIBSSH2_SESSION *session)
{
LIBSSH2_PUBLICKEY *pkey = NULL;
LIBSSH2_CHANNEL *channel = NULL;
unsigned char buffer[19];
/* packet_len(4) +
version_len(4) +
"version"(7) +
version_num(4) */
unsigned char *s, *data = NULL;
unsigned long data_len;
int response;
#ifdef LIBSSH2_DEBUG_PUBLICKEY
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Initializing publickey subsystem");
#endif
channel = libssh2_channel_open_session(session);
if (!channel) {
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, "Unable to startup channel", 0);
goto err_exit;
}
if (libssh2_channel_subsystem(channel, "publickey")) {
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, "Unable to request publickey subsystem", 0);
goto err_exit;
}
libssh2_channel_set_blocking(channel, 1);
libssh2_channel_handle_extended_data(channel, LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE);
pkey = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PUBLICKEY));
if (!pkey) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate a new publickey structure", 0);
goto err_exit;
}
pkey->channel = channel;
pkey->version = 0;
s = 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); s += 4;
#ifdef LIBSSH2_DEBUG_PUBLICKEY
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Sending publickey version packet advertising version %d support", (int)LIBSSH2_PUBLICKEY_VERSION);
#endif
if ((s - buffer) != libssh2_channel_write(channel, buffer, (s - buffer))) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send publickey version packet", 0);
goto err_exit;
}
while (1) {
if (libssh2_publickey_packet_receive(pkey, &data, &data_len)) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for response from publickey subsystem", 0);
goto err_exit;
}
s = data;
if ((response = libssh2_publickey_response_id(&s, data_len)) < 0) {
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Invalid publickey subsystem response code", 0);
goto err_exit;
}
switch (response) {
case LIBSSH2_PUBLICKEY_RESPONSE_STATUS:
/* Error */
{
unsigned long status, descr_len, lang_len;
unsigned char *descr, *lang;
status = libssh2_ntohu32(s); s += 4;
descr_len = libssh2_ntohu32(s); s += 4;
descr = s; s += descr_len;
lang_len = libssh2_ntohu32(s); s += 4;
lang = s; s += lang_len;
if (s > data + data_len) {
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Malformed publickey subsystem packet", 0);
goto err_exit;
}
libssh2_publickey_status_error(NULL, session, status, descr, descr_len);
goto err_exit;
}
case LIBSSH2_PUBLICKEY_RESPONSE_VERSION:
/* What we want */
pkey->version = libssh2_ntohu32(s);
if (pkey->version > LIBSSH2_PUBLICKEY_VERSION) {
#ifdef LIBSSH2_DEBUG_PUBLICKEY
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Truncating remote publickey version from %lu", pkey->version);
#endif
pkey->version = LIBSSH2_PUBLICKEY_VERSION;
}
#ifdef LIBSSH2_DEBUG_PUBLICKEY
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Enabling publickey subsystem version %lu", pkey->version);
#endif
LIBSSH2_FREE(session, data);
return pkey;
default:
/* Unknown/Unexpected */
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Unexpected publickey subsystem response, ignoring", 0);
LIBSSH2_FREE(session, data);
data = NULL;
}
}
/* Never reached except by direct goto */
err_exit:
if (channel) {
libssh2_channel_close(channel);
}
if (pkey) {
LIBSSH2_FREE(session, pkey);
}
if (data) {
LIBSSH2_FREE(session, data);
}
return NULL;
}
/* }}} */
/* {{{ 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, libssh2_publickey_attribute attrs[])
{
LIBSSH2_CHANNEL *channel = pkey->channel;
LIBSSH2_SESSION *session = channel->session;
unsigned char *packet = NULL, *s;
unsigned long i, packet_len = 19 + name_len + blob_len;
unsigned char *comment = NULL;
unsigned long comment_len = 0;
/* packet_len(4) +
add_len(4) +
"add"(3) +
name_len(4) +
{name}
blob_len(4) +
{blob} */
#ifdef LIBSSH2_DEBUG_PUBLICKEY
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Adding %s pubickey", name);
#endif
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 = 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) */
}
}
packet = LIBSSH2_ALLOC(session, packet_len);
if (!packet) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for publickey \"add\" packet", 0);
return -1;
}
s = packet;
libssh2_htonu32(s, packet_len - 4); s += 4;
libssh2_htonu32(s, sizeof("add") - 1); s += 4;
memcpy(s, "add", sizeof("add") - 1); s += sizeof("add") - 1;
if (pkey->version == 1) {
libssh2_htonu32(s, comment_len); s += 4;
if (comment) {
memcpy(s, comment, comment_len); s += comment_len;
}
libssh2_htonu32(s, name_len); s += 4;
memcpy(s, name, name_len); s += name_len;
libssh2_htonu32(s, blob_len); s += 4;
memcpy(s, blob, blob_len); s += blob_len;
} else {
/* Version == 2 */
libssh2_htonu32(s, name_len); s += 4;
memcpy(s, name, name_len); s += name_len;
libssh2_htonu32(s, blob_len); s += 4;
memcpy(s, blob, blob_len); s += blob_len;
*(s++) = overwrite ? 0xFF : 0;
libssh2_htonu32(s, num_attrs); s += 4;
for(i = 0; i < num_attrs; i++) {
libssh2_htonu32(s, attrs[i].name_len); s += 4;
memcpy(s, attrs[i].name, attrs[i].name_len); s += attrs[i].name_len;
libssh2_htonu32(s, attrs[i].value_len); s += 4;
memcpy(s, attrs[i].value, attrs[i].value_len); s += attrs[i].value_len;
*(s++) = attrs[i].mandatory ? 0xFF : 0;
}
}
#ifdef LIBSSH2_DEBUG_PUBLICKEY
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Sending publickey \"add\" packet: type=%s blob_len=%ld num_attrs=%ld", name, blob_len, num_attrs);
#endif
if ((s - packet) != libssh2_channel_write(channel, packet, (s - packet))) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send publickey add packet", 0);
LIBSSH2_FREE(session, packet);
return -1;
}
LIBSSH2_FREE(session, packet);
packet = NULL;
return libssh2_publickey_response_success(pkey);
}
/* }}} */
/* {{{ 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 = pkey->channel;
LIBSSH2_SESSION *session = channel->session;
unsigned char *s, *packet = NULL;
unsigned long packet_len = 22 + name_len + blob_len;
/* packet_len(4) +
remove_len(4) +
"remove"(6) +
name_len(4) +
{name}
blob_len(4) +
{blob} */
packet = LIBSSH2_ALLOC(session, packet_len);
if (!packet) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for publickey \"remove\" packet", 0);
return -1;
}
s = packet;
libssh2_htonu32(s, packet_len - 4); s += 4;
libssh2_htonu32(s, sizeof("remove") - 1); s += 4;
memcpy(s, "remove", sizeof("remove") - 1); s += sizeof("remove") - 1;
libssh2_htonu32(s, name_len); s += 4;
memcpy(s, name, name_len); s += name_len;
libssh2_htonu32(s, blob_len); s += 4;
memcpy(s, blob, blob_len); s += blob_len;
#ifdef LIBSSH2_DEBUG_PUBLICKEY
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Sending publickey \"remove\" packet: type=%s blob_len=%ld", name, blob_len);
#endif
if ((s - packet) != libssh2_channel_write(channel, packet, (s - packet))) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send publickey remove packet", 0);
LIBSSH2_FREE(session, packet);
return -1;
}
LIBSSH2_FREE(session, packet);
packet = NULL;
return libssh2_publickey_response_success(pkey);
}
/* }}} */
/* {{{ 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 = pkey->channel;
LIBSSH2_SESSION *session = channel->session;
libssh2_publickey_list *list = NULL;
unsigned char *s, buffer[12], *data = NULL;
unsigned long buffer_len = 12, keys = 0, max_keys = 0, data_len, i, response;
/* packet_len(4) +
list_len(4) +
"list"(4) */
s = buffer;
libssh2_htonu32(s, buffer_len - 4); s += 4;
libssh2_htonu32(s, sizeof("list") - 1); s += 4;
memcpy(s, "list", sizeof("list") - 1); s += sizeof("list") - 1;
#ifdef LIBSSH2_DEBUG_PUBLICKEY
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Sending publickey \"list\" packet");
#endif
if ((s - buffer) != libssh2_channel_write(channel, buffer, (s - buffer))) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send publickey list packet", 0);
return -1;
}
while (1) {
if (libssh2_publickey_packet_receive(pkey, &data, &data_len)) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for response from publickey subsystem", 0);
goto err_exit;
}
s = data;
if ((response = libssh2_publickey_response_id(&s, data_len)) < 0) {
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Invalid publickey subsystem response code", 0);
goto err_exit;
}
switch (response) {
case LIBSSH2_PUBLICKEY_RESPONSE_STATUS:
/* Error, or processing complete */
{
unsigned long status, descr_len, lang_len;
unsigned char *descr, *lang;
status = libssh2_ntohu32(s); s += 4;
descr_len = libssh2_ntohu32(s); s += 4;
descr = s; s += descr_len;
lang_len = libssh2_ntohu32(s); s += 4;
lang = s; s += lang_len;
if (s > data + data_len) {
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Malformed publickey subsystem packet", 0);
goto err_exit;
}
if (status == LIBSSH2_PUBLICKEY_SUCCESS) {
LIBSSH2_FREE(session, data);
*pkey_list = list;
*num_keys = keys;
return 0;
}
libssh2_publickey_status_error(pkey, session, status, descr, descr_len);
goto err_exit;
}
case LIBSSH2_PUBLICKEY_RESPONSE_PUBLICKEY:
/* What we want */
if (keys >= max_keys) {
/* Grow the key list if necessary */
max_keys += 8;
list = LIBSSH2_REALLOC(session, list, (max_keys + 1) * sizeof(libssh2_publickey_list));
if (!list) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for publickey list", 0);
goto err_exit;
}
}
if (pkey->version == 1) {
unsigned long comment_len;
comment_len = libssh2_ntohu32(s); s += 4;
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", 0);
goto err_exit;
}
list[keys].attrs[0].name = "comment";
list[keys].attrs[0].name_len = sizeof("comment") - 1;
list[keys].attrs[0].value = s;
list[keys].attrs[0].value_len = comment_len;
list[keys].attrs[0].mandatory = 0;
s += comment_len;
} else {
list[keys].num_attrs = 0;
list[keys].attrs = NULL;
}
list[keys].name_len = libssh2_ntohu32(s); s += 4;
list[keys].name = s; s += list[keys].name_len;
list[keys].blob_len = libssh2_ntohu32(s); s += 4;
list[keys].blob = s; s += list[keys].blob_len;
} else {
/* Version == 2 */
list[keys].name_len = libssh2_ntohu32(s); s += 4;
list[keys].name = s; s += list[keys].name_len;
list[keys].blob_len = libssh2_ntohu32(s); s += 4;
list[keys].blob = s; s += list[keys].blob_len;
list[keys].num_attrs = libssh2_ntohu32(s); s += 4;
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", 0);
goto err_exit;
}
for(i = 0; i < list[keys].num_attrs; i++) {
list[keys].attrs[i].name_len = libssh2_ntohu32(s); s += 4;
list[keys].attrs[i].name = s; s += list[keys].attrs[i].name_len;
list[keys].attrs[i].value_len = libssh2_ntohu32(s); s += 4;
list[keys].attrs[i].value = s; s += list[keys].attrs[i].value_len;
list[keys].attrs[i].mandatory = 0; /* actually an ignored value */
}
} else {
list[keys].attrs = NULL;
}
}
list[keys].packet = data; /* To be FREEd in libssh2_publickey_list_free() */
keys++;
list[keys].packet = NULL; /* Terminate the list */
data = NULL;
break;
default:
/* Unknown/Unexpected */
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Unexpected publickey subsystem response, ignoring", 0);
LIBSSH2_FREE(session, data);
}
}
/* Only reached via explicit goto */
err_exit:
if (data) {
LIBSSH2_FREE(session, data);
}
if (list) {
libssh2_publickey_list_free(pkey, list);
}
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 = pkey->channel->session;
libssh2_publickey_list *p = pkey_list;
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 void libssh2_publickey_shutdown(LIBSSH2_PUBLICKEY *pkey)
{
LIBSSH2_SESSION *session = pkey->channel->session;
libssh2_channel_free(pkey->channel);
LIBSSH2_FREE(session, pkey);
}
/* }}} */

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org> /* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, * Redistribution and use in source and binary forms,
@@ -44,7 +44,7 @@
/* {{{ libssh2_scp_recv /* {{{ libssh2_scp_recv
* Open a channel and request a remote file via SCP * Open a channel and request a remote file via SCP
*/ */
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, char *path, struct stat *sb) LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, const char *path, struct stat *sb)
{ {
int path_len = strlen(path); int path_len = strlen(path);
unsigned char *command, response[LIBSSH2_SCP_RESPONSE_BUFLEN]; unsigned char *command, response[LIBSSH2_SCP_RESPONSE_BUFLEN];
@@ -330,11 +330,12 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, char *pa
/* {{{ libssh2_scp_send_ex /* {{{ libssh2_scp_send_ex
* Send a file using SCP * Send a file using SCP
*/ */
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, char *path, int mode, size_t size, long mtime, long atime) LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, const char *path, int mode, size_t size, long mtime, long atime)
{ {
int path_len = strlen(path); int path_len = strlen(path);
unsigned char *command, *base, response[LIBSSH2_SCP_RESPONSE_BUFLEN]; unsigned char *command, response[LIBSSH2_SCP_RESPONSE_BUFLEN];
unsigned long response_len, command_len = path_len + sizeof("scp -t "); unsigned long response_len, command_len = path_len + sizeof("scp -t ");
unsigned const char *base;
LIBSSH2_CHANNEL *channel; LIBSSH2_CHANNEL *channel;
if (mtime || atime) { if (mtime || atime) {

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org> /* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, * Redistribution and use in source and binary forms,
@@ -103,9 +103,28 @@ static int libssh2_banner_receive(LIBSSH2_SESSION *session)
ret = recv(session->socket_fd, &c, 1, LIBSSH2_SOCKET_RECV_FLAGS(session)); ret = recv(session->socket_fd, &c, 1, LIBSSH2_SOCKET_RECV_FLAGS(session));
if ((ret < 0) && (ret != EAGAIN)) { if (ret < 0) {
/* Some kinda error, but don't break for non-blocking issues */ #ifdef WIN32
return 1; switch (WSAGetLastError()) {
case WSAEWOULDBLOCK:
errno = EAGAIN;
break;
case WSAENOTSOCK:
errno = EBADF;
break;
case WSAENOTCONN:
case WSAECONNABORTED:
errno = ENOTCONN;
break;
case WSAEINTR:
errno = EINTR;
break;
}
#endif /* WIN32 */
if (errno != EAGAIN) {
/* Some kinda error, but don't break for non-blocking issues */
return 1;
}
} }
if (ret <= 0) continue; if (ret <= 0) continue;
@@ -172,7 +191,7 @@ static int libssh2_banner_send(LIBSSH2_SESSION *session)
/* {{{ libssh2_banner_set /* {{{ libssh2_banner_set
* Set the local banner * Set the local banner
*/ */
LIBSSH2_API int libssh2_banner_set(LIBSSH2_SESSION *session, char *banner) LIBSSH2_API int libssh2_banner_set(LIBSSH2_SESSION *session, const char *banner)
{ {
int banner_len = banner ? strlen(banner) : 0; int banner_len = banner ? strlen(banner) : 0;
@@ -298,9 +317,9 @@ LIBSSH2_API int libssh2_session_startup(LIBSSH2_SESSION *session, int socket)
#ifdef LIBSSH2_DEBUG_TRANSPORT #ifdef LIBSSH2_DEBUG_TRANSPORT
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "session_startup for socket %d", socket); _libssh2_debug(session, LIBSSH2_DBG_TRANS, "session_startup for socket %d", socket);
#endif #endif
if (socket <= 0) { if (socket < 0) {
/* Did we forget something? */ /* Did we forget something? */
libssh2_error(session, LIBSSH2_ERROR_SOCKET_NONE, "No socket provided", 0); libssh2_error(session, LIBSSH2_ERROR_SOCKET_NONE, "Bad socket provided", 0);
return LIBSSH2_ERROR_SOCKET_NONE; return LIBSSH2_ERROR_SOCKET_NONE;
} }
session->socket_fd = socket; session->socket_fd = socket;
@@ -394,6 +413,7 @@ LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session)
if (session->local.crypt) { if (session->local.crypt) {
if (session->local.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) { if (session->local.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) {
if (session->local.crypt_abstract) { if (session->local.crypt_abstract) {
EVP_CIPHER_CTX_cleanup(session->local.crypt_abstract);
LIBSSH2_FREE(session, session->local.crypt_abstract); LIBSSH2_FREE(session, session->local.crypt_abstract);
session->local.crypt_abstract = NULL; session->local.crypt_abstract = NULL;
} }
@@ -415,6 +435,7 @@ LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session)
if (session->remote.crypt) { if (session->remote.crypt) {
if (session->remote.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) { if (session->remote.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) {
if (session->remote.crypt_abstract) { if (session->remote.crypt_abstract) {
EVP_CIPHER_CTX_cleanup(session->remote.crypt_abstract);
LIBSSH2_FREE(session, session->remote.crypt_abstract); LIBSSH2_FREE(session, session->remote.crypt_abstract);
session->remote.crypt_abstract = NULL; session->remote.crypt_abstract = NULL;
} }
@@ -497,7 +518,7 @@ LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session)
/* {{{ libssh2_session_disconnect_ex /* {{{ libssh2_session_disconnect_ex
*/ */
LIBSSH2_API int libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, int reason, char *description, char *lang) LIBSSH2_API int libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, int reason, const char *description, const char *lang)
{ {
unsigned char *s, *data; unsigned char *s, *data;
unsigned long data_len, descr_len = 0, lang_len = 0; unsigned long data_len, descr_len = 0, lang_len = 0;
@@ -547,7 +568,7 @@ LIBSSH2_API int libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, int reas
* NOTE: Currently lang_cs and lang_sc are ALWAYS set to empty string regardless of actual negotiation * NOTE: Currently lang_cs and lang_sc are ALWAYS set to empty string regardless of actual negotiation
* Strings should NOT be freed * Strings should NOT be freed
*/ */
LIBSSH2_API char *libssh2_session_methods(LIBSSH2_SESSION *session, int method_type) LIBSSH2_API const char *libssh2_session_methods(LIBSSH2_SESSION *session, int method_type)
{ {
/* All methods have char *name as their first element */ /* All methods have char *name as their first element */
LIBSSH2_KEX_METHOD *method = NULL; LIBSSH2_KEX_METHOD *method = NULL;
@@ -682,7 +703,7 @@ LIBSSH2_API int libssh2_session_flag(LIBSSH2_SESSION *session, int flag, int val
* Returns 0 if no data is waiting on channel, * Returns 0 if no data is waiting on channel,
* non-0 if data is available * non-0 if data is available
*/ */
static int libssh2_poll_channel_read(LIBSSH2_CHANNEL *channel, int extended) LIBSSH2_API int libssh2_poll_channel_read(LIBSSH2_CHANNEL *channel, int extended)
{ {
LIBSSH2_SESSION *session = channel->session; LIBSSH2_SESSION *session = channel->session;
LIBSSH2_PACKET *packet = session->packets.head; LIBSSH2_PACKET *packet = session->packets.head;

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org> /* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, * Redistribution and use in source and binary forms,
@@ -569,7 +569,7 @@ LIBSSH2_API LIBSSH2_SFTP_HANDLE *libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, char *
s = packet = LIBSSH2_ALLOC(session, packet_len); s = packet = LIBSSH2_ALLOC(session, packet_len);
if (!packet) { if (!packet) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for FXP_REMOVE packet", 0); libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for FXP_OPEN or FXP_OPENDIR packet", 0);
return NULL; return NULL;
} }
/* Filetype in SFTP 3 and earlier */ /* Filetype in SFTP 3 and earlier */
@@ -590,7 +590,7 @@ LIBSSH2_API LIBSSH2_SFTP_HANDLE *libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, char *
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Sending %s open request", (open_type == LIBSSH2_SFTP_OPENFILE) ? "file" : "directory"); _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Sending %s open request", (open_type == LIBSSH2_SFTP_OPENFILE) ? "file" : "directory");
#endif #endif
if (packet_len != libssh2_channel_write(channel, packet, packet_len)) { if (packet_len != libssh2_channel_write(channel, packet, packet_len)) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_REMOVE command", 0); libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_OPEN or FXP_OPENDIR command", 0);
LIBSSH2_FREE(session, packet); LIBSSH2_FREE(session, packet);
return NULL; return NULL;
} }
@@ -1113,8 +1113,9 @@ LIBSSH2_API int libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp, char *source_filenam
LIBSSH2_CHANNEL *channel = sftp->channel; LIBSSH2_CHANNEL *channel = sftp->channel;
LIBSSH2_SESSION *session = channel->session; LIBSSH2_SESSION *session = channel->session;
unsigned long data_len, retcode = -1, request_id; unsigned long data_len, retcode = -1, request_id;
unsigned long packet_len = source_filename_len + dest_filename_len + 21; /* packet_len(4) + packet_type(1) + request_id(4) + unsigned long packet_len = source_filename_len + dest_filename_len + 17 + (sftp->version >= 5 ? 4 : 0);
source_filename_len(4) + dest_filename_len(4) + flags(4) */ /* packet_len(4) + packet_type(1) + request_id(4) +
source_filename_len(4) + dest_filename_len(4) + flags(4){SFTP5+) */
unsigned char *packet, *s, *data; unsigned char *packet, *s, *data;
if (sftp->version < 2) { if (sftp->version < 2) {
@@ -1139,10 +1140,13 @@ LIBSSH2_API int libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp, char *source_filenam
memcpy(s, source_filename, source_filename_len); s += source_filename_len; memcpy(s, source_filename, source_filename_len); s += source_filename_len;
libssh2_htonu32(s, dest_filename_len); s += 4; libssh2_htonu32(s, dest_filename_len); s += 4;
memcpy(s, dest_filename, dest_filename_len); s += dest_filename_len; memcpy(s, dest_filename, dest_filename_len); s += dest_filename_len;
libssh2_htonu32(s, flags); s += 4;
if (packet_len != libssh2_channel_write(channel, packet, packet_len)) { if (sftp->version >= 5) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_REMOVE command", 0); libssh2_htonu32(s, flags); s += 4;
}
if (packet_len != libssh2_channel_write(channel, packet, s - packet)) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_RENAME command", 0);
LIBSSH2_FREE(session, packet); LIBSSH2_FREE(session, packet);
return -1; return -1;
} }
@@ -1213,7 +1217,7 @@ LIBSSH2_API int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, char *path, int path_l
s += libssh2_sftp_attr2bin(s, &attrs); s += libssh2_sftp_attr2bin(s, &attrs);
if (packet_len != libssh2_channel_write(channel, packet, packet_len)) { if (packet_len != libssh2_channel_write(channel, packet, packet_len)) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_REMOVE command", 0); libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_MKDIR command", 0);
LIBSSH2_FREE(session, packet); LIBSSH2_FREE(session, packet);
return -1; return -1;
} }
@@ -1265,7 +1269,7 @@ LIBSSH2_API int libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp, char *path, int path_l
memcpy(s, path, path_len); s += path_len; memcpy(s, path, path_len); s += path_len;
if (packet_len != libssh2_channel_write(channel, packet, packet_len)) { if (packet_len != libssh2_channel_write(channel, packet, packet_len)) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_REMOVE command", 0); libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_MKDIR command", 0);
LIBSSH2_FREE(session, packet); LIBSSH2_FREE(session, packet);
return -1; return -1;
} }
@@ -1448,10 +1452,11 @@ LIBSSH2_API int libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, const char *path, in
} }
link_len = libssh2_ntohu32(data + 9); link_len = libssh2_ntohu32(data + 9);
if (link_len > target_len) { if (link_len >= target_len) {
link_len = target_len; link_len = target_len - 1;
} }
memcpy(target, data + 13, link_len); memcpy(target, data + 13, link_len);
target[link_len] = 0;
LIBSSH2_FREE(session, data); LIBSSH2_FREE(session, data);
return link_len; return link_len;

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org> /* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, * Redistribution and use in source and binary forms,
@@ -49,7 +49,7 @@
* Not a common configuration for any SSH server though * Not a common configuration for any SSH server though
* username should be NULL, or a null terminated string * username should be NULL, or a null terminated string
*/ */
LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, char *username, int username_len) LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, const char *username, int username_len)
{ {
unsigned char reply_codes[3] = { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 }; unsigned char reply_codes[3] = { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 };
unsigned long data_len = username_len + 31; /* packet_type(1) + username_len(4) + service_len(4) + service(14)"ssh-connection" + unsigned long data_len = username_len + 31; /* packet_type(1) + username_len(4) + service_len(4) + service(14)"ssh-connection" +
@@ -116,8 +116,8 @@ LIBSSH2_API int libssh2_userauth_authenticated(LIBSSH2_SESSION *session)
/* {{{ libssh2_userauth_password /* {{{ libssh2_userauth_password
* Plain ol' login * Plain ol' login
*/ */
LIBSSH2_API int libssh2_userauth_password_ex(LIBSSH2_SESSION *session, char *username, int username_len, LIBSSH2_API int libssh2_userauth_password_ex(LIBSSH2_SESSION *session, const char *username, int username_len,
char *password, int password_len, const char *password, int password_len,
LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb))) LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb)))
{ {
unsigned char *data, *s, reply_codes[4] = { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, 0 }; unsigned char *data, *s, reply_codes[4] = { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, 0 };
@@ -235,7 +235,7 @@ LIBSSH2_API int libssh2_userauth_password_ex(LIBSSH2_SESSION *session, char *use
*/ */
static int libssh2_file_read_publickey(LIBSSH2_SESSION *session, unsigned char **method, unsigned long *method_len, static int libssh2_file_read_publickey(LIBSSH2_SESSION *session, unsigned char **method, unsigned long *method_len,
unsigned char **pubkeydata, unsigned long *pubkeydata_len, unsigned char **pubkeydata, unsigned long *pubkeydata_len,
char *pubkeyfile) const char *pubkeyfile)
{ {
FILE *fd; FILE *fd;
char *pubkey = NULL, c, *sp1, *sp2, *tmp; char *pubkey = NULL, c, *sp1, *sp2, *tmp;
@@ -310,12 +310,12 @@ static int libssh2_file_read_publickey(LIBSSH2_SESSION *session, unsigned char *
} }
/* }}} */ /* }}} */
/* {{{ libssh2_file_read_publickey /* {{{ libssh2_file_read_privatekey
* Read a PEM encoded private key from an id_??? style file * Read a PEM encoded private key from an id_??? style file
*/ */
static int libssh2_file_read_privatekey(LIBSSH2_SESSION *session, LIBSSH2_HOSTKEY_METHOD **hostkey_method, void **hostkey_abstract, static int libssh2_file_read_privatekey(LIBSSH2_SESSION *session, LIBSSH2_HOSTKEY_METHOD **hostkey_method, void **hostkey_abstract,
char *method, int method_len, const char *method, int method_len,
char *privkeyfile, char *passphrase) const char *privkeyfile, const char *passphrase)
{ {
LIBSSH2_HOSTKEY_METHOD **hostkey_methods_avail = libssh2_hostkey_methods(); LIBSSH2_HOSTKEY_METHOD **hostkey_methods_avail = libssh2_hostkey_methods();
@@ -349,11 +349,11 @@ static int libssh2_file_read_privatekey(LIBSSH2_SESSION *session, LIBSSH2_HOSTKE
/* {{{ libssh2_userauth_hostbased_fromfile_ex /* {{{ libssh2_userauth_hostbased_fromfile_ex
* Authenticate using a keypair found in the named files * Authenticate using a keypair found in the named files
*/ */
LIBSSH2_API int libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session, char *username, int username_len, LIBSSH2_API int libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session, const char *username, int username_len,
char *publickey, char *privatekey, const char *publickey, const char *privatekey,
char *passphrase, const char *passphrase,
char *hostname, int hostname_len, const char *hostname, int hostname_len,
char *local_username, int local_username_len) const char *local_username, int local_username_len)
{ {
LIBSSH2_HOSTKEY_METHOD *privkeyobj; LIBSSH2_HOSTKEY_METHOD *privkeyobj;
void *abstract; void *abstract;
@@ -480,9 +480,9 @@ LIBSSH2_API int libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session,
/* {{{ libssh2_userauth_publickey_fromfile_ex /* {{{ libssh2_userauth_publickey_fromfile_ex
* Authenticate using a keypair found in the named files * Authenticate using a keypair found in the named files
*/ */
LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, char *username, int username_len, LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, const char *username, int username_len,
char *publickey, char *privatekey, const char *publickey, const char *privatekey,
char *passphrase) const char *passphrase)
{ {
LIBSSH2_HOSTKEY_METHOD *privkeyobj; LIBSSH2_HOSTKEY_METHOD *privkeyobj;
void *abstract; void *abstract;
@@ -652,3 +652,204 @@ LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session,
return -1; return -1;
} }
/* }}} */ /* }}} */
/* {{{ libssh2_userauth_keyboard_interactive
* Authenticate using a challenge-response authentication
*/
LIBSSH2_API int libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION *session, const char *username, int username_len,
LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC((*response_callback)))
{
unsigned char *s, *data; /* packet */
unsigned long packet_len;
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) */
;
if (!(data = s = LIBSSH2_ALLOC(session, packet_len))) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive authentication", 0);
return -1;
}
*s++ = SSH_MSG_USERAUTH_REQUEST;
/* user name */
libssh2_htonu32(s, username_len); s += 4;
memcpy(s, username, username_len); s += username_len;
/* service name */
libssh2_htonu32(s, sizeof("ssh-connection") - 1); s += 4;
memcpy(s, "ssh-connection", sizeof("ssh-connection") - 1); s += sizeof("ssh-connection") - 1;
/* "keyboard-interactive" */
libssh2_htonu32(s, sizeof("keyboard-interactive") - 1); s += 4;
memcpy(s, "keyboard-interactive", sizeof("keyboard-interactive") - 1); s += sizeof("keyboard-interactive") - 1;
/* language tag */
libssh2_htonu32(s, 0); s += 4;
/* submethods */
libssh2_htonu32(s, 0); s += 4;
#ifdef LIBSSH2_DEBUG_USERAUTH
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Attempting keyboard-interactive authentication");
#endif
if (libssh2_packet_write(session, data, packet_len)) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send keyboard-interactive request", 0);
LIBSSH2_FREE(session, data);
return -1;
}
LIBSSH2_FREE(session, data);
for (;;) {
unsigned char reply_codes[4] = { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_INFO_REQUEST, 0 };
unsigned int auth_name_len;
char* auth_name = NULL;
unsigned auth_instruction_len;
char* auth_instruction = NULL;
unsigned int language_tag_len;
unsigned long data_len;
unsigned int num_prompts = 0;
unsigned int i;
int auth_failure = 1;
LIBSSH2_USERAUTH_KBDINT_PROMPT* prompts = NULL;
LIBSSH2_USERAUTH_KBDINT_RESPONSE* responses = NULL;
if (libssh2_packet_requirev(session, reply_codes, &data, &data_len)) {
return -1;
}
if (data[0] == SSH_MSG_USERAUTH_SUCCESS) {
#ifdef LIBSSH2_DEBUG_USERAUTH
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Keyboard-interactive authentication successful");
#endif
LIBSSH2_FREE(session, data);
session->state |= LIBSSH2_STATE_AUTHENTICATED;
return 0;
}
if (data[0] == SSH_MSG_USERAUTH_FAILURE) {
LIBSSH2_FREE(session, data);
return -1;
}
/* server requested PAM-like conversation */
s = data + 1;
/* string name (ISO-10646 UTF-8) */
auth_name_len = libssh2_ntohu32(s); s += 4;
if (!(auth_name = LIBSSH2_ALLOC(session, auth_name_len))) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive 'name' request field", 0);
goto cleanup;
}
memcpy(auth_name, s, auth_name_len); s += auth_name_len;
/* string instruction (ISO-10646 UTF-8) */
auth_instruction_len = libssh2_ntohu32(s); s += 4;
if (!(auth_instruction = LIBSSH2_ALLOC(session, auth_instruction_len))) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive 'instruction' request field", 0);
goto cleanup;
}
memcpy(auth_instruction, s, auth_instruction_len); s += auth_instruction_len;
/* string language tag (as defined in [RFC-3066]) */
language_tag_len = libssh2_ntohu32(s); s += 4;
/* ignoring this field as deprecated */ s += language_tag_len;
/* int num-prompts */
num_prompts = libssh2_ntohu32(s); s += 4;
prompts = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) * num_prompts);
if (!prompts) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive prompts array", 0);
goto cleanup;
}
memset(prompts, 0, sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) * num_prompts);
responses = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) * num_prompts);
if (!responses) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive responses array", 0);
goto cleanup;
}
memset(responses, 0, sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) * num_prompts);
for(i = 0; i != num_prompts; ++i) {
/* string prompt[1] (ISO-10646 UTF-8) */
prompts[i].length = libssh2_ntohu32(s); s += 4;
if (!(prompts[i].text = LIBSSH2_ALLOC(session, prompts[i].length))) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive prompt message", 0);
goto cleanup;
}
memcpy(prompts[i].text, s, prompts[i].length); s += prompts[i].length;
/* boolean echo[1] */
prompts[i].echo = *s++;
}
response_callback(auth_name, auth_name_len, auth_instruction, auth_instruction_len, num_prompts, prompts, responses, &session->abstract);
#ifdef LIBSSH2_DEBUG_USERAUTH
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Keyboard-interactive response callback function invoked");
#endif
packet_len = 1 /* byte SSH_MSG_USERAUTH_INFO_RESPONSE */
+ 4 /* int num-responses */
;
for (i = 0; i != num_prompts; ++i) {
packet_len += 4 + responses[i].length; /* string response[1] (ISO-10646 UTF-8) */
}
if (!(data = s = LIBSSH2_ALLOC(session, packet_len))) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive response packet", 0);
goto cleanup;
}
*s = SSH_MSG_USERAUTH_INFO_RESPONSE; s++;
libssh2_htonu32(s, num_prompts); s += 4;
for (i = 0; i != num_prompts; ++i) {
libssh2_htonu32(s, responses[i].length); s += 4;
memcpy(s, responses[i].text, responses[i].length); s += responses[i].length;
}
if (libssh2_packet_write(session, data, packet_len)) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-keyboard-interactive request", 0);
goto cleanup;
}
auth_failure = 0;
cleanup:
/* It's safe to clean all the data here, because unallocated pointers
* are filled by zeroes
*/
LIBSSH2_FREE(session, data);
if (prompts) {
for (i = 0; i != num_prompts; ++i) {
LIBSSH2_FREE(session, prompts[i].text);
}
}
if (responses) {
for (i = 0; i != num_prompts; ++i) {
LIBSSH2_FREE(session, responses[i].text);
}
}
LIBSSH2_FREE(session, prompts);
LIBSSH2_FREE(session, responses);
if (auth_failure) {
return -1;
}
}
}
/* }}} */

View File

@@ -17,7 +17,7 @@
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
int sock, i, auth_pw = 1; int sock, i, auth_pw = 1;
struct sockaddr_in sin; struct sockaddr_in sin;
char *fingerprint; const char *fingerprint;
LIBSSH2_SESSION *session; LIBSSH2_SESSION *session;
LIBSSH2_CHANNEL *channel; LIBSSH2_CHANNEL *channel;
#ifdef WIN32 #ifdef WIN32